public static async Task <VidExtraData> GetVidExtraInfo(string inputFile) { string ffprobeOutput = await GetVideoInfo.GetFfprobeInfoAsync(inputFile, GetVideoInfo.FfprobeMode.ShowBoth); VidExtraData data = new VidExtraData(ffprobeOutput); return(data); }
static string GetAspectArg(VidExtraData extraData) { if (!string.IsNullOrWhiteSpace(extraData.displayRatio) && !extraData.displayRatio.MatchesWildcard("*N/A*")) { return($"-aspect {extraData.displayRatio}"); } else { return(""); } }
static async Task Encode(I.OutMode mode, string framesPath, string outPath, Fraction fps, Fraction resampleFps) { string framesFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(I.current.interpFactor)); if (!File.Exists(framesFile)) { bool sbs = Config.GetInt(Config.Key.processingMode) == 1; I.Cancel($"Frame order file for this interpolation factor not found!{(sbs ? "\n\nDid you run the interpolation step with the current factor?" : "")}"); return; } if (mode == I.OutMode.VidGif) { await FfmpegEncode.FramesToGifConcat(framesFile, outPath, fps, true, Config.GetInt(Config.Key.gifColors), resampleFps, I.current.outItsScale); } else { VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(I.current.inPath); await FfmpegEncode.FramesToVideo(framesFile, outPath, mode, fps, resampleFps, I.current.outItsScale, extraData); await MuxOutputVideo(I.current.inPath, outPath); await Loop(outPath, await GetLoopTimes()); } }
public static async Task FramesToVideo(string framesFile, string outPath, Interpolate.OutMode outMode, Fraction fps, Fraction resampleFps, float itsScale, VidExtraData extraData, LogMode logMode = LogMode.OnlyLastLine, bool isChunk = false) { if (logMode != LogMode.Hidden) { Logger.Log((resampleFps.GetFloat() <= 0) ? "Encoding video..." : $"Encoding video resampled to {resampleFps.GetString()} FPS..."); } IoUtils.RenameExistingFile(outPath); Directory.CreateDirectory(outPath.GetParentDir()); string[] encArgs = Utils.GetEncArgs(Utils.GetCodec(outMode), (Interpolate.current.ScaledResolution.IsEmpty ? Interpolate.current.InputResolution : Interpolate.current.ScaledResolution), Interpolate.current.outFps.GetFloat()); string inArg = $"-f concat -i {Path.GetFileName(framesFile)}"; string linksDir = Path.Combine(framesFile + Paths.symlinksSuffix); if (Config.GetBool(Config.Key.allowSymlinkEncoding, true) && Symlinks.SymlinksAllowed()) { if (await Symlinks.MakeSymlinksForEncode(framesFile, linksDir, Padding.interpFrames)) { inArg = $"-i \"{linksDir}/%{Padding.interpFrames}d{GetConcatFileExt(framesFile)}\""; } } string extraArgs = Config.Get(Config.Key.ffEncArgs); List <string> filters = new List <string>(); if (resampleFps.GetFloat() >= 0.1f) { filters.Add($"fps=fps={resampleFps}"); } if (Config.GetBool(Config.Key.keepColorSpace) && extraData.HasAllValues()) { Logger.Log($"Applying color transfer ({extraData.colorSpace}).", true, false, "ffmpeg"); filters.Add($"scale=out_color_matrix={extraData.colorSpace}"); extraArgs += $" -colorspace {extraData.colorSpace} -color_primaries {extraData.colorPrimaries} -color_trc {extraData.colorTransfer} -color_range:v \"{extraData.colorRange}\""; } string vf = filters.Count > 0 ? $"-vf {string.Join(",", filters)}" : ""; fps = fps / new Fraction(itsScale); string args = ""; for (int i = 0; i < encArgs.Length; i++) { string pre = i == 0 ? "" : $" && ffmpeg {AvProcess.GetFfmpegDefaultArgs()}"; string post = (i == 0 && encArgs.Length > 1) ? $"-f null -" : outPath.Wrap(); string fs = (!isChunk && outMode == Interpolate.OutMode.VidMp4) ? $"-movflags +faststart" : ""; args += $"{pre} -vsync 0 -r {fps} {inArg} {encArgs[i]} {vf} {GetAspectArg(extraData)} {extraArgs} -threads {Config.GetInt(Config.Key.ffEncThreads)} {fs} {post} "; } //string argsOld = $"-vsync 0 -r {fps} {inArg} {encArgs} {vf} {GetAspectArg(extraData)} {extraArgs} -threads {Config.GetInt(Config.Key.ffEncThreads)} {outPath.Wrap()}"; await RunFfmpeg(args, framesFile.GetParentDir(), logMode, !isChunk); IoUtils.TryDeleteIfExists(linksDir); }
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); }