Beispiel #1
0
        public static async Task Convert(string dir, MagickFormat format, int quality, string ext = "", bool print = true, bool setProgress = true)
        {
            var files = IoUtils.GetFilesSorted(dir);

            if (print)
            {
                Logger.Log($"Converting {files.Length} files in {dir}");
            }
            int counter = 0;

            foreach (string file in files)
            {
                if (print)
                {
                    Logger.Log("Converting " + Path.GetFileName(file) + " to " + format.ToString().StripNumbers().ToUpper(), false, true);
                }
                MagickImage img = new MagickImage(file);
                img.Format  = format;
                img.Quality = quality;
                string outpath = file;
                if (!string.IsNullOrWhiteSpace(ext))
                {
                    outpath = Path.ChangeExtension(outpath, ext);
                }
                img.Write(outpath);
                counter++;
                if (setProgress)
                {
                    Program.mainForm.SetProgress((int)Math.Round(((float)counter / files.Length) * 100f));
                }
                await Task.Delay(1);
            }
        }
        public static async Task CopyLastFrame(int lastFrameNum)
        {
            if (I.canceled)
            {
                return;
            }

            try
            {
                lastFrameNum--;     // We have to do this as extracted frames start at 0, not 1
                bool   frameFolderInput = IoUtils.IsPathDirectory(I.current.inPath);
                string targetPath       = Path.Combine(I.current.framesFolder, lastFrameNum.ToString().PadLeft(Padding.inputFrames, '0') + I.current.framesExt);
                if (File.Exists(targetPath))
                {
                    return;
                }

                Size res = IoUtils.GetImage(IoUtils.GetFilesSorted(I.current.framesFolder, false).First()).Size;

                if (frameFolderInput)
                {
                    string lastFramePath = IoUtils.GetFilesSorted(I.current.inPath, false).Last();
                    await FfmpegExtract.ExtractLastFrame(lastFramePath, targetPath, res);
                }
                else
                {
                    await FfmpegExtract.ExtractLastFrame(I.current.inPath, targetPath, res);
                }
            }
            catch (Exception e)
            {
                Logger.Log("CopyLastFrame Error: " + e.Message);
            }
        }
        public static async Task DeleteInterpolatedInputFrames()
        {
            interpolatedInputFramesCount = 0;
            string[] inputFrames = IoUtils.GetFilesSorted(I.current.framesFolder);

            for (int i = 0; i < inputFrames.Length; i++)
            {
                while (Program.busy && (i + 10) > interpolatedInputFramesCount)
                {
                    await Task.Delay(1000);
                }
                if (!Program.busy)
                {
                    break;
                }

                if (i != 0 && i != inputFrames.Length - 1)
                {
                    IoUtils.OverwriteFileWithText(inputFrames[i]);
                }

                if (i % 10 == 0)
                {
                    await Task.Delay(10);
                }
            }
        }
        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);
        }
Beispiel #5
0
        public static string[] importFilenames;   // index=renamed, value=original TODO: Store on disk instead for crashes?

        public static async Task Rename()
        {
            importFilenames = IoUtils.GetFilesSorted(Interpolate.current.framesFolder).Select(x => Path.GetFileName(x)).ToArray();
            await IoUtils.RenameCounterDir(Interpolate.current.framesFolder, 0, Padding.inputFramesRenamed);

            framesAreRenamed = true;
        }
