aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.MediaEncoding
diff options
context:
space:
mode:
authornyanmisaka <nst799610810@gmail.com>2021-12-02 00:49:50 +0800
committernyanmisaka <nst799610810@gmail.com>2021-12-24 17:03:57 +0800
commit4b9c84c52e884e6d35d9bfdc41cbfc04f77b156c (patch)
tree9007ab814db4a9638898b8a22b8c766364530c96 /MediaBrowser.MediaEncoding
parent976e3160b8d558aaa3e944892a3362f004bc93a6 (diff)
EncodingHelper hwaccel pipelines refactor
separate the HW pipeline according to HWA method for maintainability.
Diffstat (limited to 'MediaBrowser.MediaEncoding')
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs82
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs51
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs27
3 files changed, 127 insertions, 33 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
index 60a2d39e5..871e7d57d 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
@@ -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();
}
}
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 1c97a1982..7b7bb8100 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -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;
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 32ff1dee6..24577e499 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -764,18 +764,23 @@ namespace MediaBrowser.MediaEncoding.Probing
if (!stream.BitDepth.HasValue)
{
- if (!string.IsNullOrEmpty(streamInfo.PixelFormat)
- && streamInfo.PixelFormat.Contains("p10", StringComparison.OrdinalIgnoreCase))
+ if (!string.IsNullOrEmpty(streamInfo.PixelFormat))
{
- stream.BitDepth = 10;
- }
-
- if (!string.IsNullOrEmpty(streamInfo.Profile)
- && (streamInfo.Profile.Contains("Main 10", StringComparison.OrdinalIgnoreCase)
- || streamInfo.Profile.Contains("High 10", StringComparison.OrdinalIgnoreCase)
- || streamInfo.Profile.Contains("Profile 2", StringComparison.OrdinalIgnoreCase)))
- {
- stream.BitDepth = 10;
+ if (string.Equals(streamInfo.PixelFormat, "yuv420p", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(streamInfo.PixelFormat, "yuv444p", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.BitDepth = 8;
+ }
+ else if (string.Equals(streamInfo.PixelFormat, "yuv420p10le", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(streamInfo.PixelFormat, "yuv444p10le", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.BitDepth = 10;
+ }
+ else if (string.Equals(streamInfo.PixelFormat, "yuv420p12le", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(streamInfo.PixelFormat, "yuv444p12le", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.BitDepth = 12;
+ }
}
}