mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-12-17 14:33:06 +03:00
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:
@@ -7,6 +7,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Text.RegularExpressions;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.MediaEncoding.Encoder
|
||||
@@ -160,6 +161,15 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
{ 6, new string[] { "transpose_opencl", "rotate by half-turn" } }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<BitStreamFilterOptionType, (string, string)> _bsfOptionsDict = new Dictionary<BitStreamFilterOptionType, (string, string)>
|
||||
{
|
||||
{ BitStreamFilterOptionType.HevcMetadataRemoveDovi, ("hevc_metadata", "remove_dovi") },
|
||||
{ BitStreamFilterOptionType.HevcMetadataRemoveHdr10Plus, ("hevc_metadata", "remove_hdr10plus") },
|
||||
{ BitStreamFilterOptionType.Av1MetadataRemoveDovi, ("av1_metadata", "remove_dovi") },
|
||||
{ BitStreamFilterOptionType.Av1MetadataRemoveHdr10Plus, ("av1_metadata", "remove_hdr10plus") },
|
||||
{ BitStreamFilterOptionType.DoviRpuStrip, ("dovi_rpu", "strip") }
|
||||
};
|
||||
|
||||
// These are the library versions that corresponds to our minimum ffmpeg version 4.4 according to the version table below
|
||||
// Refers to the versions in https://ffmpeg.org/download.html
|
||||
private static readonly Dictionary<string, Version> _ffmpegMinimumLibraryVersions = new Dictionary<string, Version>
|
||||
@@ -286,6 +296,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
|
||||
public IDictionary<int, bool> GetFiltersWithOption() => GetFFmpegFiltersWithOption();
|
||||
|
||||
public IDictionary<BitStreamFilterOptionType, bool> GetBitStreamFiltersWithOption() => _bsfOptionsDict
|
||||
.ToDictionary(item => item.Key, item => CheckBitStreamFilterWithOption(item.Value.Item1, item.Value.Item2));
|
||||
|
||||
public Version? GetFFmpegVersion()
|
||||
{
|
||||
string output;
|
||||
@@ -495,6 +508,34 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CheckBitStreamFilterWithOption(string filter, string option)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filter) || string.IsNullOrEmpty(option))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string output;
|
||||
try
|
||||
{
|
||||
output = GetProcessOutput(_encoderPath, "-h bsf=" + filter, false, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error detecting the given bit stream filter");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (output.Contains("Bit stream filter " + filter, StringComparison.Ordinal))
|
||||
{
|
||||
return output.Contains(option, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
_logger.LogWarning("Bit stream filter: {Name} with option {Option} is not available", filter, option);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CheckSupportedRuntimeKey(string keyDesc, Version? ffmpegVersion)
|
||||
{
|
||||
if (string.IsNullOrEmpty(keyDesc))
|
||||
@@ -523,6 +564,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
return !string.IsNullOrEmpty(flag) && GetProcessExitCode(_encoderPath, $"-loglevel quiet -hwaccel_flags +{flag} -hide_banner -f lavfi -i nullsrc=s=1x1:d=100 -f null -");
|
||||
}
|
||||
|
||||
public bool CheckSupportedProberOption(string option, string proberPath)
|
||||
{
|
||||
return !string.IsNullOrEmpty(option) && GetProcessExitCode(proberPath, $"-loglevel quiet -f lavfi -i nullsrc=s=1x1:d=1 -{option}");
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetCodecs(Codec codec)
|
||||
{
|
||||
string codecstr = codec == Codec.Encoder ? "encoders" : "decoders";
|
||||
|
||||
Reference in New Issue
Block a user