Merge pull request #587 from rosenbjerg/ensure-test-context-cancellationtoken-is-used

Ensure TestContext.CancellationToken is used
This commit is contained in:
Malte Rosenbjerg 2025-10-18 00:01:15 +02:00 committed by GitHub
commit 7d4545ffe0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 116 additions and 57 deletions

View file

@ -9,6 +9,10 @@ namespace FFMpegCore.Test;
[TestClass] [TestClass]
public class AudioTest public class AudioTest
{ {
private const int BaseTimeoutMilliseconds = 30_000;
public TestContext TestContext { get; set; }
[TestMethod] [TestMethod]
public void Audio_Remove() public void Audio_Remove()
{ {
@ -41,6 +45,7 @@ public class AudioTest
await FFMpegArguments await FFMpegArguments
.FromPipeInput(new StreamPipeSource(file), options => options.ForceFormat("s16le")) .FromPipeInput(new StreamPipeSource(file), options => options.ForceFormat("s16le"))
.OutputToPipe(new StreamPipeSink(memoryStream), options => options.ForceFormat("mp3")) .OutputToPipe(new StreamPipeSink(memoryStream), options => options.ForceFormat("mp3"))
.CancellableThrough(TestContext.CancellationToken)
.ProcessAsynchronously(); .ProcessAsynchronously();
} }
@ -70,7 +75,7 @@ public class AudioTest
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_ToAAC_Args_Pipe() public void Audio_ToAAC_Args_Pipe()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -83,12 +88,13 @@ public class AudioTest
.FromPipeInput(audioSamplesSource) .FromPipeInput(audioSamplesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithAudioCodec(AudioCodec.Aac)) .WithAudioCodec(AudioCodec.Aac))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_ToLibVorbis_Args_Pipe() public void Audio_ToLibVorbis_Args_Pipe()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -101,12 +107,13 @@ public class AudioTest
.FromPipeInput(audioSamplesSource) .FromPipeInput(audioSamplesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithAudioCodec(AudioCodec.LibVorbis)) .WithAudioCodec(AudioCodec.LibVorbis))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public async Task Audio_ToAAC_Args_Pipe_Async() public async Task Audio_ToAAC_Args_Pipe_Async()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -119,12 +126,13 @@ public class AudioTest
.FromPipeInput(audioSamplesSource) .FromPipeInput(audioSamplesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithAudioCodec(AudioCodec.Aac)) .WithAudioCodec(AudioCodec.Aac))
.CancellableThrough(TestContext.CancellationToken)
.ProcessAsynchronously(); .ProcessAsynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_ToAAC_Args_Pipe_ValidDefaultConfiguration() public void Audio_ToAAC_Args_Pipe_ValidDefaultConfiguration()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -137,12 +145,13 @@ public class AudioTest
.FromPipeInput(audioSamplesSource) .FromPipeInput(audioSamplesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithAudioCodec(AudioCodec.Aac)) .WithAudioCodec(AudioCodec.Aac))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_ToAAC_Args_Pipe_InvalidChannels() public void Audio_ToAAC_Args_Pipe_InvalidChannels()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -153,11 +162,12 @@ public class AudioTest
.FromPipeInput(audioSamplesSource) .FromPipeInput(audioSamplesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithAudioCodec(AudioCodec.Aac)) .WithAudioCodec(AudioCodec.Aac))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously()); .ProcessSynchronously());
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_ToAAC_Args_Pipe_InvalidFormat() public void Audio_ToAAC_Args_Pipe_InvalidFormat()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -168,11 +178,12 @@ public class AudioTest
.FromPipeInput(audioSamplesSource) .FromPipeInput(audioSamplesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithAudioCodec(AudioCodec.Aac)) .WithAudioCodec(AudioCodec.Aac))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously()); .ProcessSynchronously());
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_ToAAC_Args_Pipe_InvalidSampleRate() public void Audio_ToAAC_Args_Pipe_InvalidSampleRate()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -183,11 +194,12 @@ public class AudioTest
.FromPipeInput(audioSamplesSource) .FromPipeInput(audioSamplesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithAudioCodec(AudioCodec.Aac)) .WithAudioCodec(AudioCodec.Aac))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously()); .ProcessSynchronously());
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_Pan_ToMono() public void Audio_Pan_ToMono()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -196,6 +208,7 @@ public class AudioTest
.OutputToFile(outputFile, true, .OutputToFile(outputFile, true,
argumentOptions => argumentOptions argumentOptions => argumentOptions
.WithAudioFilters(filter => filter.Pan(1, "c0 < 0.9 * c0 + 0.1 * c1"))) .WithAudioFilters(filter => filter.Pan(1, "c0 < 0.9 * c0 + 0.1 * c1")))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
var mediaAnalysis = FFProbe.Analyse(outputFile); var mediaAnalysis = FFProbe.Analyse(outputFile);
@ -206,7 +219,7 @@ public class AudioTest
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_Pan_ToMonoNoDefinitions() public void Audio_Pan_ToMonoNoDefinitions()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -215,6 +228,7 @@ public class AudioTest
.OutputToFile(outputFile, true, .OutputToFile(outputFile, true,
argumentOptions => argumentOptions argumentOptions => argumentOptions
.WithAudioFilters(filter => filter.Pan(1))) .WithAudioFilters(filter => filter.Pan(1)))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
var mediaAnalysis = FFProbe.Analyse(outputFile); var mediaAnalysis = FFProbe.Analyse(outputFile);
@ -225,7 +239,7 @@ public class AudioTest
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_Pan_ToMonoChannelsToOutputDefinitionsMismatch() public void Audio_Pan_ToMonoChannelsToOutputDefinitionsMismatch()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -234,11 +248,12 @@ public class AudioTest
.OutputToFile(outputFile, true, .OutputToFile(outputFile, true,
argumentOptions => argumentOptions argumentOptions => argumentOptions
.WithAudioFilters(filter => filter.Pan(1, "c0=c0", "c1=c1"))) .WithAudioFilters(filter => filter.Pan(1, "c0=c0", "c1=c1")))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously()); .ProcessSynchronously());
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_Pan_ToMonoChannelsLayoutToOutputDefinitionsMismatch() public void Audio_Pan_ToMonoChannelsLayoutToOutputDefinitionsMismatch()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -247,11 +262,12 @@ public class AudioTest
.OutputToFile(outputFile, true, .OutputToFile(outputFile, true,
argumentOptions => argumentOptions argumentOptions => argumentOptions
.WithAudioFilters(filter => filter.Pan("mono", "c0=c0", "c1=c1"))) .WithAudioFilters(filter => filter.Pan("mono", "c0=c0", "c1=c1")))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously()); .ProcessSynchronously());
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_DynamicNormalizer_WithDefaultValues() public void Audio_DynamicNormalizer_WithDefaultValues()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -260,13 +276,14 @@ public class AudioTest
.OutputToFile(outputFile, true, .OutputToFile(outputFile, true,
argumentOptions => argumentOptions argumentOptions => argumentOptions
.WithAudioFilters(filter => filter.DynamicNormalizer())) .WithAudioFilters(filter => filter.DynamicNormalizer()))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Audio_DynamicNormalizer_WithNonDefaultValues() public void Audio_DynamicNormalizer_WithNonDefaultValues()
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -275,13 +292,14 @@ public class AudioTest
.OutputToFile(outputFile, true, .OutputToFile(outputFile, true,
argumentOptions => argumentOptions argumentOptions => argumentOptions
.WithAudioFilters(filter => filter.DynamicNormalizer(250, 7, 0.9, 2, 1, false, true, true, 0.5))) .WithAudioFilters(filter => filter.DynamicNormalizer(250, 7, 0.9, 2, 1, false, true, true, 0.5)))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
[TestMethod] [TestMethod]
[Timeout(10000, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
[DataRow(2)] [DataRow(2)]
[DataRow(32)] [DataRow(32)]
[DataRow(8)] [DataRow(8)]
@ -294,6 +312,7 @@ public class AudioTest
.OutputToFile(outputFile, true, .OutputToFile(outputFile, true,
argumentOptions => argumentOptions argumentOptions => argumentOptions
.WithAudioFilters(filter => filter.DynamicNormalizer(filterWindow: filterWindow))) .WithAudioFilters(filter => filter.DynamicNormalizer(filterWindow: filterWindow)))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously()); .ProcessSynchronously());
} }
} }

