[libav-devel] [PATCH 4/5] lavc/vdpau: add support for allocating surfaces internally

wm4 nfxjfg at googlemail.com
Sun Dec 27 14:41:16 CET 2015


On Sun, 20 Dec 2015 20:59:30 +0100
Anton Khirnov <anton at khirnov.net> wrote:

> ---
>  libavcodec/vdpau.c          | 101 ++++++++++++++++++++++++++++++++++++++++++--
>  libavcodec/vdpau_h264.c     |   1 +
>  libavcodec/vdpau_internal.h |  11 +++++
>  libavcodec/vdpau_mpeg12.c   |   1 +
>  libavcodec/vdpau_mpeg4.c    |   1 +
>  libavcodec/vdpau_vc1.c      |   2 +
>  6 files changed, 113 insertions(+), 4 deletions(-)
> 
> diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c
> index dd48c04..5c41ee8 100644
> --- a/libavcodec/vdpau.c
> +++ b/libavcodec/vdpau.c
> @@ -23,6 +23,10 @@
>  
>  #include <limits.h>
>  #include "libavutil/avassert.h"
> +#include "libavutil/buffer.h"
> +#include "libavutil/hwframe.h"
> +#include "libavutil/hwframe_vdpau.h"
> +
>  #include "avcodec.h"
>  #include "internal.h"
>  #include "h264.h"
> @@ -201,14 +205,52 @@ int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile,
>      else
>          vdctx->render = func;
>  
> +    status = vdctx->get_proc_address(vdctx->device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE,
> +                                     &func);
> +    if (status != VDP_STATUS_OK)
> +        return vdpau_error(status);
> +    vdctx->surf_create = func;
> +
> +    status = vdctx->get_proc_address(vdctx->device, VDP_FUNC_ID_VIDEO_SURFACE_DESTROY,
> +                                     &func);
> +    if (status != VDP_STATUS_OK)
> +        return vdpau_error(status);
> +    vdctx->surf_destroy = func;
> +
>      status = create(vdctx->device, profile, width, height, avctx->refs,
>                      &vdctx->decoder);
> -    if (status == VDP_STATUS_OK) {
> -        vdctx->width  = avctx->coded_width;
> -        vdctx->height = avctx->coded_height;
> +    if (status != VDP_STATUS_OK)
> +        return vdpau_error(status);
> +
> +    vdctx->width       = avctx->coded_width;
> +    vdctx->height      = avctx->coded_height;
> +    vdctx->chroma_type = type;
> +
> +    if (avctx->hwframe_ctx_free) {
> +        AVHWFramesContext *hwframe_ctx;
> +        AVVDPAUFramesContext *vdpau_frame_ctx;
> +        int ret;
> +
> +        vdctx->hwframe_ctx = av_hwframe_ctx_alloc(AV_PIX_FMT_VDPAU);
> +        if (!vdctx->hwframe_ctx)
> +            return AVERROR(ENOMEM);
> +
> +        hwframe_ctx              = (AVHWFramesContext*)vdctx->hwframe_ctx->data;
> +        hwframe_ctx->free        = avctx->hwframe_ctx_free;
> +        hwframe_ctx->user_opaque = avctx->hwframe_ctx_opaque;
> +
> +        vdpau_frame_ctx                   = hwframe_ctx->hwctx;
> +        vdpau_frame_ctx->device           = vdctx->device;
> +        vdpau_frame_ctx->get_proc_address = vdctx->get_proc_address;
> +
> +        ret = av_hwframe_ctx_init(vdctx->hwframe_ctx);
> +        if (ret < 0) {
> +            av_buffer_unref(&vdctx->hwframe_ctx);
> +            return ret;
> +        }
>      }
>  
> -    return vdpau_error(status);
> +    return 0;
>  }
>  
>  int ff_vdpau_common_uninit(AVCodecContext *avctx)
> @@ -218,6 +260,8 @@ int ff_vdpau_common_uninit(AVCodecContext *avctx)
>      void *func;
>      VdpStatus status;
>  
> +    av_buffer_unref(&vdctx->hwframe_ctx);
> +
>      if (vdctx->device == VDP_INVALID_HANDLE)
>          return 0; /* Decoder created and destroyed by user */
>      if (vdctx->width == UINT32_MAX && vdctx->height == UINT32_MAX)
> @@ -317,6 +361,55 @@ int ff_vdpau_add_buffer(struct vdpau_picture_context *pic_ctx,
>      return 0;
>  }
>  
> +static void vdpau_release_buffer(void *opaque, uint8_t *data)
> +{
> +    VdpVideoSurfaceDestroy *destroy = opaque;
> +    VdpVideoSurface            surf = (VdpVideoSurface)(uintptr_t)data;
> +
> +    destroy(surf);
> +}
> +
> +int ff_vdpau_get_buffer(AVCodecContext *avctx, AVFrame *frame)
> +{
> +    VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;
> +
> +    VdpVideoSurface surf;
> +    VdpStatus        err;
> +
> +    if (!vdctx->hwframe_ctx) {
> +        av_log(avctx, AV_LOG_ERROR,
> +               "You must set AVCodecContext.hwframe_ctx_free to use"
> +               "the internal VDPAU get_buffer().\n");
> +        return AVERROR(EINVAL);
> +    }
> +
> +    err = vdctx->surf_create(vdctx->device, vdctx->chroma_type,
> +                             frame->width, frame->height, &surf);
> +    if (err != VDP_STATUS_OK) {
> +        av_log(avctx, AV_LOG_ERROR, "Error creating a surface\n");
> +        return vdpau_error(err);
> +    }
> +
> +    frame->buf[0] = av_buffer_create((uint8_t*)(uintptr_t)surf, sizeof(surf),
> +                                     vdpau_release_buffer, vdctx->surf_destroy,
> +                                     AV_BUFFER_FLAG_READONLY);

Shouldn't this return/alloc the frame from a surface pool? (Though I'm
going to be happy if you tell me that vdpau surface allocation is
always maximally efficient and doesn't need a pool.)

> +    if (!frame->buf[0]) {
> +        vdctx->surf_destroy(surf);
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    frame->data[3] = (uint8_t*)(uintptr_t)surf;
> +
> +    frame->hw_ctx = av_buffer_ref(vdctx->hwframe_ctx);
> +    if (!frame->hw_ctx) {
> +        av_buffer_unref(&frame->buf[0]);
> +        frame->data[3] = NULL;
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    return 0;
> +}
> +
>  int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile)
>  {
>  #define PROFILE(prof)                      \
> diff --git a/libavcodec/vdpau_h264.c b/libavcodec/vdpau_h264.c
> index d03d127..ca4dad4 100644
> --- a/libavcodec/vdpau_h264.c
> +++ b/libavcodec/vdpau_h264.c
> @@ -266,6 +266,7 @@ AVHWAccel ff_h264_vdpau_hwaccel = {
>      .start_frame    = vdpau_h264_start_frame,
>      .end_frame      = vdpau_h264_end_frame,
>      .decode_slice   = vdpau_h264_decode_slice,
> +    .get_buffer     = ff_vdpau_get_buffer,
>      .frame_priv_data_size = sizeof(struct vdpau_picture_context),
>      .init           = vdpau_h264_init,
>      .uninit         = ff_vdpau_common_uninit,
> diff --git a/libavcodec/vdpau_internal.h b/libavcodec/vdpau_internal.h
> index f35c99d..3366f75 100644
> --- a/libavcodec/vdpau_internal.h
> +++ b/libavcodec/vdpau_internal.h
> @@ -27,7 +27,9 @@
>  #include <stdint.h>
>  #include <vdpau/vdpau.h>
>  
> +#include "libavutil/buffer.h"
>  #include "libavutil/frame.h"
> +#include "libavutil/hwframe.h"
>  
>  #include "avcodec.h"
>  #include "vdpau.h"
> @@ -77,8 +79,15 @@ typedef struct VDPAUContext {
>       */
>      VdpDecoderRender *render;
>  
> +    VdpVideoSurfaceCreate  *surf_create;
> +    VdpVideoSurfaceDestroy *surf_destroy;
> +
> +    VdpChromaType chroma_type;
> +
>      uint32_t width;
>      uint32_t height;
> +
> +    AVBufferRef *hwframe_ctx;
>  } VDPAUContext;
>  
>  struct vdpau_picture_context {
> @@ -115,4 +124,6 @@ int ff_vdpau_mpeg_end_frame(AVCodecContext *avctx);
>  int ff_vdpau_add_buffer(struct vdpau_picture_context *pic, const uint8_t *buf,
>                          uint32_t buf_size);
>  
> +int ff_vdpau_get_buffer(AVCodecContext *avctx, AVFrame *frame);
> +
>  #endif /* AVCODEC_VDPAU_INTERNAL_H */
> diff --git a/libavcodec/vdpau_mpeg12.c b/libavcodec/vdpau_mpeg12.c
> index cb6f81a..09ed9fd 100644
> --- a/libavcodec/vdpau_mpeg12.c
> +++ b/libavcodec/vdpau_mpeg12.c
> @@ -144,6 +144,7 @@ AVHWAccel ff_mpeg2_vdpau_hwaccel = {
>      .start_frame    = vdpau_mpeg_start_frame,
>      .end_frame      = ff_vdpau_mpeg_end_frame,
>      .decode_slice   = vdpau_mpeg_decode_slice,
> +    .get_buffer     = ff_vdpau_get_buffer,
>      .frame_priv_data_size = sizeof(struct vdpau_picture_context),
>      .init           = vdpau_mpeg2_init,
>      .uninit         = ff_vdpau_common_uninit,
> diff --git a/libavcodec/vdpau_mpeg4.c b/libavcodec/vdpau_mpeg4.c
> index fcad42f..5be4133 100644
> --- a/libavcodec/vdpau_mpeg4.c
> +++ b/libavcodec/vdpau_mpeg4.c
> @@ -114,6 +114,7 @@ AVHWAccel ff_mpeg4_vdpau_hwaccel = {
>      .start_frame    = vdpau_mpeg4_start_frame,
>      .end_frame      = ff_vdpau_mpeg_end_frame,
>      .decode_slice   = vdpau_mpeg4_decode_slice,
> +    .get_buffer     = ff_vdpau_get_buffer,
>      .frame_priv_data_size = sizeof(struct vdpau_picture_context),
>      .init           = vdpau_mpeg4_init,
>      .uninit         = ff_vdpau_common_uninit,
> diff --git a/libavcodec/vdpau_vc1.c b/libavcodec/vdpau_vc1.c
> index 4f87c52..111a0b7 100644
> --- a/libavcodec/vdpau_vc1.c
> +++ b/libavcodec/vdpau_vc1.c
> @@ -139,6 +139,7 @@ AVHWAccel ff_wmv3_vdpau_hwaccel = {
>      .start_frame    = vdpau_vc1_start_frame,
>      .end_frame      = ff_vdpau_mpeg_end_frame,
>      .decode_slice   = vdpau_vc1_decode_slice,
> +    .get_buffer     = ff_vdpau_get_buffer,
>      .frame_priv_data_size = sizeof(struct vdpau_picture_context),
>      .init           = vdpau_vc1_init,
>      .uninit         = ff_vdpau_common_uninit,
> @@ -154,6 +155,7 @@ AVHWAccel ff_vc1_vdpau_hwaccel = {
>      .start_frame    = vdpau_vc1_start_frame,
>      .end_frame      = ff_vdpau_mpeg_end_frame,
>      .decode_slice   = vdpau_vc1_decode_slice,
> +    .get_buffer     = ff_vdpau_get_buffer,
>      .frame_priv_data_size = sizeof(struct vdpau_picture_context),
>      .init           = vdpau_vc1_init,
>      .uninit         = ff_vdpau_common_uninit,



More information about the libav-devel mailing list