Optmized timecode generation, UI/UX improvs, finished autoencode mode

This commit is contained in:
N00MKRAD
2020-11-30 20:32:33 +01:00
parent ee29608123
commit d223351fe6
11 changed files with 85 additions and 56 deletions

View File

@@ -21,6 +21,11 @@ namespace Flowframes
static LogMode currentLogMode; static LogMode currentLogMode;
public static async Task RunFfmpeg(string args, LogMode logMode) public static async Task RunFfmpeg(string args, LogMode logMode)
{
await RunFfmpeg(args, "", logMode);
}
public static async Task RunFfmpeg(string args, string workingDir, LogMode logMode)
{ {
lastOutputFfmpeg = ""; lastOutputFfmpeg = "";
currentLogMode = logMode; currentLogMode = logMode;
@@ -31,8 +36,11 @@ namespace Flowframes
ffmpeg.StartInfo.RedirectStandardError = true; ffmpeg.StartInfo.RedirectStandardError = true;
ffmpeg.StartInfo.CreateNoWindow = true; ffmpeg.StartInfo.CreateNoWindow = true;
ffmpeg.StartInfo.FileName = "cmd.exe"; ffmpeg.StartInfo.FileName = "cmd.exe";
ffmpeg.StartInfo.Arguments = "/C cd /D \"" + GetAvDir() + "\" & ffmpeg.exe -hide_banner -loglevel warning -y -stats " + args; if(!string.IsNullOrWhiteSpace(workingDir))
if(logMode != LogMode.Hidden) Logger.Log("Running ffmpeg...", false); ffmpeg.StartInfo.Arguments = $"/C cd /D {workingDir.Wrap()} & {Path.Combine(GetAvDir(), "ffmpeg.exe").Wrap()} -hide_banner -loglevel warning -y -stats {args}";
else
ffmpeg.StartInfo.Arguments = $"/C cd /D {GetAvDir().Wrap()} & ffmpeg.exe -hide_banner -loglevel warning -y -stats {args}";
if (logMode != LogMode.Hidden) Logger.Log("Running ffmpeg...", false);
Logger.Log("cmd.exe " + ffmpeg.StartInfo.Arguments, true, false, "ffmpeg.txt"); Logger.Log("cmd.exe " + ffmpeg.StartInfo.Arguments, true, false, "ffmpeg.txt");
ffmpeg.OutputDataReceived += new DataReceivedEventHandler(FfmpegOutputHandler); ffmpeg.OutputDataReceived += new DataReceivedEventHandler(FfmpegOutputHandler);
ffmpeg.ErrorDataReceived += new DataReceivedEventHandler(FfmpegOutputHandler); ffmpeg.ErrorDataReceived += new DataReceivedEventHandler(FfmpegOutputHandler);

View File

@@ -84,8 +84,9 @@ namespace Flowframes
string loopStr = (looptimes > 0) ? $"-stream_loop {looptimes}" : ""; string loopStr = (looptimes > 0) ? $"-stream_loop {looptimes}" : "";
string presetStr = $"-preset {Config.Get("ffEncPreset")}"; string presetStr = $"-preset {Config.Get("ffEncPreset")}";
string vsyncStr = Config.GetInt("vfrMode") == 0 ? "-vsync 1" : "-vsync 2"; string vsyncStr = Config.GetInt("vfrMode") == 0 ? "-vsync 1" : "-vsync 2";
string args = $" {loopStr} {vsyncStr} -f concat -safe 0 -i {framesFile.Wrap()} -r {fps.ToString().Replace(",", ".")} -c:v {enc} -crf {crf} {presetStr} {videoEncArgs} -threads {Config.GetInt("ffEncThreads")} -c:a copy {outPath.Wrap()}"; string vfrFilename = Path.GetFileName(framesFile);
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine); string args = $" {loopStr} {vsyncStr} -f concat -safe 0 -i {vfrFilename} -r {fps.ToString().Replace(",", ".")} -c:v {enc} -crf {crf} {presetStr} {videoEncArgs} -threads {Config.GetInt("ffEncThreads")} -c:a copy {outPath.Wrap()}";
await AvProcess.RunFfmpeg(args, framesFile.GetParentDir(), AvProcess.LogMode.OnlyLastLine);
} }
public static async Task FramesToMp4VfrChunk(string framesFile, string outPath, bool useH265, int crf, float fps) public static async Task FramesToMp4VfrChunk(string framesFile, string outPath, bool useH265, int crf, float fps)
@@ -94,8 +95,9 @@ namespace Flowframes
string enc = useH265 ? "libx265" : "libx264"; string enc = useH265 ? "libx265" : "libx264";
string presetStr = $"-preset {Config.Get("ffEncPreset")}"; string presetStr = $"-preset {Config.Get("ffEncPreset")}";
string vsyncStr = Config.GetInt("vfrMode") == 0 ? "-vsync 1" : "-vsync 2"; string vsyncStr = Config.GetInt("vfrMode") == 0 ? "-vsync 1" : "-vsync 2";
string args = $" {vsyncStr} -f concat -safe 0 -i {framesFile.Wrap()} -r {fps.ToString().Replace(",", ".")} -c:v {enc} -crf {crf} {presetStr} {videoEncArgs} -threads {Config.GetInt("ffEncThreads")} -c:a copy {outPath.Wrap()}"; string vfrFilename = Path.GetFileName(framesFile);
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.Hidden); string args = $" {vsyncStr} -f concat -safe 0 -i {vfrFilename} -r {fps.ToString().Replace(",", ".")} -c:v {enc} -crf {crf} {presetStr} {videoEncArgs} -threads {Config.GetInt("ffEncThreads")} -c:a copy {outPath.Wrap()}";
await AvProcess.RunFfmpeg(args, framesFile.GetParentDir(), AvProcess.LogMode.Hidden);
} }
public static async Task ConcatVideos (string concatFile, string outPath, float fps, int looptimes = -1) public static async Task ConcatVideos (string concatFile, string outPath, float fps, int looptimes = -1)
@@ -103,8 +105,9 @@ namespace Flowframes
Logger.Log($"Merging videos..."); Logger.Log($"Merging videos...");
string loopStr = (looptimes > 0) ? $"-stream_loop {looptimes}" : ""; string loopStr = (looptimes > 0) ? $"-stream_loop {looptimes}" : "";
string vsyncStr = Config.GetInt("vfrMode") == 0 ? "-vsync 1" : "-vsync 2"; string vsyncStr = Config.GetInt("vfrMode") == 0 ? "-vsync 1" : "-vsync 2";
string args = $" {loopStr} {vsyncStr} -f concat -safe 0 -i {concatFile.Wrap()} -r {fps.ToString().Replace(",", ".")} -c copy -pix_fmt yuv420p -movflags +faststart {outPath.Wrap()}"; string vfrFilename = Path.GetFileName(concatFile);
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.Hidden); string args = $" {loopStr} {vsyncStr} -f concat -safe 0 -i {vfrFilename} -r {fps.ToString().Replace(",", ".")} -c copy -pix_fmt yuv420p -movflags +faststart {outPath.Wrap()}";
await AvProcess.RunFfmpeg(args, concatFile.GetParentDir(), AvProcess.LogMode.Hidden);
} }
public static async Task ConvertFramerate (string inputPath, string outPath, bool useH265, int crf, float newFps, bool delSrc = false) public static async Task ConvertFramerate (string inputPath, string outPath, bool useH265, int crf, float newFps, bool delSrc = false)