View file

@ -17,7 +17,7 @@ namespace FFMpegCore.Test;
[TestClass] [TestClass]
public class VideoTest public class VideoTest
{ {
private const int BaseTimeoutMilliseconds = 15_000; private const int BaseTimeoutMilliseconds = 60_000;
public TestContext TestContext { get; set; } public TestContext TestContext { get; set; }
@ -30,6 +30,7 @@ public class VideoTest
var success = FFMpegArguments var success = FFMpegArguments
.FromFileInput(TestResources.WebmVideo) .FromFileInput(TestResources.WebmVideo)
.OutputToFile(outputFile, false) .OutputToFile(outputFile, false)
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
@ -43,6 +44,7 @@ public class VideoTest
var success = FFMpegArguments var success = FFMpegArguments
.FromFileInput(TestResources.WebmVideo) .FromFileInput(TestResources.WebmVideo)
.OutputToFile(outputFile, false) .OutputToFile(outputFile, false)
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
@ -58,6 +60,7 @@ public class VideoTest
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithVideoCodec(VideoCodec.LibX264) .WithVideoCodec(VideoCodec.LibX264)
.ForcePixelFormat("yuv444p")) .ForcePixelFormat("yuv444p"))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
var analysis = FFProbe.Analyse(outputFile); var analysis = FFProbe.Analyse(outputFile);
@ -74,6 +77,7 @@ public class VideoTest
.FromFileInput(TestResources.WebmVideo) .FromFileInput(TestResources.WebmVideo)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithVideoCodec(VideoCodec.LibX264)) .WithVideoCodec(VideoCodec.LibX264))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
@ -88,6 +92,7 @@ public class VideoTest
.FromFileInput(TestResources.WebmVideo) .FromFileInput(TestResources.WebmVideo)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithVideoCodec(VideoCodec.LibX265)) .WithVideoCodec(VideoCodec.LibX265))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
@ -99,7 +104,7 @@ public class VideoTest
[DataRow(PixelFormat.Format32bppArgb)] [DataRow(PixelFormat.Format32bppArgb)]
public void Video_ToMP4_Args_Pipe_WindowsOnly(PixelFormat pixelFormat) public void Video_ToMP4_Args_Pipe_WindowsOnly(PixelFormat pixelFormat)
{ {
Video_ToMP4_Args_Pipe_Internal(pixelFormat); Video_ToMP4_Args_Pipe_Internal(pixelFormat, TestContext.CancellationToken);
} }
[TestMethod] [TestMethod]
@ -108,10 +113,10 @@ public class VideoTest
[DataRow(SKColorType.Bgra8888)] [DataRow(SKColorType.Bgra8888)]
public void Video_ToMP4_Args_Pipe(SKColorType pixelFormat) public void Video_ToMP4_Args_Pipe(SKColorType pixelFormat)
{ {
Video_ToMP4_Args_Pipe_Internal(pixelFormat); Video_ToMP4_Args_Pipe_Internal(pixelFormat, TestContext.CancellationToken);
} }
private static void Video_ToMP4_Args_Pipe_Internal(dynamic pixelFormat) private static void Video_ToMP4_Args_Pipe_Internal(dynamic pixelFormat, CancellationToken cancellationToken)
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -120,6 +125,7 @@ public class VideoTest
.FromPipeInput(videoFramesSource) .FromPipeInput(videoFramesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithVideoCodec(VideoCodec.LibX264)) .WithVideoCodec(VideoCodec.LibX264))
.CancellableThrough(cancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
@ -129,17 +135,17 @@ public class VideoTest
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly() public void Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly()
{ {
Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(PixelFormat.Format24bppRgb); Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(PixelFormat.Format24bppRgb, TestContext.CancellationToken);
} }
[TestMethod] [TestMethod]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Video_ToMP4_Args_Pipe_DifferentImageSizes() public void Video_ToMP4_Args_Pipe_DifferentImageSizes()
{ {
Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(SKColorType.Rgb565); Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(SKColorType.Rgb565, TestContext.CancellationToken);
} }
private static void Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(dynamic pixelFormat) private static void Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(dynamic pixelFormat, CancellationToken cancellationToken)
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -153,6 +159,7 @@ public class VideoTest
.FromPipeInput(videoFramesSource) .FromPipeInput(videoFramesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithVideoCodec(VideoCodec.LibX264)) .WithVideoCodec(VideoCodec.LibX264))
.CancellableThrough(cancellationToken)
.ProcessSynchronously()); .ProcessSynchronously());
} }
@ -161,17 +168,17 @@ public class VideoTest
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly_Async() public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly_Async()
{ {
await Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(PixelFormat.Format24bppRgb); await Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(PixelFormat.Format24bppRgb, TestContext.CancellationToken);
} }
[TestMethod] [TestMethod]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_Async() public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_Async()
{ {
await Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(SKColorType.Rgb565); await Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(SKColorType.Rgb565, TestContext.CancellationToken);
} }
private static async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(dynamic pixelFormat) private static async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(dynamic pixelFormat, CancellationToken cancellationToken)
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -185,6 +192,7 @@ public class VideoTest
.FromPipeInput(videoFramesSource) .FromPipeInput(videoFramesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithVideoCodec(VideoCodec.LibX264)) .WithVideoCodec(VideoCodec.LibX264))
.CancellableThrough(cancellationToken)
.ProcessAsynchronously()); .ProcessAsynchronously());
} }
@ -194,17 +202,18 @@ public class VideoTest
public void Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly() public void Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly()
{ {
Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(PixelFormat.Format24bppRgb, Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(PixelFormat.Format24bppRgb,
PixelFormat.Format32bppRgb); PixelFormat.Format32bppRgb, TestContext.CancellationToken);
} }
[TestMethod] [TestMethod]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Video_ToMP4_Args_Pipe_DifferentPixelFormats() public void Video_ToMP4_Args_Pipe_DifferentPixelFormats()
{ {
Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(SKColorType.Rgb565, SKColorType.Bgra8888); Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(SKColorType.Rgb565, SKColorType.Bgra8888, TestContext.CancellationToken);
} }
private static void Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(dynamic pixelFormatFrame1, dynamic pixelFormatFrame2) private static void Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(dynamic pixelFormatFrame1, dynamic pixelFormatFrame2,
CancellationToken cancellationToken)
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -218,6 +227,7 @@ public class VideoTest
.FromPipeInput(videoFramesSource) .FromPipeInput(videoFramesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithVideoCodec(VideoCodec.LibX264)) .WithVideoCodec(VideoCodec.LibX264))
.CancellableThrough(cancellationToken)
.ProcessSynchronously()); .ProcessSynchronously());
} }
@ -227,17 +237,18 @@ public class VideoTest
public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly_Async() public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly_Async()
{ {
await Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(PixelFormat.Format24bppRgb, await Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(PixelFormat.Format24bppRgb,
PixelFormat.Format32bppRgb); PixelFormat.Format32bppRgb, TestContext.CancellationToken);
} }
[TestMethod] [TestMethod]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_Async() public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_Async()
{ {
await Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(SKColorType.Rgb565, SKColorType.Bgra8888); await Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(SKColorType.Rgb565, SKColorType.Bgra8888, TestContext.CancellationToken);
} }
private static async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(dynamic pixelFormatFrame1, dynamic pixelFormatFrame2) private static async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(dynamic pixelFormatFrame1, dynamic pixelFormatFrame2,
CancellationToken cancellationToken)
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@ -251,6 +262,7 @@ public class VideoTest
.FromPipeInput(videoFramesSource) .FromPipeInput(videoFramesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithVideoCodec(VideoCodec.LibX264)) .WithVideoCodec(VideoCodec.LibX264))
.CancellableThrough(cancellationToken)
.ProcessAsynchronously()); .ProcessAsynchronously());
} }
@ -265,6 +277,7 @@ public class VideoTest
.FromPipeInput(new StreamPipeSource(input)) .FromPipeInput(new StreamPipeSource(input))
.OutputToFile(output, false, opt => opt .OutputToFile(output, false, opt => opt
.WithVideoCodec(VideoCodec.LibX264)) .WithVideoCodec(VideoCodec.LibX264))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
@ -280,6 +293,7 @@ public class VideoTest
await FFMpegArguments await FFMpegArguments
.FromFileInput(TestResources.Mp4Video) .FromFileInput(TestResources.Mp4Video)
.OutputToPipe(pipeSource, opt => opt.ForceFormat("mp4")) .OutputToPipe(pipeSource, opt => opt.ForceFormat("mp4"))
.CancellableThrough(TestContext.CancellationToken)
.ProcessAsynchronously(); .ProcessAsynchronously();
}); });
} }
@ -295,6 +309,7 @@ public class VideoTest
.ForceFormat("webm")) .ForceFormat("webm"))
.OutputToPipe(new StreamPipeSink(output), opt => opt .OutputToPipe(new StreamPipeSink(output), opt => opt
.ForceFormat("mpegts")) .ForceFormat("mpegts"))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
output.Position = 0; output.Position = 0;
@ -313,6 +328,7 @@ public class VideoTest
.FromFileInput(TestResources.Mp4Video) .FromFileInput(TestResources.Mp4Video)
.OutputToPipe(new StreamPipeSink(ms), opt => opt .OutputToPipe(new StreamPipeSink(ms), opt => opt
.ForceFormat("mkv")) .ForceFormat("mkv"))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
}); });
} }
@ -328,6 +344,7 @@ public class VideoTest
.OutputToPipe(pipeSource, opt => opt .OutputToPipe(pipeSource, opt => opt
.WithVideoCodec(VideoCodec.LibX264) .WithVideoCodec(VideoCodec.LibX264)
.ForceFormat("matroska")) .ForceFormat("matroska"))
.CancellableThrough(TestContext.CancellationToken)
.ProcessAsynchronously(); .ProcessAsynchronously();
} }
@ -338,11 +355,13 @@ public class VideoTest
FFMpegArguments FFMpegArguments
.FromFileInput(TestResources.Mp4Video) .FromFileInput(TestResources.Mp4Video)
.OutputToFile("temporary.mp4") .OutputToFile("temporary.mp4")
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
await FFMpegArguments await FFMpegArguments
.FromFileInput(TestResources.Mp4Video) .FromFileInput(TestResources.Mp4Video)
.OutputToFile("temporary.mp4") .OutputToFile("temporary.mp4")
.CancellableThrough(TestContext.CancellationToken)
.ProcessAsynchronously(); .ProcessAsynchronously();
File.Delete("temporary.mp4"); File.Delete("temporary.mp4");
@ -358,6 +377,7 @@ public class VideoTest
.OutputToPipe(new StreamPipeSink(output), opt => opt .OutputToPipe(new StreamPipeSink(output), opt => opt
.WithVideoCodec(VideoCodec.LibVpx) .WithVideoCodec(VideoCodec.LibVpx)
.ForceFormat("matroska")) .ForceFormat("matroska"))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
@ -376,6 +396,7 @@ public class VideoTest
var success = FFMpegArguments var success = FFMpegArguments
.FromFileInput(TestResources.Mp4Video) .FromFileInput(TestResources.Mp4Video)
.OutputToFile(outputFile, false) .OutputToFile(outputFile, false)
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
@ -392,6 +413,7 @@ public class VideoTest
.CopyChannel() .CopyChannel()
.WithBitStreamFilter(Channel.Video, Filter.H264_Mp4ToAnnexB) .WithBitStreamFilter(Channel.Video, Filter.H264_Mp4ToAnnexB)
.ForceFormat(VideoType.MpegTs)) .ForceFormat(VideoType.MpegTs))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
@ -403,7 +425,7 @@ public class VideoTest
[DataRow(PixelFormat.Format32bppArgb)] [DataRow(PixelFormat.Format32bppArgb)]
public async Task Video_ToTS_Args_Pipe_WindowsOnly(PixelFormat pixelFormat) public async Task Video_ToTS_Args_Pipe_WindowsOnly(PixelFormat pixelFormat)
{ {
await Video_ToTS_Args_Pipe_Internal(pixelFormat); await Video_ToTS_Args_Pipe_Internal(pixelFormat, TestContext.CancellationToken);
} }
[TestMethod] [TestMethod]
@ -412,10 +434,10 @@ public class VideoTest
[DataRow(SKColorType.Bgra8888)] [DataRow(SKColorType.Bgra8888)]
public async Task Video_ToTS_Args_Pipe(SKColorType pixelFormat) public async Task Video_ToTS_Args_Pipe(SKColorType pixelFormat)
{ {
await Video_ToTS_Args_Pipe_Internal(pixelFormat); await Video_ToTS_Args_Pipe_Internal(pixelFormat, TestContext.CancellationToken);
} }
private static async Task Video_ToTS_Args_Pipe_Internal(dynamic pixelFormat) private static async Task Video_ToTS_Args_Pipe_Internal(dynamic pixelFormat, CancellationToken cancellationToken)
{ {
using var output = new TemporaryFile($"out{VideoType.Ts.Extension}"); using var output = new TemporaryFile($"out{VideoType.Ts.Extension}");
var input = new RawVideoPipeSource(BitmapSource.CreateBitmaps(128, pixelFormat, 256, 256)); var input = new RawVideoPipeSource(BitmapSource.CreateBitmaps(128, pixelFormat, 256, 256));
@ -424,6 +446,7 @@ public class VideoTest
.FromPipeInput(input) .FromPipeInput(input)
.OutputToFile(output, false, opt => opt .OutputToFile(output, false, opt => opt
.ForceFormat(VideoType.Ts)) .ForceFormat(VideoType.Ts))
.CancellableThrough(cancellationToken)
.ProcessAsynchronously(); .ProcessAsynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
@ -441,6 +464,7 @@ public class VideoTest
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.Resize(200, 200) .Resize(200, 200)
.WithVideoCodec(VideoCodec.LibTheora)) .WithVideoCodec(VideoCodec.LibTheora))
.CancellableThrough(TestContext.CancellationToken)
.ProcessAsynchronously(); .ProcessAsynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
@ -461,6 +485,7 @@ public class VideoTest
.WithVideoFilters(filterOptions => filterOptions .WithVideoFilters(filterOptions => filterOptions
.Scale(VideoSize.Ed)) .Scale(VideoSize.Ed))
.WithVideoCodec(VideoCodec.LibTheora)) .WithVideoCodec(VideoCodec.LibTheora))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
var analysis = FFProbe.Analyse(outputFile); var analysis = FFProbe.Analyse(outputFile);
@ -478,6 +503,7 @@ public class VideoTest
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.UsingMultithreading(true) .UsingMultithreading(true)
.WithVideoCodec(VideoCodec.LibX264)) .WithVideoCodec(VideoCodec.LibX264))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
@ -490,7 +516,7 @@ public class VideoTest
// [DataRow(PixelFormat.Format48bppRgb)] // [DataRow(PixelFormat.Format48bppRgb)]
public void Video_ToMP4_Resize_Args_Pipe(PixelFormat pixelFormat) public void Video_ToMP4_Resize_Args_Pipe(PixelFormat pixelFormat)
{ {
Video_ToMP4_Resize_Args_Pipe_Internal(pixelFormat); Video_ToMP4_Resize_Args_Pipe_Internal(pixelFormat, TestContext.CancellationToken);
} }
[TestMethod] [TestMethod]
@ -499,10 +525,10 @@ public class VideoTest
[DataRow(SKColorType.Bgra8888)] [DataRow(SKColorType.Bgra8888)]
public void Video_ToMP4_Resize_Args_Pipe(SKColorType pixelFormat) public void Video_ToMP4_Resize_Args_Pipe(SKColorType pixelFormat)
{ {
Video_ToMP4_Resize_Args_Pipe_Internal(pixelFormat); Video_ToMP4_Resize_Args_Pipe_Internal(pixelFormat, TestContext.CancellationToken);
} }
private static void Video_ToMP4_Resize_Args_Pipe_Internal(dynamic pixelFormat) private static void Video_ToMP4_Resize_Args_Pipe_Internal(dynamic pixelFormat, CancellationToken cancellationToken)
{ {
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
var videoFramesSource = new RawVideoPipeSource(BitmapSource.CreateBitmaps(128, pixelFormat, 256, 256)); var videoFramesSource = new RawVideoPipeSource(BitmapSource.CreateBitmaps(128, pixelFormat, 256, 256));
@ -511,6 +537,7 @@ public class VideoTest
.FromPipeInput(videoFramesSource) .FromPipeInput(videoFramesSource)
.OutputToFile(outputFile, false, opt => opt .OutputToFile(outputFile, false, opt => opt
.WithVideoCodec(VideoCodec.LibX264)) .WithVideoCodec(VideoCodec.LibX264))
.CancellableThrough(cancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
} }
@ -764,6 +791,7 @@ public class VideoTest
FFMpegArguments FFMpegArguments
.FromFileInput(TestResources.Mp4Video) .FromFileInput(TestResources.Mp4Video)
.OutputToFile(outputFile, false, opt => opt.WithDuration(TimeSpan.FromSeconds(video.Duration.TotalSeconds - 2))) .OutputToFile(outputFile, false, opt => opt.WithDuration(TimeSpan.FromSeconds(video.Duration.TotalSeconds - 2)))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(File.Exists(outputFile)); Assert.IsTrue(File.Exists(outputFile));
@ -807,6 +835,7 @@ public class VideoTest
.WithDuration(analysis.Duration)) .WithDuration(analysis.Duration))
.NotifyOnProgress(OnPercentageProgess, analysis.Duration) .NotifyOnProgress(OnPercentageProgess, analysis.Duration)
.NotifyOnProgress(OnTimeProgess) .NotifyOnProgress(OnTimeProgess)
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(success); Assert.IsTrue(success);
@ -832,6 +861,7 @@ public class VideoTest
.WithDuration(TimeSpan.FromSeconds(2))) .WithDuration(TimeSpan.FromSeconds(2)))
.NotifyOnError(_ => dataReceived = true) .NotifyOnError(_ => dataReceived = true)
.Configure(opt => opt.Encoding = Encoding.UTF8) .Configure(opt => opt.Encoding = Encoding.UTF8)
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
Assert.IsTrue(dataReceived); Assert.IsTrue(dataReceived);
@ -844,17 +874,17 @@ public class VideoTest
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Video_TranscodeInMemory_WindowsOnly() public void Video_TranscodeInMemory_WindowsOnly()
{ {
Video_TranscodeInMemory_Internal(PixelFormat.Format24bppRgb); Video_TranscodeInMemory_Internal(PixelFormat.Format24bppRgb, TestContext.CancellationToken);
} }
[TestMethod] [TestMethod]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Video_TranscodeInMemory() public void Video_TranscodeInMemory()
{ {
Video_TranscodeInMemory_Internal(SKColorType.Rgb565); Video_TranscodeInMemory_Internal(SKColorType.Rgb565, TestContext.CancellationToken);
} }
private static void Video_TranscodeInMemory_Internal(dynamic pixelFormat) private static void Video_TranscodeInMemory_Internal(dynamic pixelFormat, CancellationToken cancellationToken)
{ {
using var resStream = new MemoryStream(); using var resStream = new MemoryStream();
var reader = new StreamPipeSink(resStream); var reader = new StreamPipeSink(resStream);
@ -865,6 +895,7 @@ public class VideoTest
.OutputToPipe(reader, opt => opt .OutputToPipe(reader, opt => opt
.WithVideoCodec("vp9") .WithVideoCodec("vp9")
.ForceFormat("webm")) .ForceFormat("webm"))
.CancellableThrough(cancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
resStream.Position = 0; resStream.Position = 0;
@ -884,6 +915,7 @@ public class VideoTest
.OutputToPipe(new StreamPipeSink(memoryStream), opt => opt .OutputToPipe(new StreamPipeSink(memoryStream), opt => opt
.WithVideoCodec("vp9") .WithVideoCodec("vp9")
.ForceFormat("webm")) .ForceFormat("webm"))
.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(); .ProcessSynchronously();
memoryStream.Position = 0; memoryStream.Position = 0;
@ -907,6 +939,8 @@ public class VideoTest
.WithVideoCodec(VideoCodec.LibX264) .WithVideoCodec(VideoCodec.LibX264)
.WithSpeedPreset(Speed.VeryFast)) .WithSpeedPreset(Speed.VeryFast))
.CancellableThrough(out var cancel) .CancellableThrough(out var cancel)
.CancellableThrough(TestContext.CancellationToken)
.CancellableThrough(TestContext.CancellationToken)
.ProcessAsynchronously(false); .ProcessAsynchronously(false);
await Task.Delay(300, TestContext.CancellationToken); await Task.Delay(300, TestContext.CancellationToken);
@ -930,11 +964,13 @@ public class VideoTest
.WithAudioCodec(AudioCodec.Aac) .WithAudioCodec(AudioCodec.Aac)
.WithVideoCodec(VideoCodec.LibX264) .WithVideoCodec(VideoCodec.LibX264)
.WithSpeedPreset(Speed.VeryFast)) .WithSpeedPreset(Speed.VeryFast))
.CancellableThrough(out var cancel); .CancellableThrough(out var cancel)
.CancellableThrough(TestContext.CancellationToken);
Task.Delay(300, TestContext.CancellationToken).ContinueWith(_ => cancel(), TestContext.CancellationToken); Task.Delay(300, TestContext.CancellationToken).ContinueWith(_ => cancel(), TestContext.CancellationToken);
var result = task.ProcessSynchronously(false); var result = task.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously(false);
Assert.IsFalse(result); Assert.IsFalse(result);
} }
@ -954,6 +990,7 @@ public class VideoTest
.WithVideoCodec(VideoCodec.LibX264) .WithVideoCodec(VideoCodec.LibX264)
.WithSpeedPreset(Speed.VeryFast)) .WithSpeedPreset(Speed.VeryFast))
.CancellableThrough(out var cancel, 10000) .CancellableThrough(out var cancel, 10000)
.CancellableThrough(TestContext.CancellationToken)
.ProcessAsynchronously(false); .ProcessAsynchronously(false);
await Task.Delay(300, TestContext.CancellationToken); await Task.Delay(300, TestContext.CancellationToken);
@ -987,6 +1024,7 @@ public class VideoTest
.WithVideoCodec(VideoCodec.LibX264) .WithVideoCodec(VideoCodec.LibX264)
.WithSpeedPreset(Speed.VeryFast)) .WithSpeedPreset(Speed.VeryFast))
.CancellableThrough(cts.Token) .CancellableThrough(cts.Token)
.CancellableThrough(TestContext.CancellationToken)
.ProcessAsynchronously(false); .ProcessAsynchronously(false);
cts.CancelAfter(300); cts.CancelAfter(300);
@ -1013,6 +1051,7 @@ public class VideoTest
.WithVideoCodec(VideoCodec.LibX264) .WithVideoCodec(VideoCodec.LibX264)
.WithSpeedPreset(Speed.VeryFast)) .WithSpeedPreset(Speed.VeryFast))
.CancellableThrough(cts.Token) .CancellableThrough(cts.Token)
.CancellableThrough(TestContext.CancellationToken)
.ProcessAsynchronously(); .ProcessAsynchronously();
cts.CancelAfter(300); cts.CancelAfter(300);
@ -1040,7 +1079,8 @@ public class VideoTest
cts.CancelAfter(300); cts.CancelAfter(300);
Assert.ThrowsExactly<OperationCanceledException>(() => task.ProcessSynchronously()); Assert.ThrowsExactly<OperationCanceledException>(() => task.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously());
} }
[TestMethod] [TestMethod]
@ -1062,7 +1102,8 @@ public class VideoTest
.WithSpeedPreset(Speed.VeryFast)) .WithSpeedPreset(Speed.VeryFast))
.CancellableThrough(cts.Token); .CancellableThrough(cts.Token);
Assert.ThrowsExactly<OperationCanceledException>(() => task.ProcessSynchronously()); Assert.ThrowsExactly<OperationCanceledException>(() => task.CancellableThrough(TestContext.CancellationToken)
.ProcessSynchronously());
} }
[TestMethod] [TestMethod]