Beispiel #6
0
        public static async Task ExtractAlpha(string inputDir, string outputDir, bool print = true, bool setProgress = true, bool removeInputAlpha = true)
        {
            try
            {
                var files = IoUtils.GetFilesSorted(inputDir);
                if (print)
                {
                    Logger.Log($"Extracting alpha channel from images...");
                }
                Directory.CreateDirectory(outputDir);
                Stopwatch sw = new Stopwatch();
                sw.Restart();
                int counter = 0;
                foreach (string file in files)
                {
                    MagickImage alphaImg = new MagickImage(file);

                    if (removeInputAlpha)
                    {
                        MagickImage rgbImg = alphaImg;
                        rgbImg.Format  = MagickFormat.Png24;
                        rgbImg.Quality = 10;
                        MagickImage bg = new MagickImage(MagickColors.Black, rgbImg.Width, rgbImg.Height);
                        bg.Composite(rgbImg, CompositeOperator.Over);
                        rgbImg = bg;
                        rgbImg.Write(file);
                    }

                    alphaImg.Format  = MagickFormat.Png24;
                    alphaImg.Quality = 10;

                    alphaImg.FloodFill(MagickColors.None, 0, 0);                   // Fill the image with a transparent background
                    alphaImg.InverseOpaque(MagickColors.None, MagickColors.White); // Change all the pixels that are not transparent to white.
                    alphaImg.ColorAlpha(MagickColors.Black);                       // Change the transparent pixels to black.

                    string outPath = Path.Combine(outputDir, Path.GetFileName(file));
                    alphaImg.Write(outPath);
                    counter++;
                    if (sw.ElapsedMilliseconds > 250)
                    {
                        if (setProgress)
                        {
                            Program.mainForm.SetProgress((int)Math.Round(((float)counter / files.Length) * 100f));
                        }
                        await Task.Delay(1);

                        sw.Restart();
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Log("ExtractAlpha Error: " + e.Message);
            }
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
 public void RefreshAlpha()
 {
     try
     {
         bool   alphaModel          = model.supportsAlpha;
         bool   png                 = outMode == Interpolate.OutMode.ImgPng;
         bool   gif                 = outMode == Interpolate.OutMode.VidGif;
         bool   proResAlpha         = outMode == Interpolate.OutMode.VidProRes && Config.GetInt(Config.Key.proResProfile) > 3;
         bool   outputSupportsAlpha = png || gif || proResAlpha;
         string ext                 = inputIsFrames ? Path.GetExtension(IoUtils.GetFilesSorted(inPath).First()).ToLower() : Path.GetExtension(inPath).ToLower();
         alpha = (alphaModel && outputSupportsAlpha && (ext == ".gif" || ext == ".png" || ext == ".apng" || ext == ".mov"));
         Logger.Log($"RefreshAlpha: model.supportsAlpha = {alphaModel} - outputSupportsAlpha = {outputSupportsAlpha} - " +
                    $"input ext: {ext} => alpha = {alpha}", true);
     }
     catch (Exception e)
     {
         Logger.Log("RefreshAlpha Error: " + e.Message, true);
         alpha = false;
     }
 }
Beispiel #9
0
        public static async Task MakeBinary(string inputDir, string outputDir, bool print = true, bool setProgress = true)
        {
            try
            {
                var files = IoUtils.GetFilesSorted(inputDir);
                if (print)
                {
                    Logger.Log($"Processing alpha channel...");
                }
                Directory.CreateDirectory(outputDir);
                Stopwatch sw = new Stopwatch();
                sw.Restart();
                int counter = 0;
                foreach (string file in files)
                {
                    MagickImage img = new MagickImage(file);
                    img.Format  = MagickFormat.Png24;
                    img.Quality = 10;
                    img.Threshold(new Percentage(75));

                    string outPath = Path.Combine(outputDir, Path.GetFileName(file));
                    img.Write(outPath);
                    counter++;
                    if (sw.ElapsedMilliseconds > 250)
                    {
                        if (setProgress)
                        {
                            Program.mainForm.SetProgress((int)Math.Round(((float)counter / files.Length) * 100f));
                        }
                        await Task.Delay(1);

                        sw.Restart();
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Log("MakeBinary Error: " + e.Message);
            }
        }
Beispiel #10
0
        static async Task ExportImageSequence(string framesPath, bool stepByStep)
        {
            Program.mainForm.SetStatus("Copying output frames...");
            string   desiredFormat        = Config.Get(Config.Key.imgSeqFormat).ToUpper();
            string   availableFormat      = Path.GetExtension(IoUtils.GetFilesSorted(framesPath)[0]).Remove(".").ToUpper();
            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     dontEncodeFullFpsSeq = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
            string   framesFile           = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(I.current.interpFactor));

            if (!dontEncodeFullFpsSeq)
            {
                string outputFolderPath = Path.Combine(I.current.outPath, await IoUtils.GetCurrentExportFilename(false, false));
                IoUtils.RenameExistingFolder(outputFolderPath);
                Logger.Log($"Exporting {desiredFormat.ToUpper()} frames to '{Path.GetFileName(outputFolderPath)}'...");

                if (desiredFormat.ToUpper() == availableFormat.ToUpper())   // Move if frames are already in the desired format
                {
                    await CopyOutputFrames(framesPath, framesFile, outputFolderPath, 1, fpsLimit, false);
                }
                else    // Encode if frames are not in desired format
                {
                    await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 1, I.current.outFps, new Fraction(), desiredFormat, GetImgSeqQ(desiredFormat));
                }
            }

            if (fpsLimit)
            {
                string outputFolderPath = Path.Combine(I.current.outPath, await IoUtils.GetCurrentExportFilename(true, false));
                Logger.Log($"Exporting {desiredFormat.ToUpper()} frames to '{Path.GetFileName(outputFolderPath)}' (Resampled to {maxFps} FPS)...");
                await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 1, I.current.outFps, maxFps, desiredFormat, GetImgSeqQ(desiredFormat));
            }

            if (!stepByStep)
            {
                await IoUtils.DeleteContentsOfDirAsync(I.current.interpFolder);
            }
        }
Beispiel #11
0
        public static async Task Unrename()
        {
            Stopwatch sw = new Stopwatch();

            sw.Restart();

            string[] files = IoUtils.GetFilesSorted(Interpolate.current.framesFolder);

            for (int i = 0; i < files.Length; i++)
            {
                string movePath = Path.Combine(Interpolate.current.framesFolder, importFilenames[i]);
                File.Move(files[i], movePath);

                if (sw.ElapsedMilliseconds > 100)
                {
                    await Task.Delay(1);

                    sw.Restart();
                }
            }

            framesAreRenamed = false;
        }
Beispiel #12
0
        public static async Task <Image> GetThumbnail(string path)
        {
            string imgOnDisk = Path.Combine(Paths.GetDataPath(), "thumb-temp.jpg");

            try
            {
                if (!IoUtils.IsPathDirectory(path))     // If path is video - Extract first frame
                {
                    await FfmpegExtract.ExtractSingleFrame(path, imgOnDisk, 1);

                    return(IoUtils.GetImage(imgOnDisk));
                }
                else     // Path is frame folder - Get first frame
                {
                    return(IoUtils.GetImage(IoUtils.GetFilesSorted(path)[0]));
                }
            }
            catch (Exception e)
            {
                Logger.Log("GetThumbnail Error: " + e.Message, true);
                return(null);
            }
        }
Beispiel #13
0
        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));
            }
        }
