2 * DXVA2 HW acceleration.
4 * copyright (c) 2010 Laurent Aimar
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include "libavutil/log.h"
27 #include "libavutil/time.h"
30 #include "mpegvideo.h"
31 #include "dxva2_internal.h"
33 void *ff_dxva2_get_surface(const AVFrame *frame)
35 return frame->data[3];
38 unsigned ff_dxva2_get_surface_index(const AVCodecContext *avctx,
39 const AVDXVAContext *ctx,
42 void *surface = ff_dxva2_get_surface(frame);
45 for (i = 0; i < DXVA_CONTEXT_COUNT(avctx, ctx); i++)
46 if (DXVA_CONTEXT_SURFACE(avctx, ctx, i) == surface)
53 int ff_dxva2_commit_buffer(AVCodecContext *avctx,
55 DECODER_BUFFER_DESC *dsc,
56 unsigned type, const void *data, unsigned size,
65 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
66 hr = ID3D11VideoContext_GetDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context,
67 D3D11VA_CONTEXT(ctx)->decoder,
69 &dxva_size, &dxva_data);
72 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
73 hr = IDirectXVideoDecoder_GetBuffer(DXVA2_CONTEXT(ctx)->decoder, type,
74 &dxva_data, &dxva_size);
77 av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %u: 0x%lx\n",
81 if (size <= dxva_size) {
82 memcpy(dxva_data, data, size);
85 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
86 D3D11_VIDEO_DECODER_BUFFER_DESC *dsc11 = dsc;
87 memset(dsc11, 0, sizeof(*dsc11));
88 dsc11->BufferType = type;
89 dsc11->DataSize = size;
90 dsc11->NumMBsInBuffer = mb_count;
94 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
95 DXVA2_DecodeBufferDesc *dsc2 = dsc;
96 memset(dsc2, 0, sizeof(*dsc2));
97 dsc2->CompressedBufferType = type;
98 dsc2->DataSize = size;
99 dsc2->NumMBsInBuffer = mb_count;
105 av_log(avctx, AV_LOG_ERROR, "Buffer for type %u was too small\n", type);
110 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
111 hr = ID3D11VideoContext_ReleaseDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type);
114 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
115 hr = IDirectXVideoDecoder_ReleaseBuffer(DXVA2_CONTEXT(ctx)->decoder, type);
118 av_log(avctx, AV_LOG_ERROR,
119 "Failed to release buffer type %u: 0x%lx\n",
126 int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
127 const void *pp, unsigned pp_size,
128 const void *qm, unsigned qm_size,
129 int (*commit_bs_si)(AVCodecContext *,
130 DECODER_BUFFER_DESC *bs,
131 DECODER_BUFFER_DESC *slice))
133 AVDXVAContext *ctx = avctx->hwaccel_context;
134 unsigned buffer_count = 0;
136 D3D11_VIDEO_DECODER_BUFFER_DESC buffer11[4];
139 DXVA2_DecodeBufferDesc buffer2[4];
141 DECODER_BUFFER_DESC *buffer = NULL, *buffer_slice = NULL;
142 int result, runs = 0;
148 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
149 hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder,
150 ff_dxva2_get_surface(frame),
154 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
155 hr = IDirectXVideoDecoder_BeginFrame(DXVA2_CONTEXT(ctx)->decoder,
156 ff_dxva2_get_surface(frame),
161 } while (hr == E_PENDING && ++runs < 50);
164 av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%lx\n", hr);
169 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
170 buffer = &buffer11[buffer_count];
171 type = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
175 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
176 buffer = &buffer2[buffer_count];
177 type = DXVA2_PictureParametersBufferType;
180 result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
184 av_log(avctx, AV_LOG_ERROR,
185 "Failed to add picture parameter buffer\n");
192 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
193 buffer = &buffer11[buffer_count];
194 type = D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX;
198 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
199 buffer = &buffer2[buffer_count];
200 type = DXVA2_InverseQuantizationMatrixBufferType;
203 result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
207 av_log(avctx, AV_LOG_ERROR,
208 "Failed to add inverse quantization matrix buffer\n");
215 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
216 buffer = &buffer11[buffer_count + 0];
217 buffer_slice = &buffer11[buffer_count + 1];
221 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
222 buffer = &buffer2[buffer_count + 0];
223 buffer_slice = &buffer2[buffer_count + 1];
227 result = commit_bs_si(avctx,
231 av_log(avctx, AV_LOG_ERROR,
232 "Failed to add bitstream or slice control buffer\n");
237 /* TODO Film Grain when possible */
239 assert(buffer_count == 1 + (qm_size > 0) + 2);
242 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
243 hr = ID3D11VideoContext_SubmitDecoderBuffers(D3D11VA_CONTEXT(ctx)->video_context,
244 D3D11VA_CONTEXT(ctx)->decoder,
245 buffer_count, buffer11);
248 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
249 DXVA2_DecodeExecuteParams exec = {
250 .NumCompBuffers = buffer_count,
251 .pCompressedBuffers = buffer2,
252 .pExtensionData = NULL,
254 hr = IDirectXVideoDecoder_Execute(DXVA2_CONTEXT(ctx)->decoder, &exec);
258 av_log(avctx, AV_LOG_ERROR, "Failed to execute: 0x%lx\n", hr);
264 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
265 hr = ID3D11VideoContext_DecoderEndFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder);
268 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
269 hr = IDirectXVideoDecoder_EndFrame(DXVA2_CONTEXT(ctx)->decoder, NULL);
272 av_log(avctx, AV_LOG_ERROR, "Failed to end frame: 0x%lx\n", hr);