WIP: VFR Dedupe - Added code to create timecode file

This commit is contained in:
N00MKRAD
2020-11-24 02:23:19 +01:00
parent c20c8f75ec
commit 4623aa149b
9 changed files with 74 additions and 38 deletions

View File

@@ -11,34 +11,19 @@ namespace Flowframes
{
static string videoEncArgs = "-pix_fmt yuv420p -movflags +faststart -vf \"crop = trunc(iw / 2) * 2:trunc(ih / 2) * 2\"";
public static async Task VideoToFrames(string inputFile, string frameFolderPath, bool deDupe, bool rgb8, bool hdr, bool delSrc)
public static async Task VideoToFrames(string inputFile, string frameFolderPath, bool deDupe, bool delSrc)
{
if (!Directory.Exists(frameFolderPath))
Directory.CreateDirectory(frameFolderPath);
string hdrStr = "";
if (hdr) hdrStr = FFmpegStrings.hdrFilter;
string deDupeStr = "";
if (deDupe) deDupeStr = "-vf mpdecimate";
string fmtStr = "";
if (rgb8) fmtStr = "-pix_fmt rgb8";
string args = $"-i {inputFile.Wrap()} {hdrStr} -vsync 0 {fmtStr} {deDupeStr} \"{frameFolderPath}/%08d.png\"";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
await Task.Delay(1);
if (delSrc)
DeleteSource(inputFile);
await VideoToFrames(inputFile, frameFolderPath, deDupe, delSrc, new Size());
}
public static async Task VideoToFrames(string inputFile, string frameFolderPath, int w, int h, bool deDupe, bool rgb8, bool hdr, bool delSrc)
public static async Task VideoToFrames(string inputFile, string frameFolderPath, bool deDupe, bool delSrc, Size size)
{
string sizeStr = "";
if (size.Width > 1 && size.Height > 1) sizeStr = $"-s {size.Width}x{size.Height}";
if (!Directory.Exists(frameFolderPath))
Directory.CreateDirectory(frameFolderPath);
string hdrStr = "";
if (hdr) hdrStr = FFmpegStrings.hdrFilter;
string deDupeStr = "";
if (deDupe) deDupeStr = "-vf mpdecimate";
string fmtStr = "";
if (rgb8) fmtStr = "-pix_fmt rgb8";
string args = $"-i {inputFile.Wrap()} -compression_level 3 {hdrStr} -vsync 0 {fmtStr} {deDupeStr} -s {w}x{h} \"{frameFolderPath}/%08d.png\"";
string args = $"-i {inputFile.Wrap()} -compression_level 3 -vsync 0 -pix_fmt rgb24 {sizeStr} \"{frameFolderPath}/%08d.png\"";
if(deDupe) args = $"-i {inputFile.Wrap()} -copyts -r 1000 -compression_level 3 -vsync 0 -frame_pts true -vf mpdecimate {sizeStr} \"{frameFolderPath}/%08d.png\"";
await AvProcess.RunFfmpeg(args, AvProcess.LogMode.OnlyLastLine);
await Task.Delay(1);
if (delSrc)

View File

@@ -191,6 +191,7 @@
<Compile Include="Main\BatchProcessing.cs" />
<Compile Include="Main\CreateVideo.cs" />
<Compile Include="Main\InterpolateUtils.cs" />
<Compile Include="Main\VfrDedupe.cs" />
<Compile Include="OS\AiProcess.cs" />
<Compile Include="ExtensionMethods.cs" />
<Compile Include="AudioVideo\AvProcess.cs" />
@@ -209,8 +210,8 @@
<Compile Include="IO\IOUtils.cs" />
<Compile Include="IO\Paths.cs" />
<Compile Include="Logger.cs" />
<Compile Include="Magick\Coverter.cs" />
<Compile Include="Magick\FrameDedup.cs" />
<Compile Include="Magick\Converter.cs" />
<Compile Include="Magick\MagickDedupe.cs" />
<Compile Include="OS\NvApi.cs" />
<Compile Include="OS\OSUtils.cs" />
<Compile Include="OS\Python.cs" />

View File

@@ -103,6 +103,7 @@ namespace Flowframes.IO
if (key == "timingMode") return WriteDefault("timingMode", "1");
if (key == "tempDirCustom") return WriteDefault("tempDirCustom", "C:/");
if (key == "ffprobeCountFrames") return WriteDefault("ffprobeCountFrames", "False");
if (key == "vfrDedupe") return WriteDefault("vfrDedupe", "True");
return WriteDefault(key, "0");
}

View File

@@ -12,7 +12,7 @@ using System.Threading.Tasks;
namespace Flowframes.Magick
{
class Coverter
class Converter
{
public static async Task Convert (string dir, MagickFormat format, int quality, string ext = "", bool print = true, bool setProgress = true)
{

View File

@@ -10,7 +10,7 @@ using ImageMagick;
namespace Flowframes.Magick
{
class FrameDedup
class MagickDedupe
{
public enum Mode { None, Info, Enabled, Auto }
public static Mode currentMode;

View File

@@ -30,7 +30,7 @@ namespace Flowframes.Main
}
await Task.Delay(10);
if(Config.GetInt("timingMode") == 1)
await FrameDedup.Reduplicate(path);
await MagickDedupe.Reduplicate(path);
Program.mainForm.SetStatus("Creating output video from frames...");
try
{
@@ -61,7 +61,7 @@ namespace Flowframes.Main
if (new DirectoryInfo(framesPath).GetFiles()[0].Extension != ".png")
{
Logger.Log("Converting output frames to PNG to encode with Gifski...");
await Coverter.Convert(framesPath, ImageMagick.MagickFormat.Png00, 20, "png", false);
await Converter.Convert(framesPath, ImageMagick.MagickFormat.Png00, 20, "png", false);
}
await GifskiCommands.CreateGifFromFrames(i.currentOutFps.RoundToInt(), Config.GetInt("gifskiQ"), framesPath, outPath);
}

View File

@@ -62,7 +62,9 @@ namespace Flowframes
if (cancelled) return;
sw.Restart();
await Task.Delay(10);
await FrameDedup.Run(framesPath);
if (Config.GetBool("vfrDedupe"))
VfrDedupe.CreateTimecodeFile(framesPath, Config.GetBool("enableLoop"), interpFactor);
await MagickDedupe.Run(framesPath);
if (cancelled) return;
string interpFramesDir = Path.Combine(currentTempDir, "frames-interpolated");
string outPath = Path.Combine(outDir, Path.GetFileNameWithoutExtension(inPath) + IOUtils.GetAiSuffix(ai, interpFactor) + Utils.GetExt(outMode));
@@ -86,7 +88,6 @@ namespace Flowframes
{
Logger.Log("Extracting frames using FFmpeg...");
await Task.Delay(10);
bool rgb8 = Formats.preprocess.Contains(Path.GetExtension(inPath).ToLower());
Program.mainForm.SetStatus("Extracting frames from video...");
Size resolution = IOUtils.GetVideoRes(inPath);
int maxHeight = Config.GetInt("maxVidHeight");
@@ -95,11 +96,11 @@ namespace Flowframes
float factor = (float)maxHeight / resolution.Height;
int width = (resolution.Width * factor).RoundToInt();
Logger.Log($"Video is bigger than the maximum - Downscaling to {width}x{maxHeight}.");
await FFmpegCommands.VideoToFrames(inPath, outPath, width, maxHeight, false, rgb8, false, false);
await FFmpegCommands.VideoToFrames(inPath, outPath, Config.GetBool("vfrDedupe"), false, new Size(width, maxHeight));
}
else
{
await FFmpegCommands.VideoToFrames(inPath, outPath, false, rgb8, false, false);
await FFmpegCommands.VideoToFrames(inPath, outPath, Config.GetBool("vfrDedupe"), false);
}
/*
if (AvProcess.lastOutputFfmpeg.ToLower().Contains("invalid"))
@@ -111,7 +112,7 @@ namespace Flowframes
if (extractAudio)
{
string audioFile = Path.Combine(currentTempDir, "audio.m4a");
if (!File.Exists(audioFile))
if (audioFile != null && !File.Exists(audioFile))
await FFmpegCommands.ExtractAudio(inPath, audioFile);
}
if (!cancelled && Config.GetBool("enableLoop"))
@@ -172,7 +173,8 @@ namespace Flowframes
cancelled = true;
Program.mainForm.SetStatus("Cancelled.");
Program.mainForm.SetProgress(0);
IOUtils.TryDeleteIfExists(currentTempDir);
if(!Config.GetBool("keepTempFolder"))
IOUtils.TryDeleteIfExists(currentTempDir);
Program.mainForm.SetWorking(false);
Logger.Log("Cancelled interpolation.");
if (!string.IsNullOrWhiteSpace(reason))

47
Code/Main/VfrDedupe.cs Normal file
View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Flowframes.Main
{
class VfrDedupe
{
public static void CreateTimecodeFile(string framesPath, bool loopEnabled, int interpFactor)
{
FileInfo[] frameFiles = new DirectoryInfo(framesPath).GetFiles("*.png");
string vfrFile = Path.Combine(framesPath.GetParentDir(), "vfr.ini");
int lastFrameDuration = 1;
// Calculate time duration between frames
int totalFileCount = 1;
for (int i = 0; i < (frameFiles.Length - 1); i++)
{
string filename1 = frameFiles[i].Name;
string filename2 = frameFiles[i + 1].Name;
int durationTotal = Path.GetFileNameWithoutExtension(filename2).GetInt() - Path.GetFileNameWithoutExtension(filename1).GetInt();
lastFrameDuration = durationTotal;
float durationPerInterpFrame = (float)durationTotal / interpFactor;
int interpolatedFrameCount = interpFactor;
// If loop is enabled, account for the extra frame added to the end for loop continuity
if (loopEnabled && i == (frameFiles.Length - 2))
interpolatedFrameCount = interpolatedFrameCount * 2;
//Logger.Log("Frame " + i);
// Generate frames file lines
for (int frm = 0; frm < interpolatedFrameCount; frm++)
{
//Logger.Log("Writing info for interp frame " + frm);
string durationStr = (durationPerInterpFrame / 1000f).ToString("0.0000").Replace(",", ".");
File.AppendAllText(vfrFile, $"{totalFileCount.ToString().PadLeft(8, '0')}.png\nduration {durationStr}\n");
totalFileCount++;
}
}
}
}
}

View File

@@ -18,9 +18,8 @@ namespace Flowframes.UI
public static async Task ExtractVideo(string videoPath, bool withAudio)
{
string outPath = Path.ChangeExtension(videoPath, null) + "-extracted";
bool rgb8 = Formats.preprocess.Contains(Path.GetExtension(videoPath).ToLower());
Program.mainForm.SetWorking(true);
await FFmpegCommands.VideoToFrames(videoPath, Path.Combine(outPath, "frames"), false, rgb8, false, false);
await FFmpegCommands.VideoToFrames(videoPath, Path.Combine(outPath, "frames"), false, false);
File.WriteAllText(Path.Combine(outPath, "fps.ini"), Interpolate.currentInFps.ToString());
if (withAudio)
await FFmpegCommands.ExtractAudio(videoPath, Path.Combine(outPath, "audio"));
@@ -94,7 +93,8 @@ namespace Flowframes.UI
Program.mainForm.SetWorking(true);
await Task.Delay(10);
framesPath = Path.ChangeExtension(inPath, null) + "-frames";
await Interpolate.ExtractFrames(inPath, framesPath);
Directory.CreateDirectory(framesPath);
await Interpolate.ExtractFrames(inPath, framesPath, false);
}
else
{
@@ -103,7 +103,7 @@ namespace Flowframes.UI
Program.mainForm.SetWorking(true);
Logger.Log("Running frame de-duplication", true);
await Task.Delay(10);
await FrameDedup.Run(framesPath, testRun);
await MagickDedupe.Run(framesPath, testRun);
IOUtils.TryDeleteIfExists(framesPath);
Program.mainForm.SetProgress(0);
Program.mainForm.SetWorking(false);