diff options
Diffstat (limited to 'MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs')
| -rw-r--r-- | MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 119 |
1 files changed, 42 insertions, 77 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 5cfead502..764230feb 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -12,6 +12,7 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using AsyncKeyedLock; +using Jellyfin.Data.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using Jellyfin.Extensions.Json.Converters; @@ -79,8 +80,14 @@ namespace MediaBrowser.MediaEncoding.Encoder private bool _isVaapiDeviceAmd = false; private bool _isVaapiDeviceInteliHD = false; private bool _isVaapiDeviceInteli965 = false; + private bool _isVaapiDeviceSupportVulkanDrmModifier = false; private bool _isVaapiDeviceSupportVulkanDrmInterop = false; + private static string[] _vulkanImageDrmFmtModifierExts = + { + "VK_EXT_image_drm_format_modifier", + }; + private static string[] _vulkanExternalMemoryDmaBufExts = { "VK_KHR_external_memory_fd", @@ -141,34 +148,50 @@ namespace MediaBrowser.MediaEncoding.Encoder public bool IsVaapiDeviceInteli965 => _isVaapiDeviceInteli965; /// <inheritdoc /> + public bool IsVaapiDeviceSupportVulkanDrmModifier => _isVaapiDeviceSupportVulkanDrmModifier; + + /// <inheritdoc /> public bool IsVaapiDeviceSupportVulkanDrmInterop => _isVaapiDeviceSupportVulkanDrmInterop; [GeneratedRegex(@"[^\/\\]+?(\.[^\/\\\n.]+)?$")] private static partial Regex FfprobePathRegex(); /// <summary> - /// Run at startup or if the user removes a Custom path from transcode page. + /// Run at startup to validate ffmpeg. /// Sets global variables FFmpegPath. - /// Precedence is: Config > CLI > $PATH. + /// Precedence is: CLI/Env var > Config > $PATH. /// </summary> - public void SetFFmpegPath() + /// <returns>bool indicates whether a valid ffmpeg is found.</returns> + public bool SetFFmpegPath() { + var skipValidation = _config.GetFFmpegSkipValidation(); + if (skipValidation) + { + _logger.LogWarning("FFmpeg: Skipping FFmpeg Validation due to FFmpeg:novalidation set to true"); + return true; + } + // 1) Check if the --ffmpeg CLI switch has been given var ffmpegPath = _startupOptionFFmpegPath; + string ffmpegPathSetMethodText = "command line or environment variable"; if (string.IsNullOrEmpty(ffmpegPath)) { // 2) Custom path stored in config/encoding xml file under tag <EncoderAppPath> should be used as a fallback ffmpegPath = _configurationManager.GetEncodingOptions().EncoderAppPath; + ffmpegPathSetMethodText = "encoding.xml config file"; if (string.IsNullOrEmpty(ffmpegPath)) { // 3) Check "ffmpeg" ffmpegPath = "ffmpeg"; + ffmpegPathSetMethodText = "system $PATH"; } } if (!ValidatePath(ffmpegPath)) { _ffmpegPath = null; + _logger.LogError("FFmpeg: Path set by {FfmpegPathSetMethodText} is invalid", ffmpegPathSetMethodText); + return false; } // Write the FFmpeg path to the config/encoding.xml file as <EncoderAppPathDisplay> so it appears in UI @@ -194,7 +217,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _threads = EncodingHelper.GetNumberOfThreads(null, options, null); - _isPkeyPauseSupported = validator.CheckSupportedRuntimeKey("p pause transcoding"); + _isPkeyPauseSupported = validator.CheckSupportedRuntimeKey("p pause transcoding", _ffmpegVersion); _isLowPriorityHwDecodeSupported = validator.CheckSupportedHwaccelFlag("low_priority"); // Check the Vaapi device vendor @@ -206,6 +229,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _isVaapiDeviceAmd = validator.CheckVaapiDeviceByDriverName("Mesa Gallium driver", options.VaapiDevice); _isVaapiDeviceInteliHD = validator.CheckVaapiDeviceByDriverName("Intel iHD driver", options.VaapiDevice); _isVaapiDeviceInteli965 = validator.CheckVaapiDeviceByDriverName("Intel i965 driver", options.VaapiDevice); + _isVaapiDeviceSupportVulkanDrmModifier = validator.CheckVulkanDrmDeviceByExtensionName(options.VaapiDevice, _vulkanImageDrmFmtModifierExts); _isVaapiDeviceSupportVulkanDrmInterop = validator.CheckVulkanDrmDeviceByExtensionName(options.VaapiDevice, _vulkanExternalMemoryDmaBufExts); if (_isVaapiDeviceAmd) @@ -221,6 +245,11 @@ namespace MediaBrowser.MediaEncoding.Encoder _logger.LogInformation("VAAPI device {RenderNodePath} is Intel GPU (i965)", options.VaapiDevice); } + if (_isVaapiDeviceSupportVulkanDrmModifier) + { + _logger.LogInformation("VAAPI device {RenderNodePath} supports Vulkan DRM modifier", options.VaapiDevice); + } + if (_isVaapiDeviceSupportVulkanDrmInterop) { _logger.LogInformation("VAAPI device {RenderNodePath} supports Vulkan DRM interop", options.VaapiDevice); @@ -229,65 +258,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } _logger.LogInformation("FFmpeg: {FfmpegPath}", _ffmpegPath ?? string.Empty); - } - - /// <summary> - /// Triggered from the Settings > Transcoding UI page when users submits Custom FFmpeg path to use. - /// Only write the new path to xml if it exists. Do not perform validation checks on ffmpeg here. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="pathType">The path type.</param> - public void UpdateEncoderPath(string path, string pathType) - { - var config = _configurationManager.GetEncodingOptions(); - - // Filesystem may not be case insensitive, but EncoderAppPathDisplay should always point to a valid file? - if (string.IsNullOrEmpty(config.EncoderAppPath) - && string.Equals(config.EncoderAppPathDisplay, path, StringComparison.OrdinalIgnoreCase)) - { - _logger.LogDebug("Existing ffmpeg path is empty and the new path is the same as {EncoderAppPathDisplay}. Skipping", nameof(config.EncoderAppPathDisplay)); - return; - } - - string newPath; - - _logger.LogInformation("Attempting to update encoder path to {Path}. pathType: {PathType}", path ?? string.Empty, pathType ?? string.Empty); - - if (!string.Equals(pathType, "custom", StringComparison.OrdinalIgnoreCase)) - { - throw new ArgumentException("Unexpected pathType value"); - } - - if (string.IsNullOrWhiteSpace(path)) - { - // User had cleared the custom path in UI - newPath = string.Empty; - } - else - { - if (Directory.Exists(path)) - { - // Given path is directory, so resolve down to filename - newPath = GetEncoderPathFromDirectory(path, "ffmpeg"); - } - else - { - newPath = path; - } - - if (!new EncoderValidator(_logger, newPath).ValidateVersion()) - { - throw new ResourceNotFoundException(); - } - } - - // Write the new ffmpeg path to the xml as <EncoderAppPath> - // This ensures its not lost on next startup - config.EncoderAppPath = newPath; - _configurationManager.SaveConfiguration("encoding", config); - - // Trigger SetFFmpegPath so we validate the new path and setup probe path - SetFFmpegPath(); + return !string.IsNullOrWhiteSpace(ffmpegPath); } /// <summary> @@ -306,7 +277,7 @@ namespace MediaBrowser.MediaEncoding.Encoder bool rc = new EncoderValidator(_logger, path).ValidateVersion(); if (!rc) { - _logger.LogWarning("FFmpeg: Failed version check: {Path}", path); + _logger.LogError("FFmpeg: Failed version check: {Path}", path); return false; } @@ -710,18 +681,18 @@ namespace MediaBrowser.MediaEncoding.Encoder filters.Add("thumbnail=n=" + (useLargerBatchSize ? "50" : "24")); } - // Use SW tonemap on HDR10/HLG video stream only when the zscale or tonemapx filter is available. + // Use SW tonemap on HDR video stream only when the zscale or tonemapx filter is available. + // Only enable Dolby Vision tonemap when tonemapx is available var enableHdrExtraction = false; - if (string.Equals(videoStream?.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) - || string.Equals(videoStream?.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) + if (videoStream?.VideoRange == VideoRange.HDR) { if (SupportsFilter("tonemapx")) { enableHdrExtraction = true; filters.Add("tonemapx=tonemap=bt2390:desat=0:peak=100:t=bt709:m=bt709:p=bt709:format=yuv420p"); } - else if (SupportsFilter("zscale")) + else if (SupportsFilter("zscale") && videoStream.VideoRangeType != VideoRangeType.DOVI) { enableHdrExtraction = true; filters.Add("zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0:peak=100,zscale=t=bt709:m=bt709,format=yuv420p"); @@ -764,8 +735,6 @@ namespace MediaBrowser.MediaEncoding.Encoder using (var processWrapper = new ProcessWrapper(process, this)) { - bool ranToCompletion; - using (await _thumbnailResourcePool.LockAsync(cancellationToken).ConfigureAwait(false)) { StartProcess(processWrapper); @@ -779,22 +748,18 @@ namespace MediaBrowser.MediaEncoding.Encoder try { await process.WaitForExitAsync(TimeSpan.FromMilliseconds(timeoutMs)).ConfigureAwait(false); - ranToCompletion = true; } - catch (OperationCanceledException) + catch (OperationCanceledException ex) { process.Kill(true); - ranToCompletion = false; + throw new FfmpegException(string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction timed out for {0} after {1}ms", inputPath, timeoutMs), ex); } } - var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; var file = _fileSystem.GetFileInfo(tempExtractPath); - if (exitCode == -1 || !file.Exists || file.Length == 0) + if (processWrapper.ExitCode > 0 || !file.Exists || file.Length == 0) { - _logger.LogError("ffmpeg image extraction failed for {Path}", inputPath); - throw new FfmpegException(string.Format(CultureInfo.InvariantCulture, "ffmpeg image extraction failed for {0}", inputPath)); } |
