Skip to content

Commit

Permalink
win: amf: Revert RC/HRD defaults; improve documentation & config parsing
Browse files Browse the repository at this point in the history
* Revert RC and HRD defaults back to 'vbr_latency' and 'disabled' due to
  encoding artifacts or quality regressions noted on several cards.

* Document all new and existing AMF options in the docs and UI. Rearrange
  AMF options to better reflect importance (Usage is primary) and group by
  relatedness; group RC and HRD together, group all other quality-related
  sub options together.

* Various cleanups & fixes to AMF option parsing, including proper setting of
  defaults when invalid configuration is parsed.
  • Loading branch information
psyke83 committed Apr 14, 2024
1 parent fb4d4f5 commit 405f9ad
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 141 deletions.
114 changes: 72 additions & 42 deletions docs/source/about/advanced_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1471,34 +1471,42 @@ keybindings
`AMD AMF Encoder <https://localhost:47990/config/#amd-amf-encoder>`__
---------------------------------------------------------------------

`amd_quality <https://localhost:47990/config/#amd_quality>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`amd_usage <https://localhost:47990/config/#amd_usage>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Description**
The encoder preset to use.
The encoder usage profile is used to set the base set of encoding
parameters.

.. note:: This option only applies when using amdvce `encoder`_.

.. note:: The other AMF options that follow will override a subset
of the settings applied by your usage profile, but there are
hidden parameters set in usage profiles that cannot be
overridden elsewhere.

**Choices**

.. table::
:widths: auto

========== ===========
Value Description
========== ===========
speed prefer speed
balanced balanced
quality prefer quality
========== ===========
======================= ===========
Value Description
======================= ===========
transcoding transcoding (slowest)
webcam webcam (slow)
lowlatency_high_quality low latency, high quality (fast)
lowlatency low latency (faster)
ultralowlatency ultra low latency (fastest)
======================= ===========

**Default**
``balanced``
``ultralowlatency``

**Example**
.. code-block:: text
amd_quality = balanced
amd_usage = ultralowlatency
`amd_rc <https://localhost:47990/config/#amd_rc>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -1508,6 +1516,11 @@ keybindings

.. note:: This option only applies when using amdvce `encoder`_.

.. warning:: The 'vbr_latency' option generally works best, but
some bitrate overshoots may still occur. Enabling HRD allows
all bitrate based rate controls to better constrain peak bitrate,
but may result in encoding artifacts depending on your card.

**Choices**

.. table::
Expand All @@ -1523,81 +1536,98 @@ keybindings
=========== ===========

**Default**
``cbr``
``vbr_latency``

**Example**
.. code-block:: text
amd_rc = cbr
amd_rc = vbr_latency
`amd_usage <https://localhost:47990/config/#amd_usage>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`amd_enforce_hrd <https://localhost:47990/config/#amd_enforce_hrd>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Description**
The encoder usage profile, used to balance latency with encoding quality.
Enable Hypothetical Reference Decoder (HRD) enforcement to help constrain the target bitrate.

.. note:: This option only applies when using amdvce `encoder`_.

.. warning: HRD is known to cause encoding artifacts or negatively affect
encoding quality on certain cards.
**Choices**

.. table::
:widths: auto

======================= ===========
Value Description
======================= ===========
transcoding transcoding (slowest)
webcam webcam (slow)
lowlatency_high_quality low latency, high quality (fast)
lowlatency low latency (faster)
ultralowlatency ultra low latency (fastest)
======================= ===========
======== ===========
Value Description
======== ===========
enabled enable HRD
disabled disable HRD
======== ===========

**Default**
``ultralowlatency``
``disabled``

**Example**
.. code-block:: text
amd_usage = ultralowlatency
amd_enforce_hrd = disabled
`amd_preanalysis <https://localhost:47990/config/#amd_preanalysis>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`amd_quality <https://localhost:47990/config/#amd_quality>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Description**
Preanalysis can increase encoding quality at the cost of latency.
The quality profile controls the tradeoff between
speed and quality of encoding.

.. note:: This option only applies when using amdvce `encoder`_.

**Choices**

.. table::
:widths: auto

========== ===========
Value Description
========== ===========
speed prefer speed
balanced balanced
quality prefer quality
========== ===========

**Default**
``disabled``
``balanced``

**Example**
.. code-block:: text
amd_preanalysis = disabled
amd_quality = balanced
`amd_vbaq <https://localhost:47990/config/#amd_vbaq>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`amd_preanalysis <https://localhost:47990/config/#amd_preanalysis>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Description**
Variance Based Adaptive Quantization (VBAQ) can increase subjective visual quality.
Preanalysis can increase encoding quality at the cost of latency.

