[FFmpeg-devel] [PATCH v2 11/36] vaapi_encode: Choose profiles dynamically

Xiang, Haihao haihao.xiang at intel.com
Tue Jun 12 10:22:39 EEST 2018


On Fri, 2018-06-08 at 00:43 +0100, Mark Thompson wrote:
> Previously there was one fixed choice for each codec (e.g. H.265 -> Main
> profile), and using anything else then required an explicit option from
> the user.  This changes to selecting the profile based on the input format
> and the set of profiles actually supported by the driver (e.g. P010 input
> will choose Main 10 profile for H.265 if the driver supports it).
> 
> The entrypoint and render target format are also chosen dynamically in the
> same way, removing those explicit selections from the per-codec code.
> ---
>  doc/encoders.texi               |   3 +
>  libavcodec/vaapi_encode.c       | 271 ++++++++++++++++++++++++++++++++-------
> -
>  libavcodec/vaapi_encode.h       |  43 +++++--
>  libavcodec/vaapi_encode_h264.c  |  45 ++-----
>  libavcodec/vaapi_encode_h265.c  |  35 ++----
>  libavcodec/vaapi_encode_mjpeg.c |  13 +-
>  libavcodec/vaapi_encode_mpeg2.c |  36 ++----
>  libavcodec/vaapi_encode_vp8.c   |  11 +-
>  libavcodec/vaapi_encode_vp9.c   |  34 ++---
>  9 files changed, 310 insertions(+), 181 deletions(-)
> 
> diff --git a/doc/encoders.texi b/doc/encoders.texi
> index 7b095754d1..16be6359b3 100644
> --- a/doc/encoders.texi
> +++ b/doc/encoders.texi
> @@ -2565,6 +2565,9 @@ The following standard libavcodec options are used:
>  @option{bf} / @option{max_b_frames}
>  @item
>  @option{profile}
> +
> +If not set, this will be determined automatically from the format of the
> input
> +frames and the profiles supported by the driver.
>  @item
>  @option{level}
>  @item
> diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
> index 27ce792fbe..6104470b31 100644
> --- a/libavcodec/vaapi_encode.c
> +++ b/libavcodec/vaapi_encode.c
> @@ -983,70 +983,247 @@ static av_cold void
> vaapi_encode_add_global_param(AVCodecContext *avctx,
>      ++ctx->nb_global_params;
>  }
>  
> -static av_cold int vaapi_encode_config_attributes(AVCodecContext *avctx)
> +typedef struct VAAPIEncodeRTFormat {
> +    const char *name;
> +    unsigned int value;
> +    int depth;
> +    int components;

How about adding a prefix of 'nb_' to this field? I think nb_components is more
readable. 

> +    int log2_chroma_w;
> +    int log2_chroma_h;
> +} VAAPIEncodeRTFormat;
> +
> +static const VAAPIEncodeRTFormat vaapi_encode_rt_formats[] = {
> +    { "YUV400",    VA_RT_FORMAT_YUV400,        8, 1,      },
> +    { "YUV420",    VA_RT_FORMAT_YUV420,        8, 3, 1, 1 },
> +    { "YUV422",    VA_RT_FORMAT_YUV422,        8, 3, 1, 0 },
> +    { "YUV444",    VA_RT_FORMAT_YUV444,        8, 3, 0, 0 },
> +    { "YUV411",    VA_RT_FORMAT_YUV411,        8, 3, 2, 0 },
> +#if VA_CHECK_VERSION(0, 38, 1)
> +    { "YUV420_10", VA_RT_FORMAT_YUV420_10BPP, 10, 3, 1, 1 },
> +#endif
> +};
> +
> +static const VAEntrypoint vaapi_encode_entrypoints_normal[] = {
> +    VAEntrypointEncSlice,
> +    VAEntrypointEncPicture,
> +#if VA_CHECK_VERSION(0, 39, 2)
> +    VAEntrypointEncSliceLP,
> +#endif
> +    0
> +};
> +#if VA_CHECK_VERSION(0, 39, 2)
> +static const VAEntrypoint vaapi_encode_entrypoints_low_power[] = {
> +    VAEntrypointEncSliceLP,
> +    0
> +};
> +#endif
> +
> +static av_cold int vaapi_encode_profile_entrypoint(AVCodecContext *avctx)
>  {
> -    VAAPIEncodeContext *ctx = avctx->priv_data;
> +    VAAPIEncodeContext      *ctx = avctx->priv_data;
> +    VAProfile    *va_profiles    = NULL;
> +    VAEntrypoint *va_entrypoints = NULL;
>      VAStatus vas;
> -    int i, n, err;
> -    VAProfile    *profiles    = NULL;
> -    VAEntrypoint *entrypoints = NULL;
> -    VAConfigAttrib attr[] = {
> -        { VAConfigAttribRTFormat         },
> -        { VAConfigAttribRateControl      },
> -        { VAConfigAttribEncMaxRefFrames  },
> -        { VAConfigAttribEncPackedHeaders },
> -    };
> +    const VAEntrypoint *usable_entrypoints;
> +    const VAAPIEncodeProfile *profile;
> +    const AVPixFmtDescriptor *desc;
> +    VAConfigAttrib rt_format_attr;
> +    const VAAPIEncodeRTFormat *rt_format;
> +    int i, j, n, depth, err;
> +
> +
> +    if (ctx->low_power) {
> +#if VA_CHECK_VERSION(0, 39, 2)
> +        usable_entrypoints = vaapi_encode_entrypoints_low_power;
> +#else
> +        av_log(avctx, AV_LOG_ERROR, "Low-power encoding is not "
> +               "supported with this VAAPI version.\n");

Is it possible to report the minimal VAAPI version in the log in case user
doesn't know the requirement on vaapi version 0.39.2?

> +        return AVERROR(EINVAL);
> +#endif
> +    } else {
> +        usable_entrypoints = vaapi_encode_entrypoints_normal;
> +    }
> +
> +    desc = av_pix_fmt_desc_get(ctx->input_frames->sw_format);
> +    if (!desc) {
> +        av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%d).\n",
> +               ctx->input_frames->sw_format);
> +        return AVERROR(EINVAL);
> +    }
> +    depth = desc->comp[0].depth;
> +    for (i = 1; i < desc->nb_components; i++) {
> +        if (desc->comp[i].depth != depth) {
> +            av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%s).\n",
> +                   desc->name);
> +            return AVERROR(EINVAL);
> +        }
> +    }
> +    av_log(avctx, AV_LOG_VERBOSE, "Input surface format is %s.\n",
> +           desc->name);
>  
>      n = vaMaxNumProfiles(ctx->hwctx->display);
> -    profiles = av_malloc_array(n, sizeof(VAProfile));
> -    if (!profiles) {
> +    va_profiles = av_malloc_array(n, sizeof(VAProfile));
> +    if (!va_profiles) {
>          err = AVERROR(ENOMEM);
>          goto fail;
>      }
> -    vas = vaQueryConfigProfiles(ctx->hwctx->display, profiles, &n);
> +    vas = vaQueryConfigProfiles(ctx->hwctx->display, va_profiles, &n);
>      if (vas != VA_STATUS_SUCCESS) {
> -        av_log(ctx, AV_LOG_ERROR, "Failed to query profiles: %d (%s).\n",
> +        av_log(avctx, AV_LOG_ERROR, "Failed to query profiles: %d (%s).\n",
>                 vas, vaErrorStr(vas));
> -        err = AVERROR(ENOSYS);
> +        err = AVERROR_EXTERNAL;
>          goto fail;
>      }
> -    for (i = 0; i < n; i++) {
> -        if (profiles[i] == ctx->va_profile)
> -            break;
> +
> +    av_assert0(ctx->codec->profiles);
> +    for (i = 0; (ctx->codec->profiles[i].av_profile !=
> +                 FF_PROFILE_UNKNOWN); i++) {
> +        profile = &ctx->codec->profiles[i];
> +        if (depth               != profile->depth ||
> +            desc->nb_components != profile->components)
> +            continue;
> +        if (desc->nb_components > 1 &&
> +            (desc->log2_chroma_w != profile->log2_chroma_w ||
> +             desc->log2_chroma_h != profile->log2_chroma_h))
> +            continue;
> +        if (avctx->profile != profile->av_profile &&
> +            avctx->profile != FF_PROFILE_UNKNOWN)
> +            continue;
> +
> +        for (j = 0; j < n; j++) {
> +            if (va_profiles[j] == profile->va_profile)
> +                break;
> +        }
> +        if (j >= n) {
> +            av_log(avctx, AV_LOG_VERBOSE, "Matching profile %d is "
> +                   "not supported by driver.\n", profile->va_profile);

Is it possible to report the profile string in the log as what you did below?

> +            continue;
> +        }
> +
> +        ctx->profile = profile;
> +        break;
>      }
> -    if (i >= n) {
> -        av_log(ctx, AV_LOG_ERROR, "Encoding profile not found (%d).\n",
> -               ctx->va_profile);
> -        err = AVERROR(ENOSYS);
> -        goto fail;
> +    if (!ctx->profile) {
> +        av_log(avctx, AV_LOG_ERROR, "No usable encoding profile found.\n");
> +        return AVERROR(ENOSYS);

Set err to AVERROR(ENOSYS) then goto fail, otherwise it will result in memory
leak.

>      }
>  
> +    avctx->profile  = profile->av_profile;
> +    ctx->va_profile = profile->va_profile;
> +#if VA_CHECK_VERSION(1, 0, 0)
> +    av_log(avctx, AV_LOG_VERBOSE, "Using VAAPI profile %s (%d).\n",
> +           vaProfileStr(ctx->va_profile), ctx->va_profile);
> +#else
> +    av_log(avctx, AV_LOG_VERBOSE, "Using VAAPI profile %d.\n",
> +           ctx->va_profile);
> +#endif
> +
>      n = vaMaxNumEntrypoints(ctx->hwctx->display);
> -    entrypoints = av_malloc_array(n, sizeof(VAEntrypoint));
> -    if (!entrypoints) {
> +    va_entrypoints = av_malloc_array(n, sizeof(VAEntrypoint));
> +    if (!va_entrypoints) {
>          err = AVERROR(ENOMEM);
>          goto fail;
>      }
>      vas = vaQueryConfigEntrypoints(ctx->hwctx->display, ctx->va_profile,
> -                                   entrypoints, &n);
> +                                   va_entrypoints, &n);
>      if (vas != VA_STATUS_SUCCESS) {
> -        av_log(ctx, AV_LOG_ERROR, "Failed to query entrypoints for "
> +        av_log(avctx, AV_LOG_ERROR, "Failed to query entrypoints for "
>                 "profile %u: %d (%s).\n", ctx->va_profile,

Log profile string?

>                 vas, vaErrorStr(vas));
> -        err = AVERROR(ENOSYS);
> +        err = AVERROR_EXTERNAL;
>          goto fail;
>      }
> +
>      for (i = 0; i < n; i++) {
> -        if (entrypoints[i] == ctx->va_entrypoint)
> +        for (j = 0; usable_entrypoints[j]; j++) {
> +            if (va_entrypoints[i] == usable_entrypoints[j])
> +                break;
> +        }
> +        if (usable_entrypoints[j])
>              break;
>      }
>      if (i >= n) {
> -        av_log(ctx, AV_LOG_ERROR, "Encoding entrypoint not found "
> -               "(%d / %d).\n", ctx->va_profile, ctx->va_entrypoint);
> +        av_log(avctx, AV_LOG_ERROR, "No usable encoding entrypoint found "
> +               "for profile %d.\n", ctx->va_profile);

Log profile string?

> +        err = AVERROR(ENOSYS);
> +        goto fail;
> +    }
> +
> +    ctx->va_entrypoint = va_entrypoints[i];
> +#if VA_CHECK_VERSION(1, 0, 0)
> +    av_log(avctx, AV_LOG_VERBOSE, "Using VAAPI entrypoint %s (%d).\n",
> +           vaEntrypointStr(ctx->va_entrypoint), ctx->va_entrypoint);
> +#else
> +    av_log(avctx, AV_LOG_VERBOSE, "Using VAAPI entrypoint %d.\n",
> +           ctx->va_entrypoint);
> +#endif
> +
> +    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_encode_rt_formats); i++) {
> +        rt_format = &vaapi_encode_rt_formats[i];
> +        if (rt_format->depth         == depth &&
> +            rt_format->components    == profile->components    &&
> +            rt_format->log2_chroma_w == profile->log2_chroma_w &&
> +            rt_format->log2_chroma_h == profile->log2_chroma_h)
> +            break;
> +    }
> +    if (i >= FF_ARRAY_ELEMS(vaapi_encode_rt_formats)) {
> +        av_log(avctx, AV_LOG_ERROR, "No usable render target format "
> +               "found for profile %d entrypoint %d.\n",
> +               ctx->va_profile, ctx->va_entrypoint);

Log profile and entrypoint strings?

>          err = AVERROR(ENOSYS);
>          goto fail;
>      }
>  
> +    rt_format_attr = (VAConfigAttrib) { VAConfigAttribRTFormat };
> +    vas = vaGetConfigAttributes(ctx->hwctx->display,
> +                                ctx->va_profile, ctx->va_entrypoint,
> +                                &rt_format_attr, 1);
> +    if (vas != VA_STATUS_SUCCESS) {
> +        av_log(avctx, AV_LOG_ERROR, "Failed to query RT format "
> +               "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
> +        err = AVERROR_EXTERNAL;
> +        goto fail;
> +    }
> +
> +    if (rt_format_attr.value == VA_ATTRIB_NOT_SUPPORTED) {
> +        av_log(avctx, AV_LOG_VERBOSE, "RT format config attribute not "
> +               "supported by driver: assuming surface RT format %s "
> +               "is valid.\n", rt_format->name);

I think it would be better to log it as a warning. 

> +    } else if (!(rt_format_attr.value & rt_format->value)) {
> +        av_log(avctx, AV_LOG_ERROR, "Surface RT format %s not supported "
> +               "by driver for encoding profile %d entrypoint %d.\n",
> +               rt_format->name, ctx->va_profile, ctx->va_entrypoint);
> +        err = AVERROR(ENOSYS);
> +        goto fail;
> +    } else {
> +        av_log(avctx, AV_LOG_VERBOSE, "Using VAAPI render target "
> +               "format %s (%#x).\n", rt_format->name, rt_format->value);
> +        ctx->config_attributes[ctx->nb_config_attributes++] =
> +            (VAConfigAttrib) {
> +            .type  = VAConfigAttribRTFormat,
> +            .value = rt_format->value,
> +        };
> +    }
> +
> +    err = 0;
> +fail:
> +    av_freep(&va_profiles);
> +    av_freep(&va_entrypoints);
> +    return err;
> +}
> +
> +static av_cold int vaapi_encode_config_attributes(AVCodecContext *avctx)
> +{
> +    VAAPIEncodeContext *ctx = avctx->priv_data;
> +    VAStatus vas;
> +    int i;
> +
> +    VAConfigAttrib attr[] = {
> +        { VAConfigAttribRateControl      },
> +        { VAConfigAttribEncMaxRefFrames  },
> +        { VAConfigAttribEncPackedHeaders },
> +    };
> +
>      vas = vaGetConfigAttributes(ctx->hwctx->display,
>                                  ctx->va_profile, ctx->va_entrypoint,
>                                  attr, FF_ARRAY_ELEMS(attr));
> @@ -1066,20 +1243,6 @@ static av_cold int
> vaapi_encode_config_attributes(AVCodecContext *avctx)
>              continue;
>          }
>          switch (attr[i].type) {
> -        case VAConfigAttribRTFormat:
> -            if (!(ctx->va_rt_format & attr[i].value)) {
> -                av_log(avctx, AV_LOG_ERROR, "Surface RT format %#x "
> -                       "is not supported (mask %#x).\n",
> -                       ctx->va_rt_format, attr[i].value);
> -                err = AVERROR(EINVAL);
> -                goto fail;
> -            }
> -            ctx->config_attributes[ctx->nb_config_attributes++] =
> -                (VAConfigAttrib) {
> -                .type  = VAConfigAttribRTFormat,
> -                .value = ctx->va_rt_format,
> -            };
> -            break;
>          case VAConfigAttribRateControl:
>              // Hack for backward compatibility: CBR was the only
>              // usable RC mode for a long time, so old drivers will
> @@ -1098,8 +1261,7 @@ static av_cold int
> vaapi_encode_config_attributes(AVCodecContext *avctx)
>                  av_log(avctx, AV_LOG_ERROR, "Rate control mode %#x "
>                         "is not supported (mask: %#x).\n",
>                         ctx->va_rc_mode, attr[i].value);
> -                err = AVERROR(EINVAL);
> -                goto fail;
> +                return AVERROR(EINVAL);
>              }
>              ctx->config_attributes[ctx->nb_config_attributes++] =
>                  (VAConfigAttrib) {
> @@ -1115,8 +1277,7 @@ static av_cold int
> vaapi_encode_config_attributes(AVCodecContext *avctx)
>              if (avctx->gop_size > 1 && ref_l0 < 1) {
>                  av_log(avctx, AV_LOG_ERROR, "P frames are not "
>                         "supported (%#x).\n", attr[i].value);
> -                err = AVERROR(EINVAL);
> -                goto fail;
> +                return AVERROR(EINVAL);
>              }
>              if (avctx->max_b_frames > 0 && ref_l1 < 1) {
>                  av_log(avctx, AV_LOG_WARNING, "B frames are not "
> @@ -1148,11 +1309,7 @@ static av_cold int
> vaapi_encode_config_attributes(AVCodecContext *avctx)
>          }
>      }
>  
> -    err = 0;
> -fail:
> -    av_freep(&profiles);
> -    av_freep(&entrypoints);
> -    return err;
> +    return 0;
>  }
>  
>  static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx)
> @@ -1407,6 +1564,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx)
>      ctx->device = (AVHWDeviceContext*)ctx->device_ref->data;
>      ctx->hwctx = ctx->device->hwctx;
>  
> +    err = vaapi_encode_profile_entrypoint(avctx);
> +    if (err < 0)
> +        goto fail;
> +
>      err = vaapi_encode_config_attributes(avctx);
>      if (err < 0)
>          goto fail;
> diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h
> index 54dc4a475e..212ab6726d 100644
> --- a/libavcodec/vaapi_encode.h
> +++ b/libavcodec/vaapi_encode.h
> @@ -23,6 +23,10 @@
>  
>  #include <va/va.h>
>  
> +#if VA_CHECK_VERSION(1, 0, 0)
> +#include <va/va_str.h>
> +#endif
> +
>  #include "libavutil/hwcontext.h"
>  #include "libavutil/hwcontext_vaapi.h"
>  
> @@ -86,18 +90,32 @@ typedef struct VAAPIEncodePicture {
>      VAAPIEncodeSlice *slices;
>  } VAAPIEncodePicture;
>  
> +typedef struct VAAPIEncodeProfile {
> +    // lavc profile value (FF_PROFILE_*).
> +    int       av_profile;
> +    // Supported bit depth.
> +    int       depth;
> +    // Number of components.
> +    int       components;
> +    // Chroma subsampling in width dimension.
> +    int       log2_chroma_w;
> +    // Chroma subsampling in height dimension.
> +    int       log2_chroma_h;
> +    // VAAPI profile value.
> +    VAProfile va_profile;
> +} VAAPIEncodeProfile;
> +
>  typedef struct VAAPIEncodeContext {
>      const AVClass *class;
>  
>      // Codec-specific hooks.
>      const struct VAAPIEncodeType *codec;
>  
> -    // Encoding profile (VAProfileXXX).
> -    VAProfile       va_profile;
> -    // Encoding entrypoint (usually VAEntryointEncSlice).
> -    VAEntrypoint    va_entrypoint;
> -    // Surface colour/sampling format (usually VA_RT_FORMAT_YUV420).
> -    unsigned int    va_rt_format;
> +    // Global options.
> +
> +    // Use low power encoding mode.
> +    int             low_power;
> +
>      // Rate control mode.
>      unsigned int    va_rc_mode;
>      // Supported packed headers (initially the desired set, modified
> @@ -113,6 +131,14 @@ typedef struct VAAPIEncodeContext {
>      // Everything above this point must be set before calling
>      // ff_vaapi_encode_init().
>  
> +    // Chosen encoding profile details.
> +    const VAAPIEncodeProfile *profile;
> +
> +    // Encoding profile (VAProfile*).
> +    VAProfile       va_profile;
> +    // Encoding entrypoint (VAEntryoint*).
> +    VAEntrypoint    va_entrypoint;
> +
>      // Configuration attributes to use when creating va_config.
>      VAConfigAttrib  config_attributes[MAX_CONFIG_ATTRIBUTES];
>      int          nb_config_attributes;
> @@ -204,8 +230,11 @@ typedef struct VAAPIEncodeContext {
>      int end_of_stream;
>  } VAAPIEncodeContext;
>  
> -
>  typedef struct VAAPIEncodeType {
> +    // List of supported profiles and corresponding VAAPI profiles.
> +    // (Must end with FF_PROFILE_UNKNOWN.)
> +    const VAAPIEncodeProfile *profiles;
> +
>      // Perform any extra codec-specific configuration after the
>      // codec context is initialised (set up the private data and
>      // add any necessary global parameters).
> diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c
> index 8f999b2311..ab8bf13ef3 100644
> --- a/libavcodec/vaapi_encode_h264.c
> +++ b/libavcodec/vaapi_encode_h264.c
> @@ -866,7 +866,17 @@ static av_cold int
> vaapi_encode_h264_configure(AVCodecContext *avctx)
>      return 0;
>  }
>  
> +static const VAAPIEncodeProfile vaapi_encode_h264_profiles[] = {
> +    { FF_PROFILE_H264_HIGH, 8, 3, 1, 1, VAProfileH264High },
> +    { FF_PROFILE_H264_MAIN, 8, 3, 1, 1, VAProfileH264Main },
> +    { FF_PROFILE_H264_CONSTRAINED_BASELINE,
> +                            8, 3, 1, 1, VAProfileH264ConstrainedBaseline },
> +    { FF_PROFILE_UNKNOWN }
> +};
> +
>  static const VAAPIEncodeType vaapi_encode_type_h264 = {
> +    .profiles              = vaapi_encode_h264_profiles,
> +
>      .configure             = &vaapi_encode_h264_configure,
>  
>      .sequence_params_size  = sizeof(VAEncSequenceParameterBufferH264),
> @@ -899,30 +909,17 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext
> *avctx)
>      if (avctx->level == FF_LEVEL_UNKNOWN)
>          avctx->level = priv->level;
>  
> +    // Reject unsupported profiles.
>      switch (avctx->profile) {
>      case FF_PROFILE_H264_BASELINE:
>          av_log(avctx, AV_LOG_WARNING, "H.264 baseline profile is not "
>                 "supported, using constrained baseline profile instead.\n");
>          avctx->profile = FF_PROFILE_H264_CONSTRAINED_BASELINE;
> -    case FF_PROFILE_H264_CONSTRAINED_BASELINE:
> -        ctx->va_profile = VAProfileH264ConstrainedBaseline;
> -        if (avctx->max_b_frames != 0) {
> -            avctx->max_b_frames = 0;
> -            av_log(avctx, AV_LOG_WARNING, "H.264 constrained baseline profile
> "
> -                   "doesn't support encoding with B frames, disabling
> them.\n");
> -        }
> -        break;
> -    case FF_PROFILE_H264_MAIN:
> -        ctx->va_profile = VAProfileH264Main;
>          break;
>      case FF_PROFILE_H264_EXTENDED:
>          av_log(avctx, AV_LOG_ERROR, "H.264 extended profile "
>                 "is not supported.\n");
>          return AVERROR_PATCHWELCOME;
> -    case FF_PROFILE_UNKNOWN:
> -    case FF_PROFILE_H264_HIGH:
> -        ctx->va_profile = VAProfileH264High;
> -        break;
>      case FF_PROFILE_H264_HIGH_10:
>      case FF_PROFILE_H264_HIGH_10_INTRA:
>          av_log(avctx, AV_LOG_ERROR, "H.264 10-bit profiles "
> @@ -937,25 +934,9 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext
> *avctx)
>          av_log(avctx, AV_LOG_ERROR, "H.264 non-4:2:0 profiles "
>                 "are not supported.\n");
>          return AVERROR_PATCHWELCOME;
> -    default:
> -        av_log(avctx, AV_LOG_ERROR, "Unknown H.264 profile %d.\n",
> -               avctx->profile);
> -        return AVERROR(EINVAL);
> -    }
> -    if (priv->low_power) {
> -#if VA_CHECK_VERSION(0, 39, 2)
> -        ctx->va_entrypoint = VAEntrypointEncSliceLP;
> -#else
> -        av_log(avctx, AV_LOG_ERROR, "Low-power encoding is not "
> -               "supported with this VAAPI version.\n");
> -        return AVERROR(EINVAL);
> -#endif
> -    } else {
> -        ctx->va_entrypoint = VAEntrypointEncSlice;
>      }
>  
> -    // Only 8-bit encode is supported.
> -    ctx->va_rt_format = VA_RT_FORMAT_YUV420;
> +    ctx->low_power = priv->low_power;
>  
>      if (avctx->bit_rate > 0) {
>          if (avctx->rc_max_rate == avctx->bit_rate)
> @@ -1022,7 +1003,7 @@ static const AVOption vaapi_encode_h264_options[] = {
>  
>      { "profile", "Set profile (profile_idc and constraint_set*_flag)",
>        OFFSET(profile), AV_OPT_TYPE_INT,
> -      { .i64 = FF_PROFILE_H264_HIGH }, 0x0000, 0xffff, FLAGS, "profile" },
> +      { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, 0xffff, FLAGS,
> "profile" },
>  
>  #define PROFILE(name, value)  name, NULL, 0, AV_OPT_TYPE_CONST, \
>        { .i64 = value }, 0, 0, FLAGS, "profile"
> diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c
> index 8f191efc4b..9fa16593d0 100644
> --- a/libavcodec/vaapi_encode_h265.c
> +++ b/libavcodec/vaapi_encode_h265.c
> @@ -1025,7 +1025,17 @@ static av_cold int
> vaapi_encode_h265_configure(AVCodecContext *avctx)
>      return 0;
>  }
>  
> +static const VAAPIEncodeProfile vaapi_encode_h265_profiles[] = {
> +    { FF_PROFILE_HEVC_MAIN,     8, 3, 1, 1, VAProfileHEVCMain       },
> +#if VA_CHECK_VERSION(0, 37, 0)
> +    { FF_PROFILE_HEVC_MAIN_10, 10, 3, 1, 1, VAProfileHEVCMain10     },
> +#endif
> +    { FF_PROFILE_UNKNOWN }
> +};
> +
>  static const VAAPIEncodeType vaapi_encode_type_h265 = {
> +    .profiles              = vaapi_encode_h265_profiles,
> +
>      .configure             = &vaapi_encode_h265_configure,
>  
>      .sequence_params_size  = sizeof(VAEncSequenceParameterBufferHEVC),
> @@ -1058,29 +1068,6 @@ static av_cold int
> vaapi_encode_h265_init(AVCodecContext *avctx)
>      if (avctx->level == FF_LEVEL_UNKNOWN)
>          avctx->level = priv->level;
>  
> -    switch (avctx->profile) {
> -    case FF_PROFILE_HEVC_MAIN:
> -    case FF_PROFILE_UNKNOWN:
> -        ctx->va_profile = VAProfileHEVCMain;
> -        ctx->va_rt_format = VA_RT_FORMAT_YUV420;
> -        break;
> -    case FF_PROFILE_HEVC_MAIN_10:
> -#ifdef VA_RT_FORMAT_YUV420_10BPP
> -        ctx->va_profile = VAProfileHEVCMain10;
> -        ctx->va_rt_format = VA_RT_FORMAT_YUV420_10BPP;
> -        break;
> -#else
> -        av_log(avctx, AV_LOG_ERROR, "10-bit encoding is not "
> -               "supported with this VAAPI version.\n");
> -        return AVERROR(ENOSYS);
> -#endif
> -    default:
> -        av_log(avctx, AV_LOG_ERROR, "Unknown H.265 profile %d.\n",
> -               avctx->profile);
> -        return AVERROR(EINVAL);
> -    }
> -    ctx->va_entrypoint = VAEntrypointEncSlice;
> -
>      if (avctx->bit_rate > 0) {
>          if (avctx->rc_max_rate == avctx->bit_rate)
>              ctx->va_rc_mode = VA_RC_CBR;
> @@ -1120,7 +1107,7 @@ static const AVOption vaapi_encode_h265_options[] = {
>  
>      { "profile", "Set profile (general_profile_idc)",
>        OFFSET(profile), AV_OPT_TYPE_INT,
> -      { .i64 = FF_PROFILE_HEVC_MAIN }, 0x00, 0xff, FLAGS, "profile" },
> +      { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, 0xff, FLAGS,
> "profile" },
>  
>  #define PROFILE(name, value)  name, NULL, 0, AV_OPT_TYPE_CONST, \
>        { .i64 = value }, 0, 0, FLAGS, "profile"
> diff --git a/libavcodec/vaapi_encode_mjpeg.c b/libavcodec/vaapi_encode_mjpeg.c
> index 481981a71c..b328beaa09 100644
> --- a/libavcodec/vaapi_encode_mjpeg.c
> +++ b/libavcodec/vaapi_encode_mjpeg.c
> @@ -359,7 +359,15 @@ static av_cold int
> vaapi_encode_mjpeg_configure(AVCodecContext *avctx)
>      return 0;
>  }
>  
> +static const VAAPIEncodeProfile vaapi_encode_mjpeg_profiles[] = {
> +    { FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT,
> +            8, 3, 1, 1, VAProfileJPEGBaseline },
> +    { FF_PROFILE_UNKNOWN }
> +};
> +
>  static const VAAPIEncodeType vaapi_encode_type_mjpeg = {
> +    .profiles              = vaapi_encode_mjpeg_profiles,
> +
>      .configure             = &vaapi_encode_mjpeg_configure,
>  
>      .picture_params_size   = sizeof(VAEncPictureParameterBufferJPEG),
> @@ -380,11 +388,6 @@ static av_cold int vaapi_encode_mjpeg_init(AVCodecContext
> *avctx)
>  
>      ctx->codec = &vaapi_encode_type_mjpeg;
>  
> -    ctx->va_profile    = VAProfileJPEGBaseline;
> -    ctx->va_entrypoint = VAEntrypointEncPicture;
> -
> -    ctx->va_rt_format = VA_RT_FORMAT_YUV420;
> -
>      ctx->va_rc_mode = VA_RC_CQP;
>  
>      // The JPEG image header - see note above.
> diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c
> index 5577fa9e04..7f6c7833da 100644
> --- a/libavcodec/vaapi_encode_mpeg2.c
> +++ b/libavcodec/vaapi_encode_mpeg2.c
> @@ -552,7 +552,15 @@ static av_cold int
> vaapi_encode_mpeg2_configure(AVCodecContext *avctx)
>      return 0;
>  }
>  
> +static const VAAPIEncodeProfile vaapi_encode_mpeg2_profiles[] = {
> +    { FF_PROFILE_MPEG2_MAIN,   8, 3, 1, 1, VAProfileMPEG2Main   },
> +    { FF_PROFILE_MPEG2_SIMPLE, 8, 3, 1, 1, VAProfileMPEG2Simple },
> +    { FF_PROFILE_UNKNOWN }
> +};
> +
>  static const VAAPIEncodeType vaapi_encode_type_mpeg2 = {
> +    .profiles              = vaapi_encode_mpeg2_profiles,
> +
>      .configure             = &vaapi_encode_mpeg2_configure,
>  
>      .sequence_params_size  = sizeof(VAEncSequenceParameterBufferMPEG2),
> @@ -577,31 +585,6 @@ static av_cold int vaapi_encode_mpeg2_init(AVCodecContext
> *avctx)
>  
>      ctx->codec = &vaapi_encode_type_mpeg2;
>  
> -    switch (avctx->profile) {
> -    case FF_PROFILE_MPEG2_SIMPLE:
> -        ctx->va_profile = VAProfileMPEG2Simple;
> -        break;
> -    case FF_PROFILE_MPEG2_MAIN:
> -        ctx->va_profile = VAProfileMPEG2Main;
> -        break;
> -    case FF_PROFILE_MPEG2_422:
> -        av_log(avctx, AV_LOG_ERROR, "MPEG-2 4:2:2 profile "
> -               "is not supported.\n");
> -        return AVERROR_PATCHWELCOME;
> -    case FF_PROFILE_MPEG2_HIGH:
> -        av_log(avctx, AV_LOG_ERROR, "MPEG-2 high profile "
> -               "is not supported.\n");
> -        return AVERROR_PATCHWELCOME;
> -    case FF_PROFILE_MPEG2_SS:
> -    case FF_PROFILE_MPEG2_SNR_SCALABLE:
> -        av_log(avctx, AV_LOG_ERROR, "MPEG-2 scalable profiles "
> -               "are not supported.\n");
> -        return AVERROR_PATCHWELCOME;
> -    default:
> -        av_log(avctx, AV_LOG_ERROR, "Unknown MPEG-2 profile %d.\n",
> -               avctx->profile);
> -        return AVERROR(EINVAL);
> -    }
>      switch (avctx->level) {
>      case 4: // High
>      case 6: // High 1440
> @@ -620,8 +603,6 @@ static av_cold int vaapi_encode_mpeg2_init(AVCodecContext
> *avctx)
>          return AVERROR(EINVAL);
>      }
>  
> -    ctx->va_entrypoint = VAEntrypointEncSlice;
> -    ctx->va_rt_format  = VA_RT_FORMAT_YUV420;
>      ctx->va_rc_mode    = VA_RC_CQP;
>  
>      ctx->va_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE |
> @@ -643,7 +624,6 @@ static av_cold int vaapi_encode_mpeg2_close(AVCodecContext
> *avctx)
>  }
>  
>  static const AVCodecDefault vaapi_encode_mpeg2_defaults[] = {
> -    { "profile",        "4"   },
>      { "level",          "4"   },
>      { "bf",             "1"   },
>      { "g",              "120" },
> diff --git a/libavcodec/vaapi_encode_vp8.c b/libavcodec/vaapi_encode_vp8.c
> index 6cdd30abda..a502df7885 100644
> --- a/libavcodec/vaapi_encode_vp8.c
> +++ b/libavcodec/vaapi_encode_vp8.c
> @@ -175,7 +175,14 @@ static av_cold int
> vaapi_encode_vp8_configure(AVCodecContext *avctx)
>      return 0;
>  }
>  
> +static const VAAPIEncodeProfile vaapi_encode_vp8_profiles[] = {
> +    { 0 /* VP8 has no profiles */, 8, 3, 1, 1, VAProfileVP8Version0_3 },
> +    { FF_PROFILE_UNKNOWN }
> +};
> +
>  static const VAAPIEncodeType vaapi_encode_type_vp8 = {
> +    .profiles              = vaapi_encode_vp8_profiles,
> +
>      .configure             = &vaapi_encode_vp8_configure,
>  
>      .sequence_params_size  = sizeof(VAEncSequenceParameterBufferVP8),
> @@ -198,10 +205,6 @@ static av_cold int vaapi_encode_vp8_init(AVCodecContext
> *avctx)
>  
>      ctx->codec = &vaapi_encode_type_vp8;
>  
> -    ctx->va_profile    = VAProfileVP8Version0_3;
> -    ctx->va_entrypoint = VAEntrypointEncSlice;
> -    ctx->va_rt_format  = VA_RT_FORMAT_YUV420;
> -
>      if (avctx->flags & AV_CODEC_FLAG_QSCALE) {
>          ctx->va_rc_mode = VA_RC_CQP;
>      } else if (avctx->bit_rate > 0) {
> diff --git a/libavcodec/vaapi_encode_vp9.c b/libavcodec/vaapi_encode_vp9.c
> index bf99597e4c..88c0ce3b0a 100644
> --- a/libavcodec/vaapi_encode_vp9.c
> +++ b/libavcodec/vaapi_encode_vp9.c
> @@ -203,7 +203,15 @@ static av_cold int
> vaapi_encode_vp9_configure(AVCodecContext *avctx)
>      return 0;
>  }
>  
> +static const VAAPIEncodeProfile vaapi_encode_vp9_profiles[] = {
> +    { FF_PROFILE_VP9_0,  8, 3, 1, 1, VAProfileVP9Profile0 },
> +    { FF_PROFILE_VP9_2, 10, 3, 1, 1, VAProfileVP9Profile2 },
> +    { FF_PROFILE_UNKNOWN }
> +};
> +
>  static const VAAPIEncodeType vaapi_encode_type_vp9 = {
> +    .profiles              = vaapi_encode_vp9_profiles,
> +
>      .configure             = &vaapi_encode_vp9_configure,
>  
>      .sequence_params_size  = sizeof(VAEncSequenceParameterBufferVP9),
> @@ -219,31 +227,6 @@ static av_cold int vaapi_encode_vp9_init(AVCodecContext
> *avctx)
>  
>      ctx->codec = &vaapi_encode_type_vp9;
>  
> -    switch (avctx->profile) {
> -    case FF_PROFILE_VP9_0:
> -    case FF_PROFILE_UNKNOWN:
> -        ctx->va_profile = VAProfileVP9Profile0;
> -        ctx->va_rt_format = VA_RT_FORMAT_YUV420;
> -        break;
> -    case FF_PROFILE_VP9_1:
> -        av_log(avctx, AV_LOG_ERROR, "VP9 profile 1 is not "
> -               "supported.\n");
> -        return AVERROR_PATCHWELCOME;
> -    case FF_PROFILE_VP9_2:
> -        ctx->va_profile = VAProfileVP9Profile2;
> -        ctx->va_rt_format = VA_RT_FORMAT_YUV420_10BPP;
> -        break;
> -    case FF_PROFILE_VP9_3:
> -        av_log(avctx, AV_LOG_ERROR, "VP9 profile 3 is not "
> -               "supported.\n");
> -        return AVERROR_PATCHWELCOME;
> -    default:
> -        av_log(avctx, AV_LOG_ERROR, "Unknown VP9 profile %d.\n",
> -               avctx->profile);
> -        return AVERROR(EINVAL);
> -    }
> -    ctx->va_entrypoint = VAEntrypointEncSlice;
> -
>      if (avctx->flags & AV_CODEC_FLAG_QSCALE) {
>          ctx->va_rc_mode = VA_RC_CQP;
>      } else if (avctx->bit_rate > 0) {
> @@ -276,7 +259,6 @@ static const AVOption vaapi_encode_vp9_options[] = {
>  };
>  
>  static const AVCodecDefault vaapi_encode_vp9_defaults[] = {
> -    { "profile",        "0"   },
>      { "b",              "0"   },
>      { "bf",             "0"   },
>      { "g",              "250" },


More information about the ffmpeg-devel mailing list