diff mbox

[FFmpeg-devel,v2,01/11] vaapi_encode: Support more RC modes

Message ID 20190127234707.27689-1-sw@jkqxz.net
State Superseded
Headers show

Commit Message

Mark Thompson Jan. 27, 2019, 11:46 p.m. UTC
Allow setting the mode explicitly, and try to make a sensible choice
given the available parameters if not.
---
 doc/encoders.texi         |  24 +++
 libavcodec/vaapi_encode.c | 370 +++++++++++++++++++++++++++-----------
 libavcodec/vaapi_encode.h |  65 +++++++
 3 files changed, 351 insertions(+), 108 deletions(-)

Comments

Fu, Linjie Jan. 28, 2019, 2:19 a.m. UTC | #1
> -----Original Message-----

> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf

> Of Mark Thompson

> Sent: Monday, January 28, 2019 07:47

> To: ffmpeg-devel@ffmpeg.org

> Subject: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC

> modes

> 

> Allow setting the mode explicitly, and try to make a sensible choice

> given the available parameters if not.

> ---

>  doc/encoders.texi         |  24 +++

>  libavcodec/vaapi_encode.c | 370 +++++++++++++++++++++++++++---------

> --

>  libavcodec/vaapi_encode.h |  65 +++++++

>  3 files changed, 351 insertions(+), 108 deletions(-)

> 

> diff --git a/doc/encoders.texi b/doc/encoders.texi

> index e86ae69cc5..29625ba07c 100644

> --- a/doc/encoders.texi

> +++ b/doc/encoders.texi

> @@ -2824,6 +2824,30 @@ Set the B-frame reference depth.  When set to

> one (the default), all B-frames

>  will refer only to P- or I-frames.  When set to greater values multiple layers

>  of B-frames will be present, frames in each layer only referring to frames in

>  higher layers.

> +

> +@item rc_mode

> +Set the rate control mode to use.  A given driver may only support a subset

> of

> +modes.

> +

> +Possible modes:

> +@table @option

> +@item auto

> +Choose the mode automatically based on driver support and the other

> options.

> +This is the default.

> +@item CQP

> +Constant-quality.

> +@item CBR

> +Constant-bitrate.

> +@item VBR

> +Variable-bitrate.

> +@item ICQ

> +Intelligent constant-quality.

> +@item QVBR

> +Quality-defined variable-bitrate.

> +@item AVBR

> +Average variable bitrate.

> +@end table

> +

>  @end table

> 

>  Each encoder also has its own specific options:

> diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c

> index b4e9fadaee..d0e101b118 100644

> --- a/libavcodec/vaapi_encode.c

> +++ b/libavcodec/vaapi_encode.c

> @@ -1283,17 +1283,42 @@ fail:

>      return err;

>  }

> 

> +static const VAAPIEncodeRCMode vaapi_encode_rc_modes[] = {

> +    //                                  Bitrate   Quality

> +    //                                     | Maxrate | HRD/VBV

> +    { 0 }, //                              |    |    |    |

> +    { RC_MODE_CQP,  "CQP",  1, VA_RC_CQP,  0,   0,   1,   0 },

> +    { RC_MODE_CBR,  "CBR",  1, VA_RC_CBR,  1,   0,   0,   1 },

> +    { RC_MODE_VBR,  "VBR",  1, VA_RC_VBR,  1,   1,   0,   1 },

> +#if VA_CHECK_VERSION(1, 1, 0)

> +    { RC_MODE_ICQ,  "ICQ",  1, VA_RC_ICQ,  0,   0,   1,   0 },

> +#else

> +    { RC_MODE_ICQ,  "ICQ",  0 },

> +#endif

> +#if VA_CHECK_VERSION(1, 3, 0)

> +    { RC_MODE_QVBR, "QVBR", 1, VA_RC_QVBR, 1,   1,   1,   1 },

> +    { RC_MODE_AVBR, "AVBR", 0, VA_RC_AVBR, 1,   0,   0,   0 },

> +#else

> +    { RC_MODE_QVBR, "QVBR", 0 },

> +    { RC_MODE_AVBR, "AVBR", 0 },

> +#endif

> +};

> +

>  static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)

>  {

>      VAAPIEncodeContext *ctx = avctx->priv_data;

> +    uint32_t supported_va_rc_modes;

> +    const VAAPIEncodeRCMode *rc_mode;

>      int64_t rc_bits_per_second;

>      int     rc_target_percentage;

>      int     rc_window_size;

> +    int     rc_quality;

>      int64_t hrd_buffer_size;

>      int64_t hrd_initial_buffer_fullness;

>      int fr_num, fr_den;

>      VAConfigAttrib rc_attr = { VAConfigAttribRateControl };

>      VAStatus vas;

> +    char supported_rc_modes_string[64];

> 

>      vas = vaGetConfigAttributes(ctx->hwctx->display,

>                                  ctx->va_profile, ctx->va_entrypoint,

> @@ -1303,119 +1328,215 @@ static av_cold int

> vaapi_encode_init_rate_control(AVCodecContext *avctx)

>                 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));

>          return AVERROR_EXTERNAL;

>      }

> -

>      if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {

>          av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any "

> -               "supported rate control modes: assuming constant-quality.\n");

> -        ctx->va_rc_mode = VA_RC_CQP;

> -        return 0;

> -    }

> -    if (ctx->codec->flags & FLAG_CONSTANT_QUALITY_ONLY ||

> -        avctx->flags & AV_CODEC_FLAG_QSCALE ||

> -        avctx->bit_rate <= 0) {

> -        if (rc_attr.value & VA_RC_CQP) {

> -            av_log(avctx, AV_LOG_VERBOSE, "Using constant-quality mode.\n");

> -            ctx->va_rc_mode = VA_RC_CQP;

> -            if (avctx->bit_rate > 0 || avctx->rc_max_rate > 0) {

> -                av_log(avctx, AV_LOG_WARNING, "Bitrate target parameters "

> -                       "ignored in constant-quality mode.\n");

> +               "supported rate control modes: assuming CQP only.\n");

> +        supported_va_rc_modes = VA_RC_CQP;

> +        strcpy(supported_rc_modes_string, "unknown");

> +    } else {

> +        char *str = supported_rc_modes_string;

> +        size_t len = sizeof(supported_rc_modes_string);

> +        int i, first = 1, res;

> +

> +        supported_va_rc_modes = rc_attr.value;

> +

> +        first = 1;


Redundant “first” here I think.

> +        for (i = 0; i < FF_ARRAY_ELEMS(vaapi_encode_rc_modes); i++) {

> +            rc_mode = &vaapi_encode_rc_modes[i];

> +            if (supported_va_rc_modes & rc_mode->va_mode) {

> +                res = snprintf(str, len, "%s%s",

> +                               first ? "" : ", ", rc_mode->name);

> +                first = 0;

> +                if (res < 0) {

> +                    *str = 0;

> +                    break;

> +                }

> +                len -= res;

> +                str += res;

> +                if (len == 0)

> +                    break;

>              }

> -            return 0;

> -        } else {

> -            av_log(avctx, AV_LOG_ERROR, "Driver does not support "

> -                   "constant-quality mode (%#x).\n", rc_attr.value);

> -            return AVERROR(EINVAL);

>          }

> -    }

> 

> -    if (!(rc_attr.value & (VA_RC_CBR | VA_RC_VBR))) {

> -        av_log(avctx, AV_LOG_ERROR, "Driver does not support any "

> -               "bitrate-targetted rate control modes.\n");

> -        return AVERROR(EINVAL);

> +        av_log(avctx, AV_LOG_DEBUG, "Driver supports RC modes %s.\n",

> +               supported_rc_modes_string);

> +    }

> +

> +    // Rate control mode selection:

> +    // * If the user has set a mode explicitly with the rc_mode option,

> +    //   use it and fail if it is not available.

> +    // * If an explicit QP option has been set, use CQP.

> +    // * If the codec is CQ-only, use CQP.

> +    // * If the QSCALE avcodec option is set, use CQP.

> +    // * If bitrate and quality are both set, try QVBR.

> +    // * If quality is set, try ICQ, then CQP.

> +    // * If bitrate and maxrate are set and have the same value, try CBR.

> +    // * If a bitrate is set, try AVBR, then VBR, then CBR.

> +    // * If no bitrate is set, try ICQ, then CQP.

> +

> +#define TRY_RC_MODE(mode, fail) do { \

> +        rc_mode = &vaapi_encode_rc_modes[mode]; \

> +        if (!(rc_mode->va_mode & supported_va_rc_modes)) { \

> +            if (fail) { \

> +                av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \

> +                       "RC mode (supported modes: %s).\n", rc_mode->name, \

> +                       supported_rc_modes_string); \

> +                return AVERROR(EINVAL); \

> +            } \

> +            av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \

> +                   "RC mode.\n", rc_mode->name); \

> +            rc_mode = NULL; \

> +        } else { \

> +            goto rc_mode_found; \

> +        } \

> +    } while (0)

> +


Will it be better to put the definition of TRY_RC_MODE in the front of this file?

Thanks,
- Linjie
Eoff, Ullysses A Jan. 28, 2019, 4:23 a.m. UTC | #2
> -----Original Message-----

> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Mark Thompson

> Sent: Sunday, January 27, 2019 3:47 PM

> To: ffmpeg-devel@ffmpeg.org

> Subject: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes

> 

> Allow setting the mode explicitly, and try to make a sensible choice

> given the available parameters if not.

> ---

>  doc/encoders.texi         |  24 +++

>  libavcodec/vaapi_encode.c | 370 +++++++++++++++++++++++++++-----------

>  libavcodec/vaapi_encode.h |  65 +++++++

>  3 files changed, 351 insertions(+), 108 deletions(-)

> 

> diff --git a/doc/encoders.texi b/doc/encoders.texi

> index e86ae69cc5..29625ba07c 100644

> --- a/doc/encoders.texi

> +++ b/doc/encoders.texi

> @@ -2824,6 +2824,30 @@ Set the B-frame reference depth.  When set to one (the default), all B-frames

>  will refer only to P- or I-frames.  When set to greater values multiple layers

>  of B-frames will be present, frames in each layer only referring to frames in

>  higher layers.

> +

> +@item rc_mode

> +Set the rate control mode to use.  A given driver may only support a subset of

> +modes.

> +

> +Possible modes:

> +@table @option

> +@item auto

> +Choose the mode automatically based on driver support and the other options.

> +This is the default.

> +@item CQP

> +Constant-quality.

> +@item CBR

> +Constant-bitrate.

> +@item VBR

> +Variable-bitrate.

> +@item ICQ

> +Intelligent constant-quality.

> +@item QVBR

> +Quality-defined variable-bitrate.

> +@item AVBR

> +Average variable bitrate.

> +@end table

> +

>  @end table

> 

>  Each encoder also has its own specific options:

> diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c

> index b4e9fadaee..d0e101b118 100644

> --- a/libavcodec/vaapi_encode.c

> +++ b/libavcodec/vaapi_encode.c

> @@ -1283,17 +1283,42 @@ fail:

>      return err;

>  }

> 

> +static const VAAPIEncodeRCMode vaapi_encode_rc_modes[] = {

> +    //                                  Bitrate   Quality

> +    //                                     | Maxrate | HRD/VBV

> +    { 0 }, //                              |    |    |    |

> +    { RC_MODE_CQP,  "CQP",  1, VA_RC_CQP,  0,   0,   1,   0 },

> +    { RC_MODE_CBR,  "CBR",  1, VA_RC_CBR,  1,   0,   0,   1 },

> +    { RC_MODE_VBR,  "VBR",  1, VA_RC_VBR,  1,   1,   0,   1 },

> +#if VA_CHECK_VERSION(1, 1, 0)

> +    { RC_MODE_ICQ,  "ICQ",  1, VA_RC_ICQ,  0,   0,   1,   0 },

> +#else

> +    { RC_MODE_ICQ,  "ICQ",  0 },

> +#endif

> +#if VA_CHECK_VERSION(1, 3, 0)

> +    { RC_MODE_QVBR, "QVBR", 1, VA_RC_QVBR, 1,   1,   1,   1 },

> +    { RC_MODE_AVBR, "AVBR", 0, VA_RC_AVBR, 1,   0,   0,   0 },

> +#else

> +    { RC_MODE_QVBR, "QVBR", 0 },

> +    { RC_MODE_AVBR, "AVBR", 0 },

> +#endif

> +};

