diff --git a/FFMpegCore/FFMPEG/FFBase.cs b/FFMpegCore/FFMPEG/FFBase.cs deleted file mode 100644 index 554f36d..0000000 --- a/FFMpegCore/FFMPEG/FFBase.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using RunProcessAsTask; - -namespace FFMpegCore.FFMPEG -{ - public abstract class FFBase : IDisposable - { - protected Process Process; - - protected FFBase() - { - } - - /// - /// Is 'true' when an exception is thrown during process kill (for paranoia level users). - /// - public bool IsKillFaulty { get; private set; } - - /// - /// Returns true if the associated process is still alive/running. - /// - public bool IsWorking - { - get - { - bool processHasExited; - - try - { - processHasExited = Process.HasExited; - } - catch - { - processHasExited = true; - } - - return !processHasExited && Process.GetProcesses().Any(x => x.Id == Process.Id); - } - } - - public void Dispose() - { - Process?.Dispose(); - } - - protected void CreateProcess(string args, string processPath, bool rStandardInput = false, - bool rStandardOutput = false, bool rStandardError = false) - { - if (IsWorking) - throw new InvalidOperationException( - "The current FFMpeg process is busy with another operation. Create a new object for parallel executions."); - - Process = new Process(); - IsKillFaulty = false; - Process.StartInfo.FileName = processPath; - Process.StartInfo.Arguments = args; - Process.StartInfo.UseShellExecute = false; - Process.StartInfo.CreateNoWindow = true; - - Process.StartInfo.RedirectStandardInput = rStandardInput; - Process.StartInfo.RedirectStandardOutput = rStandardOutput; - Process.StartInfo.RedirectStandardError = rStandardError; - } - - public void Kill() - { - try - { - if (IsWorking) - Process.Kill(); - } - catch - { - IsKillFaulty = true; - } - } - protected async Task RunProcessAsync(string filePath, string arguments) - { - var result = await ProcessEx.RunAsync(filePath, arguments); - return string.Join("", result.StandardOutput); - } - } - - public static class ProcessHelpers - { - public static void RunProcess(string filePath, string arguments) - { - - } - public static async Task RunProcessAsync(string fileName, string arguments) - { - var startInfo = new ProcessStartInfo(fileName, arguments); - startInfo.RedirectStandardOutput = true; - startInfo.RedirectStandardError = true; - - var result = await ProcessEx.RunAsync(startInfo); - return string.Join("", result.StandardOutput); - } - } -} \ No newline at end of file diff --git a/FFMpegCore/FFMPEG/FFMpeg.cs b/FFMpegCore/FFMPEG/FFMpeg.cs index b5b49db..a44a4e7 100644 --- a/FFMpegCore/FFMPEG/FFMpeg.cs +++ b/FFMpegCore/FFMPEG/FFMpeg.cs @@ -13,12 +13,13 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; +using Instances; namespace FFMpegCore.FFMPEG { public delegate void ConversionHandler(double percentage); - public class FFMpeg : FFBase + public class FFMpeg { IArgumentBuilder ArgumentBuilder { get; set; } @@ -457,6 +458,11 @@ public VideoInfo Convert(ArgumentContainer arguments) return new VideoInfo(output); } + /// + /// Returns true if the associated process is still alive/running. + /// + public bool IsWorking => _instance.Started; + /// /// Stops any current job that FFMpeg is running. /// @@ -464,53 +470,31 @@ public void Stop() { if (IsWorking) { - Process.StandardInput.Write('q'); + _instance.SendInput("q").Wait(); } } #region Private Members & Methods - private string _ffmpegPath; + private readonly string _ffmpegPath; private TimeSpan _totalTime; private volatile StringBuilder _errorOutput = new StringBuilder(); private bool RunProcess(ArgumentContainer container, FileInfo output) { - var successState = true; + _instance?.Dispose(); + var arguments = ArgumentBuilder.BuildArguments(container); + _instance = new Instance(_ffmpegPath, arguments); + _instance.DataReceived += OutputData; + var exitCode = _instance.BlockUntilFinished(); - CreateProcess(ArgumentBuilder.BuildArguments(container), _ffmpegPath, true, rStandardError: true); - - try + if (!File.Exists(output.FullName) || new FileInfo(output.FullName).Length == 0) { - Process.Start(); - Process.ErrorDataReceived += OutputData; - Process.BeginErrorReadLine(); - Process.WaitForExit(); - } - catch (Exception) - { - successState = false; - } - finally - { - Process.Close(); - - if (File.Exists(output.FullName)) - { - using var file = File.Open(output.FullName, FileMode.Open); - if (file.Length == 0) - { - throw new FFMpegException(FFMpegExceptionType.Process, _errorOutput); - } - } - else - { - throw new FFMpegException(FFMpegExceptionType.Process, _errorOutput); - } + throw new FFMpegException(FFMpegExceptionType.Process, _errorOutput); } - return successState; + return exitCode == 0; } private void Cleanup(IEnumerable pathList) @@ -524,23 +508,28 @@ private void Cleanup(IEnumerable pathList) } } - private static Regex _progressRegex = new Regex(@"\w\w:\w\w:\w\w", RegexOptions.Compiled); - private void OutputData(object sender, DataReceivedEventArgs e) - { - if (e.Data == null) - return; + private static readonly Regex ProgressRegex = new Regex(@"\w\w:\w\w:\w\w", RegexOptions.Compiled); + private Instance _instance; - _errorOutput.AppendLine(e.Data); + private void OutputData(object sender, (DataType Type, string Data) msg) + { + var (type, data) = msg; + + if (data == null) return; + if (type == DataType.Error) + { + _errorOutput.AppendLine(data); + return; + } + #if DEBUG - Trace.WriteLine(e.Data); + Trace.WriteLine(data); #endif - if (OnProgress == null || !IsWorking) return; - - - if (!e.Data.Contains("frame")) return; + if (OnProgress == null) return; + if (!data.Contains("frame")) return; - var match = _progressRegex.Match(e.Data); + var match = ProgressRegex.Match(data); if (!match.Success) return; var processed = TimeSpan.Parse(match.Value, CultureInfo.InvariantCulture); diff --git a/FFMpegCore/FFMPEG/FFMpegOptions.cs b/FFMpegCore/FFMPEG/FFMpegOptions.cs index 7555620..23f7559 100644 --- a/FFMpegCore/FFMPEG/FFMpegOptions.cs +++ b/FFMpegCore/FFMPEG/FFMpegOptions.cs @@ -3,6 +3,7 @@ using System; using System.IO; using System.Runtime.InteropServices; +using Instances; namespace FFMpegCore.FFMPEG { @@ -44,13 +45,7 @@ private static string FFBinary(string name) ffName = Path.Combine(target, ffName); } - var path = Path.Combine(Options.RootDirectory, ffName); - - if (!File.Exists(path)) - throw new FFMpegException(FFMpegExceptionType.Dependency, - $"{name} cannot be found @ {path}"); - - return path; + return Path.Combine(Options.RootDirectory, ffName); } } } diff --git a/FFMpegCore/FFMPEG/FFProbe.cs b/FFMpegCore/FFMPEG/FFProbe.cs index 0e084cd..5002817 100644 --- a/FFMpegCore/FFMPEG/FFProbe.cs +++ b/FFMpegCore/FFMPEG/FFProbe.cs @@ -4,17 +4,18 @@ using System; using System.Globalization; using System.Threading.Tasks; +using Instances; namespace FFMpegCore.FFMPEG { - public sealed class FFProbe : FFBase + public sealed class FFProbe { static readonly double BITS_TO_MB = 1024 * 1024 * 8; + private readonly string _ffprobePath; public FFProbe(): base() { FFProbeHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory); - _ffprobePath = FFMpegOptions.Options.FFProbeBinary; } @@ -44,7 +45,9 @@ public Task ParseVideoInfoAsync(string source) /// A video info object containing all details necessary. public VideoInfo ParseVideoInfo(VideoInfo info) { - var output = RunProcess(BuildFFProbeArguments(info)); + var instance = new Instance(_ffprobePath, BuildFFProbeArguments(info)); + instance.BlockUntilFinished(); + var output = string.Join("", instance.OutputData); return ParseVideoInfoInternal(info, output); } /// @@ -54,7 +57,9 @@ public VideoInfo ParseVideoInfo(VideoInfo info) /// A video info object containing all details necessary. public async Task ParseVideoInfoAsync(VideoInfo info) { - var output = await RunProcessAsync(_ffprobePath, BuildFFProbeArguments(info)); + var instance = new Instance(_ffprobePath, BuildFFProbeArguments(info)); + await instance.FinishedRunning(); + var output = string.Join("", instance.OutputData); return ParseVideoInfoInternal(info, output); } @@ -115,35 +120,5 @@ private VideoInfo ParseVideoInfoInternal(VideoInfo info, string probeOutput) return info; } - - #region Private Members & Methods - - private readonly string _ffprobePath; - - private string RunProcess(string args) - { - CreateProcess(args, _ffprobePath, rStandardOutput: true); - - string output; - - try - { - Process.Start(); - output = Process.StandardOutput.ReadToEnd(); - } - catch (Exception) - { - output = ""; - } - finally - { - Process.WaitForExit(); - Process.Close(); - } - - return output; - } - - #endregion } } diff --git a/FFMpegCore/FFMpegCore.csproj b/FFMpegCore/FFMpegCore.csproj index 3fc56cf..b92a3da 100644 --- a/FFMpegCore/FFMpegCore.csproj +++ b/FFMpegCore/FFMpegCore.csproj @@ -129,7 +129,7 @@ - +