From 50cb183ae29959c354dc641aa320d18aa02b732f Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Tue, 2 Mar 2021 19:33:19 +0100 Subject: [PATCH] Add cancel timeout (cherry picked from commit 6383164f267516fbd50d50b2a511c15c25a168dc) Former-commit-id: 9672713e633ddcbaf7555e067bb7e7531624f444 --- FFMpegCore.Test/VideoTest.cs | 48 ++++++++++++++++---- FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs | 26 +++++++---- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/FFMpegCore.Test/VideoTest.cs b/FFMpegCore.Test/VideoTest.cs index eb5b46b..958f04e 100644 --- a/FFMpegCore.Test/VideoTest.cs +++ b/FFMpegCore.Test/VideoTest.cs @@ -12,6 +12,7 @@ using FFMpegCore.Arguments; using FFMpegCore.Exceptions; using FFMpegCore.Pipes; +using System.Threading; namespace FFMpegCore.Test { @@ -596,24 +597,55 @@ public void Video_TranscodeInMemory() public async Task Video_Cancel_Async() { var outputFile = new TemporaryFile("out.mp4"); - + var task = FFMpegArguments - .FromFileInput(TestResources.Mp4Video) + .FromFileInput("testsrc2=size=320x240[out0]; sine[out1]", false, args => args + .WithCustomArgument("-re") + .ForceFormat("lavfi")) .OutputToFile(outputFile, false, opt => opt - .Resize(new Size(1000, 1000)) .WithAudioCodec(AudioCodec.Aac) .WithVideoCodec(VideoCodec.LibX264) - .WithConstantRateFactor(14) - .WithSpeedPreset(Speed.VerySlow) - .Loop(3)) + .WithSpeedPreset(Speed.VeryFast)) .CancellableThrough(out var cancel) .ProcessAsynchronously(false); - + await Task.Delay(300); cancel(); - + var result = await task; + Assert.IsFalse(result); } + + [TestMethod, Timeout(10000)] + public async Task Video_Cancel_Async_With_Timeout() + { + var outputFile = new TemporaryFile("out.mp4"); + + var task = FFMpegArguments + .FromFileInput("testsrc2=size=320x240[out0]; sine[out1]", false, args => args + .WithCustomArgument("-re") + .ForceFormat("lavfi")) + .OutputToFile(outputFile, false, opt => opt + .WithAudioCodec(AudioCodec.Aac) + .WithVideoCodec(VideoCodec.LibX264) + .WithSpeedPreset(Speed.VeryFast)) + .CancellableThrough(out var cancel, 10000) + .ProcessAsynchronously(false); + + await Task.Delay(300); + cancel(); + + var result = await task; + + var outputInfo = FFProbe.Analyse(outputFile); + + Assert.IsTrue(result); + Assert.IsNotNull(outputInfo); + Assert.AreEqual(320, outputInfo.PrimaryVideoStream.Width); + Assert.AreEqual(240, outputInfo.PrimaryVideoStream.Height); + Assert.AreEqual("h264", outputInfo.PrimaryVideoStream.CodecName); + Assert.AreEqual("aac", outputInfo.PrimaryAudioStream.CodecName); + } } } diff --git a/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs b/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs index cfbe42a..5161fd4 100644 --- a/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs +++ b/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs @@ -27,7 +27,7 @@ internal FFMpegArgumentProcessor(FFMpegArguments ffMpegArguments) public string Arguments => _ffMpegArguments.Text; - private event EventHandler CancelEvent = null!; + private event EventHandler CancelEvent = null!; public FFMpegArgumentProcessor NotifyOnProgress(Action onPercentageProgress, TimeSpan totalTimeSpan) { @@ -45,9 +45,9 @@ public FFMpegArgumentProcessor NotifyOnOutput(Action onOutput) _onOutput = onOutput; return this; } - public FFMpegArgumentProcessor CancellableThrough(out Action cancel) + public FFMpegArgumentProcessor CancellableThrough(out Action cancel, int timeout = 0) { - cancel = () => CancelEvent?.Invoke(this, EventArgs.Empty); + cancel = () => CancelEvent?.Invoke(this, timeout); return this; } public bool ProcessSynchronously(bool throwOnError = true) @@ -55,11 +55,15 @@ public bool ProcessSynchronously(bool throwOnError = true) using var instance = PrepareInstance(out var cancellationTokenSource); var errorCode = -1; - void OnCancelEvent(object sender, EventArgs args) + void OnCancelEvent(object sender, int timeout) { instance.SendInput("q"); - cancellationTokenSource.Cancel(); - instance.Started = false; + + if (!cancellationTokenSource.Token.WaitHandle.WaitOne(timeout, true)) + { + cancellationTokenSource.Cancel(); + instance.Started = false; + } } CancelEvent += OnCancelEvent; instance.Exited += delegate { cancellationTokenSource.Cancel(); }; @@ -102,11 +106,15 @@ public async Task ProcessAsynchronously(bool throwOnError = true) using var instance = PrepareInstance(out var cancellationTokenSource); var errorCode = -1; - void OnCancelEvent(object sender, EventArgs args) + void OnCancelEvent(object sender, int timeout) { instance.SendInput("q"); - cancellationTokenSource.Cancel(); - instance.Started = false; + + if (!cancellationTokenSource.Token.WaitHandle.WaitOne(timeout, true)) + { + cancellationTokenSource.Cancel(); + instance.Started = false; + } } CancelEvent += OnCancelEvent;