Beispiel #14
0
        public static async Task Preprocess(string dir, bool setProgress = true)
        {
            var files = IoUtils.GetFilesSorted(dir);

            Logger.Log($"Preprocessing {files} files in {dir}");
            int counter = 0;

            foreach (string file in files)
            {
                //Logger.Log("Converting " + Path.GetFileName(file) + " to " + format, false, true);
                MagickImage img = new MagickImage(file);
                //img.Format = MagickFormat.Bmp;
                //img.Write(file);
                //img = new MagickImage(file);
                img.Format  = MagickFormat.Png24;
                img.Quality = 10;
                counter++;
                if (setProgress)
                {
                    Program.mainForm.SetProgress((int)Math.Round(((float)counter / files.Length) * 100f));
                }
                await Task.Delay(1);
            }
        }
Beispiel #15
0
        public static async Task BlendSceneChanges(string framesFilePath, bool setStatus = true)
        {
            Stopwatch sw = new Stopwatch();

            sw.Restart();
            int totalFrames = 0;

            string keyword     = "SCN:";
            string fileContent = File.ReadAllText(framesFilePath);

            if (!fileContent.Contains(keyword))
            {
                Logger.Log("Skipping BlendSceneChanges as there are no scene changes in this frames file.", true);
                return;
            }

            string[] framesLines = fileContent.SplitIntoLines();     // Array with frame filenames

            string oldStatus = Program.mainForm.GetStatus();

            if (setStatus)
            {
                Program.mainForm.SetStatus("Blending scene transitions...");
            }

            int amountOfBlendFrames = (int)Interpolate.current.interpFactor - 1;

            string[] frames = FrameRename.framesAreRenamed ? new string[0] : IoUtils.GetFilesSorted(Interpolate.current.framesFolder);

            List <Task> runningTasks = new List <Task>();
            int         maxThreads   = Environment.ProcessorCount * 2;

            foreach (string line in framesLines)
            {
                try
                {
                    if (line.Contains(keyword))
                    {
                        string   trimmedLine     = line.Split(keyword).Last();
                        string[] inputFrameNames = trimmedLine.Split('>');
                        string   frameFrom       = FrameRename.framesAreRenamed ? inputFrameNames[0] : frames[inputFrameNames[0].GetInt()];
                        string   frameTo         = FrameRename.framesAreRenamed ? inputFrameNames[1] : frames[inputFrameNames[1].GetInt()];

                        string img1 = Path.Combine(Interpolate.current.framesFolder, frameFrom);
                        string img2 = Path.Combine(Interpolate.current.framesFolder, frameTo);

                        string        firstOutputFrameName = line.Split('/').Last().Remove("'").Split('#').First();
                        string        ext = Path.GetExtension(firstOutputFrameName);
                        int           firstOutputFrameNum = firstOutputFrameName.GetInt();
                        List <string> outputFilenames     = new List <string>();

                        for (int blendFrameNum = 1; blendFrameNum <= amountOfBlendFrames; blendFrameNum++)
                        {
                            int    outputNum  = firstOutputFrameNum + blendFrameNum;
                            string outputPath = Path.Combine(Interpolate.current.interpFolder, outputNum.ToString().PadLeft(Padding.interpFrames, '0'));
                            outputPath = Path.ChangeExtension(outputPath, ext);
                            outputFilenames.Add(outputPath);
                        }

                        if (runningTasks.Count >= maxThreads)
                        {
                            do
                            {
                                await Task.Delay(10);

                                RemoveCompletedTasks(runningTasks);
                            } while (runningTasks.Count >= maxThreads);
                        }

                        Logger.Log($"Starting task for transition {inputFrameNames[0]} > {inputFrameNames[1]} ({runningTasks.Count}/{maxThreads} running)", true);
                        Task newTask = Task.Run(() => BlendImages(img1, img2, outputFilenames.ToArray()));
                        runningTasks.Add(newTask);
                        totalFrames += outputFilenames.Count;

                        await Task.Delay(1);
                    }
                }
                catch (Exception e)
                {
                    Logger.Log("Failed to blend scene changes: " + e.Message, true);
                }
            }

            while (true)
            {
                RemoveCompletedTasks(runningTasks);

                if (runningTasks.Count < 1)
                {
                    break;
                }

                await Task.Delay(10);
            }

            Logger.Log($"Created {totalFrames} blend frames in {FormatUtils.TimeSw(sw)} ({(totalFrames / (sw.ElapsedMilliseconds / 1000f)).ToString("0.00")} FPS)", true);

            if (setStatus)
            {
                Program.mainForm.SetStatus(oldStatus);
            }
        }
Beispiel #16
0
        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);
        }