|
@@ -37,6 +37,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
"ConstrainedHigh"
|
|
"ConstrainedHigh"
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+ private static readonly Version minVersionForCudaOverlay = new Version(4, 4);
|
|
|
|
+
|
|
public EncodingHelper(
|
|
public EncodingHelper(
|
|
IMediaEncoder mediaEncoder,
|
|
IMediaEncoder mediaEncoder,
|
|
ISubtitleEncoder subtitleEncoder)
|
|
ISubtitleEncoder subtitleEncoder)
|
|
@@ -106,17 +108,41 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
private bool IsCudaSupported()
|
|
private bool IsCudaSupported()
|
|
{
|
|
{
|
|
return _mediaEncoder.SupportsHwaccel("cuda")
|
|
return _mediaEncoder.SupportsHwaccel("cuda")
|
|
- && _mediaEncoder.SupportsFilter("scale_cuda", null)
|
|
|
|
- && _mediaEncoder.SupportsFilter("yadif_cuda", null);
|
|
|
|
|
|
+ && _mediaEncoder.SupportsFilter("scale_cuda")
|
|
|
|
+ && _mediaEncoder.SupportsFilter("yadif_cuda")
|
|
|
|
+ && _mediaEncoder.SupportsFilter("hwupload_cuda");
|
|
}
|
|
}
|
|
|
|
|
|
- private bool IsTonemappingSupported(EncodingJobInfo state, EncodingOptions options)
|
|
|
|
|
|
+ private bool IsOpenclTonemappingSupported(EncodingJobInfo state, EncodingOptions options)
|
|
{
|
|
{
|
|
var videoStream = state.VideoStream;
|
|
var videoStream = state.VideoStream;
|
|
- return IsColorDepth10(state)
|
|
|
|
|
|
+ if (videoStream == null)
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return options.EnableTonemapping
|
|
|
|
+ && (string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)
|
|
|
|
+ || string.Equals(videoStream.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase))
|
|
|
|
+ && IsColorDepth10(state)
|
|
&& _mediaEncoder.SupportsHwaccel("opencl")
|
|
&& _mediaEncoder.SupportsHwaccel("opencl")
|
|
- && options.EnableTonemapping
|
|
|
|
- && string.Equals(videoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
|
+ && _mediaEncoder.SupportsFilter("tonemap_opencl");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private bool IsCudaTonemappingSupported(EncodingJobInfo state, EncodingOptions options)
|
|
|
|
+ {
|
|
|
|
+ var videoStream = state.VideoStream;
|
|
|
|
+ if (videoStream == null)
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return options.EnableTonemapping
|
|
|
|
+ && (string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)
|
|
|
|
+ || string.Equals(videoStream.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase))
|
|
|
|
+ && IsColorDepth10(state)
|
|
|
|
+ && _mediaEncoder.SupportsHwaccel("cuda")
|
|
|
|
+ && _mediaEncoder.SupportsFilterWithOption(FilterOptionType.TonemapCudaName);
|
|
}
|
|
}
|
|
|
|
|
|
private bool IsVppTonemappingSupported(EncodingJobInfo state, EncodingOptions options)
|
|
private bool IsVppTonemappingSupported(EncodingJobInfo state, EncodingOptions options)
|
|
@@ -132,23 +158,25 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
|
|
if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
{
|
|
// Limited to HEVC for now since the filter doesn't accept master data from VP9.
|
|
// Limited to HEVC for now since the filter doesn't accept master data from VP9.
|
|
- return IsColorDepth10(state)
|
|
|
|
|
|
+ return options.EnableVppTonemapping
|
|
|
|
+ && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)
|
|
|
|
+ && IsColorDepth10(state)
|
|
&& string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
|
|
&& string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
|
|
&& _mediaEncoder.SupportsHwaccel("vaapi")
|
|
&& _mediaEncoder.SupportsHwaccel("vaapi")
|
|
- && options.EnableVppTonemapping
|
|
|
|
- && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
|
+ && _mediaEncoder.SupportsFilter("tonemap_vaapi");
|
|
}
|
|
}
|
|
|
|
|
|
// Hybrid VPP tonemapping for QSV with VAAPI
|
|
// Hybrid VPP tonemapping for QSV with VAAPI
|
|
if (OperatingSystem.IsLinux() && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
|
if (OperatingSystem.IsLinux() && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
{
|
|
// Limited to HEVC for now since the filter doesn't accept master data from VP9.
|
|
// Limited to HEVC for now since the filter doesn't accept master data from VP9.
|
|
- return IsColorDepth10(state)
|
|
|
|
|
|
+ return options.EnableVppTonemapping
|
|
|
|
+ && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)
|
|
|
|
+ && IsColorDepth10(state)
|
|
&& string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
|
|
&& string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
|
|
&& _mediaEncoder.SupportsHwaccel("vaapi")
|
|
&& _mediaEncoder.SupportsHwaccel("vaapi")
|
|
- && _mediaEncoder.SupportsHwaccel("qsv")
|
|
|
|
- && options.EnableVppTonemapping
|
|
|
|
- && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
|
+ && _mediaEncoder.SupportsFilter("tonemap_vaapi")
|
|
|
|
+ && _mediaEncoder.SupportsHwaccel("qsv");
|
|
}
|
|
}
|
|
|
|
|
|
// Native VPP tonemapping may come to QSV in the future.
|
|
// Native VPP tonemapping may come to QSV in the future.
|
|
@@ -497,13 +525,16 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
/// Gets the input argument.
|
|
/// Gets the input argument.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <param name="state">Encoding state.</param>
|
|
/// <param name="state">Encoding state.</param>
|
|
- /// <param name="encodingOptions">Encoding options.</param>
|
|
|
|
|
|
+ /// <param name="options">Encoding options.</param>
|
|
/// <returns>Input arguments.</returns>
|
|
/// <returns>Input arguments.</returns>
|
|
- public string GetInputArgument(EncodingJobInfo state, EncodingOptions encodingOptions)
|
|
|
|
|
|
+ public string GetInputArgument(EncodingJobInfo state, EncodingOptions options)
|
|
{
|
|
{
|
|
var arg = new StringBuilder();
|
|
var arg = new StringBuilder();
|
|
- var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty;
|
|
|
|
- var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty;
|
|
|
|
|
|
+ var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty;
|
|
|
|
+ var outputVideoCodec = GetVideoEncoder(state, options) ?? string.Empty;
|
|
|
|
+ var isWindows = OperatingSystem.IsWindows();
|
|
|
|
+ var isLinux = OperatingSystem.IsLinux();
|
|
|
|
+ var isMacOS = OperatingSystem.IsMacOS();
|
|
#pragma warning disable CA1508 // Defaults to string.Empty
|
|
#pragma warning disable CA1508 // Defaults to string.Empty
|
|
var isSwDecoder = string.IsNullOrEmpty(videoDecoder);
|
|
var isSwDecoder = string.IsNullOrEmpty(videoDecoder);
|
|
#pragma warning restore CA1508
|
|
#pragma warning restore CA1508
|
|
@@ -514,26 +545,24 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
|
var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
|
var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
|
|
var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
|
|
var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase);
|
|
var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase);
|
|
- var isWindows = OperatingSystem.IsWindows();
|
|
|
|
- var isLinux = OperatingSystem.IsLinux();
|
|
|
|
- var isMacOS = OperatingSystem.IsMacOS();
|
|
|
|
- var isTonemappingSupported = IsTonemappingSupported(state, encodingOptions);
|
|
|
|
- var isVppTonemappingSupported = IsVppTonemappingSupported(state, encodingOptions);
|
|
|
|
|
|
+ var isCuvidVp9Decoder = videoDecoder.Contains("vp9_cuvid", StringComparison.OrdinalIgnoreCase);
|
|
|
|
+ var isOpenclTonemappingSupported = IsOpenclTonemappingSupported(state, options);
|
|
|
|
+ var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
|
|
|
|
+ var isCudaTonemappingSupported = IsCudaTonemappingSupported(state, options);
|
|
|
|
|
|
if (!IsCopyCodec(outputVideoCodec))
|
|
if (!IsCopyCodec(outputVideoCodec))
|
|
{
|
|
{
|
|
if (state.IsVideoRequest
|
|
if (state.IsVideoRequest
|
|
&& _mediaEncoder.SupportsHwaccel("vaapi")
|
|
&& _mediaEncoder.SupportsHwaccel("vaapi")
|
|
- && string.Equals(encodingOptions.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
+ && string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
{
|
|
if (isVaapiDecoder)
|
|
if (isVaapiDecoder)
|
|
{
|
|
{
|
|
- if (isTonemappingSupported && !isVppTonemappingSupported)
|
|
|
|
|
|
+ if (isOpenclTonemappingSupported && !isVppTonemappingSupported)
|
|
{
|
|
{
|
|
arg.Append("-init_hw_device vaapi=va:")
|
|
arg.Append("-init_hw_device vaapi=va:")
|
|
- .Append(encodingOptions.VaapiDevice)
|
|
|
|
- .Append(' ')
|
|
|
|
- .Append("-init_hw_device opencl=ocl@va ")
|
|
|
|
|
|
+ .Append(options.VaapiDevice)
|
|
|
|
+ .Append(" -init_hw_device opencl=ocl@va ")
|
|
.Append("-hwaccel_device va ")
|
|
.Append("-hwaccel_device va ")
|
|
.Append("-hwaccel_output_format vaapi ")
|
|
.Append("-hwaccel_output_format vaapi ")
|
|
.Append("-filter_hw_device ocl ");
|
|
.Append("-filter_hw_device ocl ");
|
|
@@ -542,14 +571,14 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
{
|
|
{
|
|
arg.Append("-hwaccel_output_format vaapi ")
|
|
arg.Append("-hwaccel_output_format vaapi ")
|
|
.Append("-vaapi_device ")
|
|
.Append("-vaapi_device ")
|
|
- .Append(encodingOptions.VaapiDevice)
|
|
|
|
|
|
+ .Append(options.VaapiDevice)
|
|
.Append(' ');
|
|
.Append(' ');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (!isVaapiDecoder && isVaapiEncoder)
|
|
else if (!isVaapiDecoder && isVaapiEncoder)
|
|
{
|
|
{
|
|
arg.Append("-vaapi_device ")
|
|
arg.Append("-vaapi_device ")
|
|
- .Append(encodingOptions.VaapiDevice)
|
|
|
|
|
|
+ .Append(options.VaapiDevice)
|
|
.Append(' ');
|
|
.Append(' ');
|
|
}
|
|
}
|
|
|
|
|
|
@@ -557,7 +586,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
}
|
|
}
|
|
|
|
|
|
if (state.IsVideoRequest
|
|
if (state.IsVideoRequest
|
|
- && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
+ && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
{
|
|
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
|
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
|
|
|
|
|
@@ -593,9 +622,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
else if (isVaapiDecoder && isVppTonemappingSupported)
|
|
else if (isVaapiDecoder && isVppTonemappingSupported)
|
|
{
|
|
{
|
|
arg.Append("-init_hw_device vaapi=va:")
|
|
arg.Append("-init_hw_device vaapi=va:")
|
|
- .Append(encodingOptions.VaapiDevice)
|
|
|
|
- .Append(' ')
|
|
|
|
- .Append("-init_hw_device qsv@va ")
|
|
|
|
|
|
+ .Append(options.VaapiDevice)
|
|
|
|
+ .Append(" -init_hw_device qsv@va ")
|
|
.Append("-hwaccel_output_format vaapi ");
|
|
.Append("-hwaccel_output_format vaapi ");
|
|
}
|
|
}
|
|
|
|
|
|
@@ -604,7 +632,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
}
|
|
}
|
|
|
|
|
|
if (state.IsVideoRequest
|
|
if (state.IsVideoRequest
|
|
- && string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)
|
|
|
|
|
|
+ && string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)
|
|
&& isNvdecDecoder)
|
|
&& isNvdecDecoder)
|
|
{
|
|
{
|
|
// Fix for 'No decoder surfaces left' error. https://trac.ffmpeg.org/ticket/7562
|
|
// Fix for 'No decoder surfaces left' error. https://trac.ffmpeg.org/ticket/7562
|
|
@@ -612,22 +640,31 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
}
|
|
}
|
|
|
|
|
|
if (state.IsVideoRequest
|
|
if (state.IsVideoRequest
|
|
- && ((string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)
|
|
|
|
- && (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder))
|
|
|
|
- || (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase)
|
|
|
|
- && (isD3d11vaDecoder || isSwDecoder))))
|
|
|
|
|
|
+ && ((string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)
|
|
|
|
+ && (isNvdecDecoder || isCuvidHevcDecoder || isCuvidVp9Decoder || isSwDecoder))))
|
|
{
|
|
{
|
|
- if (isTonemappingSupported)
|
|
|
|
|
|
+ if (!isCudaTonemappingSupported && isOpenclTonemappingSupported)
|
|
{
|
|
{
|
|
arg.Append("-init_hw_device opencl=ocl:")
|
|
arg.Append("-init_hw_device opencl=ocl:")
|
|
- .Append(encodingOptions.OpenclDevice)
|
|
|
|
- .Append(' ')
|
|
|
|
- .Append("-filter_hw_device ocl ");
|
|
|
|
|
|
+ .Append(options.OpenclDevice)
|
|
|
|
+ .Append(" -filter_hw_device ocl ");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (state.IsVideoRequest
|
|
if (state.IsVideoRequest
|
|
- && string.Equals(encodingOptions.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
+ && string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase)
|
|
|
|
+ && (isD3d11vaDecoder || isSwDecoder))
|
|
|
|
+ {
|
|
|
|
+ if (isOpenclTonemappingSupported)
|
|
|
|
+ {
|
|
|
|
+ arg.Append("-init_hw_device opencl=ocl:")
|
|
|
|
+ .Append(options.OpenclDevice)
|
|
|
|
+ .Append(" -filter_hw_device ocl ");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (state.IsVideoRequest
|
|
|
|
+ && string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
{
|
|
arg.Append("-hwaccel videotoolbox ");
|
|
arg.Append("-hwaccel videotoolbox ");
|
|
}
|
|
}
|
|
@@ -2012,14 +2049,18 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
var isQsvHevcEncoder = outputVideoCodec.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase);
|
|
var isQsvHevcEncoder = outputVideoCodec.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase);
|
|
var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
|
|
var isNvdecDecoder = videoDecoder.Contains("cuda", StringComparison.OrdinalIgnoreCase);
|
|
var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase);
|
|
var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase);
|
|
- var isTonemappingSupported = IsTonemappingSupported(state, options);
|
|
|
|
- var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
|
|
|
|
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
|
|
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
|
|
var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
|
|
var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
|
|
|
|
+ var isOpenclTonemappingSupported = IsOpenclTonemappingSupported(state, options);
|
|
|
|
+ var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
|
|
|
|
+
|
|
|
|
+ var mediaEncoderVersion = _mediaEncoder.GetMediaEncoderVersion();
|
|
|
|
+ var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= minVersionForCudaOverlay;
|
|
|
|
+ var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.ScaleCudaFormat);
|
|
|
|
|
|
// Tonemapping and burn-in graphical subtitles requires overlay_vaapi.
|
|
// Tonemapping and burn-in graphical subtitles requires overlay_vaapi.
|
|
// But it's still in ffmpeg mailing list. Disable it for now.
|
|
// But it's still in ffmpeg mailing list. Disable it for now.
|
|
- if (isTonemappingSupportedOnVaapi && isTonemappingSupported && !isVppTonemappingSupported)
|
|
|
|
|
|
+ if (isTonemappingSupportedOnVaapi && isOpenclTonemappingSupported && !isVppTonemappingSupported)
|
|
{
|
|
{
|
|
return GetOutputSizeParam(state, options, outputVideoCodec);
|
|
return GetOutputSizeParam(state, options, outputVideoCodec);
|
|
}
|
|
}
|
|
@@ -2045,13 +2086,22 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
if (!string.IsNullOrEmpty(videoSizeParam)
|
|
if (!string.IsNullOrEmpty(videoSizeParam)
|
|
&& !(isTonemappingSupportedOnQsv && isVppTonemappingSupported))
|
|
&& !(isTonemappingSupportedOnQsv && isVppTonemappingSupported))
|
|
{
|
|
{
|
|
- // For QSV, feed it into hardware encoder now
|
|
|
|
|
|
+ // upload graphical subtitle to QSV
|
|
if (isLinux && (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|
|
if (isLinux && (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase)))
|
|
|| string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
{
|
|
videoSizeParam += ",hwupload=extra_hw_frames=64";
|
|
videoSizeParam += ",hwupload=extra_hw_frames=64";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (!string.IsNullOrEmpty(videoSizeParam))
|
|
|
|
+ {
|
|
|
|
+ // upload graphical subtitle to cuda
|
|
|
|
+ if (isNvdecDecoder && isNvencEncoder && isCudaOverlaySupported && isCudaFormatConversionSupported)
|
|
|
|
+ {
|
|
|
|
+ videoSizeParam += ",hwupload_cuda";
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
var mapPrefix = state.SubtitleStream.IsExternal ?
|
|
var mapPrefix = state.SubtitleStream.IsExternal ?
|
|
@@ -2064,9 +2114,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
|
|
|
|
// Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference)
|
|
// Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference)
|
|
// Always put the scaler before the overlay for better performance
|
|
// Always put the scaler before the overlay for better performance
|
|
- var retStr = !outputSizeParam.IsEmpty
|
|
|
|
- ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\""
|
|
|
|
- : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\"";
|
|
|
|
|
|
+ var retStr = outputSizeParam.IsEmpty
|
|
|
|
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\""
|
|
|
|
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"";
|
|
|
|
|
|
// When the input may or may not be hardware VAAPI decodable
|
|
// When the input may or may not be hardware VAAPI decodable
|
|
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
|
|
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
|
|
@@ -2077,9 +2127,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
[sub]: SW scaling subtitle to FixedOutputSize
|
|
[sub]: SW scaling subtitle to FixedOutputSize
|
|
[base][sub]: SW overlay
|
|
[base][sub]: SW overlay
|
|
*/
|
|
*/
|
|
- retStr = !outputSizeParam.IsEmpty
|
|
|
|
- ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\""
|
|
|
|
- : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]hwdownload[base];[base][sub]overlay,format=nv12,hwupload\"";
|
|
|
|
|
|
+ retStr = outputSizeParam.IsEmpty
|
|
|
|
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]hwdownload[base];[base][sub]overlay,format=nv12,hwupload\""
|
|
|
|
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\"";
|
|
}
|
|
}
|
|
|
|
|
|
// If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
|
|
// If we're hardware VAAPI decoding and software encoding, download frames from the decoder first
|
|
@@ -2092,9 +2142,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
[sub]: SW scaling subtitle to FixedOutputSize
|
|
[sub]: SW scaling subtitle to FixedOutputSize
|
|
[base][sub]: SW overlay
|
|
[base][sub]: SW overlay
|
|
*/
|
|
*/
|
|
- retStr = !outputSizeParam.IsEmpty
|
|
|
|
- ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\""
|
|
|
|
- : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\"";
|
|
|
|
|
|
+ retStr = outputSizeParam.IsEmpty
|
|
|
|
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\""
|
|
|
|
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"";
|
|
}
|
|
}
|
|
else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|
|
else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase))
|
|
|| string.Equals(outputVideoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase))
|
|
@@ -2111,16 +2161,25 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
}
|
|
}
|
|
else if (isLinux)
|
|
else if (isLinux)
|
|
{
|
|
{
|
|
- retStr = !outputSizeParam.IsEmpty
|
|
|
|
- ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\""
|
|
|
|
- : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\"";
|
|
|
|
|
|
+ retStr = outputSizeParam.IsEmpty
|
|
|
|
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\""
|
|
|
|
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (isNvdecDecoder && isNvencEncoder)
|
|
else if (isNvdecDecoder && isNvencEncoder)
|
|
{
|
|
{
|
|
- retStr = !outputSizeParam.IsEmpty
|
|
|
|
- ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay,format=nv12|yuv420p,hwupload_cuda\""
|
|
|
|
- : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay,format=nv12|yuv420p,hwupload_cuda\"";
|
|
|
|
|
|
+ if (isCudaOverlaySupported && isCudaFormatConversionSupported)
|
|
|
|
+ {
|
|
|
|
+ retStr = outputSizeParam.IsEmpty
|
|
|
|
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]scale_cuda=format=yuv420p[base];[base][sub]overlay_cuda\""
|
|
|
|
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_cuda\"";
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ retStr = outputSizeParam.IsEmpty
|
|
|
|
+ ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay,format=nv12|yuv420p,hwupload_cuda\""
|
|
|
|
+ : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay,format=nv12|yuv420p,hwupload_cuda\"";
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
return string.Format(
|
|
return string.Format(
|
|
@@ -2217,11 +2276,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
var isVaapiHevcEncoder = videoEncoder.Contains("hevc_vaapi", StringComparison.OrdinalIgnoreCase);
|
|
var isVaapiHevcEncoder = videoEncoder.Contains("hevc_vaapi", StringComparison.OrdinalIgnoreCase);
|
|
var isQsvH264Encoder = videoEncoder.Contains("h264_qsv", StringComparison.OrdinalIgnoreCase);
|
|
var isQsvH264Encoder = videoEncoder.Contains("h264_qsv", StringComparison.OrdinalIgnoreCase);
|
|
var isQsvHevcEncoder = videoEncoder.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase);
|
|
var isQsvHevcEncoder = videoEncoder.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase);
|
|
- var isTonemappingSupported = IsTonemappingSupported(state, options);
|
|
|
|
|
|
+ var isOpenclTonemappingSupported = IsOpenclTonemappingSupported(state, options);
|
|
var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
|
|
var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
|
|
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
|
|
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
|
|
var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
|
|
var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
|
|
- var isP010PixFmtRequired = (isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported))
|
|
|
|
|
|
+ var isP010PixFmtRequired = (isTonemappingSupportedOnVaapi && (isOpenclTonemappingSupported || isVppTonemappingSupported))
|
|
|| (isTonemappingSupportedOnQsv && isVppTonemappingSupported);
|
|
|| (isTonemappingSupportedOnQsv && isVppTonemappingSupported);
|
|
|
|
|
|
var outputPixFmt = "format=nv12";
|
|
var outputPixFmt = "format=nv12";
|
|
@@ -2272,15 +2331,23 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
var outputWidth = width.Value;
|
|
var outputWidth = width.Value;
|
|
var outputHeight = height.Value;
|
|
var outputHeight = height.Value;
|
|
|
|
|
|
- var isTonemappingSupported = IsTonemappingSupported(state, options);
|
|
|
|
|
|
+ var isNvencEncoder = videoEncoder.Contains("nvenc", StringComparison.OrdinalIgnoreCase);
|
|
|
|
+ var isOpenclTonemappingSupported = IsOpenclTonemappingSupported(state, options);
|
|
|
|
+ var isCudaTonemappingSupported = IsCudaTonemappingSupported(state, options);
|
|
var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase);
|
|
var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase);
|
|
- var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilter("scale_cuda", "Output format (default \"same\")");
|
|
|
|
|
|
+ var mediaEncoderVersion = _mediaEncoder.GetMediaEncoderVersion();
|
|
|
|
+ var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= minVersionForCudaOverlay;
|
|
|
|
+ var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.ScaleCudaFormat);
|
|
|
|
+ var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
|
|
|
|
|
var outputPixFmt = string.Empty;
|
|
var outputPixFmt = string.Empty;
|
|
if (isCudaFormatConversionSupported)
|
|
if (isCudaFormatConversionSupported)
|
|
{
|
|
{
|
|
- outputPixFmt = "format=nv12";
|
|
|
|
- if (isTonemappingSupported && isTonemappingSupportedOnNvenc)
|
|
|
|
|
|
+ outputPixFmt = (hasGraphicalSubs && isCudaOverlaySupported && isNvencEncoder)
|
|
|
|
+ ? "format=yuv420p"
|
|
|
|
+ : "format=nv12";
|
|
|
|
+ if ((isOpenclTonemappingSupported || isCudaTonemappingSupported)
|
|
|
|
+ && isTonemappingSupportedOnNvenc)
|
|
{
|
|
{
|
|
outputPixFmt = "format=p010";
|
|
outputPixFmt = "format=p010";
|
|
}
|
|
}
|
|
@@ -2558,16 +2625,21 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase);
|
|
var isNvencEncoder = outputVideoCodec.Contains("nvenc", StringComparison.OrdinalIgnoreCase);
|
|
var isCuvidH264Decoder = videoDecoder.Contains("h264_cuvid", StringComparison.OrdinalIgnoreCase);
|
|
var isCuvidH264Decoder = videoDecoder.Contains("h264_cuvid", StringComparison.OrdinalIgnoreCase);
|
|
var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase);
|
|
var isCuvidHevcDecoder = videoDecoder.Contains("hevc_cuvid", StringComparison.OrdinalIgnoreCase);
|
|
|
|
+ var isCuvidVp9Decoder = videoDecoder.Contains("vp9_cuvid", StringComparison.OrdinalIgnoreCase);
|
|
var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1;
|
|
var isLibX264Encoder = outputVideoCodec.IndexOf("libx264", StringComparison.OrdinalIgnoreCase) != -1;
|
|
var isLibX265Encoder = outputVideoCodec.IndexOf("libx265", StringComparison.OrdinalIgnoreCase) != -1;
|
|
var isLibX265Encoder = outputVideoCodec.IndexOf("libx265", StringComparison.OrdinalIgnoreCase) != -1;
|
|
var isLinux = OperatingSystem.IsLinux();
|
|
var isLinux = OperatingSystem.IsLinux();
|
|
var isColorDepth10 = IsColorDepth10(state);
|
|
var isColorDepth10 = IsColorDepth10(state);
|
|
- var isTonemappingSupported = IsTonemappingSupported(state, options);
|
|
|
|
- var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
|
|
|
|
- var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder);
|
|
|
|
|
|
+
|
|
|
|
+ var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && (isNvdecDecoder || isCuvidHevcDecoder || isCuvidVp9Decoder || isSwDecoder);
|
|
var isTonemappingSupportedOnAmf = string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && (isD3d11vaDecoder || isSwDecoder);
|
|
var isTonemappingSupportedOnAmf = string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && (isD3d11vaDecoder || isSwDecoder);
|
|
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
|
|
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
|
|
var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
|
|
var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
|
|
|
|
+ var isOpenclTonemappingSupported = IsOpenclTonemappingSupported(state, options);
|
|
|
|
+ var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
|
|
|
|
+ var isCudaTonemappingSupported = IsCudaTonemappingSupported(state, options);
|
|
|
|
+ var mediaEncoderVersion = _mediaEncoder.GetMediaEncoderVersion();
|
|
|
|
+ var isCudaOverlaySupported = _mediaEncoder.SupportsFilter("overlay_cuda") && mediaEncoderVersion != null && mediaEncoderVersion >= minVersionForCudaOverlay;
|
|
|
|
|
|
var hasSubs = state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
|
var hasSubs = state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
|
var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
|
var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
|
@@ -2579,19 +2651,25 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
var isScalingInAdvance = false;
|
|
var isScalingInAdvance = false;
|
|
var isCudaDeintInAdvance = false;
|
|
var isCudaDeintInAdvance = false;
|
|
var isHwuploadCudaRequired = false;
|
|
var isHwuploadCudaRequired = false;
|
|
|
|
+ var isNoTonemapFilterApplied = true;
|
|
var isDeinterlaceH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true);
|
|
var isDeinterlaceH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true);
|
|
var isDeinterlaceHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true);
|
|
var isDeinterlaceHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true);
|
|
|
|
|
|
// Add OpenCL tonemapping filter for NVENC/AMF/VAAPI.
|
|
// Add OpenCL tonemapping filter for NVENC/AMF/VAAPI.
|
|
- if (isTonemappingSupportedOnNvenc || isTonemappingSupportedOnAmf || (isTonemappingSupportedOnVaapi && !isVppTonemappingSupported))
|
|
|
|
|
|
+ if ((isTonemappingSupportedOnNvenc && !isCudaTonemappingSupported) || isTonemappingSupportedOnAmf || (isTonemappingSupportedOnVaapi && !isVppTonemappingSupported))
|
|
{
|
|
{
|
|
- // Currently only with the use of NVENC decoder can we get a decent performance.
|
|
|
|
- // Currently only the HEVC/H265 format is supported with NVDEC decoder.
|
|
|
|
// NVIDIA Pascal and Turing or higher are recommended.
|
|
// NVIDIA Pascal and Turing or higher are recommended.
|
|
// AMD Polaris and Vega or higher are recommended.
|
|
// AMD Polaris and Vega or higher are recommended.
|
|
// Intel Kaby Lake or newer is required.
|
|
// Intel Kaby Lake or newer is required.
|
|
- if (isTonemappingSupported)
|
|
|
|
|
|
+ if (isOpenclTonemappingSupported)
|
|
{
|
|
{
|
|
|
|
+ isNoTonemapFilterApplied = false;
|
|
|
|
+ var inputHdrParams = GetInputHdrParams(videoStream.ColorTransfer);
|
|
|
|
+ if (!string.IsNullOrEmpty(inputHdrParams))
|
|
|
|
+ {
|
|
|
|
+ filters.Add(inputHdrParams);
|
|
|
|
+ }
|
|
|
|
+
|
|
var parameters = "tonemap_opencl=format=nv12:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:desat={1}:threshold={2}:peak={3}";
|
|
var parameters = "tonemap_opencl=format=nv12:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:desat={1}:threshold={2}:peak={3}";
|
|
|
|
|
|
if (options.TonemappingParam != 0)
|
|
if (options.TonemappingParam != 0)
|
|
@@ -2663,7 +2741,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
filters.Add("hwdownload,format=p010");
|
|
filters.Add("hwdownload,format=p010");
|
|
}
|
|
}
|
|
|
|
|
|
- if (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder || isD3d11vaDecoder)
|
|
|
|
|
|
+ if (isNvdecDecoder
|
|
|
|
+ || isCuvidHevcDecoder
|
|
|
|
+ || isCuvidVp9Decoder
|
|
|
|
+ || isSwDecoder
|
|
|
|
+ || isD3d11vaDecoder)
|
|
{
|
|
{
|
|
// Upload the HDR10 or HLG data to the OpenCL device,
|
|
// Upload the HDR10 or HLG data to the OpenCL device,
|
|
// use tonemap_opencl filter for tone mapping,
|
|
// use tonemap_opencl filter for tone mapping,
|
|
@@ -2671,6 +2753,14 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
filters.Add("hwupload");
|
|
filters.Add("hwupload");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Fallback to hable if bt2390 is chosen but not supported in tonemap_opencl.
|
|
|
|
+ var isBt2390SupportedInOpenclTonemap = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.TonemapOpenclBt2390);
|
|
|
|
+ if (string.Equals(options.TonemappingAlgorithm, "bt2390", StringComparison.OrdinalIgnoreCase)
|
|
|
|
+ && !isBt2390SupportedInOpenclTonemap)
|
|
|
|
+ {
|
|
|
|
+ options.TonemappingAlgorithm = "hable";
|
|
|
|
+ }
|
|
|
|
+
|
|
filters.Add(
|
|
filters.Add(
|
|
string.Format(
|
|
string.Format(
|
|
CultureInfo.InvariantCulture,
|
|
CultureInfo.InvariantCulture,
|
|
@@ -2682,7 +2772,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
options.TonemappingParam,
|
|
options.TonemappingParam,
|
|
options.TonemappingRange));
|
|
options.TonemappingRange));
|
|
|
|
|
|
- if (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder || isD3d11vaDecoder)
|
|
|
|
|
|
+ if (isNvdecDecoder
|
|
|
|
+ || isCuvidHevcDecoder
|
|
|
|
+ || isCuvidVp9Decoder
|
|
|
|
+ || isSwDecoder
|
|
|
|
+ || isD3d11vaDecoder)
|
|
{
|
|
{
|
|
filters.Add("hwdownload");
|
|
filters.Add("hwdownload");
|
|
filters.Add("format=nv12");
|
|
filters.Add("format=nv12");
|
|
@@ -2698,12 +2792,18 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
// Reverse the data route from opencl to vaapi.
|
|
// Reverse the data route from opencl to vaapi.
|
|
filters.Add("hwmap=derive_device=vaapi:reverse=1");
|
|
filters.Add("hwmap=derive_device=vaapi:reverse=1");
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ var outputSdrParams = GetOutputSdrParams(options.TonemappingRange);
|
|
|
|
+ if (!string.IsNullOrEmpty(outputSdrParams))
|
|
|
|
+ {
|
|
|
|
+ filters.Add(outputSdrParams);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// When the input may or may not be hardware VAAPI decodable.
|
|
// When the input may or may not be hardware VAAPI decodable.
|
|
if ((isVaapiH264Encoder || isVaapiHevcEncoder)
|
|
if ((isVaapiH264Encoder || isVaapiHevcEncoder)
|
|
- && !(isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported)))
|
|
|
|
|
|
+ && !(isTonemappingSupportedOnVaapi && (isOpenclTonemappingSupported || isVppTonemappingSupported)))
|
|
{
|
|
{
|
|
filters.Add("format=nv12|vaapi");
|
|
filters.Add("format=nv12|vaapi");
|
|
filters.Add("hwupload");
|
|
filters.Add("hwupload");
|
|
@@ -2811,6 +2911,61 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
request.MaxHeight));
|
|
request.MaxHeight));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Add Cuda tonemapping filter.
|
|
|
|
+ if (isNvdecDecoder && isCudaTonemappingSupported)
|
|
|
|
+ {
|
|
|
|
+ isNoTonemapFilterApplied = false;
|
|
|
|
+ var inputHdrParams = GetInputHdrParams(videoStream.ColorTransfer);
|
|
|
|
+ if (!string.IsNullOrEmpty(inputHdrParams))
|
|
|
|
+ {
|
|
|
|
+ filters.Add(inputHdrParams);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var parameters = (hasGraphicalSubs && isCudaOverlaySupported && isNvencEncoder)
|
|
|
|
+ ? "tonemap_cuda=format=yuv420p:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:peak={1}:desat={2}"
|
|
|
|
+ : "tonemap_cuda=format=nv12:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:peak={1}:desat={2}";
|
|
|
|
+
|
|
|
|
+ if (options.TonemappingParam != 0)
|
|
|
|
+ {
|
|
|
|
+ parameters += ":param={3}";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!string.Equals(options.TonemappingRange, "auto", StringComparison.OrdinalIgnoreCase))
|
|
|
|
+ {
|
|
|
|
+ parameters += ":range={4}";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ filters.Add(
|
|
|
|
+ string.Format(
|
|
|
|
+ CultureInfo.InvariantCulture,
|
|
|
|
+ parameters,
|
|
|
|
+ options.TonemappingAlgorithm,
|
|
|
|
+ options.TonemappingPeak,
|
|
|
|
+ options.TonemappingDesat,
|
|
|
|
+ options.TonemappingParam,
|
|
|
|
+ options.TonemappingRange));
|
|
|
|
+
|
|
|
|
+ if (isLibX264Encoder
|
|
|
|
+ || isLibX265Encoder
|
|
|
|
+ || hasTextSubs
|
|
|
|
+ || (hasGraphicalSubs && !isCudaOverlaySupported && isNvencEncoder))
|
|
|
|
+ {
|
|
|
|
+ if (isNvencEncoder)
|
|
|
|
+ {
|
|
|
|
+ isHwuploadCudaRequired = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ filters.Add("hwdownload");
|
|
|
|
+ filters.Add("format=nv12");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var outputSdrParams = GetOutputSdrParams(options.TonemappingRange);
|
|
|
|
+ if (!string.IsNullOrEmpty(outputSdrParams))
|
|
|
|
+ {
|
|
|
|
+ filters.Add(outputSdrParams);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
// Add VPP tonemapping filter for VAAPI.
|
|
// Add VPP tonemapping filter for VAAPI.
|
|
// Full hardware based video post processing, faster than OpenCL but lacks fine tuning options.
|
|
// Full hardware based video post processing, faster than OpenCL but lacks fine tuning options.
|
|
if ((isTonemappingSupportedOnVaapi || isTonemappingSupportedOnQsv)
|
|
if ((isTonemappingSupportedOnVaapi || isTonemappingSupportedOnQsv)
|
|
@@ -2820,10 +2975,10 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
}
|
|
}
|
|
|
|
|
|
// Another case is when using Nvenc decoder.
|
|
// Another case is when using Nvenc decoder.
|
|
- if (isNvdecDecoder && !isTonemappingSupported)
|
|
|
|
|
|
+ if (isNvdecDecoder && !isOpenclTonemappingSupported && !isCudaTonemappingSupported)
|
|
{
|
|
{
|
|
var codec = videoStream.Codec;
|
|
var codec = videoStream.Codec;
|
|
- var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilter("scale_cuda", "Output format (default \"same\")");
|
|
|
|
|
|
+ var isCudaFormatConversionSupported = _mediaEncoder.SupportsFilterWithOption(FilterOptionType.ScaleCudaFormat);
|
|
|
|
|
|
// Assert 10-bit hardware decodable
|
|
// Assert 10-bit hardware decodable
|
|
if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
|
|
if (isColorDepth10 && (string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
|
|
@@ -2832,7 +2987,10 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
{
|
|
{
|
|
if (isCudaFormatConversionSupported)
|
|
if (isCudaFormatConversionSupported)
|
|
{
|
|
{
|
|
- if (isLibX264Encoder || isLibX265Encoder || hasSubs)
|
|
|
|
|
|
+ if (isLibX264Encoder
|
|
|
|
+ || isLibX265Encoder
|
|
|
|
+ || hasTextSubs
|
|
|
|
+ || (hasGraphicalSubs && !isCudaOverlaySupported && isNvencEncoder))
|
|
{
|
|
{
|
|
if (isNvencEncoder)
|
|
if (isNvencEncoder)
|
|
{
|
|
{
|
|
@@ -2859,7 +3017,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
}
|
|
}
|
|
|
|
|
|
// Assert 8-bit hardware decodable
|
|
// Assert 8-bit hardware decodable
|
|
- else if (!isColorDepth10 && (isLibX264Encoder || isLibX265Encoder || hasSubs))
|
|
|
|
|
|
+ else if (!isColorDepth10
|
|
|
|
+ && (isLibX264Encoder
|
|
|
|
+ || isLibX265Encoder
|
|
|
|
+ || hasTextSubs
|
|
|
|
+ || (hasGraphicalSubs && !isCudaOverlaySupported && isNvencEncoder)))
|
|
{
|
|
{
|
|
if (isNvencEncoder)
|
|
if (isNvencEncoder)
|
|
{
|
|
{
|
|
@@ -2880,7 +3042,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
{
|
|
{
|
|
// Convert hw context from ocl to va.
|
|
// Convert hw context from ocl to va.
|
|
// For tonemapping and text subs burn-in.
|
|
// For tonemapping and text subs burn-in.
|
|
- if (isTonemappingSupportedOnVaapi && isTonemappingSupported && !isVppTonemappingSupported)
|
|
|
|
|
|
+ if (isTonemappingSupportedOnVaapi && isOpenclTonemappingSupported && !isVppTonemappingSupported)
|
|
{
|
|
{
|
|
filters.Add("scale_vaapi");
|
|
filters.Add("scale_vaapi");
|
|
}
|
|
}
|
|
@@ -2926,6 +3088,17 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
filters.Add("hwupload_cuda");
|
|
filters.Add("hwupload_cuda");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // If no tonemap filter is applied,
|
|
|
|
+ // tag the video range as SDR to prevent the encoder from encoding HDR video.
|
|
|
|
+ if (isNoTonemapFilterApplied)
|
|
|
|
+ {
|
|
|
|
+ var outputSdrParams = GetOutputSdrParams(null);
|
|
|
|
+ if (!string.IsNullOrEmpty(outputSdrParams))
|
|
|
|
+ {
|
|
|
|
+ filters.Add(outputSdrParams);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
var output = string.Empty;
|
|
var output = string.Empty;
|
|
if (filters.Count > 0)
|
|
if (filters.Count > 0)
|
|
{
|
|
{
|
|
@@ -2938,6 +3111,36 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
return output;
|
|
return output;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ public static string GetInputHdrParams(string colorTransfer)
|
|
|
|
+ {
|
|
|
|
+ if (string.Equals(colorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase))
|
|
|
|
+ {
|
|
|
|
+ // HLG
|
|
|
|
+ return "setparams=color_primaries=bt2020:color_trc=arib-std-b67:colorspace=bt2020nc";
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ // HDR10
|
|
|
|
+ return "setparams=color_primaries=bt2020:color_trc=smpte2084:colorspace=bt2020nc";
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static string GetOutputSdrParams(string tonemappingRange)
|
|
|
|
+ {
|
|
|
|
+ // SDR
|
|
|
|
+ if (string.Equals(tonemappingRange, "tv", StringComparison.OrdinalIgnoreCase))
|
|
|
|
+ {
|
|
|
|
+ return "setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709:range=tv";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (string.Equals(tonemappingRange, "pc", StringComparison.OrdinalIgnoreCase))
|
|
|
|
+ {
|
|
|
|
+ return "setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709:range=pc";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return "setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709";
|
|
|
|
+ }
|
|
|
|
+
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Gets the number of threads.
|
|
/// Gets the number of threads.
|
|
/// </summary>
|
|
/// </summary>
|
|
@@ -3408,8 +3611,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)
|
|
if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)
|
|
&& IsVppTonemappingSupported(state, encodingOptions))
|
|
&& IsVppTonemappingSupported(state, encodingOptions))
|
|
{
|
|
{
|
|
- // Since tonemap_vaapi only support HEVC for now, no need to check the codec again.
|
|
|
|
- return GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10);
|
|
|
|
|
|
+ var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty;
|
|
|
|
+ var isQsvEncoder = outputVideoCodec.Contains("qsv", StringComparison.OrdinalIgnoreCase);
|
|
|
|
+ if (isQsvEncoder)
|
|
|
|
+ {
|
|
|
|
+ // Since tonemap_vaapi only support HEVC for now, no need to check the codec again.
|
|
|
|
+ return GetHwaccelType(state, encodingOptions, "hevc", isColorDepth10);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
|
if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
|
|
@@ -3942,6 +4150,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
|
|
|
|
if (videoStream != null)
|
|
if (videoStream != null)
|
|
{
|
|
{
|
|
|
|
+ if (videoStream.BitDepth.HasValue)
|
|
|
|
+ {
|
|
|
|
+ return videoStream.BitDepth.Value == 10;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (!string.IsNullOrEmpty(videoStream.PixelFormat))
|
|
if (!string.IsNullOrEmpty(videoStream.PixelFormat))
|
|
{
|
|
{
|
|
result = videoStream.PixelFormat.Contains("p10", StringComparison.OrdinalIgnoreCase);
|
|
result = videoStream.PixelFormat.Contains("p10", StringComparison.OrdinalIgnoreCase);
|
|
@@ -3961,12 +4174,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- result = (videoStream.BitDepth ?? 8) == 10;
|
|
|
|
- if (result)
|
|
|
|
- {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
return result;
|
|
return result;
|