]> git.sesse.net Git - ffmpeg/blob - libavcodec/dxva2.c
avcodec/dxva2: Fix "may be used uninitialized" warnings
[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 "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 = 0;
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 #if CONFIG_D3D11VA
136     D3D11_VIDEO_DECODER_BUFFER_DESC buffer11[4];
137 #endif
138     DXVA2_DecodeBufferDesc          buffer2[4];
139     DECODER_BUFFER_DESC             *buffer = NULL, *buffer_slice = NULL;
140     int result, runs = 0;
141     HRESULT hr;
142     unsigned type;
143
144     do {
145 #if CONFIG_D3D11VA
146         if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
147             hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder,
148                                                       ff_dxva2_get_surface(frame),
149                                                       0, NULL);
150 #endif
151 #if CONFIG_DXVA2
152         if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
153             hr = IDirectXVideoDecoder_BeginFrame(DXVA2_CONTEXT(ctx)->decoder,
154                                                  ff_dxva2_get_surface(frame),
155                                                  NULL);
156 #endif
157         if (hr == E_PENDING)
158             av_usleep(2000);
159     } while (hr == E_PENDING && ++runs < 50);
160
161     if (FAILED(hr)) {
162         av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%lx\n", hr);
163         return -1;
164     }
165
166 #if CONFIG_D3D11VA
167     if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
168         buffer = &buffer11[buffer_count];
169         type = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
170     }
171 #endif
172 #if CONFIG_DXVA2
173     if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
174         buffer = &buffer2[buffer_count];
175         type = DXVA2_PictureParametersBufferType;
176     }
177 #endif
178     result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
179                                     type,
180                                     pp, pp_size, 0);
181     if (result) {
182         av_log(avctx, AV_LOG_ERROR,
183                "Failed to add picture parameter buffer\n");
184         goto end;
185     }
186     buffer_count++;
187
188     if (qm_size > 0) {
189 #if CONFIG_D3D11VA
190         if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
191             buffer = &buffer11[buffer_count];
192             type = D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX;
193         }
194 #endif
195 #if CONFIG_DXVA2
196         if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
197             buffer = &buffer2[buffer_count];
198             type = DXVA2_InverseQuantizationMatrixBufferType;
199         }
200 #endif
201         result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
202                                         type,
203                                         qm, qm_size, 0);
204         if (result) {
205             av_log(avctx, AV_LOG_ERROR,
206                    "Failed to add inverse quantization matrix buffer\n");
207             goto end;
208         }
209         buffer_count++;
210     }
211
212 #if CONFIG_D3D11VA
213     if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
214         buffer       = &buffer11[buffer_count + 0];
215         buffer_slice = &buffer11[buffer_count + 1];
216     }
217 #endif
218 #if CONFIG_DXVA2
219     if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
220         buffer       = &buffer2[buffer_count + 0];
221         buffer_slice = &buffer2[buffer_count + 1];
222     }
223 #endif
224
225     result = commit_bs_si(avctx,
226                           buffer,
227                           buffer_slice);
228     if (result) {
229         av_log(avctx, AV_LOG_ERROR,
230                "Failed to add bitstream or slice control buffer\n");
231         goto end;
232     }
233     buffer_count += 2;
234
235     /* TODO Film Grain when possible */
236
237     assert(buffer_count == 1 + (qm_size > 0) + 2);
238
239 #if CONFIG_D3D11VA
240     if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
241         hr = ID3D11VideoContext_SubmitDecoderBuffers(D3D11VA_CONTEXT(ctx)->video_context,
242                                                      D3D11VA_CONTEXT(ctx)->decoder,
243                                                      buffer_count, buffer11);
244 #endif
245 #if CONFIG_DXVA2
246     if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
247         DXVA2_DecodeExecuteParams exec = {
248             .NumCompBuffers     = buffer_count,
249             .pCompressedBuffers = buffer2,
250             .pExtensionData     = NULL,
251         };
252         hr = IDirectXVideoDecoder_Execute(DXVA2_CONTEXT(ctx)->decoder, &exec);
253     }
254 #endif
255     if (FAILED(hr)) {
256         av_log(avctx, AV_LOG_ERROR, "Failed to execute: 0x%lx\n", hr);
257         result = -1;
258     }
259
260 end:
261 #if CONFIG_D3D11VA
262     if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD)
263         hr = ID3D11VideoContext_DecoderEndFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder);
264 #endif
265 #if CONFIG_DXVA2
266     if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
267         hr = IDirectXVideoDecoder_EndFrame(DXVA2_CONTEXT(ctx)->decoder, NULL);
268 #endif
269     if (FAILED(hr)) {
270         av_log(avctx, AV_LOG_ERROR, "Failed to end frame: 0x%lx\n", hr);
271         result = -1;
272     }
273
274     return result;
275 }