]> git.sesse.net Git - ffmpeg/blob - libavcodec/dxva2.c
Merge commit 'e62ff72fc1052273deb708ba715f73e5187281d4'
[ffmpeg] / libavcodec / dxva2.c
1 /*
2  * DXVA2 HW acceleration.
3  *
4  * copyright (c) 2010 Laurent Aimar
5  *
6  * This file is part of FFmpeg.
7  *
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.
12  *
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.
17  *
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
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 "dxva2_internal.h"
31
32 void *ff_dxva2_get_surface(const AVFrame *frame)
33 {
34     return frame->data[3];
35 }
36
37 unsigned ff_dxva2_get_surface_index(const AVCodecContext *avctx,
38                                     const AVDXVAContext *ctx,
39                                     const AVFrame *frame)
40 {
41     void *surface = ff_dxva2_get_surface(frame);
42     unsigned i;
43
44     for (i = 0; i < DXVA_CONTEXT_COUNT(avctx, ctx); i++)
45         if (DXVA_CONTEXT_SURFACE(avctx, ctx, i) == surface)
46             return i;
47
48     assert(0);
49     return 0;
50 }
51
52 int ff_dxva2_commit_buffer(AVCodecContext *avctx,
53                            AVDXVAContext *ctx,
54                            DECODER_BUFFER_DESC *dsc,
55                            unsigned type, const void *data, unsigned size,
56                            unsigned mb_count)
57 {
58     void     *dxva_data;
59     unsigned dxva_size;
60     int      result;
61     HRESULT hr = 0;
62
63 #if CONFIG_D3D11VA
64     if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
65         hr = ID3D11VideoContext_GetDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context,
66                                                  D3D11VA_CONTEXT(ctx)->decoder,
67                                                  type,
68                                                  &dxva_size, &dxva_data);
69 #endif
70 #if CONFIG_DXVA2
71     if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
72         hr = IDirectXVideoDecoder_GetBuffer(DXVA2_CONTEXT(ctx)->decoder, type,
73                                             &dxva_data, &dxva_size);
74 #endif
75     if (FAILED(hr)) {
76         av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %u: 0x%lx\n",
77                type, hr);
78         return -1;
79     }
80     if (size <= dxva_size) {
81         memcpy(dxva_data, data, size);
82
83 #if CONFIG_D3D11VA
84         if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
85             D3D11_VIDEO_DECODER_BUFFER_DESC *dsc11 = dsc;
86             memset(dsc11, 0, sizeof(*dsc11));
87             dsc11->BufferType           = type;
88             dsc11->DataSize             = size;
89             dsc11->NumMBsInBuffer       = mb_count;
90         }
91 #endif
92 #if CONFIG_DXVA2
93         if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
94             DXVA2_DecodeBufferDesc *dsc2 = dsc;
95             memset(dsc2, 0, sizeof(*dsc2));
96             dsc2->CompressedBufferType = type;
97             dsc2->DataSize             = size;
98             dsc2->NumMBsInBuffer       = mb_count;
99         }
100 #endif
101
102         result = 0;
103     } else {
104         av_log(avctx, AV_LOG_ERROR, "Buffer for type %u was too small\n", type);
105         result = -1;
106     }
107
108 #if CONFIG_D3D11VA
109     if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
110         hr = ID3D11VideoContext_ReleaseDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type);
111 #endif
112 #if CONFIG_DXVA2
113     if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
114         hr = IDirectXVideoDecoder_ReleaseBuffer(DXVA2_CONTEXT(ctx)->decoder, type);
115 #endif
116     if (FAILED(hr)) {
117         av_log(avctx, AV_LOG_ERROR,
118                "Failed to release buffer type %u: 0x%lx\n",
119                type, hr);
120         result = -1;
121     }
122     return result;
123 }
124
125 int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
126                               const void *pp, unsigned pp_size,
127                               const void *qm, unsigned qm_size,
128                               int (*commit_bs_si)(AVCodecContext *,
129                                                   DECODER_BUFFER_DESC *bs,
130                                                   DECODER_BUFFER_DESC *slice))
131 {
132     AVDXVAContext *ctx = avctx->hwaccel_context;
133     unsigned               buffer_count = 0;
134 #if CONFIG_D3D11VA
135     D3D11_VIDEO_DECODER_BUFFER_DESC buffer11[4];
136 #endif
137 #if CONFIG_DXVA2
138     DXVA2_DecodeBufferDesc          buffer2[4];
139 #endif
140     DECODER_BUFFER_DESC             *buffer = NULL, *buffer_slice = NULL;
141     int result, runs = 0;
142     HRESULT hr;
143     unsigned type;
144
145     do {
146 #if CONFIG_D3D11VA
147         if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
148             if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
149                 WaitForSingleObjectEx(D3D11VA_CONTEXT(ctx)->context_mutex, INFINITE, FALSE);
150             hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder,
151                                                       ff_dxva2_get_surface(frame),
152                                                       0, NULL);
153         }
154 #endif
155 #if CONFIG_DXVA2
156         if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
157             hr = IDirectXVideoDecoder_BeginFrame(DXVA2_CONTEXT(ctx)->decoder,
158                                                  ff_dxva2_get_surface(frame),
159                                                  NULL);
160 #endif
161         if (hr != E_PENDING || ++runs > 50)
162             break;
163 #if CONFIG_D3D11VA
164         if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
165             if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
166                 ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
167 #endif
168         av_usleep(2000);
169     } while(1);
170
171     if (FAILED(hr)) {
172         av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%lx\n", hr);
173 #if CONFIG_D3D11VA
174         if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
175             if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
176                 ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
177 #endif
178         return -1;
179     }
180
181 #if CONFIG_D3D11VA
182     if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
183         buffer = &buffer11[buffer_count];
184         type = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
185     }
186 #endif
187 #if CONFIG_DXVA2
188     if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
189         buffer = &buffer2[buffer_count];
190         type = DXVA2_PictureParametersBufferType;
191     }
192 #endif
193     result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
194                                     type,
195                                     pp, pp_size, 0);
196     if (result) {
197         av_log(avctx, AV_LOG_ERROR,
198                "Failed to add picture parameter buffer\n");
199         goto end;
200     }
201     buffer_count++;
202
203     if (qm_size > 0) {
204 #if CONFIG_D3D11VA
205         if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
206             buffer = &buffer11[buffer_count];
207             type = D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX;
208         }
209 #endif
210 #if CONFIG_DXVA2
211         if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
212             buffer = &buffer2[buffer_count];
213             type = DXVA2_InverseQuantizationMatrixBufferType;
214         }
215 #endif
216         result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
217                                         type,
218                                         qm, qm_size, 0);
219         if (result) {
220             av_log(avctx, AV_LOG_ERROR,
221                    "Failed to add inverse quantization matrix buffer\n");
222             goto end;
223         }
224         buffer_count++;
225     }
226
227 #if CONFIG_D3D11VA
228     if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
229         buffer       = &buffer11[buffer_count + 0];
230         buffer_slice = &buffer11[buffer_count + 1];
231     }
232 #endif
233 #if CONFIG_DXVA2
234     if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
235         buffer       = &buffer2[buffer_count + 0];
236         buffer_slice = &buffer2[buffer_count + 1];
237     }
238 #endif
239
240     result = commit_bs_si(avctx,
241                           buffer,
242                           buffer_slice);
243     if (result) {
244         av_log(avctx, AV_LOG_ERROR,
245                "Failed to add bitstream or slice control buffer\n");
246         goto end;
247     }
248     buffer_count += 2;
249
250     /* TODO Film Grain when possible */
251
252     assert(buffer_count == 1 + (qm_size > 0) + 2);
253
254 #if CONFIG_D3D11VA
255     if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
256         hr = ID3D11VideoContext_SubmitDecoderBuffers(D3D11VA_CONTEXT(ctx)->video_context,
257                                                      D3D11VA_CONTEXT(ctx)->decoder,
258                                                      buffer_count, buffer11);
259 #endif
260 #if CONFIG_DXVA2
261     if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
262         DXVA2_DecodeExecuteParams exec = {
263             .NumCompBuffers     = buffer_count,
264             .pCompressedBuffers = buffer2,
265             .pExtensionData     = NULL,
266         };
267         hr = IDirectXVideoDecoder_Execute(DXVA2_CONTEXT(ctx)->decoder, &exec);
268     }
269 #endif
270     if (FAILED(hr)) {
271         av_log(avctx, AV_LOG_ERROR, "Failed to execute: 0x%lx\n", hr);
272         result = -1;
273     }
274
275 end:
276 #if CONFIG_D3D11VA
277     if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
278         hr = ID3D11VideoContext_DecoderEndFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder);
279         if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
280             ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
281     }
282 #endif
283 #if CONFIG_DXVA2
284     if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
285         hr = IDirectXVideoDecoder_EndFrame(DXVA2_CONTEXT(ctx)->decoder, NULL);
286 #endif
287     if (FAILED(hr)) {
288         av_log(avctx, AV_LOG_ERROR, "Failed to end frame: 0x%lx\n", hr);
289         result = -1;
290     }
291
292     return result;
293 }