public static async Task RunXvfiCuda(string framesPath, float interpFactor, string mdl) { if (Interpolate.currentlyUsingAutoEnc) // Ensure AutoEnc is not paused { AutoEncode.paused = false; } try { string xvfiDir = Path.Combine(Paths.GetPkgPath(), Implementations.xvfiCuda.pkgDir); string script = "main.py"; if (!File.Exists(Path.Combine(xvfiDir, script))) { Interpolate.Cancel("XVFI script not found! Make sure you didn't modify any files."); return; } await RunXvfiCudaProcess(framesPath, Paths.interpDir, script, interpFactor, mdl); } catch (Exception e) { Logger.Log("Error running XVFI-CUDA: " + e.Message); Logger.Log("Stack Trace: " + e.StackTrace, true); } await AiFinished("XVFI"); }
public static async Task DownloadModelFiles(string ai, string model) { model = model.ToUpper(); Logger.Log($"DownloadModelFiles(string ai = {ai}, string model = {model})", true); try { string mdlDir = GetLocalPath(ai, model); if (AreFilesValid(ai, model)) { return; } Logger.Log($"Downloading '{model}' model files..."); Directory.CreateDirectory(mdlDir); await DownloadTo(GetMdlFileUrl(ai, model, "md5.txt"), mdlDir); Dictionary <string, string> fileList = await GetFilelist(ai, model); foreach (KeyValuePair <string, string> modelFile in fileList) { await DownloadTo(GetMdlFileUrl(ai, model, modelFile.Key), mdlDir); } Logger.Log($"Downloaded \"{model}\" model files.", false, true); } catch (Exception e) { Logger.Log($"DownloadModelFiles Error: {e.Message}\nStack Trace:\n{e.StackTrace}"); Interpolate.Cancel($"Error downloading model files: {e.Message}"); } }
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); } }
static async Task DownloadTo(string url, string saveDir, int retries = 3) { string savePath = Path.Combine(saveDir, Path.GetFileName(url)); IOUtils.TryDeleteIfExists(savePath); Logger.Log($"Downloading '{url}' to '{savePath}'", true); Stopwatch sw = new Stopwatch(); sw.Restart(); bool completed = false; int lastProgPercentage = -1; var client = new WebClient(); client.DownloadProgressChanged += (sender, args) => { if (sw.ElapsedMilliseconds > 200 && args.ProgressPercentage != lastProgPercentage) { sw.Restart(); lastProgPercentage = args.ProgressPercentage; Logger.Log($"Downloading model file '{Path.GetFileName(url)}'... {args.ProgressPercentage}%", false, true); } }; client.DownloadFileCompleted += (sender, args) => { if (args.Error != null) { Logger.Log("Download failed: " + args.Error.Message); } completed = true; }; client.DownloadFileTaskAsync(url, savePath).ConfigureAwait(false); while (!completed) { if (Interpolate.canceled) { client.CancelAsync(); client.Dispose(); return; } if (sw.ElapsedMilliseconds > 6000) { client.CancelAsync(); if (retries > 0) { await DownloadTo(url, saveDir, retries --); } else { Interpolate.Cancel("Model download failed."); return; } } await Task.Delay(500); } Logger.Log($"Downloaded '{Path.GetFileName(url)}' ({IOUtils.GetFilesize(savePath) / 1024} KB)", true); }
public static async Task DownloadModelFiles(AI ai, string modelDir, bool log = true) { string aiDir = ai.pkgDir; Logger.Log($"DownloadModelFiles(string ai = {ai.aiName}, string model = {modelDir}, bool log = {log})", true); try { string mdlDir = GetLocalPath(aiDir, modelDir); if (modelDir.EndsWith("_custom") || await AreFilesValid(aiDir, modelDir)) { return; } Logger.Log($"Downloading '{modelDir}' model files...", !log); Directory.CreateDirectory(mdlDir); await DownloadTo(GetMdlFileUrl(aiDir, modelDir, "files.json"), mdlDir, false); string jsonPath = Path.Combine(mdlDir, "files.json"); List <ModelFile> modelFiles = GetModelFilesFromJson(File.ReadAllText(jsonPath)); if (!File.Exists(jsonPath) || IoUtils.GetFilesize(jsonPath) < 32) { Interpolate.Cancel($"Error: Failed to download index file. Please try again."); return; } if (modelFiles.Count < 1) { Interpolate.Cancel($"Error: Can't download model files because no entries were loaded from the index file. Please try again."); return; } foreach (ModelFile mf in modelFiles) { string relPath = Path.Combine(mf.dir, mf.filename).Replace("\\", "/"); await DownloadTo(GetMdlFileUrl(aiDir, modelDir, relPath), Path.Combine(mdlDir, relPath), log); } Logger.Log($"Downloaded \"{modelDir}\" model files.", !log, true); if (!(await AreFilesValid(aiDir, modelDir))) { Interpolate.Cancel($"Model files are invalid! Please try again."); } } catch (Exception e) { Logger.Log($"DownloadModelFiles Error: {e.Message}\nStack Trace:\n{e.StackTrace}", !log); Interpolate.Cancel($"Error downloading model files: {e.Message}"); } }
public static string GetPyCmd(bool unbufferedStdOut = true) { if (HasEmbeddedPyFolder()) { Logger.Log("Using embedded Python runtime."); return(Path.Combine(GetPyFolder(), "python.exe").Wrap() + (unbufferedStdOut ? " -u " : "")); } else { if (IsSysPyInstalled()) { return("python" + (unbufferedStdOut ? " -u " : "")); } else { MessageBox.Show("Neither the Flowframes Python Runtime nor System Python installation could be found!\nEither redownload Flowframes with the embedded Python runtime enabled or install Python/Pytorch yourself."); Interpolate.Cancel("Neither the Flowframes Python Runtime nor System Python installation could be found!"); } } return(""); }
public static async Task RunRifeCuda(string framesPath, float interpFactor, string mdl) { if (Interpolate.currentlyUsingAutoEnc) // Ensure AutoEnc is not paused { AutoEncode.paused = false; } try { string rifeDir = Path.Combine(Paths.GetPkgPath(), Implementations.rifeCuda.pkgDir); string script = "rife.py"; if (!File.Exists(Path.Combine(rifeDir, script))) { Interpolate.Cancel("RIFE script not found! Make sure you didn't modify any files."); return; } string archFilesDir = Path.Combine(rifeDir, "arch"); string archFilesDirModel = Path.Combine(rifeDir, mdl, "arch"); if (Directory.Exists(archFilesDirModel)) { Logger.Log($"Model {mdl} has architecture python files - copying to arch.", true); IoUtils.DeleteContentsOfDir(archFilesDir); IoUtils.CopyDir(archFilesDirModel, archFilesDir); } await RunRifeCudaProcess(framesPath, Paths.interpDir, script, interpFactor, mdl); } catch (Exception e) { Logger.Log("Error running RIFE-CUDA: " + e.Message); Logger.Log("Stack Trace: " + e.StackTrace, true); } await AiFinished("RIFE"); }
private void forceStopBtn_Click(object sender, EventArgs e) { Interpolate.Cancel("Force stopped by user."); BatchProcessing.stopped = true; }
static void LogOutput(string line, string logFilename, bool err = false) { if (string.IsNullOrWhiteSpace(line) || line.Length < 6) { return; } Stopwatch sw = new Stopwatch(); sw.Restart(); //if (line.Contains("iVBOR")) //{ // try // { // string[] split = line.Split(':'); // //MemoryStream stream = new MemoryStream(Convert.FromBase64String(split[1])); // //Image img = Image.FromStream(stream); // Logger.Log($"Received image {split[0]} in {sw.ElapsedMilliseconds} ms", true); // } // catch (Exception e) // { // Logger.Log($"Failed to decode b64 string - {e}:"); // Logger.Log(line); // } // return; //} lastLogName = logFilename; Logger.Log(line, true, false, logFilename); if (line.Contains("ff:nocuda-cpu")) { Logger.Log("WARNING: CUDA-capable GPU device is not available, running on CPU instead!"); } if (!hasShownError && err && line.ToLower().Contains("out of memory")) { hasShownError = true; UiUtils.ShowMessageBox($"Your GPU ran out of VRAM! Please try a video with a lower resolution or use the Max Video Size option in the settings.\n\n{line}", UiUtils.MessageType.Error); } if (!hasShownError && err && line.ToLower().Contains("modulenotfounderror")) { hasShownError = true; UiUtils.ShowMessageBox($"A python module is missing.\nCheck {logFilename} for details.\n\n{line}", UiUtils.MessageType.Error); if (!Python.HasEmbeddedPyFolder()) { Process.Start("https://github.com/n00mkrad/flowframes/blob/main/PythonDependencies.md"); } } if (!hasShownError && line.ToLower().Contains("no longer supports this gpu")) { hasShownError = true; UiUtils.ShowMessageBox($"Your GPU seems to be outdated and is not supported!\n\n{line}", UiUtils.MessageType.Error); } if (!hasShownError && line.ToLower().Contains("illegal memory access")) { hasShownError = true; UiUtils.ShowMessageBox($"Your GPU appears to be unstable! If you have an overclock enabled, please disable it!\n\n{line}", UiUtils.MessageType.Error); } if (!hasShownError && line.ToLower().Contains("error(s) in loading state_dict")) { hasShownError = true; string msg = (Interpolate.current.ai.aiName == Implementations.flavrCuda.aiName) ? "\n\nFor FLAVR, you need to select the correct model for each scale!" : ""; UiUtils.ShowMessageBox($"Error loading the AI model!\n\n{line}{msg}", UiUtils.MessageType.Error); } if (!hasShownError && line.ToLower().Contains("unicodeencodeerror")) { hasShownError = true; UiUtils.ShowMessageBox($"It looks like your path contains invalid characters - remove them and try again!\n\n{line}", UiUtils.MessageType.Error); } if (!hasShownError && err && (line.Contains("RuntimeError") || line.Contains("ImportError") || line.Contains("OSError"))) { hasShownError = true; UiUtils.ShowMessageBox($"A python error occured during interpolation!\nCheck {logFilename} for details.\n\n{line}", UiUtils.MessageType.Error); } if (!hasShownError && err && line.MatchesWildcard("vk*Instance* failed")) { hasShownError = true; UiUtils.ShowMessageBox($"Vulkan failed to start up!\n\n{line}\n\nThis most likely means your GPU is not compatible.", UiUtils.MessageType.Error); } if (!hasShownError && err && line.Contains("vkAllocateMemory failed")) { hasShownError = true; bool usingDain = (Interpolate.current.ai.aiName == Implementations.dainNcnn.aiName); string msg = usingDain ? "\n\nTry reducing the tile size in the AI settings." : "\n\nTry a lower resolution (Settings -> Max Video Size)."; UiUtils.ShowMessageBox($"Vulkan ran out of memory!\n\n{line}{msg}", UiUtils.MessageType.Error); } if (!hasShownError && err && line.Contains("invalid gpu device")) { hasShownError = true; UiUtils.ShowMessageBox($"A Vulkan error occured during interpolation!\n\n{line}\n\nAre your GPU IDs set correctly?", UiUtils.MessageType.Error); } if (!hasShownError && err && line.MatchesWildcard("vk* failed")) { hasShownError = true; UiUtils.ShowMessageBox($"A Vulkan error occured during interpolation!\n\n{line}", UiUtils.MessageType.Error); } if (hasShownError) { Interpolate.Cancel(); } InterpolationProgress.UpdateLastFrameFromInterpOutput(line); }
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 MainLoop(string interpFramesPath) { if (!AutoEncodeResume.resumeNextRun) { AutoEncodeResume.Reset(); } debug = Config.GetBool("autoEncDebug", false); try { 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); } encodedFrameLines.Clear(); unencodedFrameLines.Clear(); Logger.Log($"[AE] Starting AutoEncode MainLoop - Chunk Size: {chunkSize} Frames - Safety Buffer: {safetyBufferFrames} Frames", true); int chunkNo = AutoEncodeResume.encodedChunks + 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(1000); } int lastEncodedFrameNum = 0; while (HasWorkToDo()) // Loop while proc is running and not all frames have been encoded { if (Interpolate.canceled) { return; } if (paused) { await Task.Delay(200); continue; } unencodedFrameLines.Clear(); bool aiRunning = !AiProcess.lastAiProcess.HasExited; for (int frameLineNum = lastEncodedFrameNum; frameLineNum < interpFramesLines.Length; frameLineNum++) { if (aiRunning && interpFramesLines[frameLineNum].Contains(InterpolationProgress.lastFrame.ToString().PadLeft(Padding.interpFrames, '0'))) { break; } unencodedFrameLines.Add(frameLineNum); } if (Config.GetBool(Config.Key.alwaysWaitForAutoEnc)) { int maxFrames = chunkSize + (0.5f * chunkSize).RoundToInt() + safetyBufferFrames; bool overwhelmed = unencodedFrameLines.Count > maxFrames; if (overwhelmed && !AiProcessSuspend.aiProcFrozen && OsUtils.IsProcessHidden(AiProcess.lastAiProcess)) { string dirSize = FormatUtils.Bytes(IoUtils.GetDirSize(Interpolate.current.interpFolder, true)); Logger.Log($"AutoEnc is overwhelmed! ({unencodedFrameLines.Count} unencoded frames > {maxFrames}) - Pausing.", true); AiProcessSuspend.SuspendResumeAi(true); } else if (!overwhelmed && AiProcessSuspend.aiProcFrozen) { AiProcessSuspend.SuspendResumeAi(false); } } if (unencodedFrameLines.Count > 0 && (unencodedFrameLines.Count >= (chunkSize + safetyBufferFrames) || !aiRunning)) // Encode every n frames, or after process has exited { try { List <int> frameLinesToEncode = aiRunning ? unencodedFrameLines.Take(chunkSize).ToList() : unencodedFrameLines; // Take all remaining frames if process is done string lastOfChunk = Path.Combine(interpFramesPath, interpFramesLines[frameLinesToEncode.Last()]); if (!File.Exists(lastOfChunk)) { if (debug) { Logger.Log($"[AE] Last frame of chunk doesn't exist; skipping loop iteration ({lastOfChunk})", true); } await Task.Delay(500); continue; } busy = true; string outpath = Path.Combine(videoChunksFolder, "chunks", $"{chunkNo.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 #{chunkNo} to using line {frameLinesToEncode.First()} ({firstFile}) through {frameLinesToEncode.Last()} ({lastFile}) - {unencodedFrameLines.Count} unencoded frames left in total", true, false, "ffmpeg"); await Export.EncodeChunk(outpath, Interpolate.current.interpFolder, chunkNo, Interpolate.current.outMode, frameLinesToEncode.First(), frameLinesToEncode.Count); if (Interpolate.canceled) { return; } if (aiRunning && Config.GetInt(Config.Key.autoEncMode) == 2) { Task.Run(() => DeleteOldFramesAsync(interpFramesPath, frameLinesToEncode)); } if (Interpolate.canceled) { return; } encodedFrameLines.AddRange(frameLinesToEncode); Logger.Log("[AE] Done Encoding Chunk #" + chunkNo, true, false, "ffmpeg"); lastEncodedFrameNum = (frameLinesToEncode.Last() + 1); chunkNo++; AutoEncodeResume.Save(); if (!imgSeq && Config.GetInt(Config.Key.autoEncBackupMode) > 0) { if (aiRunning && (currentMuxTask == null || (currentMuxTask != null && currentMuxTask.IsCompleted))) { currentMuxTask = Task.Run(() => Export.ChunksToVideo(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outPath, true)); } else { Logger.Log($"[AE] Skipping backup because {(!aiRunning ? "this is the final chunk" : "previous mux task has not finished yet")}!", true, false, "ffmpeg"); } } busy = false; } catch (Exception e) { Logger.Log($"AutoEnc Chunk Encoding Error: {e.Message}. Stack Trace:\n{e.StackTrace}"); Interpolate.Cancel("Auto-Encode encountered an error."); } } await Task.Delay(50); } if (Interpolate.canceled) { return; } while (currentMuxTask != null && !currentMuxTask.IsCompleted) { await Task.Delay(100); } if (imgSeq) { return; } await Export.ChunksToVideo(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outPath); } catch (Exception e) { Logger.Log($"AutoEnc Error: {e.Message}. Stack Trace:\n{e.StackTrace}"); Interpolate.Cancel("Auto-Encode encountered an error."); } }
public static void LogOutput(string line, ref string appendStr, string logFilename, LogMode logMode, bool showProgressBar) { if (Interpolate.canceled || string.IsNullOrWhiteSpace(line) || line.Trim().Length < 1) { return; } bool hidden = logMode == LogMode.Hidden; if (HideMessage(line)) // Don't print certain warnings { hidden = true; } bool replaceLastLine = logMode == LogMode.OnlyLastLine; if (line.Contains("time=") && (line.StartsWith("frame=") || line.StartsWith("size="))) { line = FormatUtils.BeautifyFfmpegStats(line); } appendStr += Environment.NewLine + line; Logger.Log($"{prefix} {line}", hidden, replaceLastLine, logFilename); if (!hidden && showProgressBar && line.Contains("Time:")) { Regex timeRegex = new Regex("(?<=Time:).*(?= )"); UpdateFfmpegProgress(timeRegex.Match(line).Value); } if (line.Contains("Unable to")) { Interpolate.Cancel($"Error: {line}"); return; } if (line.Contains("Could not open file")) { Interpolate.Cancel($"Error: {line}"); return; } if (line.Contains("No NVENC capable devices found") || line.MatchesWildcard("*nvcuda.dll*")) { Interpolate.Cancel($"Error: {line}\n\nMake sure you have an NVENC-capable Nvidia GPU."); return; } if (line.Contains("not currently supported in container") || line.Contains("Unsupported codec id")) { Interpolate.Cancel($"Error: {line}\n\nIt looks like you are trying to copy a stream into a container that doesn't support this codec."); return; } if (line.Contains("Subtitle encoding currently only possible from text to text or bitmap to bitmap")) { Interpolate.Cancel($"Error: {line}\n\nYou cannot encode image-based subtitles into text-based subtitles. Please use the Copy Subtitles option instead, with a compatible container."); return; } if (line.Contains("Only VP8 or VP9 or AV1 video and Vorbis or Opus audio and WebVTT subtitles are supported for WebM")) { Interpolate.Cancel($"Error: {line}\n\nIt looks like you are trying to copy an unsupported stream into WEBM!"); return; } if (line.MatchesWildcard("*codec*not supported*")) { Interpolate.Cancel($"Error: {line}\n\nTry using a different codec."); return; } if (line.Contains("GIF muxer supports only a single video GIF stream")) { Interpolate.Cancel($"Error: {line}\n\nYou tried to mux a non-GIF stream into a GIF file."); return; } if (line.Contains("Width and height of input videos must be same")) { Interpolate.Cancel($"Error: {line}"); return; } }
public static async Task MainLoop(string interpFramesPath) { try { UpdateChunkAndBufferSizes(); interpFramesFolder = interpFramesPath; videoChunksFolder = Path.Combine(interpFramesPath.GetParentDir(), Paths.chunksDir); if (Interpolate.currentlyUsingAutoEnc) { Directory.CreateDirectory(videoChunksFolder); } encodedFrameLines.Clear(); unencodedFrameLines.Clear(); Logger.Log($"[AutoEnc] Starting AutoEncode MainLoop - Chunk Size: {chunkSize} Frames - Safety Buffer: {safetyBufferFrames} Frames", true); int videoIndex = 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); } int lastEncodedFrameNum = 0; while (HasWorkToDo()) // Loop while proc is running and not all frames have been encoded { if (Interpolate.canceled) { return; } if (paused) { await Task.Delay(200); continue; } unencodedFrameLines.Clear(); for (int vfrLine = lastEncodedFrameNum; vfrLine < interpFramesLines.Length; vfrLine++) { unencodedFrameLines.Add(vfrLine); } bool aiRunning = !AiProcess.currentAiProcess.HasExited; if (unencodedFrameLines.Count > 0 && (unencodedFrameLines.Count >= (chunkSize + safetyBufferFrames) || !aiRunning)) // Encode every n frames, or after process has exited { List <int> frameLinesToEncode = aiRunning ? unencodedFrameLines.Take(chunkSize).ToList() : unencodedFrameLines; // Take all remaining frames if process is done string lastOfChunk = Path.Combine(interpFramesPath, interpFramesLines[frameLinesToEncode.Last()]); if (!File.Exists(lastOfChunk)) { await Task.Delay(500); continue; } 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($"[AutoEnc] Encoding Chunk #{videoIndex} to '{outpath}' using line {firstLineNum} ({Path.GetFileName(interpFramesLines[firstLineNum])}) through {lastLineNum} ({Path.GetFileName(Path.GetFileName(interpFramesLines[frameLinesToEncode.Last()]))})", true, false, "ffmpeg"); await CreateVideo.EncodeChunk(outpath, Interpolate.current.outMode, firstLineNum, frameLinesToEncode.Count); if (Interpolate.canceled) { return; } if (aiRunning && Config.GetInt("autoEncMode") == 2) { Task.Run(() => DeleteOldFramesAsync(interpFramesPath, frameLinesToEncode)); } if (Interpolate.canceled) { return; } encodedFrameLines.AddRange(frameLinesToEncode); Logger.Log("Done Encoding Chunk #" + videoIndex, true, false, "ffmpeg"); lastEncodedFrameNum = (frameLinesToEncode.Last() + 1); videoIndex++; busy = false; } await Task.Delay(50); } if (Interpolate.canceled) { return; } await CreateVideo.ChunksToVideos(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outFilename); } catch (Exception e) { Logger.Log($"AutoEnc Error: {e.Message}. Stack Trace:\n{e.StackTrace}"); Interpolate.Cancel("Auto-Encode encountered an error."); } }