/// <summary> /// Create a CanonicalPathCache. /// </summary> /// /// <remarks> /// Creates the appropriate PathStrategy object which encapsulates /// the correct algorithm. Falls back to different implementations /// depending on platform. /// </remarks> /// /// <param name="maxCapacity">Size of the cache.</param> /// <param name="symlinks">Policy for following symlinks.</param> /// <returns>A new CanonicalPathCache.</returns> public static CanonicalPathCache Create(ILogger logger, int maxCapacity, Symlinks symlinks) { PathStrategy pathStrategy; switch (symlinks) { case Symlinks.Follow: try { pathStrategy = Win32.IsWindows() ? (PathStrategy) new GetFinalPathNameByHandleStrategy() : (PathStrategy) new PosixSymlinkStrategy(); } catch (Exception) { // Failed to late-bind a suitable library. logger.Log(Severity.Warning, "Preserving symlinks in canonical paths"); pathStrategy = new QueryDirectoryStrategy(); } break; case Symlinks.Preserve: pathStrategy = new QueryDirectoryStrategy(); break; default: throw new ArgumentOutOfRangeException("Invalid symlinks option"); } return(new CanonicalPathCache(maxCapacity, pathStrategy)); }
public static async Task FramesToFrames(string framesFile, string outDir, int startNo, Fraction fps, Fraction resampleFps, string format = "png", int lossyQ = 1, LogMode logMode = LogMode.OnlyLastLine) { Directory.CreateDirectory(outDir); string inArg = $"-f concat -i {Path.GetFileName(framesFile)}"; string linksDir = Path.Combine(framesFile + Paths.symlinksSuffix); format = format.ToLower(); if (Config.GetBool(Config.Key.allowSymlinkEncoding, true) && Symlinks.SymlinksAllowed()) { if (await Symlinks.MakeSymlinksForEncode(framesFile, linksDir, Padding.interpFrames)) { inArg = $"-i {Path.GetFileName(framesFile) + Paths.symlinksSuffix}/%{Padding.interpFrames}d{GetConcatFileExt(framesFile)}"; } } string sn = $"-start_number {startNo}"; string rate = fps.ToString().Replace(",", "."); string vf = (resampleFps.GetFloat() < 0.1f) ? "" : $"-vf fps=fps={resampleFps}"; string compression = format == "png" ? pngCompr : $"-q:v {lossyQ}"; string codec = format == "webp" ? "-c:v libwebp" : ""; // Specify libwebp to avoid putting all frames into single animated WEBP string args = $"-vsync 0 -r {rate} {inArg} {codec} {compression} {sn} {vf} \"{outDir}/%{Padding.interpFrames}d.{format}\""; await RunFfmpeg(args, framesFile.GetParentDir(), logMode, "error", true); IoUtils.TryDeleteIfExists(linksDir); }
public static async Task ImportImages(string inPath, string outPath, bool alpha, Size size, bool showLog, string format) { if (showLog) { Logger.Log($"Importing images from {new DirectoryInfo(inPath).Name}..."); } Logger.Log($"ImportImages() - Alpha: {alpha} - Size: {size} - Format: {format}", true, false, "ffmpeg"); IoUtils.CreateDir(outPath); string concatFile = Path.Combine(Paths.GetDataPath(), "import-concat-temp.ini"); FfmpegUtils.CreateConcatFile(inPath, concatFile, Filetypes.imagesInterpCompat); string inArg = $"-f concat -safe 0 -i {concatFile.Wrap()}"; string linksDir = Path.Combine(concatFile + Paths.symlinksSuffix); if (Config.GetBool(Config.Key.allowSymlinkEncoding, true) && Symlinks.SymlinksAllowed()) { if (await Symlinks.MakeSymlinksForEncode(concatFile, linksDir, Padding.interpFrames)) { inArg = $"-i \"{linksDir}/%{Padding.interpFrames}d{FfmpegEncode.GetConcatFileExt(concatFile)}\""; } } string sizeStr = (size.Width > 1 && size.Height > 1) ? $"-s {size.Width}x{size.Height}" : ""; string vf = $"-vf {GetPadFilter()}"; string args = $"-r 25 {inArg} {GetImgArgs(format, true, alpha)} {sizeStr} -vsync 0 -start_number 0 {vf} \"{outPath}/%{Padding.inputFrames}d{format}\""; LogMode logMode = IoUtils.GetAmountOfFiles(inPath, false) > 50 ? LogMode.OnlyLastLine : LogMode.Hidden; await RunFfmpeg(args, logMode, "panic"); }
public static async Task CopyImages(string inpath, string outpath, bool showLog) { if (showLog) { Logger.Log($"Loading images from {new DirectoryInfo(inpath).Name}..."); } Directory.CreateDirectory(outpath); Dictionary <string, string> moveFromTo = new Dictionary <string, string>(); int counter = 0; foreach (FileInfo file in IoUtils.GetFileInfosSorted(inpath)) { string newFilename = counter.ToString().PadLeft(Padding.inputFrames, '0') + file.Extension; moveFromTo.Add(file.FullName, Path.Combine(outpath, newFilename)); counter++; } if (Config.GetBool(Config.Key.allowSymlinkEncoding) && Config.GetBool(Config.Key.allowSymlinkImport, true)) { Logger.Log($"Symlink Import enabled, creating symlinks for input frames...", true); Dictionary <string, string> moveFromToSwapped = moveFromTo.ToDictionary(x => x.Value, x => x.Key); // From/To => To/From (Link/Target) await Symlinks.CreateSymlinksParallel(moveFromToSwapped); } else { Logger.Log($"Symlink Import disabled, copying input frames...", true); await Task.Run(async() => { foreach (KeyValuePair <string, string> moveFromToPair in moveFromTo) { File.Copy(moveFromToPair.Key, moveFromToPair.Value); } }); } }
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 SymlinksCheck() { if (!IsWin10Or11()) { return; } bool silent = Config.GetBool("silentDevmodeCheck", true); string ver = Updater.GetInstalledVer().ToString(); bool symlinksAllowed = Symlinks.SymlinksAllowed(); Logger.Log($"SymlinksAllowed: {symlinksAllowed}", true); if (!symlinksAllowed && Config.Get(Config.Key.askedForDevModeVersion) != ver) { if (!silent) { MessageBox.Show("Flowframes will now enable Windows' Developer Mode which is required for video encoding improvements.\n\n" + "This requires administrator privileges once.", "Message"); } Logger.Log($"Trying to enable dev mode.", true); string devmodeBatchPath = Path.Combine(Paths.GetDataPath(), "devmode.bat"); File.WriteAllText(devmodeBatchPath, Properties.Resources.devmode); Process devmodeProc = OsUtils.NewProcess(true); devmodeProc.StartInfo.Arguments = $"/C {devmodeBatchPath.Wrap()}"; devmodeProc.Start(); while (!devmodeProc.HasExited) { await Task.Delay(100); } bool symlinksWorksNow = false; for (int retries = 8; retries > 0; retries--) { symlinksWorksNow = Symlinks.SymlinksAllowed(); if (symlinksWorksNow) { break; } await Task.Delay(500); } if (!symlinksWorksNow) { if (!silent) { MessageBox.Show("Failed to enable developer mode - Perhaps you do not have sufficient privileges.\n\n" + "Without Developer Mode, video encoding will be noticably slower.\n\nYou can still try enabling " + "it manually in the Windows 10 Settings:\nSettings -> Update & security -> For developers -> Developer mode.", "Message"); } Logger.Log("Failed to enable dev mode.", true); Config.Set("askedForDevModeVersion", ver); } else { Logger.Log("Enabled Windows Developer Mode.", silent); } IoUtils.TryDeleteIfExists(devmodeBatchPath); } }