.. note:: This option only applies when using amdvce `encoder`_.

**Default**
``enabled``
``disabled``

**Example**
.. code-block:: text
amd_vbaq = enabled
amd_preanalysis = disabled
`amd_enforce_hrd <https://localhost:47990/config/#amd_enforce_hrd>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`amd_vbaq <https://localhost:47990/config/#amd_vbaq>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**Description**
Enable Hypothetical Reference Decoder (HRD) enforcement to help constrain the target bitrate.
Variance Based Adaptive Quantization (VBAQ) can increase subjective
visual quality by prioritizing allocation of more bits to smooth
areas compared to more textured areas.

.. note:: This option only applies when using amdvce `encoder`_.

Expand All @@ -1607,7 +1637,7 @@ keybindings
**Example**
.. code-block:: text
amd_enforce_hrd = enabled
amd_vbaq = enabled
`amd_coder <https://localhost:47990/config/#amd_coder>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
78 changes: 45 additions & 33 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,24 +124,24 @@ namespace config {
};

enum class rc_av1_e : int {
cbr = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR,
cqp = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CONSTANT_QP,
vbr_latency = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR,
vbr_peak = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR,
cbr = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_CBR
vbr_peak = AMF_VIDEO_ENCODER_AV1_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR
};

enum class rc_hevc_e : int {
cbr = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR,
cqp = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP,
vbr_latency = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR,
vbr_peak = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR,
cbr = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR
vbr_peak = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR
};

enum class rc_h264_e : int {
cbr = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR,
cqp = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP,
vbr_latency = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR,
vbr_peak = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR,
cbr = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR
vbr_peak = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR
};

enum class usage_av1_e : int {
Expand Down Expand Up @@ -176,41 +176,53 @@ namespace config {

template <class T>
std::optional<int>
quality_from_view(const std::string_view &quality_type) {
quality_from_view(const std::string_view &quality_type, const std::optional<int>(&original)) {
#define _CONVERT_(x) \
if (quality_type == #x##sv) return (int) T::x
_CONVERT_(balanced);
_CONVERT_(quality);
_CONVERT_(speed);
_CONVERT_(balanced);
#undef _CONVERT_
return std::nullopt;
return original;
}

template <class T>
std::optional<int>
rc_from_view(const std::string_view &rc) {
rc_from_view(const std::string_view &rc, const std::optional<int>(&original)) {
#define _CONVERT_(x) \
if (rc == #x##sv) return (int) T::x
_CONVERT_(cbr);
_CONVERT_(cqp);
_CONVERT_(vbr_latency);
_CONVERT_(vbr_peak);
_CONVERT_(cbr);
#undef _CONVERT_
return std::nullopt;
return original;
}

template <class T>
std::optional<int>
usage_from_view(const std::string_view &usage) {
usage_from_view(const std::string_view &usage, const std::optional<int>(&original)) {
#define _CONVERT_(x) \
if (usage == #x##sv) return (int) T::x
_CONVERT_(transcoding);
_CONVERT_(webcam);
_CONVERT_(lowlatency);
_CONVERT_(lowlatency_high_quality);
_CONVERT_(transcoding);
_CONVERT_(ultralowlatency);
_CONVERT_(webcam);
#undef _CONVERT_
return std::nullopt;
return original;
}

template <class T>
std::optional<int>
enforce_hrd_from_view(const std::string_view &enforce_hrd, const std::optional<int>(&original)) {
#define _CONVERT_(x) \
if (enforce_hrd == #x##sv) return (int) T::x
_CONVERT_(_auto);
_CONVERT_(disabled);
_CONVERT_(enabled);
#undef _CONVERT_
return original;
}

int
Expand All @@ -219,7 +231,7 @@ namespace config {
if (coder == "cabac"sv || coder == "ac"sv) return cabac;
if (coder == "cavlc"sv || coder == "vlc"sv) return cavlc;

return -1;
return _auto;
}
} // namespace amd

Expand Down Expand Up @@ -350,18 +362,18 @@ namespace config {
}, // qsv

{
(int) amd::quality_h264_e::balanced, // quality (h264)
(int) amd::quality_hevc_e::balanced, // quality (hevc)
(int) amd::quality_av1_e::balanced, // quality (av1)
(int) amd::rc_h264_e::cbr, // rate control (h264)
(int) amd::rc_hevc_e::cbr, // rate control (hevc)
(int) amd::rc_av1_e::cbr, // rate control (av1)
(int) amd::usage_h264_e::ultralowlatency, // usage (h264)
(int) amd::usage_hevc_e::ultralowlatency, // usage (hevc)
(int) amd::usage_av1_e::ultralowlatency, // usage (av1)
(int) amd::rc_h264_e::vbr_latency, // rate control (h264)
(int) amd::rc_hevc_e::vbr_latency, // rate control (hevc)
(int) amd::rc_av1_e::vbr_latency, // rate control (av1)
1, // enforce_hrd
(int) amd::quality_h264_e::balanced, // quality (h264)
(int) amd::quality_hevc_e::balanced, // quality (hevc)
(int) amd::quality_av1_e::balanced, // quality (av1)
0, // preanalysis
1, // vbaq
1, // enforce_hrd
(int) amd::coder_e::_auto, // coder
}, // amd

Expand Down Expand Up @@ -982,26 +994,26 @@ namespace config {
std::string quality;
string_f(vars, "amd_quality", quality);
if (!quality.empty()) {
video.amd.amd_quality_h264 = amd::quality_from_view<amd::quality_h264_e>(quality);
video.amd.amd_quality_hevc = amd::quality_from_view<amd::quality_hevc_e>(quality);
video.amd.amd_quality_av1 = amd::quality_from_view<amd::quality_av1_e>(quality);
video.amd.amd_quality_h264 = amd::quality_from_view<amd::quality_h264_e>(quality, video.amd.amd_quality_h264);
video.amd.amd_quality_hevc = amd::quality_from_view<amd::quality_hevc_e>(quality, video.amd.amd_quality_hevc);
video.amd.amd_quality_av1 = amd::quality_from_view<amd::quality_av1_e>(quality, video.amd.amd_quality_av1);
}

std::string rc;
string_f(vars, "amd_rc", rc);
int_f(vars, "amd_coder", video.amd.amd_coder, amd::coder_from_view);
if (!rc.empty()) {
video.amd.amd_rc_h264 = amd::rc_from_view<amd::rc_h264_e>(rc);
video.amd.amd_rc_hevc = amd::rc_from_view<amd::rc_hevc_e>(rc);
video.amd.amd_rc_av1 = amd::rc_from_view<amd::rc_av1_e>(rc);
video.amd.amd_rc_h264 = amd::rc_from_view<amd::rc_h264_e>(rc, video.amd.amd_rc_h264);
video.amd.amd_rc_hevc = amd::rc_from_view<amd::rc_hevc_e>(rc, video.amd.amd_rc_hevc);
video.amd.amd_rc_av1 = amd::rc_from_view<amd::rc_av1_e>(rc, video.amd.amd_rc_av1);
}

std::string usage;
string_f(vars, "amd_usage", usage);
if (!usage.empty()) {
video.amd.amd_usage_h264 = amd::usage_from_view<amd::usage_h264_e>(usage);
video.amd.amd_usage_hevc = amd::usage_from_view<amd::usage_hevc_e>(usage);
video.amd.amd_usage_av1 = amd::usage_from_view<amd::usage_av1_e>(usage);
video.amd.amd_usage_h264 = amd::usage_from_view<amd::usage_h264_e>(usage, video.amd.amd_usage_h264);
video.amd.amd_usage_hevc = amd::usage_from_view<amd::usage_hevc_e>(usage, video.amd.amd_usage_hevc);
video.amd.amd_usage_av1 = amd::usage_from_view<amd::usage_av1_e>(usage, video.amd.amd_usage_av1);
}

bool_f(vars, "amd_preanalysis", (bool &) video.amd.amd_preanalysis);
Expand Down
14 changes: 7 additions & 7 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ namespace config {
} qsv;

struct {
std::optional<int> amd_quality_h264;
std::optional<int> amd_quality_hevc;
std::optional<int> amd_quality_av1;
std::optional<int> amd_rc_h264;
std::optional<int> amd_rc_hevc;
std::optional<int> amd_rc_av1;
std::optional<int> amd_usage_h264;
std::optional<int> amd_usage_hevc;
std::optional<int> amd_usage_av1;
std::optional<int> amd_rc_h264;
std::optional<int> amd_rc_hevc;
std::optional<int> amd_rc_av1;
int amd_enforce_hrd;
std::optional<int> amd_quality_h264;
std::optional<int> amd_quality_hevc;
std::optional<int> amd_quality_av1;
std::optional<int> amd_preanalysis;
std::optional<int> amd_vbaq;
std::optional<int> amd_enforce_hrd;
int amd_coder;
} amd;

Expand Down
Loading

0 comments on commit 405f9ad

Please sign in to comment.