Skip to content

Commit 9b1e373

Browse files
authored
Merge pull request #593 from snechaev/PR-592_Snapshot_Cancellation_Support
Add cancellation token support for the [Gif]SnapshotAsync
2 parents d916fd3 + 935e1cf commit 9b1e373

File tree

5 files changed

+51
-18
lines changed

5 files changed

+51
-18
lines changed

FFMpegCore.Extensions.SkiaSharp/FFMpegImage.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,21 @@ public static SKBitmap Snapshot(string input, Size? size = null, TimeSpan? captu
3939
/// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param>
4040
/// <param name="streamIndex">Selected video stream index.</param>
4141
/// <param name="inputFileIndex">Input file index</param>
42+
/// <param name="cancellationToken">Cancellation token</param>
4243
/// <returns>Bitmap with the requested snapshot.</returns>
4344
public static async Task<SKBitmap> SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null,
44-
int inputFileIndex = 0)
45+
int inputFileIndex = 0, CancellationToken cancellationToken = default)
4546
{
46-
var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
47+
var source = await FFProbe.AnalyseAsync(input, cancellationToken: cancellationToken).ConfigureAwait(false);
4748
var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
4849
using var ms = new MemoryStream();
4950

5051
await arguments
5152
.OutputToPipe(new StreamPipeSink(ms), options => outputOptions(options
5253
.ForceFormat("rawvideo")))
53-
.ProcessAsynchronously();
54+
.CancellableThrough(cancellationToken)
55+
.ProcessAsynchronously()
56+
.ConfigureAwait(false);
5457

5558
ms.Position = 0;
5659
return SKBitmap.Decode(ms);

FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,21 @@ public static Bitmap Snapshot(string input, Size? size = null, TimeSpan? capture
3838
/// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param>
3939
/// <param name="streamIndex">Selected video stream index.</param>
4040
/// <param name="inputFileIndex">Input file index</param>
41+
/// <param name="cancellationToken">Cancellation token</param>
4142
/// <returns>Bitmap with the requested snapshot.</returns>
4243
public static async Task<Bitmap> SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null,
43-
int inputFileIndex = 0)
44+
int inputFileIndex = 0, CancellationToken cancellationToken = default)
4445
{
45-
var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
46+
var source = await FFProbe.AnalyseAsync(input, cancellationToken: cancellationToken).ConfigureAwait(false);
4647
var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
4748
using var ms = new MemoryStream();
4849

4950
await arguments
5051
.OutputToPipe(new StreamPipeSink(ms), options => outputOptions(options
5152
.ForceFormat("rawvideo")))
52-
.ProcessAsynchronously();
53+
.CancellableThrough(cancellationToken)
54+
.ProcessAsynchronously()
55+
.ConfigureAwait(false);
5356

5457
ms.Position = 0;
5558
return new Bitmap(ms);

FFMpegCore.Test/VideoTest.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,8 @@ public async Task Video_GifSnapshot_PersistSnapshotAsync()
732732
using var outputPath = new TemporaryFile("out.gif");
733733
var input = FFProbe.Analyse(TestResources.Mp4Video);
734734

735-
await FFMpeg.GifSnapshotAsync(TestResources.Mp4Video, outputPath, captureTime: TimeSpan.FromSeconds(0));
735+
await FFMpeg.GifSnapshotAsync(TestResources.Mp4Video, outputPath, captureTime: TimeSpan.FromSeconds(0),
736+
cancellationToken: TestContext.CancellationToken);
736737

737738
var analysis = FFProbe.Analyse(outputPath);
738739
Assert.AreNotEqual(input.PrimaryVideoStream!.Width, analysis.PrimaryVideoStream!.Width);
@@ -748,7 +749,8 @@ public async Task Video_GifSnapshot_PersistSnapshotAsync_SizeSupplied()
748749
var input = FFProbe.Analyse(TestResources.Mp4Video);
749750
var desiredGifSize = new Size(320, 240);
750751

751-
await FFMpeg.GifSnapshotAsync(TestResources.Mp4Video, outputPath, desiredGifSize, TimeSpan.FromSeconds(0));
752+
await FFMpeg.GifSnapshotAsync(TestResources.Mp4Video, outputPath, desiredGifSize, TimeSpan.FromSeconds(0),
753+
cancellationToken: TestContext.CancellationToken);
752754

753755
var analysis = FFProbe.Analyse(outputPath);
754756
Assert.AreNotEqual(input.PrimaryVideoStream!.Width, desiredGifSize.Width);

FFMpegCore/FFMpeg/FFMpeg.cs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,19 @@ public static bool Snapshot(string input, string output, Size? size = null, Time
3737
/// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param>
3838
/// <param name="streamIndex">Selected video stream index.</param>
3939
/// <param name="inputFileIndex">Input file index</param>
40+
/// <param name="cancellationToken">Cancellation token</param>
4041
/// <returns>Bitmap with the requested snapshot.</returns>
4142
public static async Task<bool> SnapshotAsync(string input, string output, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null,
42-
int inputFileIndex = 0)
43+
int inputFileIndex = 0, CancellationToken cancellationToken = default)
4344
{
4445
CheckSnapshotOutputExtension(output, FileExtension.Image.All);
4546

46-
var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
47+
var source = await FFProbe.AnalyseAsync(input, cancellationToken: cancellationToken).ConfigureAwait(false);
4748

4849
return await SnapshotProcess(input, output, source, size, captureTime, streamIndex, inputFileIndex)
49-
.ProcessAsynchronously();
50+
.CancellableThrough(cancellationToken)
51+
.ProcessAsynchronously()
52+
.ConfigureAwait(false);
5053
}
5154

5255
public static bool GifSnapshot(string input, string output, Size? size = null, TimeSpan? captureTime = null, TimeSpan? duration = null,
@@ -61,14 +64,16 @@ public static bool GifSnapshot(string input, string output, Size? size = null, T
6164
}
6265

6366
public static async Task<bool> GifSnapshotAsync(string input, string output, Size? size = null, TimeSpan? captureTime = null, TimeSpan? duration = null,
64-
int? streamIndex = null)
67+
int? streamIndex = null, CancellationToken cancellationToken = default)
6568
{
6669
CheckSnapshotOutputExtension(output, [FileExtension.Gif]);
6770

68-
var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
71+
var source = await FFProbe.AnalyseAsync(input, cancellationToken: cancellationToken).ConfigureAwait(false);
6972

7073
return await GifSnapshotProcess(input, output, source, size, captureTime, duration, streamIndex)
71-
.ProcessAsynchronously();
74+
.CancellableThrough(cancellationToken)
75+
.ProcessAsynchronously()
76+
.ConfigureAwait(false);
7277
}
7378

7479
private static FFMpegArgumentProcessor SnapshotProcess(string input, string output, IMediaAnalysis source, Size? size = null, TimeSpan? captureTime = null,
@@ -321,11 +326,15 @@ public static bool SubVideo(string input, string output, TimeSpan startTime, Tim
321326
/// <param name="output">Output video file.</param>
322327
/// <param name="startTime">The start time of when the sub video needs to start</param>
323328
/// <param name="endTime">The end time of where the sub video needs to end</param>
329+
/// <param name="cancellationToken">Cancellation token</param>
324330
/// <returns>Output video information.</returns>
325-
public static async Task<bool> SubVideoAsync(string input, string output, TimeSpan startTime, TimeSpan endTime)
331+
public static async Task<bool> SubVideoAsync(string input, string output, TimeSpan startTime, TimeSpan endTime,
332+
CancellationToken cancellationToken = default)
326333
{
327334
return await BaseSubVideo(input, output, startTime, endTime)
328-
.ProcessAsynchronously();
335+
.CancellableThrough(cancellationToken)
336+
.ProcessAsynchronously()
337+
.ConfigureAwait(false);
329338
}
330339

331340
/// <summary>

FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,28 @@ private async Task<IProcessResult> Process(ProcessArguments processArguments, Ca
166166

167167
void OnCancelEvent(object sender, int timeout)
168168
{
169-
instance.SendInput("q");
169+
ExecuteIgnoringFinishedProcessExceptions(() => instance.SendInput("q"));
170170

171171
if (!cancellationTokenSource.Token.WaitHandle.WaitOne(timeout, true))
172172
{
173173
cancellationTokenSource.Cancel();
174-
instance.Kill();
174+
ExecuteIgnoringFinishedProcessExceptions(() => instance.Kill());
175+
}
176+
177+
static void ExecuteIgnoringFinishedProcessExceptions(Action action)
178+
{
179+
try
180+
{
181+
action();
182+
}
183+
catch (Instances.Exceptions.InstanceProcessAlreadyExitedException)
184+
{
185+
//ignore
186+
}
187+
catch (ObjectDisposedException)
188+
{
189+
//ignore
190+
}
175191
}
176192
}
177193

0 commit comments

Comments
 (0)