mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2026-01-04 20:30:59 -06:00
239 lines
9.9 KiB
C#
239 lines
9.9 KiB
C#
namespace FileFlows.VideoNodes
|
|
{
|
|
using System.ComponentModel;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using FileFlows.Plugin;
|
|
using FileFlows.Plugin.Attributes;
|
|
|
|
public abstract class EncodingNode : VideoNode
|
|
{
|
|
public override int Outputs => 2;
|
|
public override int Inputs => 1;
|
|
public override FlowElementType Type => FlowElementType.Process;
|
|
|
|
protected TimeSpan TotalTime;
|
|
|
|
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)
|
|
{
|
|
string output;
|
|
return Encode(args, ffmpegExe, ffmpegParameters, out output, extension, outputFile, updateWorkingFile, dontAddInputFile: dontAddInputFile, dontAddOutputFile: dontAddOutputFile);
|
|
}
|
|
|
|
public bool Encode(NodeParameters args, string ffmpegExe, List<string> ffmpegParameters, out string output, string extension = "mkv", string outputFile = "", bool updateWorkingFile = true, bool dontAddInputFile = false, bool dontAddOutputFile = false)
|
|
{
|
|
if (string.IsNullOrEmpty(extension))
|
|
extension = "mkv";
|
|
|
|
Encoder = new FFMpegEncoder(ffmpegExe, args.Logger);
|
|
Encoder.AtTime += AtTimeEvent;
|
|
|
|
if (string.IsNullOrEmpty(outputFile))
|
|
outputFile = Path.Combine(args.TempPath, Guid.NewGuid().ToString() + "." + extension);
|
|
|
|
if (TotalTime.TotalMilliseconds == 0)
|
|
{
|
|
VideoInfo videoInfo = GetVideoInfo(args);
|
|
if (videoInfo != null)
|
|
{
|
|
TotalTime = videoInfo.VideoStreams[0].Duration;
|
|
args.Logger.ILog("### Total Time: " + TotalTime);
|
|
}
|
|
}
|
|
|
|
var success = Encoder.Encode(args.WorkingFile, outputFile, ffmpegParameters, dontAddInputFile: dontAddInputFile, dontAddOutputFile: dontAddOutputFile);
|
|
args.Logger.ILog("Encoding successful: " + success.successs);
|
|
if (success.successs && updateWorkingFile)
|
|
{
|
|
args.SetWorkingFile(outputFile);
|
|
|
|
// get the new video info
|
|
var videoInfo = new VideoInfoHelper(ffmpegExe, args.Logger).Read(outputFile);
|
|
SetVideoInfo(args, videoInfo, this.Variables ?? new Dictionary<string, object>());
|
|
}
|
|
Encoder.AtTime -= AtTimeEvent;
|
|
Encoder = null;
|
|
output = success.output;
|
|
return success.successs;
|
|
}
|
|
|
|
public override Task Cancel()
|
|
{
|
|
if (Encoder != null)
|
|
Encoder.Cancel();
|
|
return base.Cancel();
|
|
}
|
|
|
|
void AtTimeEvent(TimeSpan time)
|
|
{
|
|
if (TotalTime.TotalMilliseconds == 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);
|
|
}
|
|
|
|
public string CheckVideoCodec(string ffmpeg, string vidparams)
|
|
{
|
|
if (string.IsNullOrEmpty(vidparams))
|
|
return string.Empty;
|
|
|
|
var splitParams = vidparams.ToLower().Split(" ");
|
|
|
|
if(splitParams.Contains("hevc") || splitParams.Contains("h265"))
|
|
{
|
|
// try find best hevc encoder
|
|
foreach(string vidparam in new [] { "hevc_nvenc -preset hq", "hevc_qsv -global_quality 28 -load_plugin hevc_hw", "hevc_amf", "hevc_vaapi" })
|
|
{
|
|
bool canProcess = CanUseHardwareEncodingChecker.CanProcess(Args, ffmpeg, vidparam);
|
|
if (canProcess)
|
|
return vidparam;
|
|
}
|
|
return "libx265";
|
|
}
|
|
if (splitParams.Contains("h264"))
|
|
{
|
|
// try find best hevc encoder
|
|
foreach (string vidparam in new[] { "h264_nvenc", "h264_qsv", "h264_amf", "h264_vaapi" })
|
|
{
|
|
bool canProcess = CanUseHardwareEncodingChecker.CanProcess(Args, ffmpeg, vidparam);
|
|
if (canProcess)
|
|
return vidparam;
|
|
}
|
|
return "libx264";
|
|
}
|
|
|
|
// removed in FF-137
|
|
//if (vidparams.ToLower().Contains("hevc_nvenc"))
|
|
//{
|
|
// // nvidia h265 encoding, check can
|
|
// bool canProcess = CanUseHardwareEncodingChecker.CanProcess(Args, ffmpeg, vidparams);
|
|
// if (canProcess == false)
|
|
// {
|
|
// // change to cpu encoding
|
|
// Args.Logger?.ILog("Can't encode using hevc_nvenc, falling back to CPU encoding H265 (libx265)");
|
|
// return "libx265";
|
|
// }
|
|
// return vidparams;
|
|
//}
|
|
//else if (vidparams.ToLower().Contains("h264_nvenc"))
|
|
//{
|
|
// // nvidia h264 encoding, check can
|
|
// bool canProcess = CanUseHardwareEncodingChecker.CanProcess(Args, ffmpeg, vidparams);
|
|
// if (canProcess == false)
|
|
// {
|
|
// // change to cpu encoding
|
|
// Args.Logger?.ILog("Can't encode using h264_nvenc, falling back to CPU encoding H264 (libx264)");
|
|
// return "libx264";
|
|
// }
|
|
// return vidparams;
|
|
//}
|
|
//else if (vidparams.ToLower().Contains("hevc_qsv"))
|
|
//{
|
|
// // nvidia h265 encoding, check can
|
|
// bool canProcess = CanUseHardwareEncodingChecker.CanProcess(Args, ffmpeg, vidparams);
|
|
// if (canProcess == false)
|
|
// {
|
|
// // change to cpu encoding
|
|
// Args.Logger?.ILog("Can't encode using hevc_qsv, falling back to CPU encoding H265 (libx265)");
|
|
// return "libx265";
|
|
// }
|
|
// return vidparams;
|
|
//}
|
|
//else if (vidparams.ToLower().Contains("h264_qsv"))
|
|
//{
|
|
// // nvidia h264 encoding, check can
|
|
// bool canProcess = CanUseHardwareEncodingChecker.CanProcess(Args, ffmpeg, vidparams);
|
|
// if (canProcess == false)
|
|
// {
|
|
// // change to cpu encoding
|
|
// Args.Logger?.ILog("Can't encode using h264_qsv, falling back to CPU encoding H264 (libx264)");
|
|
// return "libx264";
|
|
// }
|
|
// return vidparams;
|
|
//}
|
|
return vidparams;
|
|
}
|
|
|
|
public bool HasNvidiaCard(string ffmpeg)
|
|
{
|
|
try
|
|
{
|
|
if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
|
|
{
|
|
var cmd = Args.Process.ExecuteShellCommand(new ExecuteArgs
|
|
{
|
|
Command = "wmic",
|
|
Arguments = "path win32_VideoController get name"
|
|
}).Result;
|
|
if (cmd.ExitCode == 0)
|
|
{
|
|
// it worked
|
|
if (cmd.Output?.ToLower()?.Contains("nvidia") == false)
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// linux, crude method, look for nvidia in the /dev dir
|
|
var dir = new DirectoryInfo("/dev");
|
|
if (dir.Exists == false)
|
|
return false;
|
|
|
|
bool dev = dir.GetDirectories().Any(x => x.Name.ToLower().Contains("nvidia"));
|
|
if (dev == false)
|
|
return false;
|
|
}
|
|
|
|
// check cuda in ffmpeg itself
|
|
var result = Args.Process.ExecuteShellCommand(new ExecuteArgs
|
|
{
|
|
Command = ffmpeg,
|
|
Arguments = "-hide_banner -init_hw_device list"
|
|
}).Result;
|
|
return result.Output?.Contains("cuda") == true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Args.Logger?.ELog("Failed to detect NVIDIA card: " + ex.Message + Environment.NewLine + ex.StackTrace);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
protected bool IsSameVideoCodec(string current, string wanted)
|
|
{
|
|
wanted = ReplaceCommon(wanted);
|
|
current = ReplaceCommon(current);
|
|
|
|
return wanted == current;
|
|
|
|
string ReplaceCommon(string input)
|
|
{
|
|
input = input.ToLower();
|
|
input = Regex.Replace(input, "^(divx|xvid|m(-)?peg(-)4)$", "mpeg4", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, "^(hevc|h[\\.x\\-]?265)$", "h265", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, "^(h[\\.x\\-]?264)$", "h264", RegexOptions.IgnoreCase);
|
|
return input;
|
|
}
|
|
}
|
|
|
|
protected bool SupportsSubtitles(NodeParameters args, VideoInfo videoInfo, string extension)
|
|
{
|
|
if (videoInfo?.SubtitleStreams?.Any() != true)
|
|
return false;
|
|
bool mov_text = videoInfo.SubtitleStreams.Any(x => x.Codec == "mov_text");
|
|
// if mov_text and going to mkv, we can't convert these subtitles
|
|
if (mov_text && extension?.ToLower()?.EndsWith("mkv") == true)
|
|
return false;
|
|
return true;
|
|
//if (Regex.IsMatch(container ?? string.Empty, "(mp(e)?(g)?4)|avi|divx|xvid", RegexOptions.IgnoreCase))
|
|
// return false;
|
|
//return true;
|
|
}
|
|
}
|
|
} |