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.)