Backport fast frame counting and other stuff from Nmkoder

This commit is contained in:
n00mkrad
2021-12-06 22:46:39 +01:00
parent 659332dd0f
commit 7a3c95f6fb
16 changed files with 255 additions and 155 deletions

View File

@@ -69,8 +69,8 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<Optimize>false</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
@@ -403,6 +403,7 @@
<Compile Include="Main\InterpolateUtils.cs" />
<Compile Include="Main\FrameOrder.cs" />
<Compile Include="Main\ResumeUtils.cs" />
<Compile Include="Media\AvOutputHandler.cs" />
<Compile Include="Media\AvProcess.cs" />
<Compile Include="Media\FfmpegAlpha.cs" />
<Compile Include="Media\FfmpegAudioAndMetadata.cs" />

View File

@@ -194,7 +194,7 @@ namespace Flowframes
public void LoadBatchEntry(InterpSettings entry)
{
inputTbox.Text = entry.inPath;
MainUiFunctions.SetOutPath(inputTbox, entry.outPath);
MainUiFunctions.SetOutPath(outputTbox, entry.outPath);
interpFactorCombox.Text = entry.interpFactor.ToString();
aiCombox.SelectedIndex = Implementations.networks.IndexOf(Implementations.networks.Where(x => x.aiName == entry.ai.aiName).FirstOrDefault());
SetOutMode(entry.outMode);

View File

@@ -743,7 +743,7 @@ namespace Flowframes.IO
}
if (log)
Logger.Log($"Computed {hashType} for '{Path.GetFileNameWithoutExtension(path).Trunc(40) + Path.GetExtension(path)}' ({GetFilesizeStr(path)}): {hashStr} ({sw.GetElapsedStr()})", true);
Logger.Log($"Computed {hashType} for '{Path.GetFileNameWithoutExtension(path).Trunc(40) + Path.GetExtension(path)}' ({GetFilesizeStr(path)}): {hashStr} ({sw})", true);
return hashStr;
}

View File

@@ -232,7 +232,7 @@ namespace Flowframes.Main
MessageBox.Show("An error occured while trying to merge the video chunks.\nCheck the log for details.");
}
Logger.Log($"Merged video chunks in {sw.GetElapsedStr()}", true);
Logger.Log($"Merged video chunks in {sw}", true);
}
static async Task MergeChunks(string framesFile, string outPath, bool isBackup = false)

View File