> +

>  static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)

>  {

>      VAAPIEncodeContext *ctx = avctx->priv_data;

> +    uint32_t supported_va_rc_modes;

> +    const VAAPIEncodeRCMode *rc_mode;

>      int64_t rc_bits_per_second;

>      int     rc_target_percentage;

>      int     rc_window_size;

> +    int     rc_quality;

>      int64_t hrd_buffer_size;

>      int64_t hrd_initial_buffer_fullness;

>      int fr_num, fr_den;

>      VAConfigAttrib rc_attr = { VAConfigAttribRateControl };

>      VAStatus vas;

> +    char supported_rc_modes_string[64];

> 

>      vas = vaGetConfigAttributes(ctx->hwctx->display,

>                                  ctx->va_profile, ctx->va_entrypoint,

> @@ -1303,119 +1328,215 @@ static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)

>                 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));

>          return AVERROR_EXTERNAL;

>      }

> -

>      if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {

>          av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any "

> -               "supported rate control modes: assuming constant-quality.\n");

> -        ctx->va_rc_mode = VA_RC_CQP;

> -        return 0;

> -    }

> -    if (ctx->codec->flags & FLAG_CONSTANT_QUALITY_ONLY ||

> -        avctx->flags & AV_CODEC_FLAG_QSCALE ||

> -        avctx->bit_rate <= 0) {

> -        if (rc_attr.value & VA_RC_CQP) {

> -            av_log(avctx, AV_LOG_VERBOSE, "Using constant-quality mode.\n");

> -            ctx->va_rc_mode = VA_RC_CQP;

> -            if (avctx->bit_rate > 0 || avctx->rc_max_rate > 0) {

> -                av_log(avctx, AV_LOG_WARNING, "Bitrate target parameters "

> -                       "ignored in constant-quality mode.\n");

> +               "supported rate control modes: assuming CQP only.\n");

> +        supported_va_rc_modes = VA_RC_CQP;

> +        strcpy(supported_rc_modes_string, "unknown");

> +    } else {

> +        char *str = supported_rc_modes_string;

> +        size_t len = sizeof(supported_rc_modes_string);

> +        int i, first = 1, res;

> +

> +        supported_va_rc_modes = rc_attr.value;

> +

> +        first = 1;

> +        for (i = 0; i < FF_ARRAY_ELEMS(vaapi_encode_rc_modes); i++) {

> +            rc_mode = &vaapi_encode_rc_modes[i];

> +            if (supported_va_rc_modes & rc_mode->va_mode) {

> +                res = snprintf(str, len, "%s%s",

> +                               first ? "" : ", ", rc_mode->name);

> +                first = 0;

> +                if (res < 0) {

> +                    *str = 0;

> +                    break;

> +                }

> +                len -= res;

> +                str += res;

> +                if (len == 0)

> +                    break;

>              }

> -            return 0;

> -        } else {

> -            av_log(avctx, AV_LOG_ERROR, "Driver does not support "

> -                   "constant-quality mode (%#x).\n", rc_attr.value);

> -            return AVERROR(EINVAL);

>          }

> -    }

> 

> -    if (!(rc_attr.value & (VA_RC_CBR | VA_RC_VBR))) {

> -        av_log(avctx, AV_LOG_ERROR, "Driver does not support any "

> -               "bitrate-targetted rate control modes.\n");

> -        return AVERROR(EINVAL);

> +        av_log(avctx, AV_LOG_DEBUG, "Driver supports RC modes %s.\n",

> +               supported_rc_modes_string);

> +    }

> +

> +    // Rate control mode selection:

> +    // * If the user has set a mode explicitly with the rc_mode option,

> +    //   use it and fail if it is not available.

> +    // * If an explicit QP option has been set, use CQP.

> +    // * If the codec is CQ-only, use CQP.

> +    // * If the QSCALE avcodec option is set, use CQP.

> +    // * If bitrate and quality are both set, try QVBR.

> +    // * If quality is set, try ICQ, then CQP.

> +    // * If bitrate and maxrate are set and have the same value, try CBR.

> +    // * If a bitrate is set, try AVBR, then VBR, then CBR.

> +    // * If no bitrate is set, try ICQ, then CQP.

> +

> +#define TRY_RC_MODE(mode, fail) do { \

> +        rc_mode = &vaapi_encode_rc_modes[mode]; \

> +        if (!(rc_mode->va_mode & supported_va_rc_modes)) { \

> +            if (fail) { \

> +                av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \

> +                       "RC mode (supported modes: %s).\n", rc_mode->name, \

> +                       supported_rc_modes_string); \

> +                return AVERROR(EINVAL); \

> +            } \

> +            av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \

> +                   "RC mode.\n", rc_mode->name); \

> +            rc_mode = NULL; \

> +        } else { \

> +            goto rc_mode_found; \

> +        } \

> +    } while (0)

> +

> +    if (ctx->explicit_rc_mode)

> +        TRY_RC_MODE(ctx->explicit_rc_mode, 1);

> +

> +    if (ctx->explicit_qp)

> +        TRY_RC_MODE(RC_MODE_CQP, 1);

> +

> +    if (ctx->codec->flags & FLAG_CONSTANT_QUALITY_ONLY)

> +        TRY_RC_MODE(RC_MODE_CQP, 1);

> +

> +    if (avctx->flags & AV_CODEC_FLAG_QSCALE)

> +        TRY_RC_MODE(RC_MODE_CQP, 1);

> +

> +    if (avctx->bit_rate > 0 && avctx->global_quality > 0)

> +        TRY_RC_MODE(RC_MODE_QVBR, 0);

> +

> +    if (avctx->global_quality > 0) {

> +        TRY_RC_MODE(RC_MODE_ICQ, 0);

> +        TRY_RC_MODE(RC_MODE_CQP, 0);

> +    }

> +

> +    if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate)

> +        TRY_RC_MODE(RC_MODE_CBR, 0);

> +

> +    if (avctx->bit_rate > 0) {

> +        TRY_RC_MODE(RC_MODE_AVBR, 0);

> +        TRY_RC_MODE(RC_MODE_VBR, 0);

> +        TRY_RC_MODE(RC_MODE_CBR, 0);

> +    } else {

> +        TRY_RC_MODE(RC_MODE_ICQ, 0);

> +        TRY_RC_MODE(RC_MODE_CQP, 0);

>      }

> 

> -    if (avctx->rc_buffer_size)

> -        hrd_buffer_size = avctx->rc_buffer_size;

> -    else if (avctx->rc_max_rate > 0)

> -        hrd_buffer_size = avctx->rc_max_rate;

> -    else

> -        hrd_buffer_size = avctx->bit_rate;

> -    if (avctx->rc_initial_buffer_occupancy) {

> -        if (avctx->rc_initial_buffer_occupancy > hrd_buffer_size) {

> -            av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: "

> -                   "must have initial buffer size (%d) < "

> -                   "buffer size (%"PRId64").\n",

> -                   avctx->rc_initial_buffer_occupancy, hrd_buffer_size);

> +    av_log(avctx, AV_LOG_ERROR, "Driver does not support any "

> +           "RC mode compatible with selected options "

> +           "(supported modes: %s).\n", supported_rc_modes_string);

> +    return AVERROR(EINVAL);

> +

> +rc_mode_found:

> +    if (rc_mode->bitrate) {

> +        if (avctx->bit_rate <= 0) {

> +            av_log(avctx, AV_LOG_ERROR, "Bitrate must be set for %s "

> +                   "RC mode.\n", rc_mode->name);

>              return AVERROR(EINVAL);

>          }

> -        hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy;

> -    } else {

> -        hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4;

> -    }

> 

> -    if (avctx->rc_max_rate && avctx->rc_max_rate < avctx->bit_rate) {

> -        av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: must have "

> -               "bitrate (%"PRId64") <= maxrate (%"PRId64").\n",

> -               avctx->bit_rate, avctx->rc_max_rate);

> -        return AVERROR(EINVAL);

> -    }

> +        if (rc_mode->mode == RC_MODE_AVBR) {

> +            // For maximum confusion AVBR is hacked into the existing API

> +            // by overloading some of the fields with completely different

> +            // meanings.

> 

> -    if (avctx->rc_max_rate > avctx->bit_rate) {

> -        if (!(rc_attr.value & VA_RC_VBR)) {

> -            av_log(avctx, AV_LOG_WARNING, "Driver does not support "

> -                   "VBR mode (%#x), using CBR mode instead.\n",

> -                   rc_attr.value);

> -            ctx->va_rc_mode = VA_RC_CBR;

> +            // Target percentage does not apply in AVBR mode.

> +            rc_bits_per_second = avctx->bit_rate;

> 

> -            rc_bits_per_second   = avctx->bit_rate;

> +            // Accuracy tolerance range for meeting the specified target

> +            // bitrate.  It's very unclear how this is actually intended

> +            // to work - since we do want to get the specified bitrate,

> +            // set the accuracy to 100% for now.

>              rc_target_percentage = 100;

> -        } else {

> -            ctx->va_rc_mode = VA_RC_VBR;

> -

> -            rc_bits_per_second   = avctx->rc_max_rate;

> -            rc_target_percentage = (avctx->bit_rate * 100) /

> -                                   avctx->rc_max_rate;

> -        }

> 

> -    } else if (avctx->rc_max_rate == avctx->bit_rate) {

> -        if (!(rc_attr.value & VA_RC_CBR)) {

> -            av_log(avctx, AV_LOG_WARNING, "Driver does not support "

> -                   "CBR mode (%#x), using VBR mode instead.\n",

> -                   rc_attr.value);

> -            ctx->va_rc_mode = VA_RC_VBR;

> +            // Convergence period in frames.  The GOP size reflects the

> +            // user's intended block size for cutting, so reusing that

> +            // as the convergence period seems a reasonable default.

> +            rc_window_size = avctx->gop_size > 0 ? avctx->gop_size : 60;

> +

> +        } else if (rc_mode->maxrate) {

> +            if (avctx->rc_max_rate > 0) {

> +                if (avctx->rc_max_rate < avctx->bit_rate) {

> +                    av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: "

> +                           "bitrate (%"PRId64") must not be greater than "

> +                           "maxrate (%"PRId64").\n", avctx->bit_rate,

> +                           avctx->rc_max_rate);

> +                    return AVERROR(EINVAL);

> +                }

> +                rc_bits_per_second   = avctx->rc_max_rate;

> +                rc_target_percentage = (avctx->bit_rate * 100) /

> +                                       avctx->rc_max_rate;

> +            } else {

> +                // We only have a target bitrate, but this mode requires

> +                // that a maximum rate be supplied as well.  Since the

> +                // user does not want this to be a constraint, arbitrarily

> +                // pick a maximum rate of double the target rate.

> +                rc_bits_per_second   = 2 * avctx->bit_rate;

> +                rc_target_percentage = 50;

> +            }

>          } else {

> -            ctx->va_rc_mode = VA_RC_CBR;

> +            if (avctx->rc_max_rate > avctx->bit_rate) {

> +                av_log(avctx, AV_LOG_WARNING, "Max bitrate is ignored "

> +                       "in %s RC mode.\n", rc_mode->name);

> +            }

> +            rc_bits_per_second   = avctx->bit_rate;

> +            rc_target_percentage = 100;

>          }

> -

> -        rc_bits_per_second   = avctx->bit_rate;

> +    } else {

> +        rc_bits_per_second   = 0;

>          rc_target_percentage = 100;

> +    }

> 

