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