---
 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);
+    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,
-- 
2.0.0

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to