From 22340a457566a1fecd64623bacd32aa959099251 Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Sun, 28 Feb 2021 14:50:55 +0100 Subject: [PATCH 1/2] Add InputDeviceArgument Former-commit-id: 73531b394742ab4d67098712109a0df7ae8247cb --- .../FFMpeg/Arguments/InputDeviceArgument.cs | 26 +++++++++++++++++++ FFMpegCore/FFMpeg/FFMpegArguments.cs | 1 + 2 files changed, 27 insertions(+) create mode 100644 FFMpegCore/FFMpeg/Arguments/InputDeviceArgument.cs diff --git a/FFMpegCore/FFMpeg/Arguments/InputDeviceArgument.cs b/FFMpegCore/FFMpeg/Arguments/InputDeviceArgument.cs new file mode 100644 index 0000000..f276bbb --- /dev/null +++ b/FFMpegCore/FFMpeg/Arguments/InputDeviceArgument.cs @@ -0,0 +1,26 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace FFMpegCore.Arguments +{ + /// + /// Represents an input device parameter + /// + public class InputDeviceArgument : IInputArgument + { + private readonly string Device; + + public InputDeviceArgument(string device) + { + Device = device; + } + + public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask; + + public void Pre() { } + + public void Post() { } + + public string Text => $"-i {Device}"; + } +} diff --git a/FFMpegCore/FFMpeg/FFMpegArguments.cs b/FFMpegCore/FFMpeg/FFMpegArguments.cs index 44e20d2..8d62db0 100644 --- a/FFMpegCore/FFMpeg/FFMpegArguments.cs +++ b/FFMpegCore/FFMpeg/FFMpegArguments.cs @@ -23,6 +23,7 @@ private FFMpegArguments() { } public static FFMpegArguments FromFileInput(FileInfo fileInfo, Action? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(fileInfo.FullName, false), addArguments); public static FFMpegArguments FromFileInput(IMediaAnalysis mediaAnalysis, Action? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(mediaAnalysis.Path, false), addArguments); public static FFMpegArguments FromUrlInput(Uri uri, Action? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(uri.AbsoluteUri, false), addArguments); + public static FFMpegArguments FromDeviceInput(string device, Action? addArguments = null) => new FFMpegArguments().WithInput(new InputDeviceArgument(device), addArguments); public static FFMpegArguments FromPipeInput(IPipeSource sourcePipe, Action? addArguments = null) => new FFMpegArguments().WithInput(new InputPipeArgument(sourcePipe), addArguments); From 50cb183ae29959c354dc641aa320d18aa02b732f Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Tue, 2 Mar 2021 19:33:19 +0100 Subject: [PATCH 2/2] 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;