mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2026-01-06 10:09:32 -06:00
add PreExecute to Video Nodes
started adding Video Encode node for basic settings
This commit is contained in:
@@ -95,8 +95,6 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
var audio = new FfmpegAudioStream();
|
||||
|
||||
var bestAudio = GetBestAudioTrack(args, Model.AudioStreams.Select(x => x.Stream));
|
||||
|
||||
@@ -24,12 +24,6 @@ public class FfmpegBuilderAudioAdjustVolume : FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
if (Model.AudioStreams?.Any() != true)
|
||||
{
|
||||
args.Logger?.ILog("No audio streams detected");
|
||||
|
||||
@@ -24,12 +24,6 @@ public class FfmpegBuilderAudioNormalization : FfmpegBuilderNode
|
||||
[RequiresUnreferencedCode("")]
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
if (Model.AudioStreams?.Any() != true)
|
||||
{
|
||||
args.Logger?.ILog("No audio streams detected");
|
||||
@@ -60,7 +54,7 @@ public class FfmpegBuilderAudioNormalization : FfmpegBuilderNode
|
||||
item.stream.Filter.Add(normalizedTracks[audio.TypeIndex]);
|
||||
else
|
||||
{
|
||||
string twoPass = AudioNormalization.DoTwoPass(this, args, ffmpegExe, audio.TypeIndex);
|
||||
string twoPass = AudioNormalization.DoTwoPass(this, args, FFMPEG, audio.TypeIndex);
|
||||
item.stream.Filter.Add(twoPass);
|
||||
normalizedTracks.Add(audio.TypeIndex, twoPass);
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@ public class FfmpegBuilderAudioSetLanguage : FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
bool changes = false;
|
||||
foreach (var at in Model.AudioStreams)
|
||||
{
|
||||
|
||||
@@ -28,7 +28,6 @@ public class FfmpegBuilderAudioTrackRemover: FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
this.Init(args);
|
||||
bool removing = false;
|
||||
Regex? regex = null;
|
||||
int index = -1;
|
||||
|
||||
@@ -20,8 +20,6 @@ public class FfmpegBuilderAudioTrackReorder : FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
OrderedTracks = OrderedTracks?.Select(x => x.ToLower())?.ToList() ?? new();
|
||||
|
||||
var reordered = Reorder(Model.AudioStreams);
|
||||
|
||||
@@ -20,7 +20,6 @@ public class FfmpegBuilderAddInputFile : FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
this.Init(args);
|
||||
var dir = new FileInfo(UseSourceDirectory ? args.FileName : args.WorkingFile).Directory;
|
||||
if (dir.Exists == false)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
this.Init(args);
|
||||
var model = this.Model;
|
||||
List<string> ffArgs = new List<string>();
|
||||
ffArgs.AddRange(new[] { "-strict", "-2" }); // allow experimental stuff
|
||||
@@ -80,7 +79,7 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
ffArgs = startArgs.Concat(ffArgs).ToList();
|
||||
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, extension, dontAddInputFile: true) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, extension, dontAddInputFile: true) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
@@ -88,15 +87,15 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
|
||||
internal string[] GetHardwareDecodingArgs()
|
||||
{
|
||||
string testFile = Path.Combine(args.TempPath, Guid.NewGuid() + ".hwtest.mkv");
|
||||
string testFile = Path.Combine(Args.TempPath, Guid.NewGuid() + ".hwtest.mkv");
|
||||
foreach(var hw in new [] { "cuda", "dxva2", "qsv", "d3d11va", "opencl" })
|
||||
{
|
||||
// ffmpeg -y -hwaccel qsvf -f lavfi -i color=color=red -frames:v 10 test.mkv
|
||||
try
|
||||
{
|
||||
var result = args.Execute(new ExecuteArgs
|
||||
var result = Args.Execute(new ExecuteArgs
|
||||
{
|
||||
Command = ffmpegExe,
|
||||
Command = FFMPEG,
|
||||
ArgumentList = new[]
|
||||
{
|
||||
"-y",
|
||||
@@ -109,14 +108,14 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
});
|
||||
if (result.ExitCode == 0)
|
||||
{
|
||||
args.Logger?.ILog("Supported hardware decoding detected: " + hw);
|
||||
Args.Logger?.ILog("Supported hardware decoding detected: " + hw);
|
||||
return new[] { "-hwaccel", hw };
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
args.Logger?.ILog("No hardware decoding availble");
|
||||
Args.Logger?.ILog("No hardware decoding availble");
|
||||
return new string[] { };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
public abstract class FfmpegBuilderNode: EncodingNode
|
||||
{
|
||||
private const string MODEL_KEY = "FFMPEG_BUILDER_MODEL";
|
||||
protected string ffmpegExe;
|
||||
|
||||
public override int Inputs => 1;
|
||||
public override int Outputs => 1;
|
||||
@@ -14,15 +13,15 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
public override FlowElementType Type => FlowElementType.BuildPart;
|
||||
public override string HelpUrl => "https://github.com/revenz/FileFlows/wiki/FFMPEG-Builder";
|
||||
|
||||
protected void Init(NodeParameters args)
|
||||
{
|
||||
this.args = args;
|
||||
this.ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
throw new Exception("FFMPEG not found");
|
||||
|
||||
public override bool PreExecute(NodeParameters args)
|
||||
{
|
||||
if (base.PreExecute(args) == false)
|
||||
return false;
|
||||
|
||||
if (Model == null)
|
||||
throw new Exception("FFMPEG Builder Model not set, use the \"FFMPEG Builder Start\" node to first");
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
@@ -36,21 +35,21 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (args.Variables.ContainsKey(MODEL_KEY))
|
||||
return args.Variables[MODEL_KEY] as FfmpegModel;
|
||||
if (Args.Variables.ContainsKey(MODEL_KEY))
|
||||
return Args.Variables[MODEL_KEY] as FfmpegModel;
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (args.Variables.ContainsKey(MODEL_KEY))
|
||||
if (Args.Variables.ContainsKey(MODEL_KEY))
|
||||
{
|
||||
if (value == null)
|
||||
args.Variables.Remove(MODEL_KEY);
|
||||
Args.Variables.Remove(MODEL_KEY);
|
||||
else
|
||||
args.Variables[MODEL_KEY] = value;
|
||||
Args.Variables[MODEL_KEY] = value;
|
||||
}
|
||||
else if(value != null)
|
||||
args.Variables.Add(MODEL_KEY, value);
|
||||
Args.Variables.Add(MODEL_KEY, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +101,7 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
matchString = subtitle.Stream.Title + ":" + subtitle.Stream.Language + ":" + subtitle.Stream.Codec;
|
||||
else
|
||||
return false;
|
||||
args.Logger?.ILog($"Track [{index}] test string: {matchString}");
|
||||
Args.Logger?.ILog($"Track [{index}] test string: {matchString}");
|
||||
match = new Regex(pattern, RegexOptions.IgnoreCase).IsMatch(matchString);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,13 +11,11 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
this.args = args;
|
||||
VideoInfo videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
this.Model = Models.FfmpegModel.CreateModel(videoInfo);
|
||||
this.Init(args);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
VideoInfo videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
@@ -27,7 +25,7 @@
|
||||
return 2;
|
||||
}
|
||||
|
||||
string tempMetaDataFile = AutoChapters.GenerateMetaDataFile(this, args, videoInfo, ffmpegExe, this.Percent, this.MinimumLength);
|
||||
string tempMetaDataFile = AutoChapters.GenerateMetaDataFile(this, args, videoInfo, FFMPEG, this.Percent, this.MinimumLength);
|
||||
if (string.IsNullOrEmpty(tempMetaDataFile))
|
||||
return 2;
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ public class FfmpegBuilderComskipChapters : FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
VideoInfo videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
@@ -43,8 +43,6 @@ public class FfmpegBuilderSubtitleFormatRemover : FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
this.Init(args);
|
||||
|
||||
if (RemoveAll)
|
||||
{
|
||||
if (Model.SubtitleStreams.Any() == false)
|
||||
|
||||
@@ -42,7 +42,6 @@ public class FfmpegBuilderSubtitleTrackMerge : FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
this.Init(args);
|
||||
var dir = new FileInfo(UseSourceDirectory ? args.FileName : args.WorkingFile).Directory;
|
||||
if (dir.Exists == false)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,6 @@ public class FfmpegBuilderSubtitleTrackRemover : FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
this.Init(args);
|
||||
bool removing = false;
|
||||
var regex = new Regex(this.Pattern, RegexOptions.IgnoreCase);
|
||||
foreach(var stream in Model.SubtitleStreams)
|
||||
|
||||
@@ -1,41 +1,33 @@
|
||||
namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
|
||||
public class FfmpegBuilderCropBlackBars : FfmpegBuilderNode
|
||||
{
|
||||
public class FfmpegBuilderCropBlackBars : FfmpegBuilderNode
|
||||
[NumberInt(1)]
|
||||
[DefaultValue(10)]
|
||||
public int CroppingThreshold { get; set; }
|
||||
public override int Outputs => 2;
|
||||
|
||||
public override string HelpUrl => "https://github.com/revenz/FileFlows/wiki/FFMPEG-Builder:-Crop-Black-Bars";
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
[NumberInt(1)]
|
||||
[DefaultValue(10)]
|
||||
public int CroppingThreshold { get; set; }
|
||||
public override int Outputs => 2;
|
||||
|
||||
public override string HelpUrl => "https://github.com/revenz/FileFlows/wiki/FFMPEG-Builder:-Crop-Black-Bars";
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
string ffmpeg = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpeg))
|
||||
return -1;
|
||||
|
||||
var videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null || videoInfo.VideoStreams?.Any() != true)
|
||||
return -1;
|
||||
var videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null || videoInfo.VideoStreams?.Any() != true)
|
||||
return -1;
|
||||
|
||||
|
||||
string crop = DetectBlackBars.Detect(ffmpeg, videoInfo, args, this.CroppingThreshold);
|
||||
if (string.IsNullOrWhiteSpace(crop))
|
||||
return 2;
|
||||
string crop = DetectBlackBars.Detect(FFMPEG, videoInfo, args, this.CroppingThreshold);
|
||||
if (string.IsNullOrWhiteSpace(crop))
|
||||
return 2;
|
||||
|
||||
//var parts = crop.Split(':');
|
||||
////parts[2] = "iw-" + parts[2];
|
||||
////parts[3] = "ih-" + parts[3];
|
||||
//crop = String.Join(":", parts.Take(2));
|
||||
//var parts = crop.Split(':');
|
||||
////parts[2] = "iw-" + parts[2];
|
||||
////parts[3] = "ih-" + parts[3];
|
||||
//crop = String.Join(":", parts.Take(2));
|
||||
|
||||
args.Logger?.ILog("Black bars detected, crop: " + crop);
|
||||
args.Logger?.ILog("Black bars detected, crop: " + crop);
|
||||
|
||||
var video = Model.VideoStreams[0];
|
||||
video.Filter.AddRange(new[] { "crop=" + crop });
|
||||
return 1;
|
||||
}
|
||||
var video = Model.VideoStreams[0];
|
||||
video.Filter.AddRange(new[] { "crop=" + crop });
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,26 @@
|
||||
namespace FileFlows.VideoNodes.FfmpegBuilderNodes
|
||||
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
|
||||
|
||||
public class FfmpegBuilderHdrToSdr : FfmpegBuilderNode
|
||||
{
|
||||
public class FfmpegBuilderHdrToSdr : FfmpegBuilderNode
|
||||
public override int Outputs => 2;
|
||||
|
||||
public override string HelpUrl => "https://github.com/revenz/FileFlows/wiki/FFMPEG-Builder:-HDR-to-SDR";
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
public override int Outputs => 2;
|
||||
var videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null || videoInfo.VideoStreams?.Any() != true)
|
||||
return -1;
|
||||
|
||||
public override string HelpUrl => "https://github.com/revenz/FileFlows/wiki/FFMPEG-Builder:-HDR-to-SDR";
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
var vidStream = Model.VideoStreams?.Where(x => x.Deleted == false && x.Stream?.HDR == true).FirstOrDefault();
|
||||
if (vidStream == null)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
var videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null || videoInfo.VideoStreams?.Any() != true)
|
||||
return -1;
|
||||
|
||||
var vidStream = Model.VideoStreams?.Where(x => x.Deleted == false && x.Stream?.HDR == true).FirstOrDefault();
|
||||
if (vidStream == null)
|
||||
{
|
||||
args.Logger.ILog("No HDR video stream found");
|
||||
return 2;
|
||||
}
|
||||
|
||||
vidStream.Filter.Add("zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p");
|
||||
|
||||
return 1;
|
||||
args.Logger.ILog("No HDR video stream found");
|
||||
return 2;
|
||||
}
|
||||
|
||||
vidStream.Filter.Add("zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p");
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ public class FfmpegBuilderRemuxToMP4: FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
this.Model.Extension = "mp4";
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
|
||||
|
||||
public class FfmpegBuilderRemuxToMkv: FfmpegBuilderNode
|
||||
public class FfmpegBuilderRemuxToMkv : FfmpegBuilderNode
|
||||
{
|
||||
public override string HelpUrl => "https://github.com/revenz/FileFlows/wiki/FFMPEG-Builder:-Remux-to-MKV";
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
this.Model.Extension = "mkv";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,12 +36,6 @@ public class FfmpegBuilderScaler : FfmpegBuilderNode
|
||||
public override int Outputs => 2;
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
string ffmpeg = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpeg))
|
||||
return -1;
|
||||
|
||||
var videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null || videoInfo.VideoStreams?.Any() != true)
|
||||
return -1;
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
var videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null || videoInfo.VideoStreams?.Any() != true)
|
||||
return -1;
|
||||
|
||||
@@ -17,8 +17,6 @@ public class FfmpegBuilderVideoBitrate : FfmpegBuilderNode
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
var video = Model.VideoStreams?.Where(x => x.Deleted == false)?.FirstOrDefault();
|
||||
if (video?.Stream == null)
|
||||
{
|
||||
|
||||
@@ -23,15 +23,13 @@
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
base.Init(args);
|
||||
|
||||
string codec = args.ReplaceVariables(VideoCodec ?? string.Empty);
|
||||
string parameters = args.ReplaceVariables(VideoCodecParameters ?? codec);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(parameters))
|
||||
return 1; // nothing to do
|
||||
|
||||
parameters = CheckVideoCodec(ffmpegExe, parameters);
|
||||
parameters = CheckVideoCodec(FFMPEG, parameters);
|
||||
|
||||
bool encoding = false;
|
||||
foreach (var item in Model.VideoStreams.Select((x, index) => (stream: x, index)))
|
||||
|
||||
118
VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs
Normal file
118
VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using FileFlows.VideoNodes.FfmpegBuilderNodes.Models;
|
||||
|
||||
namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
|
||||
|
||||
/// <summary>
|
||||
/// Set a video codec encoding for a video stream based on users settings
|
||||
/// </summary>
|
||||
public class FfmpegBuilderVideoEncode:FfmpegBuilderNode
|
||||
{
|
||||
public override int Outputs => 1;
|
||||
|
||||
private const string CODEC_H264 = "h264";
|
||||
private const string CODEC_H265 = "h265";
|
||||
|
||||
public override string HelpUrl => "https://github.com/revenz/FileFlows/wiki/FFMPEG-Builder:-Video-Encode";
|
||||
|
||||
[DefaultValue("h265")]
|
||||
[Select(nameof(CodecOptions), 1)]
|
||||
public string Codec { get; set; }
|
||||
|
||||
private static List<ListOption> _CodecOptions;
|
||||
public static List<ListOption> CodecOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_CodecOptions == null)
|
||||
{
|
||||
_CodecOptions = new List<ListOption>
|
||||
{
|
||||
new () { Label = "h264", Value = CODEC_H264 },
|
||||
new () { Label = "h265", Value = CODEC_H265 }
|
||||
};
|
||||
}
|
||||
return _CodecOptions;
|
||||
}
|
||||
}
|
||||
|
||||
[DefaultValue(true)]
|
||||
[Boolean(2)]
|
||||
public bool HardwareEncoding { get; set; }
|
||||
|
||||
[Slider(3)]
|
||||
[Range(0, 51)]
|
||||
[DefaultValue(23)]
|
||||
public int Quality { get; set; }
|
||||
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
var stream = Model.VideoStreams.Where(x => x.Deleted == false).First();
|
||||
if (Codec == CODEC_H264)
|
||||
H264(stream);
|
||||
else if (Codec == CODEC_H264)
|
||||
H265(stream);
|
||||
bool encoding = false;
|
||||
return encoding ? 1 : 2;
|
||||
}
|
||||
|
||||
private void H264(FfmpegVideoStream stream)
|
||||
{
|
||||
if (HardwareEncoding == false)
|
||||
H26x_CPU(stream);
|
||||
else if (SupportsHardwareNvidia264())
|
||||
H264_Nvidia(stream);
|
||||
else
|
||||
H26x_CPU(stream);
|
||||
}
|
||||
|
||||
private void H265(FfmpegVideoStream stream)
|
||||
{
|
||||
// hevc_qsv -load_plugin hevc_hw -pix_fmt p010le -profile:v main10 -global_quality 21 -g 24 -look_ahead 1 -look_ahead_depth 60
|
||||
if (HardwareEncoding == false)
|
||||
H26x_CPU(stream);
|
||||
else if (SupportsHardwareNvidia265())
|
||||
H265_Nvidia(stream);
|
||||
else
|
||||
H26x_CPU(stream);
|
||||
}
|
||||
|
||||
|
||||
private void H26x_CPU(FfmpegVideoStream stream)
|
||||
{
|
||||
stream.EncodingParameters.Clear();
|
||||
stream.EncodingParameters.AddRange(new []
|
||||
{
|
||||
Codec == CODEC_H265 ? "libx265" : "libx264",
|
||||
"-preset", "slow",
|
||||
"-crf", Quality.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
private void H264_Nvidia(FfmpegVideoStream stream)
|
||||
{
|
||||
stream.EncodingParameters.Clear();
|
||||
stream.EncodingParameters.AddRange(new []
|
||||
{
|
||||
"h264_nvenc",
|
||||
"-rc", "vbr_hq",
|
||||
// 0 == auto, so we set to 1
|
||||
"-cq", Quality <= 0 ? "1" : Quality.ToString(),
|
||||
});
|
||||
}
|
||||
private void H265_Nvidia(FfmpegVideoStream stream)
|
||||
{
|
||||
stream.EncodingParameters.Clear();
|
||||
stream.EncodingParameters.AddRange(new []
|
||||
{
|
||||
"hevc_nvenc",
|
||||
"-rc", "constqp",
|
||||
"-qp", Quality.ToString(),
|
||||
//"-b:v", "0K", // this would do a two-pass... slower
|
||||
"-preset", "p6",
|
||||
// https://www.reddit.com/r/ffmpeg/comments/gg5szi/what_is_spatial_aq_and_temporal_aq_with_nvenc/
|
||||
"-spatial-aq", "1"
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -51,16 +51,12 @@ namespace FileFlows.VideoNodes
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
VideoInfoHelper.ProbeSize = this.ProbeSize;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
var videoInfo = new VideoInfoHelper(ffmpegExe, args.Logger).Read(args.WorkingFile);
|
||||
var videoInfo = new VideoInfoHelper(FFMPEG, args.Logger).Read(args.WorkingFile);
|
||||
if (videoInfo.VideoStreams.Any() == false)
|
||||
{
|
||||
args.Logger.ILog("No video streams detected.");
|
||||
|
||||
@@ -32,16 +32,12 @@ namespace FileFlows.VideoNodes
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
string ffmpeg = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpeg))
|
||||
return -1;
|
||||
|
||||
var videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null || videoInfo.VideoStreams?.Any() != true)
|
||||
return -1;
|
||||
|
||||
|
||||
string crop = Detect(ffmpeg, videoInfo, args, this.CroppingThreshold);
|
||||
string crop = Detect(FFMPEG, videoInfo, args, this.CroppingThreshold);
|
||||
if (crop == string.Empty)
|
||||
return 2;
|
||||
|
||||
|
||||
Binary file not shown.
@@ -438,6 +438,20 @@
|
||||
"DisableOtherVideoStreams-Help": "When checked if there are multiple video streams in the file, this will remove all but the first video stream from the file once executed."
|
||||
}
|
||||
},
|
||||
"FfmpegBuilderVideoEncode": {
|
||||
"Label": "FFMPEG Builder: Video Encode",
|
||||
"Description": "Sets the FFMPEG Builder to encode the video with simple to use presets",
|
||||
"Outputs": {
|
||||
"1": "FFMPEG Builder video streams set to encode"
|
||||
},
|
||||
"Fields": {
|
||||
"Codec": "Codec",
|
||||
"HardwareEncoding": "Hardware Encode",
|
||||
"HardwareEncoding-Help": "When checked, will test to see if hardware encoders are found on the Processing Node, and if found will use hardware encoding, otherwise will fallback to CPU encoding.",
|
||||
"Quality": "Quality",
|
||||
"Quality-Help": "Sets the quality of the video"
|
||||
}
|
||||
},
|
||||
"RemuxToMKV": {
|
||||
"Descritption": "Remuxes a video file into a MKV container. All streams will be copied to the new container",
|
||||
"Outputs": {
|
||||
|
||||
@@ -101,10 +101,6 @@
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
List<string> ffArgs = new List<string>
|
||||
{
|
||||
"-c", "copy",
|
||||
@@ -145,7 +141,7 @@
|
||||
if(extension.StartsWith("."))
|
||||
extension = extension.Substring(1);
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, extension) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, extension) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -26,11 +26,7 @@
|
||||
VideoInfo videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
|
||||
if (videoInfo.AudioStreams?.Any() != true)
|
||||
{
|
||||
args.Logger?.ILog("No audio streams detected");
|
||||
@@ -39,7 +35,7 @@
|
||||
|
||||
if(VolumePercent == 100)
|
||||
{
|
||||
args.Logger?.ILog("Volume percent set to 100, no adjustment necassary");
|
||||
args.Logger?.ILog("Volume percent set to 100, no adjustment necessary");
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -63,7 +59,7 @@
|
||||
if(extension.StartsWith("."))
|
||||
extension = extension.Substring(1);
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, extension) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, extension) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -39,10 +39,6 @@ public class AudioNormalization: EncodingNode
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
if (videoInfo.AudioStreams?.Any() != true)
|
||||
{
|
||||
args.Logger?.ILog("No audio streams detected");
|
||||
@@ -82,7 +78,7 @@ public class AudioNormalization: EncodingNode
|
||||
{
|
||||
if (TwoPass)
|
||||
{
|
||||
string twoPass = DoTwoPass(this, args, ffmpegExe, j);
|
||||
string twoPass = DoTwoPass(this, args, FFMPEG, j);
|
||||
ffArgs.AddRange(new[] { "-map", $"0:a:{j}", "-c:a:" + j, audio.Codec, "-filter:a:" + j, twoPass });
|
||||
}
|
||||
else
|
||||
@@ -113,7 +109,7 @@ public class AudioNormalization: EncodingNode
|
||||
if (extension.StartsWith("."))
|
||||
extension = extension.Substring(1);
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, extension) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, extension) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -30,10 +30,6 @@
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
List<string> ffArgs = new List<string>
|
||||
{
|
||||
"-c", "copy",
|
||||
@@ -74,7 +70,7 @@
|
||||
if(extension.StartsWith("."))
|
||||
extension = extension.Substring(1);
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, extension) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, extension) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -92,10 +92,6 @@
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
List<string> ffArgs = new List<string>
|
||||
{
|
||||
"-c", "copy",
|
||||
@@ -130,7 +126,7 @@
|
||||
if(extension.StartsWith("."))
|
||||
extension = extension.Substring(1);
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, extension) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, extension) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -24,10 +24,6 @@
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
List<string> ffArgs = new List<string>();
|
||||
|
||||
int index = 0;
|
||||
@@ -54,7 +50,7 @@
|
||||
args.Logger?.DLog("Working file: " + args.WorkingFile);
|
||||
args.Logger?.DLog("Extension: " + extension);
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, extension) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, extension) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
VideoInfo videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
@@ -38,12 +35,12 @@
|
||||
return 2;
|
||||
}
|
||||
|
||||
string tempMetaDataFile = GenerateMetaDataFile(this, args, videoInfo, ffmpegExe, this.Percent, this.MinimumLength);
|
||||
string tempMetaDataFile = GenerateMetaDataFile(this, args, videoInfo, FFMPEG, this.Percent, this.MinimumLength);
|
||||
if (string.IsNullOrEmpty(tempMetaDataFile))
|
||||
return 2;
|
||||
|
||||
string[] ffArgs = new[] { "-i", tempMetaDataFile, "-map_metadata", "1", "-codec", "copy", "-max_muxing_queue_size", "1024" };
|
||||
if (Encode(args, ffmpegExe, ffArgs.ToList()))
|
||||
if (Encode(args, FFMPEG, ffArgs.ToList()))
|
||||
{
|
||||
args.Logger?.ILog($"Adding chapters to file");
|
||||
return 1;
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
VideoInfo videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
@@ -27,7 +24,7 @@
|
||||
return 2;
|
||||
|
||||
string[] ffArgs = new[] { "-i", tempMetaDataFile, "-map_metadata", "1", "-codec", "copy", "-max_muxing_queue_size", "1024" };
|
||||
if (Encode(args, ffmpegExe, ffArgs.ToList()))
|
||||
if (Encode(args, FFMPEG, ffArgs.ToList()))
|
||||
{
|
||||
args.Logger?.ILog($"Added chapters to file");
|
||||
return 1;
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
VideoInfo videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
@@ -109,7 +106,7 @@
|
||||
"-c", "copy"
|
||||
};
|
||||
|
||||
bool concatResult = Encode(args, ffmpegExe, ffArgs, dontAddInputFile: true, extension: extension);
|
||||
bool concatResult = Encode(args, FFMPEG, ffArgs, dontAddInputFile: true, extension: extension);
|
||||
|
||||
foreach(string segment in segments.Union(new[] { concatList }))
|
||||
{
|
||||
@@ -140,7 +137,7 @@
|
||||
"-t", duration.ToString(),
|
||||
"-c", "copy"
|
||||
};
|
||||
if (Encode(args, ffmpegExe, ffArgs, outputFile: segment, updateWorkingFile: false))
|
||||
if (Encode(args, FFMPEG, ffArgs, outputFile: segment, updateWorkingFile: false))
|
||||
{
|
||||
segments.Add(segment);
|
||||
segmentsInfo.Add(DebugString(start, end));
|
||||
|
||||
@@ -14,8 +14,6 @@ namespace FileFlows.VideoNodes
|
||||
|
||||
protected TimeSpan TotalTime;
|
||||
|
||||
protected NodeParameters args;
|
||||
|
||||
private FFMpegEncoder Encoder;
|
||||
|
||||
public bool Encode(NodeParameters args, string ffmpegExe, List<string> ffmpegParameters, string extension = "mkv", string outputFile = "", bool updateWorkingFile = true, bool dontAddInputFile = false, bool dontAddOutputFile = false)
|
||||
@@ -29,7 +27,6 @@ namespace FileFlows.VideoNodes
|
||||
if (string.IsNullOrEmpty(extension))
|
||||
extension = "mkv";
|
||||
|
||||
this.args = args;
|
||||
Encoder = new FFMpegEncoder(ffmpegExe, args.Logger);
|
||||
Encoder.AtTime += AtTimeEvent;
|
||||
|
||||
@@ -73,26 +70,14 @@ namespace FileFlows.VideoNodes
|
||||
{
|
||||
if (TotalTime.TotalMilliseconds == 0)
|
||||
{
|
||||
args?.Logger?.DLog("Can't report time progress as total time is 0");
|
||||
Args?.Logger?.DLog("Can't report time progress as total time is 0");
|
||||
return;
|
||||
}
|
||||
float percent = (float)((time.TotalMilliseconds / TotalTime.TotalMilliseconds) * 100);
|
||||
if(args?.PartPercentageUpdate != null)
|
||||
args.PartPercentageUpdate(percent);
|
||||
if(Args?.PartPercentageUpdate != null)
|
||||
Args.PartPercentageUpdate(percent);
|
||||
}
|
||||
|
||||
|
||||
#if (DEBUG)
|
||||
/// <summary>
|
||||
/// Used for unit tests
|
||||
/// </summary>
|
||||
/// <param name="args">the args</param>
|
||||
public void SetArgs(NodeParameters args)
|
||||
{
|
||||
this.args = args;
|
||||
}
|
||||
#endif
|
||||
|
||||
public string CheckVideoCodec(string ffmpeg, string vidparams)
|
||||
{
|
||||
if (string.IsNullOrEmpty(vidparams))
|
||||
@@ -128,7 +113,7 @@ namespace FileFlows.VideoNodes
|
||||
if (canProcess == false)
|
||||
{
|
||||
// change to cpu encoding
|
||||
args.Logger?.ILog("Can't encode using hevc_nvenc, falling back to CPU encoding H265 (libx265)");
|
||||
Args.Logger?.ILog("Can't encode using hevc_nvenc, falling back to CPU encoding H265 (libx265)");
|
||||
return "libx265";
|
||||
}
|
||||
return vidparams;
|
||||
@@ -140,7 +125,7 @@ namespace FileFlows.VideoNodes
|
||||
if (canProcess == false)
|
||||
{
|
||||
// change to cpu encoding
|
||||
args.Logger?.ILog("Can't encode using h264_nvenc, falling back to CPU encoding H264 (libx264)");
|
||||
Args.Logger?.ILog("Can't encode using h264_nvenc, falling back to CPU encoding H264 (libx264)");
|
||||
return "libx264";
|
||||
}
|
||||
return vidparams;
|
||||
@@ -152,7 +137,7 @@ namespace FileFlows.VideoNodes
|
||||
if (canProcess == false)
|
||||
{
|
||||
// change to cpu encoding
|
||||
args.Logger?.ILog("Can't encode using hevc_qsv, falling back to CPU encoding H265 (libx265)");
|
||||
Args.Logger?.ILog("Can't encode using hevc_qsv, falling back to CPU encoding H265 (libx265)");
|
||||
return "libx265";
|
||||
}
|
||||
return vidparams;
|
||||
@@ -164,7 +149,7 @@ namespace FileFlows.VideoNodes
|
||||
if (canProcess == false)
|
||||
{
|
||||
// change to cpu encoding
|
||||
args.Logger?.ILog("Can't encode using h264_qsv, falling back to CPU encoding H264 (libx264)");
|
||||
Args.Logger?.ILog("Can't encode using h264_qsv, falling back to CPU encoding H264 (libx264)");
|
||||
return "libx264";
|
||||
}
|
||||
return vidparams;
|
||||
@@ -177,7 +162,7 @@ namespace FileFlows.VideoNodes
|
||||
//ffmpeg -loglevel error -f lavfi -i color=black:s=1080x1080 -vframes 1 -an -c:v hevc_nven2c -preset hq -f null -"
|
||||
|
||||
string cmdArgs = $"-loglevel error -f lavfi -i color=black:s=1080x1080 -vframes 1 -an -c:v {encodingParams} -f null -\"";
|
||||
var cmd = args.Process.ExecuteShellCommand(new ExecuteArgs
|
||||
var cmd = Args.Process.ExecuteShellCommand(new ExecuteArgs
|
||||
{
|
||||
Command = ffmpeg,
|
||||
Arguments = cmdArgs,
|
||||
@@ -185,7 +170,7 @@ namespace FileFlows.VideoNodes
|
||||
}).Result;
|
||||
if (cmd.ExitCode != 0 || string.IsNullOrWhiteSpace(cmd.Output) == false)
|
||||
{
|
||||
args.Logger?.WLog($"Cant process '{encodingParams}': {cmd.Output ?? ""}");
|
||||
Args.Logger?.WLog($"Cant process '{encodingParams}': {cmd.Output ?? ""}");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -197,7 +182,7 @@ namespace FileFlows.VideoNodes
|
||||
{
|
||||
if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
|
||||
{
|
||||
var cmd = args.Process.ExecuteShellCommand(new ExecuteArgs
|
||||
var cmd = Args.Process.ExecuteShellCommand(new ExecuteArgs
|
||||
{
|
||||
Command = "wmic",
|
||||
Arguments = "path win32_VideoController get name"
|
||||
@@ -222,7 +207,7 @@ namespace FileFlows.VideoNodes
|
||||
}
|
||||
|
||||
// check cuda in ffmpeg itself
|
||||
var result = args.Process.ExecuteShellCommand(new ExecuteArgs
|
||||
var result = Args.Process.ExecuteShellCommand(new ExecuteArgs
|
||||
{
|
||||
Command = ffmpeg,
|
||||
Arguments = "-hide_banner -init_hw_device list"
|
||||
@@ -231,7 +216,7 @@ namespace FileFlows.VideoNodes
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
args.Logger?.ELog("Failed to detect NVIDIA card: " + ex.Message + Environment.NewLine + ex.StackTrace);
|
||||
Args.Logger?.ELog("Failed to detect NVIDIA card: " + ex.Message + Environment.NewLine + ex.StackTrace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,12 +41,8 @@ namespace FileFlows.VideoNodes
|
||||
args.Logger.ELog("Command Line not set");
|
||||
return -1;
|
||||
}
|
||||
this.args = args;
|
||||
try
|
||||
{
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
if (string.IsNullOrEmpty(Extension))
|
||||
Extension = "mkv";
|
||||
@@ -54,7 +50,7 @@ namespace FileFlows.VideoNodes
|
||||
string outputFile = Path.Combine(args.TempPath, Guid.NewGuid().ToString() + "." + Extension);
|
||||
var ffArgs = GetFFMPEGArgs(args, outputFile);
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, updateWorkingFile: false, dontAddInputFile: true, dontAddOutputFile: true) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, updateWorkingFile: false, dontAddInputFile: true, dontAddOutputFile: true) == false)
|
||||
return -1;
|
||||
|
||||
if (File.Exists(outputFile))
|
||||
|
||||
@@ -42,14 +42,10 @@ namespace FileFlows.VideoNodes
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
var videoInfo = new VideoInfoHelper(ffmpegExe, args.Logger).Read(args.WorkingFile);
|
||||
var videoInfo = new VideoInfoHelper(FFMPEG, args.Logger).Read(args.WorkingFile);
|
||||
if (videoInfo.VideoStreams.Any() == false)
|
||||
{
|
||||
args.Logger.ILog("No video streams detected.");
|
||||
|
||||
@@ -13,17 +13,12 @@
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
|
||||
if (Force == false && args.WorkingFile?.ToLower()?.EndsWith(".mkv") == true)
|
||||
return 2;
|
||||
|
||||
try
|
||||
{
|
||||
if (Encode(args, ffmpegExe, new List<string> { "-c", "copy", "-map", "0" }, "mkv") == false)
|
||||
if (Encode(args, FFMPEG, new List<string> { "-c", "copy", "-map", "0" }, "mkv") == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
@@ -45,16 +40,12 @@
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
if (Force == false && args.WorkingFile?.ToLower()?.EndsWith(".mp4") == true)
|
||||
return 2;
|
||||
|
||||
try
|
||||
{
|
||||
if (Encode(args, ffmpegExe, new List<string> { "-c", "copy", "-map", "0" }, "mp4") == false)
|
||||
if (Encode(args, FFMPEG, new List<string> { "-c", "copy", "-map", "0" }, "mp4") == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -38,11 +38,7 @@
|
||||
VideoInfo videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
|
||||
// ffmpeg -i input.mkv -map "0:m:language:eng" -map "-0:v" -map "-0:a" output.srt
|
||||
var subTrack = videoInfo.SubtitleStreams?.Where(x => string.IsNullOrEmpty(Language) || x.Language?.ToLower() == Language.ToLower()).FirstOrDefault();
|
||||
if (subTrack == null)
|
||||
@@ -74,7 +70,7 @@
|
||||
//bool textSubtitles = Regex.IsMatch(OutputFile, @"\.(sup)$") == false;
|
||||
|
||||
|
||||
var extracted = ExtractSubtitle(args, ffmpegExe, "0:s:" + subTrack.TypeIndex, OutputFile);
|
||||
var extracted = ExtractSubtitle(args, FFMPEG, "0:s:" + subTrack.TypeIndex, OutputFile);
|
||||
if(extracted)
|
||||
{
|
||||
args.UpdateVariables(new Dictionary<string, object>
|
||||
|
||||
@@ -32,10 +32,6 @@
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
List<string> ffArgs = new List<string>()
|
||||
{
|
||||
"-map", "0:v",
|
||||
@@ -74,7 +70,7 @@
|
||||
if(extension.StartsWith("."))
|
||||
extension = extension.Substring(1);
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, extension) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, extension) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -57,10 +57,6 @@
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
List<string> ffArgs = new List<string>()
|
||||
{
|
||||
"-map", "0:v",
|
||||
@@ -106,7 +102,7 @@
|
||||
if(extension.StartsWith("."))
|
||||
extension = extension.Substring(1);
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, extension) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, extension) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -56,7 +56,6 @@ namespace FileFlows.VideoNodes
|
||||
VideoCodec = VideoCodec.ToLower();
|
||||
AudioCodec = AudioCodec.ToLower();
|
||||
|
||||
this.args = args;
|
||||
try
|
||||
{
|
||||
VideoInfo videoInfo = GetVideoInfo(args);
|
||||
@@ -65,10 +64,6 @@ namespace FileFlows.VideoNodes
|
||||
|
||||
Language = Language?.ToLower() ?? "";
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
// ffmpeg is one based for stream index, so video should be 1, audio should be 2
|
||||
|
||||
string encodeVideoParameters = string.Empty, encodeAudioParameters = string.Empty;
|
||||
@@ -88,7 +83,7 @@ namespace FileFlows.VideoNodes
|
||||
|
||||
if (videoIsRightCodec == null || crop != string.Empty)
|
||||
{
|
||||
string codecParameters = CheckVideoCodec(ffmpegExe, VideoCodecParameters);
|
||||
string codecParameters = CheckVideoCodec(FFMPEG, VideoCodecParameters);
|
||||
encodeVideoParameters = $"-map 0:v:0 -c:v {codecParameters} {crop}";
|
||||
}
|
||||
Extension = args.ReplaceVariables(Extension)?.EmptyAsNull() ?? "mkv";
|
||||
@@ -162,7 +157,7 @@ namespace FileFlows.VideoNodes
|
||||
}
|
||||
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, Extension) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, Extension) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -4,64 +4,74 @@ namespace FileFlows.VideoNodes
|
||||
|
||||
public abstract class VideoNode : Node
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Node Parameters
|
||||
/// </summary>
|
||||
protected NodeParameters Args { get; private set; }
|
||||
|
||||
|
||||
|
||||
#if (DEBUG)
|
||||
/// <summary>
|
||||
/// Used for unit tests
|
||||
/// </summary>
|
||||
/// <param name="args">the args</param>
|
||||
public void SetArgs(NodeParameters args)
|
||||
{
|
||||
this.Args = args;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets the FFMPEG executable location
|
||||
/// </summary>
|
||||
protected string FFMPEG { get; private set; }
|
||||
public override string Icon => "fas fa-video";
|
||||
|
||||
protected string GetFFMpegExe(NodeParameters args)
|
||||
/// <summary>
|
||||
/// Executed before execute, sets ffmpegexe etc
|
||||
/// </summary>
|
||||
/// <param name="args">the node parametes</param>
|
||||
/// <returns>true if successfully</returns>
|
||||
public override bool PreExecute(NodeParameters args)
|
||||
{
|
||||
string ffmpeg = args.GetToolPath("FFMpeg");
|
||||
this.Args = args;
|
||||
this.FFMPEG = GetFFMpegExe();
|
||||
return string.IsNullOrEmpty(this.FFMPEG) == false;
|
||||
}
|
||||
|
||||
private string GetFFMpegExe()
|
||||
{
|
||||
string ffmpeg = Args.GetToolPath("FFMpeg");
|
||||
if (string.IsNullOrEmpty(ffmpeg))
|
||||
{
|
||||
args.Logger.ELog("FFMpeg tool not found.");
|
||||
Args.Logger.ELog("FFMpeg tool not found.");
|
||||
return "";
|
||||
}
|
||||
var fileInfo = new FileInfo(ffmpeg);
|
||||
if (fileInfo.Exists == false)
|
||||
{
|
||||
args.Logger.ELog("FFMpeg tool configured by ffmpeg.exe file does not exist.");
|
||||
Args.Logger.ELog("FFMpeg tool configured by ffmpeg.exe file does not exist.");
|
||||
return "";
|
||||
}
|
||||
return fileInfo.FullName;
|
||||
}
|
||||
protected string GetFFMpegPath(NodeParameters args)
|
||||
{
|
||||
string ffmpeg = args.GetToolPath("FFMpeg");
|
||||
if (string.IsNullOrEmpty(ffmpeg))
|
||||
{
|
||||
args.Logger.ELog("FFMpeg tool not found.");
|
||||
return "";
|
||||
}
|
||||
var fileInfo = new FileInfo(ffmpeg);
|
||||
if (fileInfo.Exists == false)
|
||||
{
|
||||
args.Logger.ELog("FFMpeg tool configured by ffmpeg.exe file does not exist.");
|
||||
return "";
|
||||
}
|
||||
return fileInfo.DirectoryName;
|
||||
}
|
||||
protected string GetFFPlayExe(NodeParameters args)
|
||||
{
|
||||
string ffmpeg = args.GetToolPath("FFMpeg");
|
||||
if (string.IsNullOrEmpty(ffmpeg))
|
||||
{
|
||||
args.Logger.ELog("FFMpeg tool not found.");
|
||||
return "";
|
||||
}
|
||||
|
||||
var fileInfo = new FileInfo(ffmpeg);
|
||||
if (fileInfo.Exists == false)
|
||||
{
|
||||
args.Logger.ELog("FFMpeg tool configured by ffmpeg file does not exist.");
|
||||
return "";
|
||||
}
|
||||
|
||||
var ffplay = Path.Combine(fileInfo.DirectoryName, "ffplay" + fileInfo.Extension);
|
||||
if (File.Exists(ffplay) == false)
|
||||
{
|
||||
args.Logger.ELog("FFMpeg tool configured by ffplay file does not exist.");
|
||||
return "";
|
||||
}
|
||||
return ffplay;
|
||||
}
|
||||
// protected string GetFFMpegPath(NodeParameters args)
|
||||
// {
|
||||
// string ffmpeg = args.GetToolPath("FFMpeg");
|
||||
// if (string.IsNullOrEmpty(ffmpeg))
|
||||
// {
|
||||
// args.Logger.ELog("FFMpeg tool not found.");
|
||||
// return "";
|
||||
// }
|
||||
// var fileInfo = new FileInfo(ffmpeg);
|
||||
// if (fileInfo.Exists == false)
|
||||
// {
|
||||
// args.Logger.ELog("FFMpeg tool configured by ffmpeg.exe file does not exist.");
|
||||
// return "";
|
||||
// }
|
||||
// return fileInfo.DirectoryName;
|
||||
// }
|
||||
|
||||
private const string VIDEO_INFO = "VideoInfo";
|
||||
protected void SetVideoInfo(NodeParameters args, VideoInfo videoInfo, Dictionary<string, object> variables)
|
||||
@@ -119,5 +129,76 @@ namespace FileFlows.VideoNodes
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private bool? HW_NVIDIA_265;
|
||||
/// <summary>
|
||||
/// Can process NVIDIA h265 hardware encoding
|
||||
/// </summary>
|
||||
/// <returns>true if can support NVIDIA h265 hardware encoding</returns>
|
||||
protected bool SupportsHardwareNvidia265()
|
||||
{
|
||||
if (HW_NVIDIA_265 == null)
|
||||
HW_NVIDIA_265 = CanProcessEncoder("hevc_nvenc");
|
||||
return HW_NVIDIA_265.Value;
|
||||
}
|
||||
|
||||
private bool? HW_NVIDIA_264;
|
||||
/// <summary>
|
||||
/// Can process NVIDIA h264 hardware encoding
|
||||
/// </summary>
|
||||
/// <returns>true if can support NVIDIA h264 hardware encoding</returns>
|
||||
protected bool SupportsHardwareNvidia264()
|
||||
{
|
||||
if (HW_NVIDIA_264 == null)
|
||||
HW_NVIDIA_264 = CanProcessEncoder("h264_nvenc");
|
||||
return HW_NVIDIA_264.Value;
|
||||
}
|
||||
|
||||
|
||||
private bool? HW_QSV_265;
|
||||
/// <summary>
|
||||
/// Can process QSV h265 hardware encoding
|
||||
/// </summary>
|
||||
/// <returns>true if can support QSV h265 hardware encoding</returns>
|
||||
protected bool SupportsHardwareQsv265()
|
||||
{
|
||||
if (HW_QSV_265 == null)
|
||||
HW_QSV_265 = CanProcessEncoder("hevc_qsv");
|
||||
return HW_QSV_265.Value;
|
||||
}
|
||||
private bool? HW_QSV_264;
|
||||
/// <summary>
|
||||
/// Can process QSV h264 hardware encoding
|
||||
/// </summary>
|
||||
/// <returns>true if can support QSV h264 hardware encoding</returns>
|
||||
protected bool SupportsHardwareQsv264()
|
||||
{
|
||||
if (HW_QSV_264 == null)
|
||||
HW_QSV_264 = CanProcessEncoder("h264_qsv");
|
||||
return HW_QSV_264.Value;
|
||||
}
|
||||
|
||||
public bool CanProcessEncoder(string encodingParams)
|
||||
{
|
||||
//ffmpeg -loglevel error -f lavfi -i color=black:s=1080x1080 -vframes 1 -an -c:v hevc_nven2c -preset hq -f null -"
|
||||
|
||||
string cmdArgs = $"-loglevel error -f lavfi -i color=black:s=1080x1080 -vframes 1 -an -c:v {encodingParams} -f null -\"";
|
||||
var cmd = Args.Process.ExecuteShellCommand(new ExecuteArgs
|
||||
{
|
||||
Command = FFMPEG,
|
||||
Arguments = cmdArgs,
|
||||
Silent = true
|
||||
}).Result;
|
||||
if (cmd.ExitCode != 0 || string.IsNullOrWhiteSpace(cmd.Output) == false)
|
||||
{
|
||||
Args.Logger?.WLog($"Cant process '{encodingParams}': {cmd.Output ?? ""}");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,6 @@ namespace FileFlows.VideoNodes
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
this.args = args;
|
||||
Extension = args.ReplaceVariables(Extension)?.EmptyAsNull() ?? "mkv";
|
||||
|
||||
try
|
||||
@@ -111,12 +110,7 @@ namespace FileFlows.VideoNodes
|
||||
else if (resolution == ResolutionHelper.Resolution.r480p && Resolution.StartsWith("640"))
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
string ffmpegExe = GetFFMpegExe(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
return -1;
|
||||
|
||||
|
||||
List<string> ffArgs = new List<string>()
|
||||
{
|
||||
"-vf", $"scale={Resolution}:flags=lanczos",
|
||||
@@ -124,7 +118,7 @@ namespace FileFlows.VideoNodes
|
||||
};
|
||||
|
||||
string codec = VideoCodec == "Custom" && string.IsNullOrWhiteSpace(VideoCodecParameters) == false ?
|
||||
VideoCodecParameters : CheckVideoCodec(ffmpegExe, VideoCodec);
|
||||
VideoCodecParameters : CheckVideoCodec(FFMPEG, VideoCodec);
|
||||
|
||||
foreach (string c in codec.Split(" "))
|
||||
{
|
||||
@@ -133,7 +127,7 @@ namespace FileFlows.VideoNodes
|
||||
ffArgs.Add(c.Trim());
|
||||
}
|
||||
|
||||
if (Encode(args, ffmpegExe, ffArgs, Extension) == false)
|
||||
if (Encode(args, FFMPEG, ffArgs, Extension) == false)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user