예제 #1
0
        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");
        }
예제 #2
0
        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}");
            }
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
        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);
        }
예제 #5
0
        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}");
            }
        }
예제 #6
0
        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("");
        }
예제 #7
0
        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");
        }
예제 #8
0
 private void forceStopBtn_Click(object sender, EventArgs e)
 {
     Interpolate.Cancel("Force stopped by user.");
     BatchProcessing.stopped = true;
 }
예제 #9
0
        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);
        }
예제 #10
0
        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.");
            }
        }
예제 #11
0
        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.");
            }
        }
예제 #12
0
        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;
            }
        }
예제 #13
0
        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.");
            }
        }