Files
FileFlowsPlugins/VideoLegacyNodes/VideoNodes/VideoEncode.cs

172 lines
7.0 KiB
C#

namespace FileFlows.VideoNodes
{
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Text.RegularExpressions;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
public class VideoEncode : EncodingNode
{
[DefaultValue("hevc")]
[TextVariable(1)]
public string VideoCodec { get; set; }
[DefaultValue("hevc")]
[TextVariable(2)]
public string VideoCodecParameters { get; set; }
[DefaultValue("ac3")]
[TextVariable(3)]
public string AudioCodec { get; set; }
[DefaultValue("eng")]
[TextVariable(4)]
public string Language { get; set; }
[DefaultValue("mkv")]
[TextVariable(5)]
public string Extension { get; set; }
public override string Icon => "far fa-file-video";
public override int Execute(NodeParameters args)
{
if (VideoCodec == "COPY")
VideoCodec = string.Empty;
if (AudioCodec == "COPY")
AudioCodec = string.Empty;
if (string.IsNullOrEmpty(VideoCodec) && string.IsNullOrEmpty(AudioCodec))
{
args.Logger?.ELog("Video codec or Audio codec must be set");
return -1;
}
if (string.IsNullOrWhiteSpace(VideoCodecParameters))
VideoCodecParameters = VideoCodec;
VideoCodec = args.ReplaceVariables(VideoCodec ?? string.Empty);
VideoCodecParameters = args.ReplaceVariables(VideoCodecParameters ?? string.Empty);
AudioCodec = args.ReplaceVariables(AudioCodec ?? string.Empty);
Language = args.ReplaceVariables(Language);
VideoCodec = VideoCodec.ToLower();
AudioCodec = AudioCodec.ToLower();
try
{
VideoInfo videoInfo = GetVideoInfo(args);
if (videoInfo == null)
return -1;
Language = Language?.ToLower() ?? "";
// ffmpeg is one based for stream index, so video should be 1, audio should be 2
string encodeVideoParameters = string.Empty, encodeAudioParameters = string.Empty;
const string copyVideoStream = "-map 0:v -c:v copy";
const string copyAudioStream = "-map 0:a -c:a copy";
if (string.IsNullOrEmpty(VideoCodec) == false)
{
var videoIsRightCodec = videoInfo.VideoStreams.FirstOrDefault(x => IsSameVideoCodec(x.Codec ?? string.Empty, VideoCodec));
var videoTrack = videoIsRightCodec ?? videoInfo.VideoStreams[0];
args.Logger?.ILog("Video: ", videoTrack);
string crop = (args.Variables.ContainsKey(DetectBlackBars.CROP_KEY) ? args.Variables[DetectBlackBars.CROP_KEY] as string : string.Empty) ?? string.Empty;
if (crop != string.Empty)
crop = " -vf crop=" + crop;
if (videoIsRightCodec == null || crop != string.Empty)
{
string codecParameters = CheckVideoCodec(FFMPEG, VideoCodecParameters);
encodeVideoParameters = $"-map 0:v:0 -c:v {codecParameters} {crop}";
}
Extension = args.ReplaceVariables(Extension)?.EmptyAsNull() ?? "mkv";
}
else if(string.IsNullOrEmpty(Extension) == false)
{
// vidoe is being copied so use the same extension
Extension = new FileInfo(args.WorkingFile).Extension;
if(Extension.StartsWith("."))
Extension = Extension.Substring(1);
}
if (string.IsNullOrEmpty(AudioCodec) == false)
{
var bestAudio = videoInfo.AudioStreams.Where(x => System.Text.Json.JsonSerializer.Serialize(x).ToLower().Contains("commentary") == false)
.OrderBy(x =>
{
if (Language != string.Empty)
{
args.Logger?.ILog("Language: " + x.Language, x);
if (string.IsNullOrEmpty(x.Language))
return 50; // no language specified
if (x.Language?.ToLower() != Language)
return 100; // low priority not the desired language
}
return 0;
})
.ThenByDescending(x => x.Channels)
.ThenBy(x => x.Index)
.FirstOrDefault();
bool audioRightCodec = bestAudio?.Codec?.ToLower() == AudioCodec && videoInfo.AudioStreams[0] == bestAudio;
args.Logger?.ILog("Best Audio: ", bestAudio == null ? "null" : (object)bestAudio);
if (audioRightCodec == false)
encodeAudioParameters = $"-map 0:{bestAudio!.Index} -c:a {AudioCodec}";
else if(videoInfo.AudioStreams.Count > 1)
encodeAudioParameters = $"-map 0:{bestAudio!.Index} -c:a copy";
}
if(string.IsNullOrEmpty(encodeVideoParameters) && string.IsNullOrEmpty(encodeAudioParameters))
{
args.Logger?.ILog("Video and Audio does not need to be reencoded");
return 2;
}
List<string> ffArgs = new List<string>();
ffArgs.AddRange((encodeVideoParameters?.EmptyAsNull() ?? copyVideoStream).Split(" ").Where(x => string.IsNullOrEmpty(x.Trim()) == false).Select(x => x.Trim()).ToArray());
ffArgs.AddRange((encodeAudioParameters?.EmptyAsNull() ?? copyAudioStream).Split(" ").Where(x => string.IsNullOrEmpty(x.Trim()) == false).Select(x => x.Trim()).ToArray());
TotalTime = videoInfo.VideoStreams[0].Duration;
args.Logger.ILog("### Total Time: " + TotalTime);
if (videoInfo?.SubtitleStreams?.Any() == true)
{
if (SupportsSubtitles(args, videoInfo, Extension))
{
if (Language != string.Empty)
ffArgs.AddRange(new[] { "-map", $"0:s:m:language:{Language}?", "-c:s", "copy" });
else
ffArgs.AddRange(new[] { "-map", "0:s?", "-c:s", "copy" });
}
else
{
args.Logger?.WLog("Unsupported subtitle for target container, subtitles will be removed.");
}
}
if (Encode(args, FFMPEG, ffArgs, Extension) == false)
return -1;
return 1;
}
catch (Exception ex)
{
args.Logger?.ELog("Failed processing VideoFile: " + ex.Message);
return -1;
}
}
}
}