mirror of
https://github.com/n00mkrad/flowframes.git
synced 2025-12-16 16:37:48 +01:00
Optmized timecode generation, UI/UX improvs, finished autoencode mode
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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...");
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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"));
|
||||||
|
|||||||
Reference in New Issue
Block a user