From 9bf2093517385cebe6c9a71d2a2f592b815782d1 Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Sat, 8 Aug 2020 20:13:50 +0200 Subject: [PATCH] Add snapshot overloads --- FFMpegCore/FFMpeg/FFMpeg.cs | 78 +++++++++++++++----- FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs | 2 +- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/FFMpegCore/FFMpeg/FFMpeg.cs b/FFMpegCore/FFMpeg/FFMpeg.cs index 6e70354..cc042e3 100644 --- a/FFMpegCore/FFMpeg/FFMpeg.cs +++ b/FFMpegCore/FFMpeg/FFMpeg.cs @@ -7,6 +7,7 @@ using System.Drawing; using System.IO; using System.Linq; +using System.Threading.Tasks; namespace FFMpegCore { @@ -22,23 +23,35 @@ public static class FFMpeg /// Bitmap with the requested snapshot. public static bool Snapshot(MediaAnalysis source, string output, Size? size = null, TimeSpan? captureTime = null) { - captureTime ??= TimeSpan.FromSeconds(source.Duration.TotalSeconds / 3); - if (Path.GetExtension(output) != FileExtension.Png) output = Path.GetFileNameWithoutExtension(output) + FileExtension.Png; - size = PrepareSnapshotSize(source, size); - - return FFMpegArguments - .FromSeekedFiles((source.Path, captureTime ?? TimeSpan.Zero)) - .WithVideoCodec(VideoCodec.Png) - .WithFrameOutputCount(1) - .Resize(size) - .Seek(captureTime) + var arguments = BuildSnapshotArguments(source, size, captureTime); + + return arguments .OutputToFile(output) .ProcessSynchronously(); } /// + /// Saves a 'png' thumbnail from the input video to drive + /// + /// Source video analysis + /// Output video file path + /// Seek position where the thumbnail should be taken. + /// Thumbnail size. If width or height equal 0, the other will be computed automatically. + /// Bitmap with the requested snapshot. + public static Task SnapshotAsync(MediaAnalysis source, string output, Size? size = null, TimeSpan? captureTime = null) + { + if (Path.GetExtension(output) != FileExtension.Png) + output = Path.GetFileNameWithoutExtension(output) + FileExtension.Png; + + var arguments = BuildSnapshotArguments(source, size, captureTime); + + return arguments + .OutputToFile(output) + .ProcessAsynchronously(); + } + /// /// Saves a 'png' thumbnail to an in-memory bitmap /// /// Source video file. @@ -47,17 +60,10 @@ public static bool Snapshot(MediaAnalysis source, string output, Size? size = nu /// Bitmap with the requested snapshot. public static Bitmap Snapshot(MediaAnalysis source, Size? size = null, TimeSpan? captureTime = null) { - captureTime ??= TimeSpan.FromSeconds(source.Duration.TotalSeconds / 3); - - size = PrepareSnapshotSize(source, size); - + var arguments = BuildSnapshotArguments(source, size, captureTime); using var ms = new MemoryStream(); - FFMpegArguments - .FromInputFiles(source.Path) - .WithVideoCodec(VideoCodec.Png) - .WithFrameOutputCount(1) - .Resize(size) - .Seek(captureTime) + + arguments .ForceFormat("rawvideo") .OutputToPipe(new StreamPipeSink(ms)) .ProcessSynchronously(); @@ -65,6 +71,38 @@ public static Bitmap Snapshot(MediaAnalysis source, Size? size = null, TimeSpan? ms.Position = 0; return new Bitmap(ms); } + /// + /// Saves a 'png' thumbnail to an in-memory bitmap + /// + /// Source video file. + /// Seek position where the thumbnail should be taken. + /// Thumbnail size. If width or height equal 0, the other will be computed automatically. + /// Bitmap with the requested snapshot. + public static async Task SnapshotAsync(MediaAnalysis source, Size? size = null, TimeSpan? captureTime = null) + { + var arguments = BuildSnapshotArguments(source, size, captureTime); + using var ms = new MemoryStream(); + + await arguments + .ForceFormat("rawvideo") + .OutputToPipe(new StreamPipeSink(ms)) + .ProcessAsynchronously(); + + ms.Position = 0; + return new Bitmap(ms); + } + + private static FFMpegArguments BuildSnapshotArguments(MediaAnalysis source, Size? size = null, TimeSpan? captureTime = null) + { + captureTime ??= TimeSpan.FromSeconds(source.Duration.TotalSeconds / 3); + size = PrepareSnapshotSize(source, size); + + return FFMpegArguments + .FromSeekedFiles((source.Path, captureTime ?? TimeSpan.Zero)) + .WithVideoCodec(VideoCodec.Png) + .WithFrameOutputCount(1) + .Resize(size); + } private static Size? PrepareSnapshotSize(MediaAnalysis source, Size? size) { diff --git a/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs b/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs index f3f7502..71befc7 100644 --- a/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs +++ b/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs @@ -46,7 +46,7 @@ public FFMpegArgumentProcessor CancellableThrough(out Action cancel) } public bool ProcessSynchronously(bool throwOnError = true) { - var instance = PrepareInstance(out var cancellationTokenSource); + using var instance = PrepareInstance(out var cancellationTokenSource); var errorCode = -1; void OnCancelEvent(object sender, EventArgs args)