Using the not so new init and uninit callbacks, avcodec can now take
care of creating and destroying the VDPAU decoder instance.

The application is still responsible for creating the VDPAU device
and allocating video surfaces - this is necessary to keep video
surfaces on the GPU all the way to the output. But the application
will no longer needs to care about any codec-specific aspects.
---
 libavcodec/vdpau.c          | 72 +++++++++++++++++++++++++++++++++++++++++++--
 libavcodec/vdpau.h          |  9 ++++++
 libavcodec/vdpau_internal.h | 26 ++++++++++++++++
 3 files changed, 105 insertions(+), 2 deletions(-)

diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c
index f09fe80..ef60b3d 100644
--- a/libavcodec/vdpau.c
+++ b/libavcodec/vdpau.c
@@ -22,7 +22,9 @@
  */
 
 #include <limits.h>
+#include "libavutil/avassert.h"
 #include "avcodec.h"
+#include "internal.h"
 #include "h264.h"
 #include "vc1.h"
 
@@ -62,6 +64,67 @@ static int vdpau_error(VdpStatus status)
     }
 }
 
+int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile,
+                         int level, uint32_t surfaces)
+{
+    AVVDPAUContext *hwctx = avctx->hwaccel_context;
+    VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;
+    VdpDecoderCreate *create;
+    void *func;
+    VdpStatus status;
+    /* See vdpau/vdpau.h for alignment constraints. */
+    uint32_t width  = (avctx->coded_width + 1) & ~1;
+    uint32_t height = (avctx->coded_height + 3) & ~3;
+
+    vdctx->device           = hwctx->device;
+    vdctx->get_proc_address = hwctx->get_proc_address;
+
+    if (hwctx->device == VDP_INVALID_HANDLE) {
+        vdctx->decoder = hwctx->decoder;
+        vdctx->render  = hwctx->render;
+        return 0; /* Decoder created by user */
+    }
+
+    status = vdctx->get_proc_address(vdctx->device, VDP_FUNC_ID_DECODER_CREATE,
+                                     &func);
+    if (status != VDP_STATUS_OK)
+        return vdpau_error(status);
+    else
+        create = func;
+
+    status = vdctx->get_proc_address(vdctx->device, VDP_FUNC_ID_DECODER_RENDER,
+                                     &func);
+    if (status != VDP_STATUS_OK)
+        return vdpau_error(status);
+    else
+        vdctx->render = func;
+
+    status = create(vdctx->device, profile, width, height, surfaces,
+                    &vdctx->decoder);
+    return vdpau_error(status);
+}
+
+int ff_vdpau_common_uninit(AVCodecContext *avctx)
+{
+    VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;
+    VdpDecoderDestroy *destroy;
+    void *func;
+    VdpStatus status;
+
+    if (vdctx->device == VDP_INVALID_HANDLE)
+        return 0; /* Decoder created and destroyed by user */
+
+    status = vdctx->get_proc_address(vdctx->device,
+                                     VDP_FUNC_ID_DECODER_DESTROY, &func);
+    if (status != VDP_STATUS_OK)
+        return vdpau_error(status);
+    else
+        destroy = func;
+
+    status = destroy(vdctx->decoder);
+    return vdpau_error(status);
+}
+
 int ff_vdpau_common_start_frame(struct vdpau_picture_context *pic_ctx,
                                 av_unused const uint8_t *buffer,
                                 av_unused uint32_t size)
@@ -84,7 +147,7 @@ int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame 
*frame,
                            pic_ctx->bitstream_buffers);
 
     av_freep(&pic_ctx->bitstream_buffers);
-    return ff_vdpau_error(status);
+    return vdpau_error(status);
 }
 
 #if CONFIG_H263_VDPAU_HWACCEL  || CONFIG_MPEG1_VDPAU_HWACCEL || \
@@ -170,7 +233,12 @@ do {                        \
 
 AVVDPAUContext *av_vdpau_alloc_context(void)
 {
-    return av_mallocz(sizeof(AVVDPAUContext));
+    AVVDPAUContext *hwctx = av_mallocz(sizeof(AVVDPAUContext));
+    if (!hwctx)
+        return NULL;
+
+    hwctx->device = VDP_INVALID_HANDLE;
+    return hwctx;
 }
 
 /* @}*/
diff --git a/libavcodec/vdpau.h b/libavcodec/vdpau.h
index 75cb1bf..b246768 100644
--- a/libavcodec/vdpau.h
+++ b/libavcodec/vdpau.h
@@ -128,6 +128,15 @@ typedef struct AVVDPAUContext {
     attribute_deprecated
     VdpBitstreamBuffer *bitstream_buffers;
 #endif
+    /*****************************************************************
+     * No fields below this line are part of the public API. They
+     * may not be used outside of libavcodec and can be changed and
+     * removed at will.
+     * No new public fields will be added to this structure.
+     *****************************************************************
+     */
+    VdpDevice device;
+    VdpGetProcAddress *get_proc_address;
 } AVVDPAUContext;
 
 /**
diff --git a/libavcodec/vdpau_internal.h b/libavcodec/vdpau_internal.h
index 3f55ee7..54d9ad3 100644
--- a/libavcodec/vdpau_internal.h
+++ b/libavcodec/vdpau_internal.h
@@ -48,6 +48,28 @@ union AVVDPAUPictureInfo {
 #include "vdpau.h"
 #endif
 
+typedef struct VDPAUContext {
+    /**
+     * VDPAU device handle
+     */
+    VdpDevice device;
+
+    /**
+     * VDPAU decoder handle
+     */
+    VdpDecoder decoder;
+
+    /**
+     * VDPAU device driver
+     */
+    VdpGetProcAddress *get_proc_address;
+
+    /**
+     * VDPAU decoder render callback
+     */
+    VdpDecoderRender *render;
+} VDPAUContext;
+
 struct vdpau_picture_context {
     /**
      * VDPAU picture information.
@@ -70,6 +92,10 @@ struct vdpau_picture_context {
     VdpBitstreamBuffer *bitstream_buffers;
 };
 
+int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile,
+                         int level, uint32_t surfaces);
+int ff_vdpau_common_uninit(AVCodecContext *avctx);
+
 int ff_vdpau_common_start_frame(struct vdpau_picture_context *pic,
                                 const uint8_t *buffer, uint32_t size);
 int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
-- 
1.8.1.5

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

Reply via email to