Merge pull request #7828 from nyanmisaka/fix-dovi-tonemap

Fix Dolby Vision profile 5 and 8 to SDR HW tone-mapping

(cherry picked from commit 8595a979a8)
Signed-off-by: crobibero <cody@robibe.ro>
This commit is contained in:
Bond-009
2022-06-06 17:29:39 +02:00
committed by crobibero
parent 1a9919d487
commit c19c787273
4 changed files with 79 additions and 34 deletions

View File

@@ -13,11 +13,13 @@ using System.Threading;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Extensions;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
using Microsoft.Extensions.Configuration;
namespace MediaBrowser.Controller.MediaEncoding
{
@@ -32,6 +34,7 @@ namespace MediaBrowser.Controller.MediaEncoding
private readonly IApplicationPaths _appPaths;
private readonly IMediaEncoder _mediaEncoder;
private readonly ISubtitleEncoder _subtitleEncoder;
private readonly IConfiguration _config;
private static readonly string[] _videoProfilesH264 = new[]
{
@@ -54,11 +57,13 @@ namespace MediaBrowser.Controller.MediaEncoding
public EncodingHelper(
IApplicationPaths appPaths,
IMediaEncoder mediaEncoder,
ISubtitleEncoder subtitleEncoder)
ISubtitleEncoder subtitleEncoder,
IConfiguration config)
{
_appPaths = appPaths;
_mediaEncoder = mediaEncoder;
_subtitleEncoder = subtitleEncoder;
_config = config;
}
public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions)
@@ -144,15 +149,28 @@ namespace MediaBrowser.Controller.MediaEncoding
private bool IsHwTonemapAvailable(EncodingJobInfo state, EncodingOptions options)
{
if (state.VideoStream == null)
if (state.VideoStream == null
|| !options.EnableTonemapping
|| GetVideoColorBitDepth(state) != 10)
{
return false;
}
return options.EnableTonemapping
&& (string.Equals(state.VideoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)
|| string.Equals(state.VideoStream.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase))
&& GetVideoColorBitDepth(state) == 10;
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))
{
// Only native SW decoder and HW accelerator can parse dovi rpu.
var vidDecoder = GetHardwareVideoDecoder(state, options) ?? string.Empty;
var isSwDecoder = string.IsNullOrEmpty(vidDecoder);
var isNvdecDecoder = vidDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
var isVaapiDecoder = vidDecoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase);
var isD3d11vaDecoder = vidDecoder.Contains("d3d11va", StringComparison.OrdinalIgnoreCase);
return isSwDecoder || isNvdecDecoder || isVaapiDecoder || isD3d11vaDecoder;
}
return string.Equals(state.VideoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)
|| string.Equals(state.VideoStream.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase);
}
private bool IsVaapiVppTonemapAvailable(EncodingJobInfo state, EncodingOptions options)
@@ -516,8 +534,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (string.Equals(codec, "flac", StringComparison.OrdinalIgnoreCase))
{
// flac is experimental in mp4 muxer
return "flac -strict -2";
return "flac";
}
return codec.ToLowerInvariant();
@@ -1024,7 +1041,8 @@ namespace MediaBrowser.Controller.MediaEncoding
if (string.Equals(videoCodec, "h264_amf", StringComparison.OrdinalIgnoreCase)
|| string.Equals(videoCodec, "hevc_amf", StringComparison.OrdinalIgnoreCase))
{
return FormattableString.Invariant($" -qmin 18 -qmax 32 -b:v {bitrate} -maxrate {bitrate} -bufsize {bufsize}");
// Override the too high default qmin 18 in transcoding preset
return FormattableString.Invariant($" -rc cbr -qmin 0 -qmax 32 -b:v {bitrate} -maxrate {bitrate} -bufsize {bufsize}");
}
if (string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
@@ -1222,10 +1240,9 @@ namespace MediaBrowser.Controller.MediaEncoding
// Example: we encoded half of desired length, then codec detected
// scene cut and inserted a keyframe; next forced keyframe would
// be created outside of segment, which breaks seeking.
// -sc_threshold 0 is used to prevent the hardware encoder from post processing to break the set keyframe.
gopArg = string.Format(
CultureInfo.InvariantCulture,
" -g:v:0 {0} -keyint_min:v:0 {0} -sc_threshold:v:0 0",
" -g:v:0 {0} -keyint_min:v:0 {0}",
Math.Ceiling(segmentLength * framerate.Value));
}
@@ -1245,6 +1262,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|| string.Equals(codec, "hevc_vaapi", StringComparison.OrdinalIgnoreCase))
{
args += keyFrameArg;
// prevent the libx264 from post processing to break the set keyframe.
if (string.Equals(codec, "libx264", StringComparison.OrdinalIgnoreCase))
{
args += " -sc_threshold:v:0 0";
}
}
else
{
@@ -4865,22 +4888,21 @@ namespace MediaBrowser.Controller.MediaEncoding
public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions, string segmentContainer)
{
var inputModifier = string.Empty;
var probeSizeArgument = string.Empty;
var analyzeDurationArgument = string.Empty;
string analyzeDurationArgument;
if (state.MediaSource.AnalyzeDurationMs.HasValue)
// Apply -analyzeduration as per the environment variable,
// otherwise ffmpeg will break on certain files due to default value is 0.
// The default value of -probesize is more than enough, so leave it as is.
var ffmpegAnalyzeDuration = _config.GetFFmpegAnalyzeDuration() ?? string.Empty;
if (!string.IsNullOrEmpty(ffmpegAnalyzeDuration))
{
analyzeDurationArgument = "-analyzeduration " + ffmpegAnalyzeDuration;
}
else if (state.MediaSource.AnalyzeDurationMs.HasValue)
{
analyzeDurationArgument = "-analyzeduration " + (state.MediaSource.AnalyzeDurationMs.Value * 1000).ToString(CultureInfo.InvariantCulture);
}
else
{
analyzeDurationArgument = string.Empty;
}
if (!string.IsNullOrEmpty(probeSizeArgument))
{
inputModifier += " " + probeSizeArgument;
}
if (!string.IsNullOrEmpty(analyzeDurationArgument))
{