Support for preserving VFR timings and video rotation, better duration readout

This commit is contained in:
N00MKRAD
2024-11-07 15:10:36 +01:00
parent 6f0b3b39a3
commit b89ce780b4
12 changed files with 673 additions and 865 deletions

View File

@@ -8,7 +8,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Stream = Flowframes.Data.Streams.Stream;
@@ -40,6 +39,8 @@ namespace Flowframes.Data
public long CreationTime;
public bool Initialized = false;
public bool SequenceInitialized = false;
public bool IsVfr = false;
public List<float> InputTimestamps = new List<float>();
public int FileCount = 1;
public int FrameCount { get { return VideoStreams.Count > 0 ? VideoStreams[0].FrameCount : 0; } }
@@ -103,7 +104,7 @@ namespace Flowframes.Data
await InitializeSequence();
await LoadFormatInfo(ImportPath);
AllStreams = await FfmpegUtils.GetStreams(ImportPath, progressBar, StreamCount, InputRate, countFrames);
AllStreams = await FfmpegUtils.GetStreams(ImportPath, progressBar, StreamCount, InputRate, countFrames, this);
VideoStreams = AllStreams.Where(x => x.Type == Stream.StreamType.Video).Select(x => (VideoStream)x).ToList();
AudioStreams = AllStreams.Where(x => x.Type == Stream.StreamType.Audio).Select(x => (AudioStream)x).ToList();
SubtitleStreams = AllStreams.Where(x => x.Type == Stream.StreamType.Subtitle).Select(x => (SubtitleStream)x).ToList();
@@ -123,11 +124,41 @@ namespace Flowframes.Data
{
Title = await GetVideoInfo.GetFfprobeInfoAsync(path, GetVideoInfo.FfprobeMode.ShowFormat, "TAG:title");
Language = await GetVideoInfo.GetFfprobeInfoAsync(path, GetVideoInfo.FfprobeMode.ShowFormat, "TAG:language");
DurationMs = (await FfmpegCommands.GetDurationMs(path));
DurationMs = await FfmpegCommands.GetDurationMs(path, this);
FfmpegCommands.CheckVfr(path, this);
StreamCount = await FfmpegUtils.GetStreamCount(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)

View File

@@ -25,9 +25,14 @@ namespace Flowframes.Data
public ModelInfo() { }
public string GetUiString()
public string GetUiString(bool addRecommendedStr = false)
{
return $"{Name} - {Desc}{(SupportsAlpha ? " (Supports Transparency)" : "")}{(FixedFactors.Count() > 0 ? $" ({GetFactorsString()})" : "")}{(IsDefault ? " (Recommended)" : "")}";
string s = $"{Name} - {Desc}{(SupportsAlpha ? " - Transparency Support" : "")}{(FixedFactors.Count() > 0 ? $" ({GetFactorsString()})" : "")}";
if(addRecommendedStr && IsDefault)
s += " (Recommended)";
return s;
}
public string GetFactorsString ()

View File

@@ -15,6 +15,9 @@ namespace Flowframes.Data
// Aspect Ratio
public string displayRatio = "";
// Rotation
public int Rotation = 0;
private readonly string[] validColorSpaces = new string[] { "bt709", "bt470m", "bt470bg", "smpte170m", "smpte240m", "linear", "log100",
"log316", "iec61966-2-4", "bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", "smpte2084", "smpte428", "arib-std-b67" };
@@ -23,37 +26,44 @@ namespace Flowframes.Data
public VidExtraData(string ffprobeOutput)
{
string[] lines = ffprobeOutput.SplitIntoLines();
if (!Config.GetBool(Config.Key.keepColorSpace, true))
return;
bool keepColorSpace = Config.GetBool(Config.Key.keepColorSpace, true);
foreach (string line in lines)
{
if (line.Contains("color_range"))
if(line.StartsWith("rotation="))
{
colorRange = line.Split('=').LastOrDefault();
Rotation = line.Split('=').LastOrDefault().GetInt();
continue;
}
if (line.Contains("color_space"))
if (keepColorSpace)
{
colorSpace = line.Split('=').LastOrDefault();
continue;
if (line.StartsWith("color_range"))
{
colorRange = line.Split('=').LastOrDefault().Lower();
continue;
}
if (line.StartsWith("color_space"))
{
colorSpace = line.Split('=').LastOrDefault().Lower();
continue;
}
if (line.StartsWith("color_transfer"))
{
colorTransfer = line.Split('=').LastOrDefault().Lower();
continue;
}
if (line.StartsWith("color_primaries"))
{
colorPrimaries = line.Split('=').LastOrDefault().Lower();
continue;
}
}
if (line.Contains("color_transfer"))
{
colorTransfer = line.Split('=').LastOrDefault();
continue;
}
if (line.Contains("color_primaries"))
{
colorPrimaries = line.Split('=').LastOrDefault();
continue;
}
if (line.Contains("display_aspect_ratio") && Config.GetBool(Config.Key.keepAspectRatio, true))
if (line.StartsWith("display_aspect_ratio") && Config.GetBool(Config.Key.keepAspectRatio, true))
{
displayRatio = line.Split('=').LastOrDefault();
continue;
@@ -76,7 +86,7 @@ namespace Flowframes.Data
}
else
{
colorTransfer = colorTransfer.Replace("bt470bg", "gamma28").Replace("bt470m", "gamma28"); // https://forum.videohelp.com/threads/394596-Color-Matrix
colorTransfer = colorTransfer.Replace("bt470bg", "gamma28").Replace("bt470m", "gamma28"); // https://forum.videohelp.com/threads/394596-Color-Matrix
}
if (!validColorSpaces.Contains(colorPrimaries.Trim()))
@@ -86,24 +96,7 @@ namespace Flowframes.Data
}
}
public bool HasAnyValues ()
{
if (!string.IsNullOrWhiteSpace(colorSpace))
return true;
if (!string.IsNullOrWhiteSpace(colorRange))
return true;
if (!string.IsNullOrWhiteSpace(colorTransfer))
return true;
if (!string.IsNullOrWhiteSpace(colorPrimaries))
return true;
return false;
}
public bool HasAllValues()
public bool HasAllColorValues()
{
if (string.IsNullOrWhiteSpace(colorSpace))
return false;

View File

@@ -17,13 +17,17 @@ namespace Flowframes
{
public static class ExtensionMethods
{
public static string TrimNumbers(this string s, bool allowDotComma = false)
/// <summary> Remove anything from a string that is not a number, optionally allowing scientific notation (<paramref name="allowScientific"/>) </summary>
public static string TrimNumbers(this string s, bool allowDotComma = false, bool allowScientific = false)
{
if (!allowDotComma)
s = Regex.Replace(s, "[^0-9]", "");
else
s = Regex.Replace(s, "[^.,0-9]", "");
return s.Trim();
if (s == null)
return s;
// string og = s;
string regex = $@"[^{(allowDotComma ? ".," : "")}0-9\-{(allowScientific ? "e" : "")}]";
s = Regex.Replace(s, regex, "").Trim();
// Logger.Log($"Trimmed {og} -> {s} - Pattern: {regex}", true);
return s;
}
public static int GetInt(this TextBox textbox)
@@ -43,7 +47,8 @@ namespace Flowframes
try
{
return int.Parse(str.TrimNumbers());
str = str.TrimNumbers(allowDotComma: false);
return int.Parse(str);
}
catch (Exception e)
{
@@ -92,11 +97,11 @@ namespace Flowframes
public static float GetFloat(this string str)
{
if (str == null || str.Length < 1)
if (str.Length < 1 || str == null)
return 0f;
string num = str.TrimNumbers(true).Replace(",", ".");
float.TryParse(num, out float value);
float.TryParse(num, NumberStyles.Any, CultureInfo.InvariantCulture, out float value);
return value;
}

View File

@@ -86,7 +86,7 @@ namespace Flowframes.Main
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);
string extraArgsIn = await FfmpegEncode.GetFfmpegExportArgsIn(s.outFps, s.outItsScale, extraData.Rotation);
string extraArgsOut = await FfmpegEncode.GetFfmpegExportArgsOut(fpsLimit ? maxFps : new Fraction(), extraData, s.outSettings);
if(s.outSettings.Encoder == Enums.Encoding.Encoder.Exr)
@@ -94,7 +94,6 @@ namespace Flowframes.Main
extraArgsIn += " -color_trc bt709 -color_primaries bt709 -colorspace bt709";
}
if (ffplay)
{
bool useNutPipe = true; // TODO: Make this bool a config flag
@@ -393,5 +392,32 @@ namespace Flowframes.Main
Logger.Log("MergeAudio() Exception: " + e.Message, true);
}
}
public static void MuxTimestamps (string vidPath)
{
Logger.Log($"Muxing timestamps for '{vidPath}'", hidden: true);
var resampledTs = I.currentMediaFile.GetResampledTimestamps(I.currentMediaFile.InputTimestamps, I.currentSettings.interpFactor);
var tsFileLines = new List<string>() { "# timecode format v2" };
for (int i = 0; i < (resampledTs.Count - 1); i++)
{
tsFileLines.Add((resampledTs[i] * 1000f).ToString("0.000000"));
}
string tsFile = Path.Combine(Paths.GetSessionDataPath(), "ts.out.txt");
File.WriteAllLines(tsFile, tsFileLines);
string outPath = Path.ChangeExtension(vidPath, ".tmp.mkv");
string args = $"mkvmerge --output {outPath.Wrap()} --timestamps \"0:{tsFile}\" {vidPath.Wrap()}";
var outputMux = NUtilsTemp.OsUtils.RunCommand($"cd /D {Path.Combine(Paths.GetPkgPath(), Paths.audioVideoDir).Wrap()} && {args}");
Logger.Log(outputMux, hidden: true);
// Check if file exists and is not too small (min. 80% of input file)
if (File.Exists(outPath) && ((double)new FileInfo(outPath).Length / (double)new FileInfo(vidPath).Length) > 0.8d)
{
Logger.Log($"Deleting '{vidPath}' and moving '{outPath}' to '{vidPath}'", hidden: true);
File.Delete(vidPath);
File.Move(outPath, vidPath);
}
}
}
}

