public static async Task CreateOutputVid() { if (!Directory.Exists(current.interpFolder) || IOUtils.GetAmountOfFiles(current.interpFolder, false) < 2) { Cancel($"There are no interpolated frames to encode!\n\nDid you delete the folder?"); return; } if (!(await InterpolateUtils.CheckEncoderValid())) { return; } string[] outFrames = IOUtils.GetFilesSorted(current.interpFolder, $"*.{InterpolateUtils.GetOutExt()}"); if (outFrames.Length > 0 && !IOUtils.CheckImageValid(outFrames[0])) { InterpolateUtils.ShowMessage("Invalid frame files detected!\n\nIf you used Auto-Encode, this is normal, and you don't need to run " + "this step as the video was already created in the \"Interpolate\" step.", "Error"); return; } string outPath = Path.Combine(current.outPath, Path.GetFileNameWithoutExtension(current.inPath) + IOUtils.GetCurrentExportSuffix() + FFmpegUtils.GetExt(current.outMode)); await CreateVideo.Export(current.interpFolder, outPath, current.outMode, true); }
static string currentOutFile; // Keeps track of the out file, in case it gets renamed (FPS limiting, looping, etc) before finishing export public static async Task Export(string path, string outFolder, I.OutMode mode, bool stepByStep) { if (!mode.ToString().ToLower().Contains("vid")) // Copy interp frames out of temp folder and skip video export for image seq export { try { string folder = Path.Combine(outFolder, IOUtils.GetCurrentExportFilename(false, false)); await CopyOutputFrames(path, folder, stepByStep); } catch (Exception e) { Logger.Log("Failed to move interp frames folder: " + e.Message); } return; } if (IOUtils.GetAmountOfFiles(path, false, $"*.{InterpolateUtils.GetOutExt()}") <= 1) { I.Cancel("Output folder does not contain frames - An error must have occured during interpolation!", AiProcess.hasShownError); return; } await Task.Delay(10); Program.mainForm.SetStatus("Creating output video from frames..."); try { float maxFps = Config.GetFloat("maxFps"); bool fpsLimit = maxFps != 0 && I.current.outFps > maxFps; bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt("maxFpsMode") == 0; if (!dontEncodeFullFpsVid) { await Encode(mode, path, Path.Combine(outFolder, IOUtils.GetCurrentExportFilename(false, true)), I.current.outFps); } if (fpsLimit) { await Encode(mode, path, Path.Combine(outFolder, IOUtils.GetCurrentExportFilename(true, true)), I.current.outFps, maxFps); } } catch (Exception e) { Logger.Log("FramesToVideo Error: " + e.Message, false); MessageBox.Show("An error occured while trying to convert the interpolated frames to a video.\nCheck the log for details."); } }
static async Task GenerateFrameLines(int number, int startIndex, int count, int factor, bool loopEnabled, bool sceneDetection, bool debug) { int totalFileCount = (startIndex) * factor; int interpFramesAmount = factor; string ext = InterpolateUtils.GetOutExt(); string fileContent = ""; for (int i = startIndex; i < (startIndex + count); i++) { if (Interpolate.canceled) { return; } if (i >= frameFilesWithoutLast.Length) { break; } if (debug && i == startIndex) { fileContent += $"# NEW THREAD - {startIndex} to {startIndex + count}\n"; } string inputFilenameNoExt = Path.GetFileNameWithoutExtension(frameFilesWithoutLast[i].Name); int dupesAmount = dupesDict.ContainsKey(inputFilenameNoExt) ? dupesDict[inputFilenameNoExt] : 0; bool discardThisFrame = (sceneDetection && (i + 2) < frameFilesWithoutLast.Length && sceneFrames.Contains(Path.GetFileNameWithoutExtension(frameFilesWithoutLast[i + 1].Name))); // i+2 is in scene detection folder, means i+1 is ugly interp frame if (i + 1 == frameFilesWithoutLast.Length) // Is last frame { if (sceneDetection && sceneFrames.Contains(Path.GetFileNameWithoutExtension(frameFiles.Last().Name))) // Scene detection for last frame { discardThisFrame = true; } } if (loopEnabled && i == (frameFiles.Length - 2)) // If loop is enabled, account for the extra frame for loop continuity { interpFramesAmount = interpFramesAmount * 2; } for (int frm = 0; frm < interpFramesAmount; frm++) // Generate frames file lines { if (discardThisFrame) // If frame is scene cut frame { totalFileCount++; int lastNum = totalFileCount; fileContent = WriteFrameWithDupes(dupesAmount, fileContent, totalFileCount, ext, debug, $"[In: {inputFilenameNoExt}] [{((frm == 0) ? " Source " : $"Interp {frm}")}] [DiscardNext]");
public static async Task CreateEncFile(string framesPath, bool loopEnabled, float interpFactor, bool notFirstRun) { if (Interpolate.canceled) { return; } Logger.Log($"Generating frame order information for {interpFactor}x...", false, true); bool loop = Config.GetBool("enableLoop"); bool sceneDetection = true; string ext = InterpolateUtils.GetOutExt(); frameFileContents.Clear(); lastOutFileCount = 0; frameFiles = new DirectoryInfo(framesPath).GetFiles($"*.png"); frameFilesWithoutLast = frameFiles; Array.Resize(ref frameFilesWithoutLast, frameFilesWithoutLast.Length - 1); string vfrFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(interpFactor)); string fileContent = ""; string dupesFile = Path.Combine(framesPath.GetParentDir(), $"dupes.ini"); LoadDupesFile(dupesFile); string scnFramesPath = Path.Combine(framesPath.GetParentDir(), Paths.scenesDir); sceneFrames.Clear(); if (Directory.Exists(scnFramesPath)) { sceneFrames = Directory.GetFiles(scnFramesPath).Select(file => Path.GetFileNameWithoutExtension(file)).ToList(); } bool debug = Config.GetBool("frameOrderDebug", false); int interpFramesAmount = (int)interpFactor; // TODO: This code won't work with fractional factors List <Task> tasks = new List <Task>(); int linesPerTask = 400 / (int)interpFactor; int num = 0; for (int i = 0; i < frameFilesWithoutLast.Length; i += linesPerTask) { tasks.Add(GenerateFrameLines(num, i, linesPerTask, (int)interpFactor, loopEnabled, sceneDetection, debug)); num++; } await Task.WhenAll(tasks); for (int x = 0; x < frameFileContents.Count; x++) { fileContent += frameFileContents[x]; } lastOutFileCount++; fileContent += $"file '{Paths.interpDir}/{lastOutFileCount.ToString().PadLeft(Padding.interpFrames, '0')}.{ext}'"; // Last frame (source) if (loop) { fileContent = fileContent.Remove(fileContent.LastIndexOf("\n")); } File.WriteAllText(vfrFile, fileContent); if (notFirstRun) { return; // Skip all steps that only need to be done once } if (loop) { int lastFileNumber = frameFiles.Last().Name.GetInt() + 1; string loopFrameTargetPath = Path.Combine(frameFilesWithoutLast.First().FullName.GetParentDir(), lastFileNumber.ToString().PadLeft(Padding.inputFrames, '0') + $".png"); if (File.Exists(loopFrameTargetPath)) { if (debug) { Logger.Log($"Won't copy loop frame - {Path.GetFileName(loopFrameTargetPath)} already exists.", true); } return; } File.Copy(frameFilesWithoutLast.First().FullName, loopFrameTargetPath); if (debug) { Logger.Log($"Copied loop frame to {loopFrameTargetPath}.", true); } } }
static int GetInterpFramesAmount() { return(IOUtils.GetAmountOfFiles(interpFramesFolder, false, $"*.{InterpolateUtils.GetOutExt()}")); }