hybird vpp tonemapping for QSV on Linux

This commit is contained in:
nyanmisaka 2021-01-29 17:53:42 +08:00
parent b0e0e19468
commit 3052068161
2 changed files with 94 additions and 21 deletions

View File

@ -142,7 +142,20 @@ namespace MediaBrowser.Controller.MediaEncoding
&& string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase); && string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase);
} }
// Vpp tonemapping may come to QSV in the future. // Hybrid VPP tonemapping for QSV with VAAPI
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
if (isLinux && string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase))
{
// Limited to HEVC for now since the filter doesn't accept master data from VP9.
return IsColorDepth10(state)
&& string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)
&& _mediaEncoder.SupportsHwaccel("vaapi")
&& _mediaEncoder.SupportsHwaccel("qsv")
&& options.EnableVppTonemapping
&& string.Equals(videoStream.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase);
}
// Native VPP tonemapping may come to QSV in the future.
return false; return false;
} }
@ -552,10 +565,20 @@ namespace MediaBrowser.Controller.MediaEncoding
} }
// While using SW decoder // While using SW decoder
else else if (isSwDecoder)
{ {
arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); arg.Append("-init_hw_device qsv=hw -filter_hw_device hw ");
} }
// Hybrid VPP tonemapping with VAAPI
else if (isVaapiDecoder && isVppTonemappingSupported)
{
arg.Append("-init_hw_device vaapi=va:")
.Append(encodingOptions.VaapiDevice)
.Append(' ')
.Append("-init_hw_device qsv@va ")
.Append("-hwaccel_output_format vaapi ");
}
} }
} }
@ -1952,15 +1975,18 @@ namespace MediaBrowser.Controller.MediaEncoding
var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1; var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1; var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isVaapiHevcEncoder = outputVideoCodec.IndexOf("hevc_vaapi", StringComparison.OrdinalIgnoreCase) != -1; var isVaapiHevcEncoder = outputVideoCodec.IndexOf("hevc_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
var isQsvH264Encoder = outputVideoCodec.Contains("h264_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 isTonemappingSupported = IsTonemappingSupported(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);
// 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 (isTonemappingSupported && isTonemappingSupportedOnVaapi && !isVppTonemappingSupported) if (isTonemappingSupportedOnVaapi && isTonemappingSupported && !isVppTonemappingSupported)
{ {
return GetOutputSizeParam(state, options, outputVideoCodec); return GetOutputSizeParam(state, options, outputVideoCodec);
} }
@ -1983,7 +2009,8 @@ namespace MediaBrowser.Controller.MediaEncoding
height.Value); height.Value);
} }
if (!string.IsNullOrEmpty(videoSizeParam)) if (!string.IsNullOrEmpty(videoSizeParam)
&& !(isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{ {
// For QSV, feed it into hardware encoder now // For QSV, feed it into hardware encoder now
if (isLinux && (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) if (isLinux && (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
@ -2017,7 +2044,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 = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload[base];[base][sub]overlay,format=nv12,hwupload\""; 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\"";
} }
// 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
@ -2030,7 +2059,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 = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]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\"";
} }
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))
@ -2041,7 +2072,11 @@ namespace MediaBrowser.Controller.MediaEncoding
with fixed frame size. with fixed frame size.
Currently only supports linux. Currently only supports linux.
*/ */
if (isLinux) if (isTonemappingSupportedOnQsv && isVppTonemappingSupported)
{
retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3},hwdownload,format=nv12[base];[base][sub]overlay\"";
}
else if (isLinux)
{ {
retStr = !outputSizeParam.IsEmpty 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}]{3}[base];[base][sub]overlay_qsv\""
@ -2147,16 +2182,27 @@ namespace MediaBrowser.Controller.MediaEncoding
var isVaapiDecoder = videoDecoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase); var isVaapiDecoder = videoDecoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase);
var isVaapiH264Encoder = videoEncoder.Contains("h264_vaapi", StringComparison.OrdinalIgnoreCase); var isVaapiH264Encoder = videoEncoder.Contains("h264_vaapi", StringComparison.OrdinalIgnoreCase);
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 isQsvHevcEncoder = videoEncoder.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase);
var isTonemappingSupported = IsTonemappingSupported(state, options); var isTonemappingSupported = IsTonemappingSupported(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 isP010PixFmtRequired = (isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported))
|| (isTonemappingSupportedOnQsv && isVppTonemappingSupported);
var outputPixFmt = "format=nv12"; var outputPixFmt = "format=nv12";
if (isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported)) if (isP010PixFmtRequired)
{ {
outputPixFmt = "format=p010"; outputPixFmt = "format=p010";
} }
if (isTonemappingSupportedOnQsv && isVppTonemappingSupported)
{
qsv_or_vaapi = false;
}
if (!videoWidth.HasValue if (!videoWidth.HasValue
|| outputWidth != videoWidth.Value || outputWidth != videoWidth.Value
|| !videoHeight.HasValue || !videoHeight.HasValue
@ -2176,7 +2222,7 @@ namespace MediaBrowser.Controller.MediaEncoding
} }
// Assert 10-bit is P010 so as we can avoid the extra scaler to get a bit more fps on high res HDR videos. // Assert 10-bit is P010 so as we can avoid the extra scaler to get a bit more fps on high res HDR videos.
else if (!(isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported))) else if (!isP010PixFmtRequired)
{ {
filters.Add( filters.Add(
string.Format( string.Format(
@ -2477,6 +2523,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder); var isTonemappingSupportedOnNvenc = string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && (isNvdecDecoder || isCuvidHevcDecoder || 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 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;
@ -2619,13 +2666,15 @@ namespace MediaBrowser.Controller.MediaEncoding
} }
// When burning in graphical subtitles using overlay_qsv, upload videostream to the same qsv context. // When burning in graphical subtitles using overlay_qsv, upload videostream to the same qsv context.
else if (isLinux && hasGraphicalSubs && (isQsvH264Encoder || isQsvHevcEncoder)) else if (isLinux && hasGraphicalSubs && (isQsvH264Encoder || isQsvHevcEncoder)
&& !(isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{ {
filters.Add("hwupload=extra_hw_frames=64"); filters.Add("hwupload=extra_hw_frames=64");
} }
// 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.
else if ((IsVaapiSupported(state) && isVaapiDecoder) && (isLibX264Encoder || isLibX265Encoder)) else if ((IsVaapiSupported(state) && isVaapiDecoder) && (isLibX264Encoder || isLibX265Encoder)
&& !(isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{ {
var codec = videoStream.Codec; var codec = videoStream.Codec;
@ -2654,7 +2703,8 @@ namespace MediaBrowser.Controller.MediaEncoding
// Add hardware deinterlace filter before scaling filter. // Add hardware deinterlace filter before scaling filter.
if (isDeinterlaceH264 || isDeinterlaceHevc) if (isDeinterlaceH264 || isDeinterlaceHevc)
{ {
if (isVaapiEncoder) if (isVaapiEncoder
|| (isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{ {
filters.Add( filters.Add(
string.Format( string.Format(
@ -2717,9 +2767,10 @@ namespace MediaBrowser.Controller.MediaEncoding
request.MaxHeight)); request.MaxHeight));
} }
// 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 && isVppTonemappingSupported) if ((isTonemappingSupportedOnVaapi || isTonemappingSupportedOnQsv)
&& isVppTonemappingSupported)
{ {
filters.Add("tonemap_vaapi=format=nv12:transfer=bt709:matrix=bt709:primaries=bt709"); filters.Add("tonemap_vaapi=format=nv12:transfer=bt709:matrix=bt709:primaries=bt709");
} }
@ -2777,13 +2828,15 @@ namespace MediaBrowser.Controller.MediaEncoding
} }
// Add parameters to use VAAPI with burn-in text subtitles (GH issue #642) // Add parameters to use VAAPI with burn-in text subtitles (GH issue #642)
if (isVaapiH264Encoder || isVaapiHevcEncoder) if (isVaapiH264Encoder
|| isVaapiHevcEncoder
|| (isTonemappingSupportedOnQsv && isVppTonemappingSupported))
{ {
if (hasTextSubs) if (hasTextSubs)
{ {
// 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 (isTonemappingSupported && isTonemappingSupportedOnVaapi && !isVppTonemappingSupported) if (isTonemappingSupportedOnVaapi && isTonemappingSupported && !isVppTonemappingSupported)
{ {
filters.Add("scale_vaapi"); filters.Add("scale_vaapi");
} }
@ -2794,8 +2847,6 @@ namespace MediaBrowser.Controller.MediaEncoding
} }
} }
var output = string.Empty;
if (hasTextSubs) if (hasTextSubs)
{ {
var subParam = GetTextSubtitleParam(state); var subParam = GetTextSubtitleParam(state);
@ -2809,17 +2860,29 @@ namespace MediaBrowser.Controller.MediaEncoding
filters.Add("hwmap"); filters.Add("hwmap");
} }
if (isTonemappingSupportedOnQsv && isVppTonemappingSupported)
{
filters.Add("hwmap,format=vaapi");
}
if (isNvdecDecoder && isNvencEncoder) if (isNvdecDecoder && isNvencEncoder)
{ {
isHwuploadCudaRequired = true; isHwuploadCudaRequired = true;
} }
} }
// Interop the VAAPI data to QSV for hybrid tonemapping
if (isTonemappingSupportedOnQsv && isVppTonemappingSupported && !hasGraphicalSubs)
{
filters.Add("hwmap=derive_device=qsv,scale_qsv");
}
if (isHwuploadCudaRequired && !hasGraphicalSubs) if (isHwuploadCudaRequired && !hasGraphicalSubs)
{ {
filters.Add("hwupload_cuda"); filters.Add("hwupload_cuda");
} }
var output = string.Empty;
if (filters.Count > 0) if (filters.Count > 0)
{ {
output += string.Format( output += string.Format(
@ -3292,6 +3355,14 @@ namespace MediaBrowser.Controller.MediaEncoding
return null; return null;
} }
// Hybrid VPP tonemapping with VAAPI
if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)
&& IsVppTonemappingSupported(state, encodingOptions))
{
// 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))
{ {
switch (videoStream.Codec.ToLowerInvariant()) switch (videoStream.Codec.ToLowerInvariant())
@ -3520,7 +3591,9 @@ namespace MediaBrowser.Controller.MediaEncoding
} }
} }
if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)) if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)
|| (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)
&& IsVppTonemappingSupported(state, options)))
{ {
if (IsVaapiSupported(state) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase)) if (IsVaapiSupported(state) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
{ {

View File

@ -55,7 +55,7 @@ namespace MediaBrowser.Controller.MediaEncoding
/// </summary> /// </summary>
/// <param name="filter">The filter.</param> /// <param name="filter">The filter.</param>
/// <param name="option">The option.</param> /// <param name="option">The option.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> /// <returns><c>true</c> if the filter is supported, <c>false</c> otherwise.</returns>
bool SupportsFilter(string filter, string option); bool SupportsFilter(string filter, string option);
/// <summary> /// <summary>