Fix image sequence import, fix JPEG export args, include img ext in frame output dir name

This commit is contained in:
N00MKRAD
2024-11-08 11:54:26 +01:00
parent 71da171156
commit 70e17dcabc
9 changed files with 85 additions and 55 deletions

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Windows.Navigation;
namespace Flowframes.Data namespace Flowframes.Data
{ {
@@ -59,13 +58,27 @@ namespace Flowframes.Data
return; 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('/'); 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) if (numbers.Length == 1)
{ {
Numerator = numbers[0].GetFloat().RoundToInt(); float numFloat = numbers[0].GetFloat();
Denominator = 1; 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; return;
} }

View File

@@ -74,11 +74,12 @@ namespace Flowframes.Data
Size = GetSize(); Size = GetSize();
} }
public async Task InitializeSequence() public void InitializeSequence()
{ {
try try
{ {
if (SequenceInitialized) return; if (SequenceInitialized)
return;
string seqPath = Path.Combine(Paths.GetFrameSeqPath(), CreationTime.ToString(), "frames.concat"); string seqPath = Path.Combine(Paths.GetFrameSeqPath(), CreationTime.ToString(), "frames.concat");
string chosenExt = IoUtils.GetUniqueExtensions(SourcePath).FirstOrDefault(); string chosenExt = IoUtils.GetUniqueExtensions(SourcePath).FirstOrDefault();
@@ -101,7 +102,7 @@ namespace Flowframes.Data
try try
{ {
if (IsDirectory && !SequenceInitialized) if (IsDirectory && !SequenceInitialized)
await InitializeSequence(); InitializeSequence();
await LoadFormatInfo(ImportPath); await LoadFormatInfo(ImportPath);
AllStreams = await FfmpegUtils.GetStreams(ImportPath, progressBar, StreamCount, InputRate, countFrames, this); AllStreams = await FfmpegUtils.GetStreams(ImportPath, progressBar, StreamCount, InputRate, countFrames, this);
@@ -122,11 +123,19 @@ namespace Flowframes.Data
private async Task LoadFormatInfo(string path) 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"); Title = await GetVideoInfo.GetFfprobeInfoAsync(path, GetVideoInfo.FfprobeMode.ShowFormat, "TAG:title");
Language = await GetVideoInfo.GetFfprobeInfoAsync(path, GetVideoInfo.FfprobeMode.ShowFormat, "TAG:language"); Language = await GetVideoInfo.GetFfprobeInfoAsync(path, GetVideoInfo.FfprobeMode.ShowFormat, "TAG:language");
DurationMs = await FfmpegCommands.GetDurationMs(path, this); DurationMs = await FfmpegCommands.GetDurationMs(path, this);
FfmpegCommands.CheckVfr(path, this); FfmpegCommands.CheckVfr(path, this);
StreamCount = await FfmpegUtils.GetStreamCount(path);
TotalKbits = (await GetVideoInfo.GetFfprobeInfoAsync(path, GetVideoInfo.FfprobeMode.ShowFormat, "bit_rate")).GetInt() / 1000; TotalKbits = (await GetVideoInfo.GetFfprobeInfoAsync(path, GetVideoInfo.FfprobeMode.ShowFormat, "bit_rate")).GetInt() / 1000;
} }

View File

@@ -262,7 +262,7 @@ namespace Flowframes.IO
if (key == Key.maxVidHeight) return WriteDefault(key, "2160"); if (key == Key.maxVidHeight) return WriteDefault(key, "2160");
if (key == Key.clearLogOnInput) return WriteDefault(key, "True"); if (key == Key.clearLogOnInput) return WriteDefault(key, "True");
if (key == Key.tempDirCustom) return WriteDefault(key, "D:/"); 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]"); if (key == Key.exportNamePatternLoop) return WriteDefault(key, "-Loop[LOOPS]");
// Interpolation // Interpolation
if (key == Key.dedupThresh) return WriteDefault(key, "2"); if (key == Key.dedupThresh) return WriteDefault(key, "2");

View File

@@ -594,7 +594,7 @@ namespace Flowframes.IO
} }
} }
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; InterpSettings curr = Interpolate.currentSettings;
string max = Config.Get(Config.Key.maxFps); string max = Config.Get(Config.Key.maxFps);
@@ -605,7 +605,7 @@ namespace Flowframes.IO
string pattern = Config.Get(Config.Key.exportNamePattern); string pattern = Config.Get(Config.Key.exportNamePattern);
string inName = Interpolate.currentSettings.inputIsFrames ? Path.GetFileName(curr.inPath) : Path.GetFileNameWithoutExtension(curr.inPath); string inName = Interpolate.currentSettings.inputIsFrames ? Path.GetFileName(curr.inPath) : Path.GetFileNameWithoutExtension(curr.inPath);
bool encodeBoth = Config.GetInt(Config.Key.maxFpsMode) == 0; 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; string filename = pattern;
filename = filename.Replace("[NAME]", inName); filename = filename.Replace("[NAME]", inName);
@@ -618,11 +618,17 @@ namespace Flowframes.IO
filename = filename.Replace("[RES]", $"{outRes.Width}x{outRes.Height}"); filename = filename.Replace("[RES]", $"{outRes.Width}x{outRes.Height}");
filename = filename.Replace("[H]", $"{outRes.Height}p"); filename = filename.Replace("[H]", $"{outRes.Height}p");
if (addSuffix) if (addFpsLimitSuffix)
{
filename += Paths.fpsLimitSuffix; filename += Paths.fpsLimitSuffix;
}
if (withExt) if (includeExt)
filename += FfmpegUtils.GetExt(curr.outSettings); {
string ext = FfmpegUtils.GetExt(curr.outSettings);
ext = isImgSeq ? ext.Replace(".", "-") : ext;
filename += ext;
}
return filename; return filename;
} }