> +    if (rc_mode->quality) {

> +        if (ctx->explicit_qp) {

> +            rc_quality = ctx->explicit_qp;

> +        } else if (avctx->global_quality > 0) {

> +            rc_quality = avctx->global_quality;

> +        } else {

> +            rc_quality = ctx->codec->default_quality;

> +            av_log(avctx, AV_LOG_WARNING, "No quality level set; "

> +                   "using default (%d).\n", rc_quality);

> +        }

>      } else {

> -        if (rc_attr.value & VA_RC_VBR) {

> -            ctx->va_rc_mode = VA_RC_VBR;

> -

> -            // We only have a target bitrate, but VAAPI requires that a

> -            // maximum rate be supplied as well.  Since the user has

> -            // offered no particular constraint, arbitrarily pick a

> -            // maximum rate of double the target rate.

> -            rc_bits_per_second   = 2 * avctx->bit_rate;

> -            rc_target_percentage = 50;

> +        rc_quality = 0;

> +    }

> +

> +    if (rc_mode->hrd) {

> +        if (avctx->rc_buffer_size)

> +            hrd_buffer_size = avctx->rc_buffer_size;

> +        else if (avctx->rc_max_rate > 0)

> +            hrd_buffer_size = avctx->rc_max_rate;

> +        else

> +            hrd_buffer_size = avctx->bit_rate;

> +        if (avctx->rc_initial_buffer_occupancy) {

> +            if (avctx->rc_initial_buffer_occupancy > hrd_buffer_size) {

> +                av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: "

> +                       "must have initial buffer size (%d) <= "

> +                       "buffer size (%"PRId64").\n",

> +                       avctx->rc_initial_buffer_occupancy, hrd_buffer_size);

> +                return AVERROR(EINVAL);

> +            }

> +            hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy;

>          } else {

> -            ctx->va_rc_mode = VA_RC_CBR;

> +            hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4;

> +        }

> 

> -            rc_bits_per_second   = avctx->bit_rate;

> -            rc_target_percentage = 100;

> +        rc_window_size = (hrd_buffer_size * 1000) / rc_bits_per_second;

> +    } else {

> +        if (avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {

> +            av_log(avctx, AV_LOG_WARNING, "Buffering settings are ignored "

> +                   "in %s RC mode.\n", rc_mode->name);

>          }

> -    }

> 

> -    rc_window_size = (hrd_buffer_size * 1000) / rc_bits_per_second;

> +        hrd_buffer_size             = 0;

> +        hrd_initial_buffer_fullness = 0;

> 

> -    av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s, %d%% of %"PRId64" bps "

> -           "over %d ms.\n", ctx->va_rc_mode == VA_RC_VBR ? "VBR" : "CBR",

> -           rc_target_percentage, rc_bits_per_second, rc_window_size);

> -    av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, "

> -           "initial fullness %"PRId64" bits.\n",

> -           hrd_buffer_size, hrd_initial_buffer_fullness);

> +        if (rc_mode->mode != RC_MODE_AVBR) {

> +            // Already set (with completely different meaning) for AVBR.

> +            rc_window_size = 1000;

> +        }

> +    }

> 

>      if (rc_bits_per_second          > UINT32_MAX ||

>          hrd_buffer_size             > UINT32_MAX ||

> @@ -1425,36 +1546,66 @@ static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)

>          return AVERROR(EINVAL);

>      }

> 

> +    ctx->rc_mode     = rc_mode;

> +    ctx->rc_quality  = rc_quality;

> +    ctx->va_rc_mode  = rc_mode->va_mode;

>      ctx->va_bit_rate = rc_bits_per_second;

> 

> +    av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s.\n", rc_mode->name);

>      ctx->config_attributes[ctx->nb_config_attributes++] =

>          (VAConfigAttrib) {

>          .type  = VAConfigAttribRateControl,

>          .value = ctx->va_rc_mode,

>      };

> 

> -    ctx->rc_params.misc.type = VAEncMiscParameterTypeRateControl;

> -    ctx->rc_params.rc = (VAEncMiscParameterRateControl) {

> -        .bits_per_second   = rc_bits_per_second,

> -        .target_percentage = rc_target_percentage,

> -        .window_size       = rc_window_size,

> -        .initial_qp        = 0,

> -        .min_qp            = (avctx->qmin > 0 ? avctx->qmin : 0),

> -        .basic_unit_size   = 0,

> +    if (rc_mode->quality)

> +        av_log(avctx, AV_LOG_VERBOSE, "RC quality: %d.\n", rc_quality);

> +

> +    if (rc_mode->va_mode != VA_RC_CQP) {

> +        if (rc_mode->mode == RC_MODE_AVBR) {

> +            av_log(avctx, AV_LOG_VERBOSE, "RC target: %"PRId64" bps "

> +                   "converging in %d frames with %d%% accuracy.\n",

> +                   rc_bits_per_second, rc_window_size,

> +                   rc_target_percentage);

> +        } else if (rc_mode->bitrate) {

> +            av_log(avctx, AV_LOG_VERBOSE, "RC target: %d%% of "

> +                   "%"PRId64" bps over %d ms.\n", rc_target_percentage,

> +                   rc_bits_per_second, rc_window_size);

> +        }

> +

> +        ctx->rc_params.misc.type = VAEncMiscParameterTypeRateControl;

> +        ctx->rc_params.rc = (VAEncMiscParameterRateControl) {

> +            .bits_per_second    = rc_bits_per_second,

> +            .target_percentage  = rc_target_percentage,

> +            .window_size        = rc_window_size,

> +            .initial_qp         = 0,

> +            .min_qp             = (avctx->qmin > 0 ? avctx->qmin : 0),

> +            .basic_unit_size    = 0,

>  #if VA_CHECK_VERSION(1, 1, 0)

> -        .max_qp            = (avctx->qmax > 0 ? avctx->qmax : 0),

> +            .ICQ_quality_factor = av_clip(rc_quality, 1, 51),

> +            .max_qp             = (avctx->qmax > 0 ? avctx->qmax : 0),

>  #endif

> -    };

> -    vaapi_encode_add_global_param(avctx, &ctx->rc_params.misc,

> -                                  sizeof(ctx->rc_params));

> +#if VA_CHECK_VERSION(1, 3, 0)

> +            .quality_factor     = rc_quality,

> +#endif

> +        };

> +        vaapi_encode_add_global_param(avctx, &ctx->rc_params.misc,

> +                                      sizeof(ctx->rc_params));

> +    }

> 

> -    ctx->hrd_params.misc.type = VAEncMiscParameterTypeHRD;

> -    ctx->hrd_params.hrd = (VAEncMiscParameterHRD) {

> -        .initial_buffer_fullness = hrd_initial_buffer_fullness,

> -        .buffer_size             = hrd_buffer_size,

> -    };

> -    vaapi_encode_add_global_param(avctx, &ctx->hrd_params.misc,

> -                                  sizeof(ctx->hrd_params));

> +    if (rc_mode->hrd) {

> +        av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, "

> +               "initial fullness %"PRId64" bits.\n",

> +               hrd_buffer_size, hrd_initial_buffer_fullness);

> +

> +        ctx->hrd_params.misc.type = VAEncMiscParameterTypeHRD;

> +        ctx->hrd_params.hrd = (VAEncMiscParameterHRD) {

> +            .initial_buffer_fullness = hrd_initial_buffer_fullness,

> +            .buffer_size             = hrd_buffer_size,

> +        };

> +        vaapi_encode_add_global_param(avctx, &ctx->hrd_params.misc,

> +                                      sizeof(ctx->hrd_params));

> +    }

> 

>      if (avctx->framerate.num > 0 && avctx->framerate.den > 0)

>          av_reduce(&fr_num, &fr_den,

> @@ -1463,6 +1614,9 @@ static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)

>          av_reduce(&fr_num, &fr_den,

>                    avctx->time_base.den, avctx->time_base.num, 65535);

> 

> +    av_log(avctx, AV_LOG_VERBOSE, "RC framerate: %d/%d (%.2f fps).\n",

> +           fr_num, fr_den, (double)fr_num / fr_den);

> +

>      ctx->fr_params.misc.type = VAEncMiscParameterTypeFrameRate;

>      ctx->fr_params.fr.framerate = (unsigned int)fr_den << 16 | fr_num;

> 

> diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h

> index a4206865ea..44a8db566e 100644

> --- a/libavcodec/vaapi_encode.h

> +++ b/libavcodec/vaapi_encode.h

> @@ -129,6 +129,36 @@ typedef struct VAAPIEncodeProfile {

>      VAProfile va_profile;

>  } VAAPIEncodeProfile;

> 

> +enum {

> +    RC_MODE_AUTO,

> +    RC_MODE_CQP,

> +    RC_MODE_CBR,

> +    RC_MODE_VBR,

> +    RC_MODE_ICQ,

> +    RC_MODE_QVBR,

> +    RC_MODE_AVBR,

> +    RC_MODE_MAX = RC_MODE_AVBR,

> +};

> +

> +typedef struct VAAPIEncodeRCMode {

> +    // Mode from above enum (RC_MODE_*).

> +    int mode;

> +    // Name.

> +    const char *name;

> +    // Supported in the compile-time VAAPI version.

> +    int supported;

> +    // VA mode value (VA_RC_*).

> +    uint32_t va_mode;

> +    // Uses bitrate parameters.

> +    int bitrate;

> +    // Supports maxrate distinct from bitrate.

> +    int maxrate;

> +    // Uses quality value.

> +    int quality;

> +    // Supports HRD/VBV parameters.

> +    int hrd;

> +} VAAPIEncodeRCMode;

> +

