Skip to content

Commit

Permalink
Fix image sequence import, fix JPEG export args, include img ext in f…
Browse files Browse the repository at this point in the history
…rame output dir name
  • Loading branch information
n00mkrad committed Nov 8, 2024
1 parent 71da171 commit 70e17dc
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 55 deletions.
21 changes: 17 additions & 4 deletions CodeLegacy/Data/Fraction.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Windows.Navigation;

namespace Flowframes.Data
{
Expand Down Expand Up @@ -59,13 +58,27 @@ public Fraction(string text)
return;
}

text = text.Replace(':', '/'); // Replace colon with slash in case someone thinks it's a good idea to write a fraction like that
string[] numbers = text.Split('/');

// Check if split is only 1 items (probably integer number)
// If split is only 1 item, it's a single number, not a fraction
if (numbers.Length == 1)
{
Numerator = numbers[0].GetFloat().RoundToInt();
Denominator = 1;
float numFloat = numbers[0].GetFloat();
int numInt = numFloat.RoundToInt();

// If parsed float is equal to the rounded int, it's a whole number
if (numbers[0].GetFloat().EqualsRoughly(numInt))
{
Numerator = numInt;
Denominator = 1;
}
else
{
// Use float constructor if not a whole number
this = new Fraction(numFloat);
}

return;
}

Expand Down
17 changes: 13 additions & 4 deletions CodeLegacy/Data/MediaFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,12 @@ public MediaFile(string path, bool requestFpsInputIfUnset = true)
Size = GetSize();
}

