public static async Task ExportFrames(string path, string outFolder, I.OutMode mode, bool stepByStep) { if (Config.GetInt(Config.Key.sceneChangeFillMode) == 1) { string frameFile = Path.Combine(I.current.tempFolder, Paths.GetFrameOrderFilename(I.current.interpFactor)); await Blend.BlendSceneChanges(frameFile); } if (!mode.ToString().ToLower().Contains("vid")) // Copy interp frames out of temp folder and skip video export for image seq export { try { await ExportImageSequence(path, stepByStep); } catch (Exception e) { Logger.Log("Failed to move interpolated frames: " + e.Message); Logger.Log("Stack Trace:\n " + e.StackTrace, true); } return; } if (IoUtils.GetAmountOfFiles(path, false, "*" + I.current.interpExt) <= 1) { I.Cancel("Output folder does not contain frames - An error must have occured during interpolation!", AiProcess.hasShownError); return; } Program.mainForm.SetStatus("Creating output video from frames..."); try { string max = Config.Get(Config.Key.maxFps); Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat()); bool fpsLimit = maxFps.GetFloat() > 0f && I.current.outFps.GetFloat() > maxFps.GetFloat(); bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0; if (!dontEncodeFullFpsVid) { await Encode(mode, path, Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(false, true)), I.current.outFps, new Fraction()); } if (fpsLimit) { await Encode(mode, path, Path.Combine(outFolder, await 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 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 Encode(I.OutMode mode, string framesPath, string outPath, float fps, float resampleFps = -1) { currentOutFile = outPath; string vfrFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(I.current.interpFactor)); if (!File.Exists(vfrFile)) { bool sbs = Config.GetInt("processingMode") == 1; I.Cancel($"Frame order file for this interpolation factor not found!{(sbs ? "\n\nDid you run the interpolation step with the current factor?" : "")}"); return; } if (mode == I.OutMode.VidGif) { await FfmpegEncode.FramesToGifConcat(vfrFile, outPath, fps, true, Config.GetInt("gifColors"), resampleFps); } else { await FfmpegEncode.FramesToVideoConcat(vfrFile, outPath, mode, fps, resampleFps); await MuxOutputVideo(I.current.inPath, outPath); await Loop(currentOutFile, GetLoopTimes()); } }
public static async Task EncodeChunk(string outPath, I.OutMode mode, int firstFrameNum, int framesAmount) { string vfrFileOriginal = Path.Combine(I.current.tempFolder, Paths.GetFrameOrderFilename(I.current.interpFactor)); string vfrFile = Path.Combine(I.current.tempFolder, Paths.GetFrameOrderFilenameChunk(firstFrameNum, firstFrameNum + framesAmount)); File.WriteAllLines(vfrFile, IOUtils.ReadLines(vfrFileOriginal).Skip(firstFrameNum).Take(framesAmount)); float maxFps = Config.GetFloat("maxFps"); bool fpsLimit = maxFps != 0 && I.current.outFps > maxFps; bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt("maxFpsMode") == 0; if (!dontEncodeFullFpsVid) { await FfmpegEncode.FramesToVideoConcat(vfrFile, outPath, mode, I.current.outFps, 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.FramesToVideoConcat(vfrFile, outPath, mode, I.current.outFps, maxFps, AvProcess.LogMode.Hidden, true); // Encode with limited fps } }
static async Task Encode(I.OutMode mode, string framesPath, string outPath, Fraction fps, Fraction resampleFps) { string framesFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(I.current.interpFactor)); if (!File.Exists(framesFile)) { bool sbs = Config.GetInt(Config.Key.processingMode) == 1; I.Cancel($"Frame order file for this interpolation factor not found!{(sbs ? "\n\nDid you run the interpolation step with the current factor?" : "")}"); return; } if (mode == I.OutMode.VidGif) { await FfmpegEncode.FramesToGifConcat(framesFile, outPath, fps, true, Config.GetInt(Config.Key.gifColors), resampleFps, I.current.outItsScale); } else { VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(I.current.inPath); await FfmpegEncode.FramesToVideo(framesFile, outPath, mode, fps, resampleFps, I.current.outItsScale, extraData); await MuxOutputVideo(I.current.inPath, outPath); await Loop(outPath, await GetLoopTimes()); } }
public static bool InputIsValid(string inDir, string outDir, Fraction fpsIn, float factor, I.OutMode outMode) { try { bool passes = true; bool isFile = !IoUtils.IsPathDirectory(inDir); float fpsOut = fpsIn.GetFloat() * factor; if ((passes && isFile && !IoUtils.IsFileValid(inDir)) || (!isFile && !IoUtils.IsDirValid(inDir))) { UiUtils.ShowMessageBox("Input path is not valid!"); passes = false; } if (passes && !IoUtils.IsDirValid(outDir)) { UiUtils.ShowMessageBox("Output path is not valid!"); passes = false; } if (passes && fpsOut < 1f || fpsOut > 1000f) { string imgSeqNote = isFile ? "" : "\n\nWhen using an image sequence as input, you always have to specify the frame rate manually."; UiUtils.ShowMessageBox($"Invalid output frame rate ({fpsOut}).\nMust be 1-1000.{imgSeqNote}"); passes = false; } string fpsLimitValue = Config.Get(Config.Key.maxFps); float fpsLimit = (fpsLimitValue.Contains("/") ? new Fraction(Config.Get(Config.Key.maxFps)).GetFloat() : fpsLimitValue.GetFloat()); if (outMode == I.OutMode.VidGif && fpsOut > 50 && !(fpsLimit > 0 && fpsLimit <= 50)) { Logger.Log($"Warning: GIF will be encoded at 50 FPS instead of {fpsOut} as the format doesn't support frame rates that high."); } if (!passes) { I.Cancel("Invalid settings detected.", true); } return(passes); } catch (Exception e) { Logger.Log($"Failed to run InputIsValid: {e.Message}\n{e.StackTrace}", true); return(false); } }
public static async Task EncodeChunk(string outPath, string interpDir, int chunkNo, I.OutMode mode, int firstFrameNum, int framesAmount) { string framesFileFull = Path.Combine(I.current.tempFolder, Paths.GetFrameOrderFilename(I.current.interpFactor)); string concatFile = Path.Combine(I.current.tempFolder, Paths.GetFrameOrderFilenameChunk(firstFrameNum, firstFrameNum + framesAmount)); File.WriteAllLines(concatFile, IoUtils.ReadLines(framesFileFull).Skip(firstFrameNum).Take(framesAmount)); List <string> inputFrames = JsonConvert.DeserializeObject <List <string> >(File.ReadAllText(framesFileFull + ".inputframes.json")).Skip(firstFrameNum).Take(framesAmount).ToList(); if (Config.GetInt(Config.Key.sceneChangeFillMode) == 1) { await Blend.BlendSceneChanges(concatFile, false); } string max = Config.Get(Config.Key.maxFps); Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat()); bool fpsLimit = maxFps.GetFloat() != 0 && I.current.outFps.GetFloat() > maxFps.GetFloat(); VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(I.current.inPath); bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0; if (mode.ToString().ToLower().StartsWith("img")) // Image Sequence output mode, not video { string desiredFormat = Config.Get(Config.Key.imgSeqFormat); string availableFormat = Path.GetExtension(IoUtils.GetFilesSorted(interpDir)[0]).Remove(".").ToUpper(); if (!dontEncodeFullFpsVid) { string outFolderPath = Path.Combine(I.current.outPath, await IoUtils.GetCurrentExportFilename(false, false)); int startNo = IoUtils.GetAmountOfFiles(outFolderPath, false) + 1; if (chunkNo == 1) // Only check for existing folder on first chunk, otherwise each chunk makes a new folder { IoUtils.RenameExistingFolder(outFolderPath); } if (desiredFormat.ToUpper() == availableFormat.ToUpper()) // Move if frames are already in the desired format { await CopyOutputFrames(interpDir, concatFile, outFolderPath, startNo, fpsLimit, true); } else // Encode if frames are not in desired format { await FfmpegEncode.FramesToFrames(concatFile, outFolderPath, startNo, I.current.outFps, new Fraction(), desiredFormat, GetImgSeqQ(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(concatFile, outputFolderPath, startNumber, I.current.outFps, maxFps, desiredFormat, GetImgSeqQ(desiredFormat), AvProcess.LogMode.Hidden); } } else { if (!dontEncodeFullFpsVid) { await FfmpegEncode.FramesToVideo(concatFile, 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(concatFile, outPath, mode, I.current.outFps, maxFps, I.current.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode with limited fps } } AutoEncodeResume.encodedChunks += 1; AutoEncodeResume.encodedFrames += framesAmount; AutoEncodeResume.processedInputFrames.AddRange(inputFrames); }