@@ -0,0 +1,132 @@
using Flowframes.MiscUtils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static Flowframes.AvProcess;
namespace Flowframes.Media
{
class AvOutputHandler
{
public static readonly string prefix = "[ffmpeg]";
public static void LogOutput(string line, ref string appendStr, string logFilename, LogMode logMode, bool showProgressBar)
{
if (Interpolate.canceled || string.IsNullOrWhiteSpace(line) || line.Trim().Length < 1)
return;
bool hidden = logMode == LogMode.Hidden;
if (HideMessage(line)) // Don't print certain warnings
hidden = true;
bool replaceLastLine = logMode == LogMode.OnlyLastLine;
if (line.Contains("time=") && (line.StartsWith("frame=") || line.StartsWith("size=")))
line = FormatUtils.BeautifyFfmpegStats(line);
appendStr += Environment.NewLine + line;
Logger.Log($"{prefix} {line}", hidden, replaceLastLine, logFilename);
if (!hidden && showProgressBar && line.Contains("Time:"))
{
Regex timeRegex = new Regex("(?<=Time:).*(?= )");
UpdateFfmpegProgress(timeRegex.Match(line).Value);
}
if (line.Contains("Unable to"))
{
Interpolate.Cancel($"Error: {line}");
return;
}
if (line.Contains("Could not open file"))
{
Interpolate.Cancel($"Error: {line}");
return;
}
if (line.Contains("No NVENC capable devices found") || line.MatchesWildcard("*nvcuda.dll*"))
{
Interpolate.Cancel($"Error: {line}\n\nMake sure you have an NVENC-capable Nvidia GPU.");
return;
}
if (line.Contains("not currently supported in container") || line.Contains("Unsupported codec id"))
{
Interpolate.Cancel($"Error: {line}\n\nIt looks like you are trying to copy a stream into a container that doesn't support this codec.");
return;
}
if (line.Contains("Subtitle encoding currently only possible from text to text or bitmap to bitmap"))
{
Interpolate.Cancel($"Error: {line}\n\nYou cannot encode image-based subtitles into text-based subtitles. Please use the Copy Subtitles option instead, with a compatible container.");
return;
}
if (line.Contains("Only VP8 or VP9 or AV1 video and Vorbis or Opus audio and WebVTT subtitles are supported for WebM"))
{
Interpolate.Cancel($"Error: {line}\n\nIt looks like you are trying to copy an unsupported stream into WEBM!");
return;
}
if (line.MatchesWildcard("*codec*not supported*"))
{
Interpolate.Cancel($"Error: {line}\n\nTry using a different codec.");
return;
}
if (line.Contains("GIF muxer supports only a single video GIF stream"))
{
Interpolate.Cancel($"Error: {line}\n\nYou tried to mux a non-GIF stream into a GIF file.");
return;
}
if (line.Contains("Width and height of input videos must be same"))
{
Interpolate.Cancel($"Error: {line}");
return;
}
}
public static void UpdateFfmpegProgress(string ffmpegTime)
{
try
{
Form1 form = Program.mainForm;
long currInDuration = (form.currInDurationCut < form.currInDuration) ? form.currInDurationCut : form.currInDuration;
if (currInDuration < 1)
{
Program.mainForm.SetProgress(0);
return;
}
long total = currInDuration / 100;
long current = FormatUtils.TimestampToMs(ffmpegTime);
int progress = Convert.ToInt32(current / total);
Program.mainForm.SetProgress(progress);
}
catch (Exception e)
{
Logger.Log($"Failed to get ffmpeg progress: {e.Message}", true);
}
}
static bool HideMessage(string msg)
{
string[] hiddenMsgs = new string[] { "can produce invalid output", "pixel format", "provided invalid" };
foreach (string str in hiddenMsgs)
if (msg.MatchesWildcard($"*{str}*"))
return true;
return false;
}
}
}

View File

