Le 2016-01-01 18:09, Anton Khirnov a écrit :
Quoting wm4 (2015-12-27 14:41:16)
On Sun, 20 Dec 2015 20:59:30 +0100
Anton Khirnov <[email protected]> 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.)


Rémi tells me the pools are not need for performance reasons. But some
old hardware requires preallocating surfaces for some other weird
reasons. And of course many other APIs can only work with the full pool
preallocated beforehand, so some support for that will be needed.

Uh? No. VDPAU has no requirements to preallocate surfaces. The problem is, preallocating is the only way to ensure that the GPU will have enough memory to meet the run-time buffers requirements.

Otherwise, you might end up, e.g. with 4 video surfaces on a bitstream that requires 16 reference frames. And fail.

--
Rémi Denis-Courmont
http://www.remlab.net/
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to