mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2024-11-10 08:34:12 +01:00
Merge branch 'master' into refactor-video-filter-args
Former-commit-id: 8452672ee6
This commit is contained in:
commit
32e5e97864
4 changed files with 84 additions and 17 deletions
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
26
FFMpegCore/FFMpeg/Arguments/InputDeviceArgument.cs
Normal file
26
FFMpegCore/FFMpeg/Arguments/InputDeviceArgument.cs
Normal 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}";
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue