mirror of
https://github.com/n00mkrad/flowframes
synced 2024-11-16 19:10:31 +01:00
ffmpeg dupes workaround, SBS ReverseRenaming fix
This commit is contained in:
parent
4d2da35727
commit
3125670bb0
@ -95,26 +95,38 @@ namespace Flowframes
|
|||||||
DeleteSource(inputDir);
|
DeleteSource(inputDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task FramesToMp4Vfr(string framesFile, string outPath, bool useH265, int crf, float fps, int looptimes = -1)
|
public static async Task FramesToMp4Vfr(string framesFile, string outPath, bool useH265, int crf, float fps, bool inRate)
|
||||||
{
|
{
|
||||||
Logger.Log($"Encoding MP4 video with CRF {crf}...");
|
Logger.Log($"Encoding MP4 video with CRF {crf}...");
|
||||||
string enc = useH265 ? "libx265" : "libx264";
|
string enc = useH265 ? "libx265" : "libx264";
|
||||||
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 vfrFilename = Path.GetFileName(framesFile);
|
string vfrFilename = Path.GetFileName(framesFile);
|
||||||
string args = $" {loopStr} {vsyncStr} -f concat -r {fps.ToString().Replace(",", ".")} -i {vfrFilename} -c:v {enc} -crf {crf} {presetStr} {videoEncArgs} -threads {Config.GetInt("ffEncThreads")} -c:a copy {outPath.Wrap()}";
|
|
||||||
|
string args = $" {vsyncStr} -f concat ";
|
||||||
|
if (inRate)
|
||||||
|
args += $"-r {fps.ToString().Replace(",", ".")} -i {vfrFilename} ";
|
||||||
|
else
|
||||||
|
args += $"-i {vfrFilename} -r {fps.ToString().Replace(",", ".")} ";
|
||||||
|
|
||||||
|
args += $"-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);
|
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, bool inRate)
|
||||||
{
|
{
|
||||||
//Logger.Log($"Encoding MP4 chunk with CRF {crf}...");
|
|
||||||
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 vfrFilename = Path.GetFileName(framesFile);
|
string vfrFilename = Path.GetFileName(framesFile);
|
||||||
string args = $" {vsyncStr} -f concat -r {fps.ToString().Replace(",", ".")} -i {vfrFilename} -c:v {enc} -crf {crf} {presetStr} {videoEncArgs} -threads {Config.GetInt("ffEncThreads")} -c:a copy {outPath.Wrap()}";
|
|
||||||
|
string args = $" {vsyncStr} -f concat ";
|
||||||
|
if (inRate)
|
||||||
|
args += $"-r {fps.ToString().Replace(",", ".")} -i {vfrFilename} ";
|
||||||
|
else
|
||||||
|
args += $"-i {vfrFilename} -r {fps.ToString().Replace(",", ".")} ";
|
||||||
|
|
||||||
|
args += $"-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);
|
await AvProcess.RunFfmpeg(args, framesFile.GetParentDir(), AvProcess.LogMode.Hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ namespace Flowframes.Main
|
|||||||
int crf = h265 ? Config.GetInt("h265Crf") : Config.GetInt("h264Crf");
|
int crf = h265 ? Config.GetInt("h265Crf") : Config.GetInt("h264Crf");
|
||||||
|
|
||||||
string vfrFile = Path.Combine(framesPath.GetParentDir(), $"vfr-x{i.lastInterpFactor}.ini");
|
string vfrFile = Path.Combine(framesPath.GetParentDir(), $"vfr-x{i.lastInterpFactor}.ini");
|
||||||
await FFmpegCommands.FramesToMp4Vfr(vfrFile, outPath, h265, crf, fps, -1);
|
await FFmpegCommands.FramesToMp4Vfr(vfrFile, outPath, h265, crf, fps, i.constantFrameRate);
|
||||||
|
|
||||||
/* DELETE THIS AS SOON AS I'M SURE I CAN USE VFR WITH TIMING DISABLED
|
/* DELETE THIS AS SOON AS I'M SURE I CAN USE VFR WITH TIMING DISABLED
|
||||||
if (Config.GetInt("timingMode") == 1 && Config.GetInt("dedupMode") != 0)
|
if (Config.GetInt("timingMode") == 1 && Config.GetInt("dedupMode") != 0)
|
||||||
@ -174,7 +174,7 @@ namespace Flowframes.Main
|
|||||||
string vfrFile = Path.Combine(i.currentTempDir, $"vfr-chunk-temp.ini");
|
string vfrFile = Path.Combine(i.currentTempDir, $"vfr-chunk-temp.ini");
|
||||||
File.WriteAllLines(vfrFile, IOUtils.ReadLines(vfrFileOriginal).Skip(firstFrameNum * 2).Take(framesAmount * 2));
|
File.WriteAllLines(vfrFile, IOUtils.ReadLines(vfrFileOriginal).Skip(firstFrameNum * 2).Take(framesAmount * 2));
|
||||||
|
|
||||||
await FFmpegCommands.FramesToMp4VfrChunk(vfrFile, outPath, h265, crf, i.currentOutFps);
|
await FFmpegCommands.FramesToMp4VfrChunk(vfrFile, outPath, h265, crf, i.currentOutFps, i.constantFrameRate);
|
||||||
IOUtils.TryDeleteIfExists(vfrFile);
|
IOUtils.TryDeleteIfExists(vfrFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ namespace Flowframes
|
|||||||
public static float currentInFps;
|
public static float currentInFps;
|
||||||
public static float currentOutFps;
|
public static float currentOutFps;
|
||||||
public static int currentInputFrameCount;
|
public static int currentInputFrameCount;
|
||||||
|
public static bool constantFrameRate;
|
||||||
public static OutMode currentOutMode;
|
public static OutMode currentOutMode;
|
||||||
public static bool currentInputIsFrames;
|
public static bool currentInputIsFrames;
|
||||||
public static bool currentlyUsingAutoEnc;
|
public static bool currentlyUsingAutoEnc;
|
||||||
@ -63,6 +64,7 @@ namespace Flowframes
|
|||||||
Utils.PathAsciiCheck(inPath, outDir);
|
Utils.PathAsciiCheck(inPath, outDir);
|
||||||
lastAi = ai;
|
lastAi = ai;
|
||||||
currentInputIsFrames = IOUtils.IsPathDirectory(inPath);
|
currentInputIsFrames = IOUtils.IsPathDirectory(inPath);
|
||||||
|
currentInputFrameCount = Utils.GetInputFrameCount(inPath);
|
||||||
Program.mainForm.SetStatus("Starting...");
|
Program.mainForm.SetStatus("Starting...");
|
||||||
Program.mainForm.SetWorking(true);
|
Program.mainForm.SetWorking(true);
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
@ -144,16 +146,19 @@ namespace Flowframes
|
|||||||
|
|
||||||
public static async Task PostProcessFrames (bool sbsMode = false)
|
public static async Task PostProcessFrames (bool sbsMode = false)
|
||||||
{
|
{
|
||||||
currentInputFrameCount = IOUtils.GetAmountOfFiles(currentFramesPath, false, "*.png");
|
if (!Directory.Exists(currentFramesPath) || currentInputFrameCount <= 0 || IOUtils.GetAmountOfFiles(currentFramesPath, false, "*.png") < 2)
|
||||||
|
Cancel("Extracted frames folder is empty!");
|
||||||
if (!Directory.Exists(currentFramesPath) || currentInputFrameCount <= 0)
|
|
||||||
Cancel("Input frames folder is empty!");
|
|
||||||
|
|
||||||
if (Config.GetInt("dedupMode") == 1)
|
if (Config.GetInt("dedupMode") == 1)
|
||||||
await MagickDedupe.Run(currentFramesPath);
|
await MagickDedupe.Run(currentFramesPath);
|
||||||
else
|
else
|
||||||
MagickDedupe.ClearCache();
|
MagickDedupe.ClearCache();
|
||||||
|
|
||||||
|
int frameCountAfterDedupe = IOUtils.GetAmountOfFiles(currentFramesPath, false, "*.png");
|
||||||
|
int dupesPercent = 100 - (((float)frameCountAfterDedupe / currentInputFrameCount) * 100f).RoundToInt();
|
||||||
|
constantFrameRate = dupesPercent < 5f; // Ignore VFR timings for CFR input. TODO: Figure out how to avoid dupes when using VFR timings
|
||||||
|
Logger.Log($"{dupesPercent}% of frames are dupes, so constantFrameRate = {constantFrameRate}");
|
||||||
|
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
|
||||||
bool useTimestamps = Config.GetInt("timingMode") == 1; // TODO: Auto-Disable timestamps if input frames are sequential, not timestamped
|
bool useTimestamps = Config.GetInt("timingMode") == 1; // TODO: Auto-Disable timestamps if input frames are sequential, not timestamped
|
||||||
|
@ -71,9 +71,7 @@ namespace Flowframes.Main
|
|||||||
currentOutPath = e.outPath;
|
currentOutPath = e.outPath;
|
||||||
currentTempDir = InterpolateUtils.GetTempFolderLoc(currentInPath, currentOutPath);
|
currentTempDir = InterpolateUtils.GetTempFolderLoc(currentInPath, currentOutPath);
|
||||||
currentFramesPath = Path.Combine(currentTempDir, Paths.framesDir);
|
currentFramesPath = Path.Combine(currentTempDir, Paths.framesDir);
|
||||||
|
|
||||||
currentInterpFramesDir = Path.Combine(currentTempDir, Paths.interpDir);
|
currentInterpFramesDir = Path.Combine(currentTempDir, Paths.interpDir);
|
||||||
|
|
||||||
currentInputIsFrames = IOUtils.IsPathDirectory(currentInPath);
|
currentInputIsFrames = IOUtils.IsPathDirectory(currentInPath);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -103,6 +101,7 @@ namespace Flowframes.Main
|
|||||||
InterpolateUtils.ShowMessage("Failed to delete existing frames folder - Make sure no file is opened in another program!", "Error");
|
InterpolateUtils.ShowMessage("Failed to delete existing frames folder - Make sure no file is opened in another program!", "Error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
AiProcess.filenameMap.Clear();
|
||||||
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);
|
||||||
@ -138,7 +137,7 @@ namespace Flowframes.Main
|
|||||||
public static async Task DoInterpolate()
|
public static async Task DoInterpolate()
|
||||||
{
|
{
|
||||||
currentFramesPath = Path.Combine(currentTempDir, Paths.framesDir);
|
currentFramesPath = Path.Combine(currentTempDir, Paths.framesDir);
|
||||||
if (!Directory.Exists(currentFramesPath))
|
if (!Directory.Exists(currentFramesPath) || IOUtils.GetAmountOfFiles(currentFramesPath, false, "*.png") < 2)
|
||||||
{
|
{
|
||||||
InterpolateUtils.ShowMessage("There are no extracted frames that can be interpolated!\nDid you run the extraction step?", "Error");
|
InterpolateUtils.ShowMessage("There are no extracted frames that can be interpolated!\nDid you run the extraction step?", "Error");
|
||||||
return;
|
return;
|
||||||
@ -149,10 +148,13 @@ namespace Flowframes.Main
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentInputFrameCount = InterpolateUtils.GetInputFrameCount(currentInPath);
|
||||||
|
|
||||||
foreach (string ini in Directory.GetFiles(currentTempDir, "*.ini", SearchOption.TopDirectoryOnly))
|
foreach (string ini in Directory.GetFiles(currentTempDir, "*.ini", SearchOption.TopDirectoryOnly))
|
||||||
IOUtils.TryDeleteIfExists(ini);
|
IOUtils.TryDeleteIfExists(ini);
|
||||||
|
|
||||||
IOUtils.ReverseRenaming(AiProcess.filenameMap, true); // Get timestamps back
|
IOUtils.ReverseRenaming(AiProcess.filenameMap, true); // Get timestamps back
|
||||||
|
|
||||||
await PostProcessFrames(true);
|
await PostProcessFrames(true);
|
||||||
|
|
||||||
lastInterpFactor = interpFactor;
|
lastInterpFactor = interpFactor;
|
||||||
|
@ -64,6 +64,14 @@ namespace Flowframes.Main
|
|||||||
bigPreviewForm.SetImage(img);
|
bigPreviewForm.SetImage(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GetInputFrameCount(string path)
|
||||||
|
{
|
||||||
|
if (IOUtils.IsPathDirectory(path))
|
||||||
|
return IOUtils.GetAmountOfFiles(path, false);
|
||||||
|
else
|
||||||
|
return FFmpegCommands.GetFrameCount(path);
|
||||||
|
}
|
||||||
|
|
||||||
public static int GetProgressWaitTime(int numFrames)
|
public static int GetProgressWaitTime(int numFrames)
|
||||||
{
|
{
|
||||||
float hddMultiplier = 2f;
|
float hddMultiplier = 2f;
|
||||||
|
@ -33,9 +33,9 @@ namespace Flowframes.UI
|
|||||||
if (!Program.lastInputPathIsSsd)
|
if (!Program.lastInputPathIsSsd)
|
||||||
Logger.Log("Your file seems to be on an HDD or USB device. It is recommended to interpolate videos on an SSD drive for best performance.");
|
Logger.Log("Your file seems to be on an HDD or USB device. It is recommended to interpolate videos on an SSD drive for best performance.");
|
||||||
if (IOUtils.IsPathDirectory(path))
|
if (IOUtils.IsPathDirectory(path))
|
||||||
Logger.Log($"Video FPS (Loaded from fps.ini): {fpsStr} - Total Number Of Frames: {IOUtils.GetAmountOfFiles(path, false)}");
|
Logger.Log($"Video FPS (Loaded from fps.ini): {fpsStr} - Total Number Of Frames: {InterpolateUtils.GetInputFrameCount(path)}");
|
||||||
else
|
else
|
||||||
Logger.Log($"Video FPS: {fpsStr} - Total Number Of Frames: {FFmpegCommands.GetFrameCount(path)}");
|
Logger.Log($"Video FPS: {fpsStr} - Total Number Of Frames: {InterpolateUtils.GetInputFrameCount(path)}");
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
await PrintResolution(path);
|
await PrintResolution(path);
|
||||||
MagickDedupe.ClearCache();
|
MagickDedupe.ClearCache();
|
||||||
|
Loading…
Reference in New Issue
Block a user