77 lines
2.5 KiB
C#
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;
|
|
}
|
|
|
|
}
|