diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index e9e8ed61820d..7076ed08777b 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -72,6 +72,7 @@ public partial class EncodingHelper private readonly Version _minFFmpegAlteredVaVkInterop = new Version(7, 0, 1); private readonly Version _minFFmpegQsvVppTonemapOption = new Version(7, 0, 1); private readonly Version _minFFmpegQsvVppOutRangeOption = new Version(7, 0, 1); + private readonly Version _minFFmpegVaapiDeviceVendorId = new Version(7, 0, 1); private static readonly Regex _validationRegex = new(ValidationRegex, RegexOptions.Compiled); @@ -208,6 +209,14 @@ private string GetMjpegEncoder(EncodingJobInfo state, EncodingOptions encodingOp { var hwType = encodingOptions.HardwareAccelerationType; + // Only Intel has VA-API MJPEG encoder + if (hwType == HardwareAccelerationType.vaapi + && !(_mediaEncoder.IsVaapiDeviceInteliHD + || _mediaEncoder.IsVaapiDeviceInteli965)) + { + return _defaultMjpegEncoder; + } + if (hwType != HardwareAccelerationType.none && encodingOptions.EnableHardwareEncoding && _mjpegCodecMap.TryGetValue(hwType, out var preferredEncoder) @@ -872,13 +881,15 @@ private string GetD3d11vaDeviceArgs(int deviceIndex, string deviceVendorId, stri options); } - private string GetVaapiDeviceArgs(string renderNodePath, string driver, string kernelDriver, string srcDeviceAlias, string alias) + private string GetVaapiDeviceArgs(string renderNodePath, string driver, string kernelDriver, string vendorId, string srcDeviceAlias, string alias) { alias ??= VaapiAlias; + var haveVendorId = !string.IsNullOrEmpty(vendorId) + && _mediaEncoder.EncoderVersion >= _minFFmpegVaapiDeviceVendorId; - // 'renderNodePath' has higher priority than 'kernelDriver' + // Priority: 'renderNodePath' > 'vendorId' > 'kernelDriver' var driverOpts = string.IsNullOrEmpty(renderNodePath) - ? (string.IsNullOrEmpty(kernelDriver) ? string.Empty : ",kernel_driver=" + kernelDriver) + ? (haveVendorId ? $",vendor_id={vendorId}" : (string.IsNullOrEmpty(kernelDriver) ? string.Empty : $",kernel_driver={kernelDriver}")) : renderNodePath; // 'driver' behaves similarly to env LIBVA_DRIVER_NAME @@ -913,7 +924,7 @@ private string GetQsvDeviceArgs(string renderNodePath, string alias) if (OperatingSystem.IsLinux()) { // derive qsv from vaapi device - return GetVaapiDeviceArgs(renderNodePath, "iHD", "i915", null, VaapiAlias) + arg + "@" + VaapiAlias; + return GetVaapiDeviceArgs(renderNodePath, "iHD", "i915", "0x8086", null, VaapiAlias) + arg + "@" + VaapiAlias; } if (OperatingSystem.IsWindows()) @@ -1008,14 +1019,14 @@ public string GetInputVideoHwaccelArgs(EncodingJobInfo state, EncodingOptions op if (_mediaEncoder.IsVaapiDeviceInteliHD) { - args.Append(GetVaapiDeviceArgs(options.VaapiDevice, "iHD", null, null, VaapiAlias)); + args.Append(GetVaapiDeviceArgs(options.VaapiDevice, "iHD", null, null, null, VaapiAlias)); } else if (_mediaEncoder.IsVaapiDeviceInteli965) { // Only override i965 since it has lower priority than iHD in libva lookup. Environment.SetEnvironmentVariable("LIBVA_DRIVER_NAME", "i965"); Environment.SetEnvironmentVariable("LIBVA_DRIVER_NAME_JELLYFIN", "i965"); - args.Append(GetVaapiDeviceArgs(options.VaapiDevice, "i965", null, null, VaapiAlias)); + args.Append(GetVaapiDeviceArgs(options.VaapiDevice, "i965", null, null, null, VaapiAlias)); } var filterDevArgs = string.Empty; @@ -1039,7 +1050,7 @@ public string GetInputVideoHwaccelArgs(EncodingJobInfo state, EncodingOptions op && Environment.OSVersion.Version >= _minKernelVersionAmdVkFmtModifier) { args.Append(GetDrmDeviceArgs(options.VaapiDevice, DrmAlias)); - args.Append(GetVaapiDeviceArgs(null, null, null, DrmAlias, VaapiAlias)); + args.Append(GetVaapiDeviceArgs(null, null, null, null, DrmAlias, VaapiAlias)); args.Append(GetVulkanDeviceArgs(0, null, DrmAlias, VulkanAlias)); // libplacebo wants an explicitly set vulkan filter device. @@ -1047,7 +1058,7 @@ public string GetInputVideoHwaccelArgs(EncodingJobInfo state, EncodingOptions op } else { - args.Append(GetVaapiDeviceArgs(options.VaapiDevice, null, null, null, VaapiAlias)); + args.Append(GetVaapiDeviceArgs(options.VaapiDevice, null, null, null, null, VaapiAlias)); filterDevArgs = GetFilterHwDeviceArgs(VaapiAlias); if (doOclTonemap) @@ -1441,7 +1452,13 @@ private string GetEncoderParam(EncoderPreset? preset, EncoderPreset defaultPrese var encoderPreset = preset ?? defaultPreset; if (string.Equals(videoEncoder, "libx264", StringComparison.OrdinalIgnoreCase) || isLibX265) { - param += " -preset " + encoderPreset.ToString().ToLowerInvariant(); + var presetString = encoderPreset switch + { + EncoderPreset.auto => EncoderPreset.veryfast.ToString().ToLowerInvariant(), + _ => encoderPreset.ToString().ToLowerInvariant() + }; + + param += " -preset " + presetString; int encodeCrf = encodingOptions.H264Crf; if (isLibX265) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 517d135d3bd1..7ae1fbbb1060 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -1104,7 +1104,11 @@ public string EscapeSubtitleFilterPath(string path) // https://ffmpeg.org/ffmpeg-filters.html#Notes-on-filtergraph-escaping // We need to double escape - return path.Replace('\\', '/').Replace(":", "\\:", StringComparison.Ordinal).Replace("'", @"'\\\''", StringComparison.Ordinal); + return path + .Replace('\\', '/') + .Replace(":", "\\:", StringComparison.Ordinal) + .Replace("'", @"'\\\''", StringComparison.Ordinal) + .Replace("\"", "\\\"", StringComparison.Ordinal); } ///