flowframes/Code/Media/AvProcess.cs

218 lines
8.3 KiB
C#

using Flowframes.IO;
using Flowframes.Os;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Flowframes.MiscUtils;
using Microsoft.VisualBasic;
using Flowframes.Media;
using System.Windows.Input;
namespace Flowframes
{
class AvProcess
{
public static Process lastAvProcess;
public static Stopwatch timeSinceLastOutput = new Stopwatch();
public static string lastOutputFfmpeg;
public enum LogMode { Visible, OnlyLastLine, Hidden }
static LogMode currentLogMode;
static bool showProgressBar;
static readonly string defLogLevel = "warning";
public static void Kill()
{
if (lastAvProcess == null) return;
try
{
OsUtils.KillProcessTree(lastAvProcess.Id);
}
catch (Exception e)
{
Logger.Log($"Failed to kill lastAvProcess process tree: {e.Message}", true);
}
}
public static async Task<string> RunFfmpeg(string args, LogMode logMode, bool reliableOutput = true, bool progressBar = false)
{
return await RunFfmpeg(args, "", logMode, defLogLevel, reliableOutput, progressBar);
}
public static async Task<string> RunFfmpeg(string args, LogMode logMode, string loglevel, bool reliableOutput = true, bool progressBar = false)
{
return await RunFfmpeg(args, "", logMode, loglevel, reliableOutput, progressBar);
}
public static async Task<string> RunFfmpeg(string args, string workingDir, LogMode logMode, bool reliableOutput = true, bool progressBar = false)
{
return await RunFfmpeg(args, workingDir, logMode, defLogLevel, reliableOutput, progressBar);
}
public static async Task<string> RunFfmpeg(string args, string workingDir, LogMode logMode, string loglevel, bool reliableOutput = true, bool progressBar = false)
{
bool show = Config.GetInt(Config.Key.cmdDebugMode) > 0;
string processOutput = "";
Process ffmpeg = OsUtils.NewProcess(!show);
NmkdStopwatch timeSinceLastOutput = new NmkdStopwatch();
lastAvProcess = ffmpeg;
if (string.IsNullOrWhiteSpace(loglevel))
loglevel = defLogLevel;
string beforeArgs = $"-hide_banner -stats -loglevel {loglevel} -y";
if (!string.IsNullOrWhiteSpace(workingDir))
ffmpeg.StartInfo.Arguments = $"{GetCmdArg()} cd /D {workingDir.Wrap()} & {Path.Combine(GetAvDir(), "ffmpeg.exe").Wrap()} {beforeArgs} {args}";
else
ffmpeg.StartInfo.Arguments = $"{GetCmdArg()} cd /D {GetAvDir().Wrap()} & ffmpeg {beforeArgs} {args}";
if (logMode != LogMode.Hidden) Logger.Log("Running FFmpeg...", false);
Logger.Log($"ffmpeg {beforeArgs} {args}", true, false, "ffmpeg");
if (!show)
{
ffmpeg.OutputDataReceived += (sender, outLine) => { AvOutputHandler.LogOutput(outLine.Data, ref processOutput, "ffmpeg", logMode, progressBar); timeSinceLastOutput.Sw.Restart(); };
ffmpeg.ErrorDataReceived += (sender, outLine) => { AvOutputHandler.LogOutput(outLine.Data, ref processOutput, "ffmpeg", logMode, progressBar); timeSinceLastOutput.Sw.Restart(); };
}
ffmpeg.Start();
ffmpeg.PriorityClass = ProcessPriorityClass.BelowNormal;
if (!show)
{
ffmpeg.BeginOutputReadLine();
ffmpeg.BeginErrorReadLine();
}
while (!ffmpeg.HasExited) await Task.Delay(10);
while (reliableOutput && timeSinceLastOutput.ElapsedMs < 200) await Task.Delay(50);
if (progressBar)
Program.mainForm.SetProgress(0);
return processOutput;
}
public static string RunFfmpegSync(string args, string workingDir = "", LogMode logMode = LogMode.Hidden, string loglevel = "warning")
{
Process ffmpeg = OsUtils.NewProcess(true);
lastAvProcess = ffmpeg;
if (string.IsNullOrWhiteSpace(loglevel))
loglevel = defLogLevel;
string beforeArgs = $"-hide_banner -stats -loglevel {loglevel} -y";
if (!string.IsNullOrWhiteSpace(workingDir))
ffmpeg.StartInfo.Arguments = $"{GetCmdArg()} cd /D {workingDir.Wrap()} & {Path.Combine(GetAvDir(), "ffmpeg.exe").Wrap()} {beforeArgs} {args}";
else
ffmpeg.StartInfo.Arguments = $"{GetCmdArg()} cd /D {GetAvDir().Wrap()} & ffmpeg {beforeArgs} {args}";
if (logMode != LogMode.Hidden) Logger.Log("Running FFmpeg...", false);
Logger.Log($"ffmpeg {beforeArgs} {args}", true, false, "ffmpeg");
ffmpeg.StartInfo.Arguments += " 2>&1";
ffmpeg.Start();
ffmpeg.PriorityClass = ProcessPriorityClass.BelowNormal;
string output = ffmpeg.StandardOutput.ReadToEnd();
ffmpeg.WaitForExit();
Logger.Log($"Synchronous ffmpeg output:\n{output}", true, false, "ffmpeg");
return output;
}
public static string GetFfmpegDefaultArgs(string loglevel = "warning")
{
return $"-hide_banner -stats -loglevel {loglevel} -y";
}
public class FfprobeSettings
{
public string Args { get; set; } = "";
public LogMode LoggingMode { get; set; } = LogMode.Hidden;
public string LogLevel { get; set; } = "panic";
public bool SetBusy { get; set; } = false;
}
public static async Task<string> RunFfprobe(FfprobeSettings settings, bool asyncOutput = false)
{
bool show = Config.GetInt(Config.Key.cmdDebugMode) > 0;
string processOutput = "";
Process ffprobe = OsUtils.NewProcess(!show);
NmkdStopwatch timeSinceLastOutput = new NmkdStopwatch();
bool concat = settings.Args.Split(" \"").Last().Remove("\"").Trim().EndsWith(".concat");
string args = $"-v {settings.LogLevel} {(concat ? "-f concat -safe 0 " : "")}{settings.Args}";
ffprobe.StartInfo.Arguments = $"{GetCmdArg()} cd /D {GetAvDir().Wrap()} & ffprobe {args}";
if (settings.LoggingMode != LogMode.Hidden) Logger.Log("Running FFprobe...", false);
Logger.Log($"ffprobe {args}", true, false, "ffmpeg");
if (!asyncOutput)
return await Task.Run(() => OsUtils.GetProcStdOut(ffprobe));
if (!show)
{
string[] ignore = new string[0];
ffprobe.OutputDataReceived += (sender, outLine) => { processOutput += outLine + Environment.NewLine; };
ffprobe.ErrorDataReceived += (sender, outLine) => { processOutput += outLine + Environment.NewLine; };
}
ffprobe.Start();
ffprobe.PriorityClass = ProcessPriorityClass.BelowNormal;
if (!show)
{
ffprobe.BeginOutputReadLine();
ffprobe.BeginErrorReadLine();
}
while (!ffprobe.HasExited) await Task.Delay(10);
while (timeSinceLastOutput.ElapsedMs < 200) await Task.Delay(50);
return processOutput;
}
public static string GetFfprobeOutput(string args)
{
Process ffprobe = OsUtils.NewProcess(true);
ffprobe.StartInfo.Arguments = $"{GetCmdArg()} cd /D {GetAvDir().Wrap()} & ffprobe.exe {args}";
Logger.Log($"ffprobe {args}", true, false, "ffmpeg");
ffprobe.Start();
ffprobe.WaitForExit();
string output = ffprobe.StandardOutput.ReadToEnd();
string err = ffprobe.StandardError.ReadToEnd();
if (!string.IsNullOrWhiteSpace(err)) output += "\n" + err;
return output;
}
static string GetAvDir()
{
return Path.Combine(Paths.GetPkgPath(), Paths.audioVideoDir);
}
static string GetCmdArg()
{
return "/C";
}
public static async Task SetBusyWhileRunning()
{
if (Program.busy) return;
await Task.Delay(100);
while (!lastAvProcess.HasExited)
await Task.Delay(10);
}
}
}