>  typedef struct VAAPIEncodeContext {

>      const AVClass *class;

> 

> @@ -146,6 +176,14 @@ typedef struct VAAPIEncodeContext {

>      // Desired B frame reference depth.

>      int             desired_b_depth;

> 

> +    // Explicitly set RC mode (otherwise attempt to pick from

> +    // available modes).

> +    int             explicit_rc_mode;

> +

> +    // Explicitly-set QP, for use with the "qp" options.

> +    // (Forces CQP mode when set, overriding everything else.)

> +    int             explicit_qp;

> +

>      // Desired packed headers.

>      unsigned int    desired_packed_headers;

> 

> @@ -165,6 +203,12 @@ typedef struct VAAPIEncodeContext {

>      // Chosen encoding profile details.

>      const VAAPIEncodeProfile *profile;

> 

> +    // Chosen rate control mode details.

> +    const VAAPIEncodeRCMode *rc_mode;

> +    // RC quality level - meaning depends on codec and RC mode.

> +    // In CQP mode this sets the fixed quantiser value.

> +    int             rc_quality;

> +

>      // Encoding profile (VAProfile*).

>      VAProfile       va_profile;

>      // Encoding entrypoint (VAEntryoint*).

> @@ -296,6 +340,10 @@ typedef struct VAAPIEncodeType {

>      // Codec feature flags.

>      int flags;

> 

> +    // Default quality for this codec - used as quantiser or RC quality

> +    // factor depending on RC mode.

> +    int default_quality;

> +

>      // Perform any extra codec-specific configuration after the

>      // codec context is initialised (set up the private data and

>      // add any necessary global parameters).

> @@ -382,5 +430,22 @@ int ff_vaapi_encode_close(AVCodecContext *avctx);

>        OFFSET(common.desired_b_depth), AV_OPT_TYPE_INT, \

>        { .i64 = 1 }, 1, INT_MAX, FLAGS }

> 

> +#define VAAPI_ENCODE_RC_MODE(name, desc) \

> +    { #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_ ## name }, \

> +      0, 0, FLAGS, "rc_mode" }

> +#define VAAPI_ENCODE_RC_OPTIONS \

> +    { "rc_mode",\

> +      "Set rate control mode", \

> +      OFFSET(common.explicit_rc_mode), AV_OPT_TYPE_INT, \

> +      { .i64 = RC_MODE_AUTO }, RC_MODE_AUTO, RC_MODE_MAX, FLAGS, "rc_mode" }, \

> +    { "auto", "Choose mode automatically based on other parameters", \

> +      0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_AUTO }, 0, 0, FLAGS, "rc_mode" }, \

> +    VAAPI_ENCODE_RC_MODE(CQP,  "Constant-quality"), \

> +    VAAPI_ENCODE_RC_MODE(CBR,  "Constant-bitrate"), \

> +    VAAPI_ENCODE_RC_MODE(VBR,  "Variable-bitrate"), \

> +    VAAPI_ENCODE_RC_MODE(ICQ,  "Intelligent constant-quality"), \

> +    VAAPI_ENCODE_RC_MODE(QVBR, "Quality-defined variable-bitrate"), \

> +    VAAPI_ENCODE_RC_MODE(AVBR, "Average variable-bitrate")

> +

> 

>  #endif /* AVCODEC_VAAPI_ENCODE_H */

> --

> 2.19.2

> 


With this patch series, mjpeg_vaapi encoder breaks with iHD driver:

LIBVA_DRIVER_NAME=iHD ffmpeg -hwaccel vaapi \
  -vaapi_device /dev/dri/renderD128 -v debug \
  -f rawvideo -pix_fmt yuv420p -s:v 1920x1080 \
  -i input.yuv -vf 'format=nv12,hwupload' -c:v mjpeg_vaapi \
  -global_quality 100 -vframes 10 -y output.mjpg

<snip>
[AVHWDeviceContext @ 0x193c580] Opened VA display via DRM device /dev/dri/renderD128.
[AVHWDeviceContext @ 0x193c580] libva: VA-API version 1.4.0
[AVHWDeviceContext @ 0x193c580] libva: va_getDriverName() returns 0
[AVHWDeviceContext @ 0x193c580] libva: User requested driver 'iHD'
[AVHWDeviceContext @ 0x193c580] libva: Trying to open /home/uaeoff/Work/workspace/media/install/lib/dri/iHD_drv_video.so
[AVHWDeviceContext @ 0x193c580] libva: Found init function __vaDriverInit_1_4
[AVHWDeviceContext @ 0x193c580] libva: va_openDriver() returns 0
[AVHWDeviceContext @ 0x193c580] Initialised VAAPI connection: version 1.4
<snip>
[mjpeg_vaapi @ 0x19847c0] Input surface format is nv12.
[mjpeg_vaapi @ 0x19847c0] Using VAAPI profile VAProfileJPEGBaseline (12).
[mjpeg_vaapi @ 0x19847c0] Using VAAPI entrypoint VAEntrypointEncPicture (7).
[mjpeg_vaapi @ 0x19847c0] Using VAAPI render target format YUV420 (0x1).
[mjpeg_vaapi @ 0x19847c0] Driver does not report any supported rate control modes: assuming CQP only.
[mjpeg_vaapi @ 0x19847c0] RC mode: CQP.
[mjpeg_vaapi @ 0x19847c0] RC quality: 100.
[mjpeg_vaapi @ 0x19847c0] RC framerate (CFR mode): 25/1 (25.00 fps).
[mjpeg_vaapi @ 0x19847c0] Using intra frames only.
[mjpeg_vaapi @ 0x19847c0] All wanted packed headers available (wanted 0x10, found 0x10).
[mjpeg_vaapi @ 0x19847c0] Failed to create encode pipeline configuration: 10 (attribute not supported).
Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or height
[AVIOContext @ 0x1987000] Statistics: 0 seeks, 0 writeouts
[AVIOContext @ 0x19802c0] Statistics: 3110400 bytes read, 0 seeks
Conversion failed!

... it works fine on i965 driver.

Regards,
U. Artie Eoff

> _______________________________________________

> ffmpeg-devel mailing list

> ffmpeg-devel@ffmpeg.org

> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Mark Thompson Feb. 4, 2019, 9:23 a.m. UTC | #3
On 28/01/2019 02:19, Fu, Linjie wrote:
>> -----Original Message-----
>> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf
>> Of Mark Thompson
>> Sent: Monday, January 28, 2019 07:47
>> To: ffmpeg-devel@ffmpeg.org
>> Subject: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC
>> modes
>>
>> Allow setting the mode explicitly, and try to make a sensible choice
>> given the available parameters if not.
>> ---
>>  doc/encoders.texi         |  24 +++
>>  libavcodec/vaapi_encode.c | 370 +++++++++++++++++++++++++++---------
>> --
>>  libavcodec/vaapi_encode.h |  65 +++++++
>>  3 files changed, 351 insertions(+), 108 deletions(-)
>>
>> ...
>> +
>>  static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)
>>  {
>>      VAAPIEncodeContext *ctx = avctx->priv_data;
>> +    uint32_t supported_va_rc_modes;
>> +    const VAAPIEncodeRCMode *rc_mode;
>>      int64_t rc_bits_per_second;
>>      int     rc_target_percentage;
>>      int     rc_window_size;
>> +    int     rc_quality;
>>      int64_t hrd_buffer_size;
>>      int64_t hrd_initial_buffer_fullness;
>>      int fr_num, fr_den;
>>      VAConfigAttrib rc_attr = { VAConfigAttribRateControl };
>>      VAStatus vas;
>> +    char supported_rc_modes_string[64];
>>
>>      vas = vaGetConfigAttributes(ctx->hwctx->display,
>>                                  ctx->va_profile, ctx->va_entrypoint,
>> @@ -1303,119 +1328,215 @@ static av_cold int
>> vaapi_encode_init_rate_control(AVCodecContext *avctx)
>>                 "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
>>          return AVERROR_EXTERNAL;
>>      }
>> -
>>      if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {
>>          av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any "
>> -               "supported rate control modes: assuming constant-quality.\n");
>> -        ctx->va_rc_mode = VA_RC_CQP;
>> -        return 0;
>> -    }
>> -    if (ctx->codec->flags & FLAG_CONSTANT_QUALITY_ONLY ||
>> -        avctx->flags & AV_CODEC_FLAG_QSCALE ||
>> -        avctx->bit_rate <= 0) {
>> -        if (rc_attr.value & VA_RC_CQP) {
>> -            av_log(avctx, AV_LOG_VERBOSE, "Using constant-quality mode.\n");
>> -            ctx->va_rc_mode = VA_RC_CQP;
>> -            if (avctx->bit_rate > 0 || avctx->rc_max_rate > 0) {
>> -                av_log(avctx, AV_LOG_WARNING, "Bitrate target parameters "
>> -                       "ignored in constant-quality mode.\n");
>> +               "supported rate control modes: assuming CQP only.\n");
>> +        supported_va_rc_modes = VA_RC_CQP;
>> +        strcpy(supported_rc_modes_string, "unknown");
>> +    } else {
>> +        char *str = supported_rc_modes_string;
>> +        size_t len = sizeof(supported_rc_modes_string);
>> +        int i, first = 1, res;
>> +
>> +        supported_va_rc_modes = rc_attr.value;
>> +
>> +        first = 1;
> 
> Redundant “first” here I think.

Yep, removed.

>> +        for (i = 0; i < FF_ARRAY_ELEMS(vaapi_encode_rc_modes); i++) {
>> +            rc_mode = &vaapi_encode_rc_modes[i];
>> +            if (supported_va_rc_modes & rc_mode->va_mode) {
>> +                res = snprintf(str, len, "%s%s",
>> +                               first ? "" : ", ", rc_mode->name);
>> +                first = 0;
>> +                if (res < 0) {
>> +                    *str = 0;
>> +                    break;
>> +                }
>> +                len -= res;
>> +                str += res;
>> +                if (len == 0)
>> +                    break;
>>              }
>> -            return 0;
>> -        } else {
>> -            av_log(avctx, AV_LOG_ERROR, "Driver does not support "
>> -                   "constant-quality mode (%#x).\n", rc_attr.value);
>> -            return AVERROR(EINVAL);
>>          }
>> -    }
>>
>> -    if (!(rc_attr.value & (VA_RC_CBR | VA_RC_VBR))) {
>> -        av_log(avctx, AV_LOG_ERROR, "Driver does not support any "
>> -               "bitrate-targetted rate control modes.\n");
>> -        return AVERROR(EINVAL);
>> +        av_log(avctx, AV_LOG_DEBUG, "Driver supports RC modes %s.\n",
>> +               supported_rc_modes_string);
>> +    }
>> +
>> +    // Rate control mode selection:
>> +    // * If the user has set a mode explicitly with the rc_mode option,
>> +    //   use it and fail if it is not available.
>> +    // * If an explicit QP option has been set, use CQP.
>> +    // * If the codec is CQ-only, use CQP.
>> +    // * If the QSCALE avcodec option is set, use CQP.
>> +    // * If bitrate and quality are both set, try QVBR.
>> +    // * If quality is set, try ICQ, then CQP.
>> +    // * If bitrate and maxrate are set and have the same value, try CBR.
>> +    // * If a bitrate is set, try AVBR, then VBR, then CBR.
>> +    // * If no bitrate is set, try ICQ, then CQP.
>> +
>> +#define TRY_RC_MODE(mode, fail) do { \
>> +        rc_mode = &vaapi_encode_rc_modes[mode]; \
>> +        if (!(rc_mode->va_mode & supported_va_rc_modes)) { \
>> +            if (fail) { \
>> +                av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \
>> +                       "RC mode (supported modes: %s).\n", rc_mode->name, \
>> +                       supported_rc_modes_string); \
>> +                return AVERROR(EINVAL); \
>> +            } \
>> +            av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \
>> +                   "RC mode.\n", rc_mode->name); \
>> +            rc_mode = NULL; \
>> +        } else { \
>> +            goto rc_mode_found; \
>> +        } \
>> +    } while (0)
>> +
> 
> Will it be better to put the definition of TRY_RC_MODE in the front of this file?

I don't think so?  Putting it here makes it clear that it is function-local, using jumps and stack variables which wouldn't be accessible outside the function.  It's also right next to all of the uses, so it's easy to see how any given use will expand.  Since it is local it probably should be #undef'ed at the end of the block using it, though, so I've added that.

Thanks,

- Mark
Mark Thompson Feb. 4, 2019, 9:26 a.m. UTC | #4
On 28/01/2019 04:23, Eoff, Ullysses A wrote:
>> -----Original Message-----
>> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Mark Thompson
>> Sent: Sunday, January 27, 2019 3:47 PM
>> To: ffmpeg-devel@ffmpeg.org
>> Subject: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes
>>
>> Allow setting the mode explicitly, and try to make a sensible choice
>> given the available parameters if not.
>> ---
>>  doc/encoders.texi         |  24 +++
>>  libavcodec/vaapi_encode.c | 370 +++++++++++++++++++++++++++-----------
>>  libavcodec/vaapi_encode.h |  65 +++++++
>>  3 files changed, 351 insertions(+), 108 deletions(-)
>>
>> ...
>>      if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {
>>          av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any "
>> -               "supported rate control modes: assuming constant-quality.\n");
>> -        ctx->va_rc_mode = VA_RC_CQP;
>> -        return 0;
>> ...
> 
> With this patch series, mjpeg_vaapi encoder breaks with iHD driver:
> 
> LIBVA_DRIVER_NAME=iHD ffmpeg -hwaccel vaapi \
>   -vaapi_device /dev/dri/renderD128 -v debug \
>   -f rawvideo -pix_fmt yuv420p -s:v 1920x1080 \
>   -i input.yuv -vf 'format=nv12,hwupload' -c:v mjpeg_vaapi \
>   -global_quality 100 -vframes 10 -y output.mjpg
> 
> <snip>
> [AVHWDeviceContext @ 0x193c580] Opened VA display via DRM device /dev/dri/renderD128.
> [AVHWDeviceContext @ 0x193c580] libva: VA-API version 1.4.0
> [AVHWDeviceContext @ 0x193c580] libva: va_getDriverName() returns 0
> [AVHWDeviceContext @ 0x193c580] libva: User requested driver 'iHD'
> [AVHWDeviceContext @ 0x193c580] libva: Trying to open /home/uaeoff/Work/workspace/media/install/lib/dri/iHD_drv_video.so
> [AVHWDeviceContext @ 0x193c580] libva: Found init function __vaDriverInit_1_4
> [AVHWDeviceContext @ 0x193c580] libva: va_openDriver() returns 0
> [AVHWDeviceContext @ 0x193c580] Initialised VAAPI connection: version 1.4
> <snip>
> [mjpeg_vaapi @ 0x19847c0] Input surface format is nv12.
> [mjpeg_vaapi @ 0x19847c0] Using VAAPI profile VAProfileJPEGBaseline (12).
> [mjpeg_vaapi @ 0x19847c0] Using VAAPI entrypoint VAEntrypointEncPicture (7).
> [mjpeg_vaapi @ 0x19847c0] Using VAAPI render target format YUV420 (0x1).
> [mjpeg_vaapi @ 0x19847c0] Driver does not report any supported rate control modes: assuming CQP only.
> [mjpeg_vaapi @ 0x19847c0] RC mode: CQP.
> [mjpeg_vaapi @ 0x19847c0] RC quality: 100.
> [mjpeg_vaapi @ 0x19847c0] RC framerate (CFR mode): 25/1 (25.00 fps).
> [mjpeg_vaapi @ 0x19847c0] Using intra frames only.
> [mjpeg_vaapi @ 0x19847c0] All wanted packed headers available (wanted 0x10, found 0x10).
> [mjpeg_vaapi @ 0x19847c0] Failed to create encode pipeline configuration: 10 (attribute not supported).
> Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as bit_rate, rate, width or height
> [AVIOContext @ 0x1987000] Statistics: 0 seeks, 0 writeouts
> [AVIOContext @ 0x19802c0] Statistics: 3110400 bytes read, 0 seeks
> Conversion failed!
> 
> ... it works fine on i965 driver.

