FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dxva2.c
Go to the documentation of this file.
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 
33 {
34  return frame->data[3];
35 }
36 
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 
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 
126  const void *pp, unsigned pp_size,
127  const void *qm, unsigned qm_size,
128  int (*commit_bs_si)(AVCodecContext *,
130  DECODER_BUFFER_DESC *slice))
131 {
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 }
#define NULL
Definition: coverity.c:32
This structure describes decoded (raw) audio or video data.
Definition: frame.h:184
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1877
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition: time.c:76
void * ff_dxva2_get_surface(const AVFrame *frame)
Definition: dxva2.c:32
void * hwaccel_context
Hardware accelerator context.
Definition: avcodec.h:2980
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame, const void *pp, unsigned pp_size, const void *qm, unsigned qm_size, int(*commit_bs_si)(AVCodecContext *, DECODER_BUFFER_DESC *bs, DECODER_BUFFER_DESC *slice))
Definition: dxva2.c:125
static AVFrame * frame
ptrdiff_t size
Definition: opengl_enc.c:101
#define av_log(a,...)
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define FALSE
Definition: windows2linux.h:37
static const chunk_decoder decoder[8]
Definition: dfa.c:327
AVFormatContext * ctx
Definition: movenc.c:48
Libavcodec external API header.
unsigned ff_dxva2_get_surface_index(const AVCodecContext *avctx, const AVDXVAContext *ctx, const AVFrame *frame)
Definition: dxva2.c:37
main external API structure.
Definition: avcodec.h:1649
int ff_dxva2_commit_buffer(AVCodecContext *avctx, AVDXVAContext *ctx, DECODER_BUFFER_DESC *dsc, unsigned type, const void *data, unsigned size, unsigned mb_count)
Definition: dxva2.c:52
GLint GLenum type
Definition: opengl_enc.c:105
void DECODER_BUFFER_DESC
HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer. ...
Definition: pixfmt.h:148
DWORD HRESULT
#define FAILED(hr)
Definition: windows2linux.h:48
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:198
HW decoding through Direct3D11, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer...
Definition: pixfmt.h:242
#define INVALID_HANDLE_VALUE
Definition: windows2linux.h:47
GLuint buffer
Definition: opengl_enc.c:102