mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2026-05-12 16:59:44 -05:00
FF-485: Created new flow element FFmpeg Builder: Pre-Execute
This commit is contained in:
@@ -3,304 +3,314 @@ using FileFlows.VideoNodes.FfmpegBuilderNodes.Models;
|
||||
using System.Runtime.InteropServices;
|
||||
using FileFlows.VideoNodes.Helpers;
|
||||
|
||||
namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
|
||||
|
||||
public class FfmpegBuilderExecutor: FfmpegBuilderNode
|
||||
{
|
||||
public class FfmpegBuilderExecutor: FfmpegBuilderNode
|
||||
public override string Icon => "far fa-file-video";
|
||||
public override int Inputs => 1;
|
||||
public override int Outputs => 2;
|
||||
public override FlowElementType Type => FlowElementType.BuildEnd;
|
||||
|
||||
public override string HelpUrl => "https://docs.fileflows.com/plugins/video-nodes/ffmpeg-builder";
|
||||
|
||||
public override bool NoEditorOnAdd => true;
|
||||
|
||||
[DefaultValue(true)]
|
||||
[Boolean(1)]
|
||||
public bool HardwareDecoding { get; set; }
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
public override string Icon => "far fa-file-video";
|
||||
public override int Inputs => 1;
|
||||
public override int Outputs => 2;
|
||||
public override FlowElementType Type => FlowElementType.BuildEnd;
|
||||
|
||||
public override string HelpUrl => "https://docs.fileflows.com/plugins/video-nodes/ffmpeg-builder";
|
||||
|
||||
public override bool NoEditorOnAdd => true;
|
||||
|
||||
[DefaultValue(true)]
|
||||
[Boolean(1)]
|
||||
public bool HardwareDecoding { get; set; }
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
var model = this.Model;
|
||||
if (model == null)
|
||||
{
|
||||
var model = this.Model;
|
||||
if (model == null)
|
||||
{
|
||||
args.Logger.ELog("FFMPEG Builder model is null");
|
||||
return -1;
|
||||
}
|
||||
else if (model.VideoInfo == null)
|
||||
{
|
||||
args.Logger.ELog("FFMPEG Builder VideoInfo is null");
|
||||
return -1;
|
||||
}
|
||||
else if (model.VideoInfo.FileName == null)
|
||||
{
|
||||
args.Logger.ELog("FFMPEG Builder VideoInfo Filename is null");
|
||||
return -1;
|
||||
}
|
||||
List<string> ffArgs = new List<string>();
|
||||
args.Logger.ELog("FFMPEG Builder model is null");
|
||||
return -1;
|
||||
}
|
||||
else if (model.VideoInfo == null)
|
||||
{
|
||||
args.Logger.ELog("FFMPEG Builder VideoInfo is null");
|
||||
return -1;
|
||||
}
|
||||
else if (model.VideoInfo.FileName == null)
|
||||
{
|
||||
args.Logger.ELog("FFMPEG Builder VideoInfo Filename is null");
|
||||
return -1;
|
||||
}
|
||||
List<string> ffArgs = new List<string>();
|
||||
|
||||
if (model.CustomParameters?.Any() == true)
|
||||
ffArgs.AddRange(model.CustomParameters);
|
||||
if (model.CustomParameters?.Any() == true)
|
||||
ffArgs.AddRange(model.CustomParameters);
|
||||
|
||||
bool hasChange = false;
|
||||
int actualIndex = 0;
|
||||
int overallIndex = 0;
|
||||
int currentType = 0;
|
||||
bool hasChange = false;
|
||||
int actualIndex = 0;
|
||||
int overallIndex = 0;
|
||||
int currentType = 0;
|
||||
|
||||
string sourceExtension = model.VideoInfo.FileName.Substring(model.VideoInfo.FileName.LastIndexOf(".") + 1).ToLower();
|
||||
string extension = (model.Extension?.EmptyAsNull() ?? "mkv").ToLower();
|
||||
string sourceExtension = model.VideoInfo.FileName.Substring(model.VideoInfo.FileName.LastIndexOf(".") + 1).ToLower();
|
||||
string extension = (model.Extension?.EmptyAsNull() ?? "mkv").ToLower();
|
||||
|
||||
foreach (var item in model.VideoStreams.Select((x, index) => (stream: (FfmpegStream)x, index, type: 1, list: model.VideoStreams.Select(x => (FfmpegStream)x).ToList())).Union(
|
||||
model.AudioStreams.Select((x, index) => (stream: (FfmpegStream)x, index, type: 2, list: model.AudioStreams.Select(x => (FfmpegStream)x).ToList()))).Union(
|
||||
model.SubtitleStreams.Select((x, index) => (stream: (FfmpegStream)x, index, type: 3, list: model.SubtitleStreams.Select(x => (FfmpegStream)x).ToList()))))
|
||||
{
|
||||
if (item.stream.Deleted)
|
||||
{
|
||||
hasChange = true;
|
||||
continue;
|
||||
}
|
||||
if (currentType != item.type)
|
||||
{
|
||||
actualIndex = 0;
|
||||
currentType = item.type;
|
||||
}
|
||||
|
||||
VideoFileStream vfs = item.stream is FfmpegVideoStream ? ((FfmpegVideoStream)item.stream).Stream :
|
||||
item.stream is FfmpegAudioStream ? ((FfmpegAudioStream)item.stream).Stream :
|
||||
((FfmpegSubtitleStream)item.stream).Stream;
|
||||
|
||||
|
||||
var streamArgs = item.stream.GetParameters(new ()
|
||||
{
|
||||
Logger = args.Logger,
|
||||
OutputOverallIndex = overallIndex,
|
||||
OutputTypeIndex = actualIndex,
|
||||
SourceExtension = sourceExtension,
|
||||
DestinationExtension = extension,
|
||||
UpdateDefaultFlag = item.list.Any(x => x.Deleted == false && x.IsDefault)
|
||||
});
|
||||
for (int i = 0; i < streamArgs.Length; i++)
|
||||
{
|
||||
streamArgs[i] = streamArgs[i].Replace("{sourceTypeIndex}", vfs.TypeIndex.ToString());
|
||||
streamArgs[i] = streamArgs[i].Replace("{index}", actualIndex.ToString());
|
||||
}
|
||||
|
||||
ffArgs.AddRange(streamArgs);
|
||||
hasChange |= item.stream.HasChange | item.stream.ForcedChange;
|
||||
++actualIndex;
|
||||
++overallIndex;
|
||||
}
|
||||
|
||||
if (model.MetadataParameters?.Any() == true)
|
||||
foreach (var item in model.VideoStreams.Select((x, index) => (stream: (FfmpegStream)x, index, type: 1, list: model.VideoStreams.Select(x => (FfmpegStream)x).ToList())).Union(
|
||||
model.AudioStreams.Select((x, index) => (stream: (FfmpegStream)x, index, type: 2, list: model.AudioStreams.Select(x => (FfmpegStream)x).ToList()))).Union(
|
||||
model.SubtitleStreams.Select((x, index) => (stream: (FfmpegStream)x, index, type: 3, list: model.SubtitleStreams.Select(x => (FfmpegStream)x).ToList()))))
|
||||
{
|
||||
if (item.stream.Deleted)
|
||||
{
|
||||
hasChange = true;
|
||||
ffArgs.AddRange(model.MetadataParameters);
|
||||
continue;
|
||||
}
|
||||
if (currentType != item.type)
|
||||
{
|
||||
actualIndex = 0;
|
||||
currentType = item.type;
|
||||
}
|
||||
|
||||
if (model.ForceEncode == false && hasChange == false && (string.IsNullOrWhiteSpace(model.Extension) || args.WorkingFile.ToLower().EndsWith("." + model.Extension.ToLower())))
|
||||
return 2; // nothing to do
|
||||
VideoFileStream vfs = item.stream is FfmpegVideoStream ? ((FfmpegVideoStream)item.stream).Stream :
|
||||
item.stream is FfmpegAudioStream ? ((FfmpegAudioStream)item.stream).Stream :
|
||||
((FfmpegSubtitleStream)item.stream).Stream;
|
||||
|
||||
|
||||
List<string> startArgs = new List<string>();
|
||||
if (model.InputFiles?.Any() == false)
|
||||
model.InputFiles.Add(new InputFile(args.WorkingFile));
|
||||
else
|
||||
model.InputFiles[0].FileName = args.WorkingFile;
|
||||
|
||||
startArgs.AddRange(new[] { "-fflags", "+genpts" }); //Generate missing PTS if DTS is present.
|
||||
|
||||
startArgs.AddRange(new[] {
|
||||
"-probesize", VideoInfoHelper.ProbeSize + "M"
|
||||
var streamArgs = item.stream.GetParameters(new ()
|
||||
{
|
||||
Logger = args.Logger,
|
||||
OutputOverallIndex = overallIndex,
|
||||
OutputTypeIndex = actualIndex,
|
||||
SourceExtension = sourceExtension,
|
||||
DestinationExtension = extension,
|
||||
UpdateDefaultFlag = item.list.Any(x => x.Deleted == false && x.IsDefault)
|
||||
});
|
||||
|
||||
|
||||
bool useHardwareEncoding = HardwareDecoding;
|
||||
if (Environment.GetEnvironmentVariable("HW_OFF") == "1")
|
||||
useHardwareEncoding = false;
|
||||
if (useHardwareEncoding)
|
||||
for (int i = 0; i < streamArgs.Length; i++)
|
||||
{
|
||||
startArgs.AddRange(GetHardwareDecodingArgs());
|
||||
}
|
||||
|
||||
if (ffArgs.Any(x => x.Contains("vaapi") && Helpers.VaapiHelper.VaapiLinux))
|
||||
{
|
||||
startArgs.Add("-vaapi_device");
|
||||
startArgs.Add(VaapiHelper.VaapiRenderDevice);
|
||||
streamArgs[i] = streamArgs[i].Replace("{sourceTypeIndex}", vfs.TypeIndex.ToString());
|
||||
streamArgs[i] = streamArgs[i].Replace("{index}", actualIndex.ToString());
|
||||
}
|
||||
|
||||
foreach (var file in model.InputFiles)
|
||||
{
|
||||
startArgs.Add("-i");
|
||||
startArgs.Add(file.FileName);
|
||||
}
|
||||
startArgs.Add("-y");
|
||||
if (extension.ToLower() == "mp4" && ffArgs.IndexOf("-movflags") < 0 && startArgs.IndexOf("-movflgs") < 0)
|
||||
{
|
||||
startArgs.AddRange(new[] { "-movflags", "+faststart" });
|
||||
}
|
||||
|
||||
ffArgs = startArgs.Concat(ffArgs).ToList();
|
||||
// FF-378: keep attachments (fonts etc)
|
||||
ffArgs.AddRange(new[] { "-map", "0:t?", "-c:t", "copy" });
|
||||
var ffmpeg = FFMPEG;
|
||||
|
||||
// string strFfArgs = string.Join(" ", ffArgs);
|
||||
// if ((strFfArgs.Contains("libaom-av1") || strFfArgs.Contains("libsvtav1")))
|
||||
// {
|
||||
// args.Logger.DLog("Using AV1");
|
||||
// if (File.Exists(ffmpeg + "-av1"))
|
||||
// {
|
||||
// ffmpeg = ffmpeg + "-av1";
|
||||
// if(ffArgs.IndexOf("-hwaccel") > 0)
|
||||
// {
|
||||
// ffArgs.RemoveRange(ffArgs.IndexOf("-hwaccel"), 2);
|
||||
// if(ffArgs.IndexOf("-hwaccel_output_format") > 0)
|
||||
// {
|
||||
// ffArgs.RemoveRange(ffArgs.IndexOf("-hwaccel_output_format"), 2);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// args.Logger.DLog("Did not find custom FFMPEG AV1: " + ffmpeg + "-av1");
|
||||
// }
|
||||
|
||||
|
||||
if (Encode(args, ffmpeg, ffArgs, extension, dontAddInputFile: true) == false)
|
||||
return -1;
|
||||
|
||||
foreach (var file in model.InputFiles)
|
||||
{
|
||||
if (file.DeleteAfterwards)
|
||||
{
|
||||
if (File.Exists(file.FileName) == false)
|
||||
continue;
|
||||
|
||||
args.Logger.ILog("Deleting file: " + file.FileName);
|
||||
try
|
||||
{
|
||||
File.Delete(file.FileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
args.Logger.WLog("Failed to delete file: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
ffArgs.AddRange(streamArgs);
|
||||
hasChange |= item.stream.HasChange | item.stream.ForcedChange;
|
||||
++actualIndex;
|
||||
++overallIndex;
|
||||
}
|
||||
|
||||
internal string[] GetHardwareDecodingArgs()
|
||||
if (model.MetadataParameters?.Any() == true)
|
||||
{
|
||||
string testFile = Path.Combine(Args.TempPath, Guid.NewGuid() + ".hwtest.mkv");
|
||||
var video = this.Model.VideoStreams.Where(x => x.Stream.IsImage == false).FirstOrDefault();
|
||||
if (string.IsNullOrWhiteSpace(video?.Stream?.Codec))
|
||||
return new string[] { };
|
||||
bool isH264 = video.Stream.Codec.Contains("264");
|
||||
bool isHevc = video.Stream.Codec.Contains("265") || video.Stream.Codec.ToLower().Contains("hevc");
|
||||
hasChange = true;
|
||||
ffArgs.AddRange(model.MetadataParameters);
|
||||
}
|
||||
|
||||
var decoders = isH264 ? Decoders_h264() :
|
||||
isHevc ? Decoders_hevc() :
|
||||
Decoders_Default();
|
||||
try
|
||||
if (model.ForceEncode == false && hasChange == false && (string.IsNullOrWhiteSpace(model.Extension) || args.WorkingFile.ToLower().EndsWith("." + model.Extension.ToLower())))
|
||||
return 2; // nothing to do
|
||||
|
||||
|
||||
List<string> startArgs = new List<string>();
|
||||
if (model.InputFiles?.Any() == false)
|
||||
model.InputFiles.Add(new InputFile(args.WorkingFile));
|
||||
else
|
||||
model.InputFiles[0].FileName = args.WorkingFile;
|
||||
|
||||
startArgs.AddRange(new[] { "-fflags", "+genpts" }); //Generate missing PTS if DTS is present.
|
||||
|
||||
startArgs.AddRange(new[] {
|
||||
"-probesize", VideoInfoHelper.ProbeSize + "M"
|
||||
});
|
||||
|
||||
|
||||
bool useHardwareEncoding = HardwareDecoding;
|
||||
if (Environment.GetEnvironmentVariable("HW_OFF") == "1")
|
||||
useHardwareEncoding = false;
|
||||
if (useHardwareEncoding)
|
||||
{
|
||||
startArgs.AddRange(GetHardwareDecodingArgs());
|
||||
}
|
||||
|
||||
if (ffArgs.Any(x => x.Contains("vaapi") && Helpers.VaapiHelper.VaapiLinux))
|
||||
{
|
||||
startArgs.Add("-vaapi_device");
|
||||
startArgs.Add(VaapiHelper.VaapiRenderDevice);
|
||||
}
|
||||
|
||||
foreach (var file in model.InputFiles)
|
||||
{
|
||||
startArgs.Add("-i");
|
||||
startArgs.Add(file.FileName);
|
||||
}
|
||||
startArgs.Add("-y");
|
||||
if (extension.ToLower() == "mp4" && ffArgs.IndexOf("-movflags") < 0 && startArgs.IndexOf("-movflgs") < 0)
|
||||
{
|
||||
startArgs.AddRange(new[] { "-movflags", "+faststart" });
|
||||
}
|
||||
|
||||
ffArgs = startArgs.Concat(ffArgs).ToList();
|
||||
// FF-378: keep attachments (fonts etc)
|
||||
ffArgs.AddRange(new[] { "-map", "0:t?", "-c:t", "copy" });
|
||||
var ffmpeg = FFMPEG;
|
||||
|
||||
// string strFfArgs = string.Join(" ", ffArgs);
|
||||
// if ((strFfArgs.Contains("libaom-av1") || strFfArgs.Contains("libsvtav1")))
|
||||
// {
|
||||
// args.Logger.DLog("Using AV1");
|
||||
// if (File.Exists(ffmpeg + "-av1"))
|
||||
// {
|
||||
// ffmpeg = ffmpeg + "-av1";
|
||||
// if(ffArgs.IndexOf("-hwaccel") > 0)
|
||||
// {
|
||||
// ffArgs.RemoveRange(ffArgs.IndexOf("-hwaccel"), 2);
|
||||
// if(ffArgs.IndexOf("-hwaccel_output_format") > 0)
|
||||
// {
|
||||
// ffArgs.RemoveRange(ffArgs.IndexOf("-hwaccel_output_format"), 2);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// args.Logger.DLog("Did not find custom FFMPEG AV1: " + ffmpeg + "-av1");
|
||||
// }
|
||||
|
||||
if(string.IsNullOrWhiteSpace(model.PreExecuteCode) == false)
|
||||
{
|
||||
var preExecutor = new PreExecutor(args, model.PreExecuteCode, ffArgs);
|
||||
if (preExecutor.Run() == false)
|
||||
return -1;
|
||||
if (preExecutor.Args?.Any() == true && string.Join(" ", ffArgs) != string.Join(" ", preExecutor.Args))
|
||||
{
|
||||
foreach (var hw in decoders)
|
||||
{
|
||||
if (hw == null)
|
||||
continue;
|
||||
if (CanUseHardwareEncoding.DisabledByVariables(Args, hw))
|
||||
continue;
|
||||
try
|
||||
{
|
||||
var arguments = new List<string>()
|
||||
{
|
||||
"-y",
|
||||
};
|
||||
arguments.AddRange(hw);
|
||||
arguments.AddRange(new[]
|
||||
{
|
||||
"-f", "lavfi",
|
||||
"-i", "color=color=red",
|
||||
"-frames:v", "10",
|
||||
testFile
|
||||
});
|
||||
|
||||
var result = Args.Execute(new ExecuteArgs
|
||||
{
|
||||
Command = FFMPEG,
|
||||
ArgumentList = arguments.ToArray()
|
||||
});
|
||||
if (result.ExitCode == 0)
|
||||
{
|
||||
Args.Logger?.ILog("Supported hardware decoding detected: " + string.Join(" ", hw));
|
||||
|
||||
return hw;
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
Args.Logger?.ILog("No hardware decoding availble");
|
||||
return new string[] { };
|
||||
args.Logger.ILog("Pre-Executor updated FFmpeg Arguments!");
|
||||
ffArgs = preExecutor.Args;
|
||||
}
|
||||
finally
|
||||
}
|
||||
|
||||
|
||||
if (Encode(args, ffmpeg, ffArgs, extension, dontAddInputFile: true) == false)
|
||||
return -1;
|
||||
|
||||
foreach (var file in model.InputFiles)
|
||||
{
|
||||
if (file.DeleteAfterwards)
|
||||
{
|
||||
if (File.Exists(file.FileName) == false)
|
||||
continue;
|
||||
|
||||
args.Logger.ILog("Deleting file: " + file.FileName);
|
||||
try
|
||||
{
|
||||
if (File.Exists(testFile))
|
||||
File.Delete(testFile);
|
||||
File.Delete(file.FileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
args.Logger.WLog("Failed to delete file: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
internal string[] GetHardwareDecodingArgs()
|
||||
{
|
||||
string testFile = Path.Combine(Args.TempPath, Guid.NewGuid() + ".hwtest.mkv");
|
||||
var video = this.Model.VideoStreams.Where(x => x.Stream.IsImage == false).FirstOrDefault();
|
||||
if (string.IsNullOrWhiteSpace(video?.Stream?.Codec))
|
||||
return new string[] { };
|
||||
bool isH264 = video.Stream.Codec.Contains("264");
|
||||
bool isHevc = video.Stream.Codec.Contains("265") || video.Stream.Codec.ToLower().Contains("hevc");
|
||||
|
||||
var decoders = isH264 ? Decoders_h264() :
|
||||
isHevc ? Decoders_hevc() :
|
||||
Decoders_Default();
|
||||
try
|
||||
{
|
||||
foreach (var hw in decoders)
|
||||
{
|
||||
if (hw == null)
|
||||
continue;
|
||||
if (CanUseHardwareEncoding.DisabledByVariables(Args, hw))
|
||||
continue;
|
||||
try
|
||||
{
|
||||
var arguments = new List<string>()
|
||||
{
|
||||
"-y",
|
||||
};
|
||||
arguments.AddRange(hw);
|
||||
arguments.AddRange(new[]
|
||||
{
|
||||
"-f", "lavfi",
|
||||
"-i", "color=color=red",
|
||||
"-frames:v", "10",
|
||||
testFile
|
||||
});
|
||||
|
||||
var result = Args.Execute(new ExecuteArgs
|
||||
{
|
||||
Command = FFMPEG,
|
||||
ArgumentList = arguments.ToArray()
|
||||
});
|
||||
if (result.ExitCode == 0)
|
||||
{
|
||||
Args.Logger?.ILog("Supported hardware decoding detected: " + string.Join(" ", hw));
|
||||
|
||||
return hw;
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
Args.Logger?.ILog("No hardware decoding availble");
|
||||
return new string[] { };
|
||||
}
|
||||
|
||||
private static readonly bool IsMac = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
|
||||
|
||||
private string[][] Decoders_h264()
|
||||
finally
|
||||
{
|
||||
return new[]
|
||||
try
|
||||
{
|
||||
//new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "cuda" }, // this fails with Impossible to convert between the formats supported by the filter 'Parsed_crop_0' and the filter 'auto_scale_0'
|
||||
IsMac ? new [] { "-hwaccel", "videotoolbox" } : null,
|
||||
new [] { "-hwaccel", "cuda" },
|
||||
new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "qsv" },
|
||||
new [] { "-hwaccel", "vaapi", "-hwaccel_output_format", "vaapi" },
|
||||
new [] { "-hwaccel", "dxva2" },
|
||||
new [] { "-hwaccel", "d3d11va" },
|
||||
new [] { "-hwaccel", "opencl" },
|
||||
};
|
||||
if (File.Exists(testFile))
|
||||
File.Delete(testFile);
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
}
|
||||
|
||||
private string[][] Decoders_hevc()
|
||||
private static readonly bool IsMac = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
|
||||
|
||||
private string[][] Decoders_h264()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
//new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "cuda" }, // this fails with Impossible to convert between the formats supported by the filter 'Parsed_crop_0' and the filter 'auto_scale_0'
|
||||
IsMac ? new [] { "-hwaccel", "videotoolbox" } : null,
|
||||
new [] { "-hwaccel", "cuda" },
|
||||
new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "qsv" },
|
||||
new [] { "-hwaccel", "vaapi", "-hwaccel_output_format", "vaapi" },
|
||||
new [] { "-hwaccel", "dxva2" },
|
||||
new [] { "-hwaccel", "d3d11va" },
|
||||
new [] { "-hwaccel", "opencl" },
|
||||
};
|
||||
}
|
||||
//new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "cuda" }, // this fails with Impossible to convert between the formats supported by the filter 'Parsed_crop_0' and the filter 'auto_scale_0'
|
||||
IsMac ? new [] { "-hwaccel", "videotoolbox" } : null,
|
||||
new [] { "-hwaccel", "cuda" },
|
||||
new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "qsv" },
|
||||
new [] { "-hwaccel", "vaapi", "-hwaccel_output_format", "vaapi" },
|
||||
new [] { "-hwaccel", "dxva2" },
|
||||
new [] { "-hwaccel", "d3d11va" },
|
||||
new [] { "-hwaccel", "opencl" },
|
||||
};
|
||||
}
|
||||
|
||||
private string[][] Decoders_Default()
|
||||
private string[][] Decoders_hevc()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
//new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "cuda" }, // this fails with Impossible to convert between the formats supported by the filter 'Parsed_crop_0' and the filter 'auto_scale_0'
|
||||
new [] { "-hwaccel", "cuda" },
|
||||
new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "qsv" },
|
||||
new [] { "-hwaccel", "vaapi", "-hwaccel_output_format", "vaapi" },
|
||||
new [] { "-hwaccel", "dxva2" },
|
||||
new [] { "-hwaccel", "d3d11va" },
|
||||
new [] { "-hwaccel", "opencl" },
|
||||
};
|
||||
}
|
||||
//new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "cuda" }, // this fails with Impossible to convert between the formats supported by the filter 'Parsed_crop_0' and the filter 'auto_scale_0'
|
||||
IsMac ? new [] { "-hwaccel", "videotoolbox" } : null,
|
||||
new [] { "-hwaccel", "cuda" },
|
||||
new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "qsv" },
|
||||
new [] { "-hwaccel", "vaapi", "-hwaccel_output_format", "vaapi" },
|
||||
new [] { "-hwaccel", "dxva2" },
|
||||
new [] { "-hwaccel", "d3d11va" },
|
||||
new [] { "-hwaccel", "opencl" },
|
||||
};
|
||||
}
|
||||
|
||||
private string[][] Decoders_Default()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
//new [] { "-hwaccel", "cuda", "-hwaccel_output_format", "cuda" }, // this fails with Impossible to convert between the formats supported by the filter 'Parsed_crop_0' and the filter 'auto_scale_0'
|
||||
new [] { "-hwaccel", "cuda" },
|
||||
new [] { "-hwaccel", "qsv", "-hwaccel_output_format", "qsv" },
|
||||
new [] { "-hwaccel", "vaapi", "-hwaccel_output_format", "vaapi" },
|
||||
new [] { "-hwaccel", "dxva2" },
|
||||
new [] { "-hwaccel", "d3d11va" },
|
||||
new [] { "-hwaccel", "opencl" },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using FileFlows.VideoNodes.FfmpegBuilderNodes.Models;
|
||||
|
||||
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
|
||||
|
||||
/// <summary>
|
||||
/// Flow element that can alter the command line arguments that the FFmpeg Builder will run
|
||||
/// </summary>
|
||||
public class FfmpegBuilderPreExecute : FfmpegBuilderNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Help URL for this node
|
||||
/// </summary>
|
||||
public override string HelpUrl => "https://docs.fileflows.com/plugins/video-nodes/ffmpeg-builder/pre-execute";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the icon for this node
|
||||
/// </summary>
|
||||
public override string Icon => "fas fa-mortar-pestle";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of outputs for this element
|
||||
/// </summary>
|
||||
public override int Outputs => 1;
|
||||
|
||||
[Required]
|
||||
[DefaultValue("// Custom javascript code that runs just before the FFmpeg Builder: Executor executes the FFmpeg process.\n// Here you can alter FFmpeg parameters etc. See Help for more information.")]
|
||||
[Code(1)]
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Executes the node
|
||||
/// </summary>
|
||||
/// <param name="args">the node parameters</param>
|
||||
/// <returns>the output number to execute next</returns>
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
this.Model.PreExecuteCode = this.Code;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,11 @@
|
||||
/// Gets or sets if the builder should forcable execute even if nothing appears to have changed
|
||||
/// </summary>
|
||||
public bool ForceEncode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the code to run prior to FFmpeg Executing
|
||||
/// </summary>
|
||||
public string PreExecuteCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video information for this video file
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
|
||||
|
||||
/// <summary>
|
||||
/// The FFmpeg Builder PreExecutor
|
||||
/// </summary>
|
||||
public class PreExecutor
|
||||
{
|
||||
private readonly string code;
|
||||
private readonly NodeParameters args;
|
||||
/// <summary>
|
||||
/// Gets or sets the FFmpeg Arguments
|
||||
/// </summary>
|
||||
public List<string> Args { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an instance of the pre-executor
|
||||
/// </summary>
|
||||
/// <param name="args">the node parameters</param>
|
||||
/// <param name="code">the code to run</param>
|
||||
/// <param name="ffArgs">the current FFmpeg arguments</param>
|
||||
public PreExecutor(NodeParameters args, string code, List<string> ffArgs)
|
||||
{
|
||||
this.args = args;
|
||||
this.code = code;
|
||||
this.Args = ffArgs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the pre-executor
|
||||
/// </summary>
|
||||
/// <returns>if the execution was successful</returns>
|
||||
public bool Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
int exitCode = args.ScriptExecutor.Execute(new FileFlows.Plugin.Models.ScriptExecutionArgs
|
||||
{
|
||||
Args = args,
|
||||
Code = code + "\n\n// automatically added return code\nreturn 1;",
|
||||
AdditionalArguments = new ()
|
||||
{
|
||||
{ "FFmpeg", this }
|
||||
}
|
||||
});
|
||||
args.Logger.ILog("PreExecute Exit Code: " + exitCode);
|
||||
return exitCode >= 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
args.Logger?.ELog("Failed executing pre-executor: " + ex.Message + Environment.NewLine + ex.StackTrace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -359,30 +359,40 @@
|
||||
"CroppingThreshold-Help": "The amount of pixels that must be greater than to crop. E.g. if there's only 5 pixels detected as black space, you may consider this too small to crop."
|
||||
}
|
||||
},
|
||||
"FfmpegBuilderPreExecute": {
|
||||
"Label": "FFMPEG Buidler: Pre-Execute",
|
||||
"Description": "This element lets you run custom code just prior to the [FFmpeg Builder: Executor](https://docs.fileflows.com/plugins/video-nodes/ffmpeg-builder) executes FFmpeg.\n\nThis allows you to alter the arguments passed into FFmpeg.",
|
||||
"Outputs": {
|
||||
"1": "Pre-Execute set"
|
||||
},
|
||||
"Fields": {
|
||||
"Code": "Code"
|
||||
}
|
||||
},
|
||||
"FfmpegBuilderRemuxToMkv": {
|
||||
"Label": "FFMPEG Builder: Remux to MKV",
|
||||
"Descritption": "Remuxes a video file into a MKV container.",
|
||||
"Description": "Remuxes a video file into a MKV container.",
|
||||
"Outputs": {
|
||||
"1": "FFMPEG Builder set to remux to MKV"
|
||||
}
|
||||
},
|
||||
"FfmpegBuilderRemuxToMP4": {
|
||||
"Label": "FFMPEG Builder: Remux to MP4",
|
||||
"Descritption": "Remuxes a video file into a MP4 container.",
|
||||
"Description": "Remuxes a video file into a MP4 container.",
|
||||
"Outputs": {
|
||||
"1": "FFMPEG Builder set to remux to MP4"
|
||||
}
|
||||
},
|
||||
"FfmpegBuilderRemuxToMov": {
|
||||
"Label": "FFMPEG Builder: Remux to MOV",
|
||||
"Descritption": "Remuxes a video file into a MOV container.",
|
||||
"Description": "Remuxes a video file into a MOV container.",
|
||||
"Outputs": {
|
||||
"1": "FFMPEG Builder set to remux to MOV"
|
||||
}
|
||||
},
|
||||
"FfmpegBuilderRemuxToWebm": {
|
||||
"Label": "FFMPEG Builder: Remux to WEBM",
|
||||
"Descritption": "Remuxes a video file into a WEGM container.",
|
||||
"Description": "Remuxes a video file into a WEGM container.",
|
||||
"Outputs": {
|
||||
"1": "FFMPEG Builder set to remux to WEGM"
|
||||
}
|
||||
@@ -480,7 +490,7 @@
|
||||
}
|
||||
},
|
||||
"ReadVideoInfo": {
|
||||
"Descritption": "Reads the video information from the current working file and updates the vi variables.",
|
||||
"Description": "Reads the video information from the current working file and updates the vi variables.",
|
||||
"Outputs": {
|
||||
"1": "File was a video file and information read into flow",
|
||||
"2": "File was not a video file or failed to be read"
|
||||
|
||||
Reference in New Issue
Block a user