@@ -10,6 +10,7 @@ using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Flowframes.MiscUtils;
using Microsoft.VisualBasic;
using Flowframes.Media;
namespace Flowframes
{
@@ -17,8 +18,6 @@ namespace Flowframes
{
public static Process lastAvProcess;
public static Stopwatch timeSinceLastOutput = new Stopwatch();
public enum TaskType { ExtractFrames, ExtractOther, Encode, GetInfo, Merge, Other };
public static TaskType lastTask = TaskType.Other;
public static string lastOutputFfmpeg;
@@ -42,52 +41,64 @@ namespace Flowframes
}
}
public static async Task RunFfmpeg(string args, LogMode logMode, TaskType taskType = TaskType.Other, bool progressBar = false)
public static async Task<string> RunFfmpeg(string args, LogMode logMode, bool reliableOutput = true, bool progressBar = false)
{
await RunFfmpeg(args, "", logMode, defLogLevel, taskType, progressBar);
return await RunFfmpeg(args, "", logMode, defLogLevel, reliableOutput, progressBar);
}
public static async Task RunFfmpeg(string args, LogMode logMode, string loglevel, TaskType taskType = TaskType.Other, bool progressBar = false)
public static async Task<string> RunFfmpeg(string args, LogMode logMode, string loglevel, bool reliableOutput = true, bool progressBar = false)
{
await RunFfmpeg(args, "", logMode, loglevel, taskType, progressBar);
return await RunFfmpeg(args, "", logMode, loglevel, reliableOutput, progressBar);
}
public static async Task RunFfmpeg(string args, string workingDir, LogMode logMode, TaskType taskType = TaskType.Other, bool progressBar = false)
public static async Task<string> RunFfmpeg(string args, string workingDir, LogMode logMode, bool reliableOutput = true, bool progressBar = false)
{
await RunFfmpeg(args, workingDir, logMode, defLogLevel, taskType, progressBar);
return await RunFfmpeg(args, workingDir, logMode, defLogLevel, reliableOutput, progressBar);
}
public static async Task RunFfmpeg(string args, string workingDir, LogMode logMode, string loglevel, TaskType taskType = TaskType.Other, bool progressBar = false)
public static async Task<string> RunFfmpeg(string args, string workingDir, LogMode logMode, string loglevel, bool reliableOutput = true, bool progressBar = false)
{
lastOutputFfmpeg = "";
currentLogMode = logMode;
showProgressBar = progressBar;
Process ffmpeg = OsUtils.NewProcess(true);
timeSinceLastOutput.Restart();
bool show = Config.GetInt(Config.Key.cmdDebugMode) > 0;
string processOutput = "";
Process ffmpeg = OsUtils.NewProcess(!show);
NmkdStopwatch timeSinceLastOutput = new NmkdStopwatch();
lastAvProcess = ffmpeg;
lastTask = taskType;
if (string.IsNullOrWhiteSpace(loglevel))
loglevel = defLogLevel;
if(!string.IsNullOrWhiteSpace(workingDir))
ffmpeg.StartInfo.Arguments = $"{GetCmdArg()} cd /D {workingDir.Wrap()} & {Path.Combine(GetAvDir(), "ffmpeg.exe").Wrap()} {GetFfmpegDefaultArgs(loglevel)} {args}";
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.exe {GetFfmpegDefaultArgs(loglevel)} {args}";
ffmpeg.StartInfo.Arguments = $"{GetCmdArg()} cd /D {GetAvDir().Wrap()} & ffmpeg {beforeArgs} {args}";
if (logMode != LogMode.Hidden) Logger.Log("Running FFmpeg...", false);
Logger.Log($"ffmpeg {GetFfmpegDefaultArgs(loglevel)} {args}", true, false, "ffmpeg");
ffmpeg.OutputDataReceived += FfmpegOutputHandler;
ffmpeg.ErrorDataReceived += FfmpegOutputHandler;
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.BeginOutputReadLine();
ffmpeg.BeginErrorReadLine();
ffmpeg.PriorityClass = ProcessPriorityClass.BelowNormal;
while (!ffmpeg.HasExited)
await Task.Delay(1);
if (!show)
{
ffmpeg.BeginOutputReadLine();
ffmpeg.BeginErrorReadLine();
}
if(progressBar)
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 GetFfmpegDefaultArgs (string loglevel = "warning")
@@ -95,71 +106,41 @@ namespace Flowframes
return $"-hide_banner -stats -loglevel {loglevel} -y";
}
static void FfmpegOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
public static async Task<string> RunFfprobe(string args, LogMode logMode = LogMode.Hidden, string loglevel = "quiet")
{
timeSinceLastOutput.Restart();
bool show = Config.GetInt(Config.Key.cmdDebugMode) > 0;
string processOutput = "";
Process ffprobe = OsUtils.NewProcess(!show);
NmkdStopwatch timeSinceLastOutput = new NmkdStopwatch();
lastAvProcess = ffprobe;
if (Interpolate.canceled || outLine == null || outLine.Data == null)
return;
if (string.IsNullOrWhiteSpace(loglevel))
loglevel = defLogLevel;
string line = outLine.Data;
lastOutputFfmpeg = lastOutputFfmpeg + "\n" + line;
ffprobe.StartInfo.Arguments = $"{GetCmdArg()} cd /D {GetAvDir().Wrap()} & ffprobe -v {loglevel} {args}";
bool hidden = currentLogMode == LogMode.Hidden;
if (logMode != LogMode.Hidden) Logger.Log("Running FFprobe...", false);
Logger.Log($"ffprobe -v {loglevel} {args}", true, false, "ffmpeg");
if (HideMessage(line)) // Don't print certain warnings
hidden = true;
bool replaceLastLine = currentLogMode == LogMode.OnlyLastLine;
if (line.StartsWith("frame="))
line = FormatUtils.BeautifyFfmpegStats(line);
Logger.Log(line, hidden, replaceLastLine, "ffmpeg");
if (line.Contains(".srt: Invalid data found"))
Logger.Log($"Warning: Failed to encode subtitle track {line.Split(':')[2]}. This track will be missing in the output file.");
if (line.Contains("Could not open file"))
Interpolate.Cancel($"FFmpeg Error: {line}");
if (line.Contains("No NVENC capable devices found") || line.MatchesWildcard("*nvcuda.dll*"))
Interpolate.Cancel($"FFmpeg Error: {line}\nMake sure you have an NVENC-capable Nvidia GPU.");
if (!hidden && showProgressBar && line.Contains("Time:"))
if (!show)
{
Regex timeRegex = new Regex("(?<=Time:).*(?= )");
UpdateFfmpegProgress(timeRegex.Match(line).Value);
ffprobe.OutputDataReceived += (sender, outLine) => { AvOutputHandler.LogOutput(outLine.Data, ref processOutput, "ffmpeg", logMode, false); timeSinceLastOutput.sw.Restart(); };
ffprobe.ErrorDataReceived += (sender, outLine) => { AvOutputHandler.LogOutput(outLine.Data, ref processOutput, "ffmpeg", logMode, false); timeSinceLastOutput.sw.Restart(); };
}
}
static bool HideMessage (string msg)
{
string[] hiddenMsgs = new string[] { "can produce invalid output", "pixel format", "provided invalid" };
ffprobe.Start();
ffprobe.PriorityClass = ProcessPriorityClass.BelowNormal;
foreach (string str in hiddenMsgs)
if (msg.MatchesWildcard($"*{str}*"))
return true;
if (!show)
{
ffprobe.BeginOutputReadLine();
ffprobe.BeginErrorReadLine();
}
return false;
}
while (!ffprobe.HasExited) await Task.Delay(10);
while (timeSinceLastOutput.ElapsedMs < 200) await Task.Delay(50);
public static async Task<string> GetFfmpegOutputAsync(string args, bool setBusy = false, bool progressBar = false)
{
timeSinceLastOutput.Restart();
if (Program.busy) setBusy = false;
lastOutputFfmpeg = "";
showProgressBar = progressBar;
Process ffmpeg = OsUtils.NewProcess(true);
lastAvProcess = ffmpeg;
ffmpeg.StartInfo.Arguments = $"{GetCmdArg()} cd /D {GetAvDir().Wrap()} & ffmpeg.exe -hide_banner -y -stats {args}";
Logger.Log($"ffmpeg {args}", true, false, "ffmpeg");
if (setBusy) Program.mainForm.SetWorking(true);
lastOutputFfmpeg = await OsUtils.GetOutputAsync(ffmpeg);
while (!ffmpeg.HasExited) await Task.Delay(50);
while(timeSinceLastOutput.ElapsedMilliseconds < 200) await Task.Delay(50);
if (setBusy) Program.mainForm.SetWorking(false);
return lastOutputFfmpeg;
return processOutput;
}
public static string GetFfprobeOutput (string args)
@@ -174,30 +155,6 @@ namespace Flowframes
if (!string.IsNullOrWhiteSpace(err)) output += "\n" + err;
return output;
}
public static void UpdateFfmpegProgress(string ffmpegTime)
{
try
{
Form1 form = Program.mainForm;
long currInDuration = (form.currInDurationCut < form.currInDuration) ? form.currInDurationCut : form.currInDuration;
if (currInDuration < 1)
{
Program.mainForm.SetProgress(0);
return;
}
long total = currInDuration / 100;
long current = FormatUtils.TimestampToMs(ffmpegTime);
int progress = Convert.ToInt32(current / total);
Program.mainForm.SetProgress(progress);
}
catch (Exception e)
{
Logger.Log($"Failed to get ffmpeg progress: {e.Message}", true);
}
}
static string GetAvDir ()
{

View File

@@ -45,7 +45,7 @@ namespace Flowframes
string loopStr = (looptimes > 0) ? $"-stream_loop {looptimes}" : "";
string vfrFilename = Path.GetFileName(concatFile);
string args = $" {loopStr} -vsync 1 -f concat -i {vfrFilename} -c copy -movflags +faststart -fflags +genpts {outPath.Wrap()}";
await RunFfmpeg(args, concatFile.GetParentDir(), LogMode.Hidden, TaskType.Merge);
await RunFfmpeg(args, concatFile.GetParentDir(), LogMode.Hidden);
}
public static async Task LoopVideo(string inputFile, int times, bool delSrc = false)
@@ -157,9 +157,13 @@ namespace Flowframes
public static async Task<int> GetFrameCountAsync(string inputFile)
{
Logger.Log($"GetFrameCountAsync('{inputFile}') - Trying ffprobe first.", true, false, "ffmpeg");
Logger.Log($"GetFrameCountAsync('{inputFile}') - Trying ffprobe packet counting first (fastest).", true, false, "ffmpeg");
int frames = await ReadFrameCountFfprobePacketCount(inputFile); // Try reading frame count with ffprobe packet counting
if (frames > 0) return frames;
int frames = await ReadFrameCountFfprobeAsync(inputFile, Config.GetBool(Config.Key.ffprobeFrameCount)); // Try reading frame count with ffprobe
Logger.Log($"GetFrameCountAsync('{inputFile}') - Trying ffprobe decoding now.", true, false, "ffmpeg");
frames = await ReadFrameCountFfprobe(inputFile); // Try reading frame count with ffprobe decoding
if (frames > 0) return frames;
Logger.Log($"Failed to get frame count using ffprobe (frames = {frames}). Trying to read with ffmpeg.", true, false, "ffmpeg");
@@ -170,7 +174,7 @@ namespace Flowframes
return 0;
}
static int ReadFrameCountFromDuration (string inputFile, long durationMs, float fps)
static int ReadFrameCountFromDuration(string inputFile, long durationMs, float fps)
{
float durationSeconds = durationMs / 1000f;
float frameCount = durationSeconds * fps;
@@ -179,21 +183,25 @@ namespace Flowframes
return frameCountRounded;
}
static async Task<int> ReadFrameCountFfprobeAsync(string inputFile, bool readFramesSlow)
public static async Task<int> ReadFrameCountFfprobePacketCount(string filePath)
{
string args = $" -v panic -threads 0 -select_streams v:0 -show_entries stream=nb_frames -of default=noprint_wrappers=1 {inputFile.Wrap()}";
if (readFramesSlow)
{
Logger.Log("Counting total frames using FFprobe. This can take a moment...");
await Task.Delay(10);
args = $" -v panic -threads 0 -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 {inputFile.Wrap()}";
}
string info = GetFfprobeOutput(args);
string output = await RunFfprobe($"-select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 {filePath.Wrap()}", LogMode.Hidden, "error");
string[] lines = output.SplitIntoLines().Where(x => !string.IsNullOrWhiteSpace(x)).ToArray();
if (lines == null || lines.Length < 1)
return 0;
return lines.Last().GetInt();
}
public static async Task<int> ReadFrameCountFfprobe(string filePath)
{
string args = $" -v panic {filePath.Wrap()} -threads 0 -select_streams v:0 -show_entries stream=nb_frames -of default=noprint_wrappers=1 {filePath.Wrap()}";
string info = await RunFfprobe(args);
string[] entries = info.SplitIntoLines();
try
{
if (readFramesSlow)
return info.GetInt();
foreach (string entry in entries)
{
if (entry.Contains("nb_frames="))
@@ -201,17 +209,18 @@ namespace Flowframes
}
}
catch { }
return -1;
}
static async Task<int> ReadFrameCountFfmpegAsync (string inputFile)
public static async Task<int> ReadFrameCountFfmpegAsync(string filePath)
{
string args = $" -loglevel panic -stats -i {inputFile.Wrap()} -map 0:v:0 -c copy -f null - ";
string info = await GetFfmpegOutputAsync(args, true, true);
string args = $" -loglevel panic -stats {filePath.Wrap()} -i {filePath.Wrap()} -map 0:v:0 -c copy -f null - ";
string info = await RunFfmpeg(args, LogMode.Hidden);
try
{
string[] lines = info.SplitIntoLines();
string lastLine = lines.Last();
string lastLine = lines.Last().ToLower();
return lastLine.Substring(0, lastLine.IndexOf("fps")).GetInt();
}
catch
@@ -231,7 +240,7 @@ namespace Flowframes
{
Logger.Log($"IsEncoderCompatible('{enc}')", true, false, "ffmpeg");
string args = $"-loglevel error -f lavfi -i color=black:s=540x540 -vframes 1 -an -c:v {enc} -f null -";
string output = await GetFfmpegOutputAsync(args);
string output = await RunFfmpeg(args, LogMode.Hidden);
return !output.ToLower().Contains("error");
}

View File

@@ -59,7 +59,7 @@ namespace Flowframes.Media
}
//string argsOld = $"-vsync 0 -r {fps} {inArg} {encArgs} {vf} {GetAspectArg(extraData)} {extraArgs} -threads {Config.GetInt(Config.Key.ffEncThreads)} {outPath.Wrap()}";
await RunFfmpeg(args, framesFile.GetParentDir(), logMode, "error", TaskType.Encode, !isChunk);
await RunFfmpeg(args, framesFile.GetParentDir(), logMode, !isChunk);
IoUtils.TryDeleteIfExists(linksDir);
}
@@ -95,7 +95,7 @@ namespace Flowframes.Media
string compression = format == "png" ? pngCompr : $"-q:v {lossyQ}";
string codec = format == "webp" ? "-c:v libwebp" : ""; // Specify libwebp to avoid putting all frames into single animated WEBP
string args = $"-vsync 0 -r {rate} {inArg} {codec} {compression} {sn} {vf} \"{outDir}/%{Padding.interpFrames}d.{format}\"";
await RunFfmpeg(args, framesFile.GetParentDir(), logMode, "error", TaskType.Encode, true);
await RunFfmpeg(args, framesFile.GetParentDir(), logMode, "error", true);
IoUtils.TryDeleteIfExists(linksDir);
}
@@ -115,7 +115,7 @@ namespace Flowframes.Media
string extraArgs = Config.Get(Config.Key.ffEncArgs);
rate = rate / new Fraction(itsScale);
string args = $"-f concat -r {rate} -i {framesFilename.Wrap()} -gifflags -offsetting {vf} {extraArgs} {outPath.Wrap()}";
await RunFfmpeg(args, framesFile.GetParentDir(), LogMode.OnlyLastLine, "error", TaskType.Encode);
await RunFfmpeg(args, framesFile.GetParentDir(), LogMode.OnlyLastLine, "error");
}
}
}

