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