diff --git a/src/FFmpeg.NET/Engine.cs b/src/FFmpeg.NET/Engine.cs old mode 100644 new mode 100755 index 6b7bffa..69f75f7 --- a/src/FFmpeg.NET/Engine.cs +++ b/src/FFmpeg.NET/Engine.cs @@ -31,6 +31,11 @@ public Engine(string ffmpegPath = null) public event EventHandler Complete; public event EventHandler Data; + + // --------------------------------------------------------- + // Wrapper methods for ease of use + // --------------------------------------------------------- + public async Task GetMetaDataAsync(IInputArgument mediaFile, CancellationToken cancellationToken) { var parameters = new FFmpegParameters @@ -87,83 +92,82 @@ public async Task ConvertAsync(IInputArgument input, ConversionOptions o public async Task ConvertAsync(IInputArgument input, Stream output, ConversionOptions options, CancellationToken cancellationToken) { - var pipeName = $"{_pipePrefix}{Guid.NewGuid()}"; var parameters = new FFmpegParameters { Task = FFmpegTask.Convert, Input = input, - Output = new OutputPipe(GetPipePath(pipeName)), ConversionOptions = options }; - - var process = CreateProcess(parameters); - var pipe = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); - - await pipe.WaitForConnectionAsync(cancellationToken); - await Task.WhenAll( - pipe.CopyToAsync(output, cancellationToken), - process.ExecuteAsync(cancellationToken).ContinueWith(x => - { - pipe.Disconnect(); - pipe.Dispose(); - }, cancellationToken) - ).ConfigureAwait(false); - Cleanup(process); + await ExecuteAsync(parameters, output, cancellationToken).ConfigureAwait(false); } public async Task ConvertAsync(IArgument argument, Stream output, CancellationToken cancellationToken) { - var outputPipeName = $"{_pipePrefix}{Guid.NewGuid()}"; - var outputArgument = new OutputPipe(GetPipePath(outputPipeName)); - var pipe = new NamedPipeServerStream(outputPipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); - - var arguments = argument.Argument + $" {outputArgument.Argument}"; - var parameters = new FFmpegParameters { CustomArguments = arguments }; - var process = CreateProcess(parameters); - - await Task.WhenAll( - pipe.WaitForConnectionAsync(cancellationToken).ContinueWith(async x => - { - await pipe.CopyToAsync(output, cancellationToken); - }), - process.ExecuteAsync(cancellationToken).ContinueWith(x => - { - pipe.Disconnect(); - pipe.Dispose(); - }, cancellationToken) - ).ConfigureAwait(false); - - Cleanup(process); - } - - private async Task ExecuteAsync(FFmpegParameters parameters, CancellationToken cancellationToken) - { - var ffmpegProcess = CreateProcess(parameters); - await ffmpegProcess.ExecuteAsync(cancellationToken).ConfigureAwait(false); - Cleanup(ffmpegProcess); + var parameters = new FFmpegParameters + { + Task = FFmpegTask.Execute, + CustomArguments = argument.Argument + }; + await ExecuteAsync(parameters, output, cancellationToken).ConfigureAwait(false); } public async Task ExecuteAsync(string arguments, CancellationToken cancellationToken) { var parameters = new FFmpegParameters { + Task = FFmpegTask.Execute, CustomArguments = arguments, }; await ExecuteAsync(parameters, cancellationToken).ConfigureAwait(false); } - // if further overloads are needed - // it should be considered if ExecuteAsync(FFmpegParameters parameters, CancellationToken cancellationToken) should be made public public async Task ExecuteAsync(string arguments, string workingDirectory, CancellationToken cancellationToken) { var parameters = new FFmpegParameters { + Task = FFmpegTask.Execute, CustomArguments = arguments, WorkingDirectory = workingDirectory }; await ExecuteAsync(parameters, cancellationToken).ConfigureAwait(false); } + // --------------------------------------------------------- + // Basic API to call ffmpeg + // --------------------------------------------------------- + + public async Task ExecuteAsync(FFmpegParameters parameters, CancellationToken cancellationToken) + { + var ffmpegProcess = CreateProcess(parameters); + await ffmpegProcess.ExecuteAsync(cancellationToken).ConfigureAwait(false); + Cleanup(ffmpegProcess); + } + + public async Task ExecuteAsync(FFmpegParameters parameters, Stream output, CancellationToken cancellationToken) + { + var outputPipeName = $"{_pipePrefix}{Guid.NewGuid()}"; + var outputArgument = new OutputPipe(GetPipePath(outputPipeName)); + var pipe = new NamedPipeServerStream(outputPipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); + + parameters.Output = outputArgument; + var ffmpegProcess = CreateProcess(parameters); + try + { + var executeProcess = ffmpegProcess.ExecuteAsync(cancellationToken); + var copyData = pipe.WaitForConnectionAsync(cancellationToken) + .ContinueWith(async x => + { + await pipe.CopyToAsync(output, cancellationToken); + }, cancellationToken).Unwrap(); + await Task.WhenAll(executeProcess, copyData).ConfigureAwait(false); + pipe.Disconnect(); + } + finally + { + pipe.Dispose(); + Cleanup(ffmpegProcess); + } + } private FFmpegProcess CreateProcess(FFmpegParameters parameters) { diff --git a/src/FFmpeg.NET/FFmpegArgumentBuilder.cs b/src/FFmpeg.NET/FFmpegArgumentBuilder.cs index baa6867..621b1cc 100644 --- a/src/FFmpeg.NET/FFmpegArgumentBuilder.cs +++ b/src/FFmpeg.NET/FFmpegArgumentBuilder.cs @@ -9,14 +9,12 @@ internal static class FFmpegArgumentBuilder { public static string Build(FFmpegParameters parameters) { - if (parameters.HasCustomArguments) - return parameters.CustomArguments; - return parameters.Task switch { FFmpegTask.Convert => Convert(parameters.Input, parameters.Output, parameters.ConversionOptions), FFmpegTask.GetMetaData => GetMetadata(parameters.Input), FFmpegTask.GetThumbnail => GetThumbnail(parameters.Input, parameters.Output, parameters.ConversionOptions), + FFmpegTask.Execute => Execute(parameters.Input, parameters.Output, parameters.CustomArguments), _ => throw new ArgumentOutOfRangeException(), }; } @@ -182,6 +180,28 @@ private static string Convert(IInputArgument input, IOutputArgument output, Conv return commandBuilder.AppendFormat(" {0} ", output.Argument).ToString(); } + private static string Execute(IInputArgument input, IOutputArgument output, string customArguments) + { + StringBuilder commandBuilder = new StringBuilder(); + commandBuilder.Append(customArguments); + + if (input != null) + { + if (input.UseStandardInput) + { + commandBuilder.Append(" -nostdin "); + } + commandBuilder.Append($" -i {input.Argument} "); + } + + if (output != null) + { + commandBuilder.Append($" {output.Argument} "); + } + + return commandBuilder.ToString(); + } + private static void AppendHWAccelOutputFormat(StringBuilder commandBuilder, ConversionOptions conversionOptions) { if (conversionOptions.HWAccel != HWAccel.None && conversionOptions.HWAccelOutputFormatCopy) diff --git a/src/FFmpeg.NET/FFmpegTask.cs b/src/FFmpeg.NET/FFmpegTask.cs index b30634d..7e2d8a8 100644 --- a/src/FFmpeg.NET/FFmpegTask.cs +++ b/src/FFmpeg.NET/FFmpegTask.cs @@ -4,6 +4,7 @@ public enum FFmpegTask { Convert, GetMetaData, - GetThumbnail + GetThumbnail, + Execute } } \ No newline at end of file