Fully implement image sequence export with NCNN VS, rework stuff

This commit is contained in:
n00mkrad
2023-02-20 19:30:23 +01:00
parent 8e5c3a618c
commit 59ac292a34
13 changed files with 146 additions and 99 deletions

View File

@@ -18,6 +18,7 @@
public class Quality
{
public enum Common { Lossless, VeryHigh, High, Medium, Low, VeryLow, Custom }
public enum JpegWebm { ImgMax, ImgHigh, ImgMed, ImgLow, ImgLowest }
public enum ProResProfile { Proxy, Lt, Standard, Hq, Quad4, Quad4Xq }
public enum GifColors { Max256, High128, Medium64, Low32, VeryLow16 }
}

View File

@@ -176,7 +176,7 @@ namespace Flowframes
bool alphaModel = model.SupportsAlpha;
bool pngOutput = outSettings.Encoder == Enums.Encoding.Encoder.Png;
bool gifOutput = outSettings.Encoder == Enums.Encoding.Encoder.Gif;
bool proResAlpha = outSettings.Encoder == Enums.Encoding.Encoder.ProResKs && Config.GetInt(Config.Key.proResProfile) > 3; // TODO: CHECK IF WORKS WITH NEW ENCODING SETTINGS CODE
bool proResAlpha = outSettings.Encoder == Enums.Encoding.Encoder.ProResKs && OutputUtils.AlphaFormats.Contains(outSettings.PixelFormat);
bool outputSupportsAlpha = pngOutput || gifOutput || proResAlpha;
string ext = inputIsFrames ? Path.GetExtension(IoUtils.GetFilesSorted(inPath).First()).ToLowerInvariant() : Path.GetExtension(inPath).ToLowerInvariant();
alpha = (alphaModel && outputSupportsAlpha && (ext == ".gif" || ext == ".png" || ext == ".apng" || ext == ".mov"));
@@ -194,8 +194,8 @@ namespace Flowframes
public void RefreshExtensions(FrameType type = FrameType.Both)
{
bool pngOutput = outSettings.Encoder == Enums.Encoding.Encoder.Png;
bool aviHqChroma = outSettings.Format == Enums.Output.Format.Avi && outSettings.PixelFormat != Enums.Encoding.PixelFormat.Yuv420P; // TODO: CHECK IF WORKS WITH NEW ENCODING SETTINGS CODE
bool proresHqChroma = outSettings.Encoder == Enums.Encoding.Encoder.ProResKs && Config.GetInt(Config.Key.proResProfile) > 3; // TODO: CHECK IF WORKS WITH NEW ENCODING SETTINGS CODE
bool aviHqChroma = outSettings.Format == Enums.Output.Format.Avi && OutputUtils.AlphaFormats.Contains(outSettings.PixelFormat);
bool proresHqChroma = outSettings.Encoder == Enums.Encoding.Encoder.ProResKs && OutputUtils.AlphaFormats.Contains(outSettings.PixelFormat);
bool forceHqChroma = pngOutput || aviHqChroma || proresHqChroma;

View File

@@ -70,6 +70,11 @@ namespace Flowframes.Data
{ Enums.Encoding.Quality.GifColors.Medium64.ToString(), "Medium (64)" },
{ Enums.Encoding.Quality.GifColors.Low32.ToString(), "Low (32)" },
{ Enums.Encoding.Quality.GifColors.VeryLow16.ToString(), "Very Low (16)" },
{ Enums.Encoding.Quality.JpegWebm.ImgMax.ToString(), "Maximum" },
{ Enums.Encoding.Quality.JpegWebm.ImgHigh.ToString(), "High" },
{ Enums.Encoding.Quality.JpegWebm.ImgMed.ToString(), "Medium" },
{ Enums.Encoding.Quality.JpegWebm.ImgLow.ToString(), "Low" },
{ Enums.Encoding.Quality.JpegWebm.ImgLowest.ToString(), "Lowest" },
};
}
}

View File

