Fix color hue shift when interpolating frames, support high bit depth frames

This commit is contained in:
N00MKRAD 2023-12-22 05:20:22 +01:00
parent 4eb1eac09c
commit 35b8d888d4
4 changed files with 81 additions and 34 deletions

View File

@ -20,6 +20,7 @@ namespace Flowframes
public string outPath;
public string FullOutPath { get; set; } = "";
public AI ai;
public string inPixFmt = "yuv420p";
public Fraction inFps;
public Fraction inFpsDetected;
public Fraction outFps;
@ -54,11 +55,17 @@ namespace Flowframes
inFpsDetected = inFpsDetectedArg;
inFps = inFpsArg;
interpFactor = interpFactorArg;
outFps = inFpsArg * (double)interpFactorArg;
outItsScale = itsScale;
outSettings = outSettingsArg;
model = modelArg;
InitArgs();
}
public void InitArgs ()
{
outFps = inFps * (double)interpFactor;
alpha = false;
stepByStep = false;
@ -204,7 +211,7 @@ namespace Flowframes
if (alpha || forceHqChroma) // Force PNG if alpha is enabled, or output is not 4:2:0 subsampled
{
if(type == FrameType.Both || type == FrameType.Import)
framesExt = ".png";
framesExt = ".tiff";
if (type == FrameType.Both || type == FrameType.Interp)
interpExt = ".png";
@ -212,7 +219,7 @@ namespace Flowframes
else
{
if (type == FrameType.Both || type == FrameType.Import)
framesExt = (Config.GetBool(Config.Key.jpegFrames) ? ".jpg" : ".png");
framesExt = (Config.GetBool(Config.Key.jpegFrames) ? ".jpg" : ".tiff");
if (type == FrameType.Both || type == FrameType.Interp)
interpExt = (Config.GetBool(Config.Key.jpegInterp) ? ".jpg" : ".png");

View File

@ -54,7 +54,7 @@ namespace Flowframes.Forms.Main
// Main Tab
UiUtils.InitCombox(interpFactorCombox, 0);
UiUtils.InitCombox(outSpeedCombox, 0);
UiUtils.InitCombox(aiModel, 2);
// Video Utils
UiUtils.InitCombox(trimCombox, 0);
@ -89,7 +89,7 @@ namespace Flowframes.Forms.Main
UpdateOutputUi();
}
public async void ResetOutputUi ()
public async void ResetOutputUi()
{
comboxOutputEncoder.Items.Clear();
Config.Set(Config.Key.PerformedHwEncCheck, false.ToString());
@ -218,12 +218,23 @@ namespace Flowframes.Forms.Main
public InterpSettings GetCurrentSettings()
{
SetTab(interpOptsTab.Name);
string inPath = inputTbox.Text.Trim();
string outPath = outputTbox.Text.Trim();
AI ai = GetAi();
float interpFactor = interpFactorCombox.GetFloat();
float itsScale = outSpeedCombox.GetInt().Clamp(1, 64);
return new InterpSettings(inPath, outPath, ai, currInFpsDetected, currInFps, interpFactor, itsScale, GetOutputSettings(), GetModel(ai));
var s = new InterpSettings()
{
inPath = inputTbox.Text.Trim(),
outPath = outputTbox.Text.Trim(),
ai = ai,
inFpsDetected = currInFpsDetected,
inFps = currInFps,
interpFactor = interpFactorCombox.GetFloat(),
outItsScale = outSpeedCombox.GetInt().Clamp(1, 64),
outSettings = GetOutputSettings(),
model = GetModel(ai),
};
s.InitArgs();
return s;
}
public InterpSettings UpdateCurrentSettings(InterpSettings settings)
@ -349,7 +360,7 @@ namespace Flowframes.Forms.Main
return ai.FriendlyName + " - " + ai.Description;
}
private void InitializeMainTab ()
private void InitializeMainTab()
{
if (_mainTabInitialized)
return;
@ -416,7 +427,7 @@ namespace Flowframes.Forms.Main
}
}
private void SaveOutputSettings ()
private void SaveOutputSettings()
{
var strings = new List<string>();
if (comboxOutputFormat.Visible) strings.Add(comboxOutputFormat.Text);
@ -692,7 +703,7 @@ namespace Flowframes.Forms.Main
{
if (!_initialized) return;
if(mainTabControl.SelectedTab == interpOptsTab)
if (mainTabControl.SelectedTab == interpOptsTab)
{
aiCombox_SelectedIndexChanged(null, null);
InitializeMainTab();

View File

@ -43,30 +43,56 @@ namespace Flowframes.Media
static string GetImgArgs(string extension, bool includePixFmt = true, bool alpha = false)
{
extension = extension.ToLowerInvariant().Remove(".").Replace("jpeg", "jpg");
string pixFmt = "-pix_fmt rgb24";
extension = extension.Lower().Remove(".").Replace("jpeg", "jpg");
string pixFmt = "yuv420p";
if (Interpolate.currentMediaFile != null && Interpolate.currentMediaFile.VideoStreams.Any())
{
pixFmt = Interpolate.currentMediaFile.VideoStreams.First().PixelFormat.Lower();
}
bool inputHighBitDepth = pixFmt.Contains("p10") || pixFmt.Contains("p16");
bool outputHighBitDepth = Interpolate.currentSettings.outSettings.PixelFormat.ToString().Lower().Contains("p10");
string args = "";
if (extension.Contains("png"))
if (extension == "png")
{
pixFmt = alpha ? "rgba" : "rgb24";
args = $"{pngCompr}";
pixFmt = alpha ? "rgba" : "rgb24"; // PNG can't use YUV so we overwrite it with RGB
args = pngCompr;
}
if (extension.Contains("jpg"))
else if (extension == "jpg")
{
pixFmt = "yuv420p";
// Fallback to YUV420P if not in list of supported formats
if (!new[] { "yuvj420p", "yuvj422p", "yuvj444p", "yuv420p", "yuv422p", "yuv444p" }.Contains(pixFmt))
{
pixFmt = "yuv420p";
}
args = $"-q:v 1";
}
if (extension.Contains("webp"))
else if (extension == "tiff")
{
pixFmt = "yuv420p";
// Fallback to YUV420P if not in list of supported formats
if (!new[] { "rgb24", "rgb48le", "pal8", "rgba", "yuv420p", "yuv422p", "yuv440p", "yuv444p" }.Contains(pixFmt))
{
pixFmt = inputHighBitDepth && outputHighBitDepth ? "rgb48le" : "yuv420p";
}
}
else if (extension == "webp")
{
// Fallback to YUV420P if not in list of supported formats
if (!new[] { "bgra", "yuv420p", "yuva420p" }.Contains(pixFmt))
{
pixFmt = "yuv420p";
}
args = $"-q:v 100";
}
if (includePixFmt)
args += $" -pix_fmt {pixFmt} -color_range full";
args += $" -pix_fmt {pixFmt}";
return args;
}
@ -105,7 +131,7 @@ namespace Flowframes.Media
}
}
public static async Task CopyImages (string inpath, string outpath, bool showLog)
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);
@ -129,14 +155,15 @@ namespace Flowframes.Media
else
{
Logger.Log($"Symlink Import disabled, copying input frames...", true);
await Task.Run(async () => {
await Task.Run(async () =>
{
foreach (KeyValuePair<string, string> moveFromToPair in moveFromTo)
File.Copy(moveFromToPair.Key, moveFromToPair.Value);
});
}
}
static bool AreImagesCompatible (string inpath, int maxHeight)
static bool AreImagesCompatible(string inpath, int maxHeight)
{
NmkdStopwatch sw = new NmkdStopwatch();
string[] validExtensions = Filetypes.imagesInterpCompat; // = new string[] { ".jpg", ".jpeg", ".png" };
@ -310,7 +337,7 @@ namespace Flowframes.Media
await RunFfmpeg(args, LogMode.Hidden);
}
public static async Task GeneratePalette (string inputFile, string outputPath, int colors = 256)
public static async Task GeneratePalette(string inputFile, string outputPath, int colors = 256)
{
string args = $"-i {inputFile.Wrap()} -vf palettegen={colors} {outputPath.Wrap()}";
await Task.Run(() => AvProcess.RunFfmpegSync(args));

View File

@ -58,7 +58,9 @@ namespace Flowframes.Os
l.Add($"inputPath = r'{inputPath}'");
l.Add($"");
if (s.InterpSettings.inputIsFrames || (s.Dedupe && !s.Realtime))
bool loadFrames = s.InterpSettings.inputIsFrames || (s.Dedupe && !s.Realtime);
if (loadFrames)
{
FileInfo[] frames = IoUtils.GetFileInfosSorted(s.InterpSettings.framesFolder, false, "*.*");
string ext = frames.FirstOrDefault().Extension;
@ -85,7 +87,7 @@ namespace Flowframes.Os
l.Add($"clip = clip + firstFrame"); // Add to end (for seamless loop interpolation)
}
l.Add(GetScaleLines(s));
l.Add(GetScaleLines(s, loadFrames));
if (sc)
l.Add($"clip = core.misc.SCDetect(clip=clip, threshold={s.SceneDetectSensitivity.ToStringDot()})"); // Scene detection
@ -96,7 +98,7 @@ namespace Flowframes.Os
if (s.Dedupe && !s.Realtime)
l.Add(GetRedupeLines(s));
l.Add($"clip = vs.core.resize.Bicubic(clip, format=vs.YUV444P16, matrix_s=cMatrix)"); // Convert RGB to YUV
l.Add($"clip = vs.core.resize.Bicubic(clip, format=vs.YUV444P16, matrix_s={(loadFrames ? "'470bg'" : "cMatrix")})"); // Convert RGB to YUV. Always use 470bg if input is frames
if (!s.Dedupe) // Ignore trimming code when using deduping that that already handles trimming in the frame order file
{
@ -131,7 +133,7 @@ namespace Flowframes.Os
return vpyPath;
}
static string GetScaleLines(VsSettings settings)
static string GetScaleLines(VsSettings settings, bool loadFrames)
{
InterpSettings interp = settings.InterpSettings;
bool resize = !interp.ScaledResolution.IsEmpty && interp.ScaledResolution != interp.InputResolution;
@ -141,7 +143,7 @@ namespace Flowframes.Os
s += $"cMatrix = '709'\n";
s += $"\n";
if (!interp.inputIsFrames)
if (!loadFrames)
{
s += "try:\n";
s += " m = clip.get_frame(0).props._Matrix\n";