[FFmpeg-devel] [RFC 3/4] vaapi: add new API to configure a VA pipeline.

Gwenole Beauchesne gb.devel at gmail.com
Wed Aug 19 19:19:07 CEST 2015


Hi,

2015-08-19 18:50 GMT+02:00 wm4 <nfxjfg at googlemail.com>:
> On Wed, 19 Aug 2015 18:01:36 +0200
> Gwenole Beauchesne <gb.devel at gmail.com> wrote:
>
>> Add av_vaapi_set_pipeline_params() interface to initialize the internal
>> FFVAContext with a valid VA display, and optional parameters including
>> a user-supplied VA context id.
>>
>> This is preparatory work for delegating VA pipeline (decoder) creation
>> to libavcodec. Meanwhile, if this new interface is used, the user shall
>> provide the VA context id and a valid AVCodecContext.get_buffer2() hook.
>> Otherwise, the older vaapi_context approach is still supported.
>>
>> This is an API change. The whole vaapi_context structure is no longer
>> needed, and thus deprecated.
>>
>> Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne at intel.com>
>> ---
>>  doc/APIchanges              |  6 ++--
>>  libavcodec/vaapi.c          | 87 ++++++++++++++++++++++++++++++++++++++++-----
>>  libavcodec/vaapi.h          | 49 +++++++++++++++++++++++--
>>  libavcodec/vaapi_internal.h |  4 +++
>>  4 files changed, 134 insertions(+), 12 deletions(-)
>>
>> diff --git a/doc/APIchanges b/doc/APIchanges
>> index aa92b69..fcdaa26 100644
>> --- a/doc/APIchanges
>> +++ b/doc/APIchanges
>> @@ -16,8 +16,10 @@ libavutil:     2014-08-09
>>  API changes, most recent first:
>>
>>  2015-xx-xx - lavc 56.58.100 - vaapi.h
>> -  Deprecate old VA-API context (vaapi_context) fields that were only
>> -  set and used by libavcodec. They are all managed internally now.
>> +  Add new API to configure the hwaccel/vaapi pipeline, currently
>> +  useful for decoders: av_vaapi_set_pipeline_params()
>> +  Deprecate old VA-API context (vaapi_context) structure, which is no
>> +  longer used for initializing a VA-API decode pipeline.
>>
>>  2015-xx-xx - lavu 54.31.100 - pixfmt.h
>>    Add a unique pixel format for VA-API (AV_PIX_FMT_VAAPI) that
>> diff --git a/libavcodec/vaapi.c b/libavcodec/vaapi.c
>> index c081bb5..afddbb3 100644
>> --- a/libavcodec/vaapi.c
>> +++ b/libavcodec/vaapi.c
>> @@ -41,24 +41,95 @@ static void destroy_buffers(VADisplay display, VABufferID *buffers, unsigned int
>>      }
>>  }
>>
>> +/** @name VA-API pipeline parameters (internal) */
>> +/**@{*/
>> +/** Pipeline configuration flags (AV_HWACCEL_FLAG_*|AV_VAAPI_PIPELINE_FLAG_*) */
>> +#define AV_VAAPI_PIPELINE_PARAM_FLAGS           "flags"
>> +/** User-supplied VA display handle */
>> +#define AV_VAAPI_PIPELINE_PARAM_DISPLAY         "display"
>> +/**@}*/
>> +
>> +#define OFFSET(x) offsetof(FFVAContext, x)
>> +static const AVOption FFVAContextOptions[] = {
>> +    { AV_VAAPI_PIPELINE_PARAM_FLAGS, "flags", OFFSET(flags),
>> +      AV_OPT_TYPE_INT, { .i64 = 0 }, 0, UINT32_MAX },
>> +    { AV_VAAPI_PIPELINE_PARAM_DISPLAY, "VA display", OFFSET(user_display),
>> +      AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, UINTPTR_MAX },
>> +    { AV_VAAPI_PIPELINE_PARAM_CONTEXT, "VA context id", OFFSET(user_context_id),
>> +      AV_OPT_TYPE_INT, { .i64 = VA_INVALID_ID }, 0, UINT32_MAX },
>> +    { NULL, }
>> +};
>> +#undef OFFSET
>> +
>> +static const AVClass FFVAContextClass = {
>> +    .class_name = "FFVAContext",
>> +    .item_name  = av_default_item_name,
>> +    .option     = FFVAContextOptions,
>> +    .version    = LIBAVUTIL_VERSION_INT,
>> +};
>> +
>> +int av_vaapi_set_pipeline_params(AVCodecContext *avctx, VADisplay display,
>> +                                 uint32_t flags, AVDictionary **params)
>> +{
>> +    int ret;
>> +
>> +    if (!display) {
>> +        av_log(avctx, AV_LOG_ERROR, "No valid VA display supplied.\n");
>> +        return AVERROR(EINVAL);
>> +    }
>> +
>> +    if (params && *params)
>> +        av_dict_copy(&avctx->internal->hwaccel_config, *params, 0);
>> +
>> +    ret = av_dict_set_int(&avctx->internal->hwaccel_config,
>> +                          AV_VAAPI_PIPELINE_PARAM_FLAGS, flags, 0);
>> +    if (ret != 0)
>> +        return ret;
>> +
>> +    return av_dict_set_int(&avctx->internal->hwaccel_config,
>> +                           AV_VAAPI_PIPELINE_PARAM_DISPLAY,
>> +                           (int64_t)(intptr_t)display, 0);
>> +}
>> +
>>  int ff_vaapi_context_init(AVCodecContext *avctx)
>>  {
>>      FFVAContext * const vactx = ff_vaapi_get_context(avctx);
>> -    const struct vaapi_context * const user_vactx = avctx->hwaccel_context;
>> +    int ret;
>>
>> -    if (!user_vactx) {
>> -        av_log(avctx, AV_LOG_ERROR, "Hardware acceleration context (hwaccel_context) does not exist.\n");
>> -        return AVERROR(ENOSYS);
>> -    }
>> +    vactx->klass = &FFVAContextClass;
>> +    av_opt_set_defaults(vactx);
>>
>> -    vactx->display              = user_vactx->display;
>> -    vactx->config_id            = user_vactx->config_id;
>> -    vactx->context_id           = user_vactx->context_id;
>> +#if FF_API_VAAPI_CONTEXT
>> +FF_DISABLE_DEPRECATION_WARNINGS
>> +    if (avctx->hwaccel_context) {
>> +        const struct vaapi_context * const user_vactx = avctx->hwaccel_context;
>> +        vactx->user_display     = (uintptr_t)user_vactx->display;
>> +        vactx->user_context_id  = user_vactx->context_id;
>> +    }
>> +FF_ENABLE_DEPRECATION_WARNINGS
>> +#endif
>>
>> +    vactx->context_id           = VA_INVALID_ID;
>>      vactx->pic_param_buf_id     = VA_INVALID_ID;
>>      vactx->iq_matrix_buf_id     = VA_INVALID_ID;
>>      vactx->bitplane_buf_id      = VA_INVALID_ID;
>>
>> +    ret = av_opt_set_dict(vactx, &avctx->internal->hwaccel_config);
>> +    if (ret != 0)
>> +        return ret;
>> +
>> +    vactx->display              = (void *)(uintptr_t)vactx->user_display;
>> +    vactx->context_id           = vactx->user_context_id;
>> +
>> +    if (!vactx->display) {
>> +        av_log(avctx, AV_LOG_ERROR, "No valid VA display found.\n");
>> +        return AVERROR(EINVAL);
>> +    }
>> +
>> +    if (vactx->context_id != VA_INVALID_ID && !avctx->get_buffer2) {
>> +        av_log(avctx, AV_LOG_ERROR, "No AVCodecContext.get_buffer2() hooked defined.\n");
>> +        return AVERROR(EINVAL);
>> +    }
>>      return 0;
>>  }
>>
>> diff --git a/libavcodec/vaapi.h b/libavcodec/vaapi.h
>> index 4448a2e..43f8381 100644
>> --- a/libavcodec/vaapi.h
>> +++ b/libavcodec/vaapi.h
>> @@ -32,7 +32,9 @@
>>
>>  #include <stdint.h>
>>  #include <libavutil/attributes.h>
>> +#include <va/va.h>
>>  #include "version.h"
>> +#include "avcodec.h"
>>
>>  /**
>>   * @defgroup lavc_codec_hwaccel_vaapi VA API Decoding
>> @@ -48,7 +50,11 @@
>>   * during initialization or through each AVCodecContext.get_buffer()
>>   * function call. In any case, they must be valid prior to calling
>>   * decoding functions.
>> + *
>> + * This structure is deprecated. Please refer to pipeline parameters
>> + * and associated accessors, e.g. av_vaapi_set_pipeline_params().
>>   */
>> +#if FF_API_VAAPI_CONTEXT
>>  struct vaapi_context {
>>      /**
>>       * Window system dependent data
>> @@ -56,6 +62,7 @@ struct vaapi_context {
>>       * - encoding: unused
>>       * - decoding: Set by user
>>       */
>> +    attribute_deprecated
>>      void *display;
>>
>>      /**
>> @@ -64,6 +71,7 @@ struct vaapi_context {
>>       * - encoding: unused
>>       * - decoding: Set by user
>>       */
>> +    attribute_deprecated
>>      uint32_t config_id;
>>
>>      /**
>> @@ -72,9 +80,9 @@ struct vaapi_context {
>>       * - encoding: unused
>>       * - decoding: Set by user
>>       */
>> +    attribute_deprecated
>>      uint32_t context_id;
>>
>> -#if FF_API_VAAPI_CONTEXT
>>      /**
>>       * VAPictureParameterBuffer ID
>>       *
>> @@ -181,8 +189,45 @@ struct vaapi_context {
>>       */
>>      attribute_deprecated
>>      uint32_t slice_data_size;
>> -#endif
>>  };
>> +#endif
>> +
>> +/** @name VA-API pipeline parameters */
>> +/**@{*/
>> +/**
>> + * VA context id (uint32_t) [default: VA_INVALID_ID]
>> + *
>> + * This defines the VA context id to use for decoding. If set, then
>> + * the user allocates and owns the handle, and shall supply VA surfaces
>> + * through an appropriate hook to AVCodecContext.get_buffer2().
>> + */
>> +#define AV_VAAPI_PIPELINE_PARAM_CONTEXT         "context"
>
> I don't understand this. Wouldn't it also be possible to use a
> user-defined get_buffer2 function, but with a context created by
> libavcodec?