@@ -372,6 +372,14 @@ namespace Flowframes
return s.ToLowerInvariant();
}
public static string Upper(this string s)
{
if (s == null)
return s;
return s.ToUpperInvariant();
}
public static EncoderInfoVideo GetInfo (this Enums.Encoding.Encoder enc)
{
return OutputUtils.GetEncoderInfoVideo(enc);

View File

@@ -379,6 +379,7 @@ namespace Flowframes
AiProcessSuspend.Reset();
if (Interpolate.currentSettings.outSettings.Format == Enums.Output.Format.Realtime)
{
await Interpolate.Realtime();

View File

@@ -259,15 +259,6 @@ namespace Flowframes.IO
if (key == Key.jpegFrames) return WriteDefault(key, "True");
// Video Export
if (key == Key.minOutVidLength) return WriteDefault(key, "5");
if (key == Key.h264Crf) return WriteDefault(key, "20");
if (key == Key.h265Crf) return WriteDefault(key, "24");
if (key == Key.av1Crf) return WriteDefault(key, "28");
if (key == Key.vp9Crf) return WriteDefault(key, "28");
if (key == Key.proResProfile) return WriteDefault(key, "2");
if (key == Key.aviCodec) return WriteDefault(key, "ffv1");
if (key == Key.imgSeqFormat) return WriteDefault(key, "PNG");
if (key == Key.aviColors) return WriteDefault(key, "yuv420p");
if (key == Key.gifColors) return WriteDefault(key, "128 (High)");
if (key == Key.gifDitherType) return WriteDefault(key, "bayer");
if (key == Key.minVidLength) return WriteDefault(key, "5");
// AI
@@ -312,9 +303,6 @@ namespace Flowframes.IO
autoEncMode,
autoEncSafeBufferCuda,
autoEncSafeBufferNcnn,
av1Crf,
aviCodec,
aviColors,
clearLogOnInput,
cmdDebugMode,
compressedPyVersion,
@@ -334,12 +322,7 @@ namespace Flowframes.IO
ffprobeFrameCount,
fixOutputDuration,
frameOrderDebug,
gifColors,
gifDitherType,
h264Crf,
h265Crf,
imgSeqFormat,
imgSeqQuality,
imgSeqSampleCount,
jpegFrames,
jpegInterp,
@@ -358,13 +341,10 @@ namespace Flowframes.IO
maxVidHeight,
minOutVidLength,
minVidLength,
mp4Enc,
mpdecimateMode,
ncnnGpus,
ncnnThreads,
opusBitrate,
pixFmt,
proResProfile,
processingMode,
rifeCudaBufferSize,
rifeCudaFp16,
@@ -379,7 +359,6 @@ namespace Flowframes.IO
tempFolderLoc,
torchGpus,
uhdThresh,
vp9Crf,
vsRtShowOsd,
vsUseLsmash
}

View File

@@ -500,12 +500,11 @@ namespace Flowframes.IO
/// <summary>
/// Add ".old" suffix to an existing file to avoid it getting overwritten. If one already exists, it will be ".old.old" etc.
/// </summary>
public static void RenameExistingFile(string path)
public static void RenameExistingFileOrDir(string path)
{
if (!File.Exists(path))
return;
try
{
if (File.Exists(path))
{
string ext = Path.GetExtension(path);
string renamedPath = path;
@@ -515,9 +514,19 @@ namespace Flowframes.IO
File.Move(path, renamedPath);
}
else if (Directory.Exists(path))
{
string renamedPath = path;
while (Directory.Exists(renamedPath))
renamedPath = renamedPath + ".old";
Directory.Move(path, renamedPath);
}
}
catch(Exception e)
{
Logger.Log($"RenameExistingFile: Failed to rename '{path}': {e.Message}", true);
Logger.Log($"RenameExistingFileOrDir: Failed to rename '{path}': {e.Message}", true);
}
}

View File

@@ -24,7 +24,7 @@ namespace Flowframes.Main
public static async Task ExportFrames(string path, string outFolder, OutputSettings exportSettings, bool stepByStep)
{
if(Config.GetInt(Config.Key.sceneChangeFillMode) == 1)
if (Config.GetInt(Config.Key.sceneChangeFillMode) == 1)
{
string frameFile = Path.Combine(I.currentSettings.tempFolder, Paths.GetFrameOrderFilename(I.currentSettings.interpFactor));
await Blend.BlendSceneChanges(frameFile);
@@ -97,17 +97,25 @@ namespace Flowframes.Main
}
else
{
s.FullOutPath = Path.Combine(s.outPath, await IoUtils.GetCurrentExportFilename(fpsLimit, true));
IoUtils.RenameExistingFile(s.FullOutPath);
bool imageSequence = s.outSettings.Encoder.GetInfo().IsImageSequence;
s.FullOutPath = Path.Combine(s.outPath, await IoUtils.GetCurrentExportFilename(fpsLimit, !imageSequence));
IoUtils.RenameExistingFileOrDir(s.FullOutPath);
if (imageSequence)
{
Directory.CreateDirectory(s.FullOutPath);
s.FullOutPath += $"/%{Padding.interpFrames}d.{s.outSettings.Encoder.GetInfo().OverideExtension}";
}
return $"{extraArgsIn} -i pipe: {extraArgsOut} {encArgs} {s.FullOutPath.Wrap()}";
}
}
static async Task ExportImageSequence (string framesPath, bool stepByStep)
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();
Enums.Encoding.Encoder desiredFormat = I.currentSettings.outSettings.Encoder;
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.currentSettings.outFps.GetFloat() > maxFps.GetFloat();
@@ -118,54 +126,25 @@ namespace Flowframes.Main
{
string outputFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(false, false));
IoUtils.RenameExistingFolder(outputFolderPath);
Logger.Log($"Exporting {desiredFormat.ToUpper()} frames to '{Path.GetFileName(outputFolderPath)}'...");
Logger.Log($"Exporting {desiredFormat.ToString().Upper()} frames to '{Path.GetFileName(outputFolderPath)}'...");
if (desiredFormat.ToUpper() == availableFormat.ToUpper()) // Move if frames are already in the desired format
if (desiredFormat.GetInfo().OverideExtension.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.currentSettings.outFps, new Fraction(), desiredFormat, GetImgSeqQ(desiredFormat));
await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 1, I.currentSettings.outFps, new Fraction(), desiredFormat, OutputUtils.GetImgSeqQ(I.currentSettings.outSettings));
}
if (fpsLimit)
{
string outputFolderPath = Path.Combine(I.currentSettings.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.currentSettings.outFps, maxFps, desiredFormat, GetImgSeqQ(desiredFormat));
Logger.Log($"Exporting {desiredFormat.ToString().Upper()} frames to '{Path.GetFileName(outputFolderPath)}' (Resampled to {maxFps} FPS)...");
await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 1, I.currentSettings.outFps, maxFps, desiredFormat, OutputUtils.GetImgSeqQ(I.currentSettings.outSettings));
}
if (!stepByStep)
await IoUtils.DeleteContentsOfDirAsync(I.currentSettings.interpFolder);
}
static int GetImgSeqQ (string format)
{
if(format.ToLowerInvariant() == "jpg" || format.ToLowerInvariant() == "jpeg")
{
switch (Config.GetInt(Config.Key.imgSeqQuality))
{
case 0: return 1;
case 1: return 3;
case 2: return 5;
case 3: return 11;
case 4: return 31;
}
}
if (format.ToLowerInvariant() == "webp")
{
switch (Config.GetInt(Config.Key.imgSeqQuality))
{
case 0: return 100;
case 1: return 90;
case 2: return 75;
case 3: return 40;
case 4: return 0;
}
}
return 1;
}
static async Task CopyOutputFrames(string framesPath, string framesFile, string outputFolderPath, int startNo, bool dontMove, bool hideLog)
{
IoUtils.CreateDir(outputFolderPath);
@@ -221,7 +200,7 @@ namespace Flowframes.Main
}
}
public static async Task MuxPipedVideo (string inputVideo, string outputPath)
public static async Task MuxPipedVideo(string inputVideo, string outputPath)
{
await MuxOutputVideo(inputVideo, Path.Combine(outputPath, outputPath));
await Loop(outputPath, await GetLoopTimes());
@@ -237,7 +216,7 @@ namespace Flowframes.Main
NmkdStopwatch sw = new NmkdStopwatch();
if(!isBackup)
if (!isBackup)
Program.mainForm.SetStatus("Merging video chunks...");
try
@@ -283,10 +262,10 @@ namespace Flowframes.Main
await FfmpegCommands.ConcatVideos(framesFile, outPath, -1, !isBackup);
if(!isBackup || (isBackup && Config.GetInt(Config.Key.autoEncBackupMode) == 2)) // Mux if no backup, or if backup AND muxing is enabled for backups
if (!isBackup || (isBackup && Config.GetInt(Config.Key.autoEncBackupMode) == 2)) // Mux if no backup, or if backup AND muxing is enabled for backups
await MuxOutputVideo(I.currentSettings.inPath, outPath, isBackup, !isBackup);
if(!isBackup)
if (!isBackup)
await Loop(outPath, await GetLoopTimes());
}
@@ -310,7 +289,7 @@ namespace Flowframes.Main
if (settings.Encoder.GetInfo().IsImageSequence) // Image Sequence output mode, not video
{
string desiredFormat = Config.Get(Config.Key.imgSeqFormat);
string desiredFormat = settings.Encoder.GetInfo().OverideExtension;
string availableFormat = Path.GetExtension(IoUtils.GetFilesSorted(interpDir)[0]).Remove(".").ToUpper();
if (!dontEncodeFullFpsVid)
@@ -318,20 +297,20 @@ namespace Flowframes.Main
string outFolderPath = Path.Combine(I.currentSettings.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
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.currentSettings.outFps, new Fraction(), desiredFormat, GetImgSeqQ(desiredFormat), AvProcess.LogMode.Hidden);
await FfmpegEncode.FramesToFrames(concatFile, outFolderPath, startNo, I.currentSettings.outFps, new Fraction(), settings.Encoder, OutputUtils.GetImgSeqQ(settings), AvProcess.LogMode.Hidden);
}
if (fpsLimit)
{
string outputFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(true, false));
int startNumber = IoUtils.GetAmountOfFiles(outputFolderPath, false) + 1;
await FfmpegEncode.FramesToFrames(concatFile, outputFolderPath, startNumber, I.currentSettings.outFps, maxFps, desiredFormat, GetImgSeqQ(desiredFormat), AvProcess.LogMode.Hidden);
await FfmpegEncode.FramesToFrames(concatFile, outputFolderPath, startNumber, I.currentSettings.outFps, maxFps, settings.Encoder, OutputUtils.GetImgSeqQ(settings), AvProcess.LogMode.Hidden);
}
}
else
@@ -384,7 +363,7 @@ namespace Flowframes.Main
if (!Config.GetBool(Config.Key.keepAudio) && !Config.GetBool(Config.Key.keepAudio))
return;
if(showLog)
if (showLog)
Program.mainForm.SetStatus("Muxing audio/subtitles into video...");
if (I.currentSettings.inputIsFrames)

