Fully fix VFR and deduplication issues esp. with GIFs

This commit is contained in:
N00MKRAD
2023-12-28 02:59:29 +01:00
parent 29e1eb172b
commit 5e4b540d1c
6 changed files with 50 additions and 18 deletions

View File

@@ -3,22 +3,22 @@
public class FpsInfo
{
public Fraction Fps { get; set; }
public Fraction AverageFps { get; set; }
public float VfrRatio { get => AverageFps.GetFloat() / Fps.GetFloat(); }
public float VfrRatioInverse { get => Fps.GetFloat() / AverageFps.GetFloat(); }
public Fraction SpecifiedFps { get; set; }
public float VfrRatio { get => Fps.GetFloat() / SpecifiedFps.GetFloat(); }
public float VfrRatioInverse { get => SpecifiedFps.GetFloat() / Fps.GetFloat(); }
public FpsInfo() { }
public FpsInfo(Fraction fps)
{
Fps = fps;
AverageFps = fps;
SpecifiedFps = fps;
}
public FpsInfo(Fraction fps, Fraction avgFps)
public FpsInfo(Fraction fps, Fraction specifiedFps)
{
Fps = fps;
AverageFps = avgFps;
SpecifiedFps = specifiedFps;
}
}
}

View File

@@ -82,11 +82,11 @@ namespace Flowframes.Main
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
bool fpsLimit = maxFps.GetFloat() > 0f && s.outFps.GetFloat() > maxFps.GetFloat();
Logger.Log($"VFR Ratio: {I.currentMediaFile.VideoStreams.First().FpsInfo.VfrRatio}");
// Logger.Log($"VFR Ratio: {I.currentMediaFile.VideoStreams.First().FpsInfo.VfrRatio} ({I.currentMediaFile.VideoStreams.First().FpsInfo.Fps} FPS Specified, {I.currentMediaFile.VideoStreams.First().FpsInfo.SpecifiedFps} FPS Avg)");
bool gifInput = I.currentMediaFile.Format.Upper() == "GIF"; // If input is GIF, we don't need to check the color space etc
VidExtraData extraData = gifInput ? new VidExtraData() : await FfmpegCommands.GetVidExtraInfo(s.inPath);
string extraArgsIn = await FfmpegEncode.GetFfmpegExportArgsIn(s.outFps, s.outItsScale * I.currentMediaFile.VideoStreams.First().FpsInfo.VfrRatioInverse);
string extraArgsIn = await FfmpegEncode.GetFfmpegExportArgsIn(s.outFps, s.outItsScale);
string extraArgsOut = await FfmpegEncode.GetFfmpegExportArgsOut(fpsLimit ? maxFps : new Fraction(), extraData, s.outSettings);
if (ffplay)

View File

@@ -115,9 +115,8 @@ namespace Flowframes.Media
string mpStr = deDupe ? ((Config.GetInt(Config.Key.mpdecimateMode) == 0) ? mpDecDef : mpDecAggr) : "";
string filters = FormatUtils.ConcatStrings(new[] { GetPadFilter(), mpStr });
string vf = filters.Length > 2 ? $"-vf {filters}" : "";
string rateArg = (rate.GetFloat() > 0) ? $"-r {rate}" : "";
string args = $"{GetTrimArg(true)} -i {inputFile.Wrap()} {GetImgArgs(format, true, alpha)} -fps_mode cfr {rateArg} -frame_pts 1 {vf} {sizeStr} {GetTrimArg(false)} \"{framesDir}/%{Padding.inputFrames}d{format}\"";
LogMode logMode = Interpolate.currentMediaFile.FrameCount > 50 ? LogMode.OnlyLastLine : LogMode.Hidden;
string rateArg = (rate.GetFloat() > 0 && !deDupe) ? $" -fps_mode cfr -r {rate}" : "-fps_mode passthrough";
string args = $"{GetTrimArg(true)} -itsscale {Interpolate.currentMediaFile.VideoStreams.First().FpsInfo.VfrRatio} -i {inputFile.Wrap()} {GetImgArgs(format, true, alpha)} {rateArg} -frame_pts 1 {vf} {sizeStr} {GetTrimArg(false)} \"{framesDir}/%{Padding.inputFrames}d{format}\""; LogMode logMode = Interpolate.currentMediaFile.FrameCount > 50 ? LogMode.OnlyLastLine : LogMode.Hidden;
await RunFfmpeg(args, logMode, true);
int amount = IoUtils.GetAmountOfFiles(framesDir, false, "*" + format);
Logger.Log($"Extracted {amount} {(amount == 1 ? "frame" : "frames")} from input.", false, true);

View File