Right, the specific workaround to not set any options on drivers which report no supported RC modes (highlighted above) needs to be carried forward to this.  Added.

Thank you for testing!

- Mark
Eoff, Ullysses A Feb. 5, 2019, 4:51 p.m. UTC | #5
> -----Original Message-----

> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Mark Thompson

> Sent: Monday, February 04, 2019 1:26 AM

> To: ffmpeg-devel@ffmpeg.org

> Subject: Re: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes

> 

> On 28/01/2019 04:23, Eoff, Ullysses A wrote:

> >> -----Original Message-----

> >> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Mark Thompson

> >> Sent: Sunday, January 27, 2019 3:47 PM

> >> To: ffmpeg-devel@ffmpeg.org

> >> Subject: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes

> >>

> >> Allow setting the mode explicitly, and try to make a sensible choice

> >> given the available parameters if not.

> >> ---

> >>  doc/encoders.texi         |  24 +++

> >>  libavcodec/vaapi_encode.c | 370 +++++++++++++++++++++++++++-----------

> >>  libavcodec/vaapi_encode.h |  65 +++++++

> >>  3 files changed, 351 insertions(+), 108 deletions(-)

> >>

> >> ...

> >>      if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {

> >>          av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any "

> >> -               "supported rate control modes: assuming constant-quality.\n");

> >> -        ctx->va_rc_mode = VA_RC_CQP;

> >> -        return 0;

> >> ...

> >

> > With this patch series, mjpeg_vaapi encoder breaks with iHD driver:

> >

> > LIBVA_DRIVER_NAME=iHD ffmpeg -hwaccel vaapi \

> >   -vaapi_device /dev/dri/renderD128 -v debug \

> >   -f rawvideo -pix_fmt yuv420p -s:v 1920x1080 \

> >   -i input.yuv -vf 'format=nv12,hwupload' -c:v mjpeg_vaapi \

> >   -global_quality 100 -vframes 10 -y output.mjpg

> >

> > <snip>

> > [AVHWDeviceContext @ 0x193c580] Opened VA display via DRM device /dev/dri/renderD128.

> > [AVHWDeviceContext @ 0x193c580] libva: VA-API version 1.4.0

> > [AVHWDeviceContext @ 0x193c580] libva: va_getDriverName() returns 0

> > [AVHWDeviceContext @ 0x193c580] libva: User requested driver 'iHD'

> > [AVHWDeviceContext @ 0x193c580] libva: Trying to open /home/uaeoff/Work/workspace/media/install/lib/dri/iHD_drv_video.so

> > [AVHWDeviceContext @ 0x193c580] libva: Found init function __vaDriverInit_1_4

> > [AVHWDeviceContext @ 0x193c580] libva: va_openDriver() returns 0

> > [AVHWDeviceContext @ 0x193c580] Initialised VAAPI connection: version 1.4

> > <snip>

> > [mjpeg_vaapi @ 0x19847c0] Input surface format is nv12.

> > [mjpeg_vaapi @ 0x19847c0] Using VAAPI profile VAProfileJPEGBaseline (12).

> > [mjpeg_vaapi @ 0x19847c0] Using VAAPI entrypoint VAEntrypointEncPicture (7).

> > [mjpeg_vaapi @ 0x19847c0] Using VAAPI render target format YUV420 (0x1).

> > [mjpeg_vaapi @ 0x19847c0] Driver does not report any supported rate control modes: assuming CQP only.

> > [mjpeg_vaapi @ 0x19847c0] RC mode: CQP.

> > [mjpeg_vaapi @ 0x19847c0] RC quality: 100.

> > [mjpeg_vaapi @ 0x19847c0] RC framerate (CFR mode): 25/1 (25.00 fps).

> > [mjpeg_vaapi @ 0x19847c0] Using intra frames only.

> > [mjpeg_vaapi @ 0x19847c0] All wanted packed headers available (wanted 0x10, found 0x10).

> > [mjpeg_vaapi @ 0x19847c0] Failed to create encode pipeline configuration: 10 (attribute not supported).

> > Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as

> bit_rate, rate, width or height

> > [AVIOContext @ 0x1987000] Statistics: 0 seeks, 0 writeouts

> > [AVIOContext @ 0x19802c0] Statistics: 3110400 bytes read, 0 seeks

> > Conversion failed!

> >

> > ... it works fine on i965 driver.

> 

> Right, the specific workaround to not set any options on drivers which report no supported RC modes (highlighted above) needs to be

> carried forward to this.  Added.

> 

> Thank you for testing!

> 


Is there a v3 I can test?  Thanks.

> - Mark

> _______________________________________________

> ffmpeg-devel mailing list

> ffmpeg-devel@ffmpeg.org

> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Eoff, Ullysses A Feb. 6, 2019, 2:09 a.m. UTC | #6
> -----Original Message-----

> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Eoff, Ullysses A

> Sent: Tuesday, February 05, 2019 8:51 AM

> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>

> Subject: Re: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes

> 

> > -----Original Message-----

> > From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Mark Thompson

> > Sent: Monday, February 04, 2019 1:26 AM

> > To: ffmpeg-devel@ffmpeg.org

> > Subject: Re: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes

> >

> > On 28/01/2019 04:23, Eoff, Ullysses A wrote:

> > >> -----Original Message-----

> > >> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Mark Thompson

> > >> Sent: Sunday, January 27, 2019 3:47 PM

> > >> To: ffmpeg-devel@ffmpeg.org

> > >> Subject: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes

> > >>

> > >> Allow setting the mode explicitly, and try to make a sensible choice

> > >> given the available parameters if not.

> > >> ---

> > >>  doc/encoders.texi         |  24 +++

> > >>  libavcodec/vaapi_encode.c | 370 +++++++++++++++++++++++++++-----------

> > >>  libavcodec/vaapi_encode.h |  65 +++++++

> > >>  3 files changed, 351 insertions(+), 108 deletions(-)

> > >>

> > >> ...

> > >>      if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {

> > >>          av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any "

> > >> -               "supported rate control modes: assuming constant-quality.\n");

> > >> -        ctx->va_rc_mode = VA_RC_CQP;

> > >> -        return 0;

> > >> ...

> > >

> > > With this patch series, mjpeg_vaapi encoder breaks with iHD driver:

> > >

> > > LIBVA_DRIVER_NAME=iHD ffmpeg -hwaccel vaapi \

> > >   -vaapi_device /dev/dri/renderD128 -v debug \

> > >   -f rawvideo -pix_fmt yuv420p -s:v 1920x1080 \

> > >   -i input.yuv -vf 'format=nv12,hwupload' -c:v mjpeg_vaapi \

> > >   -global_quality 100 -vframes 10 -y output.mjpg

> > >

> > > <snip>

> > > [AVHWDeviceContext @ 0x193c580] Opened VA display via DRM device /dev/dri/renderD128.

> > > [AVHWDeviceContext @ 0x193c580] libva: VA-API version 1.4.0

> > > [AVHWDeviceContext @ 0x193c580] libva: va_getDriverName() returns 0

> > > [AVHWDeviceContext @ 0x193c580] libva: User requested driver 'iHD'

> > > [AVHWDeviceContext @ 0x193c580] libva: Trying to open /home/uaeoff/Work/workspace/media/install/lib/dri/iHD_drv_video.so

> > > [AVHWDeviceContext @ 0x193c580] libva: Found init function __vaDriverInit_1_4

> > > [AVHWDeviceContext @ 0x193c580] libva: va_openDriver() returns 0

> > > [AVHWDeviceContext @ 0x193c580] Initialised VAAPI connection: version 1.4

> > > <snip>

> > > [mjpeg_vaapi @ 0x19847c0] Input surface format is nv12.

> > > [mjpeg_vaapi @ 0x19847c0] Using VAAPI profile VAProfileJPEGBaseline (12).

> > > [mjpeg_vaapi @ 0x19847c0] Using VAAPI entrypoint VAEntrypointEncPicture (7).

> > > [mjpeg_vaapi @ 0x19847c0] Using VAAPI render target format YUV420 (0x1).

> > > [mjpeg_vaapi @ 0x19847c0] Driver does not report any supported rate control modes: assuming CQP only.

> > > [mjpeg_vaapi @ 0x19847c0] RC mode: CQP.

> > > [mjpeg_vaapi @ 0x19847c0] RC quality: 100.

> > > [mjpeg_vaapi @ 0x19847c0] RC framerate (CFR mode): 25/1 (25.00 fps).

> > > [mjpeg_vaapi @ 0x19847c0] Using intra frames only.

> > > [mjpeg_vaapi @ 0x19847c0] All wanted packed headers available (wanted 0x10, found 0x10).

> > > [mjpeg_vaapi @ 0x19847c0] Failed to create encode pipeline configuration: 10 (attribute not supported).

> > > Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as

> > bit_rate, rate, width or height

> > > [AVIOContext @ 0x1987000] Statistics: 0 seeks, 0 writeouts

> > > [AVIOContext @ 0x19802c0] Statistics: 3110400 bytes read, 0 seeks

> > > Conversion failed!

> > >

> > > ... it works fine on i965 driver.

> >

> > Right, the specific workaround to not set any options on drivers which report no supported RC modes (highlighted above) needs to

> be

> > carried forward to this.  Added.

> >

> > Thank you for testing!

> >

> 

> Is there a v3 I can test?  Thanks.