View File

@@ -61,10 +61,15 @@ namespace Flowframes
if (!currentlyUsingAutoEnc)
{
if (currentSettings.ai.Piped)
{
if(!currentSettings.outSettings.Encoder.GetInfo().IsImageSequence)
await Export.MuxPipedVideo(currentSettings.inPath, currentSettings.FullOutPath);
}
else
{
await Export.ExportFrames(currentSettings.interpFolder, currentSettings.outPath, currentSettings.outSettings, false);
}
}
if (!AutoEncodeResume.resumeNextRun && Config.GetBool(Config.Key.keepTempFolder) && IoUtils.GetAmountOfFiles(currentSettings.framesFolder, false) > 0)
await Task.Run(async () => { await FrameRename.Unrename(); });

View File

@@ -47,7 +47,7 @@ namespace Flowframes
if(showLog)
Logger.Log($"Merging videos...", false, Logger.GetLastLine().Contains("frame"));
IoUtils.RenameExistingFile(outPath);
IoUtils.RenameExistingFileOrDir(outPath);
string loopStr = (looptimes > 0) ? $"-stream_loop {looptimes}" : "";
string vfrFilename = Path.GetFileName(concatFile);
string args = $" {loopStr} -f concat -i {vfrFilename} -fps_mode cfr -c copy -movflags +faststart -fflags +genpts {outPath.Wrap()}";
@@ -60,7 +60,7 @@ namespace Flowframes
string ext = Path.GetExtension(inputFile);
string loopSuffix = Config.Get(Config.Key.exportNamePatternLoop).Replace("[LOOPS]", $"{times}").Replace("[PLAYS]", $"{times + 1}");
string outpath = $"{pathNoExt}{loopSuffix}{ext}";
IoUtils.RenameExistingFile(outpath);
IoUtils.RenameExistingFileOrDir(outpath);
string args = $" -stream_loop {times} -i {inputFile.Wrap()} -c copy {outpath.Wrap()}";
await RunFfmpeg(args, LogMode.Hidden);

