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.)
> + 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,
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel