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 
32 static void *get_surface(const AVFrame *frame)
33 {
34  return frame->data[3];
35 }
36 
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 
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 
136  const void *pp, unsigned pp_size,
137  const void *qm, unsigned qm_size,
138  int (*commit_bs_si)(AVCodecContext *,
140  DECODER_BUFFER_DESC *slice))
141 {
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 }
#define NULL
Definition: coverity.c:32
This structure describes decoded (raw) audio or video data.
Definition: frame.h:187
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1960
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition: time.c:84
void * hwaccel_context
Hardware accelerator context.
Definition: avcodec.h:3064
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:135
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:328
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:1732
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:62
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:201
static void * get_surface(const AVFrame *frame)
Definition: dxva2.c:32
HW decoding through Direct3D11, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer...
Definition: pixfmt.h:243
#define INVALID_HANDLE_VALUE
Definition: windows2linux.h:47
GLuint buffer
Definition: opengl_enc.c:102