View File

@@ -20,7 +20,7 @@ namespace Flowframes.Media
if (logMode != LogMode.Hidden)
Logger.Log((resampleFps.GetFloat() <= 0) ? "Encoding video..." : $"Encoding video resampled to {resampleFps.GetString()} FPS...");
IoUtils.RenameExistingFile(outPath);
IoUtils.RenameExistingFileOrDir(outPath);
Directory.CreateDirectory(outPath.GetParentDir());
string[] encArgs = Utils.GetEncArgs(settings, (Interpolate.currentSettings.ScaledResolution.IsEmpty ? Interpolate.currentSettings.InputResolution : Interpolate.currentSettings.ScaledResolution), Interpolate.currentSettings.outFps.GetFloat());
@@ -106,12 +106,11 @@ namespace Flowframes.Media
return Path.GetExtension(File.ReadAllLines(concatFilePath).FirstOrDefault().Split('\'')[1]);
}
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)
public static async Task FramesToFrames(string framesFile, string outDir, int startNo, Fraction fps, Fraction resampleFps, Enums.Encoding.Encoder format = Enums.Encoding.Encoder.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.ToLowerInvariant();
if (Config.GetBool(Config.Key.allowSymlinkEncoding, true) && Symlinks.SymlinksAllowed())
{
@@ -122,9 +121,9 @@ namespace Flowframes.Media
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 = $"-r {rate} {inArg} {codec} {compression} {sn} {vf} -fps_mode passthrough \"{outDir}/%{Padding.interpFrames}d.{format}\"";
string compression = format == Enums.Encoding.Encoder.Png ? pngCompr : $"-q:v {lossyQ}";
string codec = format == Enums.Encoding.Encoder.Webp ? "-c:v libwebp" : ""; // Specify libwebp to avoid putting all frames into single animated WEBP
string args = $"-r {rate} {inArg} {codec} {compression} {sn} {vf} -fps_mode passthrough \"{outDir}/%{Padding.interpFrames}d.{format.GetInfo().OverideExtension}\"";
await RunFfmpeg(args, framesFile.GetParentDir(), logMode, "error", true);
IoUtils.TryDeleteIfExists(linksDir);
}

View File

@@ -255,7 +255,8 @@ namespace Flowframes.Media
if (enc == Encoder.ProResKs)
{
args.Add($"-profile:v {Config.GetInt(Config.Key.proResProfile)}");
var profile = ParseUtils.GetEnum<Quality.ProResProfile>(settings.Quality, true, Strings.VideoQuality);
args.Add($"-profile:v {OutputUtils.ProresProfiles[profile]}");
}
if (enc == Encoder.Gif)
@@ -263,6 +264,18 @@ namespace Flowframes.Media
args.Add("-gifflags -offsetting");
}
if (enc == Encoder.Jpeg)
{
var qualityLevel = ParseUtils.GetEnum<Quality.JpegWebm>(settings.Quality, true, Strings.VideoQuality);
args.Add($"-q:v {OutputUtils.JpegQuality[qualityLevel]}");
}
if (enc == Encoder.Webp)
{
var qualityLevel = ParseUtils.GetEnum<Quality.JpegWebm>(settings.Quality, true, Strings.VideoQuality);
args.Add($"-q:v {OutputUtils.WebpQuality[qualityLevel]}");
}
return new string[] { string.Join(" ", args) };
}

