mirror of
https://github.com/n00mkrad/flowframes.git
synced 2025-12-16 16:37:48 +01:00
Fully fix VFR and deduplication issues esp. with GIFs
This commit is contained in:
@@ -3,22 +3,22 @@
|
|||||||
public class FpsInfo
|
public class FpsInfo
|
||||||
{
|
{
|
||||||
public Fraction Fps { get; set; }
|
public Fraction Fps { get; set; }
|
||||||
public Fraction AverageFps { get; set; }
|
public Fraction SpecifiedFps { get; set; }
|
||||||
public float VfrRatio { get => AverageFps.GetFloat() / Fps.GetFloat(); }
|
public float VfrRatio { get => Fps.GetFloat() / SpecifiedFps.GetFloat(); }
|
||||||
public float VfrRatioInverse { get => Fps.GetFloat() / AverageFps.GetFloat(); }
|
public float VfrRatioInverse { get => SpecifiedFps.GetFloat() / Fps.GetFloat(); }
|
||||||
|
|
||||||
public FpsInfo() { }
|
public FpsInfo() { }
|
||||||
|
|
||||||
public FpsInfo(Fraction fps)
|
public FpsInfo(Fraction fps)
|
||||||
{
|
{
|
||||||
Fps = fps;
|
Fps = fps;
|
||||||
AverageFps = fps;
|
SpecifiedFps = fps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FpsInfo(Fraction fps, Fraction avgFps)
|
public FpsInfo(Fraction fps, Fraction specifiedFps)
|
||||||
{
|
{
|
||||||
Fps = fps;
|
Fps = fps;
|
||||||
AverageFps = avgFps;
|
SpecifiedFps = specifiedFps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,11 +82,11 @@ namespace Flowframes.Main
|
|||||||
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
|
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
|
||||||
bool fpsLimit = maxFps.GetFloat() > 0f && s.outFps.GetFloat() > maxFps.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
|
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);
|
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);
|
string extraArgsOut = await FfmpegEncode.GetFfmpegExportArgsOut(fpsLimit ? maxFps : new Fraction(), extraData, s.outSettings);
|
||||||
|
|
||||||
if (ffplay)
|
if (ffplay)
|
||||||
|
|||||||
@@ -115,9 +115,8 @@ namespace Flowframes.Media
|
|||||||
string mpStr = deDupe ? ((Config.GetInt(Config.Key.mpdecimateMode) == 0) ? mpDecDef : mpDecAggr) : "";
|
string mpStr = deDupe ? ((Config.GetInt(Config.Key.mpdecimateMode) == 0) ? mpDecDef : mpDecAggr) : "";
|
||||||
string filters = FormatUtils.ConcatStrings(new[] { GetPadFilter(), mpStr });
|
string filters = FormatUtils.ConcatStrings(new[] { GetPadFilter(), mpStr });
|
||||||
string vf = filters.Length > 2 ? $"-vf {filters}" : "";
|
string vf = filters.Length > 2 ? $"-vf {filters}" : "";
|
||||||
string rateArg = (rate.GetFloat() > 0) ? $"-r {rate}" : "";
|
string rateArg = (rate.GetFloat() > 0 && !deDupe) ? $" -fps_mode cfr -r {rate}" : "-fps_mode passthrough";
|
||||||
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}\"";
|
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;
|
||||||
LogMode logMode = Interpolate.currentMediaFile.FrameCount > 50 ? LogMode.OnlyLastLine : LogMode.Hidden;
|
|
||||||
await RunFfmpeg(args, logMode, true);
|
await RunFfmpeg(args, logMode, true);
|
||||||
int amount = IoUtils.GetAmountOfFiles(framesDir, false, "*" + format);
|
int amount = IoUtils.GetAmountOfFiles(framesDir, false, "*" + format);
|
||||||
Logger.Log($"Extracted {amount} {(amount == 1 ? "frame" : "frames")} from input.", false, true);
|
Logger.Log($"Extracted {amount} {(amount == 1 ? "frame" : "frames")} from input.", false, true);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Flowframes.IO;
|
|||||||
using Flowframes.MiscUtils;
|
using Flowframes.MiscUtils;
|
||||||
using Flowframes.Os;
|
using Flowframes.Os;
|
||||||
using Flowframes.Properties;
|
using Flowframes.Properties;
|
||||||
|
using ImageMagick;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -69,8 +70,8 @@ namespace Flowframes.Media
|
|||||||
Size res = await GetMediaResolutionCached.GetSizeAsync(path);
|
Size res = await GetMediaResolutionCached.GetSizeAsync(path);
|
||||||
Size sar = SizeFromString(await GetFfprobeInfoAsync(path, showStreams, "sample_aspect_ratio", idx));
|
Size sar = SizeFromString(await GetFfprobeInfoAsync(path, showStreams, "sample_aspect_ratio", idx));
|
||||||
Size dar = SizeFromString(await GetFfprobeInfoAsync(path, showStreams, "display_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;
|
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);
|
VideoStream vStream = new VideoStream(lang, title, codec, codecLong, pixFmt, kbits, res, sar, dar, fps, frameCount);
|
||||||
vStream.Index = idx;
|
vStream.Index = idx;
|
||||||
vStream.IsDefault = def;
|
vStream.IsDefault = def;
|
||||||
@@ -165,7 +166,7 @@ namespace Flowframes.Media
|
|||||||
return streamList;
|
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())
|
if (path.IsConcatFile())
|
||||||
return new FpsInfo(defaultFps);
|
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 fps = streamStr.Split(", ").Where(s => s.Contains(" fps")).First().Trim().Split(' ')[0];
|
||||||
string tbr = streamStr.Split("fps, ")[1].Split(" tbr")[0].Trim();
|
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.SpecifiedFps = new Fraction(tbr); // Change FPS to TBR if they mismatch
|
||||||
info.AverageFps = new Fraction(avgFpsStr);
|
}
|
||||||
|
|
||||||
|
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;
|
return info;
|
||||||
@@ -189,6 +202,18 @@ namespace Flowframes.Media
|
|||||||
return new FpsInfo(await IoUtils.GetVideoFramerate(path));
|
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 = "")
|
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")
|
if (codec == "ssa" || codec == "ass" || codec == "mov_text" || codec == "srt" || codec == "subrip" || codec == "text" || codec == "webvtt")
|
||||||
@@ -540,6 +565,9 @@ namespace Flowframes.Media
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (str.IsEmpty() || str.Length < 3 || !str.Contains(delimiter))
|
||||||
|
return new Size();
|
||||||
|
|
||||||
string[] nums = str.Remove(" ").Trim().Split(delimiter);
|
string[] nums = str.Remove(" ").Trim().Split(delimiter);
|
||||||
return new Size(nums[0].GetInt(), nums[1].GetInt());
|
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
|
l.Add($"clip = core.misc.SCDetect(clip=clip, threshold={s.SceneDetectSensitivity.ToStringDot()})"); // Scene detection
|
||||||
|
|
||||||
Fraction outFps = s.InterpSettings.inFps * s.Factor;
|
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
|
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)
|
if (s.Dedupe && !s.Realtime)
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ namespace Flowframes.Ui
|
|||||||
await PrintResolution(path);
|
await PrintResolution(path);
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
InterpolationProgress.SetPreviewImg(await GetThumbnail(path));
|
InterpolationProgress.SetPreviewImg(await GetThumbnail(path));
|
||||||
// File.WriteAllText("media.json", Interpolate.currentMediaFile.ToJson(true));
|
|
||||||
|
|
||||||
if(AutoEncodeResume.resumeNextRun)
|
if(AutoEncodeResume.resumeNextRun)
|
||||||
Logger.Log($"Incomplete interpolation detected. Flowframes will resume the interpolation.");
|
Logger.Log($"Incomplete interpolation detected. Flowframes will resume the interpolation.");
|
||||||
|
|||||||
Reference in New Issue
Block a user