View File

@@ -35,7 +35,7 @@ namespace Flowframes.Media
string args = $"-vsync 0 {GetTrimArg(true)} {inArg} {GetImgArgs(format)} {rateArg} {scnDetect} -frame_pts 1 -s 256x144 {GetTrimArg(false)} \"{outDir}/%{Padding.inputFrames}d{format}\"";
LogMode logMode = await Interpolate.GetCurrentInputFrameCount() > 50 ? LogMode.OnlyLastLine : LogMode.Hidden;
await RunFfmpeg(args, logMode, inputIsFrames ? "panic" : "warning", TaskType.ExtractFrames, true);
await RunFfmpeg(args, logMode, inputIsFrames ? "panic" : "warning", true);
bool hiddenLog = await Interpolate.GetCurrentInputFrameCount() <= 50;
int amount = IoUtils.GetAmountOfFiles(outDir, false);
@@ -84,7 +84,7 @@ namespace Flowframes.Media
string rateArg = (rate.GetFloat() > 0) ? $" -r {rate}" : "";
string args = $"{GetTrimArg(true)} -i {inputFile.Wrap()} {GetImgArgs(format, true, alpha)} -vsync 0 {rateArg} -frame_pts 1 {vf} {sizeStr} {GetTrimArg(false)} \"{framesDir}/%{Padding.inputFrames}d{format}\"";
LogMode logMode = await Interpolate.GetCurrentInputFrameCount() > 50 ? LogMode.OnlyLastLine : LogMode.Hidden;
await RunFfmpeg(args, logMode, TaskType.ExtractFrames, true);
await RunFfmpeg(args, logMode, true);
int amount = IoUtils.GetAmountOfFiles(framesDir, false, "*" + format);
Logger.Log($"Extracted {amount} {(amount == 1 ? "frame" : "frames")} from input.", false, true);
await Task.Delay(1);
@@ -173,7 +173,7 @@ namespace Flowframes.Media
if (!allSameSize)
{
Logger.Log($"Sequence not compatible: Not all images have the same dimensions [{sw.GetElapsedStr()}].", true);
Logger.Log($"Sequence not compatible: Not all images have the same dimensions.", true);
return false;
}
@@ -182,7 +182,7 @@ namespace Flowframes.Media
if (!allDivBy2)
{
Logger.Log($"Sequence not compatible: Not all image dimensions are divisible by {div} [{sw.GetElapsedStr()}].", true);
Logger.Log($"Sequence not compatible: Not all image dimensions are divisible by {div}.", true);
return false;
}
@@ -190,7 +190,7 @@ namespace Flowframes.Media
if (!allSmallEnough)
{
Logger.Log($"Sequence not compatible: Image dimensions above max size [{sw.GetElapsedStr()}].", true);
Logger.Log($"Sequence not compatible: Image dimensions above max size.", true);
return false;
}
@@ -198,12 +198,12 @@ namespace Flowframes.Media
if (!all24Bit)
{
Logger.Log($"Sequence not compatible: Some images are not 24-bit (8bpp) [{sw.GetElapsedStr()}].", true);
Logger.Log($"Sequence not compatible: Some images are not 24-bit (8bpp).", true);
return false;
}
Interpolate.current.framesExt = files.First().Extension;
Logger.Log($"Sequence compatible! [{sw.GetElapsedStr()}]", true);
Logger.Log($"Sequence compatible!", true);
return true;
}
@@ -228,7 +228,7 @@ namespace Flowframes.Media
string vf = $"-vf {GetPadFilter()}";
string args = $"-r 25 {inArg} {GetImgArgs(format, true, alpha)} {sizeStr} -vsync 0 -start_number 0 {vf} \"{outPath}/%{Padding.inputFrames}d{format}\"";
LogMode logMode = IoUtils.GetAmountOfFiles(inPath, false) > 50 ? LogMode.OnlyLastLine : LogMode.Hidden;
await RunFfmpeg(args, logMode, "panic", TaskType.ExtractFrames);
await RunFfmpeg(args, logMode, "panic");
}
public static string[] GetTrimArgs()
@@ -282,7 +282,7 @@ namespace Flowframes.Media
string comprArg = isPng ? pngCompr : "";
string pixFmt = "-pix_fmt " + (isPng ? $"rgb24 {comprArg}" : "yuvj420p");
string args = $"-i {inputFile.Wrap()} {comprArg} {sizeStr} {pixFmt} -vf {GetPadFilter()} {outPath.Wrap()}";
await RunFfmpeg(args, LogMode.Hidden, TaskType.ExtractFrames);
await RunFfmpeg(args, LogMode.Hidden);
}
public static async Task ExtractSingleFrame(string inputFile, string outputPath, int frameNum)
@@ -291,7 +291,7 @@ namespace Flowframes.Media
string comprArg = isPng ? pngCompr : "";
string pixFmt = "-pix_fmt " + (isPng ? $"rgb24 {comprArg}" : "yuvj420p");
string args = $"-i {inputFile.Wrap()} -vf \"select=eq(n\\,{frameNum})\" -vframes 1 {pixFmt} {outputPath.Wrap()}";
await RunFfmpeg(args, LogMode.Hidden, TaskType.ExtractFrames);
await RunFfmpeg(args, LogMode.Hidden);
}
public static async Task ExtractLastFrame(string inputFile, string outputPath, Size size)
@@ -309,7 +309,7 @@ namespace Flowframes.Media
string trim = QuickSettingsTab.trimEnabled ? $"-ss {QuickSettingsTab.GetTrimEndMinusOne()} -to {QuickSettingsTab.trimEnd}" : "";
string sseof = string.IsNullOrWhiteSpace(trim) ? "-sseof -1" : "";
string args = $"{sseof} -i {inputFile.Wrap()} -update 1 {pixFmt} {sizeStr} {trim} {outputPath.Wrap()}";
await RunFfmpeg(args, LogMode.Hidden, TaskType.ExtractFrames);
await RunFfmpeg(args, LogMode.Hidden);
}
}
}