Historically, you cannot create a decode pipeline without supplying a
fixed number of VA surfaces to vaCreateContext(). You cannot have any
guarantee either that re-creating a VA context with an increased
number of VA surfaces would still get things working. I have an
example of a pretty old and semi-opensource driver that stuffs various
local states into the VA context even if they are VA surface specific.

If we wanted to call get_buffer2() multiple times to get an initial
set of VA surfaces that you could use to create a VA context, (i) this
would be ugly IMHO, and (ii) there is no guarantee either that the
user get_buffer2() impl wouldn't hang/wait until his pool of free VA
surfaces fills in again.

Because of that, I believe it's better to restrict the usages to what
it is strictly permitted, for historical reasons. So, either user
creates VA surfaces + VA context, or he lets lavc do so but for both
VA surfaces & VA context as well. Besides, as I further distilled in
one of the patches, lavc naturally works through allocating buffers
itself for SW decoders, that can work, and this is something desired
to achieve with hwaccel too. At least for vaapi. i.e. you'd only need
to provide a VADisplay handle.

>> +/**@}*/
>> +
>> +/**
>> + * Defines VA processing pipeline parameters
>> + *
>> + * This function binds the supplied VA @a display to a codec context
>> + * @a avctx.
>> + *
>> + * The user retains full ownership of the display, and thus shall
>> + * ensure the VA-API subsystem was initialized with vaInitialize(),
>> + * make due diligence to keep it live until it is no longer needed,
>> + * and dispose the associated resources with vaTerminate() whenever
>> + * appropriate.
>> + *
>> + * @note This function has no effect if it is called outside of an
>> + * AVCodecContext.get_format() hook.
>> + *
>> + * @param[in] avctx     the codec context being used for decoding the stream
>> + * @param[in] display   the VA display handle to use for decoding
>> + * @param[in] flags     zero or more OR'd AV_HWACCEL_FLAG_* or
>> + *     AV_VAAPI_PIPELINE_FLAG_* flags
>> + * @param[in] params    optional parameters to configure the pipeline
>> + * @return 0 on success, an AVERROR code on failure.
>> + */
>> +int av_vaapi_set_pipeline_params(AVCodecContext *avctx, VADisplay display,
>> +                                 uint32_t flags, AVDictionary **params);
>>
>>  /* @} */
>>
>> diff --git a/libavcodec/vaapi_internal.h b/libavcodec/vaapi_internal.h
>> index 29f46ab..958246c 100644
>> --- a/libavcodec/vaapi_internal.h
>> +++ b/libavcodec/vaapi_internal.h
>> @@ -36,6 +36,10 @@
>>   */
>>
>>  typedef struct {
>> +    const void *klass;
>> +    uint32_t flags;                     ///< Pipeline flags
>> +    uint64_t user_display;              ///< User-supplied VA display
>> +    uint32_t user_context_id;           ///< User-supplied VA context ID
>>      VADisplay display;                  ///< Windowing system dependent handle
>>      VAConfigID config_id;               ///< Configuration ID
>>      VAContextID context_id;             ///< Context ID (video decode pipeline)
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Regards,
-- 
Gwenole Beauchesne
Intel Corporation SAS / 2 rue de Paris, 92196 Meudon Cedex, France
Registration Number (RCS): Nanterre B 302 456 199


More information about the ffmpeg-devel mailing list