FYI, we just released vaapi-fits (https://github.com/intel/vaapi-fits).
It comes with a basic default example test input spec that is sufficient
enough to catch this patch regression.  Keep in mind, though, that
some of the tests already fail with current ToT.  So you'll need to
compare results before and after patches.  Feel free to give it a try
before sending patches to catch simple regressions.

I recommend running like:

LIBVA_DRIVER_NAME=iHD vaapi-fits run test/ffmpeg-vaapi \
 --parallel-metrics -v -k tag:KBL

Add an additional "-v" for more verbosity (i.e. to see command
lines).  Also, change "-k tag:KBL" based on your physical Intel
platform.

We supplement our testing with this framework with more
comprehensive internal test input specifications, FWIW.

Feel free to ping me if you have any questions.

U. Artie

> 

> > - Mark

> > _______________________________________________

> > ffmpeg-devel mailing list

> > ffmpeg-devel@ffmpeg.org

> > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

> _______________________________________________

> ffmpeg-devel mailing list

> ffmpeg-devel@ffmpeg.org

> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Mark Thompson Feb. 10, 2019, 7:51 p.m. UTC | #7
On 05/02/2019 16:51, Eoff, Ullysses A wrote:
>> -----Original Message-----
>> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Mark Thompson
>> Sent: Monday, February 04, 2019 1:26 AM
>> To: ffmpeg-devel@ffmpeg.org
>> Subject: Re: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes
>>
>> On 28/01/2019 04:23, Eoff, Ullysses A wrote:
>>>> -----Original Message-----
>>>> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Mark Thompson
>>>> Sent: Sunday, January 27, 2019 3:47 PM
>>>> To: ffmpeg-devel@ffmpeg.org
>>>> Subject: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes
>>>>
>>>> Allow setting the mode explicitly, and try to make a sensible choice
>>>> given the available parameters if not.
>>>> ---
>>>>  doc/encoders.texi         |  24 +++
>>>>  libavcodec/vaapi_encode.c | 370 +++++++++++++++++++++++++++-----------
>>>>  libavcodec/vaapi_encode.h |  65 +++++++
>>>>  3 files changed, 351 insertions(+), 108 deletions(-)
>>>>
>>>> ...
>>>>      if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {
>>>>          av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any "
>>>> -               "supported rate control modes: assuming constant-quality.\n");
>>>> -        ctx->va_rc_mode = VA_RC_CQP;
>>>> -        return 0;
>>>> ...
>>>
>>> With this patch series, mjpeg_vaapi encoder breaks with iHD driver:
>>>
>>> LIBVA_DRIVER_NAME=iHD ffmpeg -hwaccel vaapi \
>>>   -vaapi_device /dev/dri/renderD128 -v debug \
>>>   -f rawvideo -pix_fmt yuv420p -s:v 1920x1080 \
>>>   -i input.yuv -vf 'format=nv12,hwupload' -c:v mjpeg_vaapi \
>>>   -global_quality 100 -vframes 10 -y output.mjpg
>>>
>>> <snip>
>>> [AVHWDeviceContext @ 0x193c580] Opened VA display via DRM device /dev/dri/renderD128.
>>> [AVHWDeviceContext @ 0x193c580] libva: VA-API version 1.4.0
>>> [AVHWDeviceContext @ 0x193c580] libva: va_getDriverName() returns 0
>>> [AVHWDeviceContext @ 0x193c580] libva: User requested driver 'iHD'
>>> [AVHWDeviceContext @ 0x193c580] libva: Trying to open /home/uaeoff/Work/workspace/media/install/lib/dri/iHD_drv_video.so
>>> [AVHWDeviceContext @ 0x193c580] libva: Found init function __vaDriverInit_1_4
>>> [AVHWDeviceContext @ 0x193c580] libva: va_openDriver() returns 0
>>> [AVHWDeviceContext @ 0x193c580] Initialised VAAPI connection: version 1.4
>>> <snip>
>>> [mjpeg_vaapi @ 0x19847c0] Input surface format is nv12.
>>> [mjpeg_vaapi @ 0x19847c0] Using VAAPI profile VAProfileJPEGBaseline (12).
>>> [mjpeg_vaapi @ 0x19847c0] Using VAAPI entrypoint VAEntrypointEncPicture (7).
>>> [mjpeg_vaapi @ 0x19847c0] Using VAAPI render target format YUV420 (0x1).
>>> [mjpeg_vaapi @ 0x19847c0] Driver does not report any supported rate control modes: assuming CQP only.
>>> [mjpeg_vaapi @ 0x19847c0] RC mode: CQP.
>>> [mjpeg_vaapi @ 0x19847c0] RC quality: 100.
>>> [mjpeg_vaapi @ 0x19847c0] RC framerate (CFR mode): 25/1 (25.00 fps).
>>> [mjpeg_vaapi @ 0x19847c0] Using intra frames only.
>>> [mjpeg_vaapi @ 0x19847c0] All wanted packed headers available (wanted 0x10, found 0x10).
>>> [mjpeg_vaapi @ 0x19847c0] Failed to create encode pipeline configuration: 10 (attribute not supported).
>>> Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as
>> bit_rate, rate, width or height
>>> [AVIOContext @ 0x1987000] Statistics: 0 seeks, 0 writeouts
>>> [AVIOContext @ 0x19802c0] Statistics: 3110400 bytes read, 0 seeks
>>> Conversion failed!
>>>
>>> ... it works fine on i965 driver.
>>
>> Right, the specific workaround to not set any options on drivers which report no supported RC modes (highlighted above) needs to be
>> carried forward to this.  Added.
>>
>> Thank you for testing!
>>
> 
> Is there a v3 I can test?  Thanks.

New version sent.  It now doesn't bail out from that function early because it does want to do some other setup there; instead it just avoids setting that particular attribute at the end if the driver has declared that it doesn't support it.

Thanks,

- Mark
Eoff, Ullysses A Feb. 12, 2019, 12:08 a.m. UTC | #8
> -----Original Message-----

> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Mark Thompson

> Sent: Sunday, February 10, 2019 11:51 AM

> To: ffmpeg-devel@ffmpeg.org

> Subject: Re: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes

> 

> On 05/02/2019 16:51, Eoff, Ullysses A wrote:

> >> -----Original Message-----

> >> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Mark Thompson

> >> Sent: Monday, February 04, 2019 1:26 AM

> >> To: ffmpeg-devel@ffmpeg.org

> >> Subject: Re: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes

> >>

> >> On 28/01/2019 04:23, Eoff, Ullysses A wrote:

> >>>> -----Original Message-----

> >>>> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces@ffmpeg.org] On Behalf Of Mark Thompson

> >>>> Sent: Sunday, January 27, 2019 3:47 PM

> >>>> To: ffmpeg-devel@ffmpeg.org

> >>>> Subject: [FFmpeg-devel] [PATCH v2 01/11] vaapi_encode: Support more RC modes

> >>>>

> >>>> Allow setting the mode explicitly, and try to make a sensible choice

> >>>> given the available parameters if not.

> >>>> ---

> >>>>  doc/encoders.texi         |  24 +++

> >>>>  libavcodec/vaapi_encode.c | 370 +++++++++++++++++++++++++++-----------

> >>>>  libavcodec/vaapi_encode.h |  65 +++++++

> >>>>  3 files changed, 351 insertions(+), 108 deletions(-)

> >>>>

> >>>> ...

> >>>>      if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {

> >>>>          av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any "

> >>>> -               "supported rate control modes: assuming constant-quality.\n");

> >>>> -        ctx->va_rc_mode = VA_RC_CQP;

> >>>> -        return 0;

> >>>> ...

> >>>

> >>> With this patch series, mjpeg_vaapi encoder breaks with iHD driver:

> >>>

> >>> LIBVA_DRIVER_NAME=iHD ffmpeg -hwaccel vaapi \

> >>>   -vaapi_device /dev/dri/renderD128 -v debug \

> >>>   -f rawvideo -pix_fmt yuv420p -s:v 1920x1080 \

> >>>   -i input.yuv -vf 'format=nv12,hwupload' -c:v mjpeg_vaapi \

> >>>   -global_quality 100 -vframes 10 -y output.mjpg

> >>>

> >>> <snip>

> >>> [AVHWDeviceContext @ 0x193c580] Opened VA display via DRM device /dev/dri/renderD128.

> >>> [AVHWDeviceContext @ 0x193c580] libva: VA-API version 1.4.0

> >>> [AVHWDeviceContext @ 0x193c580] libva: va_getDriverName() returns 0

> >>> [AVHWDeviceContext @ 0x193c580] libva: User requested driver 'iHD'

> >>> [AVHWDeviceContext @ 0x193c580] libva: Trying to open

> /home/uaeoff/Work/workspace/media/install/lib/dri/iHD_drv_video.so

> >>> [AVHWDeviceContext @ 0x193c580] libva: Found init function __vaDriverInit_1_4

> >>> [AVHWDeviceContext @ 0x193c580] libva: va_openDriver() returns 0

> >>> [AVHWDeviceContext @ 0x193c580] Initialised VAAPI connection: version 1.4

> >>> <snip>

> >>> [mjpeg_vaapi @ 0x19847c0] Input surface format is nv12.

> >>> [mjpeg_vaapi @ 0x19847c0] Using VAAPI profile VAProfileJPEGBaseline (12).

> >>> [mjpeg_vaapi @ 0x19847c0] Using VAAPI entrypoint VAEntrypointEncPicture (7).

> >>> [mjpeg_vaapi @ 0x19847c0] Using VAAPI render target format YUV420 (0x1).

> >>> [mjpeg_vaapi @ 0x19847c0] Driver does not report any supported rate control modes: assuming CQP only.

> >>> [mjpeg_vaapi @ 0x19847c0] RC mode: CQP.

> >>> [mjpeg_vaapi @ 0x19847c0] RC quality: 100.

> >>> [mjpeg_vaapi @ 0x19847c0] RC framerate (CFR mode): 25/1 (25.00 fps).

> >>> [mjpeg_vaapi @ 0x19847c0] Using intra frames only.

> >>> [mjpeg_vaapi @ 0x19847c0] All wanted packed headers available (wanted 0x10, found 0x10).

> >>> [mjpeg_vaapi @ 0x19847c0] Failed to create encode pipeline configuration: 10 (attribute not supported).

> >>> Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe incorrect parameters such as

> >> bit_rate, rate, width or height

> >>> [AVIOContext @ 0x1987000] Statistics: 0 seeks, 0 writeouts

> >>> [AVIOContext @ 0x19802c0] Statistics: 3110400 bytes read, 0 seeks

> >>> Conversion failed!

> >>>

> >>> ... it works fine on i965 driver.

> >>

> >> Right, the specific workaround to not set any options on drivers which report no supported RC modes (highlighted above) needs to

> be

> >> carried forward to this.  Added.

> >>

> >> Thank you for testing!

> >>

> >

> > Is there a v3 I can test?  Thanks.

> 

> New version sent.  It now doesn't bail out from that function early because it does want to do some other setup there; instead it just

> avoids setting that particular attribute at the end if the driver has declared that it doesn't support it.

> 


[UAE] Yep, v3 works now.  Thanks. 

> Thanks,

> 

> - Mark

> _______________________________________________

> ffmpeg-devel mailing list

> ffmpeg-devel@ffmpeg.org

> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
diff mbox

Patch

diff --git a/doc/encoders.texi b/doc/encoders.texi
index e86ae69cc5..29625ba07c 100644
--- a/doc/encoders.texi
+++ b/doc/encoders.texi
@@ -2824,6 +2824,30 @@  Set the B-frame reference depth.  When set to one (the default), all B-frames
 will refer only to P- or I-frames.  When set to greater values multiple layers
 of B-frames will be present, frames in each layer only referring to frames in
 higher layers.
+
+@item rc_mode
+Set the rate control mode to use.  A given driver may only support a subset of
+modes.
+
+Possible modes:
+@table @option
+@item auto
+Choose the mode automatically based on driver support and the other options.
+This is the default.
+@item CQP
+Constant-quality.
+@item CBR
+Constant-bitrate.
+@item VBR
+Variable-bitrate.
+@item ICQ
+Intelligent constant-quality.
+@item QVBR
+Quality-defined variable-bitrate.
+@item AVBR
+Average variable bitrate.
+@end table
+
 @end table
 
 Each encoder also has its own specific options:
diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
index b4e9fadaee..d0e101b118 100644
--- a/libavcodec/vaapi_encode.c
+++ b/libavcodec/vaapi_encode.c
@@ -1283,17 +1283,42 @@  fail:
     return err;
 }
 