View File

@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Win32Interop.Enums;
using static Flowframes.Data.Enums.Encoding;
using Encoder = Flowframes.Data.Enums.Encoding.Encoder;
using PixFmt = Flowframes.Data.Enums.Encoding.PixelFormat;
@@ -10,6 +11,8 @@ namespace Flowframes.MiscUtils
{
internal class OutputUtils
{
public static readonly List<PixFmt> AlphaFormats = new List<PixFmt> { PixFmt.Rgba, PixFmt.Yuva420P, PixFmt.Yuva444P10Le };
public static EncoderInfoVideo GetEncoderInfoVideo(Encoder encoder)
{
if (encoder == Encoder.X264)
@@ -195,6 +198,8 @@ namespace Flowframes.MiscUtils
Codec = Codec.Jpeg,
Name = "mjpeg",
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuv422P, PixFmt.Yuv444P },
QualityLevels = ParseUtils.GetEnumStrings<Quality.JpegWebm>(),
QualityDefault = (int)Quality.JpegWebm.ImgHigh,
IsImageSequence = true,
OverideExtension = "jpg",
};
@@ -207,6 +212,8 @@ namespace Flowframes.MiscUtils
Codec = Codec.Webp,
Name = "libwebp",
PixelFormats = new List<PixFmt>() { PixFmt.Yuv420P, PixFmt.Yuva420P },
QualityLevels = ParseUtils.GetEnumStrings<Quality.JpegWebm>(),
QualityDefault = (int)Quality.JpegWebm.ImgHigh,
IsImageSequence = true,
OverideExtension = "webp",
};
@@ -282,5 +289,46 @@ namespace Flowframes.MiscUtils
{ Quality.Common.Low, 32 },
{ Quality.Common.VeryLow, 40 },
};
public static Dictionary<Quality.ProResProfile, string> ProresProfiles = new Dictionary<Quality.ProResProfile, string>
{
{ Quality.ProResProfile.Proxy, "proxy" },
{ Quality.ProResProfile.Lt, "proxy" },
{ Quality.ProResProfile.Standard, "standard" },
{ Quality.ProResProfile.Hq, "hq" },
{ Quality.ProResProfile.Quad4, "4444" },
{ Quality.ProResProfile.Quad4Xq, "4444xq" },
};
public static Dictionary<Quality.JpegWebm, int> JpegQuality = new Dictionary<Quality.JpegWebm, int>
{
{ Quality.JpegWebm.ImgMax, 1 },
{ Quality.JpegWebm.ImgHigh, 3 },
{ Quality.JpegWebm.ImgMed, 5 },
{ Quality.JpegWebm.ImgLow, 11 },
{ Quality.JpegWebm.ImgLowest, 31 },
};
public static Dictionary<Quality.JpegWebm, int> WebpQuality = new Dictionary<Quality.JpegWebm, int>
{
{ Quality.JpegWebm.ImgMax, 100 },
{ Quality.JpegWebm.ImgHigh, 90 },
{ Quality.JpegWebm.ImgMed, 75 },
{ Quality.JpegWebm.ImgLow, 40 },
{ Quality.JpegWebm.ImgLowest, 0 },
};
public static int GetImgSeqQ (OutputSettings settings)
{
var qualityLevel = ParseUtils.GetEnum<Quality.JpegWebm>(settings.Quality, true, Strings.VideoQuality);
if (settings.Encoder == Encoder.Jpeg)
return JpegQuality[qualityLevel];
if (settings.Encoder == Encoder.Webp)
return WebpQuality[qualityLevel];
return -1;
}
}
}