View File

@@ -39,7 +39,7 @@ namespace Flowframes.MiscUtils
{
if(task.timer.sw.ElapsedMilliseconds > task.timeoutSeconds * 1000)
{
Logger.Log($"[BgTaskMgr] Task with ID {task.id} timed out, has been running for {task.timer.GetElapsedStr()}!", true);
Logger.Log($"[BgTaskMgr] Task with ID {task.id} timed out, has been running for {task.timer}!", true);
runningTasks.Remove(task);
}
}
@@ -59,7 +59,7 @@ namespace Flowframes.MiscUtils
{
if(task.id == id)
{
Logger.Log($"[BgTaskMgr] Task '{task.name}' has finished after {task.timer.GetElapsedStr()} (Timeout {task.timeoutSeconds}s)", true);
Logger.Log($"[BgTaskMgr] Task '{task.name}' has finished after {task.timer} (Timeout {task.timeoutSeconds}s)", true);
runningTasks.Remove(task);
}
}

View File

@@ -9,7 +9,7 @@ namespace Flowframes.MiscUtils
{
NmkdStopwatch sw = new NmkdStopwatch();
var returnVal = method.DynamicInvoke(args);
Logger.Log($"Ran {methodName} in {sw.GetElapsedStr()}", true);
Logger.Log($"Ran {methodName} in {sw}", true);
return returnVal;
}
@@ -18,7 +18,7 @@ namespace Flowframes.MiscUtils
{
NmkdStopwatch sw = new NmkdStopwatch();
method.DynamicInvoke(args);
Logger.Log($"Ran {methodName} in {sw.GetElapsedStr()}", true);
Logger.Log($"Ran {methodName} in {sw}", true);
}
}
}

