Skip to content

Commit

Permalink
Full VFR handling including FPS downsampling to CFR
Browse files Browse the repository at this point in the history
  • Loading branch information
n00mkrad committed Nov 28, 2024
1 parent 32eeac5 commit defff4f
Show file tree
Hide file tree
Showing 21 changed files with 187 additions and 192 deletions.
2 changes: 2 additions & 0 deletions CodeLegacy/Data/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
{
public class Enums
{
public enum Round { Near, Up, Down }

public class Output
{
public enum Format { Mp4, Mkv, Webm, Mov, Avi, Gif, Images, Realtime };
Expand Down
28 changes: 11 additions & 17 deletions CodeLegacy/Data/Fraction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

namespace Flowframes.Data
{
public struct Fraction
public class Fraction
{
public long Numerator;
public long Denominator;
public long Numerator = 0;
public long Denominator = 1;
public static Fraction Zero = new Fraction(0, 0);

public Fraction() { }

public Fraction(long numerator, long denominator)
{
this.Numerator = numerator;
Expand All @@ -22,18 +24,6 @@ public Fraction(long numerator, long denominator)
}
}

public Fraction(long numerator, Fraction denominator)
{
//divide the numerator by the denominator fraction
this = new Fraction(numerator, 1) / denominator;
}

public Fraction(Fraction numerator, long denominator)
{
//multiply the numerator fraction by 1 over the denominator
this = numerator * new Fraction(1, denominator);
}

public Fraction(Fraction fraction)
{
Numerator = fraction.Numerator;
Expand All @@ -44,7 +34,9 @@ public Fraction(float value)
{
Numerator = (value * 10000f).RoundToInt();
Denominator = 10000;
this = GetReduced();
var reducedFrac = GetReduced();
Numerator = reducedFrac.Numerator;
Denominator = reducedFrac.Denominator;
}

public Fraction(string text)
Expand Down Expand Up @@ -76,7 +68,9 @@ public Fraction(string text)
else
{
// Use float constructor if not a whole number
this = new Fraction(numFloat);
var floatFrac = new Fraction(numFloat);
Numerator = floatFrac.Numerator;
Denominator = floatFrac.Denominator;
}

return;
Expand Down
49 changes: 7 additions & 42 deletions CodeLegacy/Data/InterpSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
using Flowframes.Main;
using Flowframes.MiscUtils;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;

namespace Flowframes
{
Expand All @@ -19,10 +16,11 @@ public class InterpSettings
public string outPath;
public string FullOutPath { get; set; } = "";
public AiInfo ai;
public string inPixFmt = "yuv420p";
public Fraction inFps;
public Fraction inFpsDetected;
public Fraction outFps;
public Fraction outFpsResampled;
public bool FpsResampling => outFpsResampled != null && outFpsResampled.Float > 0.1f && outFpsResampled.Float < outFps.Float;
public float outItsScale;
public float interpFactor;
public OutputSettings outSettings;
Expand Down Expand Up @@ -86,56 +84,23 @@ public Size InterpResolution

public InterpSettings() { }

public InterpSettings(string inPathArg, string outPathArg, AiInfo aiArg, Fraction inFpsDetectedArg, Fraction inFpsArg, float interpFactorArg, float itsScale, OutputSettings outSettingsArg, ModelCollection.ModelInfo modelArg)
{
inPath = inPathArg;
outPath = outPathArg;
ai = aiArg;
inFpsDetected = inFpsDetectedArg;
inFps = inFpsArg;
interpFactor = interpFactorArg;
outItsScale = itsScale;
outSettings = outSettingsArg;
model = modelArg;

InitArgs();
}

public void InitArgs ()
{
outFps = inFps * (double)interpFactor;

outFpsResampled = new Fraction(Config.Get(Config.Key.maxFps));
alpha = false;
stepByStep = false;

framesExt = "";
interpExt = "";

try
{
tempFolder = InterpolateUtils.GetTempFolderLoc(inPath, outPath);
framesFolder = Path.Combine(tempFolder, Paths.framesDir);
interpFolder = Path.Combine(tempFolder, Paths.interpDir);
inputIsFrames = IoUtils.IsPathDirectory(inPath);
}
catch
{
Logger.Log("Tried to create InterpSettings struct without an inpath. Can't set tempFolder, framesFolder and interpFolder.", true);
tempFolder = "";
framesFolder = "";
interpFolder = "";
inputIsFrames = false;
}

_inputResolution = new Size(0, 0);

SetPaths(inPath);
RefreshExtensions(ai: ai);
}

public void UpdatePaths (string inPathArg, string outPathArg)
private void SetPaths (string inputPath)
{
inPath = inPathArg;
outPath = outPathArg;
inPath = inputPath;
outPath = (Config.GetInt("outFolderLoc") == 0) ? inputPath.GetParentDir() : Config.Get("custOutDir").Trim();
tempFolder = InterpolateUtils.GetTempFolderLoc(inPath, outPath);
framesFolder = Path.Combine(tempFolder, Paths.framesDir);
interpFolder = Path.Combine(tempFolder, Paths.interpDir);
Expand Down
33 changes: 3 additions & 30 deletions CodeLegacy/Data/MediaFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class MediaFile
public string Format;
public string Title;
public string Language;
public Fraction? InputRate = null;
public Fraction InputRate;
public long DurationMs;
public int StreamCount;
public int TotalKbits;
Expand All @@ -42,6 +42,8 @@ public class MediaFile
public bool IsVfr = false;
public List<float> InputTimestamps = new List<float>();
public List<float> InputTimestampDurations = new List<float>();
public List<float> OutputTimestamps = new List<float>();
public List<int> OutputFrameIndexes = null;

public int FileCount = 1;
public int FrameCount { get { return VideoStreams.Count > 0 ? VideoStreams[0].FrameCount : 0; } }
Expand Down Expand Up @@ -140,35 +142,6 @@ private async Task LoadFormatInfo(string path)
TotalKbits = (await GetVideoInfo.GetFfprobeInfoAsync(path, GetVideoInfo.FfprobeMode.ShowFormat, "bit_rate")).GetInt() / 1000;
}

public List<float> GetResampledTimestamps(List<float> timestamps, double factor)
{
int originalCount = timestamps.Count;
int newCount = (int)Math.Round(originalCount * factor);
List<float> resampledTimestamps = new List<float>();

for (int i = 0; i < newCount; i++)
{
double x = i / factor;

if (x >= originalCount - 1)
{
resampledTimestamps.Add(timestamps[originalCount - 1]);
}
else
{
int index = (int)Math.Floor(x);
double fraction = x - index;
float startTime = timestamps[index];
float endTime = timestamps[index + 1];

float interpolatedTime = (float)(startTime + (endTime - startTime) * fraction);
resampledTimestamps.Add(interpolatedTime);
}
}

return resampledTimestamps;
}

public string GetName()
{
if (IsDirectory)
Expand Down
1 change: 1 addition & 0 deletions CodeLegacy/Flowframes.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@
<Compile Include="Media\GetMediaResolutionCached.cs" />
<Compile Include="Media\GetVideoInfo.cs" />
<Compile Include="Media\HwEncCheck.cs" />
<Compile Include="Media\TimestampUtils.cs" />
<Compile Include="MiscUtils\Benchmarker.cs" />
<Compile Include="MiscUtils\FrameRename.cs" />
<Compile Include="MiscUtils\ModelDownloadFormUtils.cs" />
Expand Down
3 changes: 0 additions & 3 deletions CodeLegacy/Forms/BatchForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,6 @@ public async Task LoadDroppedPaths (string[] droppedPaths, bool start = false)
Logger.Log($"BatchForm: Dropped path: '{path}'", true);

InterpSettings current = Program.mainForm.GetCurrentSettings();
string outDir = (Config.GetInt("outFolderLoc") == 0) ? path.GetParentDir() : Config.Get("custOutDir").Trim();
current.UpdatePaths(path, outDir);

current.inFpsDetected = await IoUtils.GetFpsFolderOrVideo(path);
current.inFps = current.inFpsDetected;

Expand Down
23 changes: 0 additions & 23 deletions CodeLegacy/Forms/Main/Form1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,29 +321,6 @@ public InterpSettings GetCurrentSettings()
return s;
}

public InterpSettings UpdateCurrentSettings(InterpSettings settings)
{
SetTab(interpOptsTab.Name);
string inPath = inputTbox.Text.Trim();

if (settings.inPath != inPath) // If path changed, get new instance
{
Logger.Log($"settings.inPath ({settings.inPath}) mismatches GUI inPath ({settings.inPath} - Returning fresh instance", true);
return GetCurrentSettings();
}

settings.inPath = inPath;
settings.ai = GetAi();
settings.inFpsDetected = currInFpsDetected;
settings.inFps = currInFps;
settings.interpFactor = interpFactorCombox.GetFloat();
settings.outFps = settings.inFps * settings.interpFactor;
settings.outSettings = GetOutputSettings();
settings.model = GetModel(GetAi());

return settings;
}

public void LoadBatchEntry(InterpSettings entry)
{
inputTbox.Text = entry.inPath;
Expand Down
4 changes: 1 addition & 3 deletions CodeLegacy/IO/IoUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -597,9 +597,7 @@ public static bool RenameFile(string path, string newName, bool alsoRenameExtens
public static async Task<string> GetCurrentExportFilename(bool fpsLimit, bool isImgSeq = false, bool includeExt = true)
{
InterpSettings curr = Interpolate.currentSettings;
string max = Config.Get(Config.Key.maxFps);
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
float fps = fpsLimit ? maxFps.Float : curr.outFps.Float;
float fps = fpsLimit ? curr.outFpsResampled.Float : curr.outFps.Float;

Size outRes = curr.OutputResolution; // TODO: Replace with EncodeResolution once implemented?
string pattern = Config.Get(Config.Key.exportNamePattern);
Expand Down
18 changes: 7 additions & 11 deletions CodeLegacy/Magick/Dedupe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,27 +264,21 @@ public static async Task CreateDupesFile(string framesPath, string ext)

public static async Task CreateFramesFileVideo(string videoPath, bool loop)
{
if (!Directory.Exists(Interpolate.currentSettings.tempFolder))
Directory.CreateDirectory(Interpolate.currentSettings.tempFolder);

Directory.CreateDirectory(Interpolate.currentSettings.tempFolder);
Process ffmpeg = OsUtils.NewProcess(true);
string baseCmd = $"/C cd /D {Path.Combine(IO.Paths.GetPkgPath(), IO.Paths.audioVideoDir).Wrap()}";
string mpDec = FfmpegCommands.GetMpdecimate(wrap: false); // FfmpegCommands.GetMpdecimate((int)FfmpegCommands.MpDecSensitivity.Normal, false);
ffmpeg.StartInfo.Arguments = $"{baseCmd} & ffmpeg -loglevel debug -y -i {videoPath.Wrap()} -fps_mode vfr -vf {mpDec} -f null NUL 2>&1 | findstr keep_count:";
List<string> ffmpegOutputLines = (await Task.Run(() => OsUtils.GetProcStdOut(ffmpeg, true))).SplitIntoLines().Where(l => l.IsNotEmpty()).ToList();
var ffmpegOutputLines = (await Task.Run(() => OsUtils.GetProcStdOut(ffmpeg, true))).SplitIntoLines();

var frames = new Dictionary<int, List<int>>();
var frameNums = new List<int>();
int lastKeepFrameNum = 0;

for (int frameIdx = 0; frameIdx < ffmpegOutputLines.Count; frameIdx++)
for (int frameIdx = 0; frameIdx < ffmpegOutputLines.Length; frameIdx++)
{
string line = ffmpegOutputLines[frameIdx];
bool drop = frameIdx != 0 && line.Contains(" drop ") && !line.Contains(" keep ");
// Console.WriteLine($"[Frame {frameIdx.ToString().PadLeft(6, '0')}] {(drop ? "DROP" : "KEEP")}");
// frameNums.Add(lastKeepFrameNum);

if (!drop)
if (line.Contains(" keep pts:"))
{
if (!frames.ContainsKey(frameIdx) || frames[frameIdx] == null)
{
Expand All @@ -293,14 +287,16 @@ public static async Task CreateFramesFileVideo(string videoPath, bool loop)

lastKeepFrameNum = frameIdx;
}
else
else if (line.Contains(" drop pts:"))
{
frames[lastKeepFrameNum].Add(frameIdx);
}
}

var inputFrames = new List<int>(frames.Keys);

Logger.Log($"Dedupe: Kept {inputFrames.Count}/{ffmpegOutputLines.Length} frames", true);

if (loop)
{
inputFrames.Add(inputFrames.First());
Expand Down
Loading

0 comments on commit defff4f

Please sign in to comment.