+static const VAAPIEncodeRCMode vaapi_encode_rc_modes[] = {
+    //                                  Bitrate   Quality
+    //                                     | Maxrate | HRD/VBV
+    { 0 }, //                              |    |    |    |
+    { RC_MODE_CQP,  "CQP",  1, VA_RC_CQP,  0,   0,   1,   0 },
+    { RC_MODE_CBR,  "CBR",  1, VA_RC_CBR,  1,   0,   0,   1 },
+    { RC_MODE_VBR,  "VBR",  1, VA_RC_VBR,  1,   1,   0,   1 },
+#if VA_CHECK_VERSION(1, 1, 0)
+    { RC_MODE_ICQ,  "ICQ",  1, VA_RC_ICQ,  0,   0,   1,   0 },
+#else
+    { RC_MODE_ICQ,  "ICQ",  0 },
+#endif
+#if VA_CHECK_VERSION(1, 3, 0)
+    { RC_MODE_QVBR, "QVBR", 1, VA_RC_QVBR, 1,   1,   1,   1 },
+    { RC_MODE_AVBR, "AVBR", 0, VA_RC_AVBR, 1,   0,   0,   0 },
+#else
+    { RC_MODE_QVBR, "QVBR", 0 },
+    { RC_MODE_AVBR, "AVBR", 0 },
+#endif
+};
+
 static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)
 {
     VAAPIEncodeContext *ctx = avctx->priv_data;
+    uint32_t supported_va_rc_modes;
+    const VAAPIEncodeRCMode *rc_mode;
     int64_t rc_bits_per_second;
     int     rc_target_percentage;
     int     rc_window_size;
+    int     rc_quality;
     int64_t hrd_buffer_size;
     int64_t hrd_initial_buffer_fullness;
     int fr_num, fr_den;
     VAConfigAttrib rc_attr = { VAConfigAttribRateControl };
     VAStatus vas;
+    char supported_rc_modes_string[64];
 
     vas = vaGetConfigAttributes(ctx->hwctx->display,
                                 ctx->va_profile, ctx->va_entrypoint,
@@ -1303,119 +1328,215 @@  static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)
                "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
         return AVERROR_EXTERNAL;
     }
-
     if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) {
         av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any "
-               "supported rate control modes: assuming constant-quality.\n");
-        ctx->va_rc_mode = VA_RC_CQP;
-        return 0;
-    }
-    if (ctx->codec->flags & FLAG_CONSTANT_QUALITY_ONLY ||
-        avctx->flags & AV_CODEC_FLAG_QSCALE ||
-        avctx->bit_rate <= 0) {
-        if (rc_attr.value & VA_RC_CQP) {
-            av_log(avctx, AV_LOG_VERBOSE, "Using constant-quality mode.\n");
-            ctx->va_rc_mode = VA_RC_CQP;
-            if (avctx->bit_rate > 0 || avctx->rc_max_rate > 0) {
-                av_log(avctx, AV_LOG_WARNING, "Bitrate target parameters "
-                       "ignored in constant-quality mode.\n");
+               "supported rate control modes: assuming CQP only.\n");
+        supported_va_rc_modes = VA_RC_CQP;
+        strcpy(supported_rc_modes_string, "unknown");
+    } else {
+        char *str = supported_rc_modes_string;
+        size_t len = sizeof(supported_rc_modes_string);
+        int i, first = 1, res;
+
+        supported_va_rc_modes = rc_attr.value;
+
+        first = 1;
+        for (i = 0; i < FF_ARRAY_ELEMS(vaapi_encode_rc_modes); i++) {
+            rc_mode = &vaapi_encode_rc_modes[i];
+            if (supported_va_rc_modes & rc_mode->va_mode) {
+                res = snprintf(str, len, "%s%s",
+                               first ? "" : ", ", rc_mode->name);
+                first = 0;
+                if (res < 0) {
+                    *str = 0;
+                    break;
+                }
+                len -= res;
+                str += res;
+                if (len == 0)
+                    break;
             }
-            return 0;
-        } else {
-            av_log(avctx, AV_LOG_ERROR, "Driver does not support "
-                   "constant-quality mode (%#x).\n", rc_attr.value);
-            return AVERROR(EINVAL);
         }
-    }
 
-    if (!(rc_attr.value & (VA_RC_CBR | VA_RC_VBR))) {
-        av_log(avctx, AV_LOG_ERROR, "Driver does not support any "
-               "bitrate-targetted rate control modes.\n");
-        return AVERROR(EINVAL);
+        av_log(avctx, AV_LOG_DEBUG, "Driver supports RC modes %s.\n",
+               supported_rc_modes_string);
+    }
+
+    // Rate control mode selection:
+    // * If the user has set a mode explicitly with the rc_mode option,
+    //   use it and fail if it is not available.
+    // * If an explicit QP option has been set, use CQP.
+    // * If the codec is CQ-only, use CQP.
+    // * If the QSCALE avcodec option is set, use CQP.
+    // * If bitrate and quality are both set, try QVBR.
+    // * If quality is set, try ICQ, then CQP.
+    // * If bitrate and maxrate are set and have the same value, try CBR.
+    // * If a bitrate is set, try AVBR, then VBR, then CBR.
+    // * If no bitrate is set, try ICQ, then CQP.
+
+#define TRY_RC_MODE(mode, fail) do { \
+        rc_mode = &vaapi_encode_rc_modes[mode]; \
+        if (!(rc_mode->va_mode & supported_va_rc_modes)) { \
+            if (fail) { \
+                av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \
+                       "RC mode (supported modes: %s).\n", rc_mode->name, \
+                       supported_rc_modes_string); \
+                return AVERROR(EINVAL); \
+            } \
+            av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \
+                   "RC mode.\n", rc_mode->name); \
+            rc_mode = NULL; \
+        } else { \
+            goto rc_mode_found; \
+        } \
+    } while (0)
+
+    if (ctx->explicit_rc_mode)
+        TRY_RC_MODE(ctx->explicit_rc_mode, 1);
+
+    if (ctx->explicit_qp)
+        TRY_RC_MODE(RC_MODE_CQP, 1);
+
+    if (ctx->codec->flags & FLAG_CONSTANT_QUALITY_ONLY)
+        TRY_RC_MODE(RC_MODE_CQP, 1);
+
+    if (avctx->flags & AV_CODEC_FLAG_QSCALE)
+        TRY_RC_MODE(RC_MODE_CQP, 1);
+
+    if (avctx->bit_rate > 0 && avctx->global_quality > 0)
+        TRY_RC_MODE(RC_MODE_QVBR, 0);
+
+    if (avctx->global_quality > 0) {
+        TRY_RC_MODE(RC_MODE_ICQ, 0);
+        TRY_RC_MODE(RC_MODE_CQP, 0);
+    }
+
+    if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate)
+        TRY_RC_MODE(RC_MODE_CBR, 0);
+
+    if (avctx->bit_rate > 0) {
+        TRY_RC_MODE(RC_MODE_AVBR, 0);
+        TRY_RC_MODE(RC_MODE_VBR, 0);
+        TRY_RC_MODE(RC_MODE_CBR, 0);
+    } else {
+        TRY_RC_MODE(RC_MODE_ICQ, 0);
+        TRY_RC_MODE(RC_MODE_CQP, 0);
     }
 
-    if (avctx->rc_buffer_size)
-        hrd_buffer_size = avctx->rc_buffer_size;
-    else if (avctx->rc_max_rate > 0)
-        hrd_buffer_size = avctx->rc_max_rate;
-    else
-        hrd_buffer_size = avctx->bit_rate;
-    if (avctx->rc_initial_buffer_occupancy) {
-        if (avctx->rc_initial_buffer_occupancy > hrd_buffer_size) {
-            av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: "
-                   "must have initial buffer size (%d) < "
-                   "buffer size (%"PRId64").\n",
-                   avctx->rc_initial_buffer_occupancy, hrd_buffer_size);
+    av_log(avctx, AV_LOG_ERROR, "Driver does not support any "
+           "RC mode compatible with selected options "
+           "(supported modes: %s).\n", supported_rc_modes_string);
+    return AVERROR(EINVAL);
+
+rc_mode_found:
+    if (rc_mode->bitrate) {
+        if (avctx->bit_rate <= 0) {
+            av_log(avctx, AV_LOG_ERROR, "Bitrate must be set for %s "
+                   "RC mode.\n", rc_mode->name);
             return AVERROR(EINVAL);
         }
-        hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy;
-    } else {
-        hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4;
-    }
 
-    if (avctx->rc_max_rate && avctx->rc_max_rate < avctx->bit_rate) {
-        av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: must have "
-               "bitrate (%"PRId64") <= maxrate (%"PRId64").\n",
-               avctx->bit_rate, avctx->rc_max_rate);
-        return AVERROR(EINVAL);
-    }
+        if (rc_mode->mode == RC_MODE_AVBR) {
+            // For maximum confusion AVBR is hacked into the existing API
+            // by overloading some of the fields with completely different
+            // meanings.
 
-    if (avctx->rc_max_rate > avctx->bit_rate) {
-        if (!(rc_attr.value & VA_RC_VBR)) {
-            av_log(avctx, AV_LOG_WARNING, "Driver does not support "
-                   "VBR mode (%#x), using CBR mode instead.\n",
-                   rc_attr.value);
-            ctx->va_rc_mode = VA_RC_CBR;
+            // Target percentage does not apply in AVBR mode.
+            rc_bits_per_second = avctx->bit_rate;
 
-            rc_bits_per_second   = avctx->bit_rate;
+            // Accuracy tolerance range for meeting the specified target
+            // bitrate.  It's very unclear how this is actually intended
+            // to work - since we do want to get the specified bitrate,
+            // set the accuracy to 100% for now.
             rc_target_percentage = 100;
-        } else {
-            ctx->va_rc_mode = VA_RC_VBR;
-
-            rc_bits_per_second   = avctx->rc_max_rate;
-            rc_target_percentage = (avctx->bit_rate * 100) /
-                                   avctx->rc_max_rate;
-        }
 
-    } else if (avctx->rc_max_rate == avctx->bit_rate) {
-        if (!(rc_attr.value & VA_RC_CBR)) {
-            av_log(avctx, AV_LOG_WARNING, "Driver does not support "
-                   "CBR mode (%#x), using VBR mode instead.\n",
-                   rc_attr.value);
-            ctx->va_rc_mode = VA_RC_VBR;
+            // Convergence period in frames.  The GOP size reflects the
+            // user's intended block size for cutting, so reusing that
+            // as the convergence period seems a reasonable default.
+            rc_window_size = avctx->gop_size > 0 ? avctx->gop_size : 60;
+
+        } else if (rc_mode->maxrate) {
+            if (avctx->rc_max_rate > 0) {
+                if (avctx->rc_max_rate < avctx->bit_rate) {
+                    av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: "
+                           "bitrate (%"PRId64") must not be greater than "
+                           "maxrate (%"PRId64").\n", avctx->bit_rate,
+                           avctx->rc_max_rate);
+                    return AVERROR(EINVAL);
+                }
+                rc_bits_per_second   = avctx->rc_max_rate;
+                rc_target_percentage = (avctx->bit_rate * 100) /
+                                       avctx->rc_max_rate;
+            } else {
+                // We only have a target bitrate, but this mode requires
+                // that a maximum rate be supplied as well.  Since the
+                // user does not want this to be a constraint, arbitrarily
+                // pick a maximum rate of double the target rate.
+                rc_bits_per_second   = 2 * avctx->bit_rate;
+                rc_target_percentage = 50;
+            }
         } else {
-            ctx->va_rc_mode = VA_RC_CBR;
+            if (avctx->rc_max_rate > avctx->bit_rate) {
+                av_log(avctx, AV_LOG_WARNING, "Max bitrate is ignored "
+                       "in %s RC mode.\n", rc_mode->name);
+            }
+            rc_bits_per_second   = avctx->bit_rate;
+            rc_target_percentage = 100;
         }
-
-        rc_bits_per_second   = avctx->bit_rate;
+    } else {
+        rc_bits_per_second   = 0;
         rc_target_percentage = 100;
+    }
 
