mirror of https://github.com/n00mkrad/flowframes
Backported MediaFile stuff from Nmkoder
This commit is contained in:
parent
30b3faf16d
commit
d96513ed4b
|
@ -21,6 +21,8 @@ namespace Flowframes.Data
|
|||
public int[] SupportedFactors { get; set; } = new int[0];
|
||||
public bool Piped { get; set; } = false;
|
||||
|
||||
public string LogFilename { get { return AiName.Replace("_", "-").ToLower() + "-log"; } }
|
||||
|
||||
public AI(AiBackend backend, string aiName, string friendlyName, string desc, string pkgDir, InterpFactorSupport factorSupport = InterpFactorSupport.Fixed, int[] supportedFactors = null)
|
||||
{
|
||||
Backend = backend;
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
using Flowframes.Data.Streams;
|
||||
using Flowframes.IO;
|
||||
using Flowframes.Media;
|
||||
using Flowframes.MiscUtils;
|
||||
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;
|
||||
|
||||
namespace Flowframes.Data
|
||||
{
|
||||
public class MediaFile
|
||||
{
|
||||
public bool IsDirectory;
|
||||
public FileInfo FileInfo;
|
||||
public DirectoryInfo DirectoryInfo;
|
||||
public int FileCount;
|
||||
public string Name;
|
||||
public string SourcePath;
|
||||
public string ImportPath;
|
||||
public string Format;
|
||||
public string Title;
|
||||
public string Language;
|
||||
public Fraction? InputRate = null;
|
||||
public long DurationMs;
|
||||
public int StreamCount;
|
||||
public int TotalKbits;
|
||||
public long Size;
|
||||
public List<Stream> AllStreams = new List<Stream>();
|
||||
public List<VideoStream> VideoStreams = new List<VideoStream>();
|
||||
public List<AudioStream> AudioStreams = new List<AudioStream>();
|
||||
public List<SubtitleStream> SubtitleStreams = new List<SubtitleStream>();
|
||||
public List<DataStream> DataStreams = new List<DataStream>();
|
||||
public List<AttachmentStream> AttachmentStreams = new List<AttachmentStream>();
|
||||
public VideoColorData ColorData = null;
|
||||
public long CreationTime;
|
||||
public bool Initialized = false;
|
||||
public bool SequenceInitialized = false;
|
||||
|
||||
public int FrameCount { get { return VideoStreams.Count > 0 ? VideoStreams[0].FrameCount : 0; } }
|
||||
|
||||
public MediaFile(string path /* , bool requestFpsInputIfUnset = true */)
|
||||
{
|
||||
CreationTime = (long)(DateTime.Now - new DateTime(1970, 1, 1)).TotalMilliseconds; // Unix Timestamp as UID
|
||||
|
||||
if (IoUtils.IsPathDirectory(path))
|
||||
{
|
||||
IsDirectory = true;
|
||||
DirectoryInfo = new DirectoryInfo(path);
|
||||
Name = DirectoryInfo.Name;
|
||||
SourcePath = DirectoryInfo.FullName;
|
||||
Format = "Folder";
|
||||
|
||||
// if (requestFpsInputIfUnset && InputRate == null)
|
||||
// {
|
||||
// PromptForm form = new PromptForm("Enter Frame Rate", $"Please enter a frame rate to use for the image sequence '{Name.Trunc(80)}'.", "30");
|
||||
// form.ShowDialog();
|
||||
// InputRate = new Fraction(form.EnteredText);
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
FileInfo = new FileInfo(path);
|
||||
Name = FileInfo.Name;
|
||||
SourcePath = FileInfo.FullName;
|
||||
ImportPath = FileInfo.FullName;
|
||||
Format = FileInfo.Extension.Remove(".").ToUpper();
|
||||
FileCount = 1;
|
||||
InputRate = new Fraction(-1, 1);
|
||||
}
|
||||
|
||||
Size = GetSize();
|
||||
}
|
||||
|
||||
public async Task InitializeSequence()
|
||||
{
|
||||
Logger.Log($"InitializeSequence not implemented!!");
|
||||
|
||||
// try
|
||||
// {
|
||||
// if (SequenceInitialized) return;
|
||||
//
|
||||
// Logger.Log($"Preparing image sequence...");
|
||||
// Logger.Log($"MediaFile {Name}: Preparing image sequence", true);
|
||||
// string seqPath = Path.Combine(Paths.GetFrameSeqPath(), CreationTime.ToString(), "frames.concat");
|
||||
// string chosenExt = IoUtils.GetUniqueExtensions(SourcePath).FirstOrDefault();
|
||||
// int fileCount = FfmpegUtils.CreateConcatFile(SourcePath, seqPath, new List<string> { chosenExt });
|
||||
// ImportPath = seqPath;
|
||||
// FileCount = fileCount;
|
||||
// Logger.Log($"Created concat file with {fileCount} files.", true);
|
||||
// SequenceInitialized = true;
|
||||
// }
|
||||
// catch (Exception e)
|
||||
// {
|
||||
// Logger.Log($"Error preparing frame sequence: {e.Message}\n{e.StackTrace}");
|
||||
// FileCount = 0;
|
||||
// }
|
||||
}
|
||||
|
||||
public async Task Initialize(bool progressBar = true)
|
||||
{
|
||||
Logger.Log($"MediaFile {Name}: Initializing", true);
|
||||
|
||||
try
|
||||
{
|
||||
if (IsDirectory && !SequenceInitialized)
|
||||
await InitializeSequence();
|
||||
|
||||
await LoadFormatInfo(ImportPath);
|
||||
AllStreams = await FfmpegUtils.GetStreams(ImportPath, progressBar, StreamCount, (Fraction)InputRate, true);
|
||||
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();
|
||||
DataStreams = AllStreams.Where(x => x.Type == Stream.StreamType.Data).Select(x => (DataStream)x).ToList();
|
||||
AttachmentStreams = AllStreams.Where(x => x.Type == Stream.StreamType.Attachment).Select(x => (AttachmentStream)x).ToList();
|
||||
Logger.Log($"Loaded and sorted streams for {Name}", true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log($"Failed to initialized MediaFile: {e.Message}", true);
|
||||
}
|
||||
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
private async Task LoadFormatInfo(string path)
|
||||
{
|
||||
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));
|
||||
StreamCount = await FfmpegUtils.GetStreamCount(path);
|
||||
TotalKbits = (await GetVideoInfo.GetFfprobeInfoAsync(path, GetVideoInfo.FfprobeMode.ShowFormat, "bit_rate")).GetInt() / 1000;
|
||||
}
|
||||
|
||||
public string GetName()
|
||||
{
|
||||
if (IsDirectory)
|
||||
return DirectoryInfo.Name;
|
||||
else
|
||||
return FileInfo.Name;
|
||||
}
|
||||
|
||||
public string GetPath()
|
||||
{
|
||||
if (IsDirectory)
|
||||
return DirectoryInfo.FullName;
|
||||
else
|
||||
return FileInfo.FullName;
|
||||
}
|
||||
|
||||
public long GetSize()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsDirectory)
|
||||
return IoUtils.GetDirSize(GetPath(), true);
|
||||
else
|
||||
return FileInfo.Length;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Failed to get file size of {FileInfo.FullName}: {ex.Message} (Path Length: {FileInfo.FullName.Length})", true);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckFiles()
|
||||
{
|
||||
if (IsDirectory)
|
||||
return Directory.Exists(DirectoryInfo.FullName);
|
||||
else
|
||||
return File.Exists(FileInfo.FullName);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{GetName()} ({FormatUtils.Bytes(Size)})";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,7 +57,6 @@ namespace Flowframes.IO
|
|||
return path;
|
||||
}
|
||||
|
||||
|
||||
public static string GetPkgPath()
|
||||
{
|
||||
string path = Path.Combine(GetDataPath(), "pkgs");
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
namespace Flowframes.Data.Streams
|
||||
{
|
||||
public class AttachmentStream : Stream
|
||||
{
|
||||
public string Filename { get; } = "";
|
||||
public string MimeType { get; } = "";
|
||||
|
||||
public AttachmentStream(string codec, string codecLong, string filename, string mimeType)
|
||||
{
|
||||
base.Type = StreamType.Attachment;
|
||||
Codec = codec;
|
||||
CodecLong = codecLong;
|
||||
Filename = filename;
|
||||
MimeType = mimeType;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{base.ToString()} - Filename: {Filename} - MIME Type: {MimeType}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
namespace Flowframes.Data.Streams
|
||||
{
|
||||
public class AudioStream : Stream
|
||||
{
|
||||
public int Kbits { get; }
|
||||
public int SampleRate { get; }
|
||||
public int Channels { get; }
|
||||
public string Layout { get; }
|
||||
|
||||
public AudioStream(string language, string title, string codec, string codecLong, int kbits, int sampleRate, int channels, string layout)
|
||||
{
|
||||
base.Type = StreamType.Audio;
|
||||
Language = language;
|
||||
Title = title;
|
||||
Codec = codec;
|
||||
CodecLong = codecLong;
|
||||
Kbits = kbits;
|
||||
SampleRate = sampleRate;
|
||||
Channels = channels;
|
||||
Layout = layout;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string title = string.IsNullOrWhiteSpace(Title.Trim()) ? "None" : Title;
|
||||
return $"{base.ToString()} - Language: {Language} - Title: {title} - Kbps: {Kbits} - SampleRate: {SampleRate} - Channels: {Channels} - Layout: {Layout}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
namespace Flowframes.Data.Streams
|
||||
{
|
||||
public class DataStream : Stream
|
||||
{
|
||||
public DataStream(string codec, string codecLong)
|
||||
{
|
||||
base.Type = StreamType.Data;
|
||||
Codec = codec;
|
||||
CodecLong = codecLong;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{base.ToString()}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
namespace Flowframes.Data.Streams
|
||||
{
|
||||
public class Stream
|
||||
{
|
||||
public enum StreamType { Video, Audio, Subtitle, Data, Attachment, Unknown }
|
||||
public StreamType Type;
|
||||
public int Index = -1;
|
||||
public bool IsDefault = false;
|
||||
public string Codec = "";
|
||||
public string CodecLong = "";
|
||||
public string Language = "";
|
||||
public string Title = "";
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Stream #{Index.ToString().PadLeft(2, '0')}{(IsDefault ? "*" : "")} - {Codec} {Type}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using Flowframes.Extensions;
|
||||
|
||||
namespace Flowframes.Data.Streams
|
||||
{
|
||||
public class SubtitleStream : Stream
|
||||
{
|
||||
public bool Bitmap { get; }
|
||||
|
||||
public SubtitleStream(string language, string title, string codec, string codecLong, bool bitmap)
|
||||
{
|
||||
base.Type = StreamType.Subtitle;
|
||||
Language = language;
|
||||
Title = title;
|
||||
Codec = codec;
|
||||
CodecLong = codecLong;
|
||||
Bitmap = bitmap;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string lang = string.IsNullOrWhiteSpace(Language.Trim()) ? "?" : Language;
|
||||
string ttl = string.IsNullOrWhiteSpace(Title.Trim()) ? "None" : Title;
|
||||
return $"{base.ToString()} - Language: {lang} - Title: {ttl} - Bitmap-based: {Bitmap.ToString().ToTitleCase()}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Drawing;
|
||||
|
||||
namespace Flowframes.Data.Streams
|
||||
{
|
||||
public class VideoStream : Stream
|
||||
{
|
||||
public int FrameCount { get; } = 0;
|
||||
public string PixelFormat { get; }
|
||||
public int Kbits { get; }
|
||||
public Size Resolution { get; }
|
||||
public Size Sar { get; }
|
||||
public Size Dar { get; }
|
||||
public Fraction Rate { get; }
|
||||
|
||||
public VideoStream(string language, string title, string codec, string codecLong, string pixFmt, int kbits, Size resolution, Size sar, Size dar, Fraction rate, int frameCount)
|
||||
{
|
||||
base.Type = StreamType.Video;
|
||||
Codec = codec;
|
||||
CodecLong = codecLong;
|
||||
PixelFormat = pixFmt;
|
||||
Kbits = kbits;
|
||||
Resolution = resolution;
|
||||
Sar = sar;
|
||||
Dar = dar;
|
||||
Rate = rate;
|
||||
FrameCount = frameCount;
|
||||
Language = language;
|
||||
Title = title;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{base.ToString()} - Language: {Language} - Color Format: {PixelFormat} - Size: {Resolution.Width}x{Resolution.Height} - FPS: {Rate}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using Flowframes.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Flowframes.Data
|
||||
{
|
||||
public class VideoColorData
|
||||
{
|
||||
public int ColorTransfer { get; set; } = 2;
|
||||
public int ColorMatrixCoeffs { get; set; } = 2;
|
||||
public int ColorPrimaries { get; set; } = 2;
|
||||
public int ColorRange { get; set; } = 0;
|
||||
public string RedX { get; set; } = "";
|
||||
public string RedY { get; set; } = "";
|
||||
public string GreenX { get; set; } = "";
|
||||
public string GreenY { get; set; } = "";
|
||||
public string BlueX { get; set; } = "";
|
||||
public string BlueY { get; set; } = "";
|
||||
public string WhiteX { get; set; } = "";
|
||||
public string WhiteY { get; set; } = "";
|
||||
public string LumaMin { get; set; } = "";
|
||||
public string LumaMax { get; set; } = "";
|
||||
public string MaxCll { get; set; } = "";
|
||||
public string MaxFall { get; set; } = "";
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
List<string> lines = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
lines.Add($"Color transfer: {ColorTransfer} ({ColorDataUtils.GetColorTransferName(ColorTransfer)})");
|
||||
lines.Add($"Colour matrix coefficients: {ColorMatrixCoeffs} ({ColorDataUtils.GetColorMatrixCoeffsName(ColorMatrixCoeffs)})");
|
||||
lines.Add($"Colour primaries: {ColorPrimaries} ({ColorDataUtils.GetColorPrimariesName(ColorPrimaries)})");
|
||||
lines.Add($"Colour range: {ColorRange} ({ColorDataUtils.GetColorRangeName(ColorRange)})");
|
||||
if (!string.IsNullOrWhiteSpace(RedX) && !string.IsNullOrWhiteSpace(RedY)) lines.Add($"Red color coordinates X/Y: {RedX}/{RedY}");
|
||||
if (!string.IsNullOrWhiteSpace(GreenX) && !string.IsNullOrWhiteSpace(GreenY)) lines.Add($"Green color coordinates X/Y: {GreenX}/{GreenY}");
|
||||
if (!string.IsNullOrWhiteSpace(BlueX) && !string.IsNullOrWhiteSpace(BlueY)) lines.Add($"Blue color coordinates X/Y: {BlueX}/{BlueY}");
|
||||
if (!string.IsNullOrWhiteSpace(WhiteX) && !string.IsNullOrWhiteSpace(WhiteY)) lines.Add($"White color coordinates X/Y: {WhiteX}/{WhiteY}");
|
||||
if (!string.IsNullOrWhiteSpace(LumaMin)) lines.Add($"Minimum luminance: {LumaMin}");
|
||||
if (!string.IsNullOrWhiteSpace(LumaMax)) lines.Add($"Maximum luminance: {LumaMax}");
|
||||
if (!string.IsNullOrWhiteSpace(MaxCll)) lines.Add($"Maximum Content Light Level: {MaxCll}");
|
||||
if (!string.IsNullOrWhiteSpace(MaxFall)) lines.Add($"Maximum Frame-Average Light Level: {MaxFall}");
|
||||
}
|
||||
catch { }
|
||||
|
||||
return string.Join("\n", lines);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
|||
using System.Windows.Forms;
|
||||
using Flowframes.Data;
|
||||
using System.Management.Automation;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Flowframes
|
||||
{
|
||||
|
@ -230,5 +231,45 @@ namespace Flowframes
|
|||
WildcardPattern pattern = new WildcardPattern(wildcard);
|
||||
return pattern.IsMatch(str);
|
||||
}
|
||||
|
||||
public static int RoundMod(this int n, int mod = 2) // Round to a number that's divisible by 2 (for h264 etc)
|
||||
{
|
||||
int a = (n / 2) * 2; // Smaller multiple
|
||||
int b = a + 2; // Larger multiple
|
||||
return (n - a > b - n) ? b : a; // Return of closest of two
|
||||
}
|
||||
|
||||
public static string ToTitleCase(this string s)
|
||||
{
|
||||
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(s);
|
||||
}
|
||||
|
||||
public static string ToStringShort(this Size s, string separator = "x")
|
||||
{
|
||||
return $"{s.Width}{separator}{s.Height}";
|
||||
}
|
||||
|
||||
public static bool IsConcatFile(this string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Path.GetExtension(filePath)?.ToLower() == ".concat";
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetConcStr(this string filePath, int rate = -1)
|
||||
{
|
||||
string rateStr = rate >= 0 ? $"-r {rate} " : "";
|
||||
return filePath.IsConcatFile() ? $"{rateStr}-safe 0 -f concat " : "";
|
||||
}
|
||||
|
||||
public static string GetFfmpegInputArg(this string filePath)
|
||||
{
|
||||
return $"{(filePath.IsConcatFile() ? filePath.GetConcStr() : "")} -i {filePath.Wrap()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -335,8 +335,16 @@
|
|||
<Compile Include="Data\AI.cs" />
|
||||
<Compile Include="Data\AudioTrack.cs" />
|
||||
<Compile Include="Data\Filetypes.cs" />
|
||||
<Compile Include="Data\MediaFile.cs" />
|
||||
<Compile Include="Data\ModelCollection.cs" />
|
||||
<Compile Include="Data\Servers.cs" />
|
||||
<Compile Include="Data\Streams\AttachmentStream.cs" />
|
||||
<Compile Include="Data\Streams\AudioStream.cs" />
|
||||
<Compile Include="Data\Streams\DataStream.cs" />
|
||||
<Compile Include="Data\Streams\Stream.cs" />
|
||||
<Compile Include="Data\Streams\SubtitleStream.cs" />
|
||||
<Compile Include="Data\Streams\VideoStream.cs" />
|
||||
<Compile Include="Data\VideoColorData.cs" />
|
||||
<Compile Include="Data\VidExtraData.cs" />
|
||||
<Compile Include="Data\Fraction.cs" />
|
||||
<Compile Include="Data\InterpSettings.cs" />
|
||||
|
@ -452,6 +460,7 @@
|
|||
<Compile Include="Ui\MainUiFunctions.cs" />
|
||||
<Compile Include="Ui\UiUtils.cs" />
|
||||
<Compile Include="Ui\QuickSettingsTab.cs" />
|
||||
<Compile Include="Utilities\ColorDataUtils.cs" />
|
||||
<EmbeddedResource Include="Form1.resx">
|
||||
<DependentUpon>Form1.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
|
|
|
@ -323,7 +323,7 @@ namespace Flowframes
|
|||
ValidateFactor();
|
||||
|
||||
if (!BatchProcessing.busy) // Don't load values from gui if batch processing is used
|
||||
Interpolate.current = GetCurrentSettings();
|
||||
Interpolate.currentSettings = GetCurrentSettings();
|
||||
|
||||
AiProcessSuspend.Reset();
|
||||
Interpolate.Start();
|
||||
|
@ -707,8 +707,7 @@ namespace Flowframes
|
|||
{
|
||||
if (BatchProcessing.busy || !File.Exists(inputTbox.Text.Trim())) return;
|
||||
|
||||
Interpolate.current = GetCurrentSettings();
|
||||
Interpolate.currentInputFrameCount = await GetFrameCountCached.GetFrameCountAsync(Interpolate.current.inPath);
|
||||
Interpolate.currentSettings = GetCurrentSettings();
|
||||
|
||||
AiProcessSuspend.Reset();
|
||||
await Interpolate.Realtime();
|
||||
|
|
|
@ -560,7 +560,7 @@ namespace Flowframes.IO
|
|||
|
||||
public static async Task<string> GetCurrentExportFilename(bool fpsLimit, bool withExt)
|
||||
{
|
||||
InterpSettings curr = Interpolate.current;
|
||||
InterpSettings curr = Interpolate.currentSettings;
|
||||
string max = Config.Get(Config.Key.maxFps);
|
||||
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
|
||||
float fps = fpsLimit ? maxFps.GetFloat() : curr.outFps.GetFloat();
|
||||
|
@ -570,7 +570,7 @@ namespace Flowframes.IO
|
|||
|
||||
Size outRes = await InterpolateUtils.GetOutputResolution(curr.inPath, false, false);
|
||||
string pattern = Config.Get(Config.Key.exportNamePattern);
|
||||
string inName = Interpolate.current.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 addSuffix = fpsLimit && (!pattern.Contains("[FPS]") && !pattern.Contains("[ROUNDFPS]")) && encodeBoth;
|
||||
string filename = pattern;
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace Flowframes.Magick
|
|||
if (setStatus)
|
||||
Program.mainForm.SetStatus("Blending scene transitions...");
|
||||
|
||||
string[] frames = FrameRename.framesAreRenamed ? new string[0] : IoUtils.GetFilesSorted(Interpolate.current.framesFolder);
|
||||
string[] frames = FrameRename.framesAreRenamed ? new string[0] : IoUtils.GetFilesSorted(Interpolate.currentSettings.framesFolder);
|
||||
|
||||
List<Task> runningTasks = new List<Task>();
|
||||
int maxThreads = Environment.ProcessorCount * 2;
|
||||
|
@ -52,8 +52,8 @@ namespace Flowframes.Magick
|
|||
string frameTo = FrameRename.framesAreRenamed ? values[1] : frames[values[1].GetInt()];
|
||||
int amountOfBlendFrames = values[2].GetInt();
|
||||
|
||||
string img1 = Path.Combine(Interpolate.current.framesFolder, frameFrom);
|
||||
string img2 = Path.Combine(Interpolate.current.framesFolder, frameTo);
|
||||
string img1 = Path.Combine(Interpolate.currentSettings.framesFolder, frameFrom);
|
||||
string img2 = Path.Combine(Interpolate.currentSettings.framesFolder, frameTo);
|
||||
|
||||
string firstOutputFrameName = line.Split('/').Last().Remove("'").Split('#').First();
|
||||
string ext = Path.GetExtension(firstOutputFrameName);
|
||||
|
@ -63,7 +63,7 @@ namespace Flowframes.Magick
|
|||
for (int blendFrameNum = 1; blendFrameNum <= amountOfBlendFrames; blendFrameNum++)
|
||||
{
|
||||
int outputNum = firstOutputFrameNum + blendFrameNum;
|
||||
string outputPath = Path.Combine(Interpolate.current.interpFolder, outputNum.ToString().PadLeft(Padding.interpFrames, '0'));
|
||||
string outputPath = Path.Combine(Interpolate.currentSettings.interpFolder, outputNum.ToString().PadLeft(Padding.interpFrames, '0'));
|
||||
outputPath = Path.ChangeExtension(outputPath, ext);
|
||||
outputFilenames.Add(outputPath);
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ namespace Flowframes.Magick
|
|||
|
||||
if (Interpolate.canceled) return;
|
||||
|
||||
int framesLeft = IoUtils.GetAmountOfFiles(path, false, "*" + Interpolate.current.framesExt);
|
||||
int framesLeft = IoUtils.GetAmountOfFiles(path, false, "*" + Interpolate.currentSettings.framesExt);
|
||||
int framesDeleted = framePaths.Length - framesLeft;
|
||||
float percentDeleted = ((float)framesDeleted / framePaths.Length) * 100f;
|
||||
string keptPercent = $"{(100f - percentDeleted).ToString("0.0")}%";
|
||||
|
@ -180,7 +180,7 @@ namespace Flowframes.Magick
|
|||
|
||||
static async Task<int> GetBufferSize ()
|
||||
{
|
||||
Size res = Interpolate.current.ScaledResolution;
|
||||
Size res = Interpolate.currentSettings.ScaledResolution;
|
||||
long pixels = res.Width * res.Height; // 4K = 8294400, 1440p = 3686400, 1080p = 2073600, 720p = 921600, 540p = 518400, 360p = 230400
|
||||
int bufferSize = 100;
|
||||
if (pixels < 518400) bufferSize = 1800;
|
||||
|
|
|
@ -32,14 +32,14 @@ namespace Flowframes.Main
|
|||
|
||||
public static void UpdateChunkAndBufferSizes ()
|
||||
{
|
||||
chunkSize = GetChunkSize((IoUtils.GetAmountOfFiles(Interpolate.current.framesFolder, false, "*" + Interpolate.current.framesExt) * Interpolate.current.interpFactor).RoundToInt());
|
||||
chunkSize = GetChunkSize((IoUtils.GetAmountOfFiles(Interpolate.currentSettings.framesFolder, false, "*" + Interpolate.currentSettings.framesExt) * Interpolate.currentSettings.interpFactor).RoundToInt());
|
||||
|
||||
safetyBufferFrames = 90;
|
||||
|
||||
if (Interpolate.current.ai.Backend == AI.AiBackend.Ncnn)
|
||||
if (Interpolate.currentSettings.ai.Backend == AI.AiBackend.Ncnn)
|
||||
safetyBufferFrames = Config.GetInt(Config.Key.autoEncSafeBufferNcnn, 150);
|
||||
|
||||
if (Interpolate.current.ai.Backend == AI.AiBackend.Pytorch)
|
||||
if (Interpolate.currentSettings.ai.Backend == AI.AiBackend.Pytorch)
|
||||
safetyBufferFrames = Config.GetInt(Config.Key.autoEncSafeBufferCuda, 90);
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ namespace Flowframes.Main
|
|||
{
|
||||
UpdateChunkAndBufferSizes();
|
||||
|
||||
bool imgSeq = Interpolate.current.outMode.ToString().ToLower().StartsWith("img");
|
||||
bool imgSeq = Interpolate.currentSettings.outMode.ToString().ToLower().StartsWith("img");
|
||||
interpFramesFolder = interpFramesPath;
|
||||
videoChunksFolder = Path.Combine(interpFramesPath.GetParentDir(), Paths.chunksDir);
|
||||
|
||||
|
@ -66,7 +66,7 @@ namespace Flowframes.Main
|
|||
|
||||
Logger.Log($"[AE] Starting AutoEncode MainLoop - Chunk Size: {chunkSize} Frames - Safety Buffer: {safetyBufferFrames} Frames", true);
|
||||
int chunkNo = AutoEncodeResume.encodedChunks + 1;
|
||||
string encFile = Path.Combine(interpFramesPath.GetParentDir(), Paths.GetFrameOrderFilename(Interpolate.current.interpFactor));
|
||||
string encFile = Path.Combine(interpFramesPath.GetParentDir(), Paths.GetFrameOrderFilename(Interpolate.currentSettings.interpFactor));
|
||||
interpFramesLines = IoUtils.ReadLines(encFile).Select(x => x.Split('/').Last().Remove("'").Split('#').First()).ToArray(); // Array with frame filenames
|
||||
|
||||
while (!Interpolate.canceled && GetInterpFramesAmount() < 2)
|
||||
|
@ -103,7 +103,7 @@ namespace Flowframes.Main
|
|||
|
||||
if(overwhelmed && !AiProcessSuspend.aiProcFrozen && OsUtils.IsProcessHidden(AiProcess.lastAiProcess))
|
||||
{
|
||||
string dirSize = FormatUtils.Bytes(IoUtils.GetDirSize(Interpolate.current.interpFolder, true));
|
||||
string dirSize = FormatUtils.Bytes(IoUtils.GetDirSize(Interpolate.currentSettings.interpFolder, true));
|
||||
Logger.Log($"AutoEnc is overwhelmed! ({unencodedFrameLines.Count} unencoded frames > {maxFrames}) - Pausing.", true);
|
||||
AiProcessSuspend.SuspendResumeAi(true);
|
||||
}
|
||||
|
@ -130,12 +130,12 @@ namespace Flowframes.Main
|
|||
}
|
||||
|
||||
busy = true;
|
||||
string outpath = Path.Combine(videoChunksFolder, "chunks", $"{chunkNo.ToString().PadLeft(4, '0')}{FfmpegUtils.GetExt(Interpolate.current.outMode)}");
|
||||
string outpath = Path.Combine(videoChunksFolder, "chunks", $"{chunkNo.ToString().PadLeft(4, '0')}{FfmpegUtils.GetExt(Interpolate.currentSettings.outMode)}");
|
||||
string firstFile = Path.GetFileName(interpFramesLines[frameLinesToEncode.First()].Trim());
|
||||
string lastFile = Path.GetFileName(interpFramesLines[frameLinesToEncode.Last()].Trim());
|
||||
Logger.Log($"[AE] Encoding Chunk #{chunkNo} to using line {frameLinesToEncode.First()} ({firstFile}) through {frameLinesToEncode.Last()} ({lastFile}) - {unencodedFrameLines.Count} unencoded frames left in total", true, false, "ffmpeg");
|
||||
|
||||
await Export.EncodeChunk(outpath, Interpolate.current.interpFolder, chunkNo, Interpolate.current.outMode, frameLinesToEncode.First(), frameLinesToEncode.Count);
|
||||
await Export.EncodeChunk(outpath, Interpolate.currentSettings.interpFolder, chunkNo, Interpolate.currentSettings.outMode, frameLinesToEncode.First(), frameLinesToEncode.Count);
|
||||
|
||||
if (Interpolate.canceled) return;
|
||||
|
||||
|
@ -153,7 +153,7 @@ namespace Flowframes.Main
|
|||
if(!imgSeq && Config.GetInt(Config.Key.autoEncBackupMode) > 0)
|
||||
{
|
||||
if (aiRunning && (currentMuxTask == null || (currentMuxTask != null && currentMuxTask.IsCompleted)))
|
||||
currentMuxTask = Task.Run(() => Export.ChunksToVideo(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outPath, true));
|
||||
currentMuxTask = Task.Run(() => Export.ChunksToVideo(Interpolate.currentSettings.tempFolder, videoChunksFolder, Interpolate.currentSettings.outPath, true));
|
||||
else
|
||||
Logger.Log($"[AE] Skipping backup because {(!aiRunning ? "this is the final chunk" : "previous mux task has not finished yet")}!", true, false, "ffmpeg");
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ namespace Flowframes.Main
|
|||
if (imgSeq)
|
||||
return;
|
||||
|
||||
await Export.ChunksToVideo(Interpolate.current.tempFolder, videoChunksFolder, Interpolate.current.outPath);
|
||||
await Export.ChunksToVideo(Interpolate.currentSettings.tempFolder, videoChunksFolder, Interpolate.currentSettings.outPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -239,7 +239,7 @@ namespace Flowframes.Main
|
|||
|
||||
static int GetInterpFramesAmount()
|
||||
{
|
||||
return IoUtils.GetAmountOfFiles(interpFramesFolder, false, "*" + Interpolate.current.interpExt);
|
||||
return IoUtils.GetAmountOfFiles(interpFramesFolder, false, "*" + Interpolate.currentSettings.interpExt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace Flowframes.Main
|
|||
|
||||
public static void Save ()
|
||||
{
|
||||
string saveDir = Path.Combine(I.current.tempFolder, Paths.resumeDir);
|
||||
string saveDir = Path.Combine(I.currentSettings.tempFolder, Paths.resumeDir);
|
||||
Directory.CreateDirectory(saveDir);
|
||||
|
||||
string chunksJsonPath = Path.Combine(saveDir, chunksFilename);
|
||||
|
@ -47,7 +47,7 @@ namespace Flowframes.Main
|
|||
File.WriteAllText(inputFramesJsonPath, JsonConvert.SerializeObject(processedInputFrames, Formatting.Indented));
|
||||
|
||||
string settingsJsonPath = Path.Combine(saveDir, interpSettingsFilename);
|
||||
File.WriteAllText(settingsJsonPath, JsonConvert.SerializeObject(I.current, Formatting.Indented));
|
||||
File.WriteAllText(settingsJsonPath, JsonConvert.SerializeObject(I.currentSettings, Formatting.Indented));
|
||||
}
|
||||
|
||||
public static void LoadTempFolder(string tempFolderPath)
|
||||
|
@ -72,8 +72,8 @@ namespace Flowframes.Main
|
|||
|
||||
try
|
||||
{
|
||||
string chunkJsonPath = Path.Combine(I.current.tempFolder, Paths.resumeDir, chunksFilename);
|
||||
string inFramesJsonPath = Path.Combine(I.current.tempFolder, Paths.resumeDir, inputFramesFilename);
|
||||
string chunkJsonPath = Path.Combine(I.currentSettings.tempFolder, Paths.resumeDir, chunksFilename);
|
||||
string inFramesJsonPath = Path.Combine(I.currentSettings.tempFolder, Paths.resumeDir, inputFramesFilename);
|
||||
|
||||
dynamic chunksData = JsonConvert.DeserializeObject(File.ReadAllText(chunkJsonPath));
|
||||
encodedChunks = chunksData.encodedChunks;
|
||||
|
@ -84,18 +84,18 @@ namespace Flowframes.Main
|
|||
|
||||
foreach (string inputFrameName in processedInputFrames)
|
||||
{
|
||||
string inputFrameFullPath = Path.Combine(I.current.tempFolder, Paths.framesDir, inputFrameName);
|
||||
string inputFrameFullPath = Path.Combine(I.currentSettings.tempFolder, Paths.framesDir, inputFrameName);
|
||||
IoUtils.TryDeleteIfExists(inputFrameFullPath);
|
||||
}
|
||||
|
||||
string videoChunksFolder = Path.Combine(I.current.tempFolder, Paths.chunksDir);
|
||||
string videoChunksFolder = Path.Combine(I.currentSettings.tempFolder, Paths.chunksDir);
|
||||
|
||||
FileInfo[] invalidChunks = IoUtils.GetFileInfosSorted(videoChunksFolder, true, "????.*").Skip(encodedChunks).ToArray();
|
||||
|
||||
foreach (FileInfo chunk in invalidChunks)
|
||||
chunk.Delete();
|
||||
|
||||
int inputFramesLeft = IoUtils.GetAmountOfFiles(Path.Combine(I.current.tempFolder, Paths.framesDir), false);
|
||||
int inputFramesLeft = IoUtils.GetAmountOfFiles(Path.Combine(I.currentSettings.tempFolder, Paths.framesDir), false);
|
||||
|
||||
Logger.Log($"Resume: Already encoded {encodedFrames} frames in {encodedChunks} chunks. There are now {inputFramesLeft} input frames left to interpolate.");
|
||||
|
||||
|
@ -104,7 +104,7 @@ namespace Flowframes.Main
|
|||
if(IoUtils.GetAmountOfFiles(videoChunksFolder, true, "*.*") > 0)
|
||||
{
|
||||
Logger.Log($"No more frames left to interpolate - Merging existing video chunks instead.");
|
||||
await Export.ChunksToVideo(I.current.tempFolder, videoChunksFolder, I.current.outPath);
|
||||
await Export.ChunksToVideo(I.currentSettings.tempFolder, videoChunksFolder, I.currentSettings.outPath);
|
||||
await I.Done();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace Flowframes.Main
|
|||
Logger.Log($"Queue: Processing {fname} ({entry.interpFactor}x {entry.ai.AiNameShort}).");
|
||||
|
||||
Program.mainForm.LoadBatchEntry(entry); // Load entry into GUI
|
||||
Interpolate.current = entry;
|
||||
Interpolate.currentSettings = entry;
|
||||
Program.mainForm.runBtn_Click(null, null);
|
||||
|
||||
while (Program.busy)
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace Flowframes.Main
|
|||
{
|
||||
if(Config.GetInt(Config.Key.sceneChangeFillMode) == 1)
|
||||
{
|
||||
string frameFile = Path.Combine(I.current.tempFolder, Paths.GetFrameOrderFilename(I.current.interpFactor));
|
||||
string frameFile = Path.Combine(I.currentSettings.tempFolder, Paths.GetFrameOrderFilename(I.currentSettings.interpFactor));
|
||||
await Blend.BlendSceneChanges(frameFile);
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ namespace Flowframes.Main
|
|||
return;
|
||||
}
|
||||
|
||||
if (IoUtils.GetAmountOfFiles(path, false, "*" + I.current.interpExt) <= 1)
|
||||
if (IoUtils.GetAmountOfFiles(path, false, "*" + I.currentSettings.interpExt) <= 1)
|
||||
{
|
||||
I.Cancel("Output folder does not contain frames - An error must have occured during interpolation!", AiProcess.hasShownError);
|
||||
return;
|
||||
|
@ -56,14 +56,14 @@ namespace Flowframes.Main
|
|||
{
|
||||
string max = Config.Get(Config.Key.maxFps);
|
||||
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
|
||||
bool fpsLimit = maxFps.GetFloat() > 0f && I.current.outFps.GetFloat() > maxFps.GetFloat();
|
||||
bool fpsLimit = maxFps.GetFloat() > 0f && I.currentSettings.outFps.GetFloat() > maxFps.GetFloat();
|
||||
bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
|
||||
|
||||
if (!dontEncodeFullFpsVid)
|
||||
await Encode(mode, path, Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(false, true)), I.current.outFps, new Fraction());
|
||||
await Encode(mode, path, Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(false, true)), I.currentSettings.outFps, new Fraction());
|
||||
|
||||
if (fpsLimit)
|
||||
await Encode(mode, path, Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(true, true)), I.current.outFps, maxFps);
|
||||
await Encode(mode, path, Path.Combine(outFolder, await IoUtils.GetCurrentExportFilename(true, true)), I.currentSettings.outFps, maxFps);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -79,31 +79,31 @@ namespace Flowframes.Main
|
|||
string availableFormat = Path.GetExtension(IoUtils.GetFilesSorted(framesPath)[0]).Remove(".").ToUpper();
|
||||
string max = Config.Get(Config.Key.maxFps);
|
||||
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
|
||||
bool fpsLimit = maxFps.GetFloat() > 0f && I.current.outFps.GetFloat() > maxFps.GetFloat();
|
||||
bool fpsLimit = maxFps.GetFloat() > 0f && I.currentSettings.outFps.GetFloat() > maxFps.GetFloat();
|
||||
bool dontEncodeFullFpsSeq = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
|
||||
string framesFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(I.current.interpFactor));
|
||||
string framesFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(I.currentSettings.interpFactor));
|
||||
|
||||
if (!dontEncodeFullFpsSeq)
|
||||
{
|
||||
string outputFolderPath = Path.Combine(I.current.outPath, await IoUtils.GetCurrentExportFilename(false, false));
|
||||
string outputFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(false, false));
|
||||
IoUtils.RenameExistingFolder(outputFolderPath);
|
||||
Logger.Log($"Exporting {desiredFormat.ToUpper()} frames to '{Path.GetFileName(outputFolderPath)}'...");
|
||||
|
||||
if (desiredFormat.ToUpper() == availableFormat.ToUpper()) // Move if frames are already in the desired format
|
||||
await CopyOutputFrames(framesPath, framesFile, outputFolderPath, 1, fpsLimit, false);
|
||||
else // Encode if frames are not in desired format
|
||||
await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 1, I.current.outFps, new Fraction(), desiredFormat, GetImgSeqQ(desiredFormat));
|
||||
await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 1, I.currentSettings.outFps, new Fraction(), desiredFormat, GetImgSeqQ(desiredFormat));
|
||||
}
|
||||
|
||||
if (fpsLimit)
|
||||
{
|
||||
string outputFolderPath = Path.Combine(I.current.outPath, await IoUtils.GetCurrentExportFilename(true, false));
|
||||
string outputFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(true, false));
|
||||
Logger.Log($"Exporting {desiredFormat.ToUpper()} frames to '{Path.GetFileName(outputFolderPath)}' (Resampled to {maxFps} FPS)...");
|
||||
await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 1, I.current.outFps, maxFps, desiredFormat, GetImgSeqQ(desiredFormat));
|
||||
await FfmpegEncode.FramesToFrames(framesFile, outputFolderPath, 1, I.currentSettings.outFps, maxFps, desiredFormat, GetImgSeqQ(desiredFormat));
|
||||
}
|
||||
|
||||
if (!stepByStep)
|
||||
await IoUtils.DeleteContentsOfDirAsync(I.current.interpFolder);
|
||||
await IoUtils.DeleteContentsOfDirAsync(I.currentSettings.interpFolder);
|
||||
}
|
||||
|
||||
static int GetImgSeqQ (string format)
|
||||
|
@ -167,7 +167,7 @@ namespace Flowframes.Main
|
|||
|
||||
static async Task Encode(I.OutMode mode, string framesPath, string outPath, Fraction fps, Fraction resampleFps)
|
||||
{
|
||||
string framesFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(I.current.interpFactor));
|
||||
string framesFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(I.currentSettings.interpFactor));
|
||||
|
||||
if (!File.Exists(framesFile))
|
||||
{
|
||||
|
@ -178,13 +178,13 @@ namespace Flowframes.Main
|
|||
|
||||
if (mode == I.OutMode.VidGif)
|
||||
{
|
||||
await FfmpegEncode.FramesToGifConcat(framesFile, outPath, fps, true, Config.GetInt(Config.Key.gifColors), resampleFps, I.current.outItsScale);
|
||||
await FfmpegEncode.FramesToGifConcat(framesFile, outPath, fps, true, Config.GetInt(Config.Key.gifColors), resampleFps, I.currentSettings.outItsScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(I.current.inPath);
|
||||
await FfmpegEncode.FramesToVideo(framesFile, outPath, mode, fps, resampleFps, I.current.outItsScale, extraData);
|
||||
await MuxOutputVideo(I.current.inPath, outPath);
|
||||
VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(I.currentSettings.inPath);
|
||||
await FfmpegEncode.FramesToVideo(framesFile, outPath, mode, fps, resampleFps, I.currentSettings.outItsScale, extraData);
|
||||
await MuxOutputVideo(I.currentSettings.inPath, outPath);
|
||||
await Loop(outPath, await GetLoopTimes());
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ namespace Flowframes.Main
|
|||
|
||||
public static async Task ChunksToVideo(string tempFolder, string chunksFolder, string baseOutPath, bool isBackup = false)
|
||||
{
|
||||
if (IoUtils.GetAmountOfFiles(chunksFolder, true, "*" + FfmpegUtils.GetExt(I.current.outMode)) < 1)
|
||||
if (IoUtils.GetAmountOfFiles(chunksFolder, true, "*" + FfmpegUtils.GetExt(I.currentSettings.outMode)) < 1)
|
||||
{
|
||||
I.Cancel("No video chunks found - An error must have occured during chunk encoding!", AiProcess.hasShownError);
|
||||
return;
|
||||
|
@ -252,7 +252,7 @@ namespace Flowframes.Main
|
|||
await FfmpegCommands.ConcatVideos(framesFile, outPath, -1, !isBackup);
|
||||
|
||||
if(!isBackup || (isBackup && Config.GetInt(Config.Key.autoEncBackupMode) == 2)) // Mux if no backup, or if backup AND muxing is enabled for backups
|
||||
await MuxOutputVideo(I.current.inPath, outPath, isBackup, !isBackup);
|
||||
await MuxOutputVideo(I.currentSettings.inPath, outPath, isBackup, !isBackup);
|
||||
|
||||
if(!isBackup)
|
||||
await Loop(outPath, await GetLoopTimes());
|
||||
|
@ -260,8 +260,8 @@ namespace Flowframes.Main
|
|||
|
||||
public static async Task EncodeChunk(string outPath, string interpDir, int chunkNo, I.OutMode mode, int firstFrameNum, int framesAmount)
|
||||
{
|
||||
string framesFileFull = Path.Combine(I.current.tempFolder, Paths.GetFrameOrderFilename(I.current.interpFactor));
|
||||
string concatFile = Path.Combine(I.current.tempFolder, Paths.GetFrameOrderFilenameChunk(firstFrameNum, firstFrameNum + framesAmount));
|
||||
string framesFileFull = Path.Combine(I.currentSettings.tempFolder, Paths.GetFrameOrderFilename(I.currentSettings.interpFactor));
|
||||
string concatFile = Path.Combine(I.currentSettings.tempFolder, Paths.GetFrameOrderFilenameChunk(firstFrameNum, firstFrameNum + framesAmount));
|
||||
File.WriteAllLines(concatFile, IoUtils.ReadLines(framesFileFull).Skip(firstFrameNum).Take(framesAmount));
|
||||
|
||||
List<string> inputFrames = JsonConvert.DeserializeObject<List<string>>(File.ReadAllText(framesFileFull + ".inputframes.json")).Skip(firstFrameNum).Take(framesAmount).ToList();
|
||||
|
@ -271,8 +271,8 @@ namespace Flowframes.Main
|
|||
|
||||
string max = Config.Get(Config.Key.maxFps);
|
||||
Fraction maxFps = max.Contains("/") ? new Fraction(max) : new Fraction(max.GetFloat());
|
||||
bool fpsLimit = maxFps.GetFloat() != 0 && I.current.outFps.GetFloat() > maxFps.GetFloat();
|
||||
VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(I.current.inPath);
|
||||
bool fpsLimit = maxFps.GetFloat() != 0 && I.currentSettings.outFps.GetFloat() > maxFps.GetFloat();
|
||||
VidExtraData extraData = await FfmpegCommands.GetVidExtraInfo(I.currentSettings.inPath);
|
||||
|
||||
bool dontEncodeFullFpsVid = fpsLimit && Config.GetInt(Config.Key.maxFpsMode) == 0;
|
||||
|
||||
|
@ -283,7 +283,7 @@ namespace Flowframes.Main
|
|||
|
||||
if (!dontEncodeFullFpsVid)
|
||||
{
|
||||
string outFolderPath = Path.Combine(I.current.outPath, await IoUtils.GetCurrentExportFilename(false, false));
|
||||
string outFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(false, false));
|
||||
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
|
||||
|
@ -292,27 +292,27 @@ namespace Flowframes.Main
|
|||
if (desiredFormat.ToUpper() == availableFormat.ToUpper()) // Move if frames are already in the desired format
|
||||
await CopyOutputFrames(interpDir, concatFile, outFolderPath, startNo, fpsLimit, true);
|
||||
else // Encode if frames are not in desired format
|
||||
await FfmpegEncode.FramesToFrames(concatFile, outFolderPath, startNo, I.current.outFps, new Fraction(), desiredFormat, GetImgSeqQ(desiredFormat), AvProcess.LogMode.Hidden);
|
||||
await FfmpegEncode.FramesToFrames(concatFile, outFolderPath, startNo, I.currentSettings.outFps, new Fraction(), desiredFormat, GetImgSeqQ(desiredFormat), AvProcess.LogMode.Hidden);
|
||||
}
|
||||
|
||||
if (fpsLimit)
|
||||
{
|
||||
string outputFolderPath = Path.Combine(I.current.outPath, await IoUtils.GetCurrentExportFilename(true, false));
|
||||
string outputFolderPath = Path.Combine(I.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(true, false));
|
||||
int startNumber = IoUtils.GetAmountOfFiles(outputFolderPath, false) + 1;
|
||||
await FfmpegEncode.FramesToFrames(concatFile, outputFolderPath, startNumber, I.current.outFps, maxFps, desiredFormat, GetImgSeqQ(desiredFormat), AvProcess.LogMode.Hidden);
|
||||
await FfmpegEncode.FramesToFrames(concatFile, outputFolderPath, startNumber, I.currentSettings.outFps, maxFps, desiredFormat, GetImgSeqQ(desiredFormat), AvProcess.LogMode.Hidden);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!dontEncodeFullFpsVid)
|
||||
await FfmpegEncode.FramesToVideo(concatFile, outPath, mode, I.current.outFps, new Fraction(), I.current.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode
|
||||
await FfmpegEncode.FramesToVideo(concatFile, outPath, mode, I.currentSettings.outFps, new Fraction(), I.currentSettings.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode
|
||||
|
||||
if (fpsLimit)
|
||||
{
|
||||
string filename = Path.GetFileName(outPath);
|
||||
string newParentDir = outPath.GetParentDir() + Paths.fpsLimitSuffix;
|
||||
outPath = Path.Combine(newParentDir, filename);
|
||||
await FfmpegEncode.FramesToVideo(concatFile, outPath, mode, I.current.outFps, maxFps, I.current.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode with limited fps
|
||||
await FfmpegEncode.FramesToVideo(concatFile, outPath, mode, I.currentSettings.outFps, maxFps, I.currentSettings.outItsScale, extraData, AvProcess.LogMode.Hidden, true); // Encode with limited fps
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,9 +332,9 @@ namespace Flowframes.Main
|
|||
{
|
||||
int times = -1;
|
||||
int minLength = Config.GetInt(Config.Key.minOutVidLength);
|
||||
int minFrameCount = (minLength * I.current.outFps.GetFloat()).RoundToInt();
|
||||
int outFrames = ((await I.GetCurrentInputFrameCount()) * I.current.interpFactor).RoundToInt();
|
||||
if (outFrames / I.current.outFps.GetFloat() < minLength)
|
||||
int minFrameCount = (minLength * I.currentSettings.outFps.GetFloat()).RoundToInt();
|
||||
int outFrames = (I.currentMediaFile.FrameCount * I.currentSettings.interpFactor).RoundToInt();
|
||||
if (outFrames / I.currentSettings.outFps.GetFloat() < minLength)
|
||||
times = (int)Math.Ceiling((double)minFrameCount / (double)outFrames);
|
||||
times--; // Not counting the 1st play (0 loops)
|
||||
if (times <= 0) return -1; // Never try to loop 0 times, idk what would happen, probably nothing
|
||||
|
@ -355,7 +355,7 @@ namespace Flowframes.Main
|
|||
if(showLog)
|
||||
Program.mainForm.SetStatus("Muxing audio/subtitles into video...");
|
||||
|
||||
if (I.current.inputIsFrames)
|
||||
if (I.currentSettings.inputIsFrames)
|
||||
{
|
||||
Logger.Log("Skipping muxing from input step as there is no input video, only frames.", true);
|
||||
return;
|
||||
|
@ -363,7 +363,7 @@ namespace Flowframes.Main
|
|||
|
||||
try
|
||||
{
|
||||
await FfmpegAudioAndMetadata.MergeStreamsFromInput(inputPath, outVideo, I.current.tempFolder, shortest);
|
||||
await FfmpegAudioAndMetadata.MergeStreamsFromInput(inputPath, outVideo, I.currentSettings.tempFolder, shortest);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -55,12 +55,12 @@ namespace Flowframes.Main
|
|||
|
||||
bool loop = Config.GetBool(Config.Key.enableLoop);
|
||||
bool sceneDetection = true;
|
||||
string ext = Interpolate.current.interpExt;
|
||||
string ext = Interpolate.currentSettings.interpExt;
|
||||
|
||||
frameFileContents.Clear();
|
||||
lastOutFileCount = 0;
|
||||
|
||||
frameFiles = new DirectoryInfo(framesPath).GetFiles("*" + Interpolate.current.framesExt);
|
||||
frameFiles = new DirectoryInfo(framesPath).GetFiles("*" + Interpolate.currentSettings.framesExt);
|
||||
frameFilesWithoutLast = frameFiles;
|
||||
Array.Resize(ref frameFilesWithoutLast, frameFilesWithoutLast.Length - 1);
|
||||
string framesFile = Path.Combine(framesPath.GetParentDir(), Paths.GetFrameOrderFilename(interpFactor));
|
||||
|
@ -168,7 +168,7 @@ namespace Flowframes.Main
|
|||
{
|
||||
int totalFileCount = 0;
|
||||
bool blendSceneChances = Config.GetInt(Config.Key.sceneChangeFillMode) > 0;
|
||||
string ext = Interpolate.current.interpExt;
|
||||
string ext = Interpolate.currentSettings.interpExt;
|
||||
Fraction step = new Fraction(sourceFrameCount, targetFrameCount + InterpolateUtils.GetRoundedInterpFramesPerInputFrame(factor));
|
||||
|
||||
List<FrameFileLine> lines = new List<FrameFileLine>();
|
||||
|
@ -235,7 +235,7 @@ namespace Flowframes.Main
|
|||
{
|
||||
int totalFileCount = (startIndex) * factor;
|
||||
int interpFramesAmount = factor;
|
||||
string ext = Interpolate.current.interpExt;
|
||||
string ext = Interpolate.currentSettings.interpExt;
|
||||
|
||||
string fileContent = "";
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@ namespace Flowframes
|
|||
{
|
||||
public enum OutMode { VidMp4, VidMkv, VidWebm, VidProRes, VidAvi, VidGif, ImgPng }
|
||||
|
||||
public static int currentInputFrameCount;
|
||||
public static bool currentlyUsingAutoEnc;
|
||||
public static InterpSettings current;
|
||||
public static InterpSettings currentSettings;
|
||||
public static MediaFile currentMediaFile;
|
||||
public static bool canceled = false;
|
||||
static Stopwatch sw = new Stopwatch();
|
||||
|
||||
|
@ -36,18 +36,17 @@ namespace Flowframes
|
|||
canceled = false;
|
||||
Program.initialRun = false;
|
||||
Program.mainForm.SetWorking(true);
|
||||
if (!Utils.InputIsValid(current.inPath, current.outPath, current.inFps, current.interpFactor, current.outMode, current.tempFolder)) return; // General input checks
|
||||
if (!Utils.CheckAiAvailable(current.ai, current.model)) return; // Check if selected AI pkg is installed
|
||||
if (!Utils.InputIsValid(currentSettings)) return; // General input checks
|
||||
if (!Utils.CheckPathValid(currentSettings.inPath)) return; // Check if input path/file is valid
|
||||
if (!Utils.CheckAiAvailable(currentSettings.ai, currentSettings.model)) return; // Check if selected AI pkg is installed
|
||||
if (!AutoEncodeResume.resumeNextRun && !Utils.CheckDeleteOldTempFolder()) return; // Try to delete temp folder if an old one exists
|
||||
if (!Utils.CheckPathValid(current.inPath)) return; // Check if input path/file is valid
|
||||
if (!(await Utils.CheckEncoderValid(current.outFps.GetFloat()))) return; // Check encoder compat
|
||||
Utils.ShowWarnings(current.interpFactor, current.ai);
|
||||
currentInputFrameCount = await GetFrameCountCached.GetFrameCountAsync(current.inPath);
|
||||
current.stepByStep = false;
|
||||
if (!(await Utils.CheckEncoderValid(currentSettings.outFps.GetFloat()))) return; // Check encoder compat
|
||||
Utils.ShowWarnings(currentSettings.interpFactor, currentSettings.ai);
|
||||
currentSettings.stepByStep = false;
|
||||
Program.mainForm.SetStatus("Starting...");
|
||||
sw.Restart();
|
||||
|
||||
if (!AutoEncodeResume.resumeNextRun && !(current.ai.Piped && !current.inputIsFrames && Config.GetInt(Config.Key.dedupMode) == 0))
|
||||
if (!AutoEncodeResume.resumeNextRun && !(currentSettings.ai.Piped && !currentSettings.inputIsFrames && Config.GetInt(Config.Key.dedupMode) == 0))
|
||||
{
|
||||
await GetFrames();
|
||||
if (canceled) return;
|
||||
|
@ -57,19 +56,19 @@ namespace Flowframes
|
|||
if (canceled) return;
|
||||
bool skip = await AutoEncodeResume.PrepareResumedRun();
|
||||
if (skip || canceled) return;
|
||||
await RunAi(current.interpFolder, current.ai);
|
||||
await RunAi(currentSettings.interpFolder, currentSettings.ai);
|
||||
if (canceled) return;
|
||||
Program.mainForm.SetProgress(100);
|
||||
|
||||
if (!currentlyUsingAutoEnc)
|
||||
{
|
||||
if (current.ai.Piped)
|
||||
await Export.MuxPipedVideo(current.inPath, current.FullOutPath);
|
||||
if (currentSettings.ai.Piped)
|
||||
await Export.MuxPipedVideo(currentSettings.inPath, currentSettings.FullOutPath);
|
||||
else
|
||||
await Export.ExportFrames(current.interpFolder, current.outPath, current.outMode, false);
|
||||
await Export.ExportFrames(currentSettings.interpFolder, currentSettings.outPath, currentSettings.outMode, false);
|
||||
}
|
||||
|
||||
if (!AutoEncodeResume.resumeNextRun && Config.GetBool(Config.Key.keepTempFolder) && IoUtils.GetAmountOfFiles(current.framesFolder, false) > 0)
|
||||
if (!AutoEncodeResume.resumeNextRun && Config.GetBool(Config.Key.keepTempFolder) && IoUtils.GetAmountOfFiles(currentSettings.framesFolder, false) > 0)
|
||||
await Task.Run(async () => { await FrameRename.Unrename(); });
|
||||
|
||||
await Done();
|
||||
|
@ -90,48 +89,40 @@ namespace Flowframes
|
|||
|
||||
public static async Task Realtime ()
|
||||
{
|
||||
await AiProcess.RunRifeNcnnVs(current.framesFolder, "", current.interpFactor, current.model.dir, true);
|
||||
}
|
||||
|
||||
public static async Task<int> GetCurrentInputFrameCount()
|
||||
{
|
||||
if (currentInputFrameCount < 2)
|
||||
currentInputFrameCount = await GetFrameCountCached.GetFrameCountAsync(current.inPath);
|
||||
|
||||
return currentInputFrameCount;
|
||||
await AiProcess.RunRifeNcnnVs(currentSettings.framesFolder, "", currentSettings.interpFactor, currentSettings.model.dir, true);
|
||||
}
|
||||
|
||||
public static async Task GetFrames()
|
||||
{
|
||||
current.RefreshAlpha();
|
||||
current.RefreshExtensions(InterpSettings.FrameType.Import);
|
||||
currentSettings.RefreshAlpha();
|
||||
currentSettings.RefreshExtensions(InterpSettings.FrameType.Import);
|
||||
|
||||
if (Config.GetBool(Config.Key.scnDetect))
|
||||
{
|
||||
Program.mainForm.SetStatus("Extracting scenes from video...");
|
||||
await FfmpegExtract.ExtractSceneChanges(current.inPath, Path.Combine(current.tempFolder, Paths.scenesDir), current.inFpsDetected, current.inputIsFrames, current.framesExt);
|
||||
await FfmpegExtract.ExtractSceneChanges(currentSettings.inPath, Path.Combine(currentSettings.tempFolder, Paths.scenesDir), currentSettings.inFpsDetected, currentSettings.inputIsFrames, currentSettings.framesExt);
|
||||
}
|
||||
|
||||
if (!current.inputIsFrames) // Extract if input is video, import if image sequence
|
||||
await ExtractFrames(current.inPath, current.framesFolder, current.alpha);
|
||||
if (!currentSettings.inputIsFrames) // Extract if input is video, import if image sequence
|
||||
await ExtractFrames(currentSettings.inPath, currentSettings.framesFolder, currentSettings.alpha);
|
||||
else
|
||||
await FfmpegExtract.ImportImagesCheckCompat(current.inPath, current.framesFolder, current.alpha, current.ScaledResolution, true, current.framesExt);
|
||||
await FfmpegExtract.ImportImagesCheckCompat(currentSettings.inPath, currentSettings.framesFolder, currentSettings.alpha, currentSettings.ScaledResolution, true, currentSettings.framesExt);
|
||||
}
|
||||
|
||||
public static async Task ExtractFrames(string inPath, string outPath, bool alpha)
|
||||
{
|
||||
if (canceled) return;
|
||||
Program.mainForm.SetStatus("Extracting frames from video...");
|
||||
current.RefreshExtensions(InterpSettings.FrameType.Import);
|
||||
currentSettings.RefreshExtensions(InterpSettings.FrameType.Import);
|
||||
bool mpdecimate = Config.GetInt(Config.Key.dedupMode) == 2;
|
||||
Size res = await Utils.GetOutputResolution(inPath, true, true);
|
||||
await FfmpegExtract.VideoToFrames(inPath, outPath, alpha, current.inFpsDetected, mpdecimate, false, res, current.framesExt);
|
||||
await FfmpegExtract.VideoToFrames(inPath, outPath, alpha, currentSettings.inFpsDetected, mpdecimate, false, res, currentSettings.framesExt);
|
||||
|
||||
if (mpdecimate)
|
||||
{
|
||||
int framesLeft = IoUtils.GetAmountOfFiles(outPath, false, "*" + current.framesExt);
|
||||
int framesDeleted = currentInputFrameCount - framesLeft;
|
||||
float percentDeleted = ((float)framesDeleted / currentInputFrameCount) * 100f;
|
||||
int framesLeft = IoUtils.GetAmountOfFiles(outPath, false, "*" + currentSettings.framesExt);
|
||||
int framesDeleted = currentMediaFile.FrameCount - framesLeft;
|
||||
float percentDeleted = ((float)framesDeleted / currentMediaFile.FrameCount) * 100f;
|
||||
string keptPercent = $"{(100f - percentDeleted).ToString("0.0")}%";
|
||||
|
||||
if (QuickSettingsTab.trimEnabled)
|
||||
|
@ -141,7 +132,7 @@ namespace Flowframes
|
|||
}
|
||||
|
||||
if (!Config.GetBool("allowConsecutiveSceneChanges", true))
|
||||
Utils.FixConsecutiveSceneFrames(Path.Combine(current.tempFolder, Paths.scenesDir), current.framesFolder);
|
||||
Utils.FixConsecutiveSceneFrames(Path.Combine(currentSettings.tempFolder, Paths.scenesDir), currentSettings.framesFolder);
|
||||
}
|
||||
|
||||
public static async Task PostProcessFrames(bool stepByStep)
|
||||
|
@ -150,31 +141,31 @@ namespace Flowframes
|
|||
|
||||
Program.mainForm.SetStatus("Processing frames...");
|
||||
|
||||
int extractedFrames = IoUtils.GetAmountOfFiles(current.framesFolder, false, "*" + current.framesExt);
|
||||
int extractedFrames = IoUtils.GetAmountOfFiles(currentSettings.framesFolder, false, "*" + currentSettings.framesExt);
|
||||
|
||||
if (!Directory.Exists(current.framesFolder) || currentInputFrameCount <= 0 || extractedFrames < 2)
|
||||
if (!Directory.Exists(currentSettings.framesFolder) || currentMediaFile.FrameCount <= 0 || extractedFrames < 2)
|
||||
{
|
||||
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(current.framesFolder)} - currentInputFrameCount = {currentInputFrameCount} - extractedFrames = {extractedFrames}.\n\nYour input file might be incompatible.");
|
||||
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.");
|
||||
}
|
||||
|
||||
if (Config.GetInt(Config.Key.dedupMode) == 1)
|
||||
await Dedupe.Run(current.framesFolder);
|
||||
await Dedupe.Run(currentSettings.framesFolder);
|
||||
else
|
||||
Dedupe.ClearCache();
|
||||
|
||||
if (!Config.GetBool(Config.Key.enableLoop))
|
||||
{
|
||||
await Utils.CopyLastFrame(currentInputFrameCount);
|
||||
await Utils.CopyLastFrame(currentMediaFile.FrameCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileInfo[] frameFiles = IoUtils.GetFileInfosSorted(current.framesFolder);
|
||||
FileInfo[] frameFiles = IoUtils.GetFileInfosSorted(currentSettings.framesFolder);
|
||||
string ext = frameFiles.First().Extension;
|
||||
int lastNum = frameFiles.Last().Name.GetInt() + 1;
|
||||
string loopFrameTargetPath = Path.Combine(current.framesFolder, lastNum.ToString().PadLeft(Padding.inputFrames, '0') + ext);
|
||||
string loopFrameTargetPath = Path.Combine(currentSettings.framesFolder, lastNum.ToString().PadLeft(Padding.inputFrames, '0') + ext);
|
||||
File.Copy(frameFiles.First().FullName, loopFrameTargetPath, true);
|
||||
Logger.Log($"Copied loop frame to {loopFrameTargetPath}.", true);
|
||||
}
|
||||
|
@ -186,42 +177,42 @@ namespace Flowframes
|
|||
|
||||
bool dedupe = Config.GetInt(Config.Key.dedupMode) != 0;
|
||||
|
||||
if (!ai.Piped || (ai.Piped && current.inputIsFrames) || (ai.Piped && dedupe))
|
||||
if (!ai.Piped || (ai.Piped && currentSettings.inputIsFrames) || (ai.Piped && dedupe))
|
||||
{
|
||||
await Task.Run(async () => { await Dedupe.CreateDupesFile(current.framesFolder, currentInputFrameCount, current.framesExt); });
|
||||
await Task.Run(async () => { await Dedupe.CreateDupesFile(currentSettings.framesFolder, currentMediaFile.FrameCount, currentSettings.framesExt); });
|
||||
await Task.Run(async () => { await FrameRename.Rename(); });
|
||||
}
|
||||
|
||||
if (!ai.Piped || (ai.Piped && dedupe))
|
||||
await Task.Run(async () => { await FrameOrder.CreateFrameOrderFile(current.framesFolder, Config.GetBool(Config.Key.enableLoop), current.interpFactor); });
|
||||
await Task.Run(async () => { await FrameOrder.CreateFrameOrderFile(currentSettings.framesFolder, Config.GetBool(Config.Key.enableLoop), currentSettings.interpFactor); });
|
||||
|
||||
Program.mainForm.SetStatus("Downloading models...");
|
||||
await ModelDownloader.DownloadModelFiles(ai, current.model.dir);
|
||||
await ModelDownloader.DownloadModelFiles(ai, currentSettings.model.dir);
|
||||
if (canceled) return;
|
||||
|
||||
currentlyUsingAutoEnc = Utils.CanUseAutoEnc(stepByStep, current);
|
||||
currentlyUsingAutoEnc = Utils.CanUseAutoEnc(stepByStep, currentSettings);
|
||||
|
||||
IoUtils.CreateDir(outpath);
|
||||
|
||||
List<Task> tasks = new List<Task>();
|
||||
|
||||
if (ai.AiName == Implementations.rifeCuda.AiName)
|
||||
tasks.Add(AiProcess.RunRifeCuda(current.framesFolder, current.interpFactor, current.model.dir));
|
||||
tasks.Add(AiProcess.RunRifeCuda(currentSettings.framesFolder, currentSettings.interpFactor, currentSettings.model.dir));
|
||||
|
||||
if (ai.AiName == Implementations.rifeNcnn.AiName)
|
||||
tasks.Add(AiProcess.RunRifeNcnn(current.framesFolder, outpath, current.interpFactor, current.model.dir));
|
||||
tasks.Add(AiProcess.RunRifeNcnn(currentSettings.framesFolder, outpath, currentSettings.interpFactor, currentSettings.model.dir));
|
||||
|
||||
if (ai.AiName == Implementations.rifeNcnnVs.AiName)
|
||||
tasks.Add(AiProcess.RunRifeNcnnVs(current.framesFolder, outpath, current.interpFactor, current.model.dir));
|
||||
tasks.Add(AiProcess.RunRifeNcnnVs(currentSettings.framesFolder, outpath, currentSettings.interpFactor, currentSettings.model.dir));
|
||||
|
||||
if (ai.AiName == Implementations.flavrCuda.AiName)
|
||||
tasks.Add(AiProcess.RunFlavrCuda(current.framesFolder, current.interpFactor, current.model.dir));
|
||||
tasks.Add(AiProcess.RunFlavrCuda(currentSettings.framesFolder, currentSettings.interpFactor, currentSettings.model.dir));
|
||||
|
||||
if (ai.AiName == Implementations.dainNcnn.AiName)
|
||||
tasks.Add(AiProcess.RunDainNcnn(current.framesFolder, outpath, current.interpFactor, current.model.dir, Config.GetInt(Config.Key.dainNcnnTilesize, 512)));
|
||||
tasks.Add(AiProcess.RunDainNcnn(currentSettings.framesFolder, outpath, currentSettings.interpFactor, currentSettings.model.dir, Config.GetInt(Config.Key.dainNcnnTilesize, 512)));
|
||||
|
||||
if (ai.AiName == Implementations.xvfiCuda.AiName)
|
||||
tasks.Add(AiProcess.RunXvfiCuda(current.framesFolder, current.interpFactor, current.model.dir));
|
||||
tasks.Add(AiProcess.RunXvfiCuda(currentSettings.framesFolder, currentSettings.interpFactor, currentSettings.model.dir));
|
||||
|
||||
if (currentlyUsingAutoEnc)
|
||||
{
|
||||
|
@ -235,7 +226,7 @@ namespace Flowframes
|
|||
|
||||
public static void Cancel(string reason = "", bool noMsgBox = false)
|
||||
{
|
||||
if (current == null)
|
||||
if (currentSettings == null)
|
||||
return;
|
||||
|
||||
canceled = true;
|
||||
|
@ -244,18 +235,18 @@ namespace Flowframes
|
|||
AiProcess.Kill();
|
||||
AvProcess.Kill();
|
||||
|
||||
if (!current.stepByStep && !Config.GetBool(Config.Key.keepTempFolder))
|
||||
if (!currentSettings.stepByStep && !Config.GetBool(Config.Key.keepTempFolder))
|
||||
{
|
||||
if (!BatchProcessing.busy && IoUtils.GetAmountOfFiles(Path.Combine(current.tempFolder, Paths.resumeDir), true) > 0)
|
||||
if (!BatchProcessing.busy && IoUtils.GetAmountOfFiles(Path.Combine(currentSettings.tempFolder, Paths.resumeDir), true) > 0)
|
||||
{
|
||||
DialogResult dialogResult = MessageBox.Show($"Delete the temp folder (Yes) or keep it for resuming later (No)?", "Delete temporary files?", MessageBoxButtons.YesNo);
|
||||
|
||||
if (dialogResult == DialogResult.Yes)
|
||||
Task.Run(async () => { await IoUtils.TryDeleteIfExistsAsync(current.tempFolder); });
|
||||
Task.Run(async () => { await IoUtils.TryDeleteIfExistsAsync(currentSettings.tempFolder); });
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.Run(async () => { await IoUtils.TryDeleteIfExistsAsync(current.tempFolder); });
|
||||
Task.Run(async () => { await IoUtils.TryDeleteIfExistsAsync(currentSettings.tempFolder); });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,7 +266,7 @@ namespace Flowframes
|
|||
Logger.Log("Deleting temporary files...");
|
||||
try
|
||||
{
|
||||
await Task.Run(async () => { Directory.Delete(current.tempFolder, true); });
|
||||
await Task.Run(async () => { Directory.Delete(currentSettings.tempFolder, true); });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -20,22 +20,22 @@ namespace Flowframes.Main
|
|||
canceled = false;
|
||||
Program.mainForm.SetWorking(true);
|
||||
|
||||
if(current == null)
|
||||
if(currentSettings == null)
|
||||
{
|
||||
Logger.Log($"[SBS] Getting new current settings", true);
|
||||
current = Program.mainForm.GetCurrentSettings();
|
||||
currentSettings = Program.mainForm.GetCurrentSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"[SBS] Updating current settings", true);
|
||||
current = Program.mainForm.UpdateCurrentSettings(current);
|
||||
currentSettings = Program.mainForm.UpdateCurrentSettings(currentSettings);
|
||||
}
|
||||
|
||||
current.RefreshAlpha();
|
||||
current.stepByStep = true;
|
||||
currentSettings.RefreshAlpha();
|
||||
currentSettings.stepByStep = true;
|
||||
|
||||
if (!InterpolateUtils.InputIsValid(current.inPath, current.outPath, current.inFps, current.interpFactor, current.outMode, current.tempFolder)) return; // General input checks
|
||||
if (!InterpolateUtils.CheckPathValid(current.inPath)) return; // Check if input path/file is valid
|
||||
if (!InterpolateUtils.InputIsValid(currentSettings)) return; // General input checks
|
||||
if (!InterpolateUtils.CheckPathValid(currentSettings.inPath)) return; // Check if input path/file is valid
|
||||
|
||||
if (step.Contains("Extract Frames"))
|
||||
await ExtractFramesStep();
|
||||
|
@ -56,25 +56,23 @@ namespace Flowframes.Main
|
|||
|
||||
public static async Task ExtractFramesStep()
|
||||
{
|
||||
if (!(await IoUtils.TryDeleteIfExistsAsync(current.framesFolder)))
|
||||
if (!(await IoUtils.TryDeleteIfExistsAsync(currentSettings.framesFolder)))
|
||||
{
|
||||
UiUtils.ShowMessageBox("Failed to delete existing frames folder - Make sure no file is opened in another program!", UiUtils.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
currentInputFrameCount = await GetFrameCountCached.GetFrameCountAsync(current.inPath);
|
||||
|
||||
await GetFrames();
|
||||
await PostProcessFrames(true);
|
||||
}
|
||||
|
||||
public static async Task InterpolateStep()
|
||||
{
|
||||
if (!InterpolateUtils.CheckAiAvailable(current.ai, current.model)) return;
|
||||
if (!InterpolateUtils.CheckAiAvailable(currentSettings.ai, currentSettings.model)) return;
|
||||
|
||||
current.framesFolder = Path.Combine(current.tempFolder, Paths.framesDir);
|
||||
currentSettings.framesFolder = Path.Combine(currentSettings.tempFolder, Paths.framesDir);
|
||||
|
||||
if (IoUtils.GetAmountOfFiles(current.framesFolder, false, "*") < 2)
|
||||
if (IoUtils.GetAmountOfFiles(currentSettings.framesFolder, false, "*") < 2)
|
||||
{
|
||||
if (Config.GetBool(Config.Key.sbsRunPreviousStepIfNeeded))
|
||||
{
|
||||
|
@ -82,33 +80,31 @@ namespace Flowframes.Main
|
|||
await ExtractFramesStep();
|
||||
}
|
||||
|
||||
if (IoUtils.GetAmountOfFiles(current.framesFolder, false, "*") < 2)
|
||||
if (IoUtils.GetAmountOfFiles(currentSettings.framesFolder, false, "*") < 2)
|
||||
{
|
||||
UiUtils.ShowMessageBox("There are no extracted frames that can be interpolated!\nDid you run the extraction step?", UiUtils.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(await IoUtils.TryDeleteIfExistsAsync(current.interpFolder)))
|
||||
if (!(await IoUtils.TryDeleteIfExistsAsync(currentSettings.interpFolder)))
|
||||
{
|
||||
UiUtils.ShowMessageBox("Failed to delete existing frames folder - Make sure no file is opened in another program!", UiUtils.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
currentInputFrameCount = await GetFrameCountCached.GetFrameCountAsync(current.inPath);
|
||||
|
||||
if (Config.GetBool(Config.Key.sbsAllowAutoEnc) && !(await InterpolateUtils.CheckEncoderValid(current.outFps.GetFloat()))) return;
|
||||
if (Config.GetBool(Config.Key.sbsAllowAutoEnc) && !(await InterpolateUtils.CheckEncoderValid(currentSettings.outFps.GetFloat()))) return;
|
||||
|
||||
if (canceled) return;
|
||||
Program.mainForm.SetStatus("Running AI...");
|
||||
await RunAi(current.interpFolder, current.ai, true);
|
||||
await RunAi(currentSettings.interpFolder, currentSettings.ai, true);
|
||||
await Task.Run(async () => { await FrameRename.Unrename(); }); // Get timestamps back
|
||||
Program.mainForm.SetProgress(0);
|
||||
}
|
||||
|
||||
public static async Task CreateOutputVid()
|
||||
{
|
||||
if (IoUtils.GetAmountOfFiles(current.interpFolder, false) < 2)
|
||||
if (IoUtils.GetAmountOfFiles(currentSettings.interpFolder, false) < 2)
|
||||
{
|
||||
if (Config.GetBool(Config.Key.sbsRunPreviousStepIfNeeded))
|
||||
{
|
||||
|
@ -116,16 +112,16 @@ namespace Flowframes.Main
|
|||
await InterpolateStep();
|
||||
}
|
||||
|
||||
if (IoUtils.GetAmountOfFiles(current.interpFolder, false) < 2)
|
||||
if (IoUtils.GetAmountOfFiles(currentSettings.interpFolder, false) < 2)
|
||||
{
|
||||
Cancel($"There are no interpolated frames to encode!\n\nDid you delete the folder?");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(await InterpolateUtils.CheckEncoderValid(current.outFps.GetFloat()))) return;
|
||||
if (!(await InterpolateUtils.CheckEncoderValid(currentSettings.outFps.GetFloat()))) return;
|
||||
|
||||
string[] outFrames = IoUtils.GetFilesSorted(current.interpFolder, current.interpExt);
|
||||
string[] outFrames = IoUtils.GetFilesSorted(currentSettings.interpFolder, currentSettings.interpExt);
|
||||
|
||||
if (outFrames.Length > 0 && !IoUtils.CheckImageValid(outFrames[0]))
|
||||
{
|
||||
|
@ -134,7 +130,7 @@ namespace Flowframes.Main
|
|||
return;
|
||||
}
|
||||
|
||||
await Export.ExportFrames(current.interpFolder, current.outPath, current.outMode, true);
|
||||
await Export.ExportFrames(currentSettings.interpFolder, currentSettings.outPath, currentSettings.outMode, true);
|
||||
}
|
||||
|
||||
public static async Task Reset()
|
||||
|
|
|
@ -28,20 +28,20 @@ namespace Flowframes.Main
|
|||
try
|
||||
{
|
||||
lastFrameNum--; // We have to do this as extracted frames start at 0, not 1
|
||||
bool frameFolderInput = IoUtils.IsPathDirectory(I.current.inPath);
|
||||
string targetPath = Path.Combine(I.current.framesFolder, lastFrameNum.ToString().PadLeft(Padding.inputFrames, '0') + I.current.framesExt);
|
||||
bool frameFolderInput = IoUtils.IsPathDirectory(I.currentSettings.inPath);
|
||||
string targetPath = Path.Combine(I.currentSettings.framesFolder, lastFrameNum.ToString().PadLeft(Padding.inputFrames, '0') + I.currentSettings.framesExt);
|
||||
if (File.Exists(targetPath)) return;
|
||||
|
||||
Size res = IoUtils.GetImage(IoUtils.GetFilesSorted(I.current.framesFolder, false).First()).Size;
|
||||
Size res = IoUtils.GetImage(IoUtils.GetFilesSorted(I.currentSettings.framesFolder, false).First()).Size;
|
||||
|
||||
if (frameFolderInput)
|
||||
{
|
||||
string lastFramePath = IoUtils.GetFilesSorted(I.current.inPath, false).Last();
|
||||
string lastFramePath = IoUtils.GetFilesSorted(I.currentSettings.inPath, false).Last();
|
||||
await FfmpegExtract.ExtractLastFrame(lastFramePath, targetPath, res);
|
||||
}
|
||||
else
|
||||
{
|
||||
await FfmpegExtract.ExtractLastFrame(I.current.inPath, targetPath, res);
|
||||
await FfmpegExtract.ExtractLastFrame(I.currentSettings.inPath, targetPath, res);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -95,44 +95,43 @@ namespace Flowframes.Main
|
|||
return Path.Combine(basePath, Path.GetFileNameWithoutExtension(inPath).StripBadChars().Remove(" ").Trunc(30, false) + "-temp");
|
||||
}
|
||||
|
||||
public static bool InputIsValid(string inDir, string outDir, Fraction fpsIn, float factor, I.OutMode outMode, string tempFolder)
|
||||
public static bool InputIsValid(InterpSettings s)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool passes = true;
|
||||
bool isFile = !IoUtils.IsPathDirectory(inDir);
|
||||
float fpsOut = fpsIn.GetFloat() * factor;
|
||||
bool isFile = !IoUtils.IsPathDirectory(s.inPath);
|
||||
|
||||
if ((passes && isFile && !IoUtils.IsFileValid(inDir)) || (!isFile && !IoUtils.IsDirValid(inDir)))
|
||||
if ((passes && isFile && !IoUtils.IsFileValid(s.inPath)) || (!isFile && !IoUtils.IsDirValid(s.inPath)))
|
||||
{
|
||||
UiUtils.ShowMessageBox("Input path is not valid!");
|
||||
passes = false;
|
||||
}
|
||||
|
||||
if (passes && !IoUtils.IsDirValid(outDir))
|
||||
if (passes && !IoUtils.IsDirValid(s.outPath))
|
||||
{
|
||||
UiUtils.ShowMessageBox("Output path is not valid!");
|
||||
passes = false;
|
||||
}
|
||||
|
||||
if (passes && tempFolder.StartsWith(@"\\"))
|
||||
if (passes && s.tempFolder.StartsWith(@"\\"))
|
||||
{
|
||||
UiUtils.ShowMessageBox("Flowframes does not support UNC/Network paths as a temp folder!\nPlease use a local path instead.");
|
||||
passes = false;
|
||||
}
|
||||
|
||||
if (passes && fpsOut < 1f || fpsOut > 1000f)
|
||||
if (passes && s.outFps.GetFloat() < 1f || s.outFps.GetFloat() > 1000f)
|
||||
{
|
||||
string imgSeqNote = isFile ? "" : "\n\nWhen using an image sequence as input, you always have to specify the frame rate manually.";
|
||||
UiUtils.ShowMessageBox($"Invalid output frame rate ({fpsOut}).\nMust be 1-1000.{imgSeqNote}");
|
||||
UiUtils.ShowMessageBox($"Invalid output frame rate ({s.outFps.GetFloat()}).\nMust be 1-1000.{imgSeqNote}");
|
||||
passes = false;
|
||||
}
|
||||
|
||||
string fpsLimitValue = Config.Get(Config.Key.maxFps);
|
||||
float fpsLimit = (fpsLimitValue.Contains("/") ? new Fraction(Config.Get(Config.Key.maxFps)).GetFloat() : fpsLimitValue.GetFloat());
|
||||
|
||||
if (outMode == I.OutMode.VidGif && fpsOut > 50 && !(fpsLimit > 0 && fpsLimit <= 50))
|
||||
Logger.Log($"Warning: GIF will be encoded at 50 FPS instead of {fpsOut} as the format doesn't support frame rates that high.");
|
||||
if (s.outMode == I.OutMode.VidGif && s.outFps.GetFloat() > 50 && !(fpsLimit > 0 && fpsLimit <= 50))
|
||||
Logger.Log($"Warning: GIF will be encoded at 50 FPS instead of {s.outFps.GetFloat()} as the format doesn't support frame rates that high.");
|
||||
|
||||
if (!passes)
|
||||
I.Cancel("Invalid settings detected.", true);
|
||||
|
@ -162,7 +161,7 @@ namespace Flowframes.Main
|
|||
return false;
|
||||
}
|
||||
|
||||
if (I.current.ai.AiName.ToUpper().Contains("CUDA") && NvApi.gpuList.Count < 1)
|
||||
if (I.currentSettings.ai.AiName.ToUpper().Contains("CUDA") && NvApi.gpuList.Count < 1)
|
||||
{
|
||||
UiUtils.ShowMessageBox("Warning: No Nvidia GPU was detected. CUDA might fall back to CPU!\n\nTry an NCNN implementation instead if you don't have an Nvidia GPU.", UiUtils.MessageType.Error);
|
||||
|
||||
|
@ -178,7 +177,7 @@ namespace Flowframes.Main
|
|||
|
||||
public static bool CheckDeleteOldTempFolder()
|
||||
{
|
||||
if (!IoUtils.TryDeleteIfExists(I.current.tempFolder))
|
||||
if (!IoUtils.TryDeleteIfExists(I.currentSettings.tempFolder))
|
||||
{
|
||||
UiUtils.ShowMessageBox("Failed to remove an existing temp folder of this video!\nMake sure you didn't open any frames in an editor.", UiUtils.MessageType.Error);
|
||||
I.Cancel();
|
||||
|
@ -224,7 +223,7 @@ namespace Flowframes.Main
|
|||
|
||||
public static async Task<bool> CheckEncoderValid (float encodeFps)
|
||||
{
|
||||
string enc = FfmpegUtils.GetEnc(FfmpegUtils.GetCodec(I.current.outMode));
|
||||
string enc = FfmpegUtils.GetEnc(FfmpegUtils.GetCodec(I.currentSettings.outMode));
|
||||
|
||||
float maxAv1Fps = 240;
|
||||
|
||||
|
@ -334,7 +333,12 @@ namespace Flowframes.Main
|
|||
|
||||
public static async Task<bool> UseUhd()
|
||||
{
|
||||
return (await GetOutputResolution(I.current.inPath, false)).Height >= Config.GetInt(Config.Key.uhdThresh);
|
||||
return UseUhd(await GetOutputResolution(I.currentSettings.inPath, false));
|
||||
}
|
||||
|
||||
public static bool UseUhd(Size outputRes)
|
||||
{
|
||||
return outputRes.Height >= Config.GetInt(Config.Key.uhdThresh);
|
||||
}
|
||||
|
||||
public static void FixConsecutiveSceneFrames(string sceneFramesPath, string sourceFramesPath)
|
||||
|
@ -361,7 +365,7 @@ namespace Flowframes.Main
|
|||
}
|
||||
|
||||
foreach (string frame in sceneFramesToDelete)
|
||||
IoUtils.TryDeleteIfExists(Path.Combine(sceneFramesPath, frame + I.current.framesExt));
|
||||
IoUtils.TryDeleteIfExists(Path.Combine(sceneFramesPath, frame + I.currentSettings.framesExt));
|
||||
}
|
||||
|
||||
public static int GetRoundedInterpFramesPerInputFrame(float factor, bool roundDown = true)
|
||||
|
|
|
@ -30,10 +30,10 @@ namespace Flowframes.Main
|
|||
public static void Save ()
|
||||
{
|
||||
if (timeSinceLastSave.IsRunning && timeSinceLastSave.ElapsedMilliseconds < (timeBetweenSaves * 1000f).RoundToInt()) return;
|
||||
int frames = (int)Math.Round((float)InterpolationProgress.interpolatedInputFramesCount / I.current.interpFactor) - safetyDelayFrames;
|
||||
int frames = (int)Math.Round((float)InterpolationProgress.interpolatedInputFramesCount / I.currentSettings.interpFactor) - safetyDelayFrames;
|
||||
if (frames < 1) return;
|
||||
timeSinceLastSave.Restart();
|
||||
Directory.CreateDirectory(Path.Combine(I.current.tempFolder, Paths.resumeDir));
|
||||
Directory.CreateDirectory(Path.Combine(I.currentSettings.tempFolder, Paths.resumeDir));
|
||||
SaveState(frames);
|
||||
SaveInterpSettings();
|
||||
SaveFilenameMap();
|
||||
|
@ -42,13 +42,13 @@ namespace Flowframes.Main
|
|||
static void SaveState (int frames)
|
||||
{
|
||||
ResumeState state = new ResumeState(I.currentlyUsingAutoEnc, frames);
|
||||
string filePath = Path.Combine(I.current.tempFolder, Paths.resumeDir, resumeFilename);
|
||||
string filePath = Path.Combine(I.currentSettings.tempFolder, Paths.resumeDir, resumeFilename);
|
||||
File.WriteAllText(filePath, state.ToString());
|
||||
}
|
||||
|
||||
static async Task SaveFilenameMap ()
|
||||
{
|
||||
string filePath = Path.Combine(I.current.tempFolder, Paths.resumeDir, filenameMapFilename);
|
||||
string filePath = Path.Combine(I.currentSettings.tempFolder, Paths.resumeDir, filenameMapFilename);
|
||||
|
||||
if (File.Exists(filePath) && IoUtils.GetFilesize(filePath) > 0)
|
||||
return;
|
||||
|
@ -68,8 +68,8 @@ namespace Flowframes.Main
|
|||
|
||||
static void SaveInterpSettings ()
|
||||
{
|
||||
string filepath = Path.Combine(I.current.tempFolder, Paths.resumeDir, interpSettingsFilename);
|
||||
File.WriteAllText(filepath, I.current.Serialize());
|
||||
string filepath = Path.Combine(I.currentSettings.tempFolder, Paths.resumeDir, interpSettingsFilename);
|
||||
File.WriteAllText(filepath, I.currentSettings.Serialize());
|
||||
}
|
||||
|
||||
// public static void LoadTempFolder (string tempFolderPath)
|
||||
|
@ -106,7 +106,7 @@ namespace Flowframes.Main
|
|||
static void LoadFilenameMap()
|
||||
{
|
||||
List<string> files = new List<string>();
|
||||
string filePath = Path.Combine(I.current.tempFolder, Paths.resumeDir, filenameMapFilename);
|
||||
string filePath = Path.Combine(I.currentSettings.tempFolder, Paths.resumeDir, filenameMapFilename);
|
||||
string[] fileLines = File.ReadAllLines(filePath);
|
||||
|
||||
foreach (string line in fileLines)
|
||||
|
|
|
@ -106,6 +106,48 @@ namespace Flowframes
|
|||
return $"-hide_banner -stats -loglevel {loglevel} -y";
|
||||
}
|
||||
|
||||
public class FfprobeSettings
|
||||
{
|
||||
public string Args { get; set; } = "";
|
||||
public LogMode LoggingMode { get; set; } = LogMode.Hidden;
|
||||
public string LogLevel { get; set; } = "panic";
|
||||
public bool SetBusy { get; set; } = false;
|
||||
}
|
||||
|
||||
public static async Task<string> RunFfprobe(FfprobeSettings settings)
|
||||
{
|
||||
bool show = Config.GetInt(Config.Key.cmdDebugMode) > 0;
|
||||
string processOutput = "";
|
||||
Process ffprobe = OsUtils.NewProcess(!show);
|
||||
NmkdStopwatch timeSinceLastOutput = new NmkdStopwatch();
|
||||
|
||||
ffprobe.StartInfo.Arguments = $"{GetCmdArg()} cd /D {GetAvDir().Wrap()} & ffprobe -v {settings.LogLevel} {settings.Args}";
|
||||
|
||||
if (settings.LoggingMode != LogMode.Hidden) Logger.Log("Running FFprobe...", false);
|
||||
Logger.Log($"ffprobe -v {settings.LogLevel} {settings.Args}", true, false, "ffmpeg");
|
||||
|
||||
if (!show)
|
||||
{
|
||||
string[] ignore = new string[0];
|
||||
ffprobe.OutputDataReceived += (sender, outLine) => { AvOutputHandler.LogOutput(outLine.Data, ref processOutput, "ffmpeg", settings.LoggingMode, false); timeSinceLastOutput.sw.Restart(); };
|
||||
ffprobe.ErrorDataReceived += (sender, outLine) => { AvOutputHandler.LogOutput(outLine.Data, ref processOutput, "ffmpeg", settings.LoggingMode, false); timeSinceLastOutput.sw.Restart(); };
|
||||
}
|
||||
|
||||
ffprobe.Start();
|
||||
ffprobe.PriorityClass = ProcessPriorityClass.BelowNormal;
|
||||
|
||||
if (!show)
|
||||
{
|
||||
ffprobe.BeginOutputReadLine();
|
||||
ffprobe.BeginErrorReadLine();
|
||||
}
|
||||
|
||||
while (!ffprobe.HasExited) await Task.Delay(10);
|
||||
while (timeSinceLastOutput.ElapsedMs < 200) await Task.Delay(50);
|
||||
|
||||
return processOutput;
|
||||
}
|
||||
|
||||
public static async Task<string> RunFfprobe(string args, LogMode logMode = LogMode.Hidden, string loglevel = "quiet")
|
||||
{
|
||||
bool show = Config.GetInt(Config.Key.cmdDebugMode) > 0;
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Flowframes.Media
|
|||
|
||||
public static async Task MergeStreamsFromInput (string inputVideo, string interpVideo, string tempFolder, bool shortest)
|
||||
{
|
||||
if (!File.Exists(inputVideo) && !I.current.inputIsFrames)
|
||||
if (!File.Exists(inputVideo) && !I.currentSettings.inputIsFrames)
|
||||
{
|
||||
Logger.Log("Warning: Input video file not found, can't copy audio/subtitle streams to output video!");
|
||||
return;
|
||||
|
@ -29,9 +29,9 @@ namespace Flowframes.Media
|
|||
|
||||
string subArgs = "-c:s " + Utils.GetSubCodecForContainer(containerExt);
|
||||
|
||||
bool audioCompat = Utils.ContainerSupportsAllAudioFormats(I.current.outMode, GetAudioCodecs(inputVideo));
|
||||
bool slowmo = I.current.outItsScale != 0 && I.current.outItsScale != 1;
|
||||
string audioArgs = audioCompat && !slowmo ? "" : await Utils.GetAudioFallbackArgs(inputVideo, I.current.outMode, I.current.outItsScale);
|
||||
bool audioCompat = Utils.ContainerSupportsAllAudioFormats(I.currentSettings.outMode, GetAudioCodecs(inputVideo));
|
||||
bool slowmo = I.currentSettings.outItsScale != 0 && I.currentSettings.outItsScale != 1;
|
||||
string audioArgs = audioCompat && !slowmo ? "" : await Utils.GetAudioFallbackArgs(inputVideo, I.currentSettings.outMode, I.currentSettings.outItsScale);
|
||||
|
||||
if (!audioCompat && !slowmo)
|
||||
Logger.Log("Warning: Input audio format(s) not fully supported in output container - Will re-encode.", true, false, "ffmpeg");
|
||||
|
@ -46,7 +46,7 @@ namespace Flowframes.Media
|
|||
if (!subs || (subs && !Utils.ContainerSupportsSubs(containerExt)))
|
||||
subArgs = "-sn";
|
||||
|
||||
bool isMkv = I.current.outMode == I.OutMode.VidMkv;
|
||||
bool isMkv = I.currentSettings.outMode == I.OutMode.VidMkv;
|
||||
string mkvFix = isMkv ? "-max_interleave_delta 0" : ""; // https://reddit.com/r/ffmpeg/comments/efddfs/starting_new_cluster_due_to_timestamp/
|
||||
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" : "";
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace Flowframes
|
|||
|
||||
public static int GetPadding ()
|
||||
{
|
||||
return (Interpolate.current.ai.AiName == Implementations.flavrCuda.AiName) ? 8 : 2; // FLAVR input needs to be divisible by 8
|
||||
return (Interpolate.currentSettings.ai.AiName == Implementations.flavrCuda.AiName) ? 8 : 2; // FLAVR input needs to be divisible by 8
|
||||
}
|
||||
|
||||
public static string GetPadFilter ()
|
||||
|
@ -74,11 +74,13 @@ namespace Flowframes
|
|||
DeleteSource(inputFile);
|
||||
}
|
||||
|
||||
public static long GetDuration(string inputFile)
|
||||
public static async Task<long> GetDurationMs(string inputFile)
|
||||
{
|
||||
Logger.Log($"GetDuration({inputFile}) - Reading Duration using ffprobe.", true, false, "ffmpeg");
|
||||
string args = $" -v panic -select_streams v:0 -show_entries format=duration -of csv=s=x:p=0 -sexagesimal {inputFile.Wrap()}";
|
||||
string output = GetFfprobeOutput(args);
|
||||
string args = $"-select_streams v:0 -show_entries format=duration -of csv=s=x:p=0 -sexagesimal {inputFile.Wrap()}";
|
||||
FfprobeSettings settings = new FfprobeSettings() { Args = args };
|
||||
string output = await RunFfprobe(settings);
|
||||
|
||||
return FormatUtils.TimestampToMs(output);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Flowframes.Media
|
|||
|
||||
IoUtils.RenameExistingFile(outPath);
|
||||
Directory.CreateDirectory(outPath.GetParentDir());
|
||||
string[] encArgs = Utils.GetEncArgs(Utils.GetCodec(outMode), (Interpolate.current.ScaledResolution.IsEmpty ? Interpolate.current.InputResolution : Interpolate.current.ScaledResolution), Interpolate.current.outFps.GetFloat());
|
||||
string[] encArgs = Utils.GetEncArgs(Utils.GetCodec(outMode), (Interpolate.currentSettings.ScaledResolution.IsEmpty ? Interpolate.currentSettings.InputResolution : Interpolate.currentSettings.ScaledResolution), Interpolate.currentSettings.outFps.GetFloat());
|
||||
|
||||
string inArg = $"-f concat -i {Path.GetFileName(framesFile)}";
|
||||
string linksDir = Path.Combine(framesFile + Paths.symlinksSuffix);
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Flowframes.Media
|
|||
if (inputIsFrames)
|
||||
{
|
||||
string concatFile = Path.Combine(Paths.GetDataPath(), "png-scndetect-concat-temp.ini");
|
||||
FfmpegUtils.CreateConcatFile(inPath, concatFile, Filetypes.imagesInterpCompat);
|
||||
FfmpegUtils.CreateConcatFile(inPath, concatFile, Filetypes.imagesInterpCompat.ToList());
|
||||
inArg = $"-f concat -safe 0 -i {concatFile.Wrap()}";
|
||||
}
|
||||
|
||||
|
@ -34,10 +34,10 @@ namespace Flowframes.Media
|
|||
string rateArg = (rate.GetFloat() > 0) ? $"-r {rate}" : "";
|
||||
string args = $"-vsync 0 {GetTrimArg(true)} {inArg} {GetImgArgs(format)} {rateArg} {scnDetect} -frame_pts 1 -s 256x144 {GetTrimArg(false)} \"{outDir}/%{Padding.inputFrames}d{format}\"";
|
||||
|
||||
LogMode logMode = await Interpolate.GetCurrentInputFrameCount() > 50 ? LogMode.OnlyLastLine : LogMode.Hidden;
|
||||
LogMode logMode = Interpolate.currentMediaFile.FrameCount > 50 ? LogMode.OnlyLastLine : LogMode.Hidden;
|
||||
await RunFfmpeg(args, logMode, inputIsFrames ? "panic" : "warning", true);
|
||||
|
||||
bool hiddenLog = await Interpolate.GetCurrentInputFrameCount() <= 50;
|
||||
bool hiddenLog = Interpolate.currentMediaFile.FrameCount <= 50;
|
||||
int amount = IoUtils.GetAmountOfFiles(outDir, false);
|
||||
Logger.Log($"Detected {amount} scene {(amount == 1 ? "change" : "changes")}.".Replace(" 0 ", " no "), false, !hiddenLog);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ namespace Flowframes.Media
|
|||
string vf = filters.Length > 2 ? $"-vf {filters}" : "";
|
||||
string rateArg = (rate.GetFloat() > 0) ? $" -r {rate}" : "";
|
||||
string args = $"{GetTrimArg(true)} -i {inputFile.Wrap()} {GetImgArgs(format, true, alpha)} -vsync 0 {rateArg} -frame_pts 1 {vf} {sizeStr} {GetTrimArg(false)} \"{framesDir}/%{Padding.inputFrames}d{format}\"";
|
||||
LogMode logMode = await Interpolate.GetCurrentInputFrameCount() > 50 ? LogMode.OnlyLastLine : LogMode.Hidden;
|
||||
LogMode logMode = Interpolate.currentMediaFile.FrameCount > 50 ? LogMode.OnlyLastLine : LogMode.Hidden;
|
||||
await RunFfmpeg(args, logMode, true);
|
||||
int amount = IoUtils.GetAmountOfFiles(framesDir, false, "*" + format);
|
||||
Logger.Log($"Extracted {amount} {(amount == 1 ? "frame" : "frames")} from input.", false, true);
|
||||
|
@ -202,7 +202,7 @@ namespace Flowframes.Media
|
|||
return false;
|
||||
}
|
||||
|
||||
Interpolate.current.framesExt = files.First().Extension;
|
||||
Interpolate.currentSettings.framesExt = files.First().Extension;
|
||||
Logger.Log($"Sequence compatible!", true);
|
||||
return true;
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ namespace Flowframes.Media
|
|||
Logger.Log($"ImportImages() - Alpha: {alpha} - Size: {size} - Format: {format}", true, false, "ffmpeg");
|
||||
IoUtils.CreateDir(outPath);
|
||||
string concatFile = Path.Combine(Paths.GetDataPath(), "import-concat-temp.ini");
|
||||
FfmpegUtils.CreateConcatFile(inPath, concatFile, Filetypes.imagesInterpCompat);
|
||||
FfmpegUtils.CreateConcatFile(inPath, concatFile, Filetypes.imagesInterpCompat.ToList());
|
||||
|
||||
string inArg = $"-f concat -safe 0 -i {concatFile.Wrap()}";
|
||||
string linksDir = Path.Combine(concatFile + Paths.symlinksSuffix);
|
||||
|
|
|
@ -1,17 +1,176 @@
|
|||
using Flowframes.IO;
|
||||
using Flowframes.Data;
|
||||
using Flowframes.Data.Streams;
|
||||
using Flowframes.IO;
|
||||
using Flowframes.MiscUtils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using static Flowframes.Media.GetVideoInfo;
|
||||
using Stream = Flowframes.Data.Streams.Stream;
|
||||
|
||||
namespace Flowframes.Media
|
||||
{
|
||||
class FfmpegUtils
|
||||
{
|
||||
public enum Codec { H264, H265, H264Nvenc, H265Nvenc, Av1, Vp9, ProRes, AviRaw, Gif }
|
||||
private readonly static FfprobeMode showStreams = FfprobeMode.ShowStreams;
|
||||
private readonly static FfprobeMode showFormat = FfprobeMode.ShowFormat;
|
||||
|
||||
public static async Task<int> GetStreamCount(string path)
|
||||
{
|
||||
Logger.Log($"GetStreamCount({path})", true);
|
||||
string output = await GetFfmpegInfoAsync(path, "Stream #0:");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(output.Trim()))
|
||||
return 0;
|
||||
|
||||
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)
|
||||
{
|
||||
List<Stream> streamList = new List<Stream>();
|
||||
|
||||
try
|
||||
{
|
||||
string output = await GetFfmpegInfoAsync(path, "Stream #0:");
|
||||
string[] streams = output.SplitIntoLines().Where(x => x.MatchesWildcard("*Stream #0:*: *: *")).ToArray();
|
||||
|
||||
foreach (string streamStr in streams)
|
||||
{
|
||||
try
|
||||
{
|
||||
int idx = streamStr.Split(':')[1].Split('[')[0].Split('(')[0].GetInt();
|
||||
bool def = await GetFfprobeInfoAsync(path, showStreams, "DISPOSITION:default", idx) == "1";
|
||||
|
||||
if (progressBar)
|
||||
Program.mainForm.SetProgress(FormatUtils.RatioInt(idx + 1, streamCount));
|
||||
|
||||
if (streamStr.Contains(": Video:"))
|
||||
{
|
||||
string lang = await GetFfprobeInfoAsync(path, showStreams, "TAG:language", idx);
|
||||
string title = await GetFfprobeInfoAsync(path, showStreams, "TAG:title", idx);
|
||||
string codec = await GetFfprobeInfoAsync(path, showStreams, "codec_name", idx);
|
||||
string codecLong = await GetFfprobeInfoAsync(path, showStreams, "codec_long_name", idx);
|
||||
string pixFmt = (await GetFfprobeInfoAsync(path, showStreams, "pix_fmt", idx)).ToUpper();
|
||||
int kbits = (await GetFfprobeInfoAsync(path, showStreams, "bit_rate", idx)).GetInt() / 1024;
|
||||
Size res = await GetMediaResolutionCached.GetSizeAsync(path);
|
||||
Size sar = SizeFromString(await GetFfprobeInfoAsync(path, showStreams, "sample_aspect_ratio", idx));
|
||||
Size dar = SizeFromString(await GetFfprobeInfoAsync(path, showStreams, "display_aspect_ratio", idx));
|
||||
Fraction fps = path.IsConcatFile() ? defaultFps : await IoUtils.GetVideoFramerate(path);
|
||||
int frameCount = countFrames ? await GetFrameCountCached.GetFrameCountAsync(path) : 0;
|
||||
VideoStream vStream = new VideoStream(lang, title, codec, codecLong, pixFmt, kbits, res, sar, dar, fps, frameCount);
|
||||
vStream.Index = idx;
|
||||
vStream.IsDefault = def;
|
||||
Logger.Log($"Added video stream: {vStream}", true);
|
||||
streamList.Add(vStream);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streamStr.Contains(": Audio:"))
|
||||
{
|
||||
string lang = await GetFfprobeInfoAsync(path, showStreams, "TAG:language", idx);
|
||||
string title = await GetFfprobeInfoAsync(path, showStreams, "TAG:title", idx);
|
||||
string codec = await GetFfprobeInfoAsync(path, showStreams, "codec_name", idx);
|
||||
string profile = await GetFfprobeInfoAsync(path, showStreams, "profile", idx);
|
||||
if (codec.ToLower() == "dts" && profile != "unknown") codec = profile;
|
||||
string codecLong = await GetFfprobeInfoAsync(path, showStreams, "codec_long_name", idx);
|
||||
int kbits = (await GetFfprobeInfoAsync(path, showStreams, "bit_rate", idx)).GetInt() / 1024;
|
||||
int sampleRate = (await GetFfprobeInfoAsync(path, showStreams, "sample_rate", idx)).GetInt();
|
||||
int channels = (await GetFfprobeInfoAsync(path, showStreams, "channels", idx)).GetInt();
|
||||
string layout = (await GetFfprobeInfoAsync(path, showStreams, "channel_layout", idx));
|
||||
AudioStream aStream = new AudioStream(lang, title, codec, codecLong, kbits, sampleRate, channels, layout);
|
||||
aStream.Index = idx;
|
||||
aStream.IsDefault = def;
|
||||
Logger.Log($"Added audio stream: {aStream}", true);
|
||||
streamList.Add(aStream);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streamStr.Contains(": Subtitle:"))
|
||||
{
|
||||
string lang = await GetFfprobeInfoAsync(path, showStreams, "TAG:language", idx);
|
||||
string title = await GetFfprobeInfoAsync(path, showStreams, "TAG:title", idx);
|
||||
string codec = await GetFfprobeInfoAsync(path, showStreams, "codec_name", idx);
|
||||
string codecLong = await GetFfprobeInfoAsync(path, showStreams, "codec_long_name", idx);
|
||||
bool bitmap = await IsSubtitleBitmapBased(path, idx, codec);
|
||||
SubtitleStream sStream = new SubtitleStream(lang, title, codec, codecLong, bitmap);
|
||||
sStream.Index = idx;
|
||||
sStream.IsDefault = def;
|
||||
Logger.Log($"Added subtitle stream: {sStream}", true);
|
||||
streamList.Add(sStream);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streamStr.Contains(": Data:"))
|
||||
{
|
||||
string codec = await GetFfprobeInfoAsync(path, showStreams, "codec_name", idx);
|
||||
string codecLong = await GetFfprobeInfoAsync(path, showStreams, "codec_long_name", idx);
|
||||
DataStream dStream = new DataStream(codec, codecLong);
|
||||
dStream.Index = idx;
|
||||
dStream.IsDefault = def;
|
||||
Logger.Log($"Added data stream: {dStream}", true);
|
||||
streamList.Add(dStream);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streamStr.Contains(": Attachment:"))
|
||||
{
|
||||
string codec = await GetFfprobeInfoAsync(path, showStreams, "codec_name", idx);
|
||||
string codecLong = await GetFfprobeInfoAsync(path, showStreams, "codec_long_name", idx);
|
||||
string filename = await GetFfprobeInfoAsync(path, showStreams, "TAG:filename", idx);
|
||||
string mimeType = await GetFfprobeInfoAsync(path, showStreams, "TAG:mimetype", idx);
|
||||
AttachmentStream aStream = new AttachmentStream(codec, codecLong, filename, mimeType);
|
||||
aStream.Index = idx;
|
||||
aStream.IsDefault = def;
|
||||
Logger.Log($"Added attachment stream: {aStream}", true);
|
||||
streamList.Add(aStream);
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger.Log($"Unknown stream (not vid/aud/sub/dat/att): {streamStr}", true);
|
||||
Stream stream = new Stream { Codec = "Unknown", CodecLong = "Unknown", Index = idx, IsDefault = def, Type = Stream.StreamType.Unknown };
|
||||
streamList.Add(stream);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log($"Error scanning stream: {e.Message}\n{e.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log($"GetStreams Exception: {e.Message}\n{e.StackTrace}", true);
|
||||
}
|
||||
|
||||
Logger.Log($"Video Streams: {string.Join(", ", streamList.Where(x => x.Type == Stream.StreamType.Video).Select(x => string.IsNullOrWhiteSpace(x.Title) ? "No Title" : x.Title))}", true);
|
||||
Logger.Log($"Audio Streams: {string.Join(", ", streamList.Where(x => x.Type == Stream.StreamType.Audio).Select(x => string.IsNullOrWhiteSpace(x.Title) ? "No Title" : x.Title))}", true);
|
||||
Logger.Log($"Subtitle Streams: {string.Join(", ", streamList.Where(x => x.Type == Stream.StreamType.Subtitle).Select(x => string.IsNullOrWhiteSpace(x.Title) ? "No Title" : x.Title))}", true);
|
||||
|
||||
if (progressBar)
|
||||
Program.mainForm.SetProgress(0);
|
||||
|
||||
return streamList;
|
||||
}
|
||||
|
||||
public static async Task<bool> IsSubtitleBitmapBased(string path, int streamIndex, string codec = "")
|
||||
{
|
||||
if (codec == "ssa" || codec == "ass" || codec == "mov_text" || codec == "srt" || codec == "subrip" || codec == "text" || codec == "webvtt")
|
||||
return false;
|
||||
|
||||
if (codec == "dvdsub" || codec == "dvd_subtitle" || codec == "pgssub" || codec == "hdmv_pgs_subtitle" || codec.StartsWith("dvb_"))
|
||||
return true;
|
||||
|
||||
// If codec was not listed above, manually check if it's compatible by trying to encode it:
|
||||
//string ffmpegCheck = await GetFfmpegOutputAsync(path, $"-map 0:{streamIndex} -c:s srt -t 0 -f null -");
|
||||
//return ffmpegCheck.Contains($"encoding currently only possible from text to text or bitmap to bitmap");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public enum Codec { H264, H265, H264Nvenc, H265Nvenc, Av1, Vp9, ProRes, AviRaw, Gif }
|
||||
|
||||
public static Codec GetCodec(Interpolate.OutMode mode)
|
||||
{
|
||||
|
@ -330,20 +489,42 @@ namespace Flowframes.Media
|
|||
return supported;
|
||||
}
|
||||
|
||||
public static void CreateConcatFile(string inputFilesDir, string outputPath, string[] validExtensions = null)
|
||||
public static int CreateConcatFile(string inputFilesDir, string outputPath, List<string> validExtensions = null)
|
||||
{
|
||||
if (IoUtils.GetAmountOfFiles(inputFilesDir, false) < 1)
|
||||
return 0;
|
||||
|
||||
Directory.CreateDirectory(outputPath.GetParentDir());
|
||||
|
||||
if (validExtensions == null)
|
||||
validExtensions = new List<string>();
|
||||
|
||||
validExtensions = validExtensions.Select(x => x.Remove(".").ToLower()).ToList(); // Ignore "." in extensions
|
||||
string concatFileContent = "";
|
||||
string[] files = IoUtils.GetFilesSorted(inputFilesDir);
|
||||
int fileCount = 0;
|
||||
|
||||
foreach (string file in files)
|
||||
foreach (string file in files.Where(x => validExtensions.Contains(Path.GetExtension(x).Replace(".", "").ToLower())))
|
||||
{
|
||||
if (validExtensions != null && !validExtensions.Contains(Path.GetExtension(file).ToLower()))
|
||||
continue;
|
||||
|
||||
fileCount++;
|
||||
concatFileContent += $"file '{file.Replace(@"\", "/")}'\n";
|
||||
}
|
||||
|
||||
File.WriteAllText(outputPath, concatFileContent);
|
||||
return fileCount;
|
||||
}
|
||||
|
||||
public static Size SizeFromString(string str, char delimiter = ':')
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] nums = str.Remove(" ").Trim().Split(delimiter);
|
||||
return new Size(nums[0].GetInt(), nums[1].GetInt());
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new Size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,21 +17,22 @@ namespace Flowframes.Media
|
|||
|
||||
static Dictionary<QueryInfo, string> cmdCache = new Dictionary<QueryInfo, string>();
|
||||
|
||||
private static string GetAvPath()
|
||||
public static async Task<string> GetFfmpegInfoAsync(string path, string lineFilter = "", bool noCache = false)
|
||||
{
|
||||
return Path.Combine(Paths.GetPkgPath(), Paths.audioVideoDir);
|
||||
return await GetFfmpegOutputAsync(path, "", lineFilter, noCache);
|
||||
}
|
||||
|
||||
public static async Task<string> GetFfmpegInfoAsync(string path, string lineFilter = "")
|
||||
public static async Task<string> GetFfmpegOutputAsync(string path, string args, string lineFilter = "", bool noCache = false)
|
||||
{
|
||||
return await GetFfmpegOutputAsync(path, "", lineFilter);
|
||||
return await GetFfmpegOutputAsync(path, "", args, lineFilter, noCache);
|
||||
}
|
||||
|
||||
public static async Task<string> GetFfmpegOutputAsync(string path, string args, string lineFilter = "")
|
||||
public static async Task<string> GetFfmpegOutputAsync(string path, string argsIn, string argsOut, string lineFilter = "", bool noCache = false)
|
||||
{
|
||||
Process process = OsUtils.NewProcess(true);
|
||||
process.StartInfo.Arguments = $"/C cd /D {GetAvPath().Wrap()} & ffmpeg.exe -hide_banner -y -stats -i {path.Wrap()} {args}";
|
||||
return await GetInfoAsync(path, process, lineFilter, false);
|
||||
process.StartInfo.Arguments = $"/C cd /D {GetAvPath().Wrap()} & " +
|
||||
$"ffmpeg.exe -hide_banner -y {argsIn} {path.GetConcStr()} -i {path.Wrap()} {argsOut}";
|
||||
return await GetInfoAsync(path, process, lineFilter, noCache);
|
||||
}
|
||||
|
||||
public static async Task<string> GetFfprobeInfoAsync(string path, FfprobeMode mode, string lineFilter = "", int streamIndex = -1, bool stripKeyName = true)
|
||||
|
@ -39,39 +40,64 @@ namespace Flowframes.Media
|
|||
Process process = OsUtils.NewProcess(true);
|
||||
string showFormat = mode == FfprobeMode.ShowBoth || mode == FfprobeMode.ShowFormat ? "-show_format" : "";
|
||||
string showStreams = mode == FfprobeMode.ShowBoth || mode == FfprobeMode.ShowStreams ? "-show_streams" : "";
|
||||
string streamSelect = (streamIndex >= 0) ? $"-select_streams {streamIndex}" : "";
|
||||
process.StartInfo.Arguments = $"/C cd /D {GetAvPath().Wrap()} & ffprobe -v quiet {showFormat} {showStreams} {streamSelect} {path.Wrap()}";
|
||||
return await GetInfoAsync(path, process, lineFilter, stripKeyName);
|
||||
|
||||
process.StartInfo.Arguments = $"/C cd /D {GetAvPath().Wrap()} & " +
|
||||
$"ffprobe -v quiet {path.GetConcStr()} {showFormat} {showStreams} {path.Wrap()}";
|
||||
|
||||
string output = await GetInfoAsync(path, process, lineFilter, streamIndex, stripKeyName);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static async Task<string> GetInfoAsync(string path, Process process, string lineFilter, bool stripKeyName = true)
|
||||
static async Task<string> GetInfoAsync(string path, Process process, string lineFilter, bool noCache = false) // for ffmpeg
|
||||
{
|
||||
string output = await GetOutputCached(path, process);
|
||||
string output = await GetOutputCached(path, process, noCache);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(lineFilter.Trim()))
|
||||
output = string.Join("\n", output.SplitIntoLines().Where(x => x.Contains(lineFilter)).ToArray());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static async Task<string> GetInfoAsync(string path, Process process, string lineFilter, int streamIndex = -1, bool stripKeyName = true, bool noCache = false) // for ffprobe
|
||||
{
|
||||
string output = await GetOutputCached(path, process, noCache);
|
||||
|
||||
try
|
||||
{
|
||||
if (streamIndex >= 0)
|
||||
output = output.Split("[/STREAM]")[streamIndex];
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.Log($"output.Split(\"[/STREAM]\")[{streamIndex}] failed! Can't access index {streamIndex} because array only has {output.Split("[/STREAM]").Length} items.", true);
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(lineFilter.Trim()))
|
||||
{
|
||||
if (stripKeyName)
|
||||
{
|
||||
List<string> filtered = output.SplitIntoLines().Where(x => x.Contains(lineFilter)).ToList(); // Filter
|
||||
|
||||
List<string> filtered = output.SplitIntoLines().Where(x => x.ToLower().Contains(lineFilter.ToLower())).ToList(); // Filter
|
||||
filtered = filtered.Select(x => string.Join("", x.Split('=').Skip(1))).ToList(); // Ignore everything before (and including) the first '=' sign
|
||||
output = string.Join("\n", filtered);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = string.Join("\n", output.SplitIntoLines().Where(x => x.Contains(lineFilter)).ToArray());
|
||||
output = string.Join("\n", output.SplitIntoLines().Where(x => x.ToLower().Contains(lineFilter.ToLower())).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static async Task<string> GetOutputCached(string path, Process process)
|
||||
static async Task<string> GetOutputCached(string path, Process process, bool noCache = false)
|
||||
{
|
||||
long filesize = IoUtils.GetFilesize(path);
|
||||
QueryInfo hash = new QueryInfo(path, filesize, process.StartInfo.Arguments);
|
||||
|
||||
if (filesize > 0 && CacheContains(hash, ref cmdCache))
|
||||
if (!noCache && filesize > 0 && CacheContains(hash, ref cmdCache))
|
||||
{
|
||||
Logger.Log($"GetVideoInfo: '{process.StartInfo.FileName} {process.StartInfo.Arguments}' cached, won't re-run.", true, false, "ffmpeg");
|
||||
return GetFromCache(hash, ref cmdCache);
|
||||
|
@ -100,5 +126,15 @@ namespace Flowframes.Media
|
|||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void ClearCache()
|
||||
{
|
||||
cmdCache.Clear();
|
||||
}
|
||||
|
||||
private static string GetAvPath()
|
||||
{
|
||||
return Path.Combine(Paths.GetPkgPath(), Paths.audioVideoDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ namespace Flowframes.MiscUtils
|
|||
|
||||
public static async Task Rename()
|
||||
{
|
||||
importFilenames = IoUtils.GetFilesSorted(Interpolate.current.framesFolder).Select(x => Path.GetFileName(x)).ToArray();
|
||||
await IoUtils.RenameCounterDir(Interpolate.current.framesFolder, 0, Padding.inputFramesRenamed);
|
||||
importFilenames = IoUtils.GetFilesSorted(Interpolate.currentSettings.framesFolder).Select(x => Path.GetFileName(x)).ToArray();
|
||||
await IoUtils.RenameCounterDir(Interpolate.currentSettings.framesFolder, 0, Padding.inputFramesRenamed);
|
||||
framesAreRenamed = true;
|
||||
}
|
||||
|
||||
|
@ -27,11 +27,11 @@ namespace Flowframes.MiscUtils
|
|||
Stopwatch sw = new Stopwatch();
|
||||
sw.Restart();
|
||||
|
||||
string[] files = IoUtils.GetFilesSorted(Interpolate.current.framesFolder);
|
||||
string[] files = IoUtils.GetFilesSorted(Interpolate.currentSettings.framesFolder);
|
||||
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
string movePath = Path.Combine(Interpolate.current.framesFolder, importFilenames[i]);
|
||||
string movePath = Path.Combine(Interpolate.currentSettings.framesFolder, importFilenames[i]);
|
||||
File.Move(files[i], movePath);
|
||||
|
||||
if (sw.ElapsedMilliseconds > 100)
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace Flowframes.Os
|
|||
processTime.Restart();
|
||||
lastAiProcess = proc;
|
||||
AiProcessSuspend.SetRunning(true);
|
||||
lastInPath = string.IsNullOrWhiteSpace(inPath) ? Interpolate.current.framesFolder : inPath;
|
||||
lastInPath = string.IsNullOrWhiteSpace(inPath) ? Interpolate.currentSettings.framesFolder : inPath;
|
||||
hasShownError = false;
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ namespace Flowframes.Os
|
|||
{
|
||||
lastAiProcess = proc;
|
||||
AiProcessSuspend.SetRunning(true);
|
||||
lastInPath = string.IsNullOrWhiteSpace(inPath) ? Interpolate.current.framesFolder : inPath;
|
||||
lastInPath = string.IsNullOrWhiteSpace(inPath) ? Interpolate.currentSettings.framesFolder : inPath;
|
||||
hasShownError = false;
|
||||
}
|
||||
|
||||
|
@ -97,10 +97,10 @@ namespace Flowframes.Os
|
|||
return;
|
||||
}
|
||||
|
||||
int interpFramesFiles = IoUtils.GetAmountOfFiles(Interpolate.current.interpFolder, false, "*" + Interpolate.current.interpExt);
|
||||
int interpFramesFiles = IoUtils.GetAmountOfFiles(Interpolate.currentSettings.interpFolder, false, "*" + Interpolate.currentSettings.interpExt);
|
||||
int interpFramesCount = interpFramesFiles + InterpolationProgress.deletedFramesCount;
|
||||
|
||||
if (!Interpolate.current.ai.Piped)
|
||||
if (!Interpolate.currentSettings.ai.Piped)
|
||||
InterpolationProgress.UpdateInterpProgress(interpFramesCount, InterpolationProgress.targetFrames);
|
||||
|
||||
string logStr = $"Done running {aiName} - Interpolation took {FormatUtils.Time(processTime.Elapsed)}. Peak Output FPS: {InterpolationProgress.peakFpsOut.ToString("0.00")}";
|
||||
|
@ -114,7 +114,7 @@ namespace Flowframes.Os
|
|||
Logger.Log(logStr);
|
||||
processTime.Stop();
|
||||
|
||||
if (!Interpolate.current.ai.Piped && interpFramesCount < 3)
|
||||
if (!Interpolate.currentSettings.ai.Piped && interpFramesCount < 3)
|
||||
{
|
||||
string[] logLines = File.ReadAllLines(Path.Combine(Paths.GetLogPath(), lastLogName + ".txt"));
|
||||
string log = string.Join("\n", logLines.Reverse().Take(10).Reverse().Select(x => x.Split("]: ").Last()).ToList());
|
||||
|
@ -195,7 +195,7 @@ namespace Flowframes.Os
|
|||
|
||||
Process rifePy = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd());
|
||||
AiStarted(rifePy, 3500);
|
||||
SetProgressCheck(Path.Combine(Interpolate.current.tempFolder, outDir), interpFactor);
|
||||
SetProgressCheck(Path.Combine(Interpolate.currentSettings.tempFolder, outDir), interpFactor);
|
||||
rifePy.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.rifeCuda.PkgDir).Wrap()} & " +
|
||||
$"set CUDA_VISIBLE_DEVICES={Config.Get(Config.Key.torchGpus)} & {Python.GetPyCmd()} {script} {args}";
|
||||
Logger.Log($"Running RIFE (CUDA){(await InterpolateUtils.UseUhd() ? " (UHD Mode)" : "")}...", false);
|
||||
|
@ -253,7 +253,7 @@ namespace Flowframes.Os
|
|||
|
||||
Process flavrPy = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd());
|
||||
AiStarted(flavrPy, 4000);
|
||||
SetProgressCheck(Path.Combine(Interpolate.current.tempFolder, outDir), interpFactor);
|
||||
SetProgressCheck(Path.Combine(Interpolate.currentSettings.tempFolder, outDir), interpFactor);
|
||||
flavrPy.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {Path.Combine(Paths.GetPkgPath(), Implementations.flavrCuda.PkgDir).Wrap()} & " +
|
||||
$"set CUDA_VISIBLE_DEVICES={Config.Get(Config.Key.torchGpus)} & {Python.GetPyCmd()} {script} {args}";
|
||||
Logger.Log($"Running FLAVR (CUDA)...", false);
|
||||
|
@ -338,10 +338,10 @@ namespace Flowframes.Os
|
|||
|
||||
try
|
||||
{
|
||||
bool uhd = await InterpolateUtils.UseUhd();
|
||||
Logger.Log($"Running RIFE (NCNN-VS){(uhd ? " (UHD Mode)" : "")}...", false);
|
||||
Size scaledSize = await InterpolateUtils.GetOutputResolution(Interpolate.currentSettings.inPath, false);
|
||||
Logger.Log($"Running RIFE (NCNN-VS){(InterpolateUtils.UseUhd(scaledSize) ? " (UHD Mode)" : "")}...", false);
|
||||
|
||||
await RunRifeNcnnVsProcess(framesPath, factor, outPath, mdl, uhd, rt);
|
||||
await RunRifeNcnnVsProcess(framesPath, factor, outPath, mdl, scaledSize, rt);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -352,10 +352,9 @@ namespace Flowframes.Os
|
|||
await AiFinished("RIFE", true);
|
||||
}
|
||||
|
||||
static async Task RunRifeNcnnVsProcess(string inPath, float factor, string outPath, string mdl, bool uhd, bool rt = false)
|
||||
static async Task RunRifeNcnnVsProcess(string inPath, float factor, string outPath, string mdl, Size res, bool rt = false)
|
||||
{
|
||||
IoUtils.CreateDir(outPath);
|
||||
string logFileName = "rife-ncnn-vs-log";
|
||||
Process rifeNcnnVs = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd());
|
||||
|
||||
Logger.Log($"Note: RIFE-NCNN-VS is experimental and may not work as expected with specific Flowframes features, such as FPS limiting and image sequence exporting.");
|
||||
|
@ -367,26 +366,26 @@ namespace Flowframes.Os
|
|||
}
|
||||
else
|
||||
{
|
||||
SetProgressCheck(Interpolate.currentInputFrameCount, factor, logFileName);
|
||||
SetProgressCheck(Interpolate.currentMediaFile.FrameCount, factor, Implementations.rifeNcnnVs.LogFilename);
|
||||
AiStarted(rifeNcnnVs, 1500, inPath);
|
||||
}
|
||||
|
||||
string avDir = Path.Combine(Paths.GetPkgPath(), Paths.audioVideoDir);
|
||||
string rtArgs = $"-window_title \"Flowframes Realtime Interpolation ({Interpolate.current.inFps.GetString()} FPS x{factor} = {Interpolate.current.outFps.GetString()} FPS - {mdl})\" -autoexit -seek_interval {VapourSynthUtils.GetSeekSeconds(Program.mainForm.currInDuration)} ";
|
||||
string rtArgs = $"-window_title \"Flowframes Realtime Interpolation ({Interpolate.currentSettings.inFps.GetString()} FPS x{factor} = {Interpolate.currentSettings.outFps.GetString()} FPS - {mdl})\" -autoexit -seek_interval {VapourSynthUtils.GetSeekSeconds(Program.mainForm.currInDuration)} ";
|
||||
|
||||
Interpolate.current.FullOutPath = Path.Combine(Interpolate.current.outPath, await IoUtils.GetCurrentExportFilename(false, true));
|
||||
string encArgs = FfmpegUtils.GetEncArgs(FfmpegUtils.GetCodec(Interpolate.current.outMode), (Interpolate.current.ScaledResolution.IsEmpty ? Interpolate.current.InputResolution : Interpolate.current.ScaledResolution), Interpolate.current.outFps.GetFloat(), true).FirstOrDefault();
|
||||
string ffmpegArgs = rt ? $"{Path.Combine(avDir, "ffplay").Wrap()} {rtArgs} - " : $"{Path.Combine(avDir, "ffmpeg").Wrap()} -y -i pipe: {encArgs} {Interpolate.current.FullOutPath.Wrap()}";
|
||||
Interpolate.currentSettings.FullOutPath = Path.Combine(Interpolate.currentSettings.outPath, await IoUtils.GetCurrentExportFilename(false, true));
|
||||
string encArgs = FfmpegUtils.GetEncArgs(FfmpegUtils.GetCodec(Interpolate.currentSettings.outMode), (Interpolate.currentSettings.ScaledResolution.IsEmpty ? Interpolate.currentSettings.InputResolution : Interpolate.currentSettings.ScaledResolution), Interpolate.currentSettings.outFps.GetFloat(), true).FirstOrDefault();
|
||||
string ffmpegArgs = rt ? $"{Path.Combine(avDir, "ffplay").Wrap()} {rtArgs} - " : $"{Path.Combine(avDir, "ffmpeg").Wrap()} -y -i pipe: {encArgs} {Interpolate.currentSettings.FullOutPath.Wrap()}";
|
||||
|
||||
string pkgDir = Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnnVs.PkgDir);
|
||||
|
||||
VapourSynthUtils.VsSettings vsSettings = new VapourSynthUtils.VsSettings()
|
||||
{
|
||||
InterpSettings = Interpolate.current,
|
||||
InterpSettings = Interpolate.currentSettings,
|
||||
ModelDir = mdl,
|
||||
Factor = factor,
|
||||
Res = InterpolateUtils.GetOutputResolution(Interpolate.current.InputResolution, true, true),
|
||||
Uhd = uhd,
|
||||
Res = InterpolateUtils.GetOutputResolution(Interpolate.currentSettings.InputResolution, true, true),
|
||||
Uhd = InterpolateUtils.UseUhd(res),
|
||||
GpuId = Config.Get(Config.Key.ncnnGpus).Split(',')[0].GetInt(),
|
||||
SceneDetectSensitivity = Config.GetBool(Config.Key.scnDetect) ? Config.GetFloat(Config.Key.scnDetectValue) * 0.7f : 0f,
|
||||
Loop = Config.GetBool(Config.Key.enableLoop),
|
||||
|
@ -508,7 +507,7 @@ namespace Flowframes.Os
|
|||
|
||||
Process xvfiPy = OsUtils.NewProcess(!OsUtils.ShowHiddenCmd());
|
||||
AiStarted(xvfiPy, 3500);
|
||||
SetProgressCheck(Path.Combine(Interpolate.current.tempFolder, outDir), interpFactor);
|
||||
SetProgressCheck(Path.Combine(Interpolate.currentSettings.tempFolder, outDir), interpFactor);
|
||||
xvfiPy.StartInfo.Arguments = $"{OsUtils.GetCmdArg()} cd /D {pkgPath.Wrap()} & " +
|
||||
$"set CUDA_VISIBLE_DEVICES={Config.Get(Config.Key.torchGpus)} & {Python.GetPyCmd()} {script} {args}";
|
||||
Logger.Log($"Running XVFI (CUDA)...", false);
|
||||
|
@ -539,9 +538,8 @@ namespace Flowframes.Os
|
|||
Stopwatch sw = new Stopwatch();
|
||||
sw.Restart();
|
||||
|
||||
string logFilename = ai.AiName.Replace("_", "-").ToLower() + "-log";
|
||||
lastLogName = logFilename;
|
||||
Logger.Log(line, true, false, logFilename);
|
||||
lastLogName = ai.LogFilename;
|
||||
Logger.Log(line, true, false, ai.LogFilename);
|
||||
|
||||
string lastLogLines = string.Join("\n", Logger.GetSessionLogLastLines(lastLogName, 6).Select(x => $"[{x.Split("]: [").Skip(1).FirstOrDefault()}"));
|
||||
|
||||
|
@ -553,7 +551,7 @@ namespace Flowframes.Os
|
|||
if (!hasShownError && err && line.ToLower().Contains("modulenotfounderror"))
|
||||
{
|
||||
hasShownError = true;
|
||||
UiUtils.ShowMessageBox($"A python module is missing.\nCheck {logFilename} for details.\n\n{line}", UiUtils.MessageType.Error);
|
||||
UiUtils.ShowMessageBox($"A python module is missing.\nCheck {ai.LogFilename} for details.\n\n{line}", UiUtils.MessageType.Error);
|
||||
}
|
||||
|
||||
if (!hasShownError && line.ToLower().Contains("no longer supports this gpu"))
|
||||
|
@ -565,7 +563,7 @@ namespace Flowframes.Os
|
|||
if (!hasShownError && line.ToLower().Contains("error(s) in loading state_dict"))
|
||||
{
|
||||
hasShownError = true;
|
||||
string msg = (Interpolate.current.ai.AiName == Implementations.flavrCuda.AiName) ? "\n\nFor FLAVR, you need to select the correct model for each scale!" : "";
|
||||
string msg = (Interpolate.currentSettings.ai.AiName == Implementations.flavrCuda.AiName) ? "\n\nFor FLAVR, you need to select the correct model for each scale!" : "";
|
||||
UiUtils.ShowMessageBox($"Error loading the AI model!\n\n{line}{msg}", UiUtils.MessageType.Error);
|
||||
}
|
||||
|
||||
|
@ -593,7 +591,7 @@ namespace Flowframes.Os
|
|||
if (!hasShownError && err && line.Contains("vkAllocateMemory failed"))
|
||||
{
|
||||
hasShownError = true;
|
||||
bool usingDain = (Interpolate.current.ai.AiName == Implementations.dainNcnn.AiName);
|
||||
bool usingDain = (Interpolate.currentSettings.ai.AiName == Implementations.dainNcnn.AiName);
|
||||
string msg = usingDain ? "\n\nTry reducing the tile size in the AI settings." : "\n\nTry a lower resolution (Settings -> Max Video Size).";
|
||||
UiUtils.ShowMessageBox($"Vulkan ran out of memory!\n\n{line}{msg}", UiUtils.MessageType.Error);
|
||||
}
|
||||
|
@ -652,7 +650,7 @@ namespace Flowframes.Os
|
|||
|
||||
static string GetNcnnPattern()
|
||||
{
|
||||
return $"%0{Padding.interpFrames}d{Interpolate.current.interpExt}";
|
||||
return $"%0{Padding.interpFrames}d{Interpolate.currentSettings.interpExt}";
|
||||
}
|
||||
|
||||
static string GetNcnnTilesize(int tilesize)
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace Flowframes.Os
|
|||
string mdlPath = Path.Combine(Paths.GetPkgPath(), Implementations.rifeNcnnVs.PkgDir, s.ModelDir).Replace(@"\", "/").Wrap();
|
||||
|
||||
bool sc = s.SceneDetectSensitivity >= 0.01f;
|
||||
long frameCount = (long)Interpolate.currentInputFrameCount;
|
||||
long frameCount = (long)Interpolate.currentMediaFile.FrameCount;
|
||||
|
||||
bool trim = QuickSettingsTab.trimEnabled;
|
||||
long srcTrimStartFrame = trim ? (long)(Math.Round(FormatUtils.TimestampToMs(QuickSettingsTab.trimStart) / 1000f * s.InterpSettings.inFps.GetFloat())) : 0;
|
||||
|
|
|
@ -94,11 +94,11 @@ namespace Flowframes
|
|||
{
|
||||
try
|
||||
{
|
||||
if (Interpolate.current == null || Interpolate.current.tempFolder.Length < 3)
|
||||
if (Interpolate.currentSettings == null || Interpolate.currentSettings.tempFolder.Length < 3)
|
||||
return;
|
||||
|
||||
string drivePath = Interpolate.current.tempFolder.Substring(0, 2);
|
||||
long mb = IoUtils.GetDiskSpace(Interpolate.current.tempFolder);
|
||||
string drivePath = Interpolate.currentSettings.tempFolder.Substring(0, 2);
|
||||
long mb = IoUtils.GetDiskSpace(Interpolate.currentSettings.tempFolder);
|
||||
|
||||
Logger.Log($"Disk space check for '{drivePath}/': {(mb / 1024f).ToString("0.0")} GB free.", true);
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace Flowframes.Ui
|
|||
Program.mainForm.SetTab("preview");
|
||||
|
||||
firstProgUpd = false;
|
||||
string lastFramePath = currentOutdir + "\\" + lastFrame.ToString("00000000") + I.current.interpExt;
|
||||
string lastFramePath = currentOutdir + "\\" + lastFrame.ToString("00000000") + I.currentSettings.interpExt;
|
||||
|
||||
if (lastFrame > 1)
|
||||
UpdateInterpProgress(lastFrame, targetFrames, lastFramePath);
|
||||
|
@ -79,8 +79,8 @@ namespace Flowframes.Ui
|
|||
{
|
||||
try
|
||||
{
|
||||
string ncnnStr = I.current.ai.AiName.Contains("NCNN") ? " done" : "";
|
||||
Regex frameRegex = new Regex($@"(?<=.)\d*(?={I.current.interpExt}{ncnnStr})");
|
||||
string ncnnStr = I.currentSettings.ai.AiName.Contains("NCNN") ? " done" : "";
|
||||
Regex frameRegex = new Regex($@"(?<=.)\d*(?={I.currentSettings.interpExt}{ncnnStr})");
|
||||
if (!frameRegex.IsMatch(output)) return;
|
||||
lastFrame = Math.Max(int.Parse(frameRegex.Match(output).Value), lastFrame);
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ namespace Flowframes.Ui
|
|||
public static void UpdateInterpProgress(int frames, int target, string latestFramePath = "")
|
||||
{
|
||||
if (I.canceled) return;
|
||||
interpolatedInputFramesCount = ((frames / I.current.interpFactor).RoundToInt() - 1);
|
||||
interpolatedInputFramesCount = ((frames / I.currentSettings.interpFactor).RoundToInt() - 1);
|
||||
//ResumeUtils.Save();
|
||||
frames = frames.Clamp(0, target);
|
||||
int percent = (int)Math.Round(((float)frames / target) * 100f);
|
||||
|
@ -177,7 +177,7 @@ namespace Flowframes.Ui
|
|||
public static async Task DeleteInterpolatedInputFrames()
|
||||
{
|
||||
interpolatedInputFramesCount = 0;
|
||||
string[] inputFrames = IoUtils.GetFilesSorted(I.current.framesFolder);
|
||||
string[] inputFrames = IoUtils.GetFilesSorted(I.currentSettings.framesFolder);
|
||||
|
||||
for (int i = 0; i < inputFrames.Length; i++)
|
||||
{
|
||||
|
|
|
@ -38,9 +38,10 @@ namespace Flowframes.Ui
|
|||
Logger.Log("Your file seems to be on an HDD or USB device. It is recommended to interpolate videos on an SSD drive for best performance.");
|
||||
|
||||
Logger.Log("Importing file...");
|
||||
Program.mainForm.currInDuration = FfmpegCommands.GetDuration(path);
|
||||
Interpolate.currentMediaFile = new MediaFile(path);
|
||||
await Interpolate.currentMediaFile.Initialize();
|
||||
Program.mainForm.currInDuration = Interpolate.currentMediaFile.DurationMs;
|
||||
Program.mainForm.currInDurationCut = Program.mainForm.currInDuration;
|
||||
int frameCount = await GetFrameCountCached.GetFrameCountAsync(path);
|
||||
string fpsStr = "Not Found";
|
||||
Fraction fps = (await IoUtils.GetFpsFolderOrVideo(path));
|
||||
Program.mainForm.currInFpsDetected = fps;
|
||||
|
@ -49,10 +50,10 @@ namespace Flowframes.Ui
|
|||
if (fps.GetFloat() > 0)
|
||||
fpsStr = $"{fps} (~{fps.GetFloat()})";
|
||||
|
||||
Logger.Log($"Video FPS: {fpsStr} - Total Number Of Frames: {frameCount}", false, true);
|
||||
Logger.Log($"Video FPS: {fpsStr} - Total Number Of Frames: {Interpolate.currentMediaFile.FrameCount}", false, true);
|
||||
Program.mainForm.GetInputFpsTextbox().ReadOnly = (fps.GetFloat() > 0 && !Config.GetBool("allowCustomInputRate", false));
|
||||
Program.mainForm.currInFps = fps;
|
||||
Program.mainForm.currInFrames = frameCount;
|
||||
Program.mainForm.currInFrames = Interpolate.currentMediaFile.FrameCount;
|
||||
Program.mainForm.UpdateInputInfo();
|
||||
CheckExistingFolder(path, outputTbox.Text.Trim());
|
||||
await Task.Delay(10);
|
||||
|
@ -93,13 +94,13 @@ namespace Flowframes.Ui
|
|||
|
||||
static void CheckExistingFolder (string inpath, string outpath)
|
||||
{
|
||||
if (Interpolate.current == null || !Interpolate.current.stepByStep) return;
|
||||
if (Interpolate.currentSettings == null || !Interpolate.currentSettings.stepByStep) return;
|
||||
string tmpFolder = InterpolateUtils.GetTempFolderLoc(inpath, outpath);
|
||||
if (Directory.Exists(tmpFolder))
|
||||
{
|
||||
int scnFrmAmount = IoUtils.GetAmountOfFiles(Path.Combine(tmpFolder, Paths.scenesDir), false, "*" + Interpolate.current.interpExt); // TODO: Make this work if the frames extension was changed
|
||||
int scnFrmAmount = IoUtils.GetAmountOfFiles(Path.Combine(tmpFolder, Paths.scenesDir), false, "*" + Interpolate.currentSettings.interpExt); // TODO: Make this work if the frames extension was changed
|
||||
string scnFrames = scnFrmAmount > 0 ? $"{scnFrmAmount} scene frames" : "no scene frames";
|
||||
int srcFrmAmount = IoUtils.GetAmountOfFiles(Path.Combine(tmpFolder, Paths.framesDir), false, "*" + Interpolate.current.interpExt);
|
||||
int srcFrmAmount = IoUtils.GetAmountOfFiles(Path.Combine(tmpFolder, Paths.framesDir), false, "*" + Interpolate.currentSettings.interpExt);
|
||||
string srcFrames = srcFrmAmount > 1 ? $"{srcFrmAmount} source frames" : "no source frames";
|
||||
int interpFrmAmount = IoUtils.GetAmountOfFiles(Path.Combine(tmpFolder, Paths.interpDir), false);
|
||||
string interpFrames = interpFrmAmount > 2 ? $"{interpFrmAmount} interpolated frames" : "no interpolated frames";
|
||||
|
@ -118,8 +119,8 @@ namespace Flowframes.Ui
|
|||
{
|
||||
Size res = new Size();
|
||||
|
||||
if(path == Interpolate.current?.inPath)
|
||||
res = Interpolate.current.InputResolution;
|
||||
if(path == Interpolate.currentSettings?.inPath)
|
||||
res = Interpolate.currentSettings.InputResolution;
|
||||
else
|
||||
res = await GetMediaResolutionCached.GetSizeAsync(path);
|
||||
|
||||
|
|
|
@ -0,0 +1,425 @@
|
|||
using Flowframes.Data;
|
||||
using Flowframes.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Flowframes.Utilities
|
||||
{
|
||||
class ColorDataUtils
|
||||
{
|
||||
// public static async Task<VideoColorData> GetColorData(string path)
|
||||
// {
|
||||
// VideoColorData data = new VideoColorData();
|
||||
//
|
||||
// AvProcess.FfprobeSettings settings = new AvProcess.FfprobeSettings() { Args = $"-show_frames -select_streams v:0 -read_intervals \"%+#1\" {path.Wrap()}", LogLevel = "quiet" };
|
||||
// string infoFfprobe = await AvProcess.RunFfprobe(settings);
|
||||
//
|
||||
// string[] linesFfprobe = infoFfprobe.SplitIntoLines();
|
||||
//
|
||||
// foreach (string line in linesFfprobe)
|
||||
// {
|
||||
// if (line.Contains("color_transfer="))
|
||||
// data.ColorTransfer = GetColorTransfer(line.Split('=').Last());
|
||||
//
|
||||
// else if (line.Contains("color_space="))
|
||||
// data.ColorMatrixCoeffs = GetMatrixCoeffs(line.Split('=').Last());
|
||||
//
|
||||
// else if (line.Contains("color_primaries="))
|
||||
// data.ColorPrimaries = GetColorPrimaries(line.Split('=').Last());
|
||||
//
|
||||
// else if (line.Contains("color_range="))
|
||||
// data.ColorRange = GetColorRange(line.Split('=').Last());
|
||||
//
|
||||
// else if (line.Contains("red_x="))
|
||||
// data.RedX = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
//
|
||||
// else if (line.Contains("red_y="))
|
||||
// data.RedY = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
//
|
||||
// else if (line.Contains("green_x="))
|
||||
// data.GreenX = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
//
|
||||
// else if (line.Contains("green_y="))
|
||||
// data.GreenY = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
//
|
||||
// else if (line.Contains("blue_x="))
|
||||
// data.BlueY = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
//
|
||||
// else if (line.Contains("blue_y="))
|
||||
// data.BlueX = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
//
|
||||
// else if (line.Contains("white_point_x="))
|
||||
// data.WhiteY = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
//
|
||||
// else if (line.Contains("white_point_y="))
|
||||
// data.WhiteX = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
//
|
||||
// else if (line.Contains("max_luminance="))
|
||||
// data.LumaMax = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
//
|
||||
// else if (line.Contains("min_luminance="))
|
||||
// data.LumaMin = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
//
|
||||
// else if (line.Contains("max_content="))
|
||||
// data.MaxCll = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
//
|
||||
// else if (line.Contains("max_average="))
|
||||
// data.MaxFall = line.Contains("/") ? FractionToFloat(line.Split('=').Last()) : line.Split('=').Last();
|
||||
// }
|
||||
//
|
||||
// string infoMkvinfo = await AvProcess.RunMkvInfo($"{path.Wrap()}", OS.NmkoderProcess.ProcessType.Secondary);
|
||||
//
|
||||
// if (infoMkvinfo.Contains("+ Video track"))
|
||||
// {
|
||||
// string[] lines = infoMkvinfo.Split("+ Video track")[1].Split("+ Track")[0].Split("+ Tags")[0].SplitIntoLines();
|
||||
//
|
||||
// foreach (string line in lines)
|
||||
// {
|
||||
// if (line.Contains("+ Colour transfer:"))
|
||||
// data.ColorTransfer = ValidateNumber(line.Split(':')[1]).GetInt();
|
||||
//
|
||||
// else if (line.Contains("+ Colour matrix coefficients:"))
|
||||
// data.ColorMatrixCoeffs = ValidateNumber(line.Split(':')[1]).GetInt();
|
||||
//
|
||||
// else if (line.Contains("+ Colour primaries:"))
|
||||
// data.ColorPrimaries = ValidateNumber(line.Split(':')[1]).GetInt();
|
||||
//
|
||||
// else if (line.Contains("+ Colour range:"))
|
||||
// data.ColorRange = ValidateNumber(line.Split(':')[1]).GetInt();
|
||||
//
|
||||
// else if (line.Contains("+ Red colour coordinate x:"))
|
||||
// data.RedX = ValidateNumber(line.Split(':')[1]);
|
||||
//
|
||||
// else if (line.Contains("+ Red colour coordinate y:"))
|
||||
// data.RedY = ValidateNumber(line.Split(':')[1]);
|
||||
//
|
||||
// else if (line.Contains("+ Green colour coordinate x:"))
|
||||
// data.GreenX = ValidateNumber(line.Split(':')[1]);
|
||||
//
|
||||
// else if (line.Contains("+ Green colour coordinate y:"))
|
||||
// data.GreenY = ValidateNumber(line.Split(':')[1]);
|
||||
//
|
||||
// else if (line.Contains("+ Blue colour coordinate y:"))
|
||||
// data.BlueY = ValidateNumber(line.Split(':')[1]);
|
||||
//
|
||||
// else if (line.Contains("+ Blue colour coordinate x:"))
|
||||
// data.BlueX = ValidateNumber(line.Split(':')[1]);
|
||||
//
|
||||
// else if (line.Contains("+ White colour coordinate y:"))
|
||||
// data.WhiteY = ValidateNumber(line.Split(':')[1]);
|
||||
//
|
||||
// else if (line.Contains("+ White colour coordinate x:"))
|
||||
// data.WhiteX = ValidateNumber(line.Split(':')[1]);
|
||||
//
|
||||
// else if (line.Contains("+ Maximum luminance:"))
|
||||
// data.LumaMax = ValidateNumber(line.Split(':')[1]);
|
||||
//
|
||||
// else if (line.Contains("+ Minimum luminance:"))
|
||||
// data.LumaMin = ValidateNumber(line.Split(':')[1]);
|
||||
//
|
||||
// else if (line.Contains("+ Maximum content light:"))
|
||||
// data.MaxCll = ValidateNumber(line.Split(':')[1]);
|
||||
//
|
||||
// else if (line.Contains("+ Maximum frame light:"))
|
||||
// data.MaxFall = ValidateNumber(line.Split(':')[1]);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return data;
|
||||
// }
|
||||
|
||||
private static string FractionToFloat(string fracString)
|
||||
{
|
||||
string[] fracNums = fracString.Split('/');
|
||||
return ((float)fracNums[0].GetInt() / (float)fracNums[1].GetInt()).ToString("0.#######", new CultureInfo("en-US"));
|
||||
}
|
||||
|
||||
private static string ValidateNumber(string numStr)
|
||||
{
|
||||
return Double.Parse(numStr, NumberStyles.Float, CultureInfo.InvariantCulture).ToString("0.#######", new CultureInfo("en-US"));
|
||||
}
|
||||
|
||||
// public static async Task SetColorData(string path, VideoColorData d)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// string tmpPath = IoUtils.FilenameSuffix(path, ".tmp");
|
||||
//
|
||||
// List<string> args = new List<string>();
|
||||
//
|
||||
// args.Add($"-o {tmpPath.Wrap()}");
|
||||
// args.Add($"--colour-matrix 0:{d.ColorMatrixCoeffs}");
|
||||
// args.Add($"--colour-transfer-characteristics 0:{d.ColorTransfer}");
|
||||
// args.Add($"--colour-primaries 0:{d.ColorPrimaries}");
|
||||
// args.Add($"--colour-range 0:{d.ColorRange}");
|
||||
// if (!string.IsNullOrWhiteSpace(d.LumaMax)) args.Add($"--max-luminance 0:{d.LumaMax}");
|
||||
// if (!string.IsNullOrWhiteSpace(d.LumaMin)) args.Add($"--min-luminance 0:{d.LumaMin}");
|
||||
// if (!string.IsNullOrWhiteSpace(d.RedX)) args.Add($"--chromaticity-coordinates 0:{d.RedX},{d.RedY},{d.GreenX},{d.GreenY},{d.BlueX},{d.BlueY}");
|
||||
// if (!string.IsNullOrWhiteSpace(d.RedX)) args.Add($"--white-colour-coordinates 0:{d.WhiteX},{d.WhiteY}");
|
||||
// if (!string.IsNullOrWhiteSpace(d.MaxCll)) args.Add($"--max-content-light 0:{d.MaxCll}");
|
||||
// if (!string.IsNullOrWhiteSpace(d.MaxFall)) args.Add($"--max-frame-light 0:{d.MaxFall}");
|
||||
// args.Add($"{path.Wrap()}");
|
||||
//
|
||||
// await AvProcess.RunMkvMerge(string.Join(" ", args), OS.NmkoderProcess.ProcessType.Primary, true);
|
||||
//
|
||||
// if (!File.Exists(tmpPath))
|
||||
// {
|
||||
// Logger.Log($"Error: Muxing failed.");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// int filesizeDiffKb = (int)((Math.Abs(new FileInfo(path).Length - new FileInfo(tmpPath).Length)) / 1024);
|
||||
// double filesizeFactor = (double)(new FileInfo(tmpPath).Length) / (double)(new FileInfo(path).Length);
|
||||
// Logger.Log($"{MethodBase.GetCurrentMethod().DeclaringType}: Filesize ratio of remuxed file against original: {filesizeFactor}", true);
|
||||
//
|
||||
// if (filesizeDiffKb > 1024 && (filesizeFactor < 0.95d || filesizeFactor > 1.05d))
|
||||
// {
|
||||
// Logger.Log($"Warning: Output file size differs by >1MB is not within 5% of the original file's size! Won't delete original to be sure.");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// File.Delete(path);
|
||||
// File.Move(tmpPath, path);
|
||||
// }
|
||||
// }
|
||||
// catch (Exception e)
|
||||
// {
|
||||
// Logger.Log($"SetColorData Error: {e.Message}\n{e.StackTrace}");
|
||||
// }
|
||||
// }
|
||||
|
||||
public static int GetColorPrimaries(string s) // Defined by the "Color primaries" section of ISO/IEC 23091-4/ITU-T H.273
|
||||
{
|
||||
s = s.Trim().ToLower();
|
||||
if (s == "bt709") return 1;
|
||||
if (s == "bt470m") return 4;
|
||||
if (s == "bt470bg") return 5;
|
||||
if (s == "bt601") return 6;
|
||||
if (s == "smpte240m") return 7;
|
||||
if (s == "film") return 8;
|
||||
if (s == "bt2020") return 9;
|
||||
if (s == "smpte428") return 10;
|
||||
if (s == "smpte431") return 11;
|
||||
if (s == "smpte432") return 12;
|
||||
return 2; // Fallback: 2 = Unspecified
|
||||
}
|
||||
|
||||
public static int GetColorTransfer(string s) // Defined by the "Transfer characteristics" section of ISO/IEC 23091-4/ITU-T H.273
|
||||
{
|
||||
s = s.Trim().ToLower();
|
||||
if (s == "bt709") return 1;
|
||||
if (s == "gamma22" || s == "bt470m") return 4;
|
||||
if (s == "gamma28" || s == "bt470bg") return 5; // BT.470 System B, G (historical)
|
||||
if (s == "bt601" || s == "smpte170m") return 6; // BT.601
|
||||
if (s == "smpte240m") return 7; // SMPTE 240 M
|
||||
if (s == "linear") return 8; // Linear
|
||||
//if (s == "?") return 9; // Logarithmic(100 : 1 range)
|
||||
//if (s == "?") return 10; // Logarithmic (100 * Sqrt(10) : 1 range)
|
||||
if (s == "iec61966-2-4") return 11; // IEC 61966-2-4
|
||||
if (s == "bt1361" || s == "bt1361e") return 12; // BT.1361
|
||||
if (s == "srgb") return 13; // SRGB
|
||||
if (s == "bt2020-10") return 14; // BT.2020 10-bit systems
|
||||
if (s == "bt2020-12") return 15; // BT.2020 12-bit systems
|
||||
if (s == "smpte2084") return 16; // SMPTE ST 2084, ITU BT.2100 PQ
|
||||
if (s == "smpte428") return 17; // SMPTE ST 428
|
||||
if (s == "bt2100") return 18; // BT.2100 HLG, ARIB STD-B67
|
||||
return 2; // Fallback: 2 = Unspecified
|
||||
}
|
||||
|
||||
public static int GetMatrixCoeffs(string s) // Defined by the "Matrix coefficients" section of ISO/IEC 23091-4/ITU-T H.27
|
||||
{
|
||||
s = s.Trim().ToLower();
|
||||
if (s == "bt709") return 1;
|
||||
if (s == "fcc") return 4; // US FCC 73.628
|
||||
if (s == "bt470bg") return 5; // BT.470 System B, G (historical)
|
||||
if (s == "bt601" || s == "smpte170m") return 6; // BT.601
|
||||
if (s == "smpte240m") return 7; // SMPTE 240 M
|
||||
if (s == "ycgco") return 8; // YCgCo
|
||||
if (s == "bt2020ncl" || s == "bt2020nc") return 9; // BT.2020 non-constant luminance, BT.2100 YCbCr
|
||||
if (s == "bt2020") return 10; // BT.2020 constant luminance
|
||||
if (s == "smpte2085") return 11; // SMPTE ST 2085 YDzDx
|
||||
// 12: MC_CHROMAT_NCL - Chromaticity-derived non-constant luminance
|
||||
// 13: MC_CHROMAT_CL - Chromaticity-derived constant luminance
|
||||
// 14: MC_ICTCP BT.2100 - ICtCp
|
||||
return 2; // Fallback: 2 = Unspecified
|
||||
}
|
||||
|
||||
public static int GetColorRange(string s) // Defined by the "Matrix coefficients" section of ISO/IEC 23091-4/ITU-T H.27
|
||||
{
|
||||
s = s.Trim().ToLower();
|
||||
if (s == "tv") return 1; // TV
|
||||
if (s == "pc") return 2; // PC/Full
|
||||
return 0; // Fallback: Unspecified
|
||||
}
|
||||
|
||||
public static string FormatForAom(string colorspace)
|
||||
{
|
||||
return colorspace.Replace("bt2020-10", "bt2020-10bit").Replace("bt2020-12", "bt2020-12bit");
|
||||
}
|
||||
|
||||
#region Get string from int
|
||||
|
||||
public static string GetColorPrimariesString(int n)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 1: return "bt709";
|
||||
case 4: return "bt470m";
|
||||
case 5: return "bt470bg";
|
||||
case 6: return "bt601";
|
||||
case 7: return "smpte240m";
|
||||
case 8: return "film";
|
||||
case 9: return "bt2020";
|
||||
case 10: return "smpte428";
|
||||
case 11: return "smpte431";
|
||||
case 12: return "smpte432";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static string GetColorTransferString(int n)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 1: return "bt709";
|
||||
case 4: return "gamma22"; // "bt470m"
|
||||
case 5: return "gamma28"; // "bt470bg"
|
||||
case 6: return "bt601"; // "smpte170m"
|
||||
case 7: return "smpte240m";
|
||||
case 8: return "linear";
|
||||
case 11: return "iec61966-2-4";
|
||||
case 12: return "bt1361";
|
||||
case 13: return "srgb";
|
||||
case 14: return "bt2020-10";
|
||||
case 15: return "bt2020-12";
|
||||
case 16: return "smpte2084";
|
||||
case 17: return "smpte428";
|
||||
case 18: return "bt2100";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static string GetColorMatrixCoeffsString(int n)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 1: return "bt709";
|
||||
case 4: return "fcc";
|
||||
case 5: return "bt470bg";
|
||||
case 6: return "bt601";
|
||||
case 7: return "smpte240m";
|
||||
case 8: return "ycgco";
|
||||
case 9: return "bt2020ncl";
|
||||
case 10: return "bt2020";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static string GetColorRangeString(int n)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 1: return "tv";
|
||||
case 2: return "pc";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get friendly name from int
|
||||
|
||||
public static string GetColorPrimariesName(int n)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 1: return "BT.709";
|
||||
case 2: return "Unspecified";
|
||||
case 4: return "BT.470 System B, G (historical)";
|
||||
case 5: return "BT.470 System M (historical)";
|
||||
case 6: return "BT.601";
|
||||
case 7: return "SMPTE 240";
|
||||
case 8: return "Generic film (color filters using illuminant C)";
|
||||
case 9: return "BT.2020, BT.2100";
|
||||
case 10: return "SMPTE 428 (CIE 1921 XYZ)";
|
||||
case 11: return "SMPTE RP 431-2";
|
||||
case 12: return "SMPTE EG 432-1";
|
||||
case 22: return "EBU Tech. 3213-E";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
public static string GetColorTransferName(int n)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 1: return "BT.709";
|
||||
case 2: return "Unspecified";
|
||||
case 4: return "BT.470 System B, G (historical)";
|
||||
case 5: return "BT.470 System M (historical)";
|
||||
case 6: return "BT.601";
|
||||
case 7: return "SMPTE 240 M";
|
||||
case 8: return "Linear";
|
||||
case 9: return "Logarithmic (100 : 1 range)";
|
||||
case 10: return "Logarithmic (100 * Sqrt(10) : 1 range)";
|
||||
case 11: return "IEC 61966-2-4";
|
||||
case 12: return "BT.1361";
|
||||
case 13: return "sRGB or sYCC";
|
||||
case 14: return "BT.2020 10-bit systems";
|
||||
case 15: return "BT.2020 12-bit systems";
|
||||
case 16: return "SMPTE ST 2084, ITU BT.2100 PQ";
|
||||
case 17: return "SMPTE ST 428";
|
||||
case 18: return "BT.2100 HLG, ARIB STD-B67";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
public static string GetColorMatrixCoeffsName(int n)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 1: return "BT.709";
|
||||
case 2: return "Unspecified";
|
||||
case 4: return "US FCC 73.628";
|
||||
case 5: return "BT.470 System B, G (historical)";
|
||||
case 6: return "BT.601";
|
||||
case 7: return "SMPTE 240 M";
|
||||
case 8: return "YCgCo";
|
||||
case 9: return "BT.2020 non-constant luminance, BT.2100 YCbCr";
|
||||
case 10: return "BT.2020 constant luminance";
|
||||
case 11: return "SMPTE ST 2085 YDzDx";
|
||||
case 12: return "Chromaticity-derived non-constant luminance";
|
||||
case 13: return "Chromaticity-derived constant luminance";
|
||||
case 14: return "BT.2100 ICtCp";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
public static string GetColorRangeName(int n)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 0: return "Unspecified";
|
||||
case 1: return "TV (Limited)";
|
||||
case 2: return "PC (Full)";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue