diff --git a/FFMpegCore.Test/AudioTest.cs b/FFMpegCore.Test/AudioTest.cs index 3960b9f..3172af7 100644 --- a/FFMpegCore.Test/AudioTest.cs +++ b/FFMpegCore.Test/AudioTest.cs @@ -9,6 +9,10 @@ namespace FFMpegCore.Test; [TestClass] public class AudioTest { + private const int BaseTimeoutMilliseconds = 30_000; + + public TestContext TestContext { get; set; } + [TestMethod] public void Audio_Remove() { @@ -41,6 +45,7 @@ public class AudioTest await FFMpegArguments .FromPipeInput(new StreamPipeSource(file), options => options.ForceFormat("s16le")) .OutputToPipe(new StreamPipeSink(memoryStream), options => options.ForceFormat("mp3")) + .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(); } @@ -70,7 +75,7 @@ public class AudioTest } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_ToAAC_Args_Pipe() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -83,12 +88,13 @@ public class AudioTest .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_ToLibVorbis_Args_Pipe() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -101,12 +107,13 @@ public class AudioTest .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.LibVorbis)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public async Task Audio_ToAAC_Args_Pipe_Async() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -119,12 +126,13 @@ public class AudioTest .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) + .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(); Assert.IsTrue(success); } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_ToAAC_Args_Pipe_ValidDefaultConfiguration() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -137,12 +145,13 @@ public class AudioTest .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_ToAAC_Args_Pipe_InvalidChannels() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -153,11 +162,12 @@ public class AudioTest .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_ToAAC_Args_Pipe_InvalidFormat() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -168,11 +178,12 @@ public class AudioTest .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_ToAAC_Args_Pipe_InvalidSampleRate() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -183,11 +194,12 @@ public class AudioTest .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_Pan_ToMono() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -196,6 +208,7 @@ public class AudioTest .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.Pan(1, "c0 < 0.9 * c0 + 0.1 * c1"))) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); var mediaAnalysis = FFProbe.Analyse(outputFile); @@ -206,7 +219,7 @@ public class AudioTest } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_Pan_ToMonoNoDefinitions() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -215,6 +228,7 @@ public class AudioTest .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.Pan(1))) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); var mediaAnalysis = FFProbe.Analyse(outputFile); @@ -225,7 +239,7 @@ public class AudioTest } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_Pan_ToMonoChannelsToOutputDefinitionsMismatch() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -234,11 +248,12 @@ public class AudioTest .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.Pan(1, "c0=c0", "c1=c1"))) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_Pan_ToMonoChannelsLayoutToOutputDefinitionsMismatch() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -247,11 +262,12 @@ public class AudioTest .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.Pan("mono", "c0=c0", "c1=c1"))) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_DynamicNormalizer_WithDefaultValues() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -260,13 +276,14 @@ public class AudioTest .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.DynamicNormalizer())) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Audio_DynamicNormalizer_WithNonDefaultValues() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); @@ -275,13 +292,14 @@ public class AudioTest .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.DynamicNormalizer(250, 7, 0.9, 2, 1, false, true, true, 0.5))) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } [TestMethod] - [Timeout(10000, CooperativeCancellation = true)] + [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] [DataRow(2)] [DataRow(32)] [DataRow(8)] @@ -294,6 +312,7 @@ public class AudioTest .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.DynamicNormalizer(filterWindow: filterWindow))) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } } diff --git a/FFMpegCore.Test/VideoTest.cs b/FFMpegCore.Test/VideoTest.cs index 5921a6e..626e00c 100644 --- a/FFMpegCore.Test/VideoTest.cs +++ b/FFMpegCore.Test/VideoTest.cs @@ -17,7 +17,7 @@ namespace FFMpegCore.Test; [TestClass] public class VideoTest { - private const int BaseTimeoutMilliseconds = 15_000; + private const int BaseTimeoutMilliseconds = 60_000; public TestContext TestContext { get; set; } @@ -30,6 +30,7 @@ public class VideoTest var success = FFMpegArguments .FromFileInput(TestResources.WebmVideo) .OutputToFile(outputFile, false) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } @@ -43,6 +44,7 @@ public class VideoTest var success = FFMpegArguments .FromFileInput(TestResources.WebmVideo) .OutputToFile(outputFile, false) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } @@ -58,6 +60,7 @@ public class VideoTest .OutputToFile(outputFile, false, opt => opt .WithVideoCodec(VideoCodec.LibX264) .ForcePixelFormat("yuv444p")) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); var analysis = FFProbe.Analyse(outputFile); @@ -74,6 +77,7 @@ public class VideoTest .FromFileInput(TestResources.WebmVideo) .OutputToFile(outputFile, false, opt => opt .WithVideoCodec(VideoCodec.LibX264)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } @@ -88,6 +92,7 @@ public class VideoTest .FromFileInput(TestResources.WebmVideo) .OutputToFile(outputFile, false, opt => opt .WithVideoCodec(VideoCodec.LibX265)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } @@ -99,7 +104,7 @@ public class VideoTest [DataRow(PixelFormat.Format32bppArgb)] public void Video_ToMP4_Args_Pipe_WindowsOnly(PixelFormat pixelFormat) { - Video_ToMP4_Args_Pipe_Internal(pixelFormat); + Video_ToMP4_Args_Pipe_Internal(pixelFormat, TestContext.CancellationToken); } [TestMethod] @@ -108,10 +113,10 @@ public class VideoTest [DataRow(SKColorType.Bgra8888)] 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}"); @@ -120,6 +125,7 @@ public class VideoTest .FromPipeInput(videoFramesSource) .OutputToFile(outputFile, false, opt => opt .WithVideoCodec(VideoCodec.LibX264)) + .CancellableThrough(cancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } @@ -129,17 +135,17 @@ public class VideoTest [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] 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] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] 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}"); @@ -153,6 +159,7 @@ public class VideoTest .FromPipeInput(videoFramesSource) .OutputToFile(outputFile, false, opt => opt .WithVideoCodec(VideoCodec.LibX264)) + .CancellableThrough(cancellationToken) .ProcessSynchronously()); } @@ -161,17 +168,17 @@ public class VideoTest [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] 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] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] 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}"); @@ -185,6 +192,7 @@ public class VideoTest .FromPipeInput(videoFramesSource) .OutputToFile(outputFile, false, opt => opt .WithVideoCodec(VideoCodec.LibX264)) + .CancellableThrough(cancellationToken) .ProcessAsynchronously()); } @@ -194,17 +202,18 @@ public class VideoTest public void Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly() { Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(PixelFormat.Format24bppRgb, - PixelFormat.Format32bppRgb); + PixelFormat.Format32bppRgb, TestContext.CancellationToken); } [TestMethod] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] 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}"); @@ -218,6 +227,7 @@ public class VideoTest .FromPipeInput(videoFramesSource) .OutputToFile(outputFile, false, opt => opt .WithVideoCodec(VideoCodec.LibX264)) + .CancellableThrough(cancellationToken) .ProcessSynchronously()); } @@ -227,17 +237,18 @@ public class VideoTest public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly_Async() { await Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(PixelFormat.Format24bppRgb, - PixelFormat.Format32bppRgb); + PixelFormat.Format32bppRgb, TestContext.CancellationToken); } [TestMethod] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] 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}"); @@ -251,6 +262,7 @@ public class VideoTest .FromPipeInput(videoFramesSource) .OutputToFile(outputFile, false, opt => opt .WithVideoCodec(VideoCodec.LibX264)) + .CancellableThrough(cancellationToken) .ProcessAsynchronously()); } @@ -265,6 +277,7 @@ public class VideoTest .FromPipeInput(new StreamPipeSource(input)) .OutputToFile(output, false, opt => opt .WithVideoCodec(VideoCodec.LibX264)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } @@ -280,6 +293,7 @@ public class VideoTest await FFMpegArguments .FromFileInput(TestResources.Mp4Video) .OutputToPipe(pipeSource, opt => opt.ForceFormat("mp4")) + .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(); }); } @@ -295,6 +309,7 @@ public class VideoTest .ForceFormat("webm")) .OutputToPipe(new StreamPipeSink(output), opt => opt .ForceFormat("mpegts")) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); output.Position = 0; @@ -313,6 +328,7 @@ public class VideoTest .FromFileInput(TestResources.Mp4Video) .OutputToPipe(new StreamPipeSink(ms), opt => opt .ForceFormat("mkv")) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); }); } @@ -328,6 +344,7 @@ public class VideoTest .OutputToPipe(pipeSource, opt => opt .WithVideoCodec(VideoCodec.LibX264) .ForceFormat("matroska")) + .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(); } @@ -338,11 +355,13 @@ public class VideoTest FFMpegArguments .FromFileInput(TestResources.Mp4Video) .OutputToFile("temporary.mp4") + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); await FFMpegArguments .FromFileInput(TestResources.Mp4Video) .OutputToFile("temporary.mp4") + .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(); File.Delete("temporary.mp4"); @@ -358,6 +377,7 @@ public class VideoTest .OutputToPipe(new StreamPipeSink(output), opt => opt .WithVideoCodec(VideoCodec.LibVpx) .ForceFormat("matroska")) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); @@ -376,6 +396,7 @@ public class VideoTest var success = FFMpegArguments .FromFileInput(TestResources.Mp4Video) .OutputToFile(outputFile, false) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } @@ -392,6 +413,7 @@ public class VideoTest .CopyChannel() .WithBitStreamFilter(Channel.Video, Filter.H264_Mp4ToAnnexB) .ForceFormat(VideoType.MpegTs)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } @@ -403,7 +425,7 @@ public class VideoTest [DataRow(PixelFormat.Format32bppArgb)] 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] @@ -412,10 +434,10 @@ public class VideoTest [DataRow(SKColorType.Bgra8888)] 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}"); var input = new RawVideoPipeSource(BitmapSource.CreateBitmaps(128, pixelFormat, 256, 256)); @@ -424,6 +446,7 @@ public class VideoTest .FromPipeInput(input) .OutputToFile(output, false, opt => opt .ForceFormat(VideoType.Ts)) + .CancellableThrough(cancellationToken) .ProcessAsynchronously(); Assert.IsTrue(success); @@ -441,6 +464,7 @@ public class VideoTest .OutputToFile(outputFile, false, opt => opt .Resize(200, 200) .WithVideoCodec(VideoCodec.LibTheora)) + .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(); Assert.IsTrue(success); } @@ -461,6 +485,7 @@ public class VideoTest .WithVideoFilters(filterOptions => filterOptions .Scale(VideoSize.Ed)) .WithVideoCodec(VideoCodec.LibTheora)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); var analysis = FFProbe.Analyse(outputFile); @@ -478,6 +503,7 @@ public class VideoTest .OutputToFile(outputFile, false, opt => opt .UsingMultithreading(true) .WithVideoCodec(VideoCodec.LibX264)) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } @@ -490,7 +516,7 @@ public class VideoTest // [DataRow(PixelFormat.Format48bppRgb)] 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] @@ -499,10 +525,10 @@ public class VideoTest [DataRow(SKColorType.Bgra8888)] 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}"); var videoFramesSource = new RawVideoPipeSource(BitmapSource.CreateBitmaps(128, pixelFormat, 256, 256)); @@ -511,6 +537,7 @@ public class VideoTest .FromPipeInput(videoFramesSource) .OutputToFile(outputFile, false, opt => opt .WithVideoCodec(VideoCodec.LibX264)) + .CancellableThrough(cancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } @@ -764,6 +791,7 @@ public class VideoTest FFMpegArguments .FromFileInput(TestResources.Mp4Video) .OutputToFile(outputFile, false, opt => opt.WithDuration(TimeSpan.FromSeconds(video.Duration.TotalSeconds - 2))) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(File.Exists(outputFile)); @@ -807,6 +835,7 @@ public class VideoTest .WithDuration(analysis.Duration)) .NotifyOnProgress(OnPercentageProgess, analysis.Duration) .NotifyOnProgress(OnTimeProgess) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); @@ -832,6 +861,7 @@ public class VideoTest .WithDuration(TimeSpan.FromSeconds(2))) .NotifyOnError(_ => dataReceived = true) .Configure(opt => opt.Encoding = Encoding.UTF8) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(dataReceived); @@ -844,17 +874,17 @@ public class VideoTest [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] public void Video_TranscodeInMemory_WindowsOnly() { - Video_TranscodeInMemory_Internal(PixelFormat.Format24bppRgb); + Video_TranscodeInMemory_Internal(PixelFormat.Format24bppRgb, TestContext.CancellationToken); } [TestMethod] [Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)] 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(); var reader = new StreamPipeSink(resStream); @@ -865,6 +895,7 @@ public class VideoTest .OutputToPipe(reader, opt => opt .WithVideoCodec("vp9") .ForceFormat("webm")) + .CancellableThrough(cancellationToken) .ProcessSynchronously(); resStream.Position = 0; @@ -884,6 +915,7 @@ public class VideoTest .OutputToPipe(new StreamPipeSink(memoryStream), opt => opt .WithVideoCodec("vp9") .ForceFormat("webm")) + .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); memoryStream.Position = 0; @@ -907,6 +939,8 @@ public class VideoTest .WithVideoCodec(VideoCodec.LibX264) .WithSpeedPreset(Speed.VeryFast)) .CancellableThrough(out var cancel) + .CancellableThrough(TestContext.CancellationToken) + .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(false); await Task.Delay(300, TestContext.CancellationToken); @@ -930,11 +964,13 @@ public class VideoTest .WithAudioCodec(AudioCodec.Aac) .WithVideoCodec(VideoCodec.LibX264) .WithSpeedPreset(Speed.VeryFast)) - .CancellableThrough(out var cancel); + .CancellableThrough(out var cancel) + .CancellableThrough(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); } @@ -954,6 +990,7 @@ public class VideoTest .WithVideoCodec(VideoCodec.LibX264) .WithSpeedPreset(Speed.VeryFast)) .CancellableThrough(out var cancel, 10000) + .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(false); await Task.Delay(300, TestContext.CancellationToken); @@ -987,6 +1024,7 @@ public class VideoTest .WithVideoCodec(VideoCodec.LibX264) .WithSpeedPreset(Speed.VeryFast)) .CancellableThrough(cts.Token) + .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(false); cts.CancelAfter(300); @@ -1013,6 +1051,7 @@ public class VideoTest .WithVideoCodec(VideoCodec.LibX264) .WithSpeedPreset(Speed.VeryFast)) .CancellableThrough(cts.Token) + .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(); cts.CancelAfter(300); @@ -1040,7 +1079,8 @@ public class VideoTest cts.CancelAfter(300); - Assert.ThrowsExactly(() => task.ProcessSynchronously()); + Assert.ThrowsExactly(() => task.CancellableThrough(TestContext.CancellationToken) + .ProcessSynchronously()); } [TestMethod] @@ -1062,7 +1102,8 @@ public class VideoTest .WithSpeedPreset(Speed.VeryFast)) .CancellableThrough(cts.Token); - Assert.ThrowsExactly(() => task.ProcessSynchronously()); + Assert.ThrowsExactly(() => task.CancellableThrough(TestContext.CancellationToken) + .ProcessSynchronously()); } [TestMethod] diff --git a/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs b/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs index 0aa31ca..2f350ce 100644 --- a/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs +++ b/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs @@ -10,7 +10,6 @@ namespace FFMpegCore; public class FFMpegArgumentProcessor { 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> _configurations; private readonly FFMpegArguments _ffMpegArguments; private CancellationTokenRegistration? _cancellationTokenRegistration; @@ -32,12 +31,6 @@ public class FFMpegArgumentProcessor private event EventHandler CancelEvent = null!; - ~FFMpegArgumentProcessor() - { - _cancellationTokenSource.Dispose(); - _cancellationTokenRegistration?.Dispose(); - } - /// /// Register action that will be invoked during the ffmpeg processing, when a progress time is output and parsed and progress percentage is /// calculated. @@ -92,6 +85,7 @@ public class FFMpegArgumentProcessor public FFMpegArgumentProcessor CancellableThrough(CancellationToken token, int timeout = 0) { + _cancellationTokenRegistration?.Dispose(); _cancellationTokenRegistration = token.Register(() => Cancel(timeout)); return this; } @@ -117,11 +111,12 @@ public class FFMpegArgumentProcessor { var options = GetConfiguredOptions(ffMpegOptions); var processArguments = PrepareProcessArguments(options); + using var cancellationTokenSource = new CancellationTokenSource(); IProcessResult? processResult = null; try { - processResult = Process(processArguments).ConfigureAwait(false).GetAwaiter().GetResult(); + processResult = Process(processArguments, cancellationTokenSource).ConfigureAwait(false).GetAwaiter().GetResult(); } catch (OperationCanceledException) { @@ -138,11 +133,12 @@ public class FFMpegArgumentProcessor { var options = GetConfiguredOptions(ffMpegOptions); var processArguments = PrepareProcessArguments(options); + using var cancellationTokenSource = new CancellationTokenSource(); IProcessResult? processResult = null; try { - processResult = await Process(processArguments).ConfigureAwait(false); + processResult = await Process(processArguments, cancellationTokenSource).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -155,11 +151,12 @@ public class FFMpegArgumentProcessor return HandleCompletion(throwOnError, processResult?.ExitCode ?? -1, processResult?.ErrorData ?? Array.Empty()); } - private async Task Process(ProcessArguments processArguments) + private async Task Process(ProcessArguments processArguments, CancellationTokenSource cancellationTokenSource) { IProcessResult processResult = null!; if (_cancelled) { + _cancellationTokenRegistration?.Dispose(); throw new OperationCanceledException("cancelled before starting processing"); } @@ -171,9 +168,9 @@ public class FFMpegArgumentProcessor { instance.SendInput("q"); - if (!_cancellationTokenSource.Token.WaitHandle.WaitOne(timeout, true)) + if (!cancellationTokenSource.Token.WaitHandle.WaitOne(timeout, true)) { - _cancellationTokenSource.Cancel(); + cancellationTokenSource.Cancel(); instance.Kill(); } } @@ -185,12 +182,13 @@ public class FFMpegArgumentProcessor await Task.WhenAll(instance.WaitForExitAsync().ContinueWith(t => { processResult = t.Result; - _cancellationTokenSource.Cancel(); + cancellationTokenSource.Cancel(); _ffMpegArguments.Post(); - }), _ffMpegArguments.During(_cancellationTokenSource.Token)).ConfigureAwait(false); + }), _ffMpegArguments.During(cancellationTokenSource.Token)).ConfigureAwait(false); if (_cancelled) { + _cancellationTokenRegistration?.Dispose(); throw new OperationCanceledException("ffmpeg processing was cancelled"); } @@ -199,6 +197,7 @@ public class FFMpegArgumentProcessor finally { CancelEvent -= OnCancelEvent; + _cancellationTokenRegistration?.Dispose(); } }