+    if (rc_mode->quality) {
+        if (ctx->explicit_qp) {
+            rc_quality = ctx->explicit_qp;
+        } else if (avctx->global_quality > 0) {
+            rc_quality = avctx->global_quality;
+        } else {
+            rc_quality = ctx->codec->default_quality;
+            av_log(avctx, AV_LOG_WARNING, "No quality level set; "
+                   "using default (%d).\n", rc_quality);
+        }
     } else {
-        if (rc_attr.value & VA_RC_VBR) {
-            ctx->va_rc_mode = VA_RC_VBR;
-
-            // We only have a target bitrate, but VAAPI requires that a
-            // maximum rate be supplied as well.  Since the user has
-            // offered no particular constraint, arbitrarily pick a
-            // maximum rate of double the target rate.
-            rc_bits_per_second   = 2 * avctx->bit_rate;
-            rc_target_percentage = 50;
+        rc_quality = 0;
+    }
+
+    if (rc_mode->hrd) {
+        if (avctx->rc_buffer_size)
+            hrd_buffer_size = avctx->rc_buffer_size;
+        else if (avctx->rc_max_rate > 0)
+            hrd_buffer_size = avctx->rc_max_rate;
+        else
+            hrd_buffer_size = avctx->bit_rate;
+        if (avctx->rc_initial_buffer_occupancy) {
+            if (avctx->rc_initial_buffer_occupancy > hrd_buffer_size) {
+                av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: "
+                       "must have initial buffer size (%d) <= "
+                       "buffer size (%"PRId64").\n",
+                       avctx->rc_initial_buffer_occupancy, hrd_buffer_size);
+                return AVERROR(EINVAL);
+            }
+            hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy;
         } else {
-            ctx->va_rc_mode = VA_RC_CBR;
+            hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4;
+        }
 
-            rc_bits_per_second   = avctx->bit_rate;
-            rc_target_percentage = 100;
+        rc_window_size = (hrd_buffer_size * 1000) / rc_bits_per_second;
+    } else {
+        if (avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {
+            av_log(avctx, AV_LOG_WARNING, "Buffering settings are ignored "
+                   "in %s RC mode.\n", rc_mode->name);
         }
-    }
 
-    rc_window_size = (hrd_buffer_size * 1000) / rc_bits_per_second;
+        hrd_buffer_size             = 0;
+        hrd_initial_buffer_fullness = 0;
 
-    av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s, %d%% of %"PRId64" bps "
-           "over %d ms.\n", ctx->va_rc_mode == VA_RC_VBR ? "VBR" : "CBR",
-           rc_target_percentage, rc_bits_per_second, rc_window_size);
-    av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, "
-           "initial fullness %"PRId64" bits.\n",
-           hrd_buffer_size, hrd_initial_buffer_fullness);
+        if (rc_mode->mode != RC_MODE_AVBR) {
+            // Already set (with completely different meaning) for AVBR.
+            rc_window_size = 1000;
+        }
+    }
 
     if (rc_bits_per_second          > UINT32_MAX ||
         hrd_buffer_size             > UINT32_MAX ||
@@ -1425,36 +1546,66 @@  static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)
         return AVERROR(EINVAL);
     }
 
+    ctx->rc_mode     = rc_mode;
+    ctx->rc_quality  = rc_quality;
+    ctx->va_rc_mode  = rc_mode->va_mode;
     ctx->va_bit_rate = rc_bits_per_second;
 
+    av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s.\n", rc_mode->name);
     ctx->config_attributes[ctx->nb_config_attributes++] =
         (VAConfigAttrib) {
         .type  = VAConfigAttribRateControl,
         .value = ctx->va_rc_mode,
     };
 
-    ctx->rc_params.misc.type = VAEncMiscParameterTypeRateControl;
-    ctx->rc_params.rc = (VAEncMiscParameterRateControl) {
-        .bits_per_second   = rc_bits_per_second,
-        .target_percentage = rc_target_percentage,
-        .window_size       = rc_window_size,
-        .initial_qp        = 0,
-        .min_qp            = (avctx->qmin > 0 ? avctx->qmin : 0),
-        .basic_unit_size   = 0,
+    if (rc_mode->quality)
+        av_log(avctx, AV_LOG_VERBOSE, "RC quality: %d.\n", rc_quality);
+
+    if (rc_mode->va_mode != VA_RC_CQP) {
+        if (rc_mode->mode == RC_MODE_AVBR) {
+            av_log(avctx, AV_LOG_VERBOSE, "RC target: %"PRId64" bps "
+                   "converging in %d frames with %d%% accuracy.\n",
+                   rc_bits_per_second, rc_window_size,
+                   rc_target_percentage);
+        } else if (rc_mode->bitrate) {
+            av_log(avctx, AV_LOG_VERBOSE, "RC target: %d%% of "
+                   "%"PRId64" bps over %d ms.\n", rc_target_percentage,
+                   rc_bits_per_second, rc_window_size);
+        }
+
+        ctx->rc_params.misc.type = VAEncMiscParameterTypeRateControl;
+        ctx->rc_params.rc = (VAEncMiscParameterRateControl) {
+            .bits_per_second    = rc_bits_per_second,
+            .target_percentage  = rc_target_percentage,
+            .window_size        = rc_window_size,
+            .initial_qp         = 0,
+            .min_qp             = (avctx->qmin > 0 ? avctx->qmin : 0),
+            .basic_unit_size    = 0,
 #if VA_CHECK_VERSION(1, 1, 0)
-        .max_qp            = (avctx->qmax > 0 ? avctx->qmax : 0),
+            .ICQ_quality_factor = av_clip(rc_quality, 1, 51),
+            .max_qp             = (avctx->qmax > 0 ? avctx->qmax : 0),
 #endif
-    };
-    vaapi_encode_add_global_param(avctx, &ctx->rc_params.misc,
-                                  sizeof(ctx->rc_params));
+#if VA_CHECK_VERSION(1, 3, 0)
+            .quality_factor     = rc_quality,
+#endif
+        };
+        vaapi_encode_add_global_param(avctx, &ctx->rc_params.misc,
+                                      sizeof(ctx->rc_params));
+    }
 
-    ctx->hrd_params.misc.type = VAEncMiscParameterTypeHRD;
-    ctx->hrd_params.hrd = (VAEncMiscParameterHRD) {
-        .initial_buffer_fullness = hrd_initial_buffer_fullness,
-        .buffer_size             = hrd_buffer_size,
-    };
-    vaapi_encode_add_global_param(avctx, &ctx->hrd_params.misc,
-                                  sizeof(ctx->hrd_params));
+    if (rc_mode->hrd) {
+        av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, "
+               "initial fullness %"PRId64" bits.\n",
+               hrd_buffer_size, hrd_initial_buffer_fullness);
+
+        ctx->hrd_params.misc.type = VAEncMiscParameterTypeHRD;
+        ctx->hrd_params.hrd = (VAEncMiscParameterHRD) {
+            .initial_buffer_fullness = hrd_initial_buffer_fullness,
+            .buffer_size             = hrd_buffer_size,
+        };
+        vaapi_encode_add_global_param(avctx, &ctx->hrd_params.misc,
+                                      sizeof(ctx->hrd_params));
+    }
 
     if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
         av_reduce(&fr_num, &fr_den,
@@ -1463,6 +1614,9 @@  static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)
         av_reduce(&fr_num, &fr_den,
                   avctx->time_base.den, avctx->time_base.num, 65535);
 
+    av_log(avctx, AV_LOG_VERBOSE, "RC framerate: %d/%d (%.2f fps).\n",
+           fr_num, fr_den, (double)fr_num / fr_den);
+
     ctx->fr_params.misc.type = VAEncMiscParameterTypeFrameRate;
     ctx->fr_params.fr.framerate = (unsigned int)fr_den << 16 | fr_num;
 
diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h
index a4206865ea..44a8db566e 100644
--- a/libavcodec/vaapi_encode.h
+++ b/libavcodec/vaapi_encode.h
@@ -129,6 +129,36 @@  typedef struct VAAPIEncodeProfile {
     VAProfile va_profile;
 } VAAPIEncodeProfile;
 
+enum {
+    RC_MODE_AUTO,
+    RC_MODE_CQP,
+    RC_MODE_CBR,
+    RC_MODE_VBR,
+    RC_MODE_ICQ,
+    RC_MODE_QVBR,
+    RC_MODE_AVBR,
+    RC_MODE_MAX = RC_MODE_AVBR,
+};
+
+typedef struct VAAPIEncodeRCMode {
+    // Mode from above enum (RC_MODE_*).
+    int mode;
+    // Name.
+    const char *name;
+    // Supported in the compile-time VAAPI version.
+    int supported;
+    // VA mode value (VA_RC_*).
+    uint32_t va_mode;
+    // Uses bitrate parameters.
+    int bitrate;
+    // Supports maxrate distinct from bitrate.
+    int maxrate;
+    // Uses quality value.
+    int quality;
+    // Supports HRD/VBV parameters.
+    int hrd;
+} VAAPIEncodeRCMode;
+
 typedef struct VAAPIEncodeContext {
     const AVClass *class;
 
@@ -146,6 +176,14 @@  typedef struct VAAPIEncodeContext {
     // Desired B frame reference depth.
     int             desired_b_depth;
 
+    // Explicitly set RC mode (otherwise attempt to pick from
+    // available modes).
+    int             explicit_rc_mode;
+
+    // Explicitly-set QP, for use with the "qp" options.
+    // (Forces CQP mode when set, overriding everything else.)
+    int             explicit_qp;
+
     // Desired packed headers.
     unsigned int    desired_packed_headers;
 
@@ -165,6 +203,12 @@  typedef struct VAAPIEncodeContext {
     // Chosen encoding profile details.
     const VAAPIEncodeProfile *profile;
 
+    // Chosen rate control mode details.
+    const VAAPIEncodeRCMode *rc_mode;
+    // RC quality level - meaning depends on codec and RC mode.
+    // In CQP mode this sets the fixed quantiser value.
+    int             rc_quality;
+
     // Encoding profile (VAProfile*).
     VAProfile       va_profile;
     // Encoding entrypoint (VAEntryoint*).
@@ -296,6 +340,10 @@  typedef struct VAAPIEncodeType {
     // Codec feature flags.
     int flags;
 
+    // Default quality for this codec - used as quantiser or RC quality
+    // factor depending on RC mode.
+    int default_quality;
+
     // Perform any extra codec-specific configuration after the
     // codec context is initialised (set up the private data and
     // add any necessary global parameters).
@@ -382,5 +430,22 @@  int ff_vaapi_encode_close(AVCodecContext *avctx);
       OFFSET(common.desired_b_depth), AV_OPT_TYPE_INT, \
       { .i64 = 1 }, 1, INT_MAX, FLAGS }
 
+#define VAAPI_ENCODE_RC_MODE(name, desc) \
+    { #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_ ## name }, \
+      0, 0, FLAGS, "rc_mode" }
+#define VAAPI_ENCODE_RC_OPTIONS \
+    { "rc_mode",\
+      "Set rate control mode", \
+      OFFSET(common.explicit_rc_mode), AV_OPT_TYPE_INT, \
+      { .i64 = RC_MODE_AUTO }, RC_MODE_AUTO, RC_MODE_MAX, FLAGS, "rc_mode" }, \
+    { "auto", "Choose mode automatically based on other parameters", \
+      0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_AUTO }, 0, 0, FLAGS, "rc_mode" }, \
+    VAAPI_ENCODE_RC_MODE(CQP,  "Constant-quality"), \
+    VAAPI_ENCODE_RC_MODE(CBR,  "Constant-bitrate"), \
+    VAAPI_ENCODE_RC_MODE(VBR,  "Variable-bitrate"), \
+    VAAPI_ENCODE_RC_MODE(ICQ,  "Intelligent constant-quality"), \
+    VAAPI_ENCODE_RC_MODE(QVBR, "Quality-defined variable-bitrate"), \
+    VAAPI_ENCODE_RC_MODE(AVBR, "Average variable-bitrate")
+
 
 #endif /* AVCODEC_VAAPI_ENCODE_H */