diff --git a/Apprise/Apprise.csproj b/Apprise/Apprise.csproj index a62295e1..850537e7 100644 Binary files a/Apprise/Apprise.csproj and b/Apprise/Apprise.csproj differ diff --git a/BasicNodes/BasicNodes.csproj b/BasicNodes/BasicNodes.csproj index f5a66865..18257423 100644 Binary files a/BasicNodes/BasicNodes.csproj and b/BasicNodes/BasicNodes.csproj differ diff --git a/ChecksumNodes/ChecksumNodes.csproj b/ChecksumNodes/ChecksumNodes.csproj index b69b792b..761883c0 100644 Binary files a/ChecksumNodes/ChecksumNodes.csproj and b/ChecksumNodes/ChecksumNodes.csproj differ diff --git a/CollectionNodes/CollectionNodes.csproj b/CollectionNodes/CollectionNodes.csproj index 14567a58..2785f805 100644 Binary files a/CollectionNodes/CollectionNodes.csproj and b/CollectionNodes/CollectionNodes.csproj differ diff --git a/DiscordNodes/DiscordNodes.csproj b/DiscordNodes/DiscordNodes.csproj index 03705af6..8866143c 100644 Binary files a/DiscordNodes/DiscordNodes.csproj and b/DiscordNodes/DiscordNodes.csproj differ diff --git a/EmailNodes/EmailNodes.csproj b/EmailNodes/EmailNodes.csproj index 363aced3..98d16328 100644 Binary files a/EmailNodes/EmailNodes.csproj and b/EmailNodes/EmailNodes.csproj differ diff --git a/Emby/Emby.csproj b/Emby/Emby.csproj index 6641c68d..2ba1e556 100644 Binary files a/Emby/Emby.csproj and b/Emby/Emby.csproj differ diff --git a/FileFlows.Plugin.dll b/FileFlows.Plugin.dll index 92fecd0c..de5e5245 100644 Binary files a/FileFlows.Plugin.dll and b/FileFlows.Plugin.dll differ diff --git a/FileFlows.Plugin.pdb b/FileFlows.Plugin.pdb index c4af8307..26165175 100644 Binary files a/FileFlows.Plugin.pdb and b/FileFlows.Plugin.pdb differ diff --git a/Gotify/Gotify.csproj b/Gotify/Gotify.csproj index 2c5aaf02..6ddb5ec0 100644 Binary files a/Gotify/Gotify.csproj and b/Gotify/Gotify.csproj differ diff --git a/ImageNodes/ImageNodes.csproj b/ImageNodes/ImageNodes.csproj index 68716761..0b53f79a 100644 Binary files a/ImageNodes/ImageNodes.csproj and b/ImageNodes/ImageNodes.csproj differ diff --git a/MetaNodes/MetaNodes.csproj b/MetaNodes/MetaNodes.csproj index 125d5b5e..a84a28b2 100644 Binary files a/MetaNodes/MetaNodes.csproj and b/MetaNodes/MetaNodes.csproj differ diff --git a/MusicNodes/MusicNodes.csproj b/MusicNodes/MusicNodes.csproj index d9becabf..592a2e10 100644 Binary files a/MusicNodes/MusicNodes.csproj and b/MusicNodes/MusicNodes.csproj differ diff --git a/Plex/Plex.csproj b/Plex/Plex.csproj index f04e9d6d..76d3489a 100644 Binary files a/Plex/Plex.csproj and b/Plex/Plex.csproj differ diff --git a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs index 909d3fee..d1942877 100644 --- a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs +++ b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAddTrack.cs @@ -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)); diff --git a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAdjustVolume.cs b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAdjustVolume.cs index 187e2890..0d445a7a 100644 --- a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAdjustVolume.cs +++ b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioAdjustVolume.cs @@ -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"); diff --git a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioNormalization.cs b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioNormalization.cs index 385a81f6..0f259804 100644 --- a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioNormalization.cs +++ b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioNormalization.cs @@ -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); } diff --git a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioSetLanguage.cs b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioSetLanguage.cs index 61b89c52..ae7e5bd1 100644 --- a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioSetLanguage.cs +++ b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioSetLanguage.cs @@ -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) { diff --git a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackRemover.cs b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackRemover.cs index f1d73a63..1abd5449 100644 --- a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackRemover.cs +++ b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackRemover.cs @@ -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; diff --git a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackReorder.cs b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackReorder.cs index 74643f58..338be187 100644 --- a/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackReorder.cs +++ b/VideoNodes/FfmpegBuilderNodes/Audio/FfmpegBuilderAudioTrackReorder.cs @@ -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); diff --git a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderAddInputFile.cs b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderAddInputFile.cs index 64a0cb3e..9559f477 100644 --- a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderAddInputFile.cs +++ b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderAddInputFile.cs @@ -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) { diff --git a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs index 343ea890..0f80d85b 100644 --- a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs +++ b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs @@ -18,7 +18,6 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes public override int Execute(NodeParameters args) { - this.Init(args); var model = this.Model; List ffArgs = new List(); 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[] { }; } } diff --git a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs index 6f844afb..e534f40d 100644 --- a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs +++ b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs @@ -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); } diff --git a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs index 93326014..6a31ecbf 100644 --- a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs +++ b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs @@ -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; } } diff --git a/VideoNodes/FfmpegBuilderNodes/Metadata/FfmpegBuilderAutoChapters.cs b/VideoNodes/FfmpegBuilderNodes/Metadata/FfmpegBuilderAutoChapters.cs index a2354274..00a39e26 100644 --- a/VideoNodes/FfmpegBuilderNodes/Metadata/FfmpegBuilderAutoChapters.cs +++ b/VideoNodes/FfmpegBuilderNodes/Metadata/FfmpegBuilderAutoChapters.cs @@ -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; diff --git a/VideoNodes/FfmpegBuilderNodes/Metadata/FfmpegBuilderComskipChapters.cs b/VideoNodes/FfmpegBuilderNodes/Metadata/FfmpegBuilderComskipChapters.cs index 791eb908..30c0a68e 100644 --- a/VideoNodes/FfmpegBuilderNodes/Metadata/FfmpegBuilderComskipChapters.cs +++ b/VideoNodes/FfmpegBuilderNodes/Metadata/FfmpegBuilderComskipChapters.cs @@ -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; diff --git a/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleFormatRemover.cs b/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleFormatRemover.cs index 3e9837a2..4f020c72 100644 --- a/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleFormatRemover.cs +++ b/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleFormatRemover.cs @@ -43,8 +43,6 @@ public class FfmpegBuilderSubtitleFormatRemover : FfmpegBuilderNode public override int Execute(NodeParameters args) { - this.Init(args); - if (RemoveAll) { if (Model.SubtitleStreams.Any() == false) diff --git a/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleTrackMerge.cs b/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleTrackMerge.cs index 065eaf1a..29da64e3 100644 --- a/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleTrackMerge.cs +++ b/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleTrackMerge.cs @@ -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) { diff --git a/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleTrackRemover.cs b/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleTrackRemover.cs index d509e582..7ad67ec5 100644 --- a/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleTrackRemover.cs +++ b/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderSubtitleTrackRemover.cs @@ -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) diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderCropBlackBars.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderCropBlackBars.cs index 4837756b..f63ab692 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderCropBlackBars.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderCropBlackBars.cs @@ -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; } -} +} \ No newline at end of file diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderHdrToSdr.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderHdrToSdr.cs index 4220e66a..951128ee 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderHdrToSdr.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderHdrToSdr.cs @@ -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; } -} +} \ No newline at end of file diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderRemuxToMP4.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderRemuxToMP4.cs index c6891399..7ba285d3 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderRemuxToMP4.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderRemuxToMP4.cs @@ -6,7 +6,6 @@ public class FfmpegBuilderRemuxToMP4: FfmpegBuilderNode public override int Execute(NodeParameters args) { - base.Init(args); this.Model.Extension = "mp4"; return 1; } diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderRemuxToMkv.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderRemuxToMkv.cs index c1995a14..6228feca 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderRemuxToMkv.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderRemuxToMkv.cs @@ -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; } -} +} \ No newline at end of file diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderScaler.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderScaler.cs index 74d625b7..9bdefc03 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderScaler.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderScaler.cs @@ -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; diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideo10Bit.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideo10Bit.cs index 7a58a763..9f18c968 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideo10Bit.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideo10Bit.cs @@ -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; diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoBitrate.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoBitrate.cs index ed50f100..6480536f 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoBitrate.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoBitrate.cs @@ -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) { diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoCodec.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoCodec.cs index bb7ee08e..e7d39cda 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoCodec.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoCodec.cs @@ -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))) diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs new file mode 100644 index 00000000..b7418f1a --- /dev/null +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs @@ -0,0 +1,118 @@ +using FileFlows.VideoNodes.FfmpegBuilderNodes.Models; + +namespace FileFlows.VideoNodes.FfmpegBuilderNodes; + +/// +/// Set a video codec encoding for a video stream based on users settings +/// +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 _CodecOptions; + public static List CodecOptions + { + get + { + if (_CodecOptions == null) + { + _CodecOptions = new List + { + 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" + }); + } + +} diff --git a/VideoNodes/InputNodes/VideoFile.cs b/VideoNodes/InputNodes/VideoFile.cs index b203a3e9..325f9971 100644 --- a/VideoNodes/InputNodes/VideoFile.cs +++ b/VideoNodes/InputNodes/VideoFile.cs @@ -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."); diff --git a/VideoNodes/LogicalNodes/DetectBlackBars.cs b/VideoNodes/LogicalNodes/DetectBlackBars.cs index acb48e30..e6f99653 100644 --- a/VideoNodes/LogicalNodes/DetectBlackBars.cs +++ b/VideoNodes/LogicalNodes/DetectBlackBars.cs @@ -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; diff --git a/VideoNodes/VideoNodes.csproj b/VideoNodes/VideoNodes.csproj index 4d5d4ac9..1b68acfd 100644 Binary files a/VideoNodes/VideoNodes.csproj and b/VideoNodes/VideoNodes.csproj differ diff --git a/VideoNodes/VideoNodes.en.json b/VideoNodes/VideoNodes.en.json index 207e1499..289a0168 100644 --- a/VideoNodes/VideoNodes.en.json +++ b/VideoNodes/VideoNodes.en.json @@ -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": { diff --git a/VideoNodes/VideoNodes/AudioAddTrack.cs b/VideoNodes/VideoNodes/AudioAddTrack.cs index d20b3a5d..d20d16d1 100644 --- a/VideoNodes/VideoNodes/AudioAddTrack.cs +++ b/VideoNodes/VideoNodes/AudioAddTrack.cs @@ -101,10 +101,6 @@ if (videoInfo == null) return -1; - string ffmpegExe = GetFFMpegExe(args); - if (string.IsNullOrEmpty(ffmpegExe)) - return -1; - List ffArgs = new List { "-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; diff --git a/VideoNodes/VideoNodes/AudioAdjustVolume.cs b/VideoNodes/VideoNodes/AudioAdjustVolume.cs index 7200b5a0..4567ec32 100644 --- a/VideoNodes/VideoNodes/AudioAdjustVolume.cs +++ b/VideoNodes/VideoNodes/AudioAdjustVolume.cs @@ -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; diff --git a/VideoNodes/VideoNodes/AudioNormalization.cs b/VideoNodes/VideoNodes/AudioNormalization.cs index 62c6ae3d..a99bae72 100644 --- a/VideoNodes/VideoNodes/AudioNormalization.cs +++ b/VideoNodes/VideoNodes/AudioNormalization.cs @@ -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; diff --git a/VideoNodes/VideoNodes/AudioTrackRemover.cs b/VideoNodes/VideoNodes/AudioTrackRemover.cs index d6156ed6..9a634e64 100644 --- a/VideoNodes/VideoNodes/AudioTrackRemover.cs +++ b/VideoNodes/VideoNodes/AudioTrackRemover.cs @@ -30,10 +30,6 @@ if (videoInfo == null) return -1; - string ffmpegExe = GetFFMpegExe(args); - if (string.IsNullOrEmpty(ffmpegExe)) - return -1; - List ffArgs = new List { "-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; diff --git a/VideoNodes/VideoNodes/AudioTrackReorder.cs b/VideoNodes/VideoNodes/AudioTrackReorder.cs index 7c27ca0f..fc1498ee 100644 --- a/VideoNodes/VideoNodes/AudioTrackReorder.cs +++ b/VideoNodes/VideoNodes/AudioTrackReorder.cs @@ -92,10 +92,6 @@ if (videoInfo == null) return -1; - string ffmpegExe = GetFFMpegExe(args); - if (string.IsNullOrEmpty(ffmpegExe)) - return -1; - List ffArgs = new List { "-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; diff --git a/VideoNodes/VideoNodes/AudioTrackSetLanguage.cs b/VideoNodes/VideoNodes/AudioTrackSetLanguage.cs index 71f20f80..039df493 100644 --- a/VideoNodes/VideoNodes/AudioTrackSetLanguage.cs +++ b/VideoNodes/VideoNodes/AudioTrackSetLanguage.cs @@ -24,10 +24,6 @@ if (videoInfo == null) return -1; - string ffmpegExe = GetFFMpegExe(args); - if (string.IsNullOrEmpty(ffmpegExe)) - return -1; - List ffArgs = new List(); 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; diff --git a/VideoNodes/VideoNodes/AutoChapters.cs b/VideoNodes/VideoNodes/AutoChapters.cs index 2107feee..8bfcc5f3 100644 --- a/VideoNodes/VideoNodes/AutoChapters.cs +++ b/VideoNodes/VideoNodes/AutoChapters.cs @@ -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; diff --git a/VideoNodes/VideoNodes/ComskipChapters.cs b/VideoNodes/VideoNodes/ComskipChapters.cs index d3a21431..98e64ad1 100644 --- a/VideoNodes/VideoNodes/ComskipChapters.cs +++ b/VideoNodes/VideoNodes/ComskipChapters.cs @@ -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; diff --git a/VideoNodes/VideoNodes/ComskipRemoveAds.cs b/VideoNodes/VideoNodes/ComskipRemoveAds.cs index 4e49141c..833f4300 100644 --- a/VideoNodes/VideoNodes/ComskipRemoveAds.cs +++ b/VideoNodes/VideoNodes/ComskipRemoveAds.cs @@ -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)); diff --git a/VideoNodes/VideoNodes/EncodingNode.cs b/VideoNodes/VideoNodes/EncodingNode.cs index 3230aa58..1e6701e3 100644 --- a/VideoNodes/VideoNodes/EncodingNode.cs +++ b/VideoNodes/VideoNodes/EncodingNode.cs @@ -14,8 +14,6 @@ namespace FileFlows.VideoNodes protected TimeSpan TotalTime; - protected NodeParameters args; - private FFMpegEncoder Encoder; public bool Encode(NodeParameters args, string ffmpegExe, List 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) - /// - /// Used for unit tests - /// - /// the args - 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; } } diff --git a/VideoNodes/VideoNodes/FFMPEG.cs b/VideoNodes/VideoNodes/FFMPEG.cs index 972de0ff..a31f6101 100644 --- a/VideoNodes/VideoNodes/FFMPEG.cs +++ b/VideoNodes/VideoNodes/FFMPEG.cs @@ -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)) diff --git a/VideoNodes/VideoNodes/ReadVideoInfo.cs b/VideoNodes/VideoNodes/ReadVideoInfo.cs index 25063925..3e45edf4 100644 --- a/VideoNodes/VideoNodes/ReadVideoInfo.cs +++ b/VideoNodes/VideoNodes/ReadVideoInfo.cs @@ -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."); diff --git a/VideoNodes/VideoNodes/Remux.cs b/VideoNodes/VideoNodes/Remux.cs index 69dfb7d9..32d368cb 100644 --- a/VideoNodes/VideoNodes/Remux.cs +++ b/VideoNodes/VideoNodes/Remux.cs @@ -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 { "-c", "copy", "-map", "0" }, "mkv") == false) + if (Encode(args, FFMPEG, new List { "-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 { "-c", "copy", "-map", "0" }, "mp4") == false) + if (Encode(args, FFMPEG, new List { "-c", "copy", "-map", "0" }, "mp4") == false) return -1; return 1; diff --git a/VideoNodes/VideoNodes/SubtitleExtractor.cs b/VideoNodes/VideoNodes/SubtitleExtractor.cs index 43d594d1..7ebde434 100644 --- a/VideoNodes/VideoNodes/SubtitleExtractor.cs +++ b/VideoNodes/VideoNodes/SubtitleExtractor.cs @@ -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 diff --git a/VideoNodes/VideoNodes/SubtitleLanguageRemover.cs b/VideoNodes/VideoNodes/SubtitleLanguageRemover.cs index bd7c210c..14385b71 100644 --- a/VideoNodes/VideoNodes/SubtitleLanguageRemover.cs +++ b/VideoNodes/VideoNodes/SubtitleLanguageRemover.cs @@ -32,10 +32,6 @@ if (videoInfo == null) return -1; - string ffmpegExe = GetFFMpegExe(args); - if (string.IsNullOrEmpty(ffmpegExe)) - return -1; - List ffArgs = new List() { "-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; diff --git a/VideoNodes/VideoNodes/SubtitleRemover.cs b/VideoNodes/VideoNodes/SubtitleRemover.cs index 4b5fadc0..331ed7a8 100644 --- a/VideoNodes/VideoNodes/SubtitleRemover.cs +++ b/VideoNodes/VideoNodes/SubtitleRemover.cs @@ -57,10 +57,6 @@ if (videoInfo == null) return -1; - string ffmpegExe = GetFFMpegExe(args); - if (string.IsNullOrEmpty(ffmpegExe)) - return -1; - List ffArgs = new List() { "-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; diff --git a/VideoNodes/VideoNodes/VideoEncode.cs b/VideoNodes/VideoNodes/VideoEncode.cs index 98da93cf..37f89fc0 100644 --- a/VideoNodes/VideoNodes/VideoEncode.cs +++ b/VideoNodes/VideoNodes/VideoEncode.cs @@ -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; diff --git a/VideoNodes/VideoNodes/VideoNode.cs b/VideoNodes/VideoNodes/VideoNode.cs index 750af1f1..a33bfdcf 100644 --- a/VideoNodes/VideoNodes/VideoNode.cs +++ b/VideoNodes/VideoNodes/VideoNode.cs @@ -4,64 +4,74 @@ namespace FileFlows.VideoNodes public abstract class VideoNode : Node { + /// + /// Gets the Node Parameters + /// + protected NodeParameters Args { get; private set; } + + + +#if (DEBUG) + /// + /// Used for unit tests + /// + /// the args + public void SetArgs(NodeParameters args) + { + this.Args = args; + } +#endif + + /// + /// Gets the FFMPEG executable location + /// + protected string FFMPEG { get; private set; } public override string Icon => "fas fa-video"; - protected string GetFFMpegExe(NodeParameters args) + /// + /// Executed before execute, sets ffmpegexe etc + /// + /// the node parametes + /// true if successfully + 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 variables) @@ -119,5 +129,76 @@ namespace FileFlows.VideoNodes } return result; } + + + + + + private bool? HW_NVIDIA_265; + /// + /// Can process NVIDIA h265 hardware encoding + /// + /// true if can support NVIDIA h265 hardware encoding + protected bool SupportsHardwareNvidia265() + { + if (HW_NVIDIA_265 == null) + HW_NVIDIA_265 = CanProcessEncoder("hevc_nvenc"); + return HW_NVIDIA_265.Value; + } + + private bool? HW_NVIDIA_264; + /// + /// Can process NVIDIA h264 hardware encoding + /// + /// true if can support NVIDIA h264 hardware encoding + protected bool SupportsHardwareNvidia264() + { + if (HW_NVIDIA_264 == null) + HW_NVIDIA_264 = CanProcessEncoder("h264_nvenc"); + return HW_NVIDIA_264.Value; + } + + + private bool? HW_QSV_265; + /// + /// Can process QSV h265 hardware encoding + /// + /// true if can support QSV h265 hardware encoding + protected bool SupportsHardwareQsv265() + { + if (HW_QSV_265 == null) + HW_QSV_265 = CanProcessEncoder("hevc_qsv"); + return HW_QSV_265.Value; + } + private bool? HW_QSV_264; + /// + /// Can process QSV h264 hardware encoding + /// + /// true if can support QSV h264 hardware encoding + 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; + } } } \ No newline at end of file diff --git a/VideoNodes/VideoNodes/VideoScaler.cs b/VideoNodes/VideoNodes/VideoScaler.cs index 4c604fe6..c159f33a 100644 --- a/VideoNodes/VideoNodes/VideoScaler.cs +++ b/VideoNodes/VideoNodes/VideoScaler.cs @@ -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 ffArgs = new List() { "-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;