View File

@@ -4,7 +4,6 @@ using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms;
using Padding = Flowframes.Data.Padding; using Padding = Flowframes.Data.Padding;
using I = Flowframes.Interpolate; using I = Flowframes.Interpolate;
using System.Diagnostics; using System.Diagnostics;
@@ -20,7 +19,8 @@ namespace Flowframes.Main
{ {
class Export 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) public static async Task ExportFrames(string path, string outFolder, OutputSettings exportSettings, bool stepByStep)
{ {
@@ -55,16 +55,15 @@ namespace Flowframes.Main
try try
{ {
string max = Config.Get(Config.Key.maxFps); bool fpsLimit = MaxFpsFrac.Float > 0f && I.currentSettings.outFps.Float > MaxFpsFrac.Float;
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
bool fpsLimit = maxFps.Float > 0f && I.currentSettings.outFps.Float > maxFps.Float;
bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0; bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
string exportPath = Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(fpsLimit));
if (!dontEncodeFullFpsVid) 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) 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) catch (Exception e)
{ {
@@ -77,19 +76,14 @@ namespace Flowframes.Main
{ {
InterpSettings s = I.currentSettings; InterpSettings s = I.currentSettings;
string encArgs = FfmpegUtils.GetEncArgs(s.outSettings, (s.ScaledResolution.IsEmpty ? s.InputResolution : s.ScaledResolution), s.outFps.Float, true).FirstOrDefault(); string encArgs = FfmpegUtils.GetEncArgs(s.outSettings, (s.ScaledResolution.IsEmpty ? s.InputResolution : s.ScaledResolution), s.outFps.Float, true).FirstOrDefault();
bool fpsLimit = MaxFpsFrac.Float > 0f && s.outFps.Float > MaxFpsFrac.Float;
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 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, extraData.Rotation); 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"; extraArgsIn += " -color_trc bt709 -color_primaries bt709 -colorspace bt709";
} }
@@ -108,7 +102,7 @@ namespace Flowframes.Main
else else
{ {
bool imageSequence = s.outSettings.Encoder.GetInfo().IsImageSequence; 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); IoUtils.RenameExistingFileOrDir(s.FullOutPath);
if (imageSequence) if (imageSequence)
@@ -126,15 +120,15 @@ namespace Flowframes.Main
Program.mainForm.SetStatus("Copying output frames..."); Program.mainForm.SetStatus("Copying output frames...");
Enums.Encoding.Encoder desiredFormat = I.currentSettings.outSettings.Encoder; Enums.Encoding.Encoder desiredFormat = I.currentSettings.outSettings.Encoder;
string availableFormat = Path.GetExtension(IoUtils.GetFilesSorted(framesPath, "*.*")[0]).Remove(".").Upper(); 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 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)); 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); IoUtils.RenameExistingFolder(outputFolderPath);
Logger.Log($"Exporting {desiredFormat.ToString().Upper()} frames to '{Path.GetFileName(outputFolderPath)}'..."); Logger.Log($"Exporting {desiredFormat.ToString().Upper()} frames to '{Path.GetFileName(outputFolderPath)}'...");
@@ -146,7 +140,7 @@ namespace Flowframes.Main
if (fpsLimit) 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)..."); 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)); await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 1, I.currentSettings.outFps, maxFps, desiredFormat, OutputUtils.GetImgSeqQ(I.currentSettings.outSettings));
} }
@@ -244,7 +238,7 @@ namespace Flowframes.Main
File.WriteAllText(tempConcatFile, concatFileContent); File.WriteAllText(tempConcatFile, concatFileContent);
Logger.Log($"CreateVideo: Running MergeChunks() for frames file '{Path.GetFileName(tempConcatFile)}'", true); Logger.Log($"CreateVideo: Running MergeChunks() for frames file '{Path.GetFileName(tempConcatFile)}'", true);
bool fpsLimit = dir.Name.Contains(Paths.fpsLimitSuffix); 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); await MergeChunks(tempConcatFile, outPath, isBackup);
if (!isBackup) if (!isBackup)
@@ -290,9 +284,7 @@ namespace Flowframes.Main
if (Config.GetInt(Config.Key.sceneChangeFillMode) == 1) if (Config.GetInt(Config.Key.sceneChangeFillMode) == 1)
await Blend.BlendSceneChanges(concatFile, false); await Blend.BlendSceneChanges(concatFile, false);
string max = Config.Get(Config.Key.maxFps); bool fpsLimit = MaxFpsFrac.Float != 0 && I.currentSettings.outFps.Float > MaxFpsFrac.Float;
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
bool fpsLimit = maxFps.Float != 0 && I.currentSettings.outFps.Float > maxFps.Float;
VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(I.currentSettings.inPath); VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(I.currentSettings.inPath);
bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0; bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
@@ -304,7 +296,7 @@ namespace Flowframes.Main
if (!dontEncodeFullFpsVid) 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; 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 if (chunkNo == 1) // Only check for existing folder on first chunk, otherwise each chunk makes a new folder
@@ -318,9 +310,9 @@ namespace Flowframes.Main
if (fpsLimit) 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; 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 else
@@ -333,7 +325,7 @@ namespace Flowframes.Main
string filename = Path.GetFileName(outPath); string filename = Path.GetFileName(outPath);
string newParentDir = outPath.GetParentDir() + Paths.fpsLimitSuffix; string newParentDir = outPath.GetParentDir() + Paths.fpsLimitSuffix;
outPath = Path.Combine(newParentDir, filename); 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
} }
} }
@@ -393,7 +385,7 @@ namespace Flowframes.Main
} }
} }
public static void MuxTimestamps (string vidPath) public static void MuxTimestamps(string vidPath)
{ {
Logger.Log($"Muxing timestamps for '{vidPath}'", hidden: true); Logger.Log($"Muxing timestamps for '{vidPath}'", hidden: true);
var resampledTs = I.currentMediaFile.GetResampledTimestamps(I.currentMediaFile.InputTimestamps, I.currentSettings.interpFactor); var resampledTs = I.currentMediaFile.GetResampledTimestamps(I.currentMediaFile.InputTimestamps, I.currentSettings.interpFactor);

View File

@@ -173,7 +173,7 @@ namespace Flowframes
if (extractedFrames == 1) if (extractedFrames == 1)
Cancel("Only a single frame was extracted from your input file!\n\nPossibly your input is an image, not a video?"); Cancel("Only a single frame was extracted from your input file!\n\nPossibly your input is an image, not a video?");
else 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) if (Config.GetInt(Config.Key.dedupMode) == 1)

View File

@@ -94,6 +94,9 @@ namespace Flowframes
public static async Task<long> GetDurationMs(string inputFile, MediaFile mediaFile, bool demuxInsteadOfPacketTs = false, bool allowDurationFromMetadata = true) public static async Task<long> GetDurationMs(string inputFile, MediaFile mediaFile, bool demuxInsteadOfPacketTs = false, bool allowDurationFromMetadata = true)
{ {
if (mediaFile.IsDirectory)
return 0;
if (allowDurationFromMetadata) if (allowDurationFromMetadata)
{ {
Logger.Log($"GetDuration({inputFile}) - Reading duration by checking metadata.", true, false, "ffmpeg"); Logger.Log($"GetDuration({inputFile}) - Reading duration by checking metadata.", true, false, "ffmpeg");

View File

@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Win32Interop.Enums;
using static Flowframes.AvProcess; using static Flowframes.AvProcess;
using Utils = Flowframes.Media.FfmpegUtils; using Utils = Flowframes.Media.FfmpegUtils;
@@ -131,13 +132,19 @@ namespace Flowframes.Media
inArg = $"-i {Path.GetFileName(framesFile) + Paths.symlinksSuffix}/%{Padding.interpFrames}d{GetConcatFileExt(framesFile)}"; inArg = $"-i {Path.GetFileName(framesFile) + Paths.symlinksSuffix}/%{Padding.interpFrames}d{GetConcatFileExt(framesFile)}";
} }
string sn = $"-start_number {startNo}"; var ffArgs = new List<string>()
string rate = fps.ToString().Replace(",", "."); {
string vf = (resampleFps.Float < 0.1f) ? "" : $"-vf fps=fps={resampleFps}"; $"-r {fps.ToString().Replace(",", ".")}", // Rate
string compression = format == Enums.Encoding.Encoder.Png ? pngCompr : $"-q:v {lossyQ}"; inArg,
string codec = format == Enums.Encoding.Encoder.Webp ? "-c:v libwebp" : ""; // Specify libwebp to avoid putting all frames into single animated WEBP format == Enums.Encoding.Encoder.Webp ? "-c:v libwebp" : "", // Codec - Specify libwebp to avoid putting all frames into single animated WEBP
string args = $"-r {rate} {inArg} {codec} {compression} {sn} {vf} -fps_mode passthrough \"{outDir}/%{Padding.interpFrames}d.{format.GetInfo().OverideExtension}\""; format == Enums.Encoding.Encoder.Png ? pngCompr : $"-q:v {lossyQ}", // Compression
await RunFfmpeg(args, framesFile.GetParentDir(), logMode, "error", true); $"-start_number {startNo}",
resampleFps.Float < 0.1f ? "" : $"-vf fps=fps={resampleFps}", // FPS Resample
"-fps_mode passthrough",
$"{outDir}/%{Padding.interpFrames}d.{format.GetInfo().OverideExtension}".Wrap(),
};
await RunFfmpeg(string.Join(" ", ffArgs.Where(s => s.IsNotEmpty())), framesFile.GetParentDir(), logMode, "error", true);
IoUtils.TryDeleteIfExists(linksDir); IoUtils.TryDeleteIfExists(linksDir);
} }

View File

@@ -351,7 +351,7 @@ namespace Flowframes.Media
if (enc == Encoder.Jpeg) if (enc == Encoder.Jpeg)
{ {
var qualityLevel = ParseUtils.GetEnum<Quality.JpegWebm>(settings.Quality, true, Strings.VideoQuality); var qualityLevel = ParseUtils.GetEnum<Quality.JpegWebm>(settings.Quality, true, Strings.VideoQuality);
args.Add($"-q:v {OutputUtils.JpegQuality[qualityLevel]}"); args.Add($"-q:v {OutputUtils.JpegQuality[qualityLevel]} -color_range full");
} }
if (enc == Encoder.Webp) if (enc == Encoder.Webp)