Enable AQ for NVENC & AMF encoders for better subjective quality

Similar to QSV's MBBRC, for NVENC it's Spatial-AQ, and for AMF it's VBAQ/CAQ.

This significantly improves subjective quality at low bitrates.

Signed-off-by: nyanmisaka <nst799610810@gmail.com>
This commit is contained in:
nyanmisaka committed 2026-10-03 14:40:08 +08:00
1 parent bbc40674a8
commit b532d90fdc
1 file changed
+28 -9
@@ -88,6 +88,7 @@ namespace MediaBrowser.Controller.MediaEncoding
private readonly Version _minFFmpegRkmppHevcDecDoviRpu = new Version(7, 1, 1);
private readonly Version _minFFmpegReadrateCatchupOption = new Version(8, 0);
private readonly Version _minFFmpegNoiseBsfDrop = new Version(5, 0);
private readonly Version _minFFmpegAmfAv1EncCAQ = new Version(7, 1);
private static readonly string[] _videoProfilesH264 =
[
@@ -1668,14 +1669,6 @@ namespace MediaBrowser.Controller.MediaEncoding
// TODO: probe QSV encoders' capabilities and enable more tuning options
// See also https://github.com/intel/media-delivery/blob/master/doc/quality.rst
// Enable MacroBlock level bitrate control for better subjective visual quality
var mbbrcOpt = string.Empty;
if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|| string.Equals(videoCodec, "hevc_qsv", StringComparison.OrdinalIgnoreCase))
{
mbbrcOpt = " -mbbrc 1";
}
// Some less powerful H.264 HW decoders require strict CPB size
// So bufsize optimizations should not be applied to them
int factor = 2;
@@ -1696,7 +1689,7 @@ namespace MediaBrowser.Controller.MediaEncoding
int qsvInitOcc = (int)Math.Min((long)bitrate * 1 * factor, int.MaxValue);
int qsvBufsize = (int)Math.Min((long)bitrate * 2 * factor, int.MaxValue);
return FormattableString.Invariant($"{mbbrcOpt} -b:v {bitrate} -maxrate {qsvMaxrate} -rc_init_occupancy {qsvInitOcc} -bufsize {qsvBufsize}");
return string.Create(CultureInfo.InvariantCulture, $" -b:v {bitrate} -maxrate {qsvMaxrate} -rc_init_occupancy {qsvInitOcc} -bufsize {qsvBufsize}");
}
if (string.Equals(videoCodec, "h264_amf", StringComparison.OrdinalIgnoreCase)
@@ -1813,6 +1806,13 @@ namespace MediaBrowser.Controller.MediaEncoding
EncoderPreset[] valid_presets = [EncoderPreset.veryslow, EncoderPreset.slower, EncoderPreset.slow, EncoderPreset.medium, EncoderPreset.fast, EncoderPreset.faster, EncoderPreset.veryfast];
param += " -preset " + (valid_presets.Contains(encoderPreset) ? encoderPreset : EncoderPreset.veryfast).ToString().ToLowerInvariant();
// Enable MacroBlock level bitrate control for better subjective visual quality
if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|| string.Equals(videoEncoder, "hevc_qsv", StringComparison.OrdinalIgnoreCase))
{
param += " -mbbrc 1";
}
}
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) // h264 (h264_nvenc)
|| string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase) // hevc (hevc_nvenc)
@@ -1829,6 +1829,13 @@ namespace MediaBrowser.Controller.MediaEncoding
EncoderPreset.faster => " -preset p2",
_ => " -preset p1"
};
// Enable Spatial Adaptive Quantization for better subjective visual quality
// H.264 is skipped for now because Maxwell 1 does not support it
if (!string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
{
param += " -spatial-aq 1 -aq-strength 15";
}
}
else if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase) // h264 (h264_amf)
|| string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase) // hevc (hevc_amf)
@@ -1844,6 +1851,18 @@ namespace MediaBrowser.Controller.MediaEncoding
_ => " -quality speed"
};
// Enable Variance Based/Context Adaptive Quantization for better subjective visual quality
if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase)
|| string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase))
{
param += " -vbaq 1";
}
else if (string.Equals(videoEncoder, "av1_amf", StringComparison.OrdinalIgnoreCase)
&& _mediaEncoder.EncoderVersion >= _minFFmpegAmfAv1EncCAQ)
{
param += " -aq_mode caq";
}
if (string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase)
|| string.Equals(videoEncoder, "av1_amf", StringComparison.OrdinalIgnoreCase))
{