Improve dynamic HDR metadata handling (#13277)

* Add support for bitstream filter to remove dynamic hdr metadata

* Add support for ffprobe's only_first_vframe for HDR10+ detection

* Add BitStreamFilterOptionType for metadata removal check

* Map HDR10+ metadata to VideoRangeType.cs

Current implementation uses a hack that abuses the EL flag to avoid database schema changes. Should add proper field once EFCore migration is merged.

* Add more Dolby Vision Range types

Out of spec ones are problematic and should be marked as a dedicated invalid type and handled by the server to not crash the player.

Profile 7 videos should not be treated as normal HDR10 videos at all and should remove the metadata before serving.

* Remove dynamic hdr metadata when necessary

* Allow direct playback of HDR10+ videos on HDR10 clients

* Only use dovi codec tag when dovi metadata is not removed

* Handle DV Profile 7 Videos better

* Fix HDR10+ with new bitmask

* Indicate the presence of HDR10+ in HLS SUPPLEMENTAL-CODECS

* Fix Dovi 8.4 not labeled as HLG in HLS

* Fallback to dovi_rpu bsf for av1 when possible

* Fix dovi_rpu cli for av1

* Use correct EFCore db column for HDR10+

* Undo outdated migration

* Add proper hdr10+ migration

* Remove outdated migration

* Rebase to new db code

* Add migrations for Hdr10PlusPresentFlag

* Directly use bsf enum

* Add xmldocs for SupportsBitStreamFilterWithOption

* Make `VideoRangeType.Unknown` explicitly default on api models.

* Unset default for non-api model class

* Use tuples for bsf dictionary for now
This commit is contained in:
gnattu
2025-04-03 08:06:02 +08:00
committed by GitHub
parent 9c7cf808aa
commit 49ac705867
21 changed files with 2328 additions and 67 deletions

View File

@@ -345,6 +345,15 @@ namespace MediaBrowser.Model.Dlna
return !condition.IsRequired;
}
// Special case: HDR10 also satisfies if the video is HDR10Plus
if (currentValue.Value == VideoRangeType.HDR10Plus)
{
if (IsConditionSatisfied(condition, VideoRangeType.HDR10))
{
return true;
}
}
var conditionType = condition.Condition;
if (conditionType == ProfileConditionType.EqualsAny)
{

View File

@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;

View File

@@ -153,6 +153,8 @@ namespace MediaBrowser.Model.Entities
/// <value>The title.</value>
public string Title { get; set; }
public bool? Hdr10PlusPresentFlag { get; set; }
/// <summary>
/// Gets the video range.
/// </summary>
@@ -172,6 +174,7 @@ namespace MediaBrowser.Model.Entities
/// Gets the video range type.
/// </summary>
/// <value>The video range type.</value>
[DefaultValue(VideoRangeType.Unknown)]
public VideoRangeType VideoRangeType
{
get
@@ -779,8 +782,8 @@ namespace MediaBrowser.Model.Entities
var blPresentFlag = BlPresentFlag == 1;
var dvBlCompatId = DvBlSignalCompatibilityId;
var isDoViProfile = dvProfile == 5 || dvProfile == 7 || dvProfile == 8 || dvProfile == 10;
var isDoViFlag = rpuPresentFlag && blPresentFlag && (dvBlCompatId == 0 || dvBlCompatId == 1 || dvBlCompatId == 4 || dvBlCompatId == 2 || dvBlCompatId == 6);
var isDoViProfile = dvProfile is 5 or 7 or 8 or 10;
var isDoViFlag = rpuPresentFlag && blPresentFlag && dvBlCompatId is 0 or 1 or 4 or 2 or 6;
if ((isDoViProfile && isDoViFlag)
|| string.Equals(codecTag, "dovi", StringComparison.OrdinalIgnoreCase)
@@ -788,7 +791,7 @@ namespace MediaBrowser.Model.Entities
|| string.Equals(codecTag, "dvhe", StringComparison.OrdinalIgnoreCase)
|| string.Equals(codecTag, "dav1", StringComparison.OrdinalIgnoreCase))
{
return dvProfile switch
var dvRangeSet = dvProfile switch
{
5 => (VideoRange.HDR, VideoRangeType.DOVI),
8 => dvBlCompatId switch
@@ -796,32 +799,40 @@ namespace MediaBrowser.Model.Entities
1 => (VideoRange.HDR, VideoRangeType.DOVIWithHDR10),
4 => (VideoRange.HDR, VideoRangeType.DOVIWithHLG),
2 => (VideoRange.SDR, VideoRangeType.DOVIWithSDR),
// While not in Dolby Spec, Profile 8 CCid 6 media are possible to create, and since CCid 6 stems from Bluray (Profile 7 originally) an HDR10 base layer is guaranteed to exist.
6 => (VideoRange.HDR, VideoRangeType.DOVIWithHDR10),
// There is no other case to handle here as per Dolby Spec. Default case included for completeness and linting purposes
_ => (VideoRange.SDR, VideoRangeType.SDR)
// Out of Dolby Spec files should be marked as invalid
_ => (VideoRange.HDR, VideoRangeType.DOVIInvalid)
},
7 => (VideoRange.HDR, VideoRangeType.HDR10),
7 => (VideoRange.HDR, VideoRangeType.DOVIWithEL),
10 => dvBlCompatId switch
{
0 => (VideoRange.HDR, VideoRangeType.DOVI),
1 => (VideoRange.HDR, VideoRangeType.DOVIWithHDR10),
2 => (VideoRange.SDR, VideoRangeType.DOVIWithSDR),
4 => (VideoRange.HDR, VideoRangeType.DOVIWithHLG),
// While not in Dolby Spec, Profile 8 CCid 6 media are possible to create, and since CCid 6 stems from Bluray (Profile 7 originally) an HDR10 base layer is guaranteed to exist.
6 => (VideoRange.HDR, VideoRangeType.DOVIWithHDR10),
// There is no other case to handle here as per Dolby Spec. Default case included for completeness and linting purposes
_ => (VideoRange.SDR, VideoRangeType.SDR)
// Out of Dolby Spec files should be marked as invalid
_ => (VideoRange.HDR, VideoRangeType.DOVIInvalid)
},
_ => (VideoRange.SDR, VideoRangeType.SDR)
};
if (Hdr10PlusPresentFlag == true)
{
return dvRangeSet.Item2 switch
{
VideoRangeType.DOVIWithHDR10 => (VideoRange.HDR, VideoRangeType.DOVIWithHDR10Plus),
VideoRangeType.DOVIWithEL => (VideoRange.HDR, VideoRangeType.DOVIWithELHDR10Plus),
_ => dvRangeSet
};
}
return dvRangeSet;
}
var colorTransfer = ColorTransfer;
if (string.Equals(colorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase))
{
return (VideoRange.HDR, VideoRangeType.HDR10);
return Hdr10PlusPresentFlag == true ? (VideoRange.HDR, VideoRangeType.HDR10Plus) : (VideoRange.HDR, VideoRangeType.HDR10);
}
else if (string.Equals(colorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase))
{