mirror of
https://github.com/n00mkrad/flowframes.git
synced 2025-12-16 08:27:44 +01:00
Fully fix VFR and deduplication issues esp. with GIFs
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.");
|
||||
|
||||
Reference in New Issue
Block a user