add hdr tone mapping to image extraction

pull/4610/head
nyanmisaka 4 years ago
parent c2c06ae15b
commit 3e9cf98c30

@ -34,9 +34,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
public class MediaEncoder : IMediaEncoder, IDisposable public class MediaEncoder : IMediaEncoder, IDisposable
{ {
/// <summary> /// <summary>
/// The default image extraction timeout in milliseconds. /// The default SDR image extraction timeout in milliseconds.
/// </summary> /// </summary>
internal const int DefaultImageExtractionTimeout = 10000; internal const int DefaultSdrImageExtractionTimeout = 10000;
/// <summary>
/// The default HDR image extraction timeout in milliseconds.
/// </summary>
internal const int DefaultHdrImageExtractionTimeout = 20000;
/// <summary> /// <summary>
/// The us culture. /// The us culture.
@ -495,9 +500,36 @@ namespace MediaBrowser.MediaEncoding.Encoder
} }
else else
{ {
// The failure of HDR extraction usually occurs when using custom ffmpeg that does not contain the zscale filter.
try
{
return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, true, true, cancellationToken).ConfigureAwait(false);
}
catch (ArgumentException)
{
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "I-frame or HDR image extraction failed, will attempt with I-frame extraction disabled. Input: {Arguments}", inputArgument);
}
try
{
return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, true, cancellationToken).ConfigureAwait(false);
}
catch (ArgumentException)
{
throw;
}
catch (Exception ex)
{
_logger.LogError(ex, "HDR image extraction failed, will fallback to SDR image extraction. Input: {Arguments}", inputArgument);
}
try try
{ {
return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, true, cancellationToken).ConfigureAwait(false); return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, true, false, cancellationToken).ConfigureAwait(false);
} }
catch (ArgumentException) catch (ArgumentException)
{ {
@ -509,10 +541,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
} }
} }
return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, cancellationToken).ConfigureAwait(false); return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, false, cancellationToken).ConfigureAwait(false);
} }
private async Task<string> ExtractImageInternal(string inputPath, string container, MediaStream videoStream, int? imageStreamIndex, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, CancellationToken cancellationToken) private async Task<string> ExtractImageInternal(string inputPath, string container, MediaStream videoStream, int? imageStreamIndex, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, bool allowTonemap, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(inputPath)) if (string.IsNullOrEmpty(inputPath))
{ {
@ -553,6 +585,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
var mapArg = imageStreamIndex.HasValue ? (" -map 0:v:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty; var mapArg = imageStreamIndex.HasValue ? (" -map 0:v:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty;
var enableHdrExtraction = allowTonemap && videoStream != null && !string.IsNullOrEmpty(videoStream.VideoRange) && string.Equals(videoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase);
if (enableHdrExtraction)
{
string tonemapFilters = "zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0:peak=100,zscale=t=bt709:m=bt709,format=yuv420p";
if (string.IsNullOrEmpty(vf))
{
vf = "-vf " + tonemapFilters;
}
else
{
vf += "," + tonemapFilters;
}
}
// Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case. // Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case.
var enableThumbnail = useIFrame && !string.Equals("wtv", container, StringComparison.OrdinalIgnoreCase); var enableThumbnail = useIFrame && !string.Equals("wtv", container, StringComparison.OrdinalIgnoreCase);
if (enableThumbnail) if (enableThumbnail)
@ -635,7 +681,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
var timeoutMs = _configurationManager.Configuration.ImageExtractionTimeoutMs; var timeoutMs = _configurationManager.Configuration.ImageExtractionTimeoutMs;
if (timeoutMs <= 0) if (timeoutMs <= 0)
{ {
timeoutMs = DefaultImageExtractionTimeout; timeoutMs = enableHdrExtraction ? DefaultHdrImageExtractionTimeout : DefaultSdrImageExtractionTimeout;
} }
ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMilliseconds(timeoutMs)).ConfigureAwait(false); ranToCompletion = await process.WaitForExitAsync(TimeSpan.FromMilliseconds(timeoutMs)).ConfigureAwait(false);

Loading…
Cancel
Save