mirror of https://github.com/n00mkrad/flowframes
Fixed and improved FPS limiting feature, added AVI codec options
This commit is contained in:
parent
98c6aedac6
commit
14df754538
|
@ -93,26 +93,31 @@ namespace Flowframes
|
|||
}
|
||||
|
||||
public static async Task FramesToVideoConcat(string framesFile, string outPath, Interpolate.OutMode outMode, float fps, AvProcess.LogMode logMode = AvProcess.LogMode.OnlyLastLine, bool isChunk = false)
|
||||
{
|
||||
await FramesToVideoConcat(framesFile, outPath, outMode, fps, 0, logMode, isChunk);
|
||||
}
|
||||
|
||||
public static async Task FramesToVideoConcat(string framesFile, string outPath, Interpolate.OutMode outMode, float fps, float resampleFps, AvProcess.LogMode logMode = AvProcess.LogMode.OnlyLastLine, bool isChunk = false)
|
||||
{
|
||||
if (logMode != AvProcess.LogMode.Hidden)
|
||||
Logger.Log($"Encoding video...");
|
||||
string encArgs = Utils.GetEncArgs(Utils.GetCodec(outMode)) + " -pix_fmt yuv420p ";
|
||||
if (!isChunk) encArgs += $"-movflags +faststart";
|
||||
Logger.Log((resampleFps <= 0) ? $"Encoding video..." : $"Encoding video resampled to {resampleFps.ToString().Replace(",", ".")} FPS...");
|
||||
Directory.CreateDirectory(outPath.GetParentDir());
|
||||
string encArgs = Utils.GetEncArgs(Utils.GetCodec(outMode));
|
||||
if (!isChunk) encArgs += $" -movflags +faststart";
|
||||
string vfrFilename = Path.GetFileName(framesFile);
|
||||
//string vsync = (Interpolate.current.interpFactor == 2) ? "-vsync 1" : "-vsync 2";
|
||||
string rate = fps.ToString().Replace(",", ".");
|
||||
string vf = (resampleFps <= 0) ? "" : $"-vf fps=fps={resampleFps.ToString().Replace(",", ".")}";
|
||||
string extraArgs = Config.Get("ffEncArgs");
|
||||
string args = $"-loglevel error -vsync 0 -f concat -r {rate} -i {vfrFilename} {encArgs} {extraArgs} -threads {Config.GetInt("ffEncThreads")} {outPath.Wrap()}";
|
||||
//string args = $"-vsync 0 -f concat -i {vfrFilename} {encArgs} {extraArgs} -threads {Config.GetInt("ffEncThreads")} {outPath.Wrap()}";
|
||||
string args = $"-loglevel error -vsync 0 -f concat -r {rate} -i {vfrFilename} {encArgs} {vf} {extraArgs} -threads {Config.GetInt("ffEncThreads")} {outPath.Wrap()}";
|
||||
await AvProcess.RunFfmpeg(args, framesFile.GetParentDir(), logMode);
|
||||
}
|
||||
|
||||
public static async Task ConcatVideos(string concatFile, string outPath, float fps, int looptimes = -1)
|
||||
public static async Task ConcatVideos(string concatFile, string outPath, int looptimes = -1)
|
||||
{
|
||||
Logger.Log($"Merging videos...");
|
||||
string loopStr = (looptimes > 0) ? $"-stream_loop {looptimes}" : "";
|
||||
string vfrFilename = Path.GetFileName(concatFile);
|
||||
string args = $" {loopStr} -vsync 1 -f concat -r {fps.ToString().Replace(",", ".")} -i {vfrFilename} -c copy -pix_fmt yuv420p {outPath.Wrap()}";
|
||||
string args = $" {loopStr} -vsync 1 -f concat -i {vfrFilename} -c copy -pix_fmt yuv420p -movflags +faststart {outPath.Wrap()}";
|
||||
await AvProcess.RunFfmpeg(args, concatFile.GetParentDir(), AvProcess.LogMode.Hidden);
|
||||
}
|
||||
|
||||
|
@ -127,13 +132,16 @@ namespace Flowframes
|
|||
DeleteSource(inputPath);
|
||||
}
|
||||
|
||||
public static async Task FramesToGifConcat(string framesFile, string outPath, float fps, bool palette, int colors = 64)
|
||||
public static async Task FramesToGifConcat(string framesFile, string outPath, float fps, bool palette, int colors = 64, float resampleFps = -1, AvProcess.LogMode logMode = AvProcess.LogMode.OnlyLastLine)
|
||||
{
|
||||
Logger.Log($"Encoding GIF...");
|
||||
if (logMode != AvProcess.LogMode.Hidden)
|
||||
Logger.Log((resampleFps <= 0) ? $"Encoding GIF..." : $"Encoding GIF resampled to {resampleFps.ToString().Replace(",", ".")} FPS...");
|
||||
string vfrFilename = Path.GetFileName(framesFile);
|
||||
string filter = palette ? $"-vf \"split[s0][s1];[s0]palettegen={colors}[p];[s1][p]paletteuse=dither=floyd_steinberg:diff_mode=rectangle\"" : "";
|
||||
string rate = fps.ToString().Replace(",", ".");
|
||||
string args = $"-loglevel error -f concat -r {rate} -i {vfrFilename.Wrap()} -f gif {filter} {outPath.Wrap()}";
|
||||
string paletteFilter = palette ? $"-vf \"split[s0][s1];[s0]palettegen={colors}[p];[s1][p]paletteuse=dither=floyd_steinberg:diff_mode=rectangle\"" : "";
|
||||
string fpsFilter = (resampleFps <= 0) ? "" : $"fps=fps={resampleFps.ToStringDot()}";
|
||||
string vf = FormatUtils.ConcatStrings(new string[] { paletteFilter, fpsFilter });
|
||||
string rate = fps.ToStringDot();
|
||||
string args = $"-loglevel error -f concat -r {rate} -i {vfrFilename.Wrap()} -f gif {vf} {outPath.Wrap()}";
|
||||
await AvProcess.RunFfmpeg(args, framesFile.GetParentDir(), AvProcess.LogMode.OnlyLastLine);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Flowframes.AudioVideo
|
|||
case Codec.H265: return "libx265";
|
||||
case Codec.VP9: return "libvpx-vp9";
|
||||
case Codec.ProRes: return "prores_ks";
|
||||
case Codec.AviRaw: return "rawvideo";
|
||||
case Codec.AviRaw: return Config.Get("aviCodec");
|
||||
}
|
||||
return "libx264";
|
||||
}
|
||||
|
@ -51,12 +51,12 @@ namespace Flowframes.AudioVideo
|
|||
|
||||
if(codec == Codec.H264)
|
||||
{
|
||||
args += $"-crf {Config.GetInt("h264Crf")} -preset {Config.Get("ffEncPreset")}";
|
||||
args += $"-crf {Config.GetInt("h264Crf")} -preset {Config.Get("ffEncPreset")} -pix_fmt yuv420p";
|
||||
}
|
||||
|
||||
if (codec == Codec.H265)
|
||||
{
|
||||
args += $"-crf {Config.GetInt("h265Crf")} -preset {Config.Get("ffEncPreset")}";
|
||||
args += $"-crf {Config.GetInt("h265Crf")} -preset {Config.Get("ffEncPreset")} -pix_fmt yuv420p";
|
||||
}
|
||||
|
||||
if (codec == Codec.VP9)
|
||||
|
@ -64,12 +64,17 @@ namespace Flowframes.AudioVideo
|
|||
int crf = Config.GetInt("vp9Crf");
|
||||
string qualityStr = (crf > 0) ? $"-crf {crf}" : "-lossless 1";
|
||||
string cpuUsed = Config.GetInt("vp9Speed", 3).ToString();
|
||||
args += $"{qualityStr} -cpu-used {cpuUsed} -tile-columns 2 -tile-rows 2 -row-mt 1";
|
||||
args += $"{qualityStr} -cpu-used {cpuUsed} -tile-columns 2 -tile-rows 2 -row-mt 1 -pix_fmt yuv420p";
|
||||
}
|
||||
|
||||
if(codec == Codec.ProRes)
|
||||
{
|
||||
args += $"-profile:v {Config.GetInt("proResProfile")}";
|
||||
args += $"-profile:v {Config.GetInt("proResProfile")} -pix_fmt yuv420p";
|
||||
}
|
||||
|
||||
if (codec == Codec.AviRaw)
|
||||
{
|
||||
args += $"-pix_fmt {Config.Get("aviColors")}";
|
||||
}
|
||||
|
||||
return args;
|
||||
|
|
|
@ -165,5 +165,20 @@ namespace Flowframes
|
|||
{
|
||||
return str.Split('#')[0].SplitBy("//")[0];
|
||||
}
|
||||
|
||||
public static string FilenameSuffix(this string path, string suffix)
|
||||
{
|
||||
string filename = Path.ChangeExtension(path, null);
|
||||
string ext = Path.GetExtension(path);
|
||||
return filename + suffix + ext;
|
||||
}
|
||||
|
||||
public static string ToStringDot (this float f, string format = "")
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(format))
|
||||
return f.ToString().Replace(",", ".");
|
||||
else
|
||||
return f.ToString(format).Replace(",", ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,6 +151,9 @@
|
|||
this.cmdDebugMode = new System.Windows.Forms.ComboBox();
|
||||
this.titleLabel = new System.Windows.Forms.Label();
|
||||
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.label60 = new System.Windows.Forms.Label();
|
||||
this.aviCodec = new System.Windows.Forms.ComboBox();
|
||||
this.aviColors = new System.Windows.Forms.ComboBox();
|
||||
this.settingsTabList.SuspendLayout();
|
||||
this.generalTab.SuspendLayout();
|
||||
this.tabListPage2.SuspendLayout();
|
||||
|
@ -963,6 +966,9 @@
|
|||
// vidExportTab
|
||||
//
|
||||
this.vidExportTab.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48)))));
|
||||
this.vidExportTab.Controls.Add(this.aviColors);
|
||||
this.vidExportTab.Controls.Add(this.aviCodec);
|
||||
this.vidExportTab.Controls.Add(this.label60);
|
||||
this.vidExportTab.Controls.Add(this.proResProfile);
|
||||
this.vidExportTab.Controls.Add(this.label59);
|
||||
this.vidExportTab.Controls.Add(this.panel11);
|
||||
|
@ -1161,8 +1167,8 @@
|
|||
this.maxFpsMode.ForeColor = System.Drawing.Color.White;
|
||||
this.maxFpsMode.FormattingEnabled = true;
|
||||
this.maxFpsMode.Items.AddRange(new object[] {
|
||||
"Save Video With Limited FPS",
|
||||
"Save Both With Full FPS And Create Second Video With Limited FPS"});
|
||||
"Only Create Video With Limited FPS",
|
||||
"Create Videos With Full FPS And Limited FPS (2x Slower Encoding!)"});
|
||||
this.maxFpsMode.Location = new System.Drawing.Point(280, 127);
|
||||
this.maxFpsMode.Name = "maxFpsMode";
|
||||
this.maxFpsMode.Size = new System.Drawing.Size(400, 21);
|
||||
|
@ -1231,7 +1237,7 @@
|
|||
//
|
||||
this.label18.AutoSize = true;
|
||||
this.label18.ForeColor = System.Drawing.Color.Silver;
|
||||
this.label18.Location = new System.Drawing.Point(393, 361);
|
||||
this.label18.Location = new System.Drawing.Point(393, 391);
|
||||
this.label18.Margin = new System.Windows.Forms.Padding(10, 10, 10, 7);
|
||||
this.label18.Name = "label18";
|
||||
this.label18.Size = new System.Drawing.Size(208, 13);
|
||||
|
@ -1250,7 +1256,7 @@
|
|||
"64 (Medium)",
|
||||
"32 (Low)",
|
||||
"16 (Very Low)"});
|
||||
this.gifColors.Location = new System.Drawing.Point(280, 357);
|
||||
this.gifColors.Location = new System.Drawing.Point(280, 387);
|
||||
this.gifColors.Name = "gifColors";
|
||||
this.gifColors.Size = new System.Drawing.Size(100, 21);
|
||||
this.gifColors.TabIndex = 41;
|
||||
|
@ -1258,7 +1264,7 @@
|
|||
// label17
|
||||
//
|
||||
this.label17.AutoSize = true;
|
||||
this.label17.Location = new System.Drawing.Point(10, 360);
|
||||
this.label17.Location = new System.Drawing.Point(10, 390);
|
||||
this.label17.Margin = new System.Windows.Forms.Padding(10, 10, 10, 7);
|
||||
this.label17.Name = "label17";
|
||||
this.label17.Size = new System.Drawing.Size(154, 13);
|
||||
|
@ -1663,6 +1669,49 @@
|
|||
this.titleLabel.TabIndex = 1;
|
||||
this.titleLabel.Text = "Settings";
|
||||
//
|
||||
// label60
|
||||
//
|
||||
this.label60.AutoSize = true;
|
||||
this.label60.Location = new System.Drawing.Point(10, 360);
|
||||
this.label60.Margin = new System.Windows.Forms.Padding(10, 10, 10, 7);
|
||||
this.label60.Name = "label60";
|
||||
this.label60.Size = new System.Drawing.Size(130, 13);
|
||||
this.label60.TabIndex = 69;
|
||||
this.label60.Text = "AVI: Codec / Color Space";
|
||||
//
|
||||
// aviCodec
|
||||
//
|
||||
this.aviCodec.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.aviCodec.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.aviCodec.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.aviCodec.ForeColor = System.Drawing.Color.White;
|
||||
this.aviCodec.FormattingEnabled = true;
|
||||
this.aviCodec.Items.AddRange(new object[] {
|
||||
"ffv1",
|
||||
"huffyuv",
|
||||
"rawvideo"});
|
||||
this.aviCodec.Location = new System.Drawing.Point(280, 357);
|
||||
this.aviCodec.Name = "aviCodec";
|
||||
this.aviCodec.Size = new System.Drawing.Size(200, 21);
|
||||
this.aviCodec.TabIndex = 70;
|
||||
//
|
||||
// aviColors
|
||||
//
|
||||
this.aviColors.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.aviColors.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.aviColors.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.aviColors.ForeColor = System.Drawing.Color.White;
|
||||
this.aviColors.FormattingEnabled = true;
|
||||
this.aviColors.Items.AddRange(new object[] {
|
||||
"yuv420p",
|
||||
"yuv422p",
|
||||
"yuv444p",
|
||||
"rgb24"});
|
||||
this.aviColors.Location = new System.Drawing.Point(486, 357);
|
||||
this.aviColors.Name = "aviColors";
|
||||
this.aviColors.Size = new System.Drawing.Size(194, 21);
|
||||
this.aviColors.TabIndex = 71;
|
||||
//
|
||||
// SettingsForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
|
@ -1822,5 +1871,8 @@
|
|||
private System.Windows.Forms.Label label57;
|
||||
private System.Windows.Forms.ComboBox proResProfile;
|
||||
private System.Windows.Forms.Label label59;
|
||||
private System.Windows.Forms.ComboBox aviColors;
|
||||
private System.Windows.Forms.ComboBox aviCodec;
|
||||
private System.Windows.Forms.Label label60;
|
||||
}
|
||||
}
|
|
@ -77,6 +77,8 @@ namespace Flowframes.Forms
|
|||
ConfigParser.SaveGuiElement(vp9Crf);
|
||||
ConfigParser.SaveComboxIndex(proResProfile);
|
||||
ConfigParser.SaveGuiElement(gifColors);
|
||||
ConfigParser.SaveGuiElement(aviCodec);
|
||||
ConfigParser.SaveGuiElement(aviColors);
|
||||
ConfigParser.SaveGuiElement(maxFps);
|
||||
ConfigParser.SaveComboxIndex(maxFpsMode);
|
||||
ConfigParser.SaveComboxIndex(loopMode);
|
||||
|
@ -122,6 +124,8 @@ namespace Flowframes.Forms
|
|||
ConfigParser.LoadGuiElement(vp9Crf);
|
||||
ConfigParser.LoadComboxIndex(proResProfile);
|
||||
ConfigParser.LoadGuiElement(gifColors);
|
||||
ConfigParser.LoadGuiElement(aviCodec);
|
||||
ConfigParser.LoadGuiElement(aviColors);
|
||||
ConfigParser.LoadGuiElement(maxFps);
|
||||
ConfigParser.LoadComboxIndex(maxFpsMode);
|
||||
ConfigParser.LoadComboxIndex(loopMode);
|
||||
|
|
|
@ -126,6 +126,8 @@ namespace Flowframes.IO
|
|||
if (key == "h265Crf") return WriteDefault(key, "24");
|
||||
if (key == "vp9Crf") return WriteDefault(key, "28");
|
||||
if (key == "proResProfile") return WriteDefault(key, "2");
|
||||
if (key == "aviCodec") return WriteDefault(key, "ffv1");
|
||||
if (key == "aviColors") return WriteDefault(key, "yuv420p");
|
||||
if (key == "gifColors") return WriteDefault(key, "128 (High)");
|
||||
if (key == "minVidLength") return WriteDefault(key, "2");
|
||||
// AI
|
||||
|
|
|
@ -24,24 +24,25 @@ namespace Flowframes.Main
|
|||
|
||||
public static bool paused;
|
||||
|
||||
public static void UpdateSafetyBufferSize ()
|
||||
public static void UpdateChunkAndBufferSizes ()
|
||||
{
|
||||
chunkSize = GetChunkSize(IOUtils.GetAmountOfFiles(Interpolate.current.framesFolder, false, "*.png") * Interpolate.current.interpFactor);
|
||||
safetyBufferFrames = Interpolate.current.ai.aiName.ToUpper().Contains("NCNN") ? 60 : 30; // Use bigger safety buffer for NCNN
|
||||
}
|
||||
|
||||
public static async Task MainLoop(string interpFramesPath)
|
||||
{
|
||||
UpdateSafetyBufferSize();
|
||||
UpdateChunkAndBufferSizes();
|
||||
|
||||
interpFramesFolder = interpFramesPath;
|
||||
videoChunksFolder = Path.Combine(interpFramesPath.GetParentDir(), Paths.chunksDir);
|
||||
if (Interpolate.currentlyUsingAutoEnc)
|
||||
Directory.CreateDirectory(videoChunksFolder);
|
||||
|
||||
encodedFrameLines.Clear();
|
||||
unencodedFrameLines.Clear();
|
||||
|
||||
chunkSize = GetChunkSize(IOUtils.GetAmountOfFiles(Interpolate.current.framesFolder, false, "*.png") * Interpolate.current.interpFactor);
|
||||
Logger.Log($"Starting AutoEncode MainLoop - Chunk Size: {chunkSize} Frames - Safety Buffer: {safetyBufferFrames} Frames", true);
|
||||
|
||||
int videoIndex = 1;
|
||||
string encFile = Path.Combine(interpFramesPath.GetParentDir(), $"vfr-{Interpolate.current.interpFactor}x.ini");
|
||||
interpFramesLines = IOUtils.ReadLines(encFile).Select(x => x.Split('/').Last().Remove("'")).ToArray(); // Array with frame filenames
|
||||
|
@ -73,8 +74,6 @@ namespace Flowframes.Main
|
|||
unencodedFrameLines.Add(vfrLine);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(videoChunksFolder);
|
||||
|
||||
bool aiRunning = !AiProcess.currentAiProcess.HasExited;
|
||||
|
||||
if (unencodedFrameLines.Count >= (chunkSize + safetyBufferFrames) || !aiRunning) // Encode every n frames, or after process has exited
|
||||
|
@ -83,12 +82,10 @@ namespace Flowframes.Main
|
|||
|
||||
List<int> frameLinesToEncode = aiRunning ? unencodedFrameLines.Take(chunkSize).ToList() : unencodedFrameLines; // Take all remaining frames if process is done
|
||||
//Logger.Log($"{unencodedFrameLines.Count} unencoded frame lines, {IOUtils.GetAmountOfFiles(interpFramesFolder, false)} frames in interp folder", true, false, "ffmpeg");
|
||||
Logger.Log($"Encoding Chunk #{videoIndex} using {Path.GetFileName(interpFramesLines[frameLinesToEncode.First()])} through {Path.GetFileName(Path.GetFileName(interpFramesLines[frameLinesToEncode.Last()]))}", true, false, "ffmpeg");
|
||||
|
||||
//IOUtils.ZeroPadDir(framesToEncode, Padding.interpFrames); // Zero-pad frames before encoding to make sure filenames match with VFR file
|
||||
|
||||
string outpath = Path.Combine(videoChunksFolder, $"{videoIndex.ToString().PadLeft(4, '0')}{FFmpegUtils.GetExt(Interpolate.current.outMode)}");
|
||||
string outpath = Path.Combine(videoChunksFolder, "chunks", $"{videoIndex.ToString().PadLeft(4, '0')}{FFmpegUtils.GetExt(Interpolate.current.outMode)}");
|
||||
int firstFrameNum = frameLinesToEncode[0];
|
||||
Logger.Log($"Encoding Chunk #{videoIndex} to '{outpath}' using {Path.GetFileName(interpFramesLines[frameLinesToEncode.First()])} through {Path.GetFileName(Path.GetFileName(interpFramesLines[frameLinesToEncode.Last()]))}", true, false, "ffmpeg");
|
||||
await CreateVideo.EncodeChunk(outpath, Interpolate.current.outMode, firstFrameNum, frameLinesToEncode.Count);
|
||||
|
||||
if(Interpolate.canceled) return;
|
||||
|
@ -117,15 +114,9 @@ namespace Flowframes.Main
|
|||
|
||||
if (Interpolate.canceled) return;
|
||||
|
||||
string concatFile = Path.Combine(interpFramesPath.GetParentDir(), "chunks-concat.ini");
|
||||
string concatFileContent = "";
|
||||
foreach (string vid in IOUtils.GetFilesSorted(videoChunksFolder))
|
||||
concatFileContent += $"file '{Paths.chunksDir}/{Path.GetFileName(vid)}'\n";
|
||||
File.WriteAllText(concatFile, concatFileContent);
|
||||
|
||||
IOUtils.ReverseRenaming(AiProcess.filenameMap, true); // Get timestamps back
|
||||
|
||||
await CreateVideo.ChunksToVideo(videoChunksFolder, concatFile, Interpolate.current.outFilename);
|
||||
await CreateVideo.ChunksToVideos(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outFilename);
|
||||
}
|
||||
|
||||
public static bool HasWorkToDo ()
|
||||
|
|
|
@ -46,13 +46,16 @@ namespace Flowframes.Main
|
|||
Program.mainForm.SetStatus("Creating output video from frames...");
|
||||
try
|
||||
{
|
||||
int maxFps = Config.GetInt("maxFps");
|
||||
if (maxFps == 0) maxFps = 500;
|
||||
float maxFps = Config.GetFloat("maxFps");
|
||||
bool fpsLimit = maxFps != 0 && i.current.outFps > maxFps;
|
||||
|
||||
if (i.current.outFps > maxFps)
|
||||
await Encode(mode, path, outPath, i.current.outFps, maxFps, (Config.GetInt("maxFpsMode") == 1));
|
||||
else
|
||||
bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt("maxFpsMode") == 0;
|
||||
|
||||
if(!dontEncodeFullFpsVid)
|
||||
await Encode(mode, path, outPath, i.current.outFps);
|
||||
|
||||
if (fpsLimit)
|
||||
await Encode(mode, path, outPath.FilenameSuffix($"-{maxFps.ToStringDot("0.00")}fps"), i.current.outFps, maxFps);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -95,56 +98,51 @@ namespace Flowframes.Main
|
|||
}
|
||||
}
|
||||
|
||||
static async Task Encode(i.OutMode mode, string framesPath, string outPath, float fps, float changeFps = -1, bool keepOriginalFpsVid = true)
|
||||
static async Task Encode(i.OutMode mode, string framesPath, string outPath, float fps, float resampleFps = -1)
|
||||
{
|
||||
currentOutFile = outPath;
|
||||
string vfrFile = Path.Combine(framesPath.GetParentDir(), $"vfr-{i.current.interpFactor}x.ini");
|
||||
|
||||
if (mode == i.OutMode.VidGif)
|
||||
{
|
||||
await FFmpegCommands.FramesToGifConcat(vfrFile, outPath, fps, true, Config.GetInt("gifColors"));
|
||||
await FFmpegCommands.FramesToGifConcat(vfrFile, outPath, fps, true, Config.GetInt("gifColors"), resampleFps);
|
||||
}
|
||||
else
|
||||
{
|
||||
int looptimes = GetLoopTimes();
|
||||
bool h265 = Config.GetInt("mp4Enc") == 1;
|
||||
int crf = h265 ? Config.GetInt("h265Crf") : Config.GetInt("h264Crf");
|
||||
|
||||
await FFmpegCommands.FramesToVideoConcat(vfrFile, outPath, mode, fps);
|
||||
await FFmpegCommands.FramesToVideoConcat(vfrFile, outPath, mode, fps, resampleFps);
|
||||
await MergeAudio(i.current.inPath, outPath);
|
||||
|
||||
if (changeFps > 0)
|
||||
{
|
||||
currentOutFile = IOUtils.FilenameSuffix(outPath, $"-{changeFps.ToString("0")}fps");
|
||||
Program.mainForm.SetStatus("Creating video with desired frame rate...");
|
||||
await FFmpegCommands.ConvertFramerate(outPath, currentOutFile, h265, crf, changeFps, !keepOriginalFpsVid);
|
||||
await MergeAudio(i.current.inPath, currentOutFile);
|
||||
}
|
||||
|
||||
int looptimes = GetLoopTimes();
|
||||
if (looptimes > 0)
|
||||
await Loop(currentOutFile, looptimes);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ChunksToVideo(string chunksPath, string vfrFile, string outPath)
|
||||
public static async Task ChunksToVideos(string tempFolder, string chunksFolder, string baseOutPath)
|
||||
{
|
||||
if (IOUtils.GetAmountOfFiles(chunksPath, false, $"*{FFmpegUtils.GetExt(i.current.outMode)}") < 1)
|
||||
if (IOUtils.GetAmountOfFiles(chunksFolder, true, $"*{FFmpegUtils.GetExt(i.current.outMode)}") < 1)
|
||||
{
|
||||
i.Cancel("No video chunks found - An error must have occured during chunk encoding!", AiProcess.hasShownError);
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Delay(10);
|
||||
Program.mainForm.SetStatus("Merging video chunks...");
|
||||
try
|
||||
{
|
||||
int maxFps = Config.GetInt("maxFps");
|
||||
if (maxFps == 0) maxFps = 500;
|
||||
DirectoryInfo chunksDir = new DirectoryInfo(chunksFolder);
|
||||
foreach(DirectoryInfo dir in chunksDir.GetDirectories())
|
||||
{
|
||||
string suffix = dir.Name.Replace("chunks", "");
|
||||
string tempConcatFile = Path.Combine(tempFolder, $"chunks-concat{suffix}.ini");
|
||||
string concatFileContent = "";
|
||||
foreach (string vid in IOUtils.GetFilesSorted(dir.FullName))
|
||||
concatFileContent += $"file '{Paths.chunksDir}/{dir.Name}/{Path.GetFileName(vid)}'\n";
|
||||
File.WriteAllText(tempConcatFile, concatFileContent);
|
||||
|
||||
if (i.current.outFps > maxFps)
|
||||
await MergeChunks(chunksPath, vfrFile, outPath, i.current.outFps, maxFps, (Config.GetInt("maxFpsMode") == 1));
|
||||
else
|
||||
await MergeChunks(chunksPath, vfrFile, outPath, i.current.outFps);
|
||||
Logger.Log($"CreateVideo: Running MergeChunks() for vfrFile '{Path.GetFileName(tempConcatFile)}'", true);
|
||||
await MergeChunks(tempConcatFile, baseOutPath.FilenameSuffix(suffix));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -153,28 +151,14 @@ 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 vfrFile, string outPath)
|
||||
{
|
||||
int looptimes = GetLoopTimes();
|
||||
|
||||
bool h265 = Config.GetInt("mp4Enc") == 1;
|
||||
int crf = h265 ? Config.GetInt("h265Crf") : Config.GetInt("h264Crf");
|
||||
|
||||
await FFmpegCommands.ConcatVideos(vfrFile, outPath, fps, -1);
|
||||
await FFmpegCommands.ConcatVideos(vfrFile, outPath, -1);
|
||||
await MergeAudio(i.current.inPath, outPath);
|
||||
|
||||
int looptimes = GetLoopTimes();
|
||||
if (looptimes > 0)
|
||||
await Loop(outPath, looptimes);
|
||||
|
||||
if (changeFps > 0)
|
||||
{
|
||||
string newOutPath = IOUtils.FilenameSuffix(outPath, $"-{changeFps.ToString("0")}fps");
|
||||
Program.mainForm.SetStatus("Creating video with desired frame rate...");
|
||||
await FFmpegCommands.ConvertFramerate(outPath, newOutPath, h265, crf, changeFps, !keepOriginalFpsVid);
|
||||
await MergeAudio(i.current.inPath, newOutPath);
|
||||
if (looptimes > 0)
|
||||
await Loop(newOutPath, looptimes);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task EncodeChunk(string outPath, i.OutMode mode, int firstFrameNum, int framesAmount)
|
||||
|
@ -183,7 +167,21 @@ namespace Flowframes.Main
|
|||
string vfrFile = Path.Combine(i.current.tempFolder, $"vfr-chunk-{firstFrameNum}-{firstFrameNum + framesAmount}.ini");
|
||||
File.WriteAllLines(vfrFile, IOUtils.ReadLines(vfrFileOriginal).Skip(firstFrameNum).Take(framesAmount));
|
||||
|
||||
await FFmpegCommands.FramesToVideoConcat(vfrFile, outPath, mode, i.current.outFps, AvProcess.LogMode.Hidden, true);
|
||||
float maxFps = Config.GetFloat("maxFps");
|
||||
bool fpsLimit = maxFps != 0 && i.current.outFps > maxFps;
|
||||
|
||||
bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt("maxFpsMode") == 0;
|
||||
|
||||
if(!dontEncodeFullFpsVid)
|
||||
await FFmpegCommands.FramesToVideoConcat(vfrFile, outPath, mode, i.current.outFps, AvProcess.LogMode.Hidden, true); // Encode
|
||||
|
||||
if (fpsLimit)
|
||||
{
|
||||
string filename = Path.GetFileName(outPath);
|
||||
string newParentDir = outPath.GetParentDir() + "-" + maxFps.ToStringDot("0.00") + "fps";
|
||||
outPath = Path.Combine(newParentDir, filename);
|
||||
await FFmpegCommands.FramesToVideoConcat(vfrFile, outPath, mode, i.current.outFps, maxFps, AvProcess.LogMode.Hidden, true); // Encode with limited fps
|
||||
}
|
||||
}
|
||||
|
||||
static async Task Loop(string outPath, int looptimes)
|
||||
|
|
|
@ -333,7 +333,7 @@ namespace Flowframes.Main
|
|||
|
||||
public static bool UseAutoEnc (bool stepByStep, InterpSettings current)
|
||||
{
|
||||
AutoEncode.UpdateSafetyBufferSize();
|
||||
AutoEncode.UpdateChunkAndBufferSizes();
|
||||
|
||||
if (!current.outMode.ToString().ToLower().Contains("vid"))
|
||||
{
|
||||
|
@ -356,7 +356,7 @@ namespace Flowframes.Main
|
|||
int inFrames = IOUtils.GetAmountOfFiles(current.framesFolder, false);
|
||||
if (inFrames * current.interpFactor < (AutoEncode.chunkSize + AutoEncode.safetyBufferFrames) * 1.2f)
|
||||
{
|
||||
Logger.Log($"Not Using AutoEnc: Input frames ({inFrames}) * factor ({current.interpFactor}) is smaller (chunkSize ({AutoEncode.chunkSize}) + safetyBufferFrames ({AutoEncode.safetyBufferFrames}) * 1.2f", true);
|
||||
Logger.Log($"Not Using AutoEnc: Input frames ({inFrames}) * factor ({current.interpFactor}) is smaller than (chunkSize ({AutoEncode.chunkSize}) + safetyBufferFrames ({AutoEncode.safetyBufferFrames}) * 1.2f)", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue