2021-02-01 16:23:35 +01:00
|
|
|
|
using Flowframes.Data;
|
|
|
|
|
|
using Flowframes.IO;
|
|
|
|
|
|
using Flowframes.Main;
|
|
|
|
|
|
using Flowframes.MiscUtils;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2021-04-03 16:30:07 +02:00
|
|
|
|
using System.Diagnostics;
|
2021-02-01 16:23:35 +01:00
|
|
|
|
using System.Drawing;
|
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using static Flowframes.AvProcess;
|
2021-02-02 12:56:48 +01:00
|
|
|
|
using Utils = Flowframes.Media.FFmpegUtils;
|
2021-02-01 16:23:35 +01:00
|
|
|
|
|
2021-02-02 12:56:48 +01:00
|
|
|
|
namespace Flowframes.Media
|
2021-02-01 16:23:35 +01:00
|
|
|
|
{
|
2021-02-02 12:56:48 +01:00
|
|
|
|
partial class FfmpegEncode : FfmpegCommands
|
2021-02-01 16:23:35 +01:00
|
|
|
|
{
|
2021-05-06 12:08:03 +02:00
|
|
|
|
public static async Task FramesToVideo(string framesFile, string outPath, Interpolate.OutMode outMode, Fraction fps, Fraction resampleFps, ColorInfo colors, LogMode logMode = LogMode.OnlyLastLine, bool isChunk = false)
|
2021-02-01 16:23:35 +01:00
|
|
|
|
{
|
|
|
|
|
|
if (logMode != LogMode.Hidden)
|
2021-04-26 14:13:22 +02:00
|
|
|
|
Logger.Log((resampleFps.GetFloat() <= 0) ? "Encoding video..." : $"Encoding video resampled to {resampleFps.GetString()} FPS...");
|
2021-04-25 15:11:39 +02:00
|
|
|
|
|
2021-02-01 16:23:35 +01:00
|
|
|
|
Directory.CreateDirectory(outPath.GetParentDir());
|
|
|
|
|
|
string encArgs = Utils.GetEncArgs(Utils.GetCodec(outMode));
|
2021-05-05 10:24:59 +02:00
|
|
|
|
if (!isChunk && outMode == Interpolate.OutMode.VidMp4) encArgs += $" -movflags +faststart";
|
2021-04-03 16:30:07 +02:00
|
|
|
|
string inArg = $"-f concat -i {Path.GetFileName(framesFile)}";
|
2021-04-04 17:56:07 +02:00
|
|
|
|
string linksDir = Path.Combine(framesFile + Paths.symlinksSuffix);
|
2021-04-03 16:30:07 +02:00
|
|
|
|
|
2021-04-04 00:01:49 +02:00
|
|
|
|
if (Config.GetBool("allowSymlinkEncoding", true) && Symlinks.SymlinksAllowed())
|
2021-04-03 16:30:07 +02:00
|
|
|
|
{
|
2021-04-25 15:11:39 +02:00
|
|
|
|
if (await Symlinks.MakeSymlinksForEncode(framesFile, linksDir, Padding.interpFrames))
|
2021-04-19 21:18:17 +02:00
|
|
|
|
inArg = $"-i {Path.GetFileName(framesFile) + Paths.symlinksSuffix}/%{Padding.interpFrames}d.png";
|
2021-04-03 16:30:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-01 16:23:35 +01:00
|
|
|
|
string extraArgs = Config.Get("ffEncArgs");
|
2021-05-06 12:08:03 +02:00
|
|
|
|
string rate = fps.ToString().Replace(",", ".");
|
|
|
|
|
|
|
|
|
|
|
|
List<string> filters = new List<string>();
|
|
|
|
|
|
|
|
|
|
|
|
if (resampleFps.GetFloat() >= 0.1f)
|
|
|
|
|
|
filters.Add($"fps=fps={resampleFps}");
|
|
|
|
|
|
|
|
|
|
|
|
if (colors.HasAllValues())
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log($"Applying color transfer ({colors.colorSpace}).", true, false, "ffmpeg");
|
|
|
|
|
|
filters.Add($"scale=out_color_matrix={colors.colorSpace}");
|
|
|
|
|
|
extraArgs += $" -colorspace {colors.colorSpace} -color_primaries {colors.colorPrimaries} -color_trc {colors.colorTransfer} -color_range:v \"{colors.colorRange}\"";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string vf = filters.Count > 0 ? $"-vf {string.Join(",", filters)}" : "";
|
2021-04-03 16:30:07 +02:00
|
|
|
|
string args = $"-vsync 0 -r {rate} {inArg} {encArgs} {vf} {extraArgs} -threads {Config.GetInt("ffEncThreads")} {outPath.Wrap()}";
|
2021-03-02 15:06:44 +01:00
|
|
|
|
await RunFfmpeg(args, framesFile.GetParentDir(), logMode, "error", TaskType.Encode, !isChunk);
|
2021-04-04 17:56:07 +02:00
|
|
|
|
IOUtils.TryDeleteIfExists(linksDir);
|
2021-04-03 16:30:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-04-26 14:13:22 +02:00
|
|
|
|
public static async Task FramesToFrames(string framesFile, string outDir, Fraction fps, Fraction resampleFps, string format = "png", LogMode logMode = LogMode.OnlyLastLine)
|
2021-04-03 16:30:07 +02:00
|
|
|
|
{
|
2021-04-25 15:11:39 +02:00
|
|
|
|
Directory.CreateDirectory(outDir);
|
|
|
|
|
|
string inArg = $"-f concat -i {Path.GetFileName(framesFile)}";
|
|
|
|
|
|
string linksDir = Path.Combine(framesFile + Paths.symlinksSuffix);
|
2021-04-04 00:01:49 +02:00
|
|
|
|
|
2021-04-25 15:11:39 +02:00
|
|
|
|
if (Config.GetBool("allowSymlinkEncoding", true) && Symlinks.SymlinksAllowed())
|
2021-04-03 16:30:07 +02:00
|
|
|
|
{
|
2021-04-25 15:11:39 +02:00
|
|
|
|
if (await Symlinks.MakeSymlinksForEncode(framesFile, linksDir, Padding.interpFrames))
|
|
|
|
|
|
inArg = $"-i {Path.GetFileName(framesFile) + Paths.symlinksSuffix}/%{Padding.interpFrames}d.png";
|
2021-04-03 16:30:07 +02:00
|
|
|
|
}
|
2021-04-25 15:11:39 +02:00
|
|
|
|
|
|
|
|
|
|
string rate = fps.ToString().Replace(",", ".");
|
2021-04-26 14:13:22 +02:00
|
|
|
|
string vf = (resampleFps.GetFloat() < 0.1f) ? "" : $"-vf fps=fps={resampleFps}";
|
2021-04-25 15:11:39 +02:00
|
|
|
|
string compression = format == "png" ? pngCompr : "-q:v 1";
|
|
|
|
|
|
string args = $"-vsync 0 -r {rate} {inArg} {compression} {vf} \"{outDir}/%{Padding.interpFrames}d.{format}\"";
|
|
|
|
|
|
await RunFfmpeg(args, framesFile.GetParentDir(), logMode, "error", TaskType.Encode, true);
|
|
|
|
|
|
IOUtils.TryDeleteIfExists(linksDir);
|
2021-02-01 16:23:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-04-26 14:13:22 +02:00
|
|
|
|
public static async Task FramesToGifConcat(string framesFile, string outPath, Fraction rate, bool palette, int colors, Fraction resampleFps, LogMode logMode = LogMode.OnlyLastLine)
|
2021-02-02 12:56:48 +01:00
|
|
|
|
{
|
2021-04-26 14:13:22 +02:00
|
|
|
|
if (rate.GetFloat() > 50f && resampleFps.GetFloat() < 50f)
|
|
|
|
|
|
resampleFps = new Fraction(50, 1); // Force limit framerate as encoding above 50 will cause problems
|
2021-04-09 19:47:06 +02:00
|
|
|
|
|
2021-02-02 12:56:48 +01:00
|
|
|
|
if (logMode != LogMode.Hidden)
|
2021-04-26 14:13:22 +02:00
|
|
|
|
Logger.Log((resampleFps.GetFloat() <= 0) ? $"Encoding GIF..." : $"Encoding GIF resampled to {resampleFps.ToString().Replace(",", ".")} FPS...");
|
2021-04-09 19:47:06 +02:00
|
|
|
|
|
2021-04-25 14:02:52 +02:00
|
|
|
|
string framesFilename = Path.GetFileName(framesFile);
|
2021-04-05 12:55:31 +02:00
|
|
|
|
string dither = Config.Get("gifDitherType").Split(' ').First();
|
|
|
|
|
|
string paletteFilter = palette ? $"-vf \"split[s0][s1];[s0]palettegen={colors}[p];[s1][p]paletteuse=dither={dither}\"" : "";
|
2021-04-26 14:13:22 +02:00
|
|
|
|
string fpsFilter = (resampleFps.GetFloat() <= 0) ? "" : $"fps=fps={resampleFps}";
|
2021-02-02 12:56:48 +01:00
|
|
|
|
string vf = FormatUtils.ConcatStrings(new string[] { paletteFilter, fpsFilter });
|
2021-04-25 14:02:52 +02:00
|
|
|
|
string args = $"-f concat -r {rate} -i {framesFilename.Wrap()} -gifflags -offsetting {vf} {outPath.Wrap()}";
|
2021-03-02 15:06:44 +01:00
|
|
|
|
await RunFfmpeg(args, framesFile.GetParentDir(), LogMode.OnlyLastLine, "error", TaskType.Encode);
|
2021-02-02 12:56:48 +01:00
|
|
|
|
}
|
2021-02-01 16:23:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|