D3D11va: add a Direct3D11 video decoder similar to DXVA2
[libav.git] / libavcodec / dxva2.c
1 /*
2 * DXVA2 HW acceleration.
3 *
4 * copyright (c) 2010 Laurent Aimar
5 *
6 * This file is part of Libav.
7 *
8 * Libav 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.
12 *
13 * Libav 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.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with Libav; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <assert.h>
24 #include <string.h>
25
26 #include "libavutil/log.h"
27 #include "libavutil/time.h"
28
29 #include "avcodec.h"
30 #include "mpegvideo.h"
31 #include "dxva2_internal.h"
32
33 void *ff_dxva2_get_surface(const AVFrame *frame)
34 {
35 return frame->data[3];
36 }
37
38 unsigned ff_dxva2_get_surface_index(const AVCodecContext *avctx,
39 const AVDXVAContext *ctx,
40 const AVFrame *frame)
41 {
42 void *surface = ff_dxva2_get_surface(frame);
43 unsigned i;
44
45 for (i = 0; i < DXVA_CONTEXT_COUNT(avctx, ctx); i++)
46 if (DXVA_CONTEXT_SURFACE(avctx, ctx, i) == surface)
47 return i;
48
49 assert(0);
50 return 0;
51 }
52
53 int ff_dxva2_commit_buffer(AVCodecContext *avctx,
54 AVDXVAContext *ctx,
55 DECODER_BUFFER_DESC *dsc,
56 unsigned type, const void *data, unsigned size,
57 unsigned mb_count)
58 {
59 void *dxva_data;
60 unsigned dxva_size;
61 int result;
62 HRESULT hr;
63
64 #if CONFIG_D3D11VA
65 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
66 hr = ID3D11VideoContext_GetDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context,
67 D3D11VA_CONTEXT(ctx)->decoder,
68 type,
69 &dxva_size, &dxva_data);
70 #endif
71 #if CONFIG_DXVA2
72 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
73 hr = IDirectXVideoDecoder_GetBuffer(DXVA2_CONTEXT(ctx)->decoder, type,
74 &dxva_data, &dxva_size);
75 #endif
76 if (FAILED(hr)) {
77 av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %u: 0x%lx\n",
78 type, hr);
79 return -1;
80 }
81 if (size <= dxva_size) {
82 memcpy(dxva_data, data, size);
83
84 #if CONFIG_D3D11VA
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;
91 }
92 #endif
93 #if CONFIG_DXVA2
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;
100 }
101 #endif
102
103 result = 0;
104 } else {
105 av_log(avctx, AV_LOG_ERROR, "Buffer for type %u was too small\n", type);
106 result = -1;
107 }
108
109 #if CONFIG_D3D11VA
110 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
111 hr = ID3D11VideoContext_ReleaseDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type);
112 #endif
113 #if CONFIG_DXVA2
114 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
115 hr = IDirectXVideoDecoder_ReleaseBuffer(DXVA2_CONTEXT(ctx)->decoder, type);
116 #endif
117 if (FAILED(hr)) {
118 av_log(avctx, AV_LOG_ERROR,
119 "Failed to release buffer type %u: 0x%lx\n",
120 type, hr);
121 result = -1;
122 }
123 return result;
124 }
125
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))
132 {
133 AVDXVAContext *ctx = avctx->hwaccel_context;
134 unsigned buffer_count = 0;
135 D3D11_VIDEO_DECODER_BUFFER_DESC buffer11[4];
136 DXVA2_DecodeBufferDesc buffer2[4];
137 DECODER_BUFFER_DESC *buffer,*buffer_slice;
138 int result, runs = 0;
139 HRESULT hr;
140 unsigned type;
141
142 do {
143 #if CONFIG_D3D11VA
144 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
145 hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder,
146 ff_dxva2_get_surface(frame),
147 0, NULL);
148 #endif
149 #if CONFIG_DXVA2
150 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
151 hr = IDirectXVideoDecoder_BeginFrame(DXVA2_CONTEXT(ctx)->decoder,
152 ff_dxva2_get_surface(frame),
153 NULL);
154 #endif
155 if (hr == E_PENDING)
156 av_usleep(2000);
157 } while (hr == E_PENDING && ++runs < 50);
158
159 if (FAILED(hr)) {
160 av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%lx\n", hr);
161 return -1;
162 }
163
164 #if CONFIG_D3D11VA
165 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
166 buffer = &buffer11[buffer_count];
167 type = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
168 }
169 #endif
170 #if CONFIG_DXVA2
171 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
172 buffer = &buffer2[buffer_count];
173 type = DXVA2_PictureParametersBufferType;
174 }
175 #endif
176 result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
177 type,
178 pp, pp_size, 0);
179 if (result) {
180 av_log(avctx, AV_LOG_ERROR,
181 "Failed to add picture parameter buffer\n");
182 goto end;
183 }
184 buffer_count++;
185
186 if (qm_size > 0) {
187 #if CONFIG_D3D11VA
188 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
189 buffer = &buffer11[buffer_count];
190 type = D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX;
191 }
192 #endif
193 #if CONFIG_DXVA2
194 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
195 buffer = &buffer2[buffer_count];
196 type = DXVA2_InverseQuantizationMatrixBufferType;
197 }
198 #endif
199 result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
200 type,
201 qm, qm_size, 0);
202 if (result) {
203 av_log(avctx, AV_LOG_ERROR,
204 "Failed to add inverse quantization matrix buffer\n");
205 goto end;
206 }
207 buffer_count++;
208 }
209
210 #if CONFIG_D3D11VA
211 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
212 buffer = &buffer11[buffer_count + 0];
213 buffer_slice = &buffer11[buffer_count + 1];
214 }
215 #endif
216 #if CONFIG_DXVA2
217 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
218 buffer = &buffer2[buffer_count + 0];
219 buffer_slice = &buffer2[buffer_count + 1];
220 }
221 #endif
222
223 result = commit_bs_si(avctx,
224 buffer,
225 buffer_slice);
226 if (result) {
227 av_log(avctx, AV_LOG_ERROR,
228 "Failed to add bitstream or slice control buffer\n");
229 goto end;
230 }
231 buffer_count += 2;
232
233 /* TODO Film Grain when possible */
234
235 assert(buffer_count == 1 + (qm_size > 0) + 2);
236
237 #if CONFIG_D3D11VA
238 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
239 hr = ID3D11VideoContext_SubmitDecoderBuffers(D3D11VA_CONTEXT(ctx)->video_context,
240 D3D11VA_CONTEXT(ctx)->decoder,
241 buffer_count, buffer11);
242 #endif
243 #if CONFIG_DXVA2
244 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
245 DXVA2_DecodeExecuteParams exec = {
246 .NumCompBuffers = buffer_count,
247 .pCompressedBuffers = buffer2,
248 .pExtensionData = NULL,
249 };
250 hr = IDirectXVideoDecoder_Execute(DXVA2_CONTEXT(ctx)->decoder, &exec);
251 }
252 #endif
253 if (FAILED(hr)) {
254 av_log(avctx, AV_LOG_ERROR, "Failed to execute: 0x%lx\n", hr);
255 result = -1;
256 }
257
258 end:
259 #if CONFIG_D3D11VA
260 if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
261 hr = ID3D11VideoContext_DecoderEndFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder);
262 #endif
263 #if CONFIG_DXVA2
264 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
265 hr = IDirectXVideoDecoder_EndFrame(DXVA2_CONTEXT(ctx)->decoder, NULL);
266 #endif
267 if (FAILED(hr)) {
268 av_log(avctx, AV_LOG_ERROR, "Failed to end frame: 0x%lx\n", hr);
269 result = -1;
270 }
271
272 return result;
273 }