View file

@ -10,7 +10,6 @@ namespace FFMpegCore;
public class FFMpegArgumentProcessor public class FFMpegArgumentProcessor
{ {
private static readonly Regex ProgressRegex = new(@"time=(\d\d:\d\d:\d\d.\d\d?)", RegexOptions.Compiled); private static readonly Regex ProgressRegex = new(@"time=(\d\d:\d\d:\d\d.\d\d?)", RegexOptions.Compiled);
private readonly CancellationTokenSource _cancellationTokenSource = new();
private readonly List<Action<FFOptions>> _configurations; private readonly List<Action<FFOptions>> _configurations;
private readonly FFMpegArguments _ffMpegArguments; private readonly FFMpegArguments _ffMpegArguments;
private CancellationTokenRegistration? _cancellationTokenRegistration; private CancellationTokenRegistration? _cancellationTokenRegistration;
@ -32,12 +31,6 @@ public class FFMpegArgumentProcessor
private event EventHandler<int> CancelEvent = null!; private event EventHandler<int> CancelEvent = null!;
~FFMpegArgumentProcessor()
{
_cancellationTokenSource.Dispose();
_cancellationTokenRegistration?.Dispose();
}
/// <summary> /// <summary>
/// Register action that will be invoked during the ffmpeg processing, when a progress time is output and parsed and progress percentage is /// Register action that will be invoked during the ffmpeg processing, when a progress time is output and parsed and progress percentage is
/// calculated. /// calculated.
@ -92,6 +85,7 @@ public class FFMpegArgumentProcessor
public FFMpegArgumentProcessor CancellableThrough(CancellationToken token, int timeout = 0) public FFMpegArgumentProcessor CancellableThrough(CancellationToken token, int timeout = 0)
{ {
_cancellationTokenRegistration?.Dispose();
_cancellationTokenRegistration = token.Register(() => Cancel(timeout)); _cancellationTokenRegistration = token.Register(() => Cancel(timeout));
return this; return this;
} }
@ -117,11 +111,12 @@ public class FFMpegArgumentProcessor
{ {
var options = GetConfiguredOptions(ffMpegOptions); var options = GetConfiguredOptions(ffMpegOptions);
var processArguments = PrepareProcessArguments(options); var processArguments = PrepareProcessArguments(options);
using var cancellationTokenSource = new CancellationTokenSource();
IProcessResult? processResult = null; IProcessResult? processResult = null;
try try
{ {
processResult = Process(processArguments).ConfigureAwait(false).GetAwaiter().GetResult(); processResult = Process(processArguments, cancellationTokenSource).ConfigureAwait(false).GetAwaiter().GetResult();
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@ -138,11 +133,12 @@ public class FFMpegArgumentProcessor
{ {
var options = GetConfiguredOptions(ffMpegOptions); var options = GetConfiguredOptions(ffMpegOptions);
var processArguments = PrepareProcessArguments(options); var processArguments = PrepareProcessArguments(options);
using var cancellationTokenSource = new CancellationTokenSource();
IProcessResult? processResult = null; IProcessResult? processResult = null;
try try
{ {
processResult = await Process(processArguments).ConfigureAwait(false); processResult = await Process(processArguments, cancellationTokenSource).ConfigureAwait(false);
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@ -155,11 +151,12 @@ public class FFMpegArgumentProcessor
return HandleCompletion(throwOnError, processResult?.ExitCode ?? -1, processResult?.ErrorData ?? Array.Empty<string>()); return HandleCompletion(throwOnError, processResult?.ExitCode ?? -1, processResult?.ErrorData ?? Array.Empty<string>());
} }
private async Task<IProcessResult> Process(ProcessArguments processArguments) private async Task<IProcessResult> Process(ProcessArguments processArguments, CancellationTokenSource cancellationTokenSource)
{ {
IProcessResult processResult = null!; IProcessResult processResult = null!;
if (_cancelled) if (_cancelled)
{ {
_cancellationTokenRegistration?.Dispose();
throw new OperationCanceledException("cancelled before starting processing"); throw new OperationCanceledException("cancelled before starting processing");
} }
@ -171,9 +168,9 @@ public class FFMpegArgumentProcessor
{ {
instance.SendInput("q"); instance.SendInput("q");
if (!_cancellationTokenSource.Token.WaitHandle.WaitOne(timeout, true)) if (!cancellationTokenSource.Token.WaitHandle.WaitOne(timeout, true))
{ {
_cancellationTokenSource.Cancel(); cancellationTokenSource.Cancel();
instance.Kill(); instance.Kill();
} }
} }
@ -185,12 +182,13 @@ public class FFMpegArgumentProcessor
await Task.WhenAll(instance.WaitForExitAsync().ContinueWith(t => await Task.WhenAll(instance.WaitForExitAsync().ContinueWith(t =>
{ {
processResult = t.Result; processResult = t.Result;
_cancellationTokenSource.Cancel(); cancellationTokenSource.Cancel();
_ffMpegArguments.Post(); _ffMpegArguments.Post();
}), _ffMpegArguments.During(_cancellationTokenSource.Token)).ConfigureAwait(false); }), _ffMpegArguments.During(cancellationTokenSource.Token)).ConfigureAwait(false);
if (_cancelled) if (_cancelled)
{ {
_cancellationTokenRegistration?.Dispose();
throw new OperationCanceledException("ffmpeg processing was cancelled"); throw new OperationCanceledException("ffmpeg processing was cancelled");
} }
@ -199,6 +197,7 @@ public class FFMpegArgumentProcessor
finally finally
{ {
CancelEvent -= OnCancelEvent; CancelEvent -= OnCancelEvent;
_cancellationTokenRegistration?.Dispose();
} }
} }