[FFmpeg-devel] [PATCH] libavcodec: add h.264 dxva2 decoder to ffmpeg
Wei Gao
highgod0401 at gmail.com
Wed Dec 26 07:18:27 CET 2012
>From 8dddb4d8712ea5bcd91455b393e9563507fc9852 Mon Sep 17 00:00:00 2001
From: highgod0401 <highgod0401 at gmail.com>
Date: Wed, 26 Dec 2012 14:05:38 +0800
Subject: [PATCH] add h.264 dxva2 decoder to ffmpeg
---
configure | 1 +
libavcodec/Makefile | 5 +-
libavcodec/allcodecs.c | 1 +
libavcodec/dxva2_h264_dec.c | 196 ++++++++++
libavcodec/dxva2_wrapper.c | 907
++++++++++++++++++++++++++++++++++++++++++++
libavcodec/dxva2_wrapper.h | 160 ++++++++
6 files changed, 1268 insertions(+), 2 deletions(-)
create mode 100644 libavcodec/dxva2_h264_dec.c
create mode 100644 libavcodec/dxva2_wrapper.c
create mode 100644 libavcodec/dxva2_wrapper.h
diff --git a/configure b/configure
index 7cf8d9d..a7bef1f 100755
--- a/configure
+++ b/configure
@@ -1677,6 +1677,7 @@ h264_crystalhd_decoder_select="crystalhd
h264_mp4toannexb_bsf h264_parser"
h264_decoder_select="error_resilience golomb h264chroma h264dsp h264pred
h264qpel mpegvideo"
h264_dxva2_hwaccel_deps="dxva2api_h"
h264_dxva2_hwaccel_select="dxva2 h264_decoder"
+h264_dxva2_decoder_select="dxva2 h264_parser h264_decoder"
h264_vaapi_hwaccel_select="vaapi h264_decoder"
h264_vda_decoder_select="vda h264_parser h264_decoder"
h264_vda_hwaccel_deps="VideoDecodeAcceleration_VDADecoder_h pthreads"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 0507028..a87142d 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -42,7 +42,7 @@ OBJS-$(CONFIG_AC3DSP) += ac3dsp.o
OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o
OBJS-$(CONFIG_DCT) += dct.o dct32_fixed.o dct32_float.o
OBJS-$(CONFIG_DWT) += dwt.o snow.o
-OBJS-$(CONFIG_DXVA2) += dxva2.o
+OBJS-$(CONFIG_DXVA2) += dxva2.o dxva2_wrapper.o
OBJS-$(CONFIG_ENCODERS) += faandct.o jfdctfst.o jfdctint.o
OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o
FFT-OBJS-$(CONFIG_HARDCODED_TABLES) += cos_tables.o cos_fixed_tables.o
@@ -223,6 +223,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o
\
cabac.o h264_sei.o h264_ps.o
\
h264_refs.o h264_cavlc.o
h264_cabac.o
OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o
+OBJS-$(CONFIG_H264_DXVA2_DECODER) += dxva2_h264_dec.o
OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o
OBJS-$(CONFIG_H264_VDA_HWACCEL) += vda_h264.o
OBJS-$(CONFIG_H264_VDA_DECODER) += vda_h264_dec.o
@@ -771,7 +772,7 @@ SKIPHEADERS += %_tablegen.h
\
tableprint.h \
$(ARCH)/vp56_arith.h \
-SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h
+SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h
dxva2_wrapper.h
SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h
SKIPHEADERS-$(CONFIG_LIBUTVIDEO) += libutvideo.h
SKIPHEADERS-$(CONFIG_MPEG_XVMC_DECODER) += xvmc.h
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 4743bb1..95c2c82 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -139,6 +139,7 @@ void avcodec_register_all(void)
REGISTER_DECODER (H264_CRYSTALHD, h264_crystalhd);
REGISTER_DECODER (H264_VDA, h264_vda);
REGISTER_DECODER (H264_VDPAU, h264_vdpau);
+ REGISTER_DECODER (H264_DXVA2, h264_dxva2);
REGISTER_ENCDEC (HUFFYUV, huffyuv);
REGISTER_DECODER (IDCIN, idcin);
REGISTER_DECODER (IFF_BYTERUN1, iff_byterun1);
diff --git a/libavcodec/dxva2_h264_dec.c b/libavcodec/dxva2_h264_dec.c
new file mode 100644
index 0000000..2260fd9
--- /dev/null
+++ b/libavcodec/dxva2_h264_dec.c
@@ -0,0 +1,196 @@
+/*
+ * Call hardware decode acceleration through dxva2 API for h264
+
+ * Copyright (c) 2012 Wei Gao <weigao at multicorewareinc.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
+ */
+
+#include <string.h>
+#include "dxva2_wrapper.h"
+#include "h264.h"
+#include "avcodec.h"
+
+extern AVCodec ff_h264_decoder, ff_h264_dxva2_decoder;
+
+static const enum AVPixelFormat dxva2_h264_pixfmts[] = {
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_NONE
+};
+
+typedef struct {
+ H264Context h264ctx;
+ int h264_initialized;
+ enum AVPixelFormat pix_fmt;
+ uint8_t *databuffer;
+ dxva2_context dxva2_ctx;
+} DXVA2_h264DecoderContext;
+
+
+static int dxva2dec_decode(AVCodecContext *avctx,
+ void *data, int *got_frame, AVPacket *avpkt)
+{
+ DXVA2_h264DecoderContext *ctx = (DXVA2_h264DecoderContext
*)avctx->priv_data;
+ AVFrame *pic = data;
+ int ret;
+ ret = ff_h264_decoder.decode(avctx, data, got_frame, avpkt);
+ if (*got_frame)
+ {
+ pic->format = ctx->pix_fmt;
+ pic->data[0] = ctx->databuffer;
+ pic->data[1] = pic->data[0] + (sizeof(uint8_t) * (avctx->width) *
(avctx->height));
+ pic->data[2] = pic->data[1] + ((sizeof(uint8_t) * (avctx->width) *
(avctx->height)) >> 2);
+ pic->linesize[0] = avctx->width;
+ pic->linesize[1] = avctx->width>>1;
+ pic->linesize[2] = avctx->width>>1;
+ av_extract_dxva2(&(ctx->dxva2_ctx),pic);
+ }
+ avctx->pix_fmt = ctx->pix_fmt;
+ return ret;
+}
+
+static av_cold int dxva2dec_close(AVCodecContext *avctx)
+{
+ DXVA2_h264DecoderContext *ctx = avctx->priv_data;
+ /* release buffers and decoder */
+ av_release_dxva2(&ctx->dxva2_ctx);
+ if(ctx->databuffer)
+ {
+ av_free(ctx->databuffer);
+ }
+ /* close H.264 decoder */
+ if (ctx->h264_initialized)
+ ff_h264_decoder.close(avctx);
+ return 0;
+}
+
+static av_cold int check_format(AVCodecContext *avctx)
+{
+ AVCodecParserContext *parser;
+ uint8_t *pout;
+ int psize;
+ int index;
+ H264Context *h;
+ int ret = -1;
+
+ /* init parser & parse file */
+ parser = av_parser_init(avctx->codec->id);
+ if (!parser) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 parser.\n");
+ goto final;
+ }
+ parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
+ index = av_parser_parse2(parser, avctx, &pout, &psize, NULL, 0, 0, 0,
0);
+ if (index < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to parse this file.\n");
+ goto release_parser;
+ }
+
+ /* check if support */
+ h = parser->priv_data;
+ switch (h->sps.bit_depth_luma) {
+ case 8:
+ if (!CHROMA444 && !CHROMA422) {
+ // only this will H.264 decoder switch to hwaccel
+ ret = 0;
+ break;
+ }
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");
+ }
+
+release_parser:
+ av_parser_close(parser);
+
+final:
+ return ret;
+}
+
+static av_cold int dxva2dec_init(AVCodecContext *avctx)
+{
+ DXVA2_h264DecoderContext *ctx = (DXVA2_h264DecoderContext
*)avctx->priv_data;
+ dxva2_context *dxva2_ctx = (dxva2_context *)(&ctx->dxva2_ctx);
+ int ret;
+ ctx->h264_initialized = 0;
+
+ /* init pix_fmts of codec */
+ if (!ff_h264_dxva2_decoder.pix_fmts)
+ {
+ ff_h264_dxva2_decoder.pix_fmts = dxva2_h264_pixfmts;
+ }
+
+ /* check if DXVA2 supports this file */
+ if (check_format(avctx) < 0)
+ goto failed;
+
+ /* init vda */
+ memset(dxva2_ctx, 0, sizeof(dxva2_context));
+ ret = av_create_dxva2(avctx->codec_id,dxva2_ctx);
+ if(ret < 0)
+ {
+ av_log(NULL,AV_LOG_ERROR,"create dxva2 error\n");
+ return 0;
+ }
+ ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts);
+
+ ret = av_setup_dxva2(dxva2_ctx, &avctx->hwaccel_context, &avctx->pix_fmt,
avctx->width, avctx->height);
+ if (ret < 0)
+ {
+ av_log(NULL,AV_LOG_ERROR,"error DXVA setup %d\n", ret);
+ goto failed;
+ }
+
+ /* changes callback functions */
+ avctx->get_format = av_dxva2_get_format;
+ avctx->get_buffer = av_dxva2_get_buffer;
+ avctx->release_buffer = av_dxva2_release_buffer;
+
+ /* init H.264 decoder */
+ ret = ff_h264_decoder.init(avctx);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n");
+ goto failed;
+ }
+ ctx->h264_initialized = 1;
+ ctx->databuffer = av_malloc(sizeof(uint8_t) * (avctx->width) *
(avctx->height) * 3 / 2);
+
+ return 0;
+
+failed:
+ dxva2dec_close(avctx);
+ return -1;
+}
+
+static void dxva2dec_flush(AVCodecContext *avctx)
+{
+ return ff_h264_decoder.flush(avctx);
+}
+
+AVCodec ff_h264_dxva2_decoder = {
+ .name = "h264_dxva2",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .priv_data_size = sizeof(DXVA2_h264DecoderContext),
+ .init = dxva2dec_init,
+ .close = dxva2dec_close,
+ .decode = dxva2dec_decode,
+ .capabilities = CODEC_CAP_DELAY,
+ .flush = dxva2dec_flush,
+ .long_name = NULL_IF_CONFIG_SMALL("H.264 (DXVA2 acceleration)"),
+};
+
+
diff --git a/libavcodec/dxva2_wrapper.c b/libavcodec/dxva2_wrapper.c
new file mode 100644
index 0000000..9f71693
--- /dev/null
+++ b/libavcodec/dxva2_wrapper.c
@@ -0,0 +1,907 @@
+/*
+ * Call hardware decode acceleration through dxva2 API
+
+ * Copyright (c) 2012 Wei Gao <weigao at multicorewareinc.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
+ */
+
+
+#include "dxva2_wrapper.h"
+#include <dxgi.h>
+
+/* XXX Prefered format must come first */
+static const d3d_format_t d3d_formats[] = {
+ { "YV12", (D3DFORMAT)MAKEFOURCC('Y','V','1','2'), AV_PIX_FMT_YUV420P
},
+ { "NV12", (D3DFORMAT)MAKEFOURCC('N','V','1','2'), AV_PIX_FMT_NV12 },
+
+ { NULL, (D3DFORMAT)0, PIX_FMT_NONE }
+};
+
+static const GUID DXVA2_ModeMPEG2_MoComp = {
+ 0xe6a9f44b, 0x61b0,0x4563, {0x9e,0xa4,0x63,0xd2,0xa3,0xc6,0xfe,0x66}
+};
+static const GUID DXVA2_ModeMPEG2_IDCT = {
+ 0xbf22ad00, 0x03ea,0x4690, {0x80,0x77,0x47,0x33,0x46,0x20,0x9b,0x7e}
+};
+static const GUID DXVA2_ModeMPEG2_VLD = {
+ 0xee27417f, 0x5e28,0x4e65, {0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9}
+};
+static const GUID DXVA2_ModeMPEG2and1_VLD = {
+ 0x86695f12, 0x340e,0x4f04, {0x9f,0xd3,0x92,0x53,0xdd,0x32,0x74,0x60}
+};
+static const GUID DXVA2_ModeMPEG1_VLD = {
+ 0x6f3ec719, 0x3735,0x42cc, {0x80,0x63,0x65,0xcc,0x3c,0xb3,0x66,0x16}
+};
+
+static const GUID DXVA2_ModeH264_A = {
+ 0x1b81be64, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeH264_B = {
+ 0x1b81be65, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeH264_C = {
+ 0x1b81be66, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeH264_D = {
+ 0x1b81be67, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeH264_E = {
+ 0x1b81be68, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeH264_F = {
+ 0x1b81be69, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA_ModeH264_VLD_WithFMOASO_NoFGT = {
+ 0xd5f04ff9, 0x3418,0x45d8, {0x95,0x61,0x32,0xa7,0x6a,0xae,0x2d,0xdd}
+};
+static const GUID DXVADDI_Intel_ModeH264_A = {
+ 0x604F8E64, 0x4951,0x4c54, {0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6}
+};
+static const GUID DXVADDI_Intel_ModeH264_C = {
+ 0x604F8E66, 0x4951,0x4c54, {0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6}
+};
+static const GUID DXVADDI_Intel_ModeH264_E = { //
DXVA_Intel_H264_ClearVideo
+ 0x604F8E68, 0x4951,0x4c54, {0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6}
+};
+static const GUID DXVA2_ModeWMV8_A = {
+ 0x1b81be80, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeWMV8_B = {
+ 0x1b81be81, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeWMV9_A = {
+ 0x1b81be90, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeWMV9_B = {
+ 0x1b81be91, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeWMV9_C = {
+ 0x1b81be94, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+
+static const GUID DXVA2_ModeVC1_A = {
+ 0x1b81beA0, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeVC1_B = {
+ 0x1b81beA1, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeVC1_C = {
+ 0x1b81beA2, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+static const GUID DXVA2_ModeVC1_D = {
+ 0x1b81beA3, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+/* Conformity to the August 2010 update of the specification,
ModeVC1_VLD2010 */
+static const GUID DXVA2_ModeVC1_D2010 = {
+ 0x1b81beA4, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+
+static const GUID DXVA_NoEncrypt = {
+ 0x1b81bed0, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
+};
+
+static const GUID DXVA_Intel_VC1_ClearVideo = {
+ 0xBCC5DB6D, 0xA2B6,0x4AF0, {0xAC,0xE4,0xAD,0xB1,0xF7,0x87,0xBC,0x89}
+};
+
+static const GUID DXVA_nVidia_MPEG4_ASP = {
+ 0x9947EC6F, 0x689B,0x11DC, {0xA3,0x20,0x00,0x19,0xDB,0xBC,0x41,0x84}
+};
+static const GUID DXVA_ModeMPEG4pt2_VLD_Simple = {
+ 0xefd64d74, 0xc9e8,0x41d7, {0xa5,0xe9,0xe9,0xb0,0xe3,0x9f,0xa3,0x19}
+};
+static const GUID DXVA_ModeMPEG4pt2_VLD_AdvSimple_NoGMC = {
+ 0xed418a9f, 0x10d,0x4eda, {0x9a,0xe3,0x9a,0x65,0x35,0x8d,0x8d,0x2e}
+};
+static const GUID DXVA_ModeMPEG4pt2_VLD_AdvSimple_GMC = {
+ 0xab998b5b, 0x4258,0x44a9, {0x9f,0xeb,0x94,0xe5,0x97,0xa6,0xba,0xae}
+};
+
+
+static const GUID IID_IDirectXVideoDecoderService = {
+ 0xfc51a551, 0xd5e7, 0x11d9, {0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02}
+};
+static const GUID IID_IDirectXVideoAccelerationService = {
+ 0xfc51a550, 0xd5e7, 0x11d9, {0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02}
+};
+
+/* XXX Prefered modes must come first */
+static const dxva2_mode_t dxva2_modes[] = {
+ { "MPEG-2 variable-length decoder", &DXVA2_ModeMPEG2_VLD,
AV_CODEC_ID_MPEG2VIDEO },
+ { "MPEG-2 & MPEG-1 variable-length decoder", &DXVA2_ModeMPEG2and1_VLD,
AV_CODEC_ID_MPEG2VIDEO },
+ { "MPEG-2 motion compensation", &DXVA2_ModeMPEG2_MoComp,
0 },
+ { "MPEG-2 inverse discrete cosine transform", &DXVA2_ModeMPEG2_IDCT,
0 },
+
+ { "MPEG-1 variable-length decoder", &DXVA2_ModeMPEG1_VLD,
0 },
+
+ { "H.264 variable-length decoder, film grain technology",
&DXVA2_ModeH264_F, AV_CODEC_ID_H264 },
+ { "H.264 variable-length decoder, no film grain technology",
&DXVA2_ModeH264_E, AV_CODEC_ID_H264 },
+ { "H.264 variable-length decoder, no film grain technology (Intel
ClearVideo)",&DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264 },
+ { "H.264 variable-length decoder, no film grain technology, FMO/ASO",
&DXVA_ModeH264_VLD_WithFMOASO_NoFGT, AV_CODEC_ID_H264 },
+ { "H.264 inverse discrete cosine transform, film grain technology",
&DXVA2_ModeH264_D, 0 },
+ { "H.264 inverse discrete cosine transform, no film grain technology",
&DXVA2_ModeH264_C, 0 },
+ { "H.264 inverse discrete cosine transform, no film grain technology
(Intel)", &DXVADDI_Intel_ModeH264_C, 0 },
+ { "H.264 motion compensation, film grain technology",
&DXVA2_ModeH264_B, 0 },
+ { "H.264 motion compensation, no film grain technology",
&DXVA2_ModeH264_A, 0 },
+ { "H.264 motion compensation, no film grain technology (Intel)",
&DXVADDI_Intel_ModeH264_A, 0 },
+
+ { "Windows Media Video 8 motion compensation", &DXVA2_ModeWMV8_B, 0 },
+ { "Windows Media Video 8 post processing", &DXVA2_ModeWMV8_A, 0 },
+
+ { "Windows Media Video 9 IDCT", &DXVA2_ModeWMV9_C, 0 },
+ { "Windows Media Video 9 motion compensation", &DXVA2_ModeWMV9_B, 0 },
+ { "Windows Media Video 9 post processing", &DXVA2_ModeWMV9_A, 0 },
+
+ { "VC-1 variable-length decoder", &DXVA2_ModeVC1_D,
AV_CODEC_ID_VC1 },
+ { "VC-1 variable-length decoder", &DXVA2_ModeVC1_D,
AV_CODEC_ID_WMV3 },
+ { "VC-1 variable-length decoder", &DXVA2_ModeVC1_D2010,
AV_CODEC_ID_VC1 },
+ { "VC-1 variable-length decoder", &DXVA2_ModeVC1_D2010,
AV_CODEC_ID_WMV3 },
+ { "VC-1 inverse discrete cosine transform", &DXVA2_ModeVC1_C, 0 },
+ { "VC-1 motion compensation", &DXVA2_ModeVC1_B, 0 },
+ { "VC-1 post processing", &DXVA2_ModeVC1_A, 0 },
+
+ { "VC-1 variable-length decoder (Intel)",
&DXVA_Intel_VC1_ClearVideo, 0 },
+
+ { "MPEG-4 Part 2 nVidia bitstream decoder",
&DXVA_nVidia_MPEG4_ASP, 0 },
+ { "MPEG-4 Part 2 variable-length decoder, Simple Profile",
&DXVA_ModeMPEG4pt2_VLD_Simple, 0 },
+ { "MPEG-4 Part 2 variable-length decoder, Simple&Advanced Profile, no
global motion compensation", &DXVA_ModeMPEG4pt2_VLD_AdvSimple_NoGMC, 0 },
+ { "MPEG-4 Part 2 variable-length decoder, Simple&Advanced Profile, global
motion compensation", &DXVA_ModeMPEG4pt2_VLD_AdvSimple_GMC, 0 },
+
+ { NULL, NULL, 0 }
+};
+
+
+
+
+
+static const d3d_format_t *d3d_find_format(D3DFORMAT format)
+{
+ for (unsigned i = 0; d3d_formats[i].name; i++) {
+ if (d3d_formats[i].format == format)
+ return &d3d_formats[i];
+ }
+ return NULL;
+}
+static const dxva2_mode_t *dxva2_find_mode(const GUID *guid)
+{
+ for (unsigned i = 0; dxva2_modes[i].name; i++) {
+ if (IsEqualGUID(dxva2_modes[i].guid, guid))
+ return &dxva2_modes[i];
+ }
+ return NULL;
+}
+
+
+/**
+* It creates a Direct3D device usable for DXVA 2
+*/
+static int d3d_create_device(dxva2_context *va)
+{
+
+ typedef LPDIRECT3D9 (WINAPI *Create9func)(UINT SDKVersion);
+ typedef HWND (WINAPI *PROCGETSHELLWND)(void);
+ Create9func Create9 = (Create9func )GetProcAddress(va->hd3d9_dll,
TEXT("Direct3DCreate9"));
+ LPDIRECT3D9 d3dobj;
+ D3DADAPTER_IDENTIFIER9 *d3dai = &va->d3dai;
+ PROCGETSHELLWND GetShellWindow;
+ HMODULE hUser32 = GetModuleHandle( "user32" );
+ D3DPRESENT_PARAMETERS *d3dpp = &va->d3dpp;
+ LPDIRECT3DDEVICE9 d3ddev;
+ if (!Create9) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot locate reference to Direct3DCreate9
ABI in DLL");
+ return -1;
+ }
+ d3dobj = Create9(D3D_SDK_VERSION);
+ if (!d3dobj) {
+ av_log(NULL, AV_LOG_ERROR, "Direct3DCreate9 failed");
+ return -1;
+ }
+ va->d3dobj = d3dobj;
+ if (FAILED(IDirect3D9_GetAdapterIdentifier(va->d3dobj,
+ D3DADAPTER_DEFAULT, 0, d3dai))) {
+ av_log(NULL, AV_LOG_WARNING, "IDirect3D9_GetAdapterIdentifier failed");
+ ZeroMemory(d3dai, sizeof(*d3dai));
+ }
+ GetShellWindow = (PROCGETSHELLWND)
+ GetProcAddress( hUser32, "GetShellWindow" );
+ ZeroMemory(d3dpp, sizeof(*d3dpp));
+ d3dpp->Flags = D3DPRESENTFLAG_VIDEO;
+ d3dpp->Windowed = TRUE;
+ d3dpp->hDeviceWindow = NULL;
+ d3dpp->SwapEffect = D3DSWAPEFFECT_DISCARD;
+ d3dpp->MultiSampleType = D3DMULTISAMPLE_NONE;
+ d3dpp->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
+ d3dpp->BackBufferCount = 0;
+ d3dpp->BackBufferFormat = D3DFMT_X8R8G8B8;
+ d3dpp->BackBufferWidth = 0;
+ d3dpp->BackBufferHeight = 0;
+ d3dpp->EnableAutoDepthStencil = FALSE;
+
+ /* Direct3D needs a HWND to create a device, even without using ::Present
+ this HWND is used to alert Direct3D when there's a change of focus window.
+ For now, use GetShellWindow, as it looks harmless */
+
+ if (FAILED(IDirect3D9_CreateDevice(d3dobj, D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL, GetShellWindow(),
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING |
+ D3DCREATE_MULTITHREADED,
+ d3dpp, &d3ddev))) {
+ av_log(NULL, AV_LOG_ERROR, "IDirect3D9_CreateDevice failed\n");
+ return -1;
+ }
+ va->d3ddev = d3ddev;
+
+ return 0;
+}
+
+/**
+* It releases a Direct3D device and its resources.
+*/
+static void d3d_destroy_device(dxva2_context *va)
+{
+ if (va->d3ddev)
+ IDirect3DDevice9_Release(va->d3ddev);
+ if (va->d3dobj)
+ IDirect3D9_Release(va->d3dobj);
+}
+/**
+* It destroys a Direct3D device manager
+*/
+static void d3d_destroy_device_manager(dxva2_context *va)
+{
+ if (va->devmng)
+ IDirect3DDeviceManager9_Release( va->devmng );
+}
+static void dx_destroy_video_service(dxva2_context *va)
+{
+ if( va->device )
+ IDirect3DDeviceManager9_CloseDeviceHandle( va->devmng, va->device
);
+
+ if( va->vs )
+ IDirectXVideoDecoderService_Release( va->vs );
+}
+static void dx_destroy_video_decoder(dxva2_context *va)
+{
+ unsigned i;
+ if( va->decoder )
+ IDirectXVideoDecoder_Release( va->decoder );
+ va->decoder = NULL;
+ for( i = 0; i< va->surface_count; i++ )
+ IDirect3DSurface9_Release( va->surface[i].d3d );
+ va->surface_count = 0;
+}
+
+static void close(dxva2_context *external)
+{
+ dxva2_context *va = external;
+
+ dx_destroy_video_decoder(va);
+ dx_destroy_video_service(va);
+ d3d_destroy_device_manager(va);
+ d3d_destroy_device(va);
+
+ if (va->hdxva2_dll)
+ FreeLibrary(va->hdxva2_dll);
+ if (va->hd3d9_dll)
+ FreeLibrary(va->hd3d9_dll);
+}
+
+/**
+* Find the best suited decoder mode GUID and render format.
+*/
+
+static int dx_find_video_service_conversion(dxva2_context *va, GUID
*input, D3DFORMAT *output)
+{
+ /* Retrieve supported modes from the decoder service */
+ UINT input_count = 0;
+ GUID *input_list = NULL;
+ int is_suported;
+ UINT output_count;
+ D3DFORMAT *output_list;
+ if (FAILED(IDirectXVideoDecoderService_GetDecoderDeviceGuids( va->vs,
&input_count, &input_list ))) {
+ av_log(NULL, AV_LOG_ERROR,
"IDirectXVideoDecoderService_GetDecoderDeviceGuids failed\n");
+ return -1;
+ }
+ for (unsigned i = 0; i < input_count; i++) {
+ const GUID *g = &input_list[i];
+ const dxva2_mode_t *mode = dxva2_find_mode(g);
+ if (mode) {
+ av_log(NULL, AV_LOG_INFO, "- '%s' is supported by hardware\n",
mode->name);
+ } else {
+ av_log(NULL, AV_LOG_WARNING, "- Unknown GUID = %08X-%04x-%04x-XXXX\n",
+ (unsigned)g->Data1, g->Data2, g->Data3);
+ }
+ }
+
+ /* Try all supported mode by our priority */
+ for (unsigned i = 0; dxva2_modes[i].name; i++) {
+ const dxva2_mode_t *mode = &dxva2_modes[i];
+ if (!mode->codec || mode->codec != va->codec_id)
+ continue;
+
+ /* */
+ is_suported = FALSE;
+ for (unsigned count = 0; !is_suported && count < input_count; count++) {
+ const GUID *g = &input_list[count];
+ is_suported = IsEqualGUID(mode->guid, g) == 0;
+ }
+ if (!is_suported)
+ continue;
+
+ /* */
+ av_log(NULL, AV_LOG_INFO, "Trying to use '%s' as input\n", mode->name);
+ output_count = 0;
+ output_list = NULL;
+
+ if (FAILED(IDirectXVideoDecoderService_GetDecoderRenderTargets( va->vs,
mode->guid, &output_count, &output_list )))
+ {
+ av_log(NULL, AV_LOG_INFO,
"IDirectXVideoDecoderService_GetDecoderRenderTargets failed,try others\n");
+ continue;
+ }
+ for (unsigned j = 0; j < output_count; j++)
+ {
+ const D3DFORMAT f = output_list[j];
+ const d3d_format_t *format = d3d_find_format(f);
+ if (format) {
+ av_log(NULL, AV_LOG_INFO, "%s is supported for output\n", format->name);
+ } else {
+ av_log(NULL, AV_LOG_INFO, "%d is supported for output (%4.4s)\n", f,
(const char*)&f);
+ }
+ }
+
+ /* */
+ for (unsigned j = 0; d3d_formats[j].name; j++)
+ {
+ const d3d_format_t *format = &d3d_formats[j];
+
+ /* */
+ is_suported = FALSE;
+ for (unsigned k = 0; !is_suported && k < output_count; k++) {
+ is_suported = format->format == output_list[k];
+ }
+ if (!is_suported)
+ continue;
+
+ /* We have our solution */
+ av_log(NULL, AV_LOG_INFO, "Using '%s' to decode to '%s'\n", mode->name,
format->name);
+ *input = *mode->guid;
+ *output = format->format;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+/**
+* It creates a DirectX video service
+*/
+
+static int dx_create_video_service(dxva2_context *va)
+{
+ typedef HRESULT (WINAPI *CreateVideoService_func)(IDirect3DDevice9 *,
+ REFIID riid,
+ void **ppService);
+ CreateVideoService_func CreateVideoService =
+ (CreateVideoService_func)GetProcAddress(va->hdxva2_dll,
+ TEXT("DXVA2CreateVideoService"));
+
+ HRESULT hr;
+ HANDLE device;
+ IDirectXVideoDecoderService *vs;
+
+ if (!CreateVideoService)
+ {
+ av_log(NULL, AV_LOG_ERROR, "cannot load function\n");
+ return 4;
+ }
+ av_log(NULL, AV_LOG_INFO, "DXVA2CreateVideoService Success!\n");
+
+ hr = IDirect3DDeviceManager9_OpenDeviceHandle( va->devmng, &device );
+
+ if (FAILED(hr)) {
+ av_log(NULL, AV_LOG_ERROR, "OpenDeviceHandle failed\n");
+ return -1;
+ }
+ va->device = device;
+ hr = IDirect3DDeviceManager9_GetVideoService( va->devmng, device,
&IID_IDirectXVideoDecoderService, (void **)(&vs) );
+ if (FAILED(hr))
+ {
+ av_log(NULL, AV_LOG_ERROR, "GetVideoService failed\n");
+ return -1;
+ }
+ va->vs = vs;
+
+ return 0;
+}
+
+
+/**
+* It creates a Direct3D device manager
+*/
+
+static int d3d_create_device_manager(dxva2_context *va)
+{
+ typedef HRESULT (WINAPI *CreateDeviceManager9_func)(UINT *pResetToken,
IDirect3DDeviceManager9 **);
+ CreateDeviceManager9_func CreateDeviceManager9 =
+ (CreateDeviceManager9_func)GetProcAddress(va->hdxva2_dll,
TEXT("DXVA2CreateDirect3DDeviceManager9"));
+ UINT token;
+ HRESULT hr;
+ IDirect3DDeviceManager9 *devmng;
+ if (!CreateDeviceManager9)
+ {
+ av_log(NULL, AV_LOG_ERROR, "cannot load function\n");
+ return -1;
+ }
+ av_log(NULL, AV_LOG_INFO, "OurDirect3DCreateDeviceManager9 Success!\n");
+ if (FAILED(CreateDeviceManager9(&token, &devmng)))
+ {
+ av_log(NULL, AV_LOG_ERROR, " OurDirect3DCreateDeviceManager9 failed\n");
+ return -1;
+ }
+
+ hr = IDirect3DDeviceManager9_ResetDevice( devmng, va->d3ddev, token );
+ if (FAILED(hr))
+ {
+ av_log(NULL, AV_LOG_ERROR, "IDirect3DDeviceManager9_ResetDevice failed:
%08x", (unsigned)hr);
+ return -1;
+ }
+
+ IDirect3DDeviceManager9_AddRef(devmng);
+ va->token = token;
+ va->devmng = devmng;
+ av_log(NULL, AV_LOG_INFO, "obtained IDirect3DDeviceManager9\n");
+
+ return 0;
+}
+
+
+
+int av_create_dxva2(int codec_id,dxva2_context *dxva2_ctx)
+{
+ if (!dxva2_ctx)
+ return -1;
+
+ dxva2_ctx->codec_id = codec_id;
+
+
+ /* Load dll*/
+ dxva2_ctx->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
+ if (!dxva2_ctx->hd3d9_dll)
+ {
+ av_log(NULL, AV_LOG_ERROR, "cannot load d3d9.dll\n");
+ goto error;
+ }
+ dxva2_ctx->hdxva2_dll = LoadLibrary(TEXT("DXVA2.DLL"));
+ if (!dxva2_ctx->hdxva2_dll)
+ {
+ av_log(NULL, AV_LOG_ERROR, "cannot load dxva2.dll\n");
+ goto error;
+ }
+ av_log(NULL, AV_LOG_INFO, "DLLs loaded\n");
+
+ /* */
+ if (d3d_create_device(dxva2_ctx))
+ {
+ av_log(NULL, AV_LOG_ERROR, "Failed to create Direct3D device\n");
+ goto error;
+ }
+ av_log(NULL, AV_LOG_INFO, "d3d_create_device succeed\n");
+
+ if (d3d_create_device_manager(dxva2_ctx)) {
+ av_log(NULL, AV_LOG_ERROR, "d3d_create_device_manager failed\n");
+ goto error;
+ }
+
+ if (dx_create_video_service(dxva2_ctx))
+ {
+ av_log(NULL, AV_LOG_ERROR, "dx_create_video_service failed\n");
+ goto error;
+ }
+
+ /* */
+ if (dx_find_video_service_conversion(dxva2_ctx, &dxva2_ctx->input,
&dxva2_ctx->render))
+ {
+ av_log(NULL, AV_LOG_ERROR, "dx_find_video_service_conversion failed\n");
+ goto error;
+ }
+ return 0;
+ /* TODO print the hardware name/vendor for debugging purposes */
+error:
+ close(dxva2_ctx);
+ return -1;
+}
+
+
+
+/**
+* It creates a DXVA2 decoder using the given video format
+*/
+static int dx_create_video_decoder(dxva2_context *va,
+ int codec_id, const struct video_format_t *fmt)
+{
+ LPDIRECT3DSURFACE9 surface_list[VA_DXVA2_MAX_SURFACE_COUNT];
+ DXVA2_VideoDesc dsc;
+ DXVA2_ExtendedFormat *ext;
+ UINT cfg_count = 0;
+ DXVA2_ConfigPictureDecode *cfg_list = NULL;
+ IDirectXVideoDecoder *decoder;
+ int cfg_score;
+ int score;
+ av_log(NULL, AV_LOG_INFO, "dx_create_video_decoder id %d %dx%d\n",
+ codec_id, fmt->i_width, fmt->i_height);
+
+ va->width = fmt->i_width;
+ va->height = fmt->i_height;
+
+ /* Allocates all surfaces needed for the decoder */
+
+ va->surface_width = (fmt->i_width + 15) & ~15;
+ va->surface_height = (fmt->i_height + 15) & ~15;
+
+ switch (codec_id) {
+ case AV_CODEC_ID_H264:
+ va->surface_count = 16 + 1;
+ break;
+ default:
+
+ va->surface_count = 4 + 1;
+ break;
+ }
+ if (FAILED(IDirectXVideoDecoderService_CreateSurface( va->vs,
+
va->surface_width,
+
va->surface_height,
+
va->surface_count - 1,
+ va->render,
+
D3DPOOL_DEFAULT,
+ 0,
+
DXVA2_VideoDecoderRenderTarget,
+ surface_list,
NULL ))) {
+ av_log(NULL, AV_LOG_ERROR,
"IDirectXVideoAccelerationService_CreateSurface failed\n");
+ va->surface_count = 0;
+ return -1;
+ }
+ for (unsigned i = 0; i < va->surface_count; i++) {
+ ff_va_surface_t *surface = &va->surface[i];
+ surface->d3d = surface_list[i];
+ surface->refcount = 0;
+ surface->order = 0;
+ }
+ av_log(NULL, AV_LOG_INFO, "IDirectXVideoAccelerationService_CreateSurface
succeed with %d surfaces (%dx%d)\n",
+ va->surface_count, fmt->i_width, fmt->i_height);
+ ZeroMemory(&dsc, sizeof(dsc));
+ dsc.SampleWidth = fmt->i_width;
+ dsc.SampleHeight = fmt->i_height;
+ dsc.Format = va->render;
+ if (fmt->i_frame_rate > 0 && fmt->i_frame_rate_base > 0) {
+ dsc.InputSampleFreq.Numerator = fmt->i_frame_rate;
+ dsc.InputSampleFreq.Denominator = fmt->i_frame_rate_base;
+ } else {
+ dsc.InputSampleFreq.Numerator = 0;
+ dsc.InputSampleFreq.Denominator = 0;
+ }
+ dsc.OutputFrameFreq = dsc.InputSampleFreq;
+ dsc.UABProtectionLevel = FALSE;
+ dsc.Reserved = 0;
+
+ ext = &dsc.SampleFormat;
+ ext->SampleFormat = 0;//DXVA2_SampleUnknown;
+ ext->VideoChromaSubsampling = 0;//DXVA2_VideoChromaSubsampling_Unknown;
+ ext->NominalRange = 0;//DXVA2_NominalRange_Unknown;
+ ext->VideoTransferMatrix = 0;//DXVA2_VideoTransferMatrix_Unknown;
+ ext->VideoLighting = 0;//DXVA2_VideoLighting_Unknown;
+ ext->VideoPrimaries = 0;//DXVA2_VideoPrimaries_Unknown;
+ ext->VideoTransferFunction = 0;//DXVA2_VideoTransFunc_Unknown;
+
+ /* List all configurations available for the decoder */
+
+
+ if (FAILED(IDirectXVideoDecoderService_GetDecoderConfigurations( va->vs,
&va->input, &dsc, NULL, &cfg_count, &cfg_list ))) {
+ av_log(NULL, AV_LOG_ERROR,
"IDirectXVideoDecoderService_GetDecoderConfigurations failed\n");
+ return -1;
+ }
+ av_log(NULL, AV_LOG_INFO, "we got %d decoder configurations\n",
cfg_count);
+
+ /* Select the best decoder configuration */
+ cfg_score = 0;
+ for (unsigned i = 0; i < cfg_count; i++)
+ {
+ const DXVA2_ConfigPictureDecode *cfg = &cfg_list[i];
+
+ /* */
+ av_log(NULL, AV_LOG_INFO, "configuration[%d] ConfigBitstreamRaw %d\n",
+ i, cfg->ConfigBitstreamRaw);
+
+ /* */
+
+ if (cfg->ConfigBitstreamRaw == 1)
+ score = 1;
+ else if (codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2)
+ score = 2;
+ else
+ continue;
+ if (IsEqualGUID(&cfg->guidConfigBitstreamEncryption, &DXVA_NoEncrypt))
+ score += 16;
+
+ if (cfg_score < score)
+ {
+ va->cfg = *cfg;
+ cfg_score = score;
+ }
+ }
+ if (cfg_score <= 0)
+ {
+ av_log(NULL, AV_LOG_ERROR, "Failed to find a supported decoder
configuration\n");
+ return -1;
+ }
+
+
+
+ if (FAILED(IDirectXVideoDecoderService_CreateVideoDecoder( va->vs,
&va->input, &dsc, &va->cfg, surface_list, va->surface_count, &decoder )))
+ {
+ av_log(NULL, AV_LOG_ERROR,
"IDirectXVideoDecoderService_CreateVideoDecoder failed\n");
+ return -1;
+ }
+ va->decoder = decoder;
+ av_log(NULL, AV_LOG_INFO, "IDirectXVideoDecoderService_CreateVideoDecoder
succeed\n");
+ return 0;
+}
+
+
+static void dx_create_video_conversion(dxva2_context *va)
+{
+ switch (va->render) {
+ case MAKEFOURCC('N','V','1','2'):
+ va->output = (D3DFORMAT)MAKEFOURCC('Y','V','1','2');
+ break;
+ default:
+ va->output = va->render;
+ break;
+ }
+}
+int av_setup_dxva2(dxva2_context *dxva2_ctx, void **hw, enum PixelFormat
*chroma,
+ int width, int height)
+{
+ struct video_format_t fmt;
+ const d3d_format_t *output;
+ if (dxva2_ctx->width == width && dxva2_ctx->height == height &&
dxva2_ctx->decoder)
+ goto ok;
+
+
+ /* */
+ dx_destroy_video_service(dxva2_ctx);
+
+
+ *chroma = AV_PIX_FMT_NONE;
+ if (width <= 0 || height <= 0)
+ return -1;
+
+
+ memset(&fmt, 0, sizeof(fmt));
+ fmt.i_width = width;
+ fmt.i_height = height;
+ if (dx_create_video_decoder(dxva2_ctx, dxva2_ctx->codec_id, &fmt))
+ {
+ return -1;
+ }
+ /* */
+ dxva2_ctx->hw.decoder = dxva2_ctx->decoder;
+ dxva2_ctx->hw.cfg = &dxva2_ctx->cfg;
+ dxva2_ctx->hw.surface_count = dxva2_ctx->surface_count;
+ dxva2_ctx->hw.surface = dxva2_ctx->hw_surface;
+ for (unsigned i = 0; i < dxva2_ctx->surface_count; i++)
+ dxva2_ctx->hw.surface[i] = dxva2_ctx->surface[i].d3d;
+
+ /* */
+ dx_create_video_conversion(dxva2_ctx);
+
+ /* */
+ok:
+ *hw = &dxva2_ctx->hw;
+ output = d3d_find_format(dxva2_ctx->output);
+ *chroma = output->codec;
+ return 0;
+}
+
+static int get(dxva2_context *external, AVFrame *ff)
+{
+ dxva2_context *va = external;
+ unsigned i, old;
+ ff_va_surface_t *surface;
+ for (i = 0, old = 0; i < va->surface_count; i++) {
+ ff_va_surface_t *surface = &va->surface[i];
+
+ if (!surface->refcount)
+ break;
+
+ if (surface->order < va->surface[old].order)
+ old = i;
+ }
+ if (i >= va->surface_count)
+ i = old;
+
+ surface = &va->surface[i];
+ surface->refcount = 1;
+ surface->order = va->surface_order++;
+
+ /* */
+ ff->data[3] = (uint8_t *)surface->d3d;
+
+ return 0;
+}
+
+
+static void release(dxva2_context *external, AVFrame *ff)
+{
+ dxva2_context *va = external;
+
+ LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)ff->data[3];
+
+ if(NULL == d3d)
+ {
+ return;
+ }
+ for (unsigned i = 0; i < va->surface_count; i++) {
+ ff_va_surface_t *surface = &va->surface[i];
+
+ if (surface->d3d == d3d)
+ surface->refcount--;
+
+ }
+}
+
+int av_dxva2_get_buffer( struct AVCodecContext *avctx,
+ AVFrame *pic )
+{
+ dxva2_context *dxva2_ctx = (dxva2_context *)((uint8_t *)avctx->priv_data
+ avctx->codec->priv_data_size - sizeof(dxva2_context));
+ pic->type = FF_BUFFER_TYPE_USER;
+ pic->data[0] = (void *)1;
+ if(dxva2_ctx)
+ {
+ if( get( dxva2_ctx, pic) )
+ {
+ av_log(NULL, AV_LOG_ERROR, "VaGrabSurface failed" );
+ return -1;
+ }
+ return 0;
+ }
+ else
+ {
+ av_log(NULL, AV_LOG_ERROR, "No dxva2 context, get buffer failed" );
+ return -1;
+ }
+}
+
+
+void av_dxva2_release_buffer( struct AVCodecContext *avctx,
+ AVFrame *pic )
+{
+ dxva2_context *dxva2_ctx = (dxva2_context *)((uint8_t *)avctx->priv_data
+ avctx->codec->priv_data_size - sizeof(dxva2_context));
+ if( dxva2_ctx )
+ {
+ release( dxva2_ctx, pic);
+
+ }
+ for( int i = 0; i < 4; i++ )
+ pic->data[i] = NULL;
+}
+
+enum PixelFormat av_dxva2_get_format( AVCodecContext *p_context,
+ const enum PixelFormat *pi_fmt )
+{
+ return AV_PIX_FMT_DXVA2_VLD;
+}
+
+
+static void ff_copy_from_nv12(uint8_t *src[2], size_t src_pitch[2],
unsigned width, unsigned height, AVFrame *ff )
+{
+ unsigned int i, j;
+ uint8_t *dstU, *dstV;
+ unsigned int heithtUV, widthUV;
+ dstU = ff->data[1];
+ dstV = ff->data[2];
+ heithtUV = height/2;
+ widthUV = width/2;
+
+ if(ff->linesize[1] != ff->linesize[2])
+ {
+ av_log(NULL,AV_LOG_ERROR,"ff->linesize[1] != ff->linesize[2] not 4:2:0
type\n");
+ }
+ for( i = 0; i<height; i++ ) //Y
+ {
+
+ memcpy( ff->data[0] + i * ff->linesize[0], src[0]+i*src_pitch[0], width );
+ }
+ for( i = 0; i<heithtUV; i++ )
+ {
+ for( j = 0; j<widthUV; j++ )
+ {
+ dstU[i*ff->linesize[1]+j] = *(src[1]+i*src_pitch[1]+2*j);
+ dstV[i*ff->linesize[2]+j] = *(src[1]+i*src_pitch[1]+2*j+1);
+ }
+ }
+}
+
+
+
+
+int av_extract_dxva2( dxva2_context *dxva2,AVFrame *frame)
+
+{
+
+ LPDIRECT3DSURFACE9 d3d;
+ D3DLOCKED_RECT lock;
+ d3d = (LPDIRECT3DSURFACE9)(uintptr_t)frame->data[3];
+ if( FAILED( IDirect3DSurface9_LockRect( d3d, &lock,
NULL,D3DLOCK_READONLY)))
+ {
+ av_log(NULL, AV_LOG_ERROR, "Trying DXVA2\n" );
+ return FALSE;
+ }
+ if( dxva2->render == MAKEFOURCC( 'N', 'V', '1', '2' ))
+ {
+ uint8_t *plane[2] =
+ {
+ (uint8_t *)lock.pBits,
+ (uint8_t*)lock.pBits + lock.Pitch * dxva2->surface_height
+ };
+ size_t pitch[2] =
+ {
+ lock.Pitch,
+ lock.Pitch,
+ };
+
+ ff_copy_from_nv12(plane, pitch, dxva2->width, dxva2->height, frame );
+
+
+ }
+ IDirect3DSurface9_UnlockRect( d3d );
+
+ return TRUE;
+}
+
+
+void av_release_dxva2(dxva2_context *dxva2_ctx)
+{
+ if(dxva2_ctx)
+ {
+ close(dxva2_ctx);
+ }
+}
+
+
+
diff --git a/libavcodec/dxva2_wrapper.h b/libavcodec/dxva2_wrapper.h
new file mode 100644
index 0000000..961ee8b
--- /dev/null
+++ b/libavcodec/dxva2_wrapper.h
@@ -0,0 +1,160 @@
+/*
+ * Call hardware decode acceleration through dxva2 API
+
+ * Copyright (c) 2012 Wei Gao <weigao at multicorewareinc.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
+ */
+
+#ifndef VA_DXVA2_H
+#define VA_DXVA2_H
+
+#define COBJMACROS
+#pragma once
+
+#include <windows.h>
+#include <d3d9.h>
+
+
+#include "avcodec.h"
+
+#include "dxva2.h"
+
+#ifndef false
+#define false FALSE
+#endif
+
+
+
+#define VA_DXVA2_MAX_SURFACE_COUNT (64)
+typedef struct {
+ LPDIRECT3DSURFACE9 d3d;
+ int refcount;
+ unsigned int order;
+} ff_va_surface_t;
+
+typedef struct
+{
+ int codec_id;
+ int width;
+ int height;
+
+ /* DLL */
+ HINSTANCE hd3d9_dll;
+ HINSTANCE hdxva2_dll;
+
+ /* Direct3D */
+
+ LPDIRECT3D9 d3dobj;
+ LPDIRECT3DDEVICE9 d3ddev;
+ D3DPRESENT_PARAMETERS d3dpp;
+ D3DADAPTER_IDENTIFIER9 d3dai;
+
+ /* Device manager */
+ UINT token;
+ IDirect3DDeviceManager9 *devmng;
+ HANDLE device;
+
+ /* Video service */
+ IDirectXVideoDecoderService *vs;
+ GUID input;
+ D3DFORMAT render;
+
+ /* Video decoder */
+ DXVA2_ConfigPictureDecode cfg;
+ IDirectXVideoDecoder *decoder;
+
+ /* Option conversion */
+ D3DFORMAT output;
+
+ /* */
+ struct dxva_context hw;
+
+ /* */
+ unsigned surface_count;
+ unsigned surface_order;
+ int surface_width;
+ int surface_height;
+
+ ff_va_surface_t surface[VA_DXVA2_MAX_SURFACE_COUNT];
+ LPDIRECT3DSURFACE9 hw_surface[VA_DXVA2_MAX_SURFACE_COUNT];
+} dxva2_context;
+
+
+typedef struct {
+ const char *name;
+ D3DFORMAT format;
+ enum PixelFormat codec;
+} d3d_format_t;
+
+/**
+ * video format description
+ */
+struct video_format_t
+{
+ enum PixelFormat i_chroma; /**< picture chroma */
+
+ unsigned int i_width; /**< picture width */
+ unsigned int i_height; /**< picture height */
+ unsigned int i_x_offset; /**< start offset of visible
area */
+ unsigned int i_y_offset; /**< start offset of visible
area */
+ unsigned int i_visible_width; /**< width of visible area */
+ unsigned int i_visible_height; /**< height of visible area */
+
+ unsigned int i_bits_per_pixel; /**< number of bits per pixel */
+
+ unsigned int i_sar_num; /**< sample/pixel aspect ratio
*/
+ unsigned int i_sar_den;
+
+ unsigned int i_frame_rate; /**< frame rate numerator */
+ unsigned int i_frame_rate_base; /**< frame rate denominator */
+
+ uint32_t i_rmask, i_gmask, i_bmask; /**< color masks for RGB chroma
*/
+ int i_rrshift, i_lrshift;
+ int i_rgshift, i_lgshift;
+ int i_rbshift, i_lbshift;
+};
+
+
+typedef struct {
+ const char *name;
+ const GUID *guid;
+ int codec;
+} dxva2_mode_t;
+
+/*****************************************************************************
+ * Module private data
+
****************************************************************************/
+
+
+int av_create_dxva2(int codec_id,dxva2_context *dxva2_ctx);
+
+int av_setup_dxva2(dxva2_context *external, void **hw, enum PixelFormat
*chroma,int width, int height);
+
+enum PixelFormat av_dxva2_get_format( AVCodecContext *p_context,const enum
PixelFormat *pi_fmt );
+
+int av_dxva2_get_buffer( struct AVCodecContext *p_context,AVFrame
*p_ff_pic );
+
+void av_dxva2_release_buffer( struct AVCodecContext *p_context,AVFrame
*p_ff_pic );
+
+int av_extract_dxva2( dxva2_context *dxva2,AVFrame *frame);
+
+void av_release_dxva2(dxva2_context *dxva2_ctx);
+
+#endif
+
+
--
1.7.11.msysgit.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-add-h.264-dxva2-decoder-to-ffmpeg.patch
Type: application/octet-stream
Size: 44247 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20121226/3c3c0a04/attachment.obj>
More information about the ffmpeg-devel
mailing list