public async Task InitializeSequence()
public void InitializeSequence()
{
try
{
if (SequenceInitialized) return;
if (SequenceInitialized)
return;

string seqPath = Path.Combine(Paths.GetFrameSeqPath(), CreationTime.ToString(), "frames.concat");
string chosenExt = IoUtils.GetUniqueExtensions(SourcePath).FirstOrDefault();
Expand All @@ -101,7 +102,7 @@ public async Task Initialize(bool progressBar = true, bool countFrames = true)
try
{
if (IsDirectory && !SequenceInitialized)
await InitializeSequence();
InitializeSequence();

await LoadFormatInfo(ImportPath);
AllStreams = await FfmpegUtils.GetStreams(ImportPath, progressBar, StreamCount, InputRate, countFrames, this);
Expand All @@ -122,11 +123,19 @@ public async Task Initialize(bool progressBar = true, bool countFrames = true)

private async Task LoadFormatInfo(string path)
{
StreamCount = await FfmpegUtils.GetStreamCount(path);

// If input is a sequence, there's not much metadata to check
if (path.IsConcatFile())
{
DurationMs = (long)(FileCount * 1000 / ((Fraction)InputRate).Float); // Estimate duration using specified FPS and frame count
return;
}

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, this);
FfmpegCommands.CheckVfr(path, this);
StreamCount = await FfmpegUtils.GetStreamCount(path);
TotalKbits = (await GetVideoInfo.GetFfprobeInfoAsync(path, GetVideoInfo.FfprobeMode.ShowFormat, "bit_rate")).GetInt() / 1000;
}

Expand Down
2 changes: 1 addition & 1 deletion CodeLegacy/IO/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ private static string WriteDefaultValIfExists(string keyStr, Type type)
if (key == Key.maxVidHeight) return WriteDefault(key, "2160");
if (key == Key.clearLogOnInput) return WriteDefault(key, "True");
if (key == Key.tempDirCustom) return WriteDefault(key, "D:/");
if (key == Key.exportNamePattern) return WriteDefault(key, "[NAME]-[FACTOR]x-[AI]-[MODEL]-[FPS]fps");
if (key == Key.exportNamePattern) return WriteDefault(key, "[NAME]-[FACTOR]x-[MODEL]-[FPS]fps");
if (key == Key.exportNamePatternLoop) return WriteDefault(key, "-Loop[LOOPS]");
// Interpolation
if (key == Key.dedupThresh) return WriteDefault(key, "2");
Expand Down
16 changes: 11 additions & 5 deletions CodeLegacy/IO/IoUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ public static bool RenameFile(string path, string newName, bool alsoRenameExtens
}
}

public static async Task<string> GetCurrentExportFilename(bool fpsLimit, bool withExt)
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);
Expand All @@ -605,7 +605,7 @@ public static async Task<string> GetCurrentExportFilename(bool fpsLimit, bool wi
string pattern = Config.Get(Config.Key.exportNamePattern);
string inName = Interpolate.currentSettings.inputIsFrames ? Path.GetFileName(curr.inPath) : Path.GetFileNameWithoutExtension(curr.inPath);
bool encodeBoth = Config.GetInt(Config.Key.maxFpsMode) == 0;
bool addSuffix = fpsLimit && (!pattern.Contains("[FPS]") && !pattern.Contains("[ROUNDFPS]")) && encodeBoth;
bool addFpsLimitSuffix = fpsLimit && (!pattern.Contains("[FPS]") && !pattern.Contains("[ROUNDFPS]")) && encodeBoth;
string filename = pattern;

filename = filename.Replace("[NAME]", inName);
Expand All @@ -618,11 +618,17 @@ public static async Task<string> GetCurrentExportFilename(bool fpsLimit, bool wi
filename = filename.Replace("[RES]", $"{outRes.Width}x{outRes.Height}");
filename = filename.Replace("[H]", $"{outRes.Height}p");

if (addSuffix)
if (addFpsLimitSuffix)
{
filename += Paths.fpsLimitSuffix;
}

if (withExt)
filename += FfmpegUtils.GetExt(curr.outSettings);
if (includeExt)
{
string ext = FfmpegUtils.GetExt(curr.outSettings);
ext = isImgSeq ? ext.Replace(".", "-") : ext;
filename += ext;
}

return filename;
}
Expand Down
56 changes: 24 additions & 32 deletions CodeLegacy/Main/Export.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Padding = Flowframes.Data.Padding;
using I = Flowframes.Interpolate;
using System.Diagnostics;
Expand All @@ -20,7 +19,8 @@ namespace Flowframes.Main
{
class Export
{

private static string MaxFps = Config.Get(Config.Key.maxFps);
private static Fraction MaxFpsFrac = new Fraction(MaxFps);

public static async Task ExportFrames(string path, string outFolder, OutputSettings exportSettings, bool stepByStep)
{
Expand Down Expand Up @@ -55,16 +55,15 @@ public static async Task ExportFrames(string path, string outFolder, OutputSetti

try
{
string max = Config.Get(Config.Key.maxFps);
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
bool fpsLimit = maxFps.Float > 0f && I.currentSettings.outFps.Float > maxFps.Float;
bool fpsLimit = MaxFpsFrac.Float > 0f && I.currentSettings.outFps.Float > MaxFpsFrac.Float;
bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
string exportPath = Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(fpsLimit));

if (!dontEncodeFullFpsVid)
await Encode(exportSettings, path, Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(false, true)), I.currentSettings.outFps, new Fraction());
await Encode(exportSettings, path, exportPath, I.currentSettings.outFps, new Fraction());

if (fpsLimit)
await Encode(exportSettings, path, Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(true, true)), I.currentSettings.outFps, maxFps);
await Encode(exportSettings, path, exportPath, I.currentSettings.outFps, MaxFpsFrac);
}
catch (Exception e)
{
Expand All @@ -77,19 +76,14 @@ public static async Task<string> GetPipedFfmpegCmd(bool ffplay = false)
{
InterpSettings s = I.currentSettings;
string encArgs = FfmpegUtils.GetEncArgs(s.outSettings, (s.ScaledResolution.IsEmpty ? s.InputResolution : s.ScaledResolution), s.outFps.Float, true).FirstOrDefault();

string max = Config.Get(Config.Key.maxFps);
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
bool fpsLimit = maxFps.Float > 0f && s.outFps.Float > maxFps.Float;

// 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 fpsLimit = MaxFpsFrac.Float > 0f && s.outFps.Float > MaxFpsFrac.Float;
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, extraData.Rotation);
string extraArgsOut = await FfmpegEncode.GetFfmpegExportArgsOut(fpsLimit ? maxFps : new Fraction(), extraData, s.outSettings);
string extraArgsOut = await FfmpegEncode.GetFfmpegExportArgsOut(fpsLimit ? MaxFpsFrac : new Fraction(), extraData, s.outSettings);

if(s.outSettings.Encoder == Enums.Encoding.Encoder.Exr)
// For EXR, force bt709 input flags. Not sure if this really does anything, EXR
if (s.outSettings.Encoder == Enums.Encoding.Encoder.Exr)
{
extraArgsIn += " -color_trc bt709 -color_primaries bt709 -colorspace bt709";
}
Expand All @@ -108,7 +102,7 @@ public static async Task<string> GetPipedFfmpegCmd(bool ffplay = false)
else
{
bool imageSequence = s.outSettings.Encoder.GetInfo().IsImageSequence;
s.FullOutPath = Path.Combine(s.outPath, await IoUtils.GetCurrentExportFilename(fpsLimit, !imageSequence));
s.FullOutPath = Path.Combine(s.outPath, await IoUtils.GetCurrentExportFilename(fpsLimit, isImgSeq: imageSequence));
IoUtils.RenameExistingFileOrDir(s.FullOutPath);

if (imageSequence)
Expand All @@ -126,15 +120,15 @@ static async Task ExportImageSequence(string framesPath, bool stepByStep)
Program.mainForm.SetStatus("Copying output frames...");
Enums.Encoding.Encoder desiredFormat = I.currentSettings.outSettings.Encoder;
string availableFormat = Path.GetExtension(IoUtils.GetFilesSorted(framesPath, "*.*")[0]).Remove(".").Upper();
string max = Config.Get(Config.Key.maxFps);
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());

Fraction maxFps = new Fraction(MaxFps);
bool fpsLimit = maxFps.Float > 0f && I.currentSettings.outFps.Float > maxFps.Float;
bool dontEncodeFullFpsSeq = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
bool encodeFullFpsSeq = !(fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0);
string framesFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(I.currentSettings.interpFactor));

if (!dontEncodeFullFpsSeq)
if (encodeFullFpsSeq)
{
string outputFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(false, false));
string outputFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(fpsLimit: false, isImgSeq: true));
IoUtils.RenameExistingFolder(outputFolderPath);
Logger.Log($"Exporting {desiredFormat.ToString().Upper()} frames to '{Path.GetFileName(outputFolderPath)}'...");

Expand All @@ -146,7 +140,7 @@ static async Task ExportImageSequence(string framesPath, bool stepByStep)

if (fpsLimit)
{
string outputFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(true, false));
string outputFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(fpsLimit: true, isImgSeq: true));
Logger.Log($"Exporting {desiredFormat.ToString().Upper()} frames to '{Path.GetFileName(outputFolderPath)}' (Resampled to {maxFps} FPS)...");
await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 1, I.currentSettings.outFps, maxFps, desiredFormat, OutputUtils.GetImgSeqQ(I.currentSettings.outSettings));
}
Expand Down Expand Up @@ -244,7 +238,7 @@ public static async Task ChunksToVideo(string tempFolder, string chunksFolder, s
File.WriteAllText(tempConcatFile, concatFileContent);
Logger.Log($"CreateVideo: Running MergeChunks() for frames file '{Path.GetFileName(tempConcatFile)}'", true);
bool fpsLimit = dir.Name.Contains(Paths.fpsLimitSuffix);
string outPath = Path.Combine(baseOutPath, await IoUtils.GetCurrentExportFilename(fpsLimit, true));
string outPath = Path.Combine(baseOutPath, await IoUtils.GetCurrentExportFilename(fpsLimit));
await MergeChunks(tempConcatFile, outPath, isBackup);

if (!isBackup)
Expand Down Expand Up @@ -290,9 +284,7 @@ public static async Task EncodeChunk(string outPath, string interpDir, int chunk
if (Config.GetInt(Config.Key.sceneChangeFillMode) == 1)
await Blend.BlendSceneChanges(concatFile, false);

string max = Config.Get(Config.Key.maxFps);
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
bool fpsLimit = maxFps.Float != 0 && I.currentSettings.outFps.Float > maxFps.Float;
bool fpsLimit = MaxFpsFrac.Float != 0 && I.currentSettings.outFps.Float > MaxFpsFrac.Float;
VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(I.currentSettings.inPath);

bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
Expand All @@ -304,7 +296,7 @@ public static async Task EncodeChunk(string outPath, string interpDir, int chunk

if (!dontEncodeFullFpsVid)
{
string outFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(false, false));
string outFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(fpsLimit: false, isImgSeq: true));
int startNo = IoUtils.GetAmountOfFiles(outFolderPath, false) + 1;

if (chunkNo == 1) // Only check for existing folder on first chunk, otherwise each chunk makes a new folder
Expand All @@ -318,9 +310,9 @@ public static async Task EncodeChunk(string outPath, string interpDir, int chunk

if (fpsLimit)
{
string outputFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(true, false));
string outputFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(fpsLimit: true, isImgSeq: true));
int startNumber = IoUtils.GetAmountOfFiles(outputFolderPath, false) + 1;
await FfmpegEncode.FramesToFrames(concatFile, outputFolderPath, startNumber, I.currentSettings.outFps, maxFps, settings.Encoder, OutputUtils.GetImgSeqQ(settings), AvProcess.LogMode.Hidden);
await FfmpegEncode.FramesToFrames(concatFile, outputFolderPath, startNumber, I.currentSettings.outFps, MaxFpsFrac, settings.Encoder, OutputUtils.GetImgSeqQ(settings), AvProcess.LogMode.Hidden);
}
}
else
Expand All @@ -333,7 +325,7 @@ public static async Task EncodeChunk(string outPath, string interpDir, int chunk
string filename = Path.GetFileName(outPath);
string newParentDir = outPath.GetParentDir() + Paths.fpsLimitSuffix;
outPath = Path.Combine(newParentDir, filename);
await FfmpegEncode.FramesToVideo(concatFile, outPath, settings, I.currentSettings.outFps, maxFps, I.currentSettings.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode with limited fps
await FfmpegEncode.FramesToVideo(concatFile, outPath, settings, I.currentSettings.outFps, MaxFpsFrac, I.currentSettings.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode with limited fps
}
}

Expand Down Expand Up @@ -393,7 +385,7 @@ public static async Task MuxOutputVideo(string inputPath, string outVideo, bool
}
}

