vpr/ShadowStream/Modules/videoFrameModule.cs
2025-06-09 16:14:20 +01:00

77 lines
2.5 KiB
C#

using FFMediaToolkit.Decoding;
using FFMediaToolkit.Graphics;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
public static class VideoFrameExtractor
{
public static Bitmap GetFrame200(string videoPath)
{
FFMediaToolkit.FFmpegLoader.FFmpegPath = AppDomain.CurrentDomain.BaseDirectory;
using var mediaFile = MediaFile.Open(videoPath);
// 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;
if (!mediaFile.Video.TryGetNextFrame(out var secondFrame))
throw new Exception("Cannot read second frame");
double secondSeconds = mediaFile.Video.Position.TotalSeconds;
double frameDuration = secondSeconds - firstSeconds;
if (frameDuration <= 0)
throw new Exception("Invalid frame duration calculated");
double frameRate = 1.0 / frameDuration;
int totalFrames = (int)(mediaFile.Info.Duration.TotalSeconds * frameRate);
const int targetFrameIndex = 200;
if (targetFrameIndex >= totalFrames)
throw new ArgumentOutOfRangeException($"Video has only {totalFrames} frames, cannot extract frame {targetFrameIndex}");
// 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))
{
if (currentFrameIndex == targetFrameIndex)
{
targetFrameBitmap = ImageDataToBitmap(frame);
break;
}
currentFrameIndex++;
}
if (targetFrameBitmap == null)
throw new Exception($"Failed to extract frame {targetFrameIndex}");
return targetFrameBitmap;
}
private static Bitmap ImageDataToBitmap(ImageData imageData)
{
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;
}
}