diff --git a/FFmpegArgs.Executes/FFmpegRenderExtension.cs b/FFmpegArgs.Executes/FFmpegRenderExtension.cs index be9850ee..793fa7dd 100644 --- a/FFmpegArgs.Executes/FFmpegRenderExtension.cs +++ b/FFmpegArgs.Executes/FFmpegRenderExtension.cs @@ -11,10 +11,33 @@ public static class FFmpegRenderExtension public static FFmpegRender Render(this FFmpegArg ffmpegArg, Action config) => FFmpegRender.FromArguments(ffmpegArg, config); + private static Process BuildProcess(this FFmpegRender build, FFmpegRenderResult renderResult) + { + ProcessStartInfo info = new ProcessStartInfo(build.Config.FFmpegBinaryPath, build.Arguments) + { + CreateNoWindow = true, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + WorkingDirectory = build.Config.WorkingDirectory + }; + renderResult.Arguments = build.Arguments; + Process process = new Process(); + process.ErrorDataReceived += build.ErrorDataReceived; + process.ErrorDataReceived += (o, d) => renderResult._ErrorDatas.Add(d?.Data ?? string.Empty); + process.OutputDataReceived += build.OutputDataReceived; + process.OutputDataReceived += (o, d) => renderResult._OutputDatas.Add(d?.Data ?? string.Empty); + process.StartInfo = info; + return process; + } + + + + public static FFmpegRenderResult Execute( - this FFmpegRender build, - Action onEncodingProgress, + this FFmpegRender build, + Action onEncodingProgress, CancellationToken token = default) { build.OnEncodingProgress += onEncodingProgress ?? throw new ArgumentNullException(nameof(onEncodingProgress)); @@ -24,7 +47,7 @@ public static FFmpegRenderResult Execute( public static FFmpegRenderResult Execute( this FFmpegRender build, Action onEncodingProgress, - Action onOutputDataReceived, + Action onOutputDataReceived, CancellationToken token = default) { build.OnEncodingProgress += onEncodingProgress ?? throw new ArgumentNullException(nameof(onEncodingProgress)); @@ -35,23 +58,8 @@ public static FFmpegRenderResult Execute( public static FFmpegRenderResult Execute(this FFmpegRender build, CancellationToken token = default) { if (build == null) throw new ArgumentNullException(nameof(build)); - ProcessStartInfo info = new ProcessStartInfo(build.Config.FFmpegBinaryPath, build.Arguments) - { - CreateNoWindow = true, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - WorkingDirectory = build.Config.WorkingDirectory - }; - FFmpegRenderResult renderResult = new FFmpegRenderResult(); - renderResult.Arguments = build.Arguments; - using Process process = new Process(); - process.ErrorDataReceived += build.ErrorDataReceived; - process.ErrorDataReceived += (o, d) => renderResult._ErrorDatas.Add(d?.Data ?? string.Empty); - process.OutputDataReceived += build.OutputDataReceived; - process.OutputDataReceived += (o, d) => renderResult._OutputDatas.Add(d?.Data ?? string.Empty); - process.StartInfo = info; + using Process process = build.BuildProcess(renderResult); process.Start(); process.BeginErrorReadLine(); process.BeginOutputReadLine(); @@ -68,16 +76,51 @@ public static Task ExecuteAsync( Action onEncodingProgress, Action onOutputDataReceived, CancellationToken token = default) - => Task.Run(() => build.Execute(onEncodingProgress, onOutputDataReceived, token)); + { + build.OnEncodingProgress += onEncodingProgress ?? throw new ArgumentNullException(nameof(onEncodingProgress)); + build.OnOutputDataReceived += onOutputDataReceived ?? throw new ArgumentNullException(nameof(onOutputDataReceived)); + return build.ExecuteAsync(token); + } public static Task ExecuteAsync( - this FFmpegRender build, - Action onEncodingProgress, + this FFmpegRender build, + Action onEncodingProgress, CancellationToken token = default) - => Task.Run(() => build.Execute(onEncodingProgress, token)); - public static Task ExecuteAsync( - this FFmpegRender build, + { + build.OnEncodingProgress += onEncodingProgress ?? throw new ArgumentNullException(nameof(onEncodingProgress)); + return build.ExecuteAsync(token); + } + + + public static async Task ExecuteAsync( + this FFmpegRender build, CancellationToken token = default) - => Task.Run(() => build.Execute(token)); + { + if (build == null) throw new ArgumentNullException(nameof(build)); + FFmpegRenderResult renderResult = new FFmpegRenderResult(); + using Process process = build.BuildProcess(renderResult); +#if NET5_0_OR_GREATER +#else + //https://github.com/Tyrrrz/CliWrap/blob/8ff36a648d57b22497a7cb6feae14ef28bbb2be8/CliWrap/Utils/ProcessEx.cs#L41 + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + process.EnableRaisingEvents = true; + process.Exited += (sender, args) => tcs.TrySetResult(null); +#endif + if (!process.Start()) + { + throw new InvalidOperationException("Failed to obtain the handle when starting a process. " + + "This could mean that the target executable doesn't exist or that execute permission is missing."); + } + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + using var register = token.Register(() => process.Kill()); +#if NET5_0_OR_GREATER + await process.WaitForExitAsync(); +#else + await tcs.Task.ConfigureAwait(false); +#endif + renderResult.ExitCode = process.ExitCode; + return renderResult; + } } }