mirror of https://github.com/n00mkrad/flowframes
AutoEnc now works with image sequences, WIP, needs more testing
This commit is contained in:
parent
9b72b88526
commit
024c723fd2
|
@ -314,9 +314,8 @@ namespace Flowframes.IO
|
|||
autoEncBackupMode,
|
||||
autoEncDebug,
|
||||
autoEncMode,
|
||||
autoEncSafeBufferFlavrCuda,
|
||||
autoEncSafeBufferCuda,
|
||||
autoEncSafeBufferNcnn,
|
||||
autoEncSafeBufferRifeCuda,
|
||||
aviCodec,
|
||||
aviColors,
|
||||
clearLogOnInput,
|
||||
|
|
|
@ -36,14 +36,11 @@ namespace Flowframes.Main
|
|||
|
||||
safetyBufferFrames = 90;
|
||||
|
||||
if (Interpolate.current.ai.aiName.ToUpper().Contains("NCNN"))
|
||||
if (Interpolate.current.ai.backend == AI.Backend.Ncnn)
|
||||
safetyBufferFrames = Config.GetInt(Config.Key.autoEncSafeBufferNcnn, 150);
|
||||
|
||||
if (Interpolate.current.ai.aiName == Implementations.rifeCuda.aiName)
|
||||
safetyBufferFrames = Config.GetInt(Config.Key.autoEncSafeBufferRifeCuda, 90);
|
||||
|
||||
if (Interpolate.current.ai.aiName == Implementations.flavrCuda.aiName)
|
||||
safetyBufferFrames = Config.GetInt(Config.Key.autoEncSafeBufferFlavrCuda, 90);
|
||||
if (Interpolate.current.ai.backend == AI.Backend.Pytorch)
|
||||
safetyBufferFrames = Config.GetInt(Config.Key.autoEncSafeBufferCuda, 90);
|
||||
}
|
||||
|
||||
public static async Task MainLoop(string interpFramesPath)
|
||||
|
@ -54,8 +51,10 @@ namespace Flowframes.Main
|
|||
{
|
||||
UpdateChunkAndBufferSizes();
|
||||
|
||||
bool imgSeq = Interpolate.current.outMode.ToString().ToLower().StartsWith("img");
|
||||
interpFramesFolder = interpFramesPath;
|
||||
videoChunksFolder = Path.Combine(interpFramesPath.GetParentDir(), Paths.chunksDir);
|
||||
|
||||
if (Interpolate.currentlyUsingAutoEnc)
|
||||
Directory.CreateDirectory(videoChunksFolder);
|
||||
|
||||
|
@ -63,12 +62,12 @@ namespace Flowframes.Main
|
|||
unencodedFrameLines.Clear();
|
||||
|
||||
Logger.Log($"[AE] Starting AutoEncode MainLoop - Chunk Size: {chunkSize} Frames - Safety Buffer: {safetyBufferFrames} Frames", true);
|
||||
int videoIndex = 1;
|
||||
int chunkIndex = 1;
|
||||
string encFile = Path.Combine(interpFramesPath.GetParentDir(), Paths.GetFrameOrderFilename(Interpolate.current.interpFactor));
|
||||
interpFramesLines = IoUtils.ReadLines(encFile).Select(x => x.Split('/').Last().Remove("'").Split('#').First()).ToArray(); // Array with frame filenames
|
||||
|
||||
while (!Interpolate.canceled && GetInterpFramesAmount() < 2)
|
||||
await Task.Delay(2000);
|
||||
await Task.Delay(1000);
|
||||
|
||||
int lastEncodedFrameNum = 0;
|
||||
|
||||
|
@ -128,12 +127,12 @@ namespace Flowframes.Main
|
|||
}
|
||||
|
||||
busy = true;
|
||||
string outpath = Path.Combine(videoChunksFolder, "chunks", $"{videoIndex.ToString().PadLeft(4, '0')}{FfmpegUtils.GetExt(Interpolate.current.outMode)}");
|
||||
int firstLineNum = frameLinesToEncode.First();
|
||||
int lastLineNum = frameLinesToEncode.Last();
|
||||
Logger.Log($"[AE] Encoding Chunk #{videoIndex} to '{outpath}' using line {firstLineNum} ({Path.GetFileName(interpFramesLines[firstLineNum])}) through {lastLineNum} ({Path.GetFileName(Path.GetFileName(interpFramesLines[frameLinesToEncode.Last()]))})", true, false, "ffmpeg");
|
||||
string outpath = Path.Combine(videoChunksFolder, "chunks", $"{chunkIndex.ToString().PadLeft(4, '0')}{FfmpegUtils.GetExt(Interpolate.current.outMode)}");
|
||||
string firstFile = Path.GetFileName(interpFramesLines[frameLinesToEncode.First()].Trim());
|
||||
string lastFile = Path.GetFileName(interpFramesLines[frameLinesToEncode.Last()].Trim());
|
||||
Logger.Log($"[AE] Encoding Chunk #{chunkIndex} to using line {frameLinesToEncode.First()} ({firstFile}) through {frameLinesToEncode.Last()} ({lastFile})", true, false, "ffmpeg");
|
||||
|
||||
await CreateVideo.EncodeChunk(outpath, Interpolate.current.outMode, firstLineNum, frameLinesToEncode.Count);
|
||||
await CreateVideo.EncodeChunk(outpath, Interpolate.current.interpFolder, Interpolate.current.outMode, frameLinesToEncode.First(), frameLinesToEncode.Count);
|
||||
|
||||
if (Interpolate.canceled) return;
|
||||
|
||||
|
@ -144,12 +143,12 @@ namespace Flowframes.Main
|
|||
|
||||
encodedFrameLines.AddRange(frameLinesToEncode);
|
||||
|
||||
Logger.Log("[AE] Done Encoding Chunk #" + videoIndex, true, false, "ffmpeg");
|
||||
Logger.Log("[AE] Done Encoding Chunk #" + chunkIndex, true, false, "ffmpeg");
|
||||
lastEncodedFrameNum = (frameLinesToEncode.Last() + 1);
|
||||
|
||||
videoIndex++;
|
||||
chunkIndex++;
|
||||
|
||||
if(Config.GetInt(Config.Key.autoEncBackupMode) > 0)
|
||||
if(!imgSeq && Config.GetInt(Config.Key.autoEncBackupMode) > 0)
|
||||
{
|
||||
if (aiRunning && (currentMuxTask == null || (currentMuxTask != null && currentMuxTask.IsCompleted)))
|
||||
currentMuxTask = Task.Run(() => CreateVideo.ChunksToVideos(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outPath, true));
|
||||
|
@ -174,6 +173,9 @@ namespace Flowframes.Main
|
|||
while (currentMuxTask != null && !currentMuxTask.IsCompleted)
|
||||
await Task.Delay(100);
|
||||
|
||||
if (imgSeq)
|
||||
return;
|
||||
|
||||
await CreateVideo.ChunksToVideos(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -48,7 +48,6 @@ namespace Flowframes.Main
|
|||
return;
|
||||
}
|
||||
|
||||
await Task.Delay(10);
|
||||
Program.mainForm.SetStatus("Creating output video from frames...");
|
||||
|
||||
try
|
||||
|
@ -88,17 +87,17 @@ namespace Flowframes.Main
|
|||
IoUtils.RenameExistingFolder(outputFolderPath);
|
||||
Logger.Log($"Exporting {desiredFormat.ToUpper()} frames to '{Path.GetFileName(outputFolderPath)}'...");
|
||||
|
||||
if (desiredFormat.ToUpper() == availableFormat.ToUpper()) // Move as the frames are already in the desired format
|
||||
if (desiredFormat.ToUpper() == availableFormat.ToUpper()) // Move if frames are already in the desired format
|
||||
await CopyOutputFrames(framesPath, framesFile, outputFolderPath, fpsLimit);
|
||||
else // Encode with ffmpeg
|
||||
await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, I.current.outFps, new Fraction(), desiredFormat);
|
||||
else // Encode if frames are not in desired format
|
||||
await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 0, I.current.outFps, new Fraction(), desiredFormat);
|
||||
}
|
||||
|
||||
if (fpsLimit)
|
||||
{
|
||||
string outputFolderPath = Path.Combine(I.current.outPath, await IoUtils.GetCurrentExportFilename(true, false));
|
||||
Logger.Log($"Exporting {desiredFormat.ToUpper()} frames to '{Path.GetFileName(outputFolderPath)}' (Resampled to {maxFps} FPS)...");
|
||||
await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, I.current.outFps, maxFps, desiredFormat);
|
||||
await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 0, I.current.outFps, maxFps, desiredFormat);
|
||||
}
|
||||
|
||||
if (!stepByStep)
|
||||
|
@ -222,7 +221,7 @@ namespace Flowframes.Main
|
|||
await Loop(outPath, await GetLoopTimes());
|
||||
}
|
||||
|
||||
public static async Task EncodeChunk(string outPath, I.OutMode mode, int firstFrameNum, int framesAmount)
|
||||
public static async Task EncodeChunk(string outPath, string interpDir, I.OutMode mode, int firstFrameNum, int framesAmount)
|
||||
{
|
||||
string framesFileFull = Path.Combine(I.current.tempFolder, Paths.GetFrameOrderFilename(I.current.interpFactor));
|
||||
string framesFileChunk = Path.Combine(I.current.tempFolder, Paths.GetFrameOrderFilenameChunk(firstFrameNum, firstFrameNum + framesAmount));
|
||||
|
@ -238,15 +237,43 @@ namespace Flowframes.Main
|
|||
|
||||
bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
|
||||
|
||||
if (!dontEncodeFullFpsVid)
|
||||
await FfmpegEncode.FramesToVideo(framesFileChunk, outPath, mode, I.current.outFps, new Fraction(), I.current.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode
|
||||
|
||||
if (fpsLimit)
|
||||
if (mode.ToString().ToLower().StartsWith("img")) // Image Sequence output mode, not video
|
||||
{
|
||||
string filename = Path.GetFileName(outPath);
|
||||
string newParentDir = outPath.GetParentDir() + Paths.fpsLimitSuffix;
|
||||
outPath = Path.Combine(newParentDir, filename);
|
||||
await FfmpegEncode.FramesToVideo(framesFileChunk, outPath, mode, I.current.outFps, maxFps, I.current.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode with limited fps
|
||||
//await FfmpegEncode.FramesToFrames(framesFileChunk, outPath, I.current.outFps, maxFps, Config.Get(Config.Key.imgSeqFormat).ToUpper(), AvProcess.LogMode.Hidden);
|
||||
|
||||
string desiredFormat = Config.Get(Config.Key.imgSeqFormat);
|
||||
string availableFormat = Path.GetExtension(IoUtils.GetFilesSorted(interpDir)[0]).Remove(".").ToUpper();
|
||||
|
||||
if (!dontEncodeFullFpsVid)
|
||||
{
|
||||
string outputFolderPath = Path.Combine(I.current.outPath, await IoUtils.GetCurrentExportFilename(false, false));
|
||||
int startNumber = IoUtils.GetAmountOfFiles(outputFolderPath, false) + 1;
|
||||
|
||||
if (desiredFormat.ToUpper() == availableFormat.ToUpper()) // Move if frames are already in the desired format
|
||||
await CopyOutputFrames(interpDir, framesFileChunk, outputFolderPath, fpsLimit);
|
||||
else // Encode if frames are not in desired format
|
||||
await FfmpegEncode.FramesToFrames(framesFileChunk, outputFolderPath, startNumber, I.current.outFps, new Fraction(), desiredFormat, AvProcess.LogMode.Hidden);
|
||||
}
|
||||
|
||||
if (fpsLimit)
|
||||
{
|
||||
string outputFolderPath = Path.Combine(I.current.outPath, await IoUtils.GetCurrentExportFilename(true, false));
|
||||
int startNumber = IoUtils.GetAmountOfFiles(outputFolderPath, false) + 1;
|
||||
await FfmpegEncode.FramesToFrames(framesFileChunk, outputFolderPath, startNumber, I.current.outFps, maxFps, desiredFormat, AvProcess.LogMode.Hidden);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!dontEncodeFullFpsVid)
|
||||
await FfmpegEncode.FramesToVideo(framesFileChunk, outPath, mode, I.current.outFps, new Fraction(), I.current.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode
|
||||
|
||||
if (fpsLimit)
|
||||
{
|
||||
string filename = Path.GetFileName(outPath);
|
||||
string newParentDir = outPath.GetParentDir() + Paths.fpsLimitSuffix;
|
||||
outPath = Path.Combine(newParentDir, filename);
|
||||
await FfmpegEncode.FramesToVideo(framesFileChunk, outPath, mode, I.current.outFps, maxFps, I.current.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode with limited fps
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -279,21 +279,21 @@ namespace Flowframes.Main
|
|||
{
|
||||
AutoEncode.UpdateChunkAndBufferSizes();
|
||||
|
||||
if (!current.outMode.ToString().ToLower().Contains("vid") || current.outMode.ToString().ToLower().Contains("gif"))
|
||||
if (Config.GetInt(Config.Key.cmdDebugMode) > 0)
|
||||
{
|
||||
Logger.Log($"Not Using AutoEnc: Out Mode is not video ({current.outMode.ToString()})", true);
|
||||
Logger.Log($"Not Using AutoEnc: CMD window is shown (cmdDebugMode > 0)", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stepByStep && !Config.GetBool(Config.Key.sbsAllowAutoEnc))
|
||||
{
|
||||
Logger.Log($"Not Using AutoEnc: Using step-by-step mode, but 'sbsAllowAutoEnc' is false.", true);
|
||||
Logger.Log($"Not Using AutoEnc: Using step-by-step mode, but 'sbsAllowAutoEnc' is false", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stepByStep && Config.GetInt(Config.Key.autoEncMode) == 0)
|
||||
{
|
||||
Logger.Log($"Not Using AutoEnc: 'autoEncMode' is 0.", true);
|
||||
Logger.Log($"Not Using AutoEnc: 'autoEncMode' is 0", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,11 +65,12 @@ namespace Flowframes.Media
|
|||
return "";
|
||||
}
|
||||
|
||||
public static async Task FramesToFrames(string framesFile, string outDir, Fraction fps, Fraction resampleFps, string format = "png", LogMode logMode = LogMode.OnlyLastLine)
|
||||
public static async Task FramesToFrames(string framesFile, string outDir, int startNo, Fraction fps, Fraction resampleFps, string format = "png", LogMode logMode = LogMode.OnlyLastLine)
|
||||
{
|
||||
Directory.CreateDirectory(outDir);
|
||||
string inArg = $"-f concat -i {Path.GetFileName(framesFile)}";
|
||||
string linksDir = Path.Combine(framesFile + Paths.symlinksSuffix);
|
||||
format = format.ToLower();
|
||||
|
||||
if (Config.GetBool(Config.Key.allowSymlinkEncoding, true) && Symlinks.SymlinksAllowed())
|
||||
{
|
||||
|
@ -77,11 +78,12 @@ namespace Flowframes.Media
|
|||
inArg = $"-i {Path.GetFileName(framesFile) + Paths.symlinksSuffix}/%{Padding.interpFrames}d{GetConcatFileExt(framesFile)}";
|
||||
}
|
||||
|
||||
string sn = $"-start_number {startNo}";
|
||||
string rate = fps.ToString().Replace(",", ".");
|
||||
string vf = (resampleFps.GetFloat() < 0.1f) ? "" : $"-vf fps=fps={resampleFps}";
|
||||
string compression = format == "png" ? pngCompr : "-q:v 1";
|
||||
string codec = format.ToLower() == "webp" ? "-c:v libwebp" : ""; // Specify libwebp to avoid putting all frames into single AWEBP
|
||||
string args = $"-vsync 0 -r {rate} {inArg} {codec} {compression} {vf} \"{outDir}/%{Padding.interpFrames}d.{format}\"";
|
||||
string codec = format == "webp" ? "-c:v libwebp" : ""; // Specify libwebp to avoid putting all frames into single animated WEBP
|
||||
string args = $"-vsync 0 -r {rate} {inArg} {codec} {compression} {sn} {vf} \"{outDir}/%{Padding.interpFrames}d.{format}\"";
|
||||
await RunFfmpeg(args, framesFile.GetParentDir(), logMode, "error", TaskType.Encode, true);
|
||||
IoUtils.TryDeleteIfExists(linksDir);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ Flowframes 1.32.0 Changelog:
|
|||
- Added config option to enable custom interpolation factor (if compatible)
|
||||
- ProRes now supports Alpha output when used with profile 4444 or 4444xq
|
||||
- Fixed ProRes being locked to YUV420 colors on all presets
|
||||
- Fixed WEBP image sequence export not working correctly
|
||||
|
||||
|
||||
Flowframes 1.31.1 Changelog:
|
||||
|
|
Loading…
Reference in New Issue