From a168040cc8c0067c35801ec0469af80729c03487 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Wed, 15 Jun 2022 15:27:07 -0600 Subject: Merge pull request #7941 from jellyfin/fix-overflow (cherry picked from commit fd4ffc6ba3317987856629088b759db8c1128ecd) Signed-off-by: Joshua Boniface --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 1755b872f4..04778e6993 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1893,7 +1893,7 @@ namespace MediaBrowser.Controller.MediaEncoding return request.EnableAutoStreamCopy; } - public int? GetVideoBitrateParamValue(BaseEncodingJobOptions request, MediaStream videoStream, string outputVideoCodec) + public int GetVideoBitrateParamValue(BaseEncodingJobOptions request, MediaStream videoStream, string outputVideoCodec) { var bitrate = request.VideoBitRate; @@ -1925,7 +1925,8 @@ namespace MediaBrowser.Controller.MediaEncoding } } - return bitrate; + // Cap the max target bitrate to intMax/2 to satisify the bufsize=bitrate*2. + return Math.Min(bitrate ?? 0, int.MaxValue / 2); } private int GetMinBitrate(int sourceBitrate, int requestedBitrate) @@ -2272,7 +2273,10 @@ namespace MediaBrowser.Controller.MediaEncoding int audioStreamIndex = FindIndex(state.MediaSource.MediaStreams, state.AudioStream); if (state.AudioStream.IsExternal) { - bool hasExternalGraphicsSubs = state.SubtitleStream != null && state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream; + bool hasExternalGraphicsSubs = state.SubtitleStream != null + && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode + && state.SubtitleStream.IsExternal + && !state.SubtitleStream.IsTextSubtitleStream; int externalAudioMapIndex = hasExternalGraphicsSubs ? 2 : 1; args += string.Format( -- cgit v1.2.3 From 7f1223016df0c9b55d89992b612648ed35a636dc Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Thu, 16 Jun 2022 07:14:56 -0600 Subject: Merge pull request #7946 from cvium/svg (cherry picked from commit 4ebe70cf6a12be4f4eae0b815a269a483ee238bb) Signed-off-by: Joshua Boniface --- Emby.Drawing/ImageProcessor.cs | 83 ++++++++++++---------- .../Library/LibraryManager.cs | 13 ++-- Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj | 1 + Jellyfin.Drawing.Skia/SkiaEncoder.cs | 48 ++++++++++--- Jellyfin.Drawing.Skia/SkiaHelper.cs | 13 ---- MediaBrowser.Controller/Drawing/IImageProcessor.cs | 8 +++ 6 files changed, 98 insertions(+), 68 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 18b4139646..11256dafde 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -395,7 +395,13 @@ namespace Emby.Drawing public string GetImageBlurHash(string path) { var size = GetImageDimensions(path); - if (size.Width <= 0 || size.Height <= 0) + return GetImageBlurHash(path, size); + } + + /// + public string GetImageBlurHash(string path, ImageDimensions imageDimensions) + { + if (imageDimensions.Width <= 0 || imageDimensions.Height <= 0) { return string.Empty; } @@ -403,8 +409,8 @@ namespace Emby.Drawing // We want tiles to be as close to square as possible, and to *mostly* keep under 16 tiles for performance. // One tile is (width / xComp) x (height / yComp) pixels, which means that ideally yComp = xComp * height / width. // See more at https://github.com/woltapp/blurhash/#how-do-i-pick-the-number-of-x-and-y-components - float xCompF = MathF.Sqrt(16.0f * size.Width / size.Height); - float yCompF = xCompF * size.Height / size.Width; + float xCompF = MathF.Sqrt(16.0f * imageDimensions.Width / imageDimensions.Height); + float yCompF = xCompF * imageDimensions.Height / imageDimensions.Width; int xComp = Math.Min((int)xCompF + 1, 9); int yComp = Math.Min((int)yCompF + 1, 9); @@ -439,47 +445,46 @@ namespace Emby.Drawing .ToString("N", CultureInfo.InvariantCulture); } - private async Task<(string Path, DateTime DateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified) + private Task<(string Path, DateTime DateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified) { - var inputFormat = Path.GetExtension(originalImagePath) - .TrimStart('.') - .Replace("jpeg", "jpg", StringComparison.OrdinalIgnoreCase); + var inputFormat = Path.GetExtension(originalImagePath.AsSpan()).TrimStart('.').ToString(); // These are just jpg files renamed as tbn if (string.Equals(inputFormat, "tbn", StringComparison.OrdinalIgnoreCase)) { - return (originalImagePath, dateModified); - } - - if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat)) - { - try - { - string filename = (originalImagePath + dateModified.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("N", CultureInfo.InvariantCulture); - - string cacheExtension = _mediaEncoder.SupportsEncoder("libwebp") ? ".webp" : ".png"; - var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + cacheExtension); - - var file = _fileSystem.GetFileInfo(outputPath); - if (!file.Exists) - { - await _mediaEncoder.ConvertImage(originalImagePath, outputPath).ConfigureAwait(false); - dateModified = _fileSystem.GetLastWriteTimeUtc(outputPath); - } - else - { - dateModified = file.LastWriteTimeUtc; - } - - originalImagePath = outputPath; - } - catch (Exception ex) - { - _logger.LogError(ex, "Image conversion failed for {Path}", originalImagePath); - } - } - - return (originalImagePath, dateModified); + return Task.FromResult((originalImagePath, dateModified)); + } + + // TODO _mediaEncoder.ConvertImage is not implemented + // if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat)) + // { + // try + // { + // string filename = (originalImagePath + dateModified.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("N", CultureInfo.InvariantCulture); + // + // string cacheExtension = _mediaEncoder.SupportsEncoder("libwebp") ? ".webp" : ".png"; + // var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + cacheExtension); + // + // var file = _fileSystem.GetFileInfo(outputPath); + // if (!file.Exists) + // { + // await _mediaEncoder.ConvertImage(originalImagePath, outputPath).ConfigureAwait(false); + // dateModified = _fileSystem.GetLastWriteTimeUtc(outputPath); + // } + // else + // { + // dateModified = file.LastWriteTimeUtc; + // } + // + // originalImagePath = outputPath; + // } + // catch (Exception ex) + // { + // _logger.LogError(ex, "Image conversion failed for {Path}", originalImagePath); + // } + // } + + return Task.FromResult((originalImagePath, dateModified)); } /// diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index d6754ad4a8..c54945c93b 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1860,7 +1860,9 @@ namespace Emby.Server.Implementations.Library throw new ArgumentNullException(nameof(item)); } - var outdated = forceUpdate ? item.ImageInfos.Where(i => i.Path != null).ToArray() : item.ImageInfos.Where(ImageNeedsRefresh).ToArray(); + var outdated = forceUpdate + ? item.ImageInfos.Where(i => i.Path != null).ToArray() + : item.ImageInfos.Where(ImageNeedsRefresh).ToArray(); // Skip image processing if current or live tv source if (outdated.Length == 0 || item.SourceType != SourceType.Library) { @@ -1883,7 +1885,7 @@ namespace Emby.Server.Implementations.Library _logger.LogWarning("Cannot get image index for {ImagePath}", img.Path); continue; } - catch (Exception ex) when (ex is InvalidOperationException || ex is IOException) + catch (Exception ex) when (ex is InvalidOperationException or IOException) { _logger.LogWarning(ex, "Cannot fetch image from {ImagePath}", img.Path); continue; @@ -1895,23 +1897,24 @@ namespace Emby.Server.Implementations.Library } } + ImageDimensions size; try { - ImageDimensions size = _imageProcessor.GetImageDimensions(item, image); + size = _imageProcessor.GetImageDimensions(item, image); image.Width = size.Width; image.Height = size.Height; } catch (Exception ex) { _logger.LogError(ex, "Cannot get image dimensions for {ImagePath}", image.Path); + size = new ImageDimensions(0, 0); image.Width = 0; image.Height = 0; - continue; } try { - image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path); + image.BlurHash = _imageProcessor.GetImageBlurHash(image.Path, size); } catch (Exception ex) { diff --git a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj index 495c5b8601..4de4b231d6 100644 --- a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj +++ b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj @@ -20,6 +20,7 @@ + diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs index 2358fe6238..6875282318 100644 --- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -10,7 +10,7 @@ using MediaBrowser.Controller.Drawing; using MediaBrowser.Model.Drawing; using Microsoft.Extensions.Logging; using SkiaSharp; -using static Jellyfin.Drawing.Skia.SkiaHelper; +using SKSvg = SkiaSharp.Extended.Svg.SKSvg; namespace Jellyfin.Drawing.Skia { @@ -19,8 +19,7 @@ namespace Jellyfin.Drawing.Skia /// public class SkiaEncoder : IImageEncoder { - private static readonly HashSet _transparentImageTypes - = new HashSet(StringComparer.OrdinalIgnoreCase) { ".png", ".gif", ".webp" }; + private static readonly HashSet _transparentImageTypes = new(StringComparer.OrdinalIgnoreCase) { ".png", ".gif", ".webp" }; private readonly ILogger _logger; private readonly IApplicationPaths _appPaths; @@ -71,7 +70,7 @@ namespace Jellyfin.Drawing.Skia /// public IReadOnlyCollection SupportedOutputFormats - => new HashSet() { ImageFormat.Webp, ImageFormat.Jpg, ImageFormat.Png }; + => new HashSet { ImageFormat.Webp, ImageFormat.Jpg, ImageFormat.Png }; /// /// Check if the native lib is available. @@ -109,9 +108,7 @@ namespace Jellyfin.Drawing.Skia } /// - /// The path is null. /// The path is not valid. - /// The file at the specified path could not be used to generate a codec. public ImageDimensions GetImageSize(string path) { if (!File.Exists(path)) @@ -119,12 +116,27 @@ namespace Jellyfin.Drawing.Skia throw new FileNotFoundException("File not found", path); } - using var codec = SKCodec.Create(path, out SKCodecResult result); - EnsureSuccess(result); - - var info = codec.Info; + var extension = Path.GetExtension(path.AsSpan()); + if (extension.Equals(".svg", StringComparison.OrdinalIgnoreCase)) + { + var svg = new SKSvg(); + svg.Load(path); + return new ImageDimensions(Convert.ToInt32(svg.Picture.CullRect.Width), Convert.ToInt32(svg.Picture.CullRect.Height)); + } - return new ImageDimensions(info.Width, info.Height); + using var codec = SKCodec.Create(path, out SKCodecResult result); + switch (result) + { + case SKCodecResult.Success: + var info = codec.Info; + return new ImageDimensions(info.Width, info.Height); + case SKCodecResult.Unimplemented: + _logger.LogDebug("Image format not supported: {FilePath}", path); + return new ImageDimensions(0, 0); + default: + _logger.LogError("Unable to determine image dimensions for {FilePath}: {SkCodecResult}", path, result); + return new ImageDimensions(0, 0); + } } /// @@ -138,6 +150,13 @@ namespace Jellyfin.Drawing.Skia throw new ArgumentNullException(nameof(path)); } + var extension = Path.GetExtension(path.AsSpan()).TrimStart('.'); + if (!SupportedInputFormats.Contains(extension, StringComparison.OrdinalIgnoreCase)) + { + _logger.LogDebug("Unable to compute blur hash due to unsupported format: {ImagePath}", path); + return string.Empty; + } + // Any larger than 128x128 is too slow and there's no visually discernible difference return BlurHashEncoder.Encode(xComp, yComp, path, 128, 128); } @@ -378,6 +397,13 @@ namespace Jellyfin.Drawing.Skia throw new ArgumentException("String can't be empty.", nameof(outputPath)); } + var inputFormat = Path.GetExtension(inputPath.AsSpan()).TrimStart('.'); + if (!SupportedInputFormats.Contains(inputFormat, StringComparison.OrdinalIgnoreCase)) + { + _logger.LogDebug("Unable to encode image due to unsupported format: {ImagePath}", inputPath); + return inputPath; + } + var skiaOutputFormat = GetImageFormat(outputFormat); var hasBackgroundColor = !string.IsNullOrWhiteSpace(options.BackgroundColor); diff --git a/Jellyfin.Drawing.Skia/SkiaHelper.cs b/Jellyfin.Drawing.Skia/SkiaHelper.cs index 35dcebdaba..c001c32b8c 100644 --- a/Jellyfin.Drawing.Skia/SkiaHelper.cs +++ b/Jellyfin.Drawing.Skia/SkiaHelper.cs @@ -8,19 +8,6 @@ namespace Jellyfin.Drawing.Skia /// public static class SkiaHelper { - /// - /// Ensures the result is a success - /// by throwing an exception when that's not the case. - /// - /// The result returned by Skia. - public static void EnsureSuccess(SKCodecResult result) - { - if (result != SKCodecResult.Success) - { - throw new SkiaCodecException(result); - } - } - /// /// Gets the next valid image as a bitmap. /// diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index 03882a0b97..e5ce0aa210 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -50,6 +50,14 @@ namespace MediaBrowser.Controller.Drawing /// BlurHash. string GetImageBlurHash(string path); + /// + /// Gets the blurhash of the image. + /// + /// Path to the image file. + /// The image dimensions. + /// BlurHash. + string GetImageBlurHash(string path, ImageDimensions imageDimensions); + /// /// Gets the image cache tag. /// -- cgit v1.2.3 From 38102499cb21cae8cd177ebc6b98037b3bc3f620 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Fri, 17 Jun 2022 10:01:06 -0600 Subject: Merge pull request #7947 from nyanmisaka/video-range-condition (cherry picked from commit f1d56aa5cef4c60021e0b29c5d9fb3adf384fda7) Signed-off-by: Joshua Boniface --- Emby.Dlna/Didl/DidlBuilder.cs | 2 + Emby.Dlna/PlayTo/PlayToController.cs | 1 + Jellyfin.Api/Helpers/StreamingHelpers.cs | 3 +- .../MediaEncoding/BaseEncodingJobOptions.cs | 6 ++ .../MediaEncoding/EncodingHelper.cs | 14 +++++ .../MediaEncoding/EncodingJobInfo.cs | 42 +++++++++++++ MediaBrowser.Model/Dlna/ConditionProcessor.cs | 3 + MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs | 2 + MediaBrowser.Model/Dlna/DeviceProfile.cs | 4 +- MediaBrowser.Model/Dlna/ProfileConditionValue.cs | 3 +- MediaBrowser.Model/Dlna/StreamBuilder.cs | 45 ++++++++++++-- MediaBrowser.Model/Dlna/StreamInfo.cs | 23 +++++++ MediaBrowser.Model/Entities/MediaStream.cs | 71 +++++++++++++++------- MediaBrowser.Model/Session/TranscodeReason.cs | 1 + 14 files changed, 190 insertions(+), 30 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 6ab5843c15..df6539a5a6 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -221,6 +221,7 @@ namespace Emby.Dlna.Didl streamInfo.IsDirectStream, streamInfo.RunTimeTicks ?? 0, streamInfo.TargetVideoProfile, + streamInfo.TargetVideoRangeType, streamInfo.TargetVideoLevel, streamInfo.TargetFramerate ?? 0, streamInfo.TargetPacketLength, @@ -376,6 +377,7 @@ namespace Emby.Dlna.Didl targetHeight, streamInfo.TargetVideoBitDepth, streamInfo.TargetVideoProfile, + streamInfo.TargetVideoRangeType, streamInfo.TargetVideoLevel, streamInfo.TargetFramerate ?? 0, streamInfo.TargetPacketLength, diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index e27a8975b7..b73ce00b6f 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -561,6 +561,7 @@ namespace Emby.Dlna.PlayTo streamInfo.IsDirectStream, streamInfo.RunTimeTicks ?? 0, streamInfo.TargetVideoProfile, + streamInfo.TargetVideoRangeType, streamInfo.TargetVideoLevel, streamInfo.TargetFramerate ?? 0, streamInfo.TargetPacketLength, diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index 34dab75b82..c96ca87a56 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -312,7 +312,7 @@ namespace Jellyfin.Api.Helpers responseHeaders.Add( "contentFeatures.dlna.org", - ContentFeatureBuilder.BuildVideoHeader(profile, state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty); + ContentFeatureBuilder.BuildVideoHeader(profile, state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoRangeType, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty); } } @@ -533,6 +533,7 @@ namespace Jellyfin.Api.Helpers state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetVideoProfile, + state.TargetVideoRangeType, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, diff --git a/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs index 462585ce35..fb4e7bd1f5 100644 --- a/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs @@ -75,6 +75,12 @@ namespace MediaBrowser.Controller.MediaEncoding /// The profile. public string Profile { get; set; } + /// + /// Gets or sets the video range type. + /// + /// The video range type. + public string VideoRangeType { get; set; } + /// /// Gets or sets the level. /// diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 04778e6993..d5b0aca3c3 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1753,6 +1753,20 @@ namespace MediaBrowser.Controller.MediaEncoding } } + var requestedRangeTypes = state.GetRequestedRangeTypes(videoStream.Codec); + if (requestedProfiles.Length > 0) + { + if (string.IsNullOrEmpty(videoStream.VideoRangeType)) + { + return false; + } + + if (!requestedRangeTypes.Contains(videoStream.VideoRangeType, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + } + // Video width must fall within requested value if (request.MaxWidth.HasValue && (!videoStream.Width.HasValue || videoStream.Width.Value > request.MaxWidth.Value)) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 0824590f22..491662861f 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -366,6 +366,28 @@ namespace MediaBrowser.Controller.MediaEncoding } } + /// + /// Gets the target video range type. + /// + public string TargetVideoRangeType + { + get + { + if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec)) + { + return VideoStream?.VideoRangeType; + } + + var requestedRangeType = GetRequestedRangeTypes(ActualOutputVideoCodec).FirstOrDefault(); + if (!string.IsNullOrEmpty(requestedRangeType)) + { + return requestedRangeType; + } + + return null; + } + } + public string TargetVideoCodecTag { get @@ -579,6 +601,26 @@ namespace MediaBrowser.Controller.MediaEncoding return Array.Empty(); } + public string[] GetRequestedRangeTypes(string codec) + { + if (!string.IsNullOrEmpty(BaseRequest.VideoRangeType)) + { + return BaseRequest.VideoRangeType.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); + } + + if (!string.IsNullOrEmpty(codec)) + { + var rangetype = BaseRequest.GetOption(codec, "rangetype"); + + if (!string.IsNullOrEmpty(rangetype)) + { + return rangetype.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); + } + } + + return Array.Empty(); + } + public string GetRequestedLevel(string codec) { if (!string.IsNullOrEmpty(BaseRequest.Level)) diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs index 8d03b4c0b3..5734224167 100644 --- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs +++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs @@ -16,6 +16,7 @@ namespace MediaBrowser.Model.Dlna int? videoBitDepth, int? videoBitrate, string? videoProfile, + string? videoRangeType, double? videoLevel, float? videoFramerate, int? packetLength, @@ -42,6 +43,8 @@ namespace MediaBrowser.Model.Dlna return IsConditionSatisfied(condition, videoLevel); case ProfileConditionValue.VideoProfile: return IsConditionSatisfied(condition, videoProfile); + case ProfileConditionValue.VideoRangeType: + return IsConditionSatisfied(condition, videoRangeType); case ProfileConditionValue.VideoCodecTag: return IsConditionSatisfied(condition, videoCodecTag); case ProfileConditionValue.PacketLength: diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index 6e129246b0..47c36494bd 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -128,6 +128,7 @@ namespace MediaBrowser.Model.Dlna bool isDirectStream, long? runtimeTicks, string videoProfile, + string videoRangeType, double? videoLevel, float? videoFramerate, int? packetLength, @@ -176,6 +177,7 @@ namespace MediaBrowser.Model.Dlna bitDepth, videoBitrate, videoProfile, + videoRangeType, videoLevel, videoFramerate, packetLength, diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index 6170ff5bd6..79ae951708 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -423,6 +423,7 @@ namespace MediaBrowser.Model.Dlna /// The bit depth. /// The video bitrate. /// The video profile. + /// The video range type. /// The video level. /// The video framerate. /// The packet length. @@ -444,6 +445,7 @@ namespace MediaBrowser.Model.Dlna int? bitDepth, int? videoBitrate, string videoProfile, + string videoRangeType, double? videoLevel, float? videoFramerate, int? packetLength, @@ -483,7 +485,7 @@ namespace MediaBrowser.Model.Dlna var anyOff = false; foreach (ProfileCondition c in i.Conditions) { - if (!ConditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) + if (!ConditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)) { anyOff = true; break; diff --git a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs index eb81fde751..a32433e185 100644 --- a/MediaBrowser.Model/Dlna/ProfileConditionValue.cs +++ b/MediaBrowser.Model/Dlna/ProfileConditionValue.cs @@ -26,6 +26,7 @@ namespace MediaBrowser.Model.Dlna IsAvc = 20, IsInterlaced = 21, AudioSampleRate = 22, - AudioBitDepth = 23 + AudioBitDepth = 23, + VideoRangeType = 24 } } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index fe9ff2ebe8..fdb9fd5d54 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -221,6 +221,9 @@ namespace MediaBrowser.Model.Dlna case ProfileConditionValue.VideoProfile: return TranscodeReason.VideoProfileNotSupported; + case ProfileConditionValue.VideoRangeType: + return TranscodeReason.VideoRangeTypeNotSupported; + case ProfileConditionValue.VideoTimestamp: // TODO return 0; @@ -748,9 +751,9 @@ namespace MediaBrowser.Model.Dlna var appliedVideoConditions = options.Profile.CodecProfiles .Where(i => i.Type == CodecType.Video && i.ContainsAnyCodec(videoCodec, container) && - i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))) + i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.VideoRangeType, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))) .Select(i => - i.Conditions.All(condition => ConditionProcessor.IsVideoConditionSatisfied(condition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))); + i.Conditions.All(condition => ConditionProcessor.IsVideoConditionSatisfied(condition, videoStream?.Width, videoStream?.Height, videoStream?.BitDepth, videoStream?.BitRate, videoStream?.Profile, videoStream?.VideoRangeType, videoStream?.Level, videoFramerate, videoStream?.PacketLength, timestamp, videoStream?.IsAnamorphic, videoStream?.IsInterlaced, videoStream?.RefFrames, numVideoStreams, numAudioStreams, videoStream?.CodecTag, videoStream?.IsAVC))); // An empty appliedVideoConditions means that the codec has no conditions for the current video stream var conditionsSatisfied = appliedVideoConditions.All(satisfied => satisfied); @@ -834,6 +837,7 @@ namespace MediaBrowser.Model.Dlna int? videoBitrate = videoStream?.BitRate; double? videoLevel = videoStream?.Level; string videoProfile = videoStream?.Profile; + string videoRangeType = videoStream?.VideoRangeType; float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0; bool? isAnamorphic = videoStream?.IsAnamorphic; bool? isInterlaced = videoStream?.IsInterlaced; @@ -850,7 +854,7 @@ namespace MediaBrowser.Model.Dlna var appliedVideoConditions = options.Profile.CodecProfiles .Where(i => i.Type == CodecType.Video && i.ContainsAnyCodec(videoCodec, container) && - i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))); + i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))); var isFirstAppliedCodecProfile = true; foreach (var i in appliedVideoConditions) { @@ -1081,6 +1085,7 @@ namespace MediaBrowser.Model.Dlna int? videoBitrate = videoStream?.BitRate; double? videoLevel = videoStream?.Level; string videoProfile = videoStream?.Profile; + string videoRangeType = videoStream?.VideoRangeType; float videoFramerate = videoStream == null ? 0 : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate ?? 0; bool? isAnamorphic = videoStream?.IsAnamorphic; bool? isInterlaced = videoStream?.IsInterlaced; @@ -1098,7 +1103,7 @@ namespace MediaBrowser.Model.Dlna int? numVideoStreams = mediaSource.GetStreamCount(MediaStreamType.Video); var checkVideoConditions = (ProfileCondition[] conditions) => - conditions.Where(applyCondition => !ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)); + conditions.Where(applyCondition => !ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)); // Check container conditions var containerProfileReasons = AggregateFailureConditions( @@ -1852,6 +1857,38 @@ namespace MediaBrowser.Model.Dlna break; } + case ProfileConditionValue.VideoRangeType: + { + if (string.IsNullOrEmpty(qualifier)) + { + continue; + } + + // change from split by | to comma + // strip spaces to avoid having to encode + var values = value + .Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + + if (condition.Condition == ProfileConditionType.Equals) + { + item.SetOption(qualifier, "rangetype", string.Join(',', values)); + } + else if (condition.Condition == ProfileConditionType.EqualsAny) + { + var currentValue = item.GetOption(qualifier, "rangetype"); + if (!string.IsNullOrEmpty(currentValue) && values.Any(v => string.Equals(v, currentValue, StringComparison.OrdinalIgnoreCase))) + { + item.SetOption(qualifier, "rangetype", currentValue); + } + else + { + item.SetOption(qualifier, "rangetype", string.Join(',', values)); + } + } + + break; + } + case ProfileConditionValue.Height: { if (!enableNonQualifiedConditions) diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index da089602f1..0c66351c70 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -280,6 +280,29 @@ namespace MediaBrowser.Model.Dlna } } + /// + /// Gets the target video range type that will be in the output stream. + /// + public string TargetVideoRangeType + { + get + { + if (IsDirectStream) + { + return TargetVideoStream?.VideoRangeType; + } + + var targetVideoCodecs = TargetVideoCodec; + var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0]; + if (!string.IsNullOrEmpty(videoCodec)) + { + return GetOption(videoCodec, "rangetype"); + } + + return TargetVideoStream?.VideoRangeType; + } + } + /// /// Gets the target video codec tag. /// diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 96b48ca52a..48408e5847 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -104,32 +104,23 @@ namespace MediaBrowser.Model.Entities { get { - if (Type != MediaStreamType.Video) - { - return null; - } - - var colorTransfer = ColorTransfer; + var (videoRange, _) = GetVideoColorRange(); - if (string.Equals(colorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) - || string.Equals(colorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) - { - return "HDR"; - } - - // For some Dolby Vision files, no color transfer is provided, so check the codec - - var codecTag = CodecTag; + return videoRange; + } + } - if (string.Equals(codecTag, "dovi", StringComparison.OrdinalIgnoreCase) - || string.Equals(codecTag, "dvh1", StringComparison.OrdinalIgnoreCase) - || string.Equals(codecTag, "dvhe", StringComparison.OrdinalIgnoreCase) - || string.Equals(codecTag, "dav1", StringComparison.OrdinalIgnoreCase)) - { - return "HDR"; - } + /// + /// Gets the video range type. + /// + /// The video range type. + public string VideoRangeType + { + get + { + var (_, videoRangeType) = GetVideoColorRange(); - return "SDR"; + return videoRangeType; } } @@ -571,5 +562,39 @@ namespace MediaBrowser.Model.Entities return true; } + + public (string VideoRange, string VideoRangeType) GetVideoColorRange() + { + if (Type != MediaStreamType.Video) + { + return (null, null); + } + + var colorTransfer = ColorTransfer; + + if (string.Equals(colorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)) + { + return ("HDR", "HDR10"); + } + + if (string.Equals(colorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) + { + return ("HDR", "HLG"); + } + + // For some Dolby Vision files, no color transfer is provided, so check the codec + + var codecTag = CodecTag; + + if (string.Equals(codecTag, "dovi", StringComparison.OrdinalIgnoreCase) + || string.Equals(codecTag, "dvh1", StringComparison.OrdinalIgnoreCase) + || string.Equals(codecTag, "dvhe", StringComparison.OrdinalIgnoreCase) + || string.Equals(codecTag, "dav1", StringComparison.OrdinalIgnoreCase)) + { + return ("HDR", "DOVI"); + } + + return ("SDR", "SDR"); + } } } diff --git a/MediaBrowser.Model/Session/TranscodeReason.cs b/MediaBrowser.Model/Session/TranscodeReason.cs index 9da9f3323b..bbdf4536b7 100644 --- a/MediaBrowser.Model/Session/TranscodeReason.cs +++ b/MediaBrowser.Model/Session/TranscodeReason.cs @@ -17,6 +17,7 @@ namespace MediaBrowser.Model.Session // Video Constraints VideoProfileNotSupported = 1 << 6, + VideoRangeTypeNotSupported = 1 << 24, VideoLevelNotSupported = 1 << 7, VideoResolutionNotSupported = 1 << 8, VideoBitDepthNotSupported = 1 << 9, -- cgit v1.2.3 From a65397ae147d09703bfc2c5508e6e61b4c2998e3 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Fri, 17 Jun 2022 10:01:37 -0600 Subject: Merge pull request #7950 from nyanmisaka/brighter-vpp-tonemap (cherry picked from commit b36543275f8e1c380f5c247a04a48d5d96eb5836) Signed-off-by: Joshua Boniface --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 14 +++++++++++++- MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs | 1 + MediaBrowser.Model/Configuration/EncodingOptions.cs | 6 ++++++ 3 files changed, 20 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index d5b0aca3c3..2a5018c057 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -125,6 +125,7 @@ namespace MediaBrowser.Controller.MediaEncoding && _mediaEncoder.SupportsFilter("scale_vaapi") && _mediaEncoder.SupportsFilter("deinterlace_vaapi") && _mediaEncoder.SupportsFilter("tonemap_vaapi") + && _mediaEncoder.SupportsFilter("procamp_vaapi") && _mediaEncoder.SupportsFilterWithOption(FilterOptionType.OverlayVaapiFrameSync) && _mediaEncoder.SupportsFilter("hwupload_vaapi"); } @@ -2718,7 +2719,18 @@ namespace MediaBrowser.Controller.MediaEncoding var args = "tonemap_{0}=format={1}:p=bt709:t=bt709:m=bt709"; - if (!hwTonemapSuffix.Contains("vaapi", StringComparison.OrdinalIgnoreCase)) + if (hwTonemapSuffix.Contains("vaapi", StringComparison.OrdinalIgnoreCase)) + { + args += ",procamp_vaapi=b={2}:c={3}:extra_hw_frames=16"; + return string.Format( + CultureInfo.InvariantCulture, + args, + hwTonemapSuffix, + videoFormat ?? "nv12", + options.VppTonemappingBrightness, + options.VppTonemappingContrast); + } + else { args += ":tonemap={2}:peak={3}:desat={4}"; diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 20d372d7aa..d378c6e134 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -100,6 +100,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "scale_vaapi", "deinterlace_vaapi", "tonemap_vaapi", + "procamp_vaapi", "overlay_vaapi", "hwupload_vaapi" }; diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index fce0b6d6f6..73ebfba70e 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -26,6 +26,8 @@ namespace MediaBrowser.Model.Configuration TonemappingThreshold = 0.8; TonemappingPeak = 100; TonemappingParam = 0; + VppTonemappingBrightness = 0; + VppTonemappingContrast = 1.2; H264Crf = 23; H265Crf = 28; DeinterlaceDoubleRate = false; @@ -89,6 +91,10 @@ namespace MediaBrowser.Model.Configuration public double TonemappingParam { get; set; } + public double VppTonemappingBrightness { get; set; } + + public double VppTonemappingContrast { get; set; } + public int H264Crf { get; set; } public int H265Crf { get; set; } -- cgit v1.2.3 From a99e87a00c7dde41e03856c23fc48dcb18b7141e Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Fri, 17 Jun 2022 10:01:20 -0600 Subject: Merge pull request #7954 from cvium/fix_7953_dlna_url (cherry picked from commit 2c0c3eb3ee6eabdf1d2c94619f094f711870f820) Signed-off-by: Joshua Boniface --- Emby.Dlna/Main/DlnaEntryPoint.cs | 2 +- Emby.Server.Implementations/ApplicationHost.cs | 12 +++++++----- MediaBrowser.Controller/IServerApplicationHost.cs | 4 +++- 3 files changed, 11 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index 2a535d5565..15021c19d6 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -313,7 +313,7 @@ namespace Emby.Dlna.Main _logger.LogInformation("Registering publisher for {ResourceName} on {DeviceAddress}", fullService, address); - var uri = new UriBuilder(_appHost.GetApiUrlForLocalAccess(false) + descriptorUri); + var uri = new UriBuilder(_appHost.GetApiUrlForLocalAccess(address, false) + descriptorUri); var device = new SsdpRootDevice { diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 82294644b8..32289625fe 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1114,13 +1114,13 @@ namespace Emby.Server.Implementations } /// - public string GetApiUrlForLocalAccess(bool allowHttps = true) + public string GetApiUrlForLocalAccess(IPObject hostname = null, bool allowHttps = true) { // With an empty source, the port will be null - string smart = NetManager.GetBindInterface(string.Empty, out _); + var smart = NetManager.GetBindInterface(hostname ?? IPHost.None, out _); var scheme = !allowHttps ? Uri.UriSchemeHttp : null; int? port = !allowHttps ? HttpPort : null; - return GetLocalApiUrl(smart.Trim('/'), scheme, port); + return GetLocalApiUrl(smart, scheme, port); } /// @@ -1134,11 +1134,13 @@ namespace Emby.Server.Implementations // NOTE: If no BaseUrl is set then UriBuilder appends a trailing slash, but if there is no BaseUrl it does // not. For consistency, always trim the trailing slash. + scheme ??= ListenWithHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp; + var isHttps = string.Equals(scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase); return new UriBuilder { - Scheme = scheme ?? (ListenWithHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp), + Scheme = scheme, Host = hostname, - Port = port ?? (ListenWithHttps ? HttpsPort : HttpPort), + Port = port ?? (isHttps ? HttpsPort : HttpPort), Path = ConfigurationManager.GetNetworkConfiguration().BaseUrl }.ToString().TrimEnd('/'); } diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 75ec5f213f..11afdc4aed 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -4,6 +4,7 @@ using System.Net; using MediaBrowser.Common; +using MediaBrowser.Common.Net; using MediaBrowser.Model.System; using Microsoft.AspNetCore.Http; @@ -74,9 +75,10 @@ namespace MediaBrowser.Controller /// /// Gets an URL that can be used to access the API over LAN. /// + /// An optional hostname to use. /// A value indicating whether to allow HTTPS. /// The API URL. - string GetApiUrlForLocalAccess(bool allowHttps = true); + string GetApiUrlForLocalAccess(IPObject hostname = null, bool allowHttps = true); /// /// Gets a local (LAN) URL that can be used to access the API. -- cgit v1.2.3 From fe32b5e33353e6154e067c5fb196a36cdecc0cea Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 26 Jun 2022 20:55:36 -0400 Subject: Merge pull request #7964 from jellyfin/dovi-side-data (cherry picked from commit 39d185c7b19ed2da1ae46566152fb1cf182266cd) Signed-off-by: Joshua Boniface --- .../Data/SqliteItemRepository.cs | 70 +++++++++++++- .../MediaEncoding/EncodingHelper.cs | 20 ++-- .../Probing/MediaStreamInfo.cs | 7 ++ .../Probing/MediaStreamInfoSideData.cs | 74 +++++++++++++++ .../Probing/ProbeResultNormalizer.cs | 21 +++++ MediaBrowser.Model/Entities/MediaStream.cs | 101 ++++++++++++++++++++- .../Probing/ProbeResultNormalizerTests.cs | 8 ++ .../Test Data/Probing/video_metadata.json | 15 ++- 8 files changed, 301 insertions(+), 15 deletions(-) create mode 100644 MediaBrowser.MediaEncoding/Probing/MediaStreamInfoSideData.cs (limited to 'MediaBrowser.Controller') diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 964a630b26..4361440d75 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -170,7 +170,15 @@ namespace Emby.Server.Implementations.Data "CodecTimeBase", "ColorPrimaries", "ColorSpace", - "ColorTransfer" + "ColorTransfer", + "DvVersionMajor", + "DvVersionMinor", + "DvProfile", + "DvLevel", + "RpuPresentFlag", + "ElPresentFlag", + "BlPresentFlag", + "DvBlSignalCompatibilityId" }; private static readonly string _mediaStreamSaveColumnsInsertQuery = @@ -341,7 +349,7 @@ namespace Emby.Server.Implementations.Data public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager) { const string CreateMediaStreamsTableCommand - = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, TimeBase TEXT NULL, CodecTimeBase TEXT NULL, ColorPrimaries TEXT NULL, ColorSpace TEXT NULL, ColorTransfer TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))"; + = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, TimeBase TEXT NULL, CodecTimeBase TEXT NULL, ColorPrimaries TEXT NULL, ColorSpace TEXT NULL, ColorTransfer TEXT NULL, DvVersionMajor INT NULL, DvVersionMinor INT NULL, DvProfile INT NULL, DvLevel INT NULL, RpuPresentFlag INT NULL, ElPresentFlag INT NULL, BlPresentFlag INT NULL, DvBlSignalCompatibilityId INT NULL, PRIMARY KEY (ItemId, StreamIndex))"; const string CreateMediaAttachmentsTableCommand = "create table if not exists mediaattachments (ItemId GUID, AttachmentIndex INT, Codec TEXT, CodecTag TEXT NULL, Comment TEXT NULL, Filename TEXT NULL, MIMEType TEXT NULL, PRIMARY KEY (ItemId, AttachmentIndex))"; @@ -555,6 +563,15 @@ namespace Emby.Server.Implementations.Data AddColumn(db, "MediaStreams", "ColorPrimaries", "TEXT", existingColumnNames); AddColumn(db, "MediaStreams", "ColorSpace", "TEXT", existingColumnNames); AddColumn(db, "MediaStreams", "ColorTransfer", "TEXT", existingColumnNames); + + AddColumn(db, "MediaStreams", "DvVersionMajor", "INT", existingColumnNames); + AddColumn(db, "MediaStreams", "DvVersionMinor", "INT", existingColumnNames); + AddColumn(db, "MediaStreams", "DvProfile", "INT", existingColumnNames); + AddColumn(db, "MediaStreams", "DvLevel", "INT", existingColumnNames); + AddColumn(db, "MediaStreams", "RpuPresentFlag", "INT", existingColumnNames); + AddColumn(db, "MediaStreams", "ElPresentFlag", "INT", existingColumnNames); + AddColumn(db, "MediaStreams", "BlPresentFlag", "INT", existingColumnNames); + AddColumn(db, "MediaStreams", "DvBlSignalCompatibilityId", "INT", existingColumnNames); }, TransactionMode); @@ -5859,6 +5876,15 @@ AND Type = @InternalPersonType)"); statement.TryBind("@ColorPrimaries" + index, stream.ColorPrimaries); statement.TryBind("@ColorSpace" + index, stream.ColorSpace); statement.TryBind("@ColorTransfer" + index, stream.ColorTransfer); + + statement.TryBind("@DvVersionMajor" + index, stream.DvVersionMajor); + statement.TryBind("@DvVersionMinor" + index, stream.DvVersionMinor); + statement.TryBind("@DvProfile" + index, stream.DvProfile); + statement.TryBind("@DvLevel" + index, stream.DvLevel); + statement.TryBind("@RpuPresentFlag" + index, stream.RpuPresentFlag); + statement.TryBind("@ElPresentFlag" + index, stream.ElPresentFlag); + statement.TryBind("@BlPresentFlag" + index, stream.BlPresentFlag); + statement.TryBind("@DvBlSignalCompatibilityId" + index, stream.DvBlSignalCompatibilityId); } statement.Reset(); @@ -6030,6 +6056,46 @@ AND Type = @InternalPersonType)"); item.ColorTransfer = colorTransfer; } + if (reader.TryGetInt32(35, out var dvVersionMajor)) + { + item.DvVersionMajor = dvVersionMajor; + } + + if (reader.TryGetInt32(36, out var dvVersionMinor)) + { + item.DvVersionMinor = dvVersionMinor; + } + + if (reader.TryGetInt32(37, out var dvProfile)) + { + item.DvProfile = dvProfile; + } + + if (reader.TryGetInt32(38, out var dvLevel)) + { + item.DvLevel = dvLevel; + } + + if (reader.TryGetInt32(39, out var rpuPresentFlag)) + { + item.RpuPresentFlag = rpuPresentFlag; + } + + if (reader.TryGetInt32(40, out var elPresentFlag)) + { + item.ElPresentFlag = elPresentFlag; + } + + if (reader.TryGetInt32(41, out var blPresentFlag)) + { + item.BlPresentFlag = blPresentFlag; + } + + if (reader.TryGetInt32(42, out var dvBlSignalCompatibilityId)) + { + item.DvBlSignalCompatibilityId = dvBlSignalCompatibilityId; + } + if (item.Type == MediaStreamType.Subtitle) { item.LocalizedUndefined = _localization.GetLocalizedString("Undefined"); diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 2a5018c057..f795bf2aa8 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -157,9 +157,9 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - if (string.Equals(state.VideoStream.CodecTag, "dovi", StringComparison.OrdinalIgnoreCase) - || string.Equals(state.VideoStream.CodecTag, "dvh1", StringComparison.OrdinalIgnoreCase) - || string.Equals(state.VideoStream.CodecTag, "dvhe", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(state.VideoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) + && string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) + && string.Equals(state.VideoStream.VideoRangeType, "DOVI", StringComparison.OrdinalIgnoreCase)) { // Only native SW decoder and HW accelerator can parse dovi rpu. var vidDecoder = GetHardwareVideoDecoder(state, options) ?? string.Empty; @@ -170,22 +170,24 @@ namespace MediaBrowser.Controller.MediaEncoding return isSwDecoder || isNvdecDecoder || isVaapiDecoder || isD3d11vaDecoder; } - return string.Equals(state.VideoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) - || string.Equals(state.VideoStream.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase); + return string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) + && (string.Equals(state.VideoStream.VideoRangeType, "HDR10", StringComparison.OrdinalIgnoreCase) + || string.Equals(state.VideoStream.VideoRangeType, "HLG", StringComparison.OrdinalIgnoreCase)); } private bool IsVaapiVppTonemapAvailable(EncodingJobInfo state, EncodingOptions options) { - if (state.VideoStream == null) + if (state.VideoStream == null + || !options.EnableVppTonemapping + || GetVideoColorBitDepth(state) != 10) { return false; } // Native VPP tonemapping may come to QSV in the future. - return options.EnableVppTonemapping - && string.Equals(state.VideoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) - && GetVideoColorBitDepth(state) == 10; + return string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) + && string.Equals(state.VideoStream.VideoRangeType, "HDR10", StringComparison.OrdinalIgnoreCase); } /// diff --git a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs index c9c8c34c2e..eab8f79bb3 100644 --- a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs +++ b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs @@ -310,5 +310,12 @@ namespace MediaBrowser.MediaEncoding.Probing /// The color primaries. [JsonPropertyName("color_primaries")] public string ColorPrimaries { get; set; } + + /// + /// Gets or sets the side_data_list. + /// + /// The side_data_list. + [JsonPropertyName("side_data_list")] + public IReadOnlyList SideDataList { get; set; } } } diff --git a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfoSideData.cs b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfoSideData.cs new file mode 100644 index 0000000000..095757bef7 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfoSideData.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace MediaBrowser.MediaEncoding.Probing +{ + /// + /// Class MediaStreamInfoSideData. + /// + public class MediaStreamInfoSideData + { + /// + /// Gets or sets the SideDataType. + /// + /// The SideDataType. + [JsonPropertyName("side_data_type")] + public string? SideDataType { get; set; } + + /// + /// Gets or sets the DvVersionMajor. + /// + /// The DvVersionMajor. + [JsonPropertyName("dv_version_major")] + public int? DvVersionMajor { get; set; } + + /// + /// Gets or sets the DvVersionMinor. + /// + /// The DvVersionMinor. + [JsonPropertyName("dv_version_minor")] + public int? DvVersionMinor { get; set; } + + /// + /// Gets or sets the DvProfile. + /// + /// The DvProfile. + [JsonPropertyName("dv_profile")] + public int? DvProfile { get; set; } + + /// + /// Gets or sets the DvLevel. + /// + /// The DvLevel. + [JsonPropertyName("dv_level")] + public int? DvLevel { get; set; } + + /// + /// Gets or sets the RpuPresentFlag. + /// + /// The RpuPresentFlag. + [JsonPropertyName("rpu_present_flag")] + public int? RpuPresentFlag { get; set; } + + /// + /// Gets or sets the ElPresentFlag. + /// + /// The ElPresentFlag. + [JsonPropertyName("el_present_flag")] + public int? ElPresentFlag { get; set; } + + /// + /// Gets or sets the BlPresentFlag. + /// + /// The BlPresentFlag. + [JsonPropertyName("bl_present_flag")] + public int? BlPresentFlag { get; set; } + + /// + /// Gets or sets the DvBlSignalCompatibilityId. + /// + /// The DvBlSignalCompatibilityId. + [JsonPropertyName("dv_bl_signal_compatibility_id")] + public int? DvBlSignalCompatibilityId { get; set; } + } +} diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 3f78d0d42c..74d7341e91 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -841,6 +841,27 @@ namespace MediaBrowser.MediaEncoding.Probing { stream.ColorPrimaries = streamInfo.ColorPrimaries; } + + if (streamInfo.SideDataList != null) + { + foreach (var data in streamInfo.SideDataList) + { + // Parse Dolby Vision metadata from side_data + if (string.Equals(data.SideDataType, "DOVI configuration record", StringComparison.OrdinalIgnoreCase)) + { + stream.DvVersionMajor = data.DvVersionMajor; + stream.DvVersionMinor = data.DvVersionMinor; + stream.DvProfile = data.DvProfile; + stream.DvLevel = data.DvLevel; + stream.RpuPresentFlag = data.RpuPresentFlag; + stream.ElPresentFlag = data.ElPresentFlag; + stream.BlPresentFlag = data.BlPresentFlag; + stream.DvBlSignalCompatibilityId = data.DvBlSignalCompatibilityId; + + break; + } + } + } } else { diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 48408e5847..58988b6fae 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -72,6 +72,54 @@ namespace MediaBrowser.Model.Entities /// The color primaries. public string ColorPrimaries { get; set; } + /// + /// Gets or sets the Dolby Vision version major. + /// + /// The Dolby Vision version major. + public int? DvVersionMajor { get; set; } + + /// + /// Gets or sets the Dolby Vision version minor. + /// + /// The Dolby Vision version minor. + public int? DvVersionMinor { get; set; } + + /// + /// Gets or sets the Dolby Vision profile. + /// + /// The Dolby Vision profile. + public int? DvProfile { get; set; } + + /// + /// Gets or sets the Dolby Vision level. + /// + /// The Dolby Vision level. + public int? DvLevel { get; set; } + + /// + /// Gets or sets the Dolby Vision rpu present flag. + /// + /// The Dolby Vision rpu present flag. + public int? RpuPresentFlag { get; set; } + + /// + /// Gets or sets the Dolby Vision el present flag. + /// + /// The Dolby Vision el present flag. + public int? ElPresentFlag { get; set; } + + /// + /// Gets or sets the Dolby Vision bl present flag. + /// + /// The Dolby Vision bl present flag. + public int? BlPresentFlag { get; set; } + + /// + /// Gets or sets the Dolby Vision bl signal compatibility id. + /// + /// The Dolby Vision bl signal compatibility id. + public int? DvBlSignalCompatibilityId { get; set; } + /// /// Gets or sets the comment. /// @@ -124,6 +172,47 @@ namespace MediaBrowser.Model.Entities } } + /// + /// Gets the video dovi title. + /// + /// The video dovi title. + public string VideoDoViTitle + { + get + { + var dvProfile = DvProfile; + var rpuPresentFlag = RpuPresentFlag == 1; + var blPresentFlag = BlPresentFlag == 1; + var dvBlCompatId = DvBlSignalCompatibilityId; + + if (rpuPresentFlag + && blPresentFlag + && (dvProfile == 4 + || dvProfile == 5 + || dvProfile == 7 + || dvProfile == 8 + || dvProfile == 9)) + { + var title = "DV Profile " + dvProfile; + + if (dvBlCompatId > 0) + { + title += "." + dvBlCompatId; + } + + return dvBlCompatId switch + { + 1 => title + " (HDR10)", + 2 => title + " (SDR)", + 4 => title + " (HLG)", + _ => title + }; + } + + return null; + } + } + public string LocalizedUndefined { get; set; } public string LocalizedDefault { get; set; } @@ -582,11 +671,17 @@ namespace MediaBrowser.Model.Entities return ("HDR", "HLG"); } - // For some Dolby Vision files, no color transfer is provided, so check the codec - var codecTag = CodecTag; + var dvProfile = DvProfile; + var rpuPresentFlag = RpuPresentFlag == 1; + var blPresentFlag = BlPresentFlag == 1; + var dvBlCompatId = DvBlSignalCompatibilityId; + + var isDoViHDRProfile = dvProfile == 5 || dvProfile == 7 || dvProfile == 8; + var isDoViHDRFlag = rpuPresentFlag && blPresentFlag && (dvBlCompatId == 0 || dvBlCompatId == 1 || dvBlCompatId == 4); - if (string.Equals(codecTag, "dovi", StringComparison.OrdinalIgnoreCase) + if ((isDoViHDRProfile && isDoViHDRFlag) + || string.Equals(codecTag, "dovi", StringComparison.OrdinalIgnoreCase) || string.Equals(codecTag, "dvh1", StringComparison.OrdinalIgnoreCase) || string.Equals(codecTag, "dvhe", StringComparison.OrdinalIgnoreCase) || string.Equals(codecTag, "dav1", StringComparison.OrdinalIgnoreCase)) diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs index 53e1550ed1..13cfe885f8 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs @@ -75,6 +75,14 @@ namespace Jellyfin.MediaEncoding.Tests.Probing Assert.Equal(1, res.VideoStream.RefFrames); Assert.Equal("1/1000", res.VideoStream.TimeBase); Assert.Equal(MediaStreamType.Video, res.VideoStream.Type); + Assert.Equal(1, res.VideoStream.DvVersionMajor); + Assert.Equal(0, res.VideoStream.DvVersionMinor); + Assert.Equal(5, res.VideoStream.DvProfile); + Assert.Equal(6, res.VideoStream.DvLevel); + Assert.Equal(1, res.VideoStream.RpuPresentFlag); + Assert.Equal(0, res.VideoStream.ElPresentFlag); + Assert.Equal(1, res.VideoStream.BlPresentFlag); + Assert.Equal(0, res.VideoStream.DvBlSignalCompatibilityId); Assert.Empty(res.Chapters); Assert.Equal("Just color bars", res.Overview); diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_metadata.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_metadata.json index 720fc5c8fa..519d81179c 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_metadata.json +++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_metadata.json @@ -47,7 +47,20 @@ "tags": { "ENCODER": "Lavc57.107.100 libx264", "DURATION": "00:00:01.000000000" - } + }, + "side_data_list": [ + { + "side_data_type": "DOVI configuration record", + "dv_version_major": 1, + "dv_version_minor": 0, + "dv_profile": 5, + "dv_level": 6, + "rpu_present_flag": 1, + "el_present_flag": 0, + "bl_present_flag": 1, + "dv_bl_signal_compatibility_id": 0 + } + ] } ], "chapters": [ -- cgit v1.2.3 From 074d7dc6b6d38bb808e4daceec35da617aa1a174 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Thu, 23 Jun 2022 15:32:35 +0200 Subject: Merge pull request #7968 from jellyfin/fix-hwa-bluray (cherry picked from commit 5f15339919ebf5db0a9a05c4c98a955e5ca1f4b7) Signed-off-by: Joshua Boniface --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index f795bf2aa8..50ffcee116 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -4319,14 +4319,18 @@ namespace MediaBrowser.Controller.MediaEncoding protected string GetHardwareVideoDecoder(EncodingJobInfo state, EncodingOptions options) { var videoStream = state.VideoStream; - if (videoStream == null) + var mediaSource = state.MediaSource; + if (videoStream == null || mediaSource == null) { return null; } - // Only use alternative encoders for video files. - var videoType = state.MediaSource.VideoType ?? VideoType.VideoFile; - if (videoType != VideoType.VideoFile) + // HWA decoders can handle both video files and video folders. + var videoType = mediaSource.VideoType; + if (videoType != VideoType.VideoFile + && videoType != VideoType.Iso + && videoType != VideoType.Dvd + && videoType != VideoType.BluRay) { return null; } -- cgit v1.2.3 From 7dab8b8f88d413fcb7833b7bdf47f17844b33271 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Thu, 23 Jun 2022 15:33:14 +0200 Subject: Merge pull request #7975 from jellyfin/libva-driver-env (cherry picked from commit 910df89ccefd3f9ddef4a189715f90dcb4191e7f) Signed-off-by: Joshua Boniface --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 50ffcee116..2b33ed5a16 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -716,6 +716,9 @@ namespace MediaBrowser.Controller.MediaEncoding } 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(null, "i965", null, VaapiAlias)); } else -- cgit v1.2.3 From 9c97c533eff94d25463fb649c9572234da4af1ea Mon Sep 17 00:00:00 2001 From: "Joshua M. Boniface" Date: Sun, 26 Jun 2022 20:53:03 -0400 Subject: Merge pull request #7994 from nyanmisaka/fix-throttler (cherry picked from commit a7d45b5d3aa5b16b0aeeece690396f91fb7b7e3e) Signed-off-by: Joshua Boniface --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 4 ++-- Jellyfin.Api/Controllers/VideosController.cs | 2 +- Jellyfin.Api/Helpers/TranscodingJobHelper.cs | 21 +++++++-------------- Jellyfin.Api/Models/StreamingDtos/StreamState.cs | 8 -------- MediaBrowser.Controller/MediaEncoding/JobLogger.cs | 2 +- 5 files changed, 11 insertions(+), 26 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 8127193c20..365e44e1a3 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -285,7 +285,7 @@ namespace Jellyfin.Api.Controllers // Due to CTS.Token calling ThrowIfDisposed (https://github.com/dotnet/runtime/issues/29970) we have to "cache" the token // since it gets disposed when ffmpeg exits var cancellationToken = cancellationTokenSource.Token; - using var state = await StreamingHelpers.GetStreamingState( + var state = await StreamingHelpers.GetStreamingState( streamingRequest, Request, _authContext, @@ -1432,7 +1432,7 @@ namespace Jellyfin.Api.Controllers var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; - using var state = await StreamingHelpers.GetStreamingState( + var state = await StreamingHelpers.GetStreamingState( streamingRequest, Request, _authContext, diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 62c05331ed..4e28959345 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -427,7 +427,7 @@ namespace Jellyfin.Api.Controllers StreamOptions = streamOptions }; - using var state = await StreamingHelpers.GetStreamingState( + var state = await StreamingHelpers.GetStreamingState( streamingRequest, Request, _authContext, diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index 416418dc68..13dc878c1b 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -654,8 +654,8 @@ namespace Jellyfin.Api.Helpers { if (EnableThrottling(state)) { - transcodingJob.TranscodingThrottler = state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, new Logger(new LoggerFactory()), _serverConfigurationManager, _fileSystem); - state.TranscodingThrottler.Start(); + transcodingJob.TranscodingThrottler = new TranscodingThrottler(transcodingJob, new Logger(new LoggerFactory()), _serverConfigurationManager, _fileSystem); + transcodingJob.TranscodingThrottler.Start(); } } @@ -663,18 +663,11 @@ namespace Jellyfin.Api.Helpers { var encodingOptions = _serverConfigurationManager.GetEncodingOptions(); - // enable throttling when NOT using hardware acceleration - if (string.IsNullOrEmpty(encodingOptions.HardwareAccelerationType)) - { - return state.InputProtocol == MediaProtocol.File && - state.RunTimeTicks.HasValue && - state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && - state.IsInputVideo && - state.VideoType == VideoType.VideoFile && - !EncodingHelper.IsCopyCodec(state.OutputVideoCodec); - } - - return false; + return state.InputProtocol == MediaProtocol.File && + state.RunTimeTicks.HasValue && + state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && + state.IsInputVideo && + state.VideoType == VideoType.VideoFile; } /// diff --git a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs index cbabf087bc..192f33ebd1 100644 --- a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs +++ b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs @@ -47,11 +47,6 @@ namespace Jellyfin.Api.Models.StreamingDtos } } - /// - /// Gets or sets the transcoding throttler. - /// - public TranscodingThrottler? TranscodingThrottler { get; set; } - /// /// Gets the video request. /// @@ -191,11 +186,8 @@ namespace Jellyfin.Api.Models.StreamingDtos { _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).GetAwaiter().GetResult(); } - - TranscodingThrottler?.Dispose(); } - TranscodingThrottler = null; TranscodingJob = null; _disposed = true; diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs index 8b2837ee3c..d8475f12ae 100644 --- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs +++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs @@ -111,7 +111,7 @@ namespace MediaBrowser.Controller.MediaEncoding percent = 100.0 * currentMs / totalMs; - transcodingPosition = val; + transcodingPosition = TimeSpan.FromMilliseconds(currentMs); } } else if (part.StartsWith("size=", StringComparison.OrdinalIgnoreCase)) -- cgit v1.2.3 From 3e2fbb2685ab41827e6a34dd85162b2fe9bd5b67 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Fri, 24 Jun 2022 14:49:27 +0200 Subject: Merge pull request #8001 from jellyfin/fix-yuvj420p-hwdec Fix yuvj420p pixel format hardware decoding (cherry picked from commit d342b79218b06c2f2cd51bc1ddd08b7fc377c62c) Signed-off-by: Joshua Boniface --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 2b33ed5a16..6fb5c88740 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -4290,6 +4290,7 @@ namespace MediaBrowser.Controller.MediaEncoding return videoStream.BitDepth.Value; } else if (string.Equals(videoStream.PixelFormat, "yuv420p", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoStream.PixelFormat, "yuvj420p", StringComparison.OrdinalIgnoreCase) || string.Equals(videoStream.PixelFormat, "yuv444p", StringComparison.OrdinalIgnoreCase)) { return 8; @@ -4580,7 +4581,8 @@ namespace MediaBrowser.Controller.MediaEncoding var hwSurface = (isIntelDx11OclSupported || isIntelVaapiOclSupported) && _mediaEncoder.SupportsFilter("alphasrc"); - var is8bitSwFormatsQsv = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); + var is8bitSwFormatsQsv = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase) + || string.Equals("yuvj420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); var is8_10bitSwFormatsQsv = is8bitSwFormatsQsv || string.Equals("yuv420p10le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); // TODO: add more 8/10bit and 4:4:4 formats for Qsv after finishing the ffcheck tool @@ -4639,7 +4641,8 @@ namespace MediaBrowser.Controller.MediaEncoding } var hwSurface = IsCudaFullSupported() && _mediaEncoder.SupportsFilter("alphasrc"); - var is8bitSwFormatsNvdec = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); + var is8bitSwFormatsNvdec = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase) + || string.Equals("yuvj420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); var is8_10bitSwFormatsNvdec = is8bitSwFormatsNvdec || string.Equals("yuv420p10le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); // TODO: add more 8/10/12bit and 4:4:4 formats for Nvdec after finishing the ffcheck tool @@ -4705,7 +4708,8 @@ namespace MediaBrowser.Controller.MediaEncoding var hwSurface = _mediaEncoder.SupportsHwaccel("d3d11va") && IsOpenclFullSupported() && _mediaEncoder.SupportsFilter("alphasrc"); - var is8bitSwFormatsAmf = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); + var is8bitSwFormatsAmf = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase) + || string.Equals("yuvj420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); var is8_10bitSwFormatsAmf = is8bitSwFormatsAmf || string.Equals("yuv420p10le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); if (is8bitSwFormatsAmf) @@ -4761,7 +4765,8 @@ namespace MediaBrowser.Controller.MediaEncoding && IsVaapiFullSupported() && IsOpenclFullSupported() && _mediaEncoder.SupportsFilter("alphasrc"); - var is8bitSwFormatsVaapi = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); + var is8bitSwFormatsVaapi = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase) + || string.Equals("yuvj420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); var is8_10bitSwFormatsVaapi = is8bitSwFormatsVaapi || string.Equals("yuv420p10le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); if (is8bitSwFormatsVaapi) @@ -4818,7 +4823,8 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } - var is8bitSwFormatsVt = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); + var is8bitSwFormatsVt = string.Equals("yuv420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase) + || string.Equals("yuvj420p", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); var is8_10bitSwFormatsVt = is8bitSwFormatsVt || string.Equals("yuv420p10le", videoStream.PixelFormat, StringComparison.OrdinalIgnoreCase); if (is8bitSwFormatsVt) -- cgit v1.2.3