diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c
index 0a4b7965f71cfa5b49f652c387111a715987c603..48bc3653c981d90108baf67a2b5e30bab7b7b73b 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,68 @@ static int vdpau_error(VdpStatus status)
     }
 }
 
+int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile,
+                         int level)
+{
+    VDPAUHWContext *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;
+
+    if (hwctx->context.decoder != VDP_INVALID_HANDLE) {
+        vdctx->decoder = hwctx->context.decoder;
+        vdctx->render  = hwctx->context.render;
+        vdctx->device  = VDP_INVALID_HANDLE;
+        return 0; /* Decoder created by user */
+    }
+
+    vdctx->device           = hwctx->device;
+    vdctx->get_proc_address = hwctx->get_proc_address;
+
+    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, avctx->refs,
+                    &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)
diff --git a/libavcodec/vdpau_internal.h b/libavcodec/vdpau_internal.h
index 3f55ee7dc9c08e0c81d008534da74c8a88b732b9..94fa9aae89acb8c52ff82745a5fa0b6285d5f074 100644
--- a/libavcodec/vdpau_internal.h
+++ b/libavcodec/vdpau_internal.h
@@ -48,6 +48,34 @@ union AVVDPAUPictureInfo {
 #include "vdpau.h"
 #endif
 
+typedef struct VDPAUHWContext {
+    AVVDPAUContext context;
+    VdpDevice device;
+    VdpGetProcAddress *get_proc_address;
+} VDPAUHWContext;
+
+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 +98,10 @@ struct vdpau_picture_context {
     VdpBitstreamBuffer *bitstream_buffers;
 };
 
+int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile,
+                         int level);
+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,