View File

@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using static Flowframes.AvProcess;
using Utils = Flowframes.Media.FfmpegUtils;
using I = Flowframes.Interpolate;
using Flowframes.Main;
namespace Flowframes.Media
{
@@ -59,6 +60,11 @@ namespace Flowframes.Media
string metaArg = (isMkv && meta) ? "-map 1:t?" : ""; // https://reddit.com/r/ffmpeg/comments/fw4jnh/how_to_make_ffmpeg_keep_attached_images_in_mkv_as/
string shortestArg = shortest ? "-shortest" : "";
if (I.currentMediaFile.IsVfr)
{
Export.MuxTimestamps(tempPath);
}
if (QuickSettingsTab.trimEnabled)
{
string otherStreamsName = $"otherStreams{containerExt}";

View File

@@ -9,6 +9,7 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using static Flowframes.AvProcess;
using System.Drawing.Imaging;
namespace Flowframes
{
@@ -18,8 +19,8 @@ namespace Flowframes
public static string pngCompr = "-compression_level 3";
public enum MpDecSensitivity { Normal = 4, High = 20, VeryHigh = 32, Extreme = 40 }
public static string GetMpdecimate (int sensitivity = 4, bool wrap = true)
public static string GetMpdecimate(int sensitivity = 4, bool wrap = true)
{
string mpd = $"mpdecimate=hi=64*1024:lo=64*{sensitivity}:frac=1.0";
return wrap ? mpd.Wrap() : mpd;
@@ -33,7 +34,7 @@ namespace Flowframes
return wrap ? mpd.Wrap() : mpd;
}
public static int GetModulo ()
public static int GetModulo()
{
if (Interpolate.currentSettings.ai.NameInternal == Implementations.flavrCuda.NameInternal)
return 8;
@@ -41,7 +42,7 @@ namespace Flowframes
return Interpolate.currentSettings.outSettings.Encoder.GetInfo().Modulo;
}
public static string GetPadFilter ()
public static string GetPadFilter()
{
int mod = GetModulo();
@@ -55,7 +56,7 @@ namespace Flowframes
{
Logger.Log($"ConcatVideos('{Path.GetFileName(concatFile)}', '{outPath}', {looptimes})", true, false, "ffmpeg");
if(showLog)
if (showLog)
Logger.Log($"Merging videos...", false, Logger.GetLastLine().Contains("frame"));
IoUtils.RenameExistingFileOrDir(outPath);
@@ -91,32 +92,35 @@ namespace Flowframes
DeleteSource(inputFile);
}
public static async Task<long> GetDurationMs(string inputFile, bool demuxInsteadOfPacketTs = false)
public static async Task<long> GetDurationMs(string inputFile, MediaFile mediaFile, bool demuxInsteadOfPacketTs = false, bool allowDurationFromMetadata = true)
{
Logger.Log($"GetDuration({inputFile}) - Reading duration by checking metadata.", true, false, "ffmpeg");
string argsMeta = $"ffprobe -v quiet -show_streams -select_streams v:0 -show_entries stream=duration {inputFile.Wrap()}";
var outputLinesMeta = NUtilsTemp.OsUtils.RunCommand($"cd /D {GetAvDir().Wrap()} && {argsMeta}").SplitIntoLines();
foreach (string line in outputLinesMeta.Where(l => l.MatchesWildcard("*?=?*")))
if (allowDurationFromMetadata)
{
var split = line.Split('=');
string key = split[0];
string value = split[1];
Logger.Log($"GetDuration({inputFile}) - Reading duration by checking metadata.", true, false, "ffmpeg");
string argsMeta = $"ffprobe -v quiet -show_streams -select_streams v:0 -show_entries stream=duration {inputFile.Wrap()}";
var outputLinesMeta = NUtilsTemp.OsUtils.RunCommand($"cd /D {GetAvDir().Wrap()} && {argsMeta}").SplitIntoLines();
if(value.Contains("N/A"))
continue;
foreach (string line in outputLinesMeta.Where(l => l.MatchesWildcard("*?=?*")))
{
var split = line.Split('=');
string key = split[0];
string value = split[1];
if (key == "duration")
{
return (long)TimeSpan.FromSeconds(value.GetFloat()).TotalMilliseconds;
}
else if (key == "TAG:DURATION")
{
string[] tsSplit = value.Split(':');
int hours = tsSplit[0].GetInt();
int minutes = tsSplit[1].GetInt();
float seconds = tsSplit[2].GetFloat();
return (long)TimeSpan.FromHours(hours).Add(TimeSpan.FromMinutes(minutes)).Add(TimeSpan.FromSeconds(seconds)).TotalMilliseconds;
if (value.Contains("N/A"))
continue;
if (key == "duration")
{
return (long)TimeSpan.FromSeconds(value.GetFloat()).TotalMilliseconds;
}
else if (key == "TAG:DURATION")
{
string[] tsSplit = value.Split(':');
int hours = tsSplit[0].GetInt();
int minutes = tsSplit[1].GetInt();
float seconds = tsSplit[2].GetFloat();
return (long)TimeSpan.FromHours(hours).Add(TimeSpan.FromMinutes(minutes)).Add(TimeSpan.FromSeconds(seconds)).TotalMilliseconds;
}
}
}
@@ -135,17 +139,81 @@ namespace Flowframes
else
{
Logger.Log($"GetDuration({inputFile}) - Reading duration using packet timestamps.", true, false, "ffmpeg");
string argsPackets = $"ffprobe -v error -select_streams v:0 -show_packets -show_entries packet=dts_time -of csv=p=0 {inputFile.Wrap()}";
string argsPackets = $"ffprobe -v error -select_streams v:0 -show_packets -show_entries packet=pts_time -of csv=p=0 {inputFile.Wrap()}";
var outputLinesPackets = NUtilsTemp.OsUtils.RunCommand($"cd /D {GetAvDir().Wrap()} && {argsPackets}").SplitIntoLines().Where(l => l.IsNotEmpty()).ToList();
if (outputLinesPackets == null || outputLinesPackets.Count == 0)
return 0;
CheckVfr(inputFile, mediaFile);
string lastTimestamp = outputLinesPackets.Last().Split('=').Last();
return (long)TimeSpan.FromSeconds(lastTimestamp.GetFloat()).TotalMilliseconds;
}
}
public static void CheckVfr (string inputFile, MediaFile mediaFile, List<string> outputLinesPackets = null)
{
if (mediaFile.InputTimestamps.Any())
return;
Logger.Log($"Checking frame timing...", true, false, "ffmpeg");
if(outputLinesPackets == null)
{
string argsPackets = $"ffprobe -v error -select_streams v:0 -show_packets -show_entries packet=pts_time -read_intervals \"%+120\" -of csv=p=0 {inputFile.Wrap()}";
outputLinesPackets = NUtilsTemp.OsUtils.RunCommand($"cd /D {GetAvDir().Wrap()} && {argsPackets}").SplitIntoLines().Where(l => l.IsNotEmpty()).ToList();
}
var timestamps = new List<float>();
var timestampDurations = new List<float>();
var timestampDurationsRes = new List<float>();
foreach (string line in outputLinesPackets)
{
timestamps.Add(line.GetFloat());
}
timestamps = timestamps.OrderBy(x => x).ToList();
for (int i = 1; i < (timestamps.Count - 1); i++)
{
float diff = Math.Abs(timestamps[i] - timestamps[i - 1]);
timestampDurations.Add(diff);
// if (diff > 0)
// {
// Console.WriteLine($"Duration of {timestamps.Count}: {diff * 1000f} ms ({1f / diff} FPS)");
// }
}
//
// var tsResampleTest = Interpolate.currentMediaFile.ResampleTimestamps(timestamps, 2.5f);
//
// for (int i = 1; i < (tsResampleTest.Count - 1); i++)
// {
// float diff = Math.Abs(tsResampleTest[i] - tsResampleTest[i - 1]);
// timestampDurationsRes.Add(diff);
//
// if (diff > 0)
// {
// Console.WriteLine($"Resampled duration of {tsResampleTest.Count}: {diff * 1000f} ms ({1f / diff} FPS)");
// }
// }
mediaFile.InputTimestamps = new List<float>(timestamps);
float maxDeviationMs = (timestampDurations.Max() - timestampDurations.Min()) * 1000f;
float maxDeviationPercent = ((timestampDurations.Max() / timestampDurations.Min()) * 100f) - 100;
// float maxDeviationMsResampled = (timestampDurationsRes.Max() - timestampDurationsRes.Min()) * 1000f;
Logger.Log($"Min ts duration: {timestampDurations.Min() * 1000f} ms - Max ts duration: {timestampDurations.Max() * 1000f} ms - Biggest deviation: {maxDeviationMs.ToString("0.##")} ms", hidden: true);
// Logger.Log($"Resampled - Min ts duration: {timestampDurationsRes.Min() * 1000f} ms - Max ts duration: {timestampDurationsRes.Max() * 1000f} ms - Biggest deviation: {maxDeviationMsResampled.ToString("0.##")} ms", hidden: true);
if (maxDeviationPercent > 20f)
{
Logger.Log($"Max timestamp deviation is {maxDeviationPercent.ToString("0.##")}% or {maxDeviationMs} ms - Assuming VFR input!", hidden: true);
mediaFile.IsVfr = true;
}
}
public static async Task<Fraction> GetFramerate(string inputFile, bool preferFfmpeg = false)
{
Logger.Log($"GetFramerate(inputFile = '{inputFile}', preferFfmpeg = {preferFfmpeg})", true, false, "ffmpeg");
@@ -180,7 +248,7 @@ namespace Flowframes
}
}
}
catch(Exception ffmpegEx)
catch (Exception ffmpegEx)
{
Logger.Log("GetFramerate ffmpeg Error: " + ffmpegEx.Message, true, false);
}
@@ -207,7 +275,7 @@ namespace Flowframes
string args = $" -v panic -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 {inputFile.Wrap()}";
string[] outputLines = GetFfprobeOutput(args).SplitIntoLines();
foreach(string line in outputLines)
foreach (string line in outputLines)
{
if (!line.Contains("x") || line.Trim().Length < 3)
continue;

View File

@@ -43,12 +43,17 @@ namespace Flowframes.Media
IoUtils.TryDeleteIfExists(linksDir);
}
public static async Task<string> GetFfmpegExportArgsIn(Fraction fps, float itsScale)
public static async Task<string> GetFfmpegExportArgsIn(Fraction fps, float itsScale, int rotation = 0)
{
var args = new List<string>();
fps = fps / new Fraction(itsScale);
args.Add($"-r {fps}");
if(rotation != 0)
{
args.Add($"-display_rotation {rotation}");
}
return string.Join(" ", args);
}
@@ -62,7 +67,7 @@ namespace Flowframes.Media
if (resampleFps.Float >= 0.1f)
filters.Add($"fps={resampleFps}");
if (Config.GetBool(Config.Key.keepColorSpace) && extraData.HasAllValues())
if (Config.GetBool(Config.Key.keepColorSpace) && extraData.HasAllColorValues())
{
Logger.Log($"Using color data: Space {extraData.colorSpace}; Primaries {extraData.colorPrimaries}; Transfer {extraData.colorTransfer}; Range {extraData.colorRange}", true, false, "ffmpeg");
extraArgs.Add($"-colorspace {extraData.colorSpace} -color_primaries {extraData.colorPrimaries} -color_trc {extraData.colorTransfer} -color_range:v {extraData.colorRange.Wrap()}");

View File

@@ -37,7 +37,7 @@ namespace Flowframes.Media
return output.SplitIntoLines().Where(x => x.MatchesWildcard("*Stream #0:*: *: *")).Count();
}
public static async Task<List<Stream>> GetStreams(string path, bool progressBar, int streamCount, Fraction? defaultFps, bool countFrames)
public static async Task<List<Stream>> GetStreams(string path, bool progressBar, int streamCount, Fraction? defaultFps, bool countFrames, MediaFile mediaFile = null)
{
List<Stream> streamList = new List<Stream>();
@@ -71,10 +71,8 @@ namespace Flowframes.Media
Size sar = SizeFromString(await GetFfprobeInfoAsync(path, showStreams, "sample_aspect_ratio", idx));
Size dar = SizeFromString(await GetFfprobeInfoAsync(path, showStreams, "display_aspect_ratio", idx));
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;
FpsInfo fps = await GetFps(path, streamStr, idx, (Fraction)defaultFps, frameCount, allowFpsOverride: !mediaFile.IsVfr);
VideoStream vStream = new VideoStream(lang, title, codec, codecLong, pixFmt, kbits, res, sar, dar, fps, frameCount) { Index = idx, IsDefault = def };
Logger.Log($"Added video stream: {vStream}", true);
streamList.Add(vStream);
continue;
@@ -166,7 +164,7 @@ namespace Flowframes.Media
return streamList;
}
private static async Task<FpsInfo> GetFps(string path, string streamStr, int streamIdx, Fraction defaultFps, int frameCount)
private static async Task<FpsInfo> GetFps(string path, string streamStr, int streamIdx, Fraction defaultFps, int frameCount, bool allowFpsOverride = false)
{
if (path.IsConcatFile())
return new FpsInfo(defaultFps);
@@ -194,7 +192,7 @@ namespace Flowframes.Media
float fpsEstTolerance = GetFpsEstimationTolerance(durationMs);
if (Math.Abs(fps.Float - calculatedFps) > fpsEstTolerance)
if (allowFpsOverride && Math.Abs(fps.Float - calculatedFps) > fpsEstTolerance)
{
Logger.Log($"Detected FPS {fps} is not within tolerance (+-{fpsEstTolerance}) of calculated FPS ({calculatedFps}), using estimated FPS.", true);
info.Fps = new Fraction(calculatedFps); // Change true FPS to the estimated FPS if the estimate does not match the specified FPS
@@ -206,7 +204,7 @@ namespace Flowframes.Media
return new FpsInfo(await IoUtils.GetVideoFramerate(path));
}
private static float GetFpsEstimationTolerance (long videoDurationMs)
private static float GetFpsEstimationTolerance(long videoDurationMs)
{
if (videoDurationMs < 300) return 5.0f;
if (videoDurationMs < 1000) return 2.5f;

View File

@@ -374,7 +374,7 @@ namespace Flowframes.Os
IoUtils.CreateDir(outPath);
Process rifeNcnnVs = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd());
string avDir = Path.Combine(Paths.GetPkgPath(), Paths.audioVideoDir);
string pipedTargetArgs = $"{Path.Combine(avDir, "ffmpeg").Wrap()} -y {await Export.GetPipedFfmpegCmd(rt)}";
string pipedTargetArgs = $"{Path.Combine(avDir, "ffmpeg").Wrap()} -loglevel warning -stats -y {await Export.GetPipedFfmpegCmd(rt)}";
string pkgDir = Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnnVs.PkgDir);
int gpuId = Config.Get(Config.Key.ncnnGpus).Split(',')[0].GetInt();

View File

@@ -46,7 +46,7 @@ namespace Flowframes.Os
long srcTrimStartFrame = trim ? (long)(Math.Round(FormatUtils.TimestampToMs(QuickSettingsTab.trimStart) / 1000f * s.InterpSettings.inFps.Float)) : 0;
long srcTrimEndFrame = trim && QuickSettingsTab.doTrimEnd ? (long)(Math.Round(FormatUtils.TimestampToMs(QuickSettingsTab.trimEnd) / 1000f * s.InterpSettings.inFps.Float)) - 1 : frameCount - 1;
if(trim)
if (trim)
frameCount = srcTrimEndFrame - srcTrimStartFrame;
int endDupeCount = s.Factor.RoundToInt() - 1;
@@ -78,7 +78,7 @@ namespace Flowframes.Os
}
if (trim)
l.Add($"clip = clip.std.Trim({srcTrimStartFrame}, {srcTrimEndFrame})");
l.Add($"clip = clip.std.Trim({srcTrimStartFrame}, {srcTrimEndFrame}) # Trim");
l.Add($"");
@@ -100,7 +100,9 @@ namespace Flowframes.Os
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
Fraction factorFrac = new Fraction(s.Factor);
string interpStr = Interpolate.currentMediaFile.IsVfr ? $"factor_num={factorFrac.Numerator}, factor_den={factorFrac.Denominator}" : $"fps_num={outFps.Numerator}, fps_den={outFps.Denominator}";
l.Add($"clip = core.rife.RIFE(clip, {interpStr}, 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)
l.Add(GetRedupeLines(s));
@@ -113,21 +115,23 @@ namespace Flowframes.Os
{
if (s.Loop)
{
l.Add($"clip = clip.std.Trim(0, {targetFrameCountMatchDuration - 1})"); // -1 because we use index, not count
l.Add($"clip = clip.std.Trim(0, {targetFrameCountMatchDuration - 1}) # Trim, loop enabled"); // -1 because we use index, not count
}
else
{
if (!s.MatchDuration)
l.Add($"clip = clip.std.Trim(0, {targetFrameCountTrue - 1})"); // -1 because we use index, not count
l.Add($"clip = clip.std.Trim(0, {targetFrameCountTrue - 1}) # Trim, loop disabled, duration matching disabled"); // -1 because we use index, not count
}
}
if(s.Realtime && s.Loop)
if (s.Realtime && s.Loop)
l.AddRange(new List<string> { $"clip = clip.std.Loop(0)", "" }); // Can't loop piped video so we loop it before piping it to ffplay
if(s.Realtime && s.Osd)
if (s.Realtime && s.Osd)
l.Add(GetOsdLines());
l.Add(Debugger.IsAttached ? "clip = core.text.Text(clip, str(len(clip)), alignment=4)" : "");
l.Add(Debugger.IsAttached ? "clip = core.text.FrameNum(clip, alignment=1)" : "");
l.Add($"clip.set_output()"); // Set output
l.Add("");
@@ -206,7 +210,7 @@ namespace Flowframes.Os
s += " for i in frameList:\n";
s += " reorderedClip = reorderedClip + clip[i]\n";
s += "\n";
s += "clip = reorderedClip.std.Trim(1, reorderedClip.num_frames - 1)\n";
s += "clip = reorderedClip.std.Trim(1, reorderedClip.num_frames - 1) # Dedupe trim\n";
s += Debugger.IsAttached ? "clip = core.text.FrameNum(clip, alignment=4)\n" : "";
s += "\n";
@@ -226,7 +230,7 @@ namespace Flowframes.Os
s += " if(i < clip.num_frames):\n";
s += " reorderedClip = reorderedClip + clip[i]\n";
s += "\n";
s += "clip = reorderedClip.std.Trim(1, reorderedClip.num_frames - 1)\n";
s += "clip = reorderedClip.std.Trim(1, reorderedClip.num_frames - 1) # Redupe trim\n";
s += Debugger.IsAttached ? "clip = core.text.FrameNum(clip, alignment=1)\n" : "";
s += "\n";
@@ -275,9 +279,9 @@ namespace Flowframes.Os
{
int seekStep = 10;
if(videoLengthSeconds > 2 * 60) seekStep = 20;
if(videoLengthSeconds > 5 * 60) seekStep = 30;
if(videoLengthSeconds > 15 * 60) seekStep = 60;
if (videoLengthSeconds > 2 * 60) seekStep = 20;
if (videoLengthSeconds > 5 * 60) seekStep = 30;
if (videoLengthSeconds > 15 * 60) seekStep = 60;
return seekStep;
}

File diff suppressed because it is too large Load Diff