mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-12-22 00:35:26 +03:00
EncodingHelper hwaccel pipelines refactor
separate the HW pipeline according to HWA method for maintainability.
This commit is contained in:
@@ -16,6 +16,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
{
|
||||
"h264",
|
||||
"hevc",
|
||||
"vp8",
|
||||
"libvpx",
|
||||
"vp9",
|
||||
"libvpx-vp9",
|
||||
"av1",
|
||||
"libdav1d",
|
||||
"mpeg2video",
|
||||
"mpeg4",
|
||||
"msmpeg4",
|
||||
@@ -30,6 +36,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
"vc1_qsv",
|
||||
"vp8_qsv",
|
||||
"vp9_qsv",
|
||||
"av1_qsv",
|
||||
"h264_cuvid",
|
||||
"hevc_cuvid",
|
||||
"mpeg2_cuvid",
|
||||
@@ -37,16 +44,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
"mpeg4_cuvid",
|
||||
"vp8_cuvid",
|
||||
"vp9_cuvid",
|
||||
"av1_cuvid",
|
||||
"h264_mmal",
|
||||
"mpeg2_mmal",
|
||||
"mpeg4_mmal",
|
||||
"vc1_mmal",
|
||||
"h264_mediacodec",
|
||||
"hevc_mediacodec",
|
||||
"mpeg2_mediacodec",
|
||||
"mpeg4_mediacodec",
|
||||
"vp8_mediacodec",
|
||||
"vp9_mediacodec",
|
||||
"h264_opencl",
|
||||
"hevc_opencl",
|
||||
"mpeg2_opencl",
|
||||
@@ -89,20 +91,39 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
|
||||
private static readonly string[] _requiredFilters = new[]
|
||||
{
|
||||
// sw
|
||||
"alphasrc",
|
||||
"zscale",
|
||||
// qsv
|
||||
"scale_qsv",
|
||||
"vpp_qsv",
|
||||
"deinterlace_qsv",
|
||||
"overlay_qsv",
|
||||
// cuda
|
||||
"scale_cuda",
|
||||
"yadif_cuda",
|
||||
"hwupload_cuda",
|
||||
"overlay_cuda",
|
||||
"tonemap_cuda",
|
||||
"overlay_cuda",
|
||||
"hwupload_cuda",
|
||||
// opencl
|
||||
"scale_opencl",
|
||||
"tonemap_opencl",
|
||||
"overlay_opencl",
|
||||
// vaapi
|
||||
"scale_vaapi",
|
||||
"deinterlace_vaapi",
|
||||
"tonemap_vaapi",
|
||||
"overlay_vaapi",
|
||||
"hwupload_vaapi"
|
||||
};
|
||||
|
||||
private static readonly IReadOnlyDictionary<int, string[]> _filterOptionsDict = new Dictionary<int, string[]>
|
||||
{
|
||||
{ 0, new string[] { "scale_cuda", "Output format (default \"same\")" } },
|
||||
{ 1, new string[] { "tonemap_cuda", "GPU accelerated HDR to SDR tonemapping" } },
|
||||
{ 2, new string[] { "tonemap_opencl", "bt2390" } }
|
||||
{ 2, new string[] { "tonemap_opencl", "bt2390" } },
|
||||
{ 3, new string[] { "overlay_opencl", "Action to take when encountering EOF from secondary input" } },
|
||||
{ 4, new string[] { "overlay_vaapi", "Action to take when encountering EOF from secondary input" } }
|
||||
};
|
||||
|
||||
// These are the library versions that corresponds to our minimum ffmpeg version 4.x according to the version table below
|
||||
@@ -144,7 +165,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
string output;
|
||||
try
|
||||
{
|
||||
output = GetProcessOutput(_encoderPath, "-version");
|
||||
output = GetProcessOutput(_encoderPath, "-version", false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -225,7 +246,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
string output;
|
||||
try
|
||||
{
|
||||
output = GetProcessOutput(_encoderPath, "-version");
|
||||
output = GetProcessOutput(_encoderPath, "-version", false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -318,12 +339,38 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
return map;
|
||||
}
|
||||
|
||||
public bool CheckVaapiDeviceByDriverName(string driverName, string renderNodePath)
|
||||
{
|
||||
if (!OperatingSystem.IsLinux())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(driverName) || string.IsNullOrEmpty(renderNodePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string output;
|
||||
try
|
||||
{
|
||||
output = GetProcessOutput(_encoderPath, "-v verbose -hide_banner -init_hw_device vaapi=va:" + renderNodePath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error detecting the given vaapi render node path");
|
||||
return false;
|
||||
}
|
||||
|
||||
return output.Contains(driverName, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetHwaccelTypes()
|
||||
{
|
||||
string? output = null;
|
||||
try
|
||||
{
|
||||
output = GetProcessOutput(_encoderPath, "-hwaccels");
|
||||
output = GetProcessOutput(_encoderPath, "-hwaccels", false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -351,7 +398,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
string output;
|
||||
try
|
||||
{
|
||||
output = GetProcessOutput(_encoderPath, "-h filter=" + filter);
|
||||
output = GetProcessOutput(_encoderPath, "-h filter=" + filter, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -375,7 +422,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
string output;
|
||||
try
|
||||
{
|
||||
output = GetProcessOutput(_encoderPath, "-" + codecstr);
|
||||
output = GetProcessOutput(_encoderPath, "-" + codecstr, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -406,7 +453,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
string output;
|
||||
try
|
||||
{
|
||||
output = GetProcessOutput(_encoderPath, "-filters");
|
||||
output = GetProcessOutput(_encoderPath, "-filters", false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -444,7 +491,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
return dict;
|
||||
}
|
||||
|
||||
private string GetProcessOutput(string path, string arguments)
|
||||
private string GetProcessOutput(string path, string arguments, bool readStdErr)
|
||||
{
|
||||
using (var process = new Process()
|
||||
{
|
||||
@@ -455,7 +502,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
ErrorDialog = false,
|
||||
RedirectStandardOutput = true,
|
||||
// ffmpeg uses stderr to log info, don't show this
|
||||
RedirectStandardError = true
|
||||
}
|
||||
})
|
||||
@@ -464,7 +510,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
|
||||
process.Start();
|
||||
|
||||
return process.StandardOutput.ReadToEnd();
|
||||
return readStdErr ? process.StandardError.ReadToEnd() : process.StandardOutput.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
private List<string> _filters = new List<string>();
|
||||
private IDictionary<int, bool> _filtersWithOption = new Dictionary<int, bool>();
|
||||
|
||||
private bool _isVaapiDeviceAmd = false;
|
||||
private bool _isVaapiDeviceInteliHD = false;
|
||||
private bool _isVaapiDeviceInteli965 = false;
|
||||
|
||||
private Version _ffmpegVersion = null;
|
||||
private string _ffmpegPath = string.Empty;
|
||||
private string _ffprobePath;
|
||||
@@ -114,9 +118,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
}
|
||||
|
||||
// Write the FFmpeg path to the config/encoding.xml file as <EncoderAppPathDisplay> so it appears in UI
|
||||
var config = _configurationManager.GetEncodingOptions();
|
||||
config.EncoderAppPathDisplay = _ffmpegPath ?? string.Empty;
|
||||
_configurationManager.SaveConfiguration("encoding", config);
|
||||
var options = _configurationManager.GetEncodingOptions();
|
||||
options.EncoderAppPathDisplay = _ffmpegPath ?? string.Empty;
|
||||
_configurationManager.SaveConfiguration("encoding", options);
|
||||
|
||||
// Only if mpeg path is set, try and set path to probe
|
||||
if (_ffmpegPath != null)
|
||||
@@ -134,7 +138,31 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
SetAvailableHwaccels(validator.GetHwaccels());
|
||||
SetMediaEncoderVersion(validator);
|
||||
|
||||
_threads = EncodingHelper.GetNumberOfThreads(null, _configurationManager.GetEncodingOptions(), null);
|
||||
options = _configurationManager.GetEncodingOptions();
|
||||
_threads = EncodingHelper.GetNumberOfThreads(null, options, null);
|
||||
|
||||
// Check the Vaapi device vendor
|
||||
if (OperatingSystem.IsLinux()
|
||||
&& SupportsHwaccel("vaapi")
|
||||
&& !string.IsNullOrEmpty(options.VaapiDevice)
|
||||
&& string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_isVaapiDeviceAmd = validator.CheckVaapiDeviceByDriverName("Mesa Gallium driver", options.VaapiDevice);
|
||||
_isVaapiDeviceInteliHD = validator.CheckVaapiDeviceByDriverName("Intel iHD driver", options.VaapiDevice);
|
||||
_isVaapiDeviceInteli965 = validator.CheckVaapiDeviceByDriverName("Intel i965 driver", options.VaapiDevice);
|
||||
if (_isVaapiDeviceAmd)
|
||||
{
|
||||
_logger.LogInformation("VAAPI device {RenderNodePath} is AMD GPU", options.VaapiDevice);
|
||||
}
|
||||
else if (_isVaapiDeviceInteliHD)
|
||||
{
|
||||
_logger.LogInformation("VAAPI device {RenderNodePath} is Intel GPU (iHD)", options.VaapiDevice);
|
||||
}
|
||||
else if (_isVaapiDeviceInteli965)
|
||||
{
|
||||
_logger.LogInformation("VAAPI device {RenderNodePath} is Intel GPU (i965)", options.VaapiDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("FFmpeg: {FfmpegPath}", _ffmpegPath ?? string.Empty);
|
||||
@@ -301,6 +329,21 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsVaapiDeviceAmd()
|
||||
{
|
||||
return _isVaapiDeviceAmd;
|
||||
}
|
||||
|
||||
public bool IsVaapiDeviceInteliHD()
|
||||
{
|
||||
return _isVaapiDeviceInteliHD;
|
||||
}
|
||||
|
||||
public bool IsVaapiDeviceInteli965()
|
||||
{
|
||||
return _isVaapiDeviceInteli965;
|
||||
}
|
||||
|
||||
public Version GetMediaEncoderVersion()
|
||||
{
|
||||
return _ffmpegVersion;
|
||||
|
||||
Reference in New Issue
Block a user