View File

@@ -9,7 +9,10 @@ namespace Flowframes.IO
{ {
class Paths class Paths
{ {
public const string framesDir = "frames";
public const string interpDir = "interp";
public const string chunksDir = "vchunks";
public const string scenesDir = "scenes";
public static void Init() public static void Init()
{ {

View File

@@ -203,7 +203,7 @@ namespace Flowframes.Magick
if (statsFramesKept <= 0) if (statsFramesKept <= 0)
Interpolate.Cancel("No frames were left after de-duplication."); Interpolate.Cancel("No frames were left after de-duplication.");
Logger.Log($"Finished in {FormatUtils.Time(sw.Elapsed)} - {framePaths.Length / (sw.ElapsedMilliseconds / 1000f)} Imgs/Sec"); //Logger.Log($"Finished in {FormatUtils.Time(sw.Elapsed)} - {framePaths.Length / (sw.ElapsedMilliseconds / 1000f)} Imgs/Sec");
//RenameCounterDir(path, "png"); //RenameCounterDir(path, "png");
//ZeroPadDir(path, ext, 8); //ZeroPadDir(path, ext, 8);

View File

@@ -23,12 +23,12 @@ namespace Flowframes.Main
public static async Task MainLoop(string interpFramesPath) public static async Task MainLoop(string interpFramesPath)
{ {
interpFramesFolder = interpFramesPath; interpFramesFolder = interpFramesPath;
videoChunksFolder = Path.Combine(interpFramesPath.GetParentDir(), "video-chunks"); videoChunksFolder = Path.Combine(interpFramesPath.GetParentDir(), Paths.chunksDir);
encodedFrames.Clear(); encodedFrames.Clear();
unencodedFrames.Clear(); unencodedFrames.Clear();
int interpFramesAmount = GetInterpFramesAmount(); int interpFramesAmount;
chunkSize = GetChunkSize(IOUtils.GetAmountOfFiles(Interpolate.currentFramesPath, false, "*.png") * Interpolate.lastInterpFactor); chunkSize = GetChunkSize(IOUtils.GetAmountOfFiles(Interpolate.currentFramesPath, false, "*.png") * Interpolate.lastInterpFactor);
int videoIndex = 1; int videoIndex = 1;
@@ -36,7 +36,7 @@ namespace Flowframes.Main
while (!Interpolate.canceled && GetInterpFramesAmount() < 2) while (!Interpolate.canceled && GetInterpFramesAmount() < 2)
await Task.Delay(100); await Task.Delay(100);
while ((AiProcess.currentAiProcess != null && !AiProcess.currentAiProcess.HasExited) || encodedFrames.Count < interpFramesAmount) // Loop while proc is running and not all frames have been encoded while (HasWorkToDo()) // Loop while proc is running and not all frames have been encoded
{ {
if (Interpolate.canceled) return; if (Interpolate.canceled) return;
@@ -53,13 +53,13 @@ namespace Flowframes.Main
busy = true; busy = true;
Logger.Log("Encoding Chunk #" + videoIndex, true, false, "ffmpeg.txt"); Logger.Log("Encoding Chunk #" + videoIndex, true, false, "ffmpeg.txt");
List<string> framesToEncode = aiRunning ? unencodedFrames.Take(chunkSize).ToList() : unencodedFrames; // Take all remaining frames if process is done List<string> framesToEncode = aiRunning ? unencodedFrames.Take(chunkSize).ToList() : unencodedFrames; // Take all remaining frames if process is done
string outpath = Path.Combine(videoChunksFolder, $"{videoIndex.ToString().PadLeft(4, '0')}{InterpolateUtils.GetExt(Interpolate.currentOutMode)}"); string outpath = Path.Combine(videoChunksFolder, $"{videoIndex.ToString().PadLeft(4, '0')}{InterpolateUtils.GetExt(Interpolate.currentOutMode)}");
int firstFrameNum = Path.GetFileNameWithoutExtension(framesToEncode[0]).GetInt(); int firstFrameNum = Path.GetFileNameWithoutExtension(framesToEncode[0]).GetInt();
await CreateVideo.EncodeChunk(outpath, firstFrameNum, framesToEncode.Count); await CreateVideo.EncodeChunk(outpath, firstFrameNum, framesToEncode.Count);
videoIndex++;
if(Interpolate.canceled) return;
foreach (string frame in framesToEncode) foreach (string frame in framesToEncode)
File.WriteAllText(frame, "THIS IS A DUMMY FILE - DO NOT DELETE ME"); // Overwrite to save disk space without breaking progress counter File.WriteAllText(frame, "THIS IS A DUMMY FILE - DO NOT DELETE ME"); // Overwrite to save disk space without breaking progress counter
@@ -67,6 +67,7 @@ namespace Flowframes.Main
encodedFrames.AddRange(framesToEncode); encodedFrames.AddRange(framesToEncode);
Logger.Log("Done Encoding Chunk #" + videoIndex, true, false, "ffmpeg.txt"); Logger.Log("Done Encoding Chunk #" + videoIndex, true, false, "ffmpeg.txt");
videoIndex++;
busy = false; busy = false;
} }
await Task.Delay(50); await Task.Delay(50);
@@ -77,12 +78,17 @@ namespace Flowframes.Main
string concatFile = Path.Combine(interpFramesPath.GetParentDir(), "chunks-concat.ini"); string concatFile = Path.Combine(interpFramesPath.GetParentDir(), "chunks-concat.ini");
string concatFileContent = ""; string concatFileContent = "";
foreach (string vid in Directory.GetFiles(videoChunksFolder)) foreach (string vid in Directory.GetFiles(videoChunksFolder))
concatFileContent += $"file '{vid.Replace("\\", "/")}'\n"; concatFileContent += $"file '{Paths.chunksDir}/{Path.GetFileName(vid)}'\n";
File.WriteAllText(concatFile, concatFileContent); File.WriteAllText(concatFile, concatFileContent);
await CreateVideo.ChunksToVideo(videoChunksFolder, concatFile, Interpolate.nextOutPath); await CreateVideo.ChunksToVideo(videoChunksFolder, concatFile, Interpolate.nextOutPath);
} }
public static bool HasWorkToDo ()
{
return ((AiProcess.currentAiProcess != null && !AiProcess.currentAiProcess.HasExited) || encodedFrames.Count < GetInterpFramesAmount());
}
static int GetChunkSize(int targetFramesAmount) static int GetChunkSize(int targetFramesAmount)
{ {
if (targetFramesAmount > 50000) return 2000; if (targetFramesAmount > 50000) return 2000;

View File

@@ -119,14 +119,12 @@ namespace Flowframes.Main
static async Task MergeChunks(string chunksPath, string vfrFile, string outPath, float fps, float changeFps = -1, bool keepOriginalFpsVid = true) static async Task MergeChunks(string chunksPath, string vfrFile, string outPath, float fps, float changeFps = -1, bool keepOriginalFpsVid = true)
{ {
int looptimes = GetLoopTimes(Path.Combine(chunksPath.GetParentDir(), "frames-interpolated")); int looptimes = GetLoopTimes(Path.Combine(chunksPath.GetParentDir(), Paths.interpDir));
bool h265 = Config.GetInt("mp4Enc") == 1; bool h265 = Config.GetInt("mp4Enc") == 1;
int crf = h265 ? Config.GetInt("h265Crf") : Config.GetInt("h264Crf"); int crf = h265 ? Config.GetInt("h265Crf") : Config.GetInt("h264Crf");
//string vfrFile = Path.Combine(chunksPath.GetParentDir(), $"vfr-x{i.lastInterpFactor}.ini");
await FFmpegCommands.ConcatVideos(vfrFile, outPath, fps, -1); await FFmpegCommands.ConcatVideos(vfrFile, outPath, fps, -1);
await MergeAudio(i.lastInputPath, outPath); await MergeAudio(i.lastInputPath, outPath);
if (looptimes > 0) if (looptimes > 0)
@@ -164,12 +162,17 @@ namespace Flowframes.Main
static int GetLoopTimes(string framesOutPath) static int GetLoopTimes(string framesOutPath)
{ {
//Logger.Log("Getting loop times for path " + framesOutPath);
int times = -1; int times = -1;
int minLength = Config.GetInt("minOutVidLength"); int minLength = Config.GetInt("minOutVidLength");
//Logger.Log("minLength: " + minLength);
int minFrameCount = (minLength * i.currentOutFps).RoundToInt(); int minFrameCount = (minLength * i.currentOutFps).RoundToInt();
//Logger.Log("minFrameCount: " + minFrameCount);
int outFrames = new DirectoryInfo(framesOutPath).GetFiles($"*.{InterpolateUtils.lastExt}", SearchOption.TopDirectoryOnly).Length; int outFrames = new DirectoryInfo(framesOutPath).GetFiles($"*.{InterpolateUtils.lastExt}", SearchOption.TopDirectoryOnly).Length;
//Logger.Log("outFrames: " + outFrames);
if (outFrames / i.currentOutFps < minLength) if (outFrames / i.currentOutFps < minLength)
times = (int)Math.Ceiling((double)minFrameCount / (double)outFrames); times = (int)Math.Ceiling((double)minFrameCount / (double)outFrames);
//Logger.Log("times: " + times);
times--; // Account for this calculation not counting the 1st play (0 loops) times--; // Account for this calculation not counting the 1st play (0 loops)
if (times <= 0) return -1; // Never try to loop 0 times, idk what would happen, probably nothing if (times <= 0) return -1; // Never try to loop 0 times, idk what would happen, probably nothing
return times; return times;

View File

@@ -53,7 +53,7 @@ namespace Flowframes
lastInterpFactor = interpFactor; lastInterpFactor = interpFactor;
lastInputPath = inPath; lastInputPath = inPath;
currentTempDir = Utils.GetTempFolderLoc(inPath, outDir); currentTempDir = Utils.GetTempFolderLoc(inPath, outDir);
currentFramesPath = Path.Combine(currentTempDir, "frames"); currentFramesPath = Path.Combine(currentTempDir, Paths.framesDir);
currentOutMode = outMode; currentOutMode = outMode;
if (!Utils.CheckDeleteOldTempFolder()) return; // Try to delete temp folder if an old one exists if (!Utils.CheckDeleteOldTempFolder()) return; // Try to delete temp folder if an old one exists
if(!Utils.CheckPathValid(inPath)) return; // Check if input path/file is valid if(!Utils.CheckPathValid(inPath)) return; // Check if input path/file is valid
@@ -71,7 +71,7 @@ namespace Flowframes
await Task.Delay(10); await Task.Delay(10);
await PostProcessFrames(); await PostProcessFrames();
if (canceled) return; if (canceled) return;
string interpFramesDir = Path.Combine(currentTempDir, "frames-interpolated"); string interpFramesDir = Path.Combine(currentTempDir, Paths.interpDir);
nextOutPath = Path.Combine(outDir, Path.GetFileNameWithoutExtension(inPath) + IOUtils.GetAiSuffix(ai, interpFactor) + Utils.GetExt(outMode)); nextOutPath = Path.Combine(outDir, Path.GetFileNameWithoutExtension(inPath) + IOUtils.GetAiSuffix(ai, interpFactor) + Utils.GetExt(outMode));
int frames = IOUtils.GetAmountOfFiles(currentFramesPath, false, "*.png"); int frames = IOUtils.GetAmountOfFiles(currentFramesPath, false, "*.png");
int targetFrameCount = frames * interpFactor; int targetFrameCount = frames * interpFactor;
@@ -95,7 +95,7 @@ namespace Flowframes
if (Config.GetBool("scnDetect")) if (Config.GetBool("scnDetect"))
{ {
Program.mainForm.SetStatus("Extracting scenes from video..."); Program.mainForm.SetStatus("Extracting scenes from video...");
await FFmpegCommands.ExtractSceneChanges(inPath, Path.Combine(currentTempDir, "scenes")); await FFmpegCommands.ExtractSceneChanges(inPath, Path.Combine(currentTempDir, Paths.scenesDir));
await Task.Delay(10); await Task.Delay(10);
} }
Program.mainForm.SetStatus("Extracting frames from video..."); Program.mainForm.SetStatus("Extracting frames from video...");

View File

@@ -59,19 +59,19 @@ namespace Flowframes.Main
currentTempDir = InterpolateUtils.GetTempFolderLoc(currentInPath, currentOutPath); currentTempDir = InterpolateUtils.GetTempFolderLoc(currentInPath, currentOutPath);
if (string.IsNullOrWhiteSpace(currentFramesPath)) if (string.IsNullOrWhiteSpace(currentFramesPath))
currentFramesPath = Path.Combine(currentTempDir, "frames"); currentFramesPath = Path.Combine(currentTempDir, Paths.framesDir);
} }
public static async Task ExtractSceneChanges () public static async Task ExtractSceneChanges ()
{ {
Program.mainForm.SetStatus("Extracting scenes from video..."); Program.mainForm.SetStatus("Extracting scenes from video...");
await FFmpegCommands.ExtractSceneChanges(currentInPath, Path.Combine(currentTempDir, "scenes")); await FFmpegCommands.ExtractSceneChanges(currentInPath, Path.Combine(currentTempDir, Paths.scenesDir));
await Task.Delay(10); await Task.Delay(10);
} }
public static async Task ExtractVideoFrames () public static async Task ExtractVideoFrames ()
{ {
currentFramesPath = Path.Combine(currentTempDir, "frames"); currentFramesPath = Path.Combine(currentTempDir, Paths.framesDir);
bool extractAudio = true; bool extractAudio = true;
Program.mainForm.SetStatus("Extracting frames from video..."); Program.mainForm.SetStatus("Extracting frames from video...");
Size resolution = IOUtils.GetVideoRes(currentInPath); Size resolution = IOUtils.GetVideoRes(currentInPath);
@@ -108,7 +108,7 @@ namespace Flowframes.Main
{ {
await PostProcessFrames(); await PostProcessFrames();
string interpFramesDir = Path.Combine(currentTempDir, "frames-interpolated"); string interpFramesDir = Path.Combine(currentTempDir, Paths.interpDir);
if (!IOUtils.TryDeleteIfExists(interpFramesDir)) if (!IOUtils.TryDeleteIfExists(interpFramesDir))
{ {
InterpolateUtils.ShowMessage("Failed to delete old \"interpolated-frames folder\" - Make sure none of the files are opened in another program!", "Error"); InterpolateUtils.ShowMessage("Failed to delete old \"interpolated-frames folder\" - Make sure none of the files are opened in another program!", "Error");
@@ -127,7 +127,7 @@ namespace Flowframes.Main
public static async Task CreateOutputVid () public static async Task CreateOutputVid ()
{ {
currentInterpFramesDir = Path.Combine(currentTempDir, "frames-interpolated"); currentInterpFramesDir = Path.Combine(currentTempDir, Paths.interpDir);
string outPath = Path.Combine(currentOutPath, Path.GetFileNameWithoutExtension(currentInPath) + IOUtils.GetAiSuffix(currentAi, lastInterpFactor) + InterpolateUtils.GetExt(currentOutMode)); string outPath = Path.Combine(currentOutPath, Path.GetFileNameWithoutExtension(currentInPath) + IOUtils.GetAiSuffix(currentAi, lastInterpFactor) + InterpolateUtils.GetExt(currentOutMode));
await CreateVideo.FramesToVideo(currentInterpFramesDir, outPath, currentOutMode); await CreateVideo.FramesToVideo(currentInterpFramesDir, outPath, currentOutMode);
} }

View File

@@ -3,6 +3,7 @@ using Flowframes.UI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -27,6 +28,9 @@ namespace Flowframes.Main
public static async Task CreateTimecodeFile(string framesPath, bool loopEnabled, int interpFactor, bool firstFrameFix) public static async Task CreateTimecodeFile(string framesPath, bool loopEnabled, int interpFactor, bool firstFrameFix)
{ {
if (Interpolate.canceled) return;
Logger.Log($"Generating timecodes for {interpFactor}x...", false, true);
bool sceneDetection = true; bool sceneDetection = true;
if(frameFiles == null || frameFiles.Length < 1) if(frameFiles == null || frameFiles.Length < 1)
@@ -34,8 +38,10 @@ namespace Flowframes.Main
string vfrFile = Path.Combine(framesPath.GetParentDir(), $"vfr-x{interpFactor}.ini"); string vfrFile = Path.Combine(framesPath.GetParentDir(), $"vfr-x{interpFactor}.ini");
string fileContent = ""; string fileContent = "";
string scnFramesPath = Path.Combine(framesPath.GetParentDir(), "scenes"); string scnFramesPath = Path.Combine(framesPath.GetParentDir(), Paths.scenesDir);
string interpPath = framesPath.Replace(@"\", "/") + "-interpolated"; string interpPath = Paths.interpDir; // framesPath.Replace(@"\", "/") + "-interpolated";
List<string> sceneFrames = Directory.GetFiles(scnFramesPath).Select(file => Path.GetFileName(file)).ToList();
int lastFrameDuration = 1; int lastFrameDuration = 1;
@@ -55,9 +61,8 @@ namespace Flowframes.Main
int interpFramesAmount = interpFactor; int interpFramesAmount = interpFactor;
bool discardThisFrame = (sceneDetection && (i + 2) < frameFiles.Length && sceneFrames.Contains(frameFiles[i + 1].Name)); // i+2 is in scene detection folder, means i+1 is ugly interp frame
bool discardThisFrame = (sceneDetection && (i + 2) < frameFiles.Length && File.Exists(Path.Combine(scnFramesPath, frameFiles[i + 1].Name))); // i+2 is in scene detection folder, means i+1 is ugly interp frame
//if (discardThisFrame) Logger.Log("Will discard " + totalFileCount);
// If loop is enabled, account for the extra frame added to the end for loop continuity // If loop is enabled, account for the extra frame added to the end for loop continuity
if (loopEnabled && i == (frameFiles.Length - 2)) if (loopEnabled && i == (frameFiles.Length - 2))
@@ -66,30 +71,25 @@ namespace Flowframes.Main
// Generate frames file lines // Generate frames file lines
for (int frm = 0; frm < interpFramesAmount; frm++) for (int frm = 0; frm < interpFramesAmount; frm++)
{ {
string durationStr = ((durationPerInterpFrame / 1000f) * 1).ToString("0.00000").Replace(",", "."); string durationStr = ((durationPerInterpFrame / 1000f) * 1).ToString("0.00000", CultureInfo.InvariantCulture);
if (discardThisFrame) if (discardThisFrame)
{ {
int lastNum = totalFileCount - 1; int lastNum = totalFileCount - 1;
for (int dupeCount = 1; dupeCount < interpFramesAmount; dupeCount++) for (int dupeCount = 1; dupeCount < interpFramesAmount; dupeCount++)
{ {
//Logger.Log($"-> Writing #{frm + 1}: {lastNum}");
fileContent += $"file '{interpPath}/{lastNum.ToString().PadLeft(8, '0')}.png'\nduration {durationStr}\n"; fileContent += $"file '{interpPath}/{lastNum.ToString().PadLeft(8, '0')}.png'\nduration {durationStr}\n";
totalFileCount++; totalFileCount++;
} }
frm = interpFramesAmount - 1; frm = interpFramesAmount - 1;
} }
//Logger.Log($"-> Writing #{frm+1}: {totalFileCount}");
fileContent += $"file '{interpPath}/{totalFileCount.ToString().PadLeft(8, '0')}.png'\nduration {durationStr}\n"; fileContent += $"file '{interpPath}/{totalFileCount.ToString().PadLeft(8, '0')}.png'\nduration {durationStr}\n";
totalFileCount++; // Don't increment, so we dupe the last frame and ignore the interp frame totalFileCount++;
} }
if ((i + 1) % 100 == 0) if ((i + 1) % 100 == 0)
{
Logger.Log($"Generating timecodes for {interpFactor}x...", false, true);
await Task.Delay(1); await Task.Delay(1);
}
} }
File.WriteAllText(vfrFile, fileContent); File.WriteAllText(vfrFile, fileContent);

View File

@@ -23,7 +23,7 @@ namespace Flowframes
public static int lastStartupTimeMs = 1000; public static int lastStartupTimeMs = 1000;
static void Init (Process proc, int startupTimeMs, string defaultExt = "png") static void AiStarted (Process proc, int startupTimeMs, string defaultExt = "png")
{ {
lastStartupTimeMs = startupTimeMs; lastStartupTimeMs = startupTimeMs;
InterpolateUtils.lastExt = defaultExt; InterpolateUtils.lastExt = defaultExt;
@@ -33,13 +33,23 @@ namespace Flowframes
hasShownError = false; hasShownError = false;
} }
static void AiFinished (string aiName)
{
Program.mainForm.SetProgress(100);
string logStr = $"Done running {aiName} - Interpolation took {FormatUtils.Time(processTime.Elapsed)}";
if (AutoEncode.HasWorkToDo())
logStr += " - Waiting for encoding to finish...";
Logger.Log(logStr);
processTime.Stop();
}
public static async Task RunDainNcnn(string framesPath, string outPath, int targetFrames, int tilesize) public static async Task RunDainNcnn(string framesPath, string outPath, int targetFrames, int tilesize)
{ {
string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -n {targetFrames} -t {tilesize} -g {Config.Get("ncnnGpus")}"; string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -n {targetFrames} -t {tilesize} -g {Config.Get("ncnnGpus")}";
string dainDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.dainNcnn.fileName)); string dainDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.dainNcnn.fileName));
Process dain = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd()); Process dain = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd());
Init(dain, 1500); AiStarted(dain, 1500);
dain.StartInfo.Arguments = $"{OSUtils.GetCmdArg()} cd /D {dainDir.Wrap()} & dain-ncnn-vulkan.exe {args} -f {InterpolateUtils.lastExt} -j 4:{Config.Get("ncnnThreads")}:4"; dain.StartInfo.Arguments = $"{OSUtils.GetCmdArg()} cd /D {dainDir.Wrap()} & dain-ncnn-vulkan.exe {args} -f {InterpolateUtils.lastExt} -j 4:{Config.Get("ncnnThreads")}:4";
Logger.Log("Running DAIN...", false); Logger.Log("Running DAIN...", false);
Logger.Log("cmd.exe " + dain.StartInfo.Arguments, true); Logger.Log("cmd.exe " + dain.StartInfo.Arguments, true);
@@ -59,8 +69,7 @@ namespace Flowframes
if (Interpolate.canceled) return; if (Interpolate.canceled) return;
Magick.MagickDedupe.ZeroPadDir(outPath, InterpolateUtils.lastExt, 8); Magick.MagickDedupe.ZeroPadDir(outPath, InterpolateUtils.lastExt, 8);
Logger.Log($"Done running DAIN - Interpolation took " + FormatUtils.Time(processTime.Elapsed)); AiFinished("DAIN");
processTime.Stop();
} }
public static async Task RunCainNcnnMulti (string framesPath, string outPath, int tilesize, int times) public static async Task RunCainNcnnMulti (string framesPath, string outPath, int tilesize, int times)
@@ -100,8 +109,7 @@ namespace Flowframes
if (Interpolate.canceled) return; if (Interpolate.canceled) return;
Magick.MagickDedupe.ZeroPadDir(outPath, InterpolateUtils.lastExt, 8); Magick.MagickDedupe.ZeroPadDir(outPath, InterpolateUtils.lastExt, 8);
Logger.Log($"Done running CAIN - Interpolation took " + FormatUtils.Time(processTimeMulti.Elapsed)); AiFinished("CAIN");
processTime.Stop();
} }
static async Task RunCainPartial (string args) static async Task RunCainPartial (string args)
@@ -109,7 +117,7 @@ namespace Flowframes
string cainDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.cainNcnn.fileName)); string cainDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.cainNcnn.fileName));
string cainExe = "cain-ncnn-vulkan.exe"; string cainExe = "cain-ncnn-vulkan.exe";
Process cain = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd()); Process cain = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd());
Init(cain, 1500); AiStarted(cain, 1500);
cain.StartInfo.Arguments = $"{OSUtils.GetCmdArg()} cd /D {cainDir.Wrap()} & {cainExe} {args} -f {InterpolateUtils.lastExt} -j 4:{Config.Get("ncnnThreads")}:4"; cain.StartInfo.Arguments = $"{OSUtils.GetCmdArg()} cd /D {cainDir.Wrap()} & {cainExe} {args} -f {InterpolateUtils.lastExt} -j 4:{Config.Get("ncnnThreads")}:4";
Logger.Log("cmd.exe " + cain.StartInfo.Arguments, true); Logger.Log("cmd.exe " + cain.StartInfo.Arguments, true);
if (!OSUtils.ShowHiddenCmd()) if (!OSUtils.ShowHiddenCmd())
@@ -134,10 +142,10 @@ namespace Flowframes
string rifeDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.rifeCuda.fileName)); string rifeDir = Path.Combine(Paths.GetPkgPath(), Path.GetFileNameWithoutExtension(Packages.rifeCuda.fileName));
Process rifePy = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd()); Process rifePy = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd());
Init(rifePy, 3000, "png"); AiStarted(rifePy, 3000, "png");
string args = $" --input {framesPath.Wrap()} --times {(int)Math.Log(interpFactor, 2)}"; string args = $" --input {framesPath.Wrap()} --times {(int)Math.Log(interpFactor, 2)}";
rifePy.StartInfo.Arguments = $"{OSUtils.GetCmdArg()} cd /D {PkgUtils.GetPkgFolder(Packages.rifeCuda).Wrap()} & " + rifePy.StartInfo.Arguments = $"{OSUtils.GetCmdArg()} cd /D {PkgUtils.GetPkgFolder(Packages.rifeCuda).Wrap()} & " +
$"set CUDA_VISIBLE_DEVICES={Config.Get("torchGpus")} & {Pytorch.GetPyCmd()} {script} {args} --imgformat {InterpolateUtils.lastExt}"; $"set CUDA_VISIBLE_DEVICES={Config.Get("torchGpus")} & {Pytorch.GetPyCmd()} {script} {args} --imgformat {InterpolateUtils.lastExt} --output {Paths.interpDir}";
Logger.Log($"Running RIFE ({script})...", false); Logger.Log($"Running RIFE ({script})...", false);
Logger.Log("cmd.exe " + rifePy.StartInfo.Arguments, true); Logger.Log("cmd.exe " + rifePy.StartInfo.Arguments, true);
if (!OSUtils.ShowHiddenCmd()) if (!OSUtils.ShowHiddenCmd())
@@ -152,15 +160,14 @@ namespace Flowframes
rifePy.BeginErrorReadLine(); rifePy.BeginErrorReadLine();
} }
while (!rifePy.HasExited) await Task.Delay(1); while (!rifePy.HasExited) await Task.Delay(1);
Logger.Log($"Done running RIFE - Interpolation took " + FormatUtils.Time(processTime.Elapsed)); AiFinished("RIFE");
processTime.Stop();
} }
public static async Task RunRifeNcnn (string framesPath, string outPath, int interpFactor, int tilesize) public static async Task RunRifeNcnn (string framesPath, string outPath, int interpFactor, int tilesize)
{ {
string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get("ncnnGpus")} -f {InterpolateUtils.lastExt} -j 4:{Config.Get("ncnnThreads")}:4"; string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -t {tilesize} -g {Config.Get("ncnnGpus")} -f {InterpolateUtils.lastExt} -j 4:{Config.Get("ncnnThreads")}:4";
Process rifeNcnn = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd()); Process rifeNcnn = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd());
Init(rifeNcnn, 750); AiStarted(rifeNcnn, 750);
rifeNcnn.StartInfo.Arguments = $"{OSUtils.GetCmdArg()} cd /D {PkgUtils.GetPkgFolder(Packages.rifeNcnn).Wrap()} & rife-ncnn-vulkan.exe {args}"; rifeNcnn.StartInfo.Arguments = $"{OSUtils.GetCmdArg()} cd /D {PkgUtils.GetPkgFolder(Packages.rifeNcnn).Wrap()} & rife-ncnn-vulkan.exe {args}";
Logger.Log("Running RIFE...", false); Logger.Log("Running RIFE...", false);
Logger.Log("cmd.exe " + rifeNcnn.StartInfo.Arguments, true); Logger.Log("cmd.exe " + rifeNcnn.StartInfo.Arguments, true);
@@ -179,8 +186,8 @@ namespace Flowframes
if (Interpolate.canceled) return; if (Interpolate.canceled) return;
Magick.MagickDedupe.ZeroPadDir(outPath, InterpolateUtils.lastExt, 8); Magick.MagickDedupe.ZeroPadDir(outPath, InterpolateUtils.lastExt, 8);
Logger.Log($"Done running RIFE - Interpolation took " + FormatUtils.Time(processTime.Elapsed));
processTime.Stop(); AiFinished("RIFE");
} }
public static async Task RunRifeNcnnMulti(string framesPath, string outPath, int tilesize, int times) public static async Task RunRifeNcnnMulti(string framesPath, string outPath, int tilesize, int times)
@@ -220,14 +227,13 @@ namespace Flowframes
if (Interpolate.canceled) return; if (Interpolate.canceled) return;
Magick.MagickDedupe.ZeroPadDir(outPath, InterpolateUtils.lastExt, 8); Magick.MagickDedupe.ZeroPadDir(outPath, InterpolateUtils.lastExt, 8);
Logger.Log($"Done running RIFE - Interpolation took " + FormatUtils.Time(processTimeMulti.Elapsed)); AiFinished("RIFE");
processTime.Stop();
} }
static async Task RunRifePartial(string args) static async Task RunRifePartial(string args)
{ {
Process rifeNcnn = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd()); Process rifeNcnn = OSUtils.NewProcess(!OSUtils.ShowHiddenCmd());
Init(rifeNcnn, 1500); AiStarted(rifeNcnn, 1500);
rifeNcnn.StartInfo.Arguments = $"{OSUtils.GetCmdArg()} cd /D {PkgUtils.GetPkgFolder(Packages.rifeNcnn).Wrap()} & rife-ncnn-vulkan.exe {args} -f {InterpolateUtils.lastExt} -j 4:{Config.Get("ncnnThreads")}:4"; rifeNcnn.StartInfo.Arguments = $"{OSUtils.GetCmdArg()} cd /D {PkgUtils.GetPkgFolder(Packages.rifeNcnn).Wrap()} & rife-ncnn-vulkan.exe {args} -f {InterpolateUtils.lastExt} -j 4:{Config.Get("ncnnThreads")}:4";
Logger.Log("cmd.exe " + rifeNcnn.StartInfo.Arguments, true); Logger.Log("cmd.exe " + rifeNcnn.StartInfo.Arguments, true);
if (!OSUtils.ShowHiddenCmd()) if (!OSUtils.ShowHiddenCmd())

View File

@@ -19,7 +19,7 @@ namespace Flowframes.UI
{ {
string outPath = Path.ChangeExtension(videoPath, null) + "-extracted"; string outPath = Path.ChangeExtension(videoPath, null) + "-extracted";
Program.mainForm.SetWorking(true); Program.mainForm.SetWorking(true);
await FFmpegCommands.VideoToFrames(videoPath, Path.Combine(outPath, "frames"), false, false, false); await FFmpegCommands.VideoToFrames(videoPath, Path.Combine(outPath, Paths.framesDir), false, false, false);
File.WriteAllText(Path.Combine(outPath, "fps.ini"), Interpolate.currentInFps.ToString()); File.WriteAllText(Path.Combine(outPath, "fps.ini"), Interpolate.currentInFps.ToString());
if (withAudio) if (withAudio)
await FFmpegCommands.ExtractAudio(videoPath, Path.Combine(outPath, "audio")); await FFmpegCommands.ExtractAudio(videoPath, Path.Combine(outPath, "audio"));