diff --git a/FFMpegCore.Extensions.SkiaSharp/FFMpegImage.cs b/FFMpegCore.Extensions.SkiaSharp/FFMpegImage.cs
index f412844..41c6a1c 100644
--- a/FFMpegCore.Extensions.SkiaSharp/FFMpegImage.cs
+++ b/FFMpegCore.Extensions.SkiaSharp/FFMpegImage.cs
@@ -39,18 +39,21 @@ public static class FFMpegImage
/// Thumbnail size. If width or height equal 0, the other will be computed automatically.
/// Selected video stream index.
/// Input file index
+ /// Cancellation token
/// Bitmap with the requested snapshot.
public static async Task SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null,
- int inputFileIndex = 0)
+ int inputFileIndex = 0, CancellationToken cancellationToken = default)
{
- var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
+ var source = await FFProbe.AnalyseAsync(input, cancellationToken: cancellationToken).ConfigureAwait(false);
var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
using var ms = new MemoryStream();
await arguments
.OutputToPipe(new StreamPipeSink(ms), options => outputOptions(options
.ForceFormat("rawvideo")))
- .ProcessAsynchronously();
+ .CancellableThrough(cancellationToken)
+ .ProcessAsynchronously()
+ .ConfigureAwait(false);
ms.Position = 0;
return SKBitmap.Decode(ms);
diff --git a/FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs b/FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs
index 1c7f965..2dd2234 100644
--- a/FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs
+++ b/FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs
@@ -38,18 +38,21 @@ public static class FFMpegImage
/// Thumbnail size. If width or height equal 0, the other will be computed automatically.
/// Selected video stream index.
/// Input file index
+ /// Cancellation token
/// Bitmap with the requested snapshot.
public static async Task SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null,
- int inputFileIndex = 0)
+ int inputFileIndex = 0, CancellationToken cancellationToken = default)
{
- var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
+ var source = await FFProbe.AnalyseAsync(input, cancellationToken: cancellationToken).ConfigureAwait(false);
var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
using var ms = new MemoryStream();
await arguments
.OutputToPipe(new StreamPipeSink(ms), options => outputOptions(options
.ForceFormat("rawvideo")))
- .ProcessAsynchronously();
+ .CancellableThrough(cancellationToken)
+ .ProcessAsynchronously()
+ .ConfigureAwait(false);
ms.Position = 0;
return new Bitmap(ms);
diff --git a/FFMpegCore.Test/VideoTest.cs b/FFMpegCore.Test/VideoTest.cs
index e338324..b0a85aa 100644
--- a/FFMpegCore.Test/VideoTest.cs
+++ b/FFMpegCore.Test/VideoTest.cs
@@ -732,7 +732,8 @@ public class VideoTest
using var outputPath = new TemporaryFile("out.gif");
var input = FFProbe.Analyse(TestResources.Mp4Video);
- await FFMpeg.GifSnapshotAsync(TestResources.Mp4Video, outputPath, captureTime: TimeSpan.FromSeconds(0));
+ await FFMpeg.GifSnapshotAsync(TestResources.Mp4Video, outputPath, captureTime: TimeSpan.FromSeconds(0),
+ cancellationToken: TestContext.CancellationToken);
var analysis = FFProbe.Analyse(outputPath);
Assert.AreNotEqual(input.PrimaryVideoStream!.Width, analysis.PrimaryVideoStream!.Width);
@@ -748,7 +749,8 @@ public class VideoTest
var input = FFProbe.Analyse(TestResources.Mp4Video);
var desiredGifSize = new Size(320, 240);
- await FFMpeg.GifSnapshotAsync(TestResources.Mp4Video, outputPath, desiredGifSize, TimeSpan.FromSeconds(0));
+ await FFMpeg.GifSnapshotAsync(TestResources.Mp4Video, outputPath, desiredGifSize, TimeSpan.FromSeconds(0),
+ cancellationToken: TestContext.CancellationToken);
var analysis = FFProbe.Analyse(outputPath);
Assert.AreNotEqual(input.PrimaryVideoStream!.Width, desiredGifSize.Width);
diff --git a/FFMpegCore/FFMpeg/FFMpeg.cs b/FFMpegCore/FFMpeg/FFMpeg.cs
index 0b6de74..b9a0d5d 100644
--- a/FFMpegCore/FFMpeg/FFMpeg.cs
+++ b/FFMpegCore/FFMpeg/FFMpeg.cs
@@ -37,16 +37,19 @@ public static class FFMpeg
/// Thumbnail size. If width or height equal 0, the other will be computed automatically.
/// Selected video stream index.
/// Input file index
+ /// Cancellation token
/// Bitmap with the requested snapshot.
public static async Task SnapshotAsync(string input, string output, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null,
- int inputFileIndex = 0)
+ int inputFileIndex = 0, CancellationToken cancellationToken = default)
{
CheckSnapshotOutputExtension(output, FileExtension.Image.All);
- var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
+ var source = await FFProbe.AnalyseAsync(input, cancellationToken: cancellationToken).ConfigureAwait(false);
return await SnapshotProcess(input, output, source, size, captureTime, streamIndex, inputFileIndex)
- .ProcessAsynchronously();
+ .CancellableThrough(cancellationToken)
+ .ProcessAsynchronously()
+ .ConfigureAwait(false);
}
public static bool GifSnapshot(string input, string output, Size? size = null, TimeSpan? captureTime = null, TimeSpan? duration = null,
@@ -61,14 +64,16 @@ public static class FFMpeg
}
public static async Task GifSnapshotAsync(string input, string output, Size? size = null, TimeSpan? captureTime = null, TimeSpan? duration = null,
- int? streamIndex = null)
+ int? streamIndex = null, CancellationToken cancellationToken = default)
{
CheckSnapshotOutputExtension(output, [FileExtension.Gif]);
- var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
+ var source = await FFProbe.AnalyseAsync(input, cancellationToken: cancellationToken).ConfigureAwait(false);
return await GifSnapshotProcess(input, output, source, size, captureTime, duration, streamIndex)
- .ProcessAsynchronously();
+ .CancellableThrough(cancellationToken)
+ .ProcessAsynchronously()
+ .ConfigureAwait(false);
}
private static FFMpegArgumentProcessor SnapshotProcess(string input, string output, IMediaAnalysis source, Size? size = null, TimeSpan? captureTime = null,
@@ -321,11 +326,15 @@ public static class FFMpeg
/// Output video file.
/// The start time of when the sub video needs to start
/// The end time of where the sub video needs to end
+ /// Cancellation token
/// Output video information.
- public static async Task SubVideoAsync(string input, string output, TimeSpan startTime, TimeSpan endTime)
+ public static async Task SubVideoAsync(string input, string output, TimeSpan startTime, TimeSpan endTime,
+ CancellationToken cancellationToken = default)
{
return await BaseSubVideo(input, output, startTime, endTime)
- .ProcessAsynchronously();
+ .CancellableThrough(cancellationToken)
+ .ProcessAsynchronously()
+ .ConfigureAwait(false);
}
///
diff --git a/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs b/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs
index 2f350ce..8191223 100644
--- a/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs
+++ b/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs
@@ -166,12 +166,28 @@ public class FFMpegArgumentProcessor
void OnCancelEvent(object sender, int timeout)
{
- instance.SendInput("q");
+ ExecuteIgnoringFinishedProcessExceptions(() => instance.SendInput("q"));
if (!cancellationTokenSource.Token.WaitHandle.WaitOne(timeout, true))
{
cancellationTokenSource.Cancel();
- instance.Kill();
+ ExecuteIgnoringFinishedProcessExceptions(() => instance.Kill());
+ }
+
+ static void ExecuteIgnoringFinishedProcessExceptions(Action action)
+ {
+ try
+ {
+ action();
+ }
+ catch (Instances.Exceptions.InstanceProcessAlreadyExitedException)
+ {
+ //ignore
+ }
+ catch (ObjectDisposedException)
+ {
+ //ignore
+ }
}
}