@@ -4,6 +4,7 @@ using Flowframes.IO;
using Flowframes.MiscUtils;
using Flowframes.Os;
using Flowframes.Properties;
using ImageMagick;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -69,8 +70,8 @@ namespace Flowframes.Media
Size res = await GetMediaResolutionCached.GetSizeAsync(path);
Size sar = SizeFromString(await GetFfprobeInfoAsync(path, showStreams, "sample_aspect_ratio", idx));
Size dar = SizeFromString(await GetFfprobeInfoAsync(path, showStreams, "display_aspect_ratio", idx));
FpsInfo fps = await GetFps(path, streamStr, idx, (Fraction)defaultFps);
int frameCount = countFrames ? await GetFrameCountCached.GetFrameCountAsync(path) : 0;
FpsInfo fps = await GetFps(path, streamStr, idx, (Fraction)defaultFps, frameCount);
VideoStream vStream = new VideoStream(lang, title, codec, codecLong, pixFmt, kbits, res, sar, dar, fps, frameCount);
vStream.Index = idx;
vStream.IsDefault = def;
@@ -165,7 +166,7 @@ namespace Flowframes.Media
return streamList;
}
private static async Task<FpsInfo> GetFps (string path, string streamStr, int streamIdx, Fraction defaultFps)
private static async Task<FpsInfo> GetFps(string path, string streamStr, int streamIdx, Fraction defaultFps, int frameCount)
{
if (path.IsConcatFile())
return new FpsInfo(defaultFps);
@@ -174,13 +175,25 @@ namespace Flowframes.Media
{
string fps = streamStr.Split(", ").Where(s => s.Contains(" fps")).First().Trim().Split(' ')[0];
string tbr = streamStr.Split("fps, ")[1].Split(" tbr")[0].Trim();
long durationMs = Interpolate.currentMediaFile.DurationMs;
float fpsCalc = (float)frameCount / (durationMs / 1000f);
fpsCalc = (float)Math.Round(fpsCalc, 5);
var info = new FpsInfo(new Fraction(tbr));
var info = new FpsInfo(new Fraction(fps.GetFloat())); // Set both true FPS and average FPS to this number for now
if(tbr != fps)
Logger.Log($"FPS: {fps} - TBR: {tbr} - Est. FPS: {fpsCalc.ToString("0.#####")}", true);
if (tbr != fps)
{
string avgFpsStr = await GetFfprobeInfoAsync(path, showStreams, "avg_frame_rate", streamIdx);
info.AverageFps = new Fraction(avgFpsStr);
info.SpecifiedFps = new Fraction(tbr); // Change FPS to TBR if they mismatch
}
float fpsEstTolerance = GetFpsEstimationTolerance(durationMs);
if (Math.Abs(fps.GetFloat() - fpsCalc) > fpsEstTolerance)
{
Logger.Log($"Detected FPS {fps} is not within tolerance (+-{fpsEstTolerance}) of calculated FPS ({fpsCalc}), using estimated FPS.", true);
info.Fps = new Fraction(fpsCalc); // Change true FPS to the estimated FPS if the estimate does not match the specified FPS
}
return info;
@@ -189,6 +202,18 @@ namespace Flowframes.Media
return new FpsInfo(await IoUtils.GetVideoFramerate(path));
}
private static float GetFpsEstimationTolerance (long videoDurationMs)
{
if (videoDurationMs < 300) return 5.0f;
if (videoDurationMs < 1000) return 2.5f;
if (videoDurationMs < 2500) return 1.0f;
if (videoDurationMs < 5000) return 0.75f;
if (videoDurationMs < 10000) return 0.5f;
if (videoDurationMs < 20000) return 0.25f;
return 0.1f;
}
public static async Task<bool> IsSubtitleBitmapBased(string path, int streamIndex, string codec = "")
{
if (codec == "ssa" || codec == "ass" || codec == "mov_text" || codec == "srt" || codec == "subrip" || codec == "text" || codec == "webvtt")
@@ -540,6 +565,9 @@ namespace Flowframes.Media
{
try
{
if (str.IsEmpty() || str.Length < 3 || !str.Contains(delimiter))
return new Size();
string[] nums = str.Remove(" ").Trim().Split(delimiter);
return new Size(nums[0].GetInt(), nums[1].GetInt());
}

View File

@@ -93,6 +93,12 @@ namespace Flowframes.Os
l.Add($"clip = core.misc.SCDetect(clip=clip, threshold={s.SceneDetectSensitivity.ToStringDot()})"); // Scene detection
Fraction outFps = s.InterpSettings.inFps * s.Factor;
if (!loadFrames)
{
outFps = Interpolate.currentMediaFile.VideoStreams.First().FpsInfo.SpecifiedFps * s.Factor;
}
l.Add($"clip = core.rife.RIFE(clip, fps_num={outFps.Numerator}, fps_den={outFps.Denominator}, model_path={mdlPath}, gpu_id={s.GpuId}, gpu_thread={s.GpuThreads}, tta={s.Tta}, uhd={s.Uhd}, sc={sc})"); // Interpolate
if (s.Dedupe && !s.Realtime)

View File

@@ -58,7 +58,6 @@ namespace Flowframes.Ui
await PrintResolution(path);
await Task.Delay(10);
InterpolationProgress.SetPreviewImg(await GetThumbnail(path));
// File.WriteAllText("media.json", Interpolate.currentMediaFile.ToJson(true));
if(AutoEncodeResume.resumeNextRun)
Logger.Log($"Incomplete interpolation detected. Flowframes will resume the interpolation.");