View File

@@ -6,15 +6,16 @@ namespace Flowframes.MiscUtils
{
class NmkdStopwatch
{
public Stopwatch sw = new Stopwatch();
public Stopwatch sw = new Stopwatch();
public long ElapsedMs { get { return sw.ElapsedMilliseconds; } }
public NmkdStopwatch (bool startOnCreation = true)
public NmkdStopwatch(bool startOnCreation = true)
{
if (startOnCreation)
sw.Restart();
}
public string GetElapsedStr ()
public override string ToString()
{
return FormatUtils.TimeSw(sw);
}

View File

@@ -90,7 +90,7 @@ namespace Flowframes.Os
while (Interpolate.currentlyUsingAutoEnc && Program.busy)
{
if (AvProcess.lastAvProcess != null && !AvProcess.lastAvProcess.HasExited && AvProcess.lastTask == AvProcess.TaskType.Encode)
if (AvProcess.lastAvProcess != null && !AvProcess.lastAvProcess.HasExited)
{
string lastLine = AvProcess.lastOutputFfmpeg.SplitIntoLines().Last();
Logger.Log(FormatUtils.BeautifyFfmpegStats(lastLine), false, Logger.GetLastLine().ToLower().Contains("frame"));

View File

@@ -226,7 +226,7 @@ namespace Flowframes.Os
while (timeSinceLastOutput.ElapsedMilliseconds < 100) await Task.Delay(50);
output = output.Trim('\r', '\n');
Logger.Log($"Output (after {sw.GetElapsedStr()}): {output.Replace("\r", " / ").Replace("\n", " / ").Trunc(250)}", true);
Logger.Log($"Output (after {sw}): {output.Replace("\r", " / ").Replace("\n", " / ").Trunc(250)}", true);
if (onlyLastLine)
output = output.SplitIntoLines().LastOrDefault();

View File

@@ -112,7 +112,7 @@ namespace Flowframes.Ui
}
Config.Set(dict);
Logger.Log($"Config Editor: Saved {grid.Rows.Count} config keys in {sw.GetElapsedStr()}", true);
Logger.Log($"Config Editor: Saved {grid.Rows.Count} config keys in {sw}", true);
}
#endregion

View File

@@ -26,7 +26,7 @@ namespace Flowframes.Ui
if (Config.GetBool(Config.Key.clearLogOnInput))
Logger.ClearLogBox();
SetOutPath(inputTbox, inputTbox.Text.Trim().GetParentDir());
SetOutPath(outputTbox, inputTbox.Text.Trim().GetParentDir());
Program.lastInputPath = path;
Program.lastInputPathIsSsd = OsUtils.DriveIsSSD(path);