Merge branch 'master' into refactor-video-filter-args

Former-commit-id: 8452672ee6
This commit is contained in:
Malte Rosenbjerg 2021-03-05 18:06:50 +01:00
commit 32e5e97864
4 changed files with 84 additions and 17 deletions

View file

@ -12,6 +12,7 @@
using FFMpegCore.Arguments; using FFMpegCore.Arguments;
using FFMpegCore.Exceptions; using FFMpegCore.Exceptions;
using FFMpegCore.Pipes; using FFMpegCore.Pipes;
using System.Threading;
namespace FFMpegCore.Test namespace FFMpegCore.Test
{ {
@ -553,14 +554,13 @@ public async Task Video_Cancel_Async()
var outputFile = new TemporaryFile("out.mp4"); var outputFile = new TemporaryFile("out.mp4");
var task = FFMpegArguments 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 .OutputToFile(outputFile, false, opt => opt
.Resize(new Size(1000, 1000))
.WithAudioCodec(AudioCodec.Aac) .WithAudioCodec(AudioCodec.Aac)
.WithVideoCodec(VideoCodec.LibX264) .WithVideoCodec(VideoCodec.LibX264)
.WithConstantRateFactor(14) .WithSpeedPreset(Speed.VeryFast))
.WithSpeedPreset(Speed.VerySlow)
.Loop(3))
.CancellableThrough(out var cancel) .CancellableThrough(out var cancel)
.ProcessAsynchronously(false); .ProcessAsynchronously(false);
@ -568,7 +568,39 @@ public async Task Video_Cancel_Async()
cancel(); cancel();
var result = await task; var result = await task;
Assert.IsFalse(result); 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);
}
} }
} }

View file

@ -0,0 +1,26 @@
using System.Threading;
using System.Threading.Tasks;
namespace FFMpegCore.Arguments
{
/// <summary>
/// Represents an input device parameter
/// </summary>
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}";
}
}

View file

@ -27,7 +27,7 @@ internal FFMpegArgumentProcessor(FFMpegArguments ffMpegArguments)
public string Arguments => _ffMpegArguments.Text; public string Arguments => _ffMpegArguments.Text;
private event EventHandler CancelEvent = null!; private event EventHandler<int> CancelEvent = null!;
public FFMpegArgumentProcessor NotifyOnProgress(Action<double> onPercentageProgress, TimeSpan totalTimeSpan) public FFMpegArgumentProcessor NotifyOnProgress(Action<double> onPercentageProgress, TimeSpan totalTimeSpan)
{ {
@ -45,9 +45,9 @@ public FFMpegArgumentProcessor NotifyOnOutput(Action<string, DataType> onOutput)
_onOutput = onOutput; _onOutput = onOutput;
return this; 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; return this;
} }
public bool ProcessSynchronously(bool throwOnError = true) public bool ProcessSynchronously(bool throwOnError = true)
@ -55,11 +55,15 @@ public bool ProcessSynchronously(bool throwOnError = true)
using var instance = PrepareInstance(out var cancellationTokenSource); using var instance = PrepareInstance(out var cancellationTokenSource);
var errorCode = -1; var errorCode = -1;
void OnCancelEvent(object sender, EventArgs args) void OnCancelEvent(object sender, int timeout)
{ {
instance.SendInput("q"); instance.SendInput("q");
cancellationTokenSource.Cancel();
instance.Started = false; if (!cancellationTokenSource.Token.WaitHandle.WaitOne(timeout, true))
{
cancellationTokenSource.Cancel();
instance.Started = false;
}
} }
CancelEvent += OnCancelEvent; CancelEvent += OnCancelEvent;
instance.Exited += delegate { cancellationTokenSource.Cancel(); }; instance.Exited += delegate { cancellationTokenSource.Cancel(); };
@ -102,11 +106,15 @@ public async Task<bool> ProcessAsynchronously(bool throwOnError = true)
using var instance = PrepareInstance(out var cancellationTokenSource); using var instance = PrepareInstance(out var cancellationTokenSource);
var errorCode = -1; var errorCode = -1;
void OnCancelEvent(object sender, EventArgs args) void OnCancelEvent(object sender, int timeout)
{ {
instance.SendInput("q"); instance.SendInput("q");
cancellationTokenSource.Cancel();
instance.Started = false; if (!cancellationTokenSource.Token.WaitHandle.WaitOne(timeout, true))
{
cancellationTokenSource.Cancel();
instance.Started = false;
}
} }
CancelEvent += OnCancelEvent; CancelEvent += OnCancelEvent;

View file

@ -22,6 +22,7 @@ private FFMpegArguments() { }
public static FFMpegArguments FromFileInput(string filePath, bool verifyExists = true, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(verifyExists, filePath), addArguments); public static FFMpegArguments FromFileInput(string filePath, bool verifyExists = true, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(verifyExists, filePath), addArguments);
public static FFMpegArguments FromFileInput(FileInfo fileInfo, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(fileInfo.FullName, false), addArguments); public static FFMpegArguments FromFileInput(FileInfo fileInfo, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(fileInfo.FullName, false), addArguments);
public static FFMpegArguments FromUrlInput(Uri uri, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(uri.AbsoluteUri, false), addArguments); public static FFMpegArguments FromUrlInput(Uri uri, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(uri.AbsoluteUri, false), addArguments);
public static FFMpegArguments FromDeviceInput(string device, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputDeviceArgument(device), addArguments);
public static FFMpegArguments FromPipeInput(IPipeSource sourcePipe, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputPipeArgument(sourcePipe), addArguments); public static FFMpegArguments FromPipeInput(IPipeSource sourcePipe, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputPipeArgument(sourcePipe), addArguments);