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