public static async Task VideoToFrames(string inputFile, string framesDir, bool alpha, Fraction rate, bool deDupe, bool delSrc, Size size, string format) { Logger.Log("Extracting video frames from input video..."); Logger.Log($"VideoToFrames() - Alpha: {alpha} - Rate: {rate} - Size: {size} - Format: {format}", true, false, "ffmpeg"); string sizeStr = (size.Width > 1 && size.Height > 1) ? $"-s {size.Width}x{size.Height}" : ""; IoUtils.CreateDir(framesDir); string mpStr = deDupe ? ((Config.GetInt(Config.Key.mpdecimateMode) == 0) ? mpDecDef : mpDecAggr) : ""; string filters = FormatUtils.ConcatStrings(new[] { GetPadFilter(), mpStr }); string vf = filters.Length > 2 ? $"-vf {filters}" : ""; string rateArg = (rate.GetFloat() > 0) ? $" -r {rate}" : ""; string args = $"{GetTrimArg(true)} -i {inputFile.Wrap()} {GetImgArgs(format, true, alpha)} -vsync 0 {rateArg} -frame_pts 1 {vf} {sizeStr} {GetTrimArg(false)} \"{framesDir}/%{Padding.inputFrames}d{format}\""; LogMode logMode = await Interpolate.GetCurrentInputFrameCount() > 50 ? LogMode.OnlyLastLine : LogMode.Hidden; await RunFfmpeg(args, logMode, true); int amount = IoUtils.GetAmountOfFiles(framesDir, false, "*" + format); Logger.Log($"Extracted {amount} {(amount == 1 ? "frame" : "frames")} from input.", false, true); await Task.Delay(1); if (delSrc) { DeleteSource(inputFile); } }
public static async Task ExtractFrames(string inPath, string outPath, bool alpha) { if (canceled) { return; } Program.mainForm.SetStatus("Extracting frames from video..."); current.RefreshExtensions(InterpSettings.FrameType.Import); bool mpdecimate = Config.GetInt(Config.Key.dedupMode) == 2; Size res = await Utils.GetOutputResolution(inPath, true, true); await FfmpegExtract.VideoToFrames(inPath, outPath, alpha, current.inFpsDetected, mpdecimate, false, res, current.framesExt); if (mpdecimate) { int framesLeft = IoUtils.GetAmountOfFiles(outPath, false, "*" + current.framesExt); int framesDeleted = currentInputFrameCount - framesLeft; float percentDeleted = ((float)framesDeleted / currentInputFrameCount) * 100f; string keptPercent = $"{(100f - percentDeleted).ToString("0.0")}%"; if (QuickSettingsTab.trimEnabled) { Logger.Log($"Deduplication: Kept {framesLeft} frames."); } else { Logger.Log($"Deduplication: Kept {framesLeft} ({keptPercent}) frames, deleted {framesDeleted} frames."); } } if (!Config.GetBool("allowConsecutiveSceneChanges", true)) { Utils.FixConsecutiveSceneFrames(Path.Combine(current.tempFolder, Paths.scenesDir), current.framesFolder); } }
public static async Task ExtractSceneChanges(string inPath, string outDir, Fraction rate, bool inputIsFrames, string format) { Logger.Log("Extracting scene changes..."); Directory.CreateDirectory(outDir); string inArg = $"-i {inPath.Wrap()}"; if (inputIsFrames) { string concatFile = Path.Combine(Paths.GetDataPath(), "png-scndetect-concat-temp.ini"); FfmpegUtils.CreateConcatFile(inPath, concatFile, Filetypes.imagesInterpCompat); inArg = $"-f concat -safe 0 -i {concatFile.Wrap()}"; } string scnDetect = $"-vf \"select='gt(scene,{Config.GetFloatString(Config.Key.scnDetectValue)})'\""; string rateArg = (rate.GetFloat() > 0) ? $"-r {rate}" : ""; string args = $"-vsync 0 {GetTrimArg(true)} {inArg} {GetImgArgs(format)} {rateArg} {scnDetect} -frame_pts 1 -s 256x144 {GetTrimArg(false)} \"{outDir}/%{Padding.inputFrames}d{format}\""; LogMode logMode = await Interpolate.GetCurrentInputFrameCount() > 50 ? LogMode.OnlyLastLine : LogMode.Hidden; await RunFfmpeg(args, logMode, inputIsFrames? "panic" : "warning", true); bool hiddenLog = await Interpolate.GetCurrentInputFrameCount() <= 50; int amount = IoUtils.GetAmountOfFiles(outDir, false); Logger.Log($"Detected {amount} scene {(amount == 1 ? "change" : "changes")}.".Replace(" 0 ", " no "), false, !hiddenLog); }
public static async Task ImportImages(string inPath, string outPath, bool alpha, Size size, bool showLog, string format) { if (showLog) { Logger.Log($"Importing images from {new DirectoryInfo(inPath).Name}..."); } Logger.Log($"ImportImages() - Alpha: {alpha} - Size: {size} - Format: {format}", true, false, "ffmpeg"); IoUtils.CreateDir(outPath); string concatFile = Path.Combine(Paths.GetDataPath(), "import-concat-temp.ini"); FfmpegUtils.CreateConcatFile(inPath, concatFile, Filetypes.imagesInterpCompat); string inArg = $"-f concat -safe 0 -i {concatFile.Wrap()}"; string linksDir = Path.Combine(concatFile + Paths.symlinksSuffix); if (Config.GetBool(Config.Key.allowSymlinkEncoding, true) && Symlinks.SymlinksAllowed()) { if (await Symlinks.MakeSymlinksForEncode(concatFile, linksDir, Padding.interpFrames)) { inArg = $"-i \"{linksDir}/%{Padding.interpFrames}d{FfmpegEncode.GetConcatFileExt(concatFile)}\""; } } string sizeStr = (size.Width > 1 && size.Height > 1) ? $"-s {size.Width}x{size.Height}" : ""; string vf = $"-vf {GetPadFilter()}"; string args = $"-r 25 {inArg} {GetImgArgs(format, true, alpha)} {sizeStr} -vsync 0 -start_number 0 {vf} \"{outPath}/%{Padding.inputFrames}d{format}\""; LogMode logMode = IoUtils.GetAmountOfFiles(inPath, false) > 50 ? LogMode.OnlyLastLine : LogMode.Hidden; await RunFfmpeg(args, logMode, "panic"); }
public static async Task CreateOutputVid() { if (IoUtils.GetAmountOfFiles(current.interpFolder, false) < 2) { if (Config.GetBool(Config.Key.sbsRunPreviousStepIfNeeded)) { Logger.Log($"There are no interpolated frames to export - Running interpolation step first..."); await InterpolateStep(); } if (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, current.interpExt); if (outFrames.Length > 0 && !IoUtils.CheckImageValid(outFrames[0])) { UiUtils.ShowMessageBox("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.", UiUtils.MessageType.Error); return; } await Export.ExportFrames(current.interpFolder, current.outPath, current.outMode, true); }
public static bool CheckAiAvailable(AI ai, ModelCollection.ModelInfo model) { if (IoUtils.GetAmountOfFiles(Path.Combine(Paths.GetPkgPath(), ai.pkgDir), true) < 1) { UiUtils.ShowMessageBox("The selected AI is not installed!", UiUtils.MessageType.Error); I.Cancel("Selected AI not available.", true); return(false); } if (model == null || model.dir.Trim() == "") { UiUtils.ShowMessageBox("No valid AI model has been selected!", UiUtils.MessageType.Error); I.Cancel("No valid model selected.", true); return(false); } if (I.current.ai.aiName.ToUpper().Contains("CUDA") && NvApi.gpuList.Count < 1) { UiUtils.ShowMessageBox("Warning: No Nvidia GPU was detected. CUDA might fall back to CPU!\n\nTry an NCNN implementation instead if you don't have an Nvidia GPU.", UiUtils.MessageType.Error); if (!Config.GetBool("allowCudaWithoutDetectedGpu", true)) { I.Cancel("No CUDA-capable graphics card available.", true); return(false); } } return(true); }
static void CheckExistingFolder(string inpath, string outpath) { if (Interpolate.current == null || !Interpolate.current.stepByStep) { return; } string tmpFolder = InterpolateUtils.GetTempFolderLoc(inpath, outpath); if (Directory.Exists(tmpFolder)) { int scnFrmAmount = IoUtils.GetAmountOfFiles(Path.Combine(tmpFolder, Paths.scenesDir), false, "*" + Interpolate.current.interpExt); // TODO: Make this work if the frames extension was changed string scnFrames = scnFrmAmount > 0 ? $"{scnFrmAmount} scene frames" : "no scene frames"; int srcFrmAmount = IoUtils.GetAmountOfFiles(Path.Combine(tmpFolder, Paths.framesDir), false, "*" + Interpolate.current.interpExt); string srcFrames = srcFrmAmount > 1 ? $"{srcFrmAmount} source frames" : "no source frames"; int interpFrmAmount = IoUtils.GetAmountOfFiles(Path.Combine(tmpFolder, Paths.interpDir), false); string interpFrames = interpFrmAmount > 2 ? $"{interpFrmAmount} interpolated frames" : "no interpolated frames"; string msg = $"A temporary folder for this video already exists. It contains {scnFrames}, {srcFrames}, {interpFrames}."; DialogResult dialogResult = MessageBox.Show($"{msg}\n\nClick \"Yes\" to use the existing files or \"No\" to delete them.", "Use files from existing temp folder?", MessageBoxButtons.YesNo); if (dialogResult == DialogResult.No) { IoUtils.TryDeleteIfExists(tmpFolder); Logger.Log("Deleted old temp folder."); } } }
static async Task AiFinished(string aiName) { if (Interpolate.canceled) { return; } Program.mainForm.SetProgress(100); AiProcessSuspend.SetRunning(false); int interpFramesFiles = IoUtils.GetAmountOfFiles(Interpolate.current.interpFolder, false, "*" + Interpolate.current.interpExt); int interpFramesCount = interpFramesFiles + InterpolationProgress.deletedFramesCount; InterpolationProgress.UpdateInterpProgress(interpFramesCount, InterpolationProgress.targetFrames); string logStr = $"Done running {aiName} - Interpolation took {FormatUtils.Time(processTime.Elapsed)}. Peak Output FPS: {InterpolationProgress.peakFpsOut.ToString("0.00")}"; if (Interpolate.currentlyUsingAutoEnc && AutoEncode.HasWorkToDo()) { logStr += " - Waiting for encoding to finish..."; Program.mainForm.SetStatus("Creating output video from frames..."); } Logger.Log(logStr); processTime.Stop(); if (interpFramesCount < 3) { string[] logLines = File.ReadAllLines(Path.Combine(Paths.GetLogPath(), lastLogName + ".txt")); string log = string.Join("\n", logLines.Reverse().Take(10).Reverse().Select(x => x.Split("]: ").Last()).ToList()); string amount = interpFramesCount > 0 ? $"Only {interpFramesCount}" : "No"; Interpolate.Cancel($"Interpolation failed - {amount} interpolated frames were created.\n\n\nLast 10 log lines:\n{log}\n\nCheck the log '{lastLogName}' for more details."); return; } try { while (Interpolate.currentlyUsingAutoEnc && Program.busy) { if (AvProcess.lastAvProcess != null && !AvProcess.lastAvProcess.HasExited) { if (Logger.LastLogLine.ToLower().Contains("frame: ")) { Logger.Log(FormatUtils.BeautifyFfmpegStats(Logger.LastLogLine), false, Logger.LastUiLine.ToLower().Contains("frame")); } } if (AvProcess.lastAvProcess.HasExited && !AutoEncode.HasWorkToDo()) // Stop logging if ffmpeg is not running & AE is done { break; } await Task.Delay(500); } } catch (Exception e) { Logger.Log($"AiFinished encoder logging error: {e.Message}\n{e.StackTrace}", true); } }
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."); } }
public static async Task ChunksToVideo(string tempFolder, string chunksFolder, string baseOutPath, bool isBackup = false) { 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; } NmkdStopwatch sw = new NmkdStopwatch(); if (!isBackup) { Program.mainForm.SetStatus("Merging video chunks..."); } try { 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); Logger.Log($"CreateVideo: Running MergeChunks() for frames file '{Path.GetFileName(tempConcatFile)}'", true); bool fpsLimit = dir.Name.Contains(Paths.fpsLimitSuffix); string outPath = Path.Combine(baseOutPath, await IoUtils.GetCurrentExportFilename(fpsLimit, true)); await MergeChunks(tempConcatFile, outPath, isBackup); if (!isBackup) { Task.Run(async() => { await IoUtils.TryDeleteIfExistsAsync(IoUtils.FilenameSuffix(outPath, Paths.backupSuffix)); }); } } } catch (Exception e) { Logger.Log("ChunksToVideo Error: " + e.Message, isBackup); if (!isBackup) { MessageBox.Show("An error occured while trying to merge the video chunks.\nCheck the log for details."); } } Logger.Log($"Merged video chunks in {sw}", true); }
public static async Task <int> GetFrameCountAsync(string path, int retryCount = 3) { Logger.Log($"Getting frame count ({path})", true); long filesize = IoUtils.GetFilesize(path); QueryInfo hash = new QueryInfo(path, filesize); if (filesize > 0 && CacheContains(hash)) { Logger.Log($"Cache contains this hash, using cached value.", true); return(GetFromCache(hash)); } else { Logger.Log($"Hash not cached, reading frame count.", true); } int frameCount; if (IoUtils.IsPathDirectory(path)) { frameCount = IoUtils.GetAmountOfFiles(path, false); } else { frameCount = await FfmpegCommands.GetFrameCountAsync(path); } if (frameCount > 0) { Logger.Log($"Adding hash with value {frameCount} to cache.", true); cache.Add(hash, frameCount); } else { if (retryCount > 0) { Logger.Log($"Got {frameCount} frames, retrying ({retryCount} left)", true); Clear(); frameCount = await GetFrameCountAsync(path, retryCount - 1); } else { Logger.Log($"Failed to get frames and out of retries ({frameCount} frames for {path})", true); } } return(frameCount); }
public static async Task InterpolateStep() { if (!InterpolateUtils.CheckAiAvailable(current.ai, current.model)) { return; } current.framesFolder = Path.Combine(current.tempFolder, Paths.framesDir); if (IoUtils.GetAmountOfFiles(current.framesFolder, false, "*") < 2) { if (Config.GetBool(Config.Key.sbsRunPreviousStepIfNeeded)) { Logger.Log($"There are no extracted frames to interpolate - Running extract step first..."); await ExtractFramesStep(); } if (IoUtils.GetAmountOfFiles(current.framesFolder, false, "*") < 2) { UiUtils.ShowMessageBox("There are no extracted frames that can be interpolated!\nDid you run the extraction step?", UiUtils.MessageType.Error); return; } } if (!(await IoUtils.TryDeleteIfExistsAsync(current.interpFolder))) { UiUtils.ShowMessageBox("Failed to delete existing frames folder - Make sure no file is opened in another program!", UiUtils.MessageType.Error); return; } currentInputFrameCount = await GetFrameCountCached.GetFrameCountAsync(current.inPath); if (Config.GetBool(Config.Key.sbsAllowAutoEnc) && !(await InterpolateUtils.CheckEncoderValid())) { return; } if (canceled) { return; } Program.mainForm.SetStatus("Running AI..."); await RunAi(current.interpFolder, current.ai, true); await Task.Run(async() => { await FrameRename.Unrename(); }); // Get timestamps back Program.mainForm.SetProgress(0); }
public static void UpdateChunkAndBufferSizes() { chunkSize = GetChunkSize((IoUtils.GetAmountOfFiles(Interpolate.current.framesFolder, false, "*" + Interpolate.current.framesExt) * Interpolate.current.interpFactor).RoundToInt()); safetyBufferFrames = 90; if (Interpolate.current.ai.backend == AI.Backend.Ncnn) { safetyBufferFrames = Config.GetInt(Config.Key.autoEncSafeBufferNcnn, 150); } if (Interpolate.current.ai.backend == AI.Backend.Pytorch) { safetyBufferFrames = Config.GetInt(Config.Key.autoEncSafeBufferCuda, 90); } }
public static async Task PostProcessFrames(bool stepByStep) { if (canceled) { return; } Program.mainForm.SetStatus("Processing frames..."); int extractedFrames = IoUtils.GetAmountOfFiles(current.framesFolder, false, "*" + current.framesExt); if (!Directory.Exists(current.framesFolder) || currentInputFrameCount <= 0 || extractedFrames < 2) { if (extractedFrames == 1) { Cancel("Only a single frame was extracted from your input file!\n\nPossibly your input is an image, not a video?"); } else { Cancel($"Frame extraction failed!\nExtracted {extractedFrames} frames - current.framesFolder exists: {Directory.Exists(current.framesFolder)} - currentInputFrameCount = {currentInputFrameCount} - extractedFrames = {extractedFrames}.\n\nYour input file might be incompatible."); } } if (Config.GetInt(Config.Key.dedupMode) == 1) { await Dedupe.Run(current.framesFolder); } else { Dedupe.ClearCache(); } if (!Config.GetBool(Config.Key.enableLoop)) { await Utils.CopyLastFrame(currentInputFrameCount); } else { FileInfo[] frameFiles = IoUtils.GetFileInfosSorted(current.framesFolder); string ext = frameFiles.First().Extension; int lastNum = frameFiles.Last().Name.GetInt() + 1; string loopFrameTargetPath = Path.Combine(current.framesFolder, lastNum.ToString().PadLeft(Padding.inputFrames, '0') + ext); File.Copy(frameFiles.First().FullName, loopFrameTargetPath, true); Logger.Log($"Copied loop frame to {loopFrameTargetPath}.", true); } }
static void SetProgressCheck(string interpPath, float factor) { int frames = IoUtils.GetAmountOfFiles(lastInPath, false); int target = ((frames * factor) - (factor - 1)).RoundToInt(); InterpolationProgress.progressPaused = false; InterpolationProgress.currentFactor = factor; if (InterpolationProgress.progCheckRunning) { InterpolationProgress.targetFrames = target; } else { InterpolationProgress.GetProgressByFrameAmount(interpPath, target); } }
public static void Cancel(string reason = "", bool noMsgBox = false) { if (current == null) { return; } canceled = true; Program.mainForm.SetStatus("Canceled."); Program.mainForm.SetProgress(0); AiProcess.Kill(); AvProcess.Kill(); if (!current.stepByStep && !Config.GetBool(Config.Key.keepTempFolder)) { if (!BatchProcessing.busy && IoUtils.GetAmountOfFiles(Path.Combine(current.tempFolder, Paths.resumeDir), true) > 0) { DialogResult dialogResult = MessageBox.Show($"Delete the temp folder (Yes) or keep it for resuming later (No)?", "Delete temporary files?", MessageBoxButtons.YesNo); if (dialogResult == DialogResult.Yes) { Task.Run(async() => { await IoUtils.TryDeleteIfExistsAsync(current.tempFolder); }); } } else { Task.Run(async() => { await IoUtils.TryDeleteIfExistsAsync(current.tempFolder); }); } } AutoEncode.busy = false; Program.mainForm.SetWorking(false); Program.mainForm.SetTab("interpolation"); Logger.LogIfLastLineDoesNotContainMsg("Canceled interpolation."); if (!string.IsNullOrWhiteSpace(reason) && !noMsgBox) { UiUtils.ShowMessageBox($"Canceled:\n\n{reason}"); } }
static bool EntryIsValid(InterpSettings entry) { if (entry.inPath == null || (IoUtils.IsPathDirectory(entry.inPath) && !Directory.Exists(entry.inPath)) || (!IoUtils.IsPathDirectory(entry.inPath) && !File.Exists(entry.inPath))) { Logger.Log("Queue: Can't process queue entry: Input path is invalid."); return(false); } if (entry.outPath == null || (!Directory.Exists(entry.outPath) && Config.GetInt("outFolderLoc") != 1)) { Logger.Log("Queue: Can't process queue entry: Output path is invalid."); return(false); } if (IoUtils.GetAmountOfFiles(Path.Combine(Paths.GetPkgPath(), entry.ai.pkgDir), true) < 1) { Logger.Log("Queue: Can't process queue entry: Selected AI is not available."); return(false); } return(true); }
public static bool CanUseAutoEnc(bool stepByStep, InterpSettings current) { AutoEncode.UpdateChunkAndBufferSizes(); if (Config.GetInt(Config.Key.cmdDebugMode) > 0) { Logger.Log($"Not Using AutoEnc: CMD window is shown (cmdDebugMode > 0)", true); return(false); } if (current.outMode == I.OutMode.VidGif) { Logger.Log($"Not Using AutoEnc: Using GIF output", 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); return(false); } if (!stepByStep && Config.GetInt(Config.Key.autoEncMode) == 0) { Logger.Log($"Not Using AutoEnc: 'autoEncMode' is 0", true); return(false); } 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 than (chunkSize ({AutoEncode.chunkSize}) + safetyBufferFrames ({AutoEncode.safetyBufferFrames}) * 1.2f)", true); return(false); } return(true); }
static async Task RunRifeNcnnProcess(string inPath, float factor, string outPath, string mdl) { Directory.CreateDirectory(outPath); Process rifeNcnn = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd()); AiStarted(rifeNcnn, 1500, inPath); SetProgressCheck(outPath, factor); int targetFrames = ((IoUtils.GetAmountOfFiles(lastInPath, false, "*.*") * factor).RoundToInt()); // TODO: Maybe won't work with fractional factors ?? string frames = mdl.Contains("v4") ? $"-n {targetFrames}" : ""; string uhdStr = await InterpolateUtils.UseUhd() ? "-u" : ""; string ttaStr = Config.GetBool(Config.Key.rifeNcnnUseTta, false) ? "-x" : ""; rifeNcnn.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnn.pkgDir).Wrap()} & rife-ncnn-vulkan.exe " + $" -v -i {inPath.Wrap()} -o {outPath.Wrap()} {frames} -m {mdl.ToLower()} {ttaStr} {uhdStr} -g {Config.Get(Config.Key.ncnnGpus)} -f {GetNcnnPattern()} -j {GetNcnnThreads()}"; Logger.Log("cmd.exe " + rifeNcnn.StartInfo.Arguments, true); if (!OsUtils.ShowHiddenCmd()) { rifeNcnn.OutputDataReceived += (sender, outLine) => { LogOutput("[O] " + outLine.Data, "rife-ncnn-log"); }; rifeNcnn.ErrorDataReceived += (sender, outLine) => { LogOutput("[E] " + outLine.Data, "rife-ncnn-log", true); }; } rifeNcnn.Start(); if (!OsUtils.ShowHiddenCmd()) { rifeNcnn.BeginOutputReadLine(); rifeNcnn.BeginErrorReadLine(); } while (!rifeNcnn.HasExited) { await Task.Delay(1); } }
public static async Task RunDainNcnnProcess(string framesPath, string outPath, float factor, string mdl, int tilesize) { string dainDir = Path.Combine(Paths.GetPkgPath(), Implementations.dainNcnn.pkgDir); Directory.CreateDirectory(outPath); Process dain = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd()); AiStarted(dain, 1500); SetProgressCheck(outPath, factor); int targetFrames = ((IoUtils.GetAmountOfFiles(lastInPath, false, "*.*") * factor).RoundToInt()); string args = $" -v -i {framesPath.Wrap()} -o {outPath.Wrap()} -n {targetFrames} -m {mdl.ToLower()}" + $" -t {GetNcnnTilesize(tilesize)} -g {Config.Get(Config.Key.ncnnGpus)} -f {GetNcnnPattern()} -j 2:1:2"; dain.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {dainDir.Wrap()} & dain-ncnn-vulkan.exe {args}"; Logger.Log("Running DAIN...", false); Logger.Log("cmd.exe " + dain.StartInfo.Arguments, true); if (!OsUtils.ShowHiddenCmd()) { dain.OutputDataReceived += (sender, outLine) => { LogOutput("[O] " + outLine.Data, "dain-ncnn-log"); }; dain.ErrorDataReceived += (sender, outLine) => { LogOutput("[E] " + outLine.Data, "dain-ncnn-log", true); }; } dain.Start(); if (!OsUtils.ShowHiddenCmd()) { dain.BeginOutputReadLine(); dain.BeginErrorReadLine(); } while (!dain.HasExited) { await Task.Delay(100); } }
public void DragDropHandler(string[] files) { if (Program.busy) { return; } bool start = Program.initialRun && Program.args.Contains("start"); if (files.Length > 1) { queueBtn_Click(null, null); if (BatchProcessing.currentBatchForm != null) { BatchProcessing.currentBatchForm.LoadDroppedPaths(files, start); } } else { SetTab("interpolation"); Logger.Log("Selected video/directory: " + Path.GetFileName(files[0]), true); inputTbox.Text = files[0]; bool resume = (IoUtils.GetAmountOfFiles(Path.Combine(files[0], Paths.resumeDir), true, "*.json") > 0); AutoEncodeResume.resumeNextRun = resume; if (resume) { AutoEncodeResume.LoadTempFolder(files[0]); } trimCombox.SelectedIndex = 0; MainUiFunctions.InitInput(outputTbox, inputTbox, fpsInTbox, start); } }
public static void FixConsecutiveSceneFrames(string sceneFramesPath, string sourceFramesPath) { if (!Directory.Exists(sceneFramesPath) || IoUtils.GetAmountOfFiles(sceneFramesPath, false) < 1) { return; } List <string> sceneFrames = IoUtils.GetFilesSorted(sceneFramesPath).Select(x => Path.GetFileNameWithoutExtension(x)).ToList(); List <string> sourceFrames = IoUtils.GetFilesSorted(sourceFramesPath).Select(x => Path.GetFileNameWithoutExtension(x)).ToList(); List <string> sceneFramesToDelete = new List <string>(); foreach (string scnFrame in sceneFrames) { if (sceneFramesToDelete.Contains(scnFrame)) { continue; } int sourceIndexForScnFrame = sourceFrames.IndexOf(scnFrame); // Get source index of scene frame if ((sourceIndexForScnFrame + 1) == sourceFrames.Count) { continue; } string followingFrame = sourceFrames[sourceIndexForScnFrame + 1]; // Get filename/timestamp of the next source frame if (sceneFrames.Contains(followingFrame)) // If next source frame is in scene folder, add to deletion list { sceneFramesToDelete.Add(followingFrame); } } foreach (string frame in sceneFramesToDelete) { IoUtils.TryDeleteIfExists(Path.Combine(sceneFramesPath, frame + I.current.framesExt)); } }
public static async Task <bool> PrepareResumedRun() // Remove already interpolated frames, return true if interpolation should be skipped { if (!resumeNextRun) { return(false); } try { string chunkJsonPath = Path.Combine(I.current.tempFolder, Paths.resumeDir, chunksFilename); string inFramesJsonPath = Path.Combine(I.current.tempFolder, Paths.resumeDir, inputFramesFilename); dynamic chunksData = JsonConvert.DeserializeObject(File.ReadAllText(chunkJsonPath)); encodedChunks = chunksData.encodedChunks; encodedFrames = chunksData.encodedFrames; List <string> processedInputFrames = JsonConvert.DeserializeObject <List <string> >(File.ReadAllText(inFramesJsonPath)); int uniqueInputFrames = processedInputFrames.Distinct().Count(); foreach (string inputFrameName in processedInputFrames) { string inputFrameFullPath = Path.Combine(I.current.tempFolder, Paths.framesDir, inputFrameName); IoUtils.TryDeleteIfExists(inputFrameFullPath); } string videoChunksFolder = Path.Combine(I.current.tempFolder, Paths.chunksDir); FileInfo[] invalidChunks = IoUtils.GetFileInfosSorted(videoChunksFolder, true, "????.*").Skip(encodedChunks).ToArray(); foreach (FileInfo chunk in invalidChunks) { chunk.Delete(); } int inputFramesLeft = IoUtils.GetAmountOfFiles(Path.Combine(I.current.tempFolder, Paths.framesDir), false); Logger.Log($"Resume: Already encoded {encodedFrames} frames in {encodedChunks} chunks. There are now {inputFramesLeft} input frames left to interpolate."); if (inputFramesLeft < 2) { if (IoUtils.GetAmountOfFiles(videoChunksFolder, true, "*.*") > 0) { Logger.Log($"No more frames left to interpolate - Merging existing video chunks instead."); await Export.ChunksToVideo(I.current.tempFolder, videoChunksFolder, I.current.outPath); await I.Done(); } else { I.Cancel("There are no more frames left to interpolate in this temp folder!"); } return(true); } return(false); } catch (Exception e) { Logger.Log($"Failed to prepare resumed run: {e.Message}\n{e.StackTrace}"); I.Cancel("Failed to resume interpolation. Check the logs for details."); resumeNextRun = false; return(true); } // string stateFilepath = Path.Combine(I.current.tempFolder, Paths.resumeDir, resumeFilename); // ResumeState state = new ResumeState(File.ReadAllText(stateFilepath)); // // string fileMapFilepath = Path.Combine(I.current.tempFolder, Paths.resumeDir, filenameMapFilename); // List<string> inputFrameLines = File.ReadAllLines(fileMapFilepath).Where(l => l.Trim().Length > 3).ToList(); // List<string> inputFrames = inputFrameLines.Select(l => Path.Combine(I.current.framesFolder, l.Split('|')[1])).ToList(); // // for (int i = 0; i < state.interpolatedInputFrames; i++) // { // IoUtils.TryDeleteIfExists(inputFrames[i]); // if (i % 1000 == 0) await Task.Delay(1); // } // // Directory.Move(I.current.interpFolder, I.current.interpFolder + Paths.prevSuffix); // Move existing interp frames // Directory.CreateDirectory(I.current.interpFolder); // Re-create empty interp folder }
static int GetInterpFramesAmount() { return(IoUtils.GetAmountOfFiles(interpFramesFolder, false, "*" + Interpolate.current.interpExt)); }
public static async Task RemoveDupeFrames(string path, float threshold, string ext, bool testRun = false, bool debugLog = false, bool skipIfNoDupes = false) { Stopwatch sw = new Stopwatch(); sw.Restart(); Logger.Log("Removing duplicate frames - Threshold: " + threshold.ToString("0.00")); FileInfo[] framePaths = IoUtils.GetFileInfosSorted(path, false, "*." + ext); List <string> framesToDelete = new List <string>(); int bufferSize = await GetBufferSize(); int currentOutFrame = 1; int currentDupeCount = 0; int statsFramesKept = 0; int statsFramesDeleted = 0; bool hasReachedEnd = false; string fileContent = ""; for (int i = 0; i < framePaths.Length; i++) // Loop through frames { if (hasReachedEnd) { break; } string frame1 = framePaths[i].FullName; int compareWithIndex = i + 1; while (true) // Loop dupes { //compareWithIndex++; if (compareWithIndex >= framePaths.Length) { hasReachedEnd = true; break; } if (framesToDelete.Contains(framePaths[compareWithIndex].FullName) || !File.Exists(framePaths[compareWithIndex].FullName)) { //Logger.Log($"Frame {compareWithIndex} was already deleted - skipping"); compareWithIndex++; } else { string frame2 = framePaths[compareWithIndex].FullName; float diff = GetDifference(frame1, frame2); if (diff < threshold) // Is a duped frame. { if (!testRun) { framesToDelete.Add(frame2); if (debugLog) { Logger.Log("Deduplication: Deleted " + Path.GetFileName(frame2)); } } statsFramesDeleted++; currentDupeCount++; } else { fileContent += $"{Path.GetFileNameWithoutExtension(framePaths[i].Name)}:{currentDupeCount}\n"; statsFramesKept++; currentOutFrame++; currentDupeCount = 0; break; } } } if (sw.ElapsedMilliseconds >= 500 || (i + 1) == framePaths.Length) // Print every 0.5s (or when done) { sw.Restart(); Logger.Log($"Deduplication: Running de-duplication ({i}/{framePaths.Length}), deleted {statsFramesDeleted} ({(((float)statsFramesDeleted / framePaths.Length) * 100f).ToString("0")}%) duplicate frames so far...", false, true); Program.mainForm.SetProgress((int)Math.Round(((float)i / framePaths.Length) * 100f)); if (imageCache.Count > bufferSize || (imageCache.Count > 50 && OsUtils.GetFreeRamMb() < 3500)) { ClearCache(); } } // int oldIndex = -1; // TODO: Compare with 1st to fix loops? // if (i >= framePaths.Length) // If this is the last frame, compare with 1st to avoid OutOfRange error // { // oldIndex = i; // i = 0; // } if (i % 3 == 0) { await Task.Delay(1); } if (Interpolate.canceled) { return; } } foreach (string frame in framesToDelete) { IoUtils.TryDeleteIfExists(frame); } string testStr = testRun ? " [TestRun]" : ""; if (Interpolate.canceled) { return; } int framesLeft = IoUtils.GetAmountOfFiles(path, false, "*" + Interpolate.current.framesExt); int framesDeleted = framePaths.Length - framesLeft; float percentDeleted = ((float)framesDeleted / framePaths.Length) * 100f; string keptPercent = $"{(100f - percentDeleted).ToString("0.0")}%"; Logger.Log($"[Deduplication]{testStr} Done. Kept {framesLeft} ({keptPercent}) frames, deleted {framesDeleted} frames.", false, true); if (statsFramesKept <= 0) { Interpolate.Cancel("No frames were left after de-duplication!\n\nTry decreasing the de-duplication threshold."); } }
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); }
static async Task DeleteNcnnDupes(string dir, float factor) { int dupeCount = InterpolateUtils.GetRoundedInterpFramesPerInputFrame(factor); var files = IoUtils.GetFileInfosSorted(dir, false).Reverse().Take(dupeCount).ToList(); Logger.Log($"DeleteNcnnDupes: Calculated dupe count from factor; deleting last {dupeCount} interp frames of {IoUtils.GetAmountOfFiles(dir, false)} ({string.Join(", ", files.Select(x => x.Name))})", true); int attempts = 4; while (attempts > 0) { try { files.ForEach(x => x.Delete()); break; } catch (Exception ex) { attempts--; if (attempts < 1) { Logger.Log($"DeleteNcnnDupes Error: {ex.Message}", true); break; } else { await Task.Delay(500); } } } }