vlc fully implemented
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace ShadowStream.Obejeckte;
|
||||
//Quinn
|
||||
public class Catagory
|
||||
@@ -20,4 +22,9 @@ public class Catagory
|
||||
{
|
||||
items.Clear();
|
||||
}
|
||||
|
||||
public List<Item> getAllItems()
|
||||
{
|
||||
return items;
|
||||
}
|
||||
}
|
@@ -20,11 +20,22 @@ public class Jason_Writer
|
||||
// Save one list of locJason objects to JSON file with given name
|
||||
public async Task SaveList(string listName, List<locJason> list)
|
||||
{
|
||||
Console.WriteLine($"Saving JSON list '{listName}' with {list.Count} items.");
|
||||
foreach (var item in list)
|
||||
{
|
||||
Console.WriteLine($" - Path: {item.path}, Type: {item.type}, ImageData length: {(item.imageData?.Length ?? 0)}");
|
||||
}
|
||||
|
||||
string filePath = Path.Combine(_folderPath, $"{listName}.json");
|
||||
string jsonString = JsonConvert.SerializeObject(list, Formatting.Indented);
|
||||
File.WriteAllText(filePath, jsonString);
|
||||
await File.WriteAllTextAsync(filePath, jsonString);
|
||||
|
||||
Console.WriteLine($"Saved JSON to: {filePath}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Load one list of locJason objects from JSON file with given name
|
||||
public List<locJason> LoadList(string listName)
|
||||
{
|
||||
|
@@ -1,76 +1,96 @@
|
||||
using FFMediaToolkit.Decoding;
|
||||
using FFMediaToolkit.Graphics;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media.Imaging;
|
||||
using LibVLCSharp.Shared;
|
||||
|
||||
public static class VideoFrameExtractor
|
||||
{
|
||||
public static Bitmap GetFrame200(string videoPath)
|
||||
public static BitmapImage GetFrame200(string videoPath)
|
||||
{
|
||||
FFMediaToolkit.FFmpegLoader.FFmpegPath = AppDomain.CurrentDomain.BaseDirectory;
|
||||
Core.Initialize();
|
||||
using var libVLC = new LibVLC("--no-xlib");
|
||||
using var media = new Media(libVLC, videoPath, FromType.FromPath);
|
||||
using var mp = new MediaPlayer(media);
|
||||
|
||||
using var mediaFile = MediaFile.Open(videoPath);
|
||||
mp.Play();
|
||||
|
||||
// Read first two frames to estimate frame rate
|
||||
if (!mediaFile.Video.TryGetNextFrame(out var firstFrame))
|
||||
throw new Exception("Cannot read first frame");
|
||||
double firstSeconds = mediaFile.Video.Position.TotalSeconds;
|
||||
while (!mp.IsPlaying)
|
||||
Thread.Sleep(10);
|
||||
|
||||
if (!mediaFile.Video.TryGetNextFrame(out var secondFrame))
|
||||
throw new Exception("Cannot read second frame");
|
||||
double secondSeconds = mediaFile.Video.Position.TotalSeconds;
|
||||
// Seek to ~200th frame at 30 fps
|
||||
mp.Time = (long)((200.0 / 30.0) * 1000);
|
||||
Thread.Sleep(500);
|
||||
|
||||
double frameDuration = secondSeconds - firstSeconds;
|
||||
if (frameDuration <= 0)
|
||||
throw new Exception("Invalid frame duration calculated");
|
||||
if (!mp.IsPlaying)
|
||||
mp.Play();
|
||||
|
||||
double frameRate = 1.0 / frameDuration;
|
||||
Thread.Sleep(1000);
|
||||
|
||||
int totalFrames = (int)(mediaFile.Info.Duration.TotalSeconds * frameRate);
|
||||
string path = Path.GetTempFileName() + ".png";
|
||||
|
||||
const int targetFrameIndex = 200;
|
||||
if (targetFrameIndex >= totalFrames)
|
||||
throw new ArgumentOutOfRangeException($"Video has only {totalFrames} frames, cannot extract frame {targetFrameIndex}");
|
||||
if (!mp.TakeSnapshot(0, path, 0, 0))
|
||||
throw new Exception("Snapshot failed.");
|
||||
|
||||
// Reopen to reset reading
|
||||
mediaFile.Dispose();
|
||||
using var mediaFile2 = MediaFile.Open(videoPath);
|
||||
|
||||
int currentFrameIndex = 0;
|
||||
Bitmap targetFrameBitmap = null;
|
||||
|
||||
while (mediaFile2.Video.TryGetNextFrame(out var frame))
|
||||
// Wait for snapshot file to be fully written and valid
|
||||
int attempts = 10;
|
||||
while (attempts-- > 0)
|
||||
{
|
||||
if (currentFrameIndex == targetFrameIndex)
|
||||
{
|
||||
targetFrameBitmap = ImageDataToBitmap(frame);
|
||||
if (File.Exists(path) && new FileInfo(path).Length > 0)
|
||||
break;
|
||||
}
|
||||
currentFrameIndex++;
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
if (targetFrameBitmap == null)
|
||||
throw new Exception($"Failed to extract frame {targetFrameIndex}");
|
||||
if (!File.Exists(path))
|
||||
throw new FileNotFoundException("Snapshot file not found", path);
|
||||
|
||||
return targetFrameBitmap;
|
||||
var fileInfo = new FileInfo(path);
|
||||
if (fileInfo.Length == 0)
|
||||
throw new Exception("Snapshot file is empty or corrupted.");
|
||||
|
||||
BitmapImage image = null;
|
||||
|
||||
try
|
||||
{
|
||||
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
if (fs == null)
|
||||
throw new Exception("FileStream is null.");
|
||||
|
||||
image = new BitmapImage();
|
||||
|
||||
image.BeginInit();
|
||||
image.CacheOption = BitmapCacheOption.OnLoad;
|
||||
// Removed CreateOptions.IgnoreImageCache here to avoid ArgumentNullException
|
||||
image.StreamSource = fs ?? throw new Exception("StreamSource cannot be null.");
|
||||
fs.Position = 0;
|
||||
image.EndInit();
|
||||
image.Freeze();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error loading snapshot image from {path}: {ex}");
|
||||
throw new Exception("Failed to load snapshot image.", ex);
|
||||
}
|
||||
|
||||
// Async delayed delete of temp snapshot file (after 1 minute)
|
||||
DeleteFileLaterAsync(path);
|
||||
|
||||
return image!;
|
||||
}
|
||||
|
||||
private static Bitmap ImageDataToBitmap(ImageData imageData)
|
||||
private static async void DeleteFileLaterAsync(string path, int delayMs = 60000)
|
||||
{
|
||||
var bitmap = new Bitmap(imageData.ImageSize.Width, imageData.ImageSize.Height, PixelFormat.Format24bppRgb);
|
||||
var bmpData = bitmap.LockBits(
|
||||
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||
ImageLockMode.WriteOnly,
|
||||
bitmap.PixelFormat);
|
||||
|
||||
// Convert Span<byte> to byte[] for Marshal.Copy
|
||||
Marshal.Copy(imageData.Data.ToArray(), 0, bmpData.Scan0, imageData.Data.Length);
|
||||
|
||||
bitmap.UnlockBits(bmpData);
|
||||
|
||||
return bitmap;
|
||||
try
|
||||
{
|
||||
await Task.Delay(delayMs);
|
||||
File.Delete(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[WARNING] Failed to delete temp snapshot file {path}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user