public static void MuxTimestamps (string vidPath)
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);
Expand Down
2 changes: 1 addition & 1 deletion CodeLegacy/Main/Interpolate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public static async Task PostProcessFrames(bool stepByStep)
if (extractedFrames == 1)
Cancel("Only a single frame was extracted from your input file!\n\nPossibly your input is an image, not a video?");
else
Cancel($"Frame extraction failed!\nExtracted {extractedFrames} frames - current.framesFolder exists: {Directory.Exists(currentSettings.framesFolder)} - currentInputFrameCount = {currentMediaFile.FrameCount} - extractedFrames = {extractedFrames}.\n\nYour input file might be incompatible.");
Cancel($"Frame extraction failed!\nExtracted {extractedFrames} frames - Frames Folder exists: {Directory.Exists(currentSettings.framesFolder)} - Current Frame Count = {currentMediaFile.FrameCount}.\n\nYour input file might be incompatible.");
}

if (Config.GetInt(Config.Key.dedupMode) == 1)
Expand Down
3 changes: 3 additions & 0 deletions CodeLegacy/Media/FfmpegCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ public static async Task ChangeSpeed(string inputFile, float newSpeedPercent, bo

public static async Task<long> GetDurationMs(string inputFile, MediaFile mediaFile, bool demuxInsteadOfPacketTs = false, bool allowDurationFromMetadata = true)
{
if (mediaFile.IsDirectory)
return 0;

if (allowDurationFromMetadata)
{
Logger.Log($"GetDuration({inputFile}) - Reading duration by checking metadata.", true, false, "ffmpeg");
Expand Down
Loading

0 comments on commit 70e17dc

Please sign in to comment.