Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * This file is part of FFmpeg. | |
3 | * | |
4 | * FFmpeg is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU Lesser General Public | |
6 | * License as published by the Free Software Foundation; either | |
7 | * version 2.1 of the License, or (at your option) any later version. | |
8 | * | |
9 | * FFmpeg is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | * Lesser General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU Lesser General Public | |
15 | * License along with FFmpeg; if not, write to the Free Software | |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | */ | |
18 | ||
19 | #include <windows.h> | |
20 | ||
21 | #ifdef _WIN32_WINNT | |
22 | #undef _WIN32_WINNT | |
23 | #endif | |
24 | #define _WIN32_WINNT 0x0600 | |
25 | #define DXVA2API_USE_BITFIELDS | |
26 | #define COBJMACROS | |
27 | ||
28 | #include <stdint.h> | |
29 | ||
30 | #include <d3d9.h> | |
31 | #include <dxva2api.h> | |
32 | ||
33 | #include "ffmpeg.h" | |
34 | ||
35 | #include "libavcodec/dxva2.h" | |
36 | ||
37 | #include "libavutil/avassert.h" | |
38 | #include "libavutil/buffer.h" | |
39 | #include "libavutil/frame.h" | |
40 | #include "libavutil/imgutils.h" | |
41 | #include "libavutil/pixfmt.h" | |
42 | ||
43 | /* define all the GUIDs used directly here, | |
44 | to avoid problems with inconsistent dxva2api.h versions in mingw-w64 and different MSVC version */ | |
45 | #include <initguid.h> | |
46 | DEFINE_GUID(IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02); | |
47 | ||
48 | DEFINE_GUID(DXVA2_ModeMPEG2_VLD, 0xee27417f, 0x5e28,0x4e65,0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9); | |
49 | DEFINE_GUID(DXVA2_ModeMPEG2and1_VLD, 0x86695f12, 0x340e,0x4f04,0x9f,0xd3,0x92,0x53,0xdd,0x32,0x74,0x60); | |
50 | DEFINE_GUID(DXVA2_ModeH264_E, 0x1b81be68, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); | |
51 | DEFINE_GUID(DXVA2_ModeH264_F, 0x1b81be69, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); | |
52 | DEFINE_GUID(DXVADDI_Intel_ModeH264_E, 0x604F8E68, 0x4951,0x4C54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6); | |
53 | DEFINE_GUID(DXVA2_ModeVC1_D, 0x1b81beA3, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); | |
54 | DEFINE_GUID(DXVA2_ModeVC1_D2010, 0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); | |
55 | DEFINE_GUID(DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); | |
56 | DEFINE_GUID(GUID_NULL, 0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00); | |
57 | ||
58 | typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT); | |
59 | typedef HRESULT WINAPI pCreateDeviceManager9(UINT *, IDirect3DDeviceManager9 **); | |
60 | ||
61 | typedef struct dxva2_mode { | |
62 | const GUID *guid; | |
63 | enum AVCodecID codec; | |
64 | } dxva2_mode; | |
65 | ||
66 | static const dxva2_mode dxva2_modes[] = { | |
67 | /* MPEG-2 */ | |
68 | { &DXVA2_ModeMPEG2_VLD, AV_CODEC_ID_MPEG2VIDEO }, | |
69 | { &DXVA2_ModeMPEG2and1_VLD, AV_CODEC_ID_MPEG2VIDEO }, | |
70 | ||
71 | /* H.264 */ | |
72 | { &DXVA2_ModeH264_F, AV_CODEC_ID_H264 }, | |
73 | { &DXVA2_ModeH264_E, AV_CODEC_ID_H264 }, | |
74 | /* Intel specific H.264 mode */ | |
75 | { &DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264 }, | |
76 | ||
77 | /* VC-1 / WMV3 */ | |
78 | { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_VC1 }, | |
79 | { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_WMV3 }, | |
80 | { &DXVA2_ModeVC1_D, AV_CODEC_ID_VC1 }, | |
81 | { &DXVA2_ModeVC1_D, AV_CODEC_ID_WMV3 }, | |
82 | ||
83 | { NULL, 0 }, | |
84 | }; | |
85 | ||
86 | typedef struct surface_info { | |
87 | int used; | |
88 | uint64_t age; | |
89 | } surface_info; | |
90 | ||
91 | typedef struct DXVA2Context { | |
92 | HMODULE d3dlib; | |
93 | HMODULE dxva2lib; | |
94 | ||
95 | HANDLE deviceHandle; | |
96 | ||
97 | IDirect3D9 *d3d9; | |
98 | IDirect3DDevice9 *d3d9device; | |
99 | IDirect3DDeviceManager9 *d3d9devmgr; | |
100 | IDirectXVideoDecoderService *decoder_service; | |
101 | IDirectXVideoDecoder *decoder; | |
102 | ||
103 | GUID decoder_guid; | |
104 | DXVA2_ConfigPictureDecode decoder_config; | |
105 | ||
106 | LPDIRECT3DSURFACE9 *surfaces; | |
107 | surface_info *surface_infos; | |
108 | uint32_t num_surfaces; | |
109 | uint64_t surface_age; | |
110 | ||
111 | AVFrame *tmp_frame; | |
112 | } DXVA2Context; | |
113 | ||
114 | typedef struct DXVA2SurfaceWrapper { | |
115 | DXVA2Context *ctx; | |
116 | LPDIRECT3DSURFACE9 surface; | |
117 | IDirectXVideoDecoder *decoder; | |
118 | } DXVA2SurfaceWrapper; | |
119 | ||
120 | static void dxva2_destroy_decoder(AVCodecContext *s) | |
121 | { | |
122 | InputStream *ist = s->opaque; | |
123 | DXVA2Context *ctx = ist->hwaccel_ctx; | |
124 | int i; | |
125 | ||
126 | if (ctx->surfaces) { | |
127 | for (i = 0; i < ctx->num_surfaces; i++) { | |
128 | if (ctx->surfaces[i]) | |
129 | IDirect3DSurface9_Release(ctx->surfaces[i]); | |
130 | } | |
131 | } | |
132 | av_freep(&ctx->surfaces); | |
133 | av_freep(&ctx->surface_infos); | |
134 | ctx->num_surfaces = 0; | |
135 | ctx->surface_age = 0; | |
136 | ||
137 | if (ctx->decoder) { | |
138 | IDirectXVideoDecoder_Release(ctx->decoder); | |
139 | ctx->decoder = NULL; | |
140 | } | |
141 | } | |
142 | ||
143 | static void dxva2_uninit(AVCodecContext *s) | |
144 | { | |
145 | InputStream *ist = s->opaque; | |
146 | DXVA2Context *ctx = ist->hwaccel_ctx; | |
147 | ||
148 | ist->hwaccel_uninit = NULL; | |
149 | ist->hwaccel_get_buffer = NULL; | |
150 | ist->hwaccel_retrieve_data = NULL; | |
151 | ||
152 | if (ctx->decoder) | |
153 | dxva2_destroy_decoder(s); | |
154 | ||
155 | if (ctx->decoder_service) | |
156 | IDirectXVideoDecoderService_Release(ctx->decoder_service); | |
157 | ||
158 | if (ctx->d3d9devmgr && ctx->deviceHandle != INVALID_HANDLE_VALUE) | |
159 | IDirect3DDeviceManager9_CloseDeviceHandle(ctx->d3d9devmgr, ctx->deviceHandle); | |
160 | ||
161 | if (ctx->d3d9devmgr) | |
162 | IDirect3DDeviceManager9_Release(ctx->d3d9devmgr); | |
163 | ||
164 | if (ctx->d3d9device) | |
165 | IDirect3DDevice9_Release(ctx->d3d9device); | |
166 | ||
167 | if (ctx->d3d9) | |
168 | IDirect3D9_Release(ctx->d3d9); | |
169 | ||
170 | if (ctx->d3dlib) | |
171 | FreeLibrary(ctx->d3dlib); | |
172 | ||
173 | if (ctx->dxva2lib) | |
174 | FreeLibrary(ctx->dxva2lib); | |
175 | ||
176 | av_frame_free(&ctx->tmp_frame); | |
177 | ||
178 | av_freep(&ist->hwaccel_ctx); | |
179 | av_freep(&s->hwaccel_context); | |
180 | } | |
181 | ||
182 | static void dxva2_release_buffer(void *opaque, uint8_t *data) | |
183 | { | |
184 | DXVA2SurfaceWrapper *w = opaque; | |
185 | DXVA2Context *ctx = w->ctx; | |
186 | int i; | |
187 | ||
188 | for (i = 0; i < ctx->num_surfaces; i++) { | |
189 | if (ctx->surfaces[i] == w->surface) { | |
190 | ctx->surface_infos[i].used = 0; | |
191 | break; | |
192 | } | |
193 | } | |
194 | IDirect3DSurface9_Release(w->surface); | |
195 | IDirectXVideoDecoder_Release(w->decoder); | |
196 | av_free(w); | |
197 | } | |
198 | ||
199 | static int dxva2_get_buffer(AVCodecContext *s, AVFrame *frame, int flags) | |
200 | { | |
201 | InputStream *ist = s->opaque; | |
202 | DXVA2Context *ctx = ist->hwaccel_ctx; | |
203 | int i, old_unused = -1; | |
204 | LPDIRECT3DSURFACE9 surface; | |
205 | DXVA2SurfaceWrapper *w = NULL; | |
206 | ||
207 | av_assert0(frame->format == AV_PIX_FMT_DXVA2_VLD); | |
208 | ||
209 | for (i = 0; i < ctx->num_surfaces; i++) { | |
210 | surface_info *info = &ctx->surface_infos[i]; | |
211 | if (!info->used && (old_unused == -1 || info->age < ctx->surface_infos[old_unused].age)) | |
212 | old_unused = i; | |
213 | } | |
214 | if (old_unused == -1) { | |
215 | av_log(NULL, AV_LOG_ERROR, "No free DXVA2 surface!\n"); | |
216 | return AVERROR(ENOMEM); | |
217 | } | |
218 | i = old_unused; | |
219 | ||
220 | surface = ctx->surfaces[i]; | |
221 | ||
222 | w = av_mallocz(sizeof(*w)); | |
223 | if (!w) | |
224 | return AVERROR(ENOMEM); | |
225 | ||
226 | frame->buf[0] = av_buffer_create((uint8_t*)surface, 0, | |
227 | dxva2_release_buffer, w, | |
228 | AV_BUFFER_FLAG_READONLY); | |
229 | if (!frame->buf[0]) { | |
230 | av_free(w); | |
231 | return AVERROR(ENOMEM); | |
232 | } | |
233 | ||
234 | w->ctx = ctx; | |
235 | w->surface = surface; | |
236 | IDirect3DSurface9_AddRef(w->surface); | |
237 | w->decoder = ctx->decoder; | |
238 | IDirectXVideoDecoder_AddRef(w->decoder); | |
239 | ||
240 | ctx->surface_infos[i].used = 1; | |
241 | ctx->surface_infos[i].age = ctx->surface_age++; | |
242 | ||
243 | frame->data[3] = (uint8_t *)surface; | |
244 | ||
245 | return 0; | |
246 | } | |
247 | ||
248 | static int dxva2_retrieve_data(AVCodecContext *s, AVFrame *frame) | |
249 | { | |
250 | LPDIRECT3DSURFACE9 surface = (LPDIRECT3DSURFACE9)frame->data[3]; | |
251 | InputStream *ist = s->opaque; | |
252 | DXVA2Context *ctx = ist->hwaccel_ctx; | |
253 | D3DSURFACE_DESC surfaceDesc; | |
254 | D3DLOCKED_RECT LockedRect; | |
255 | HRESULT hr; | |
256 | int ret; | |
257 | ||
258 | IDirect3DSurface9_GetDesc(surface, &surfaceDesc); | |
259 | ||
260 | ctx->tmp_frame->width = frame->width; | |
261 | ctx->tmp_frame->height = frame->height; | |
262 | ctx->tmp_frame->format = AV_PIX_FMT_NV12; | |
263 | ||
264 | ret = av_frame_get_buffer(ctx->tmp_frame, 32); | |
265 | if (ret < 0) | |
266 | return ret; | |
267 | ||
268 | hr = IDirect3DSurface9_LockRect(surface, &LockedRect, NULL, D3DLOCK_READONLY); | |
269 | if (FAILED(hr)) { | |
270 | av_log(NULL, AV_LOG_ERROR, "Unable to lock DXVA2 surface\n"); | |
271 | return AVERROR_UNKNOWN; | |
272 | } | |
273 | ||
274 | av_image_copy_plane(ctx->tmp_frame->data[0], ctx->tmp_frame->linesize[0], | |
275 | (uint8_t*)LockedRect.pBits, | |
276 | LockedRect.Pitch, frame->width, frame->height); | |
277 | ||
278 | av_image_copy_plane(ctx->tmp_frame->data[1], ctx->tmp_frame->linesize[1], | |
279 | (uint8_t*)LockedRect.pBits + LockedRect.Pitch * surfaceDesc.Height, | |
280 | LockedRect.Pitch, frame->width, frame->height / 2); | |
281 | ||
282 | IDirect3DSurface9_UnlockRect(surface); | |
283 | ||
284 | ret = av_frame_copy_props(ctx->tmp_frame, frame); | |
285 | if (ret < 0) | |
286 | goto fail; | |
287 | ||
288 | av_frame_unref(frame); | |
289 | av_frame_move_ref(frame, ctx->tmp_frame); | |
290 | ||
291 | return 0; | |
292 | fail: | |
293 | av_frame_unref(ctx->tmp_frame); | |
294 | return ret; | |
295 | } | |
296 | ||
297 | static int dxva2_alloc(AVCodecContext *s) | |
298 | { | |
299 | InputStream *ist = s->opaque; | |
300 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; | |
301 | DXVA2Context *ctx; | |
302 | pDirect3DCreate9 *createD3D = NULL; | |
303 | pCreateDeviceManager9 *createDeviceManager = NULL; | |
304 | HRESULT hr; | |
305 | D3DPRESENT_PARAMETERS d3dpp = {0}; | |
306 | D3DDISPLAYMODE d3ddm; | |
307 | unsigned resetToken = 0; | |
308 | UINT adapter = D3DADAPTER_DEFAULT; | |
309 | ||
310 | ctx = av_mallocz(sizeof(*ctx)); | |
311 | if (!ctx) | |
312 | return AVERROR(ENOMEM); | |
313 | ||
314 | ctx->deviceHandle = INVALID_HANDLE_VALUE; | |
315 | ||
316 | ist->hwaccel_ctx = ctx; | |
317 | ist->hwaccel_uninit = dxva2_uninit; | |
318 | ist->hwaccel_get_buffer = dxva2_get_buffer; | |
319 | ist->hwaccel_retrieve_data = dxva2_retrieve_data; | |
320 | ||
321 | ctx->d3dlib = LoadLibrary("d3d9.dll"); | |
322 | if (!ctx->d3dlib) { | |
323 | av_log(NULL, loglevel, "Failed to load D3D9 library\n"); | |
324 | goto fail; | |
325 | } | |
326 | ctx->dxva2lib = LoadLibrary("dxva2.dll"); | |
327 | if (!ctx->dxva2lib) { | |
328 | av_log(NULL, loglevel, "Failed to load DXVA2 library\n"); | |
329 | goto fail; | |
330 | } | |
331 | ||
332 | createD3D = (pDirect3DCreate9 *)GetProcAddress(ctx->d3dlib, "Direct3DCreate9"); | |
333 | if (!createD3D) { | |
334 | av_log(NULL, loglevel, "Failed to locate Direct3DCreate9\n"); | |
335 | goto fail; | |
336 | } | |
337 | createDeviceManager = (pCreateDeviceManager9 *)GetProcAddress(ctx->dxva2lib, "DXVA2CreateDirect3DDeviceManager9"); | |
338 | if (!createDeviceManager) { | |
339 | av_log(NULL, loglevel, "Failed to locate DXVA2CreateDirect3DDeviceManager9\n"); | |
340 | goto fail; | |
341 | } | |
342 | ||
343 | ctx->d3d9 = createD3D(D3D_SDK_VERSION); | |
344 | if (!ctx->d3d9) { | |
345 | av_log(NULL, loglevel, "Failed to create IDirect3D object\n"); | |
346 | goto fail; | |
347 | } | |
348 | ||
349 | if (ist->hwaccel_device) { | |
350 | adapter = atoi(ist->hwaccel_device); | |
351 | av_log(NULL, AV_LOG_INFO, "Using HWAccel device %d\n", adapter); | |
352 | } | |
353 | ||
354 | IDirect3D9_GetAdapterDisplayMode(ctx->d3d9, adapter, &d3ddm); | |
355 | d3dpp.Windowed = TRUE; | |
356 | d3dpp.BackBufferWidth = 640; | |
357 | d3dpp.BackBufferHeight = 480; | |
358 | d3dpp.BackBufferCount = 0; | |
359 | d3dpp.BackBufferFormat = d3ddm.Format; | |
360 | d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; | |
361 | d3dpp.Flags = D3DPRESENTFLAG_VIDEO; | |
362 | ||
363 | hr = IDirect3D9_CreateDevice(ctx->d3d9, adapter, D3DDEVTYPE_HAL, GetShellWindow(), | |
364 | D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, | |
365 | &d3dpp, &ctx->d3d9device); | |
366 | if (FAILED(hr)) { | |
367 | av_log(NULL, loglevel, "Failed to create Direct3D device\n"); | |
368 | goto fail; | |
369 | } | |
370 | ||
371 | hr = createDeviceManager(&resetToken, &ctx->d3d9devmgr); | |
372 | if (FAILED(hr)) { | |
373 | av_log(NULL, loglevel, "Failed to create Direct3D device manager\n"); | |
374 | goto fail; | |
375 | } | |
376 | ||
377 | hr = IDirect3DDeviceManager9_ResetDevice(ctx->d3d9devmgr, ctx->d3d9device, resetToken); | |
378 | if (FAILED(hr)) { | |
379 | av_log(NULL, loglevel, "Failed to bind Direct3D device to device manager\n"); | |
380 | goto fail; | |
381 | } | |
382 | ||
383 | hr = IDirect3DDeviceManager9_OpenDeviceHandle(ctx->d3d9devmgr, &ctx->deviceHandle); | |
384 | if (FAILED(hr)) { | |
385 | av_log(NULL, loglevel, "Failed to open device handle\n"); | |
386 | goto fail; | |
387 | } | |
388 | ||
389 | hr = IDirect3DDeviceManager9_GetVideoService(ctx->d3d9devmgr, ctx->deviceHandle, &IID_IDirectXVideoDecoderService, (void **)&ctx->decoder_service); | |
390 | if (FAILED(hr)) { | |
391 | av_log(NULL, loglevel, "Failed to create IDirectXVideoDecoderService\n"); | |
392 | goto fail; | |
393 | } | |
394 | ||
395 | ctx->tmp_frame = av_frame_alloc(); | |
396 | if (!ctx->tmp_frame) | |
397 | goto fail; | |
398 | ||
399 | s->hwaccel_context = av_mallocz(sizeof(struct dxva_context)); | |
400 | if (!s->hwaccel_context) | |
401 | goto fail; | |
402 | ||
403 | return 0; | |
404 | fail: | |
405 | dxva2_uninit(s); | |
406 | return AVERROR(EINVAL); | |
407 | } | |
408 | ||
409 | static int dxva2_get_decoder_configuration(AVCodecContext *s, const GUID *device_guid, | |
410 | const DXVA2_VideoDesc *desc, | |
411 | DXVA2_ConfigPictureDecode *config) | |
412 | { | |
413 | InputStream *ist = s->opaque; | |
414 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; | |
415 | DXVA2Context *ctx = ist->hwaccel_ctx; | |
416 | unsigned cfg_count = 0, best_score = 0; | |
417 | DXVA2_ConfigPictureDecode *cfg_list = NULL; | |
418 | DXVA2_ConfigPictureDecode best_cfg = {{0}}; | |
419 | HRESULT hr; | |
420 | int i; | |
421 | ||
422 | hr = IDirectXVideoDecoderService_GetDecoderConfigurations(ctx->decoder_service, device_guid, desc, NULL, &cfg_count, &cfg_list); | |
423 | if (FAILED(hr)) { | |
424 | av_log(NULL, loglevel, "Unable to retrieve decoder configurations\n"); | |
425 | return AVERROR(EINVAL); | |
426 | } | |
427 | ||
428 | for (i = 0; i < cfg_count; i++) { | |
429 | DXVA2_ConfigPictureDecode *cfg = &cfg_list[i]; | |
430 | ||
431 | unsigned score; | |
432 | if (cfg->ConfigBitstreamRaw == 1) | |
433 | score = 1; | |
434 | else if (s->codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2) | |
435 | score = 2; | |
436 | else | |
437 | continue; | |
438 | if (IsEqualGUID(&cfg->guidConfigBitstreamEncryption, &DXVA2_NoEncrypt)) | |
439 | score += 16; | |
440 | if (score > best_score) { | |
441 | best_score = score; | |
442 | best_cfg = *cfg; | |
443 | } | |
444 | } | |
445 | CoTaskMemFree(cfg_list); | |
446 | ||
447 | if (!best_score) { | |
448 | av_log(NULL, loglevel, "No valid decoder configuration available\n"); | |
449 | return AVERROR(EINVAL); | |
450 | } | |
451 | ||
452 | *config = best_cfg; | |
453 | return 0; | |
454 | } | |
455 | ||
456 | static int dxva2_create_decoder(AVCodecContext *s) | |
457 | { | |
458 | InputStream *ist = s->opaque; | |
459 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; | |
460 | DXVA2Context *ctx = ist->hwaccel_ctx; | |
461 | struct dxva_context *dxva_ctx = s->hwaccel_context; | |
462 | GUID *guid_list = NULL; | |
463 | unsigned guid_count = 0, i, j; | |
464 | GUID device_guid = GUID_NULL; | |
465 | D3DFORMAT target_format = 0; | |
466 | DXVA2_VideoDesc desc = { 0 }; | |
467 | DXVA2_ConfigPictureDecode config; | |
468 | HRESULT hr; | |
469 | int surface_alignment; | |
470 | int ret; | |
471 | ||
472 | hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list); | |
473 | if (FAILED(hr)) { | |
474 | av_log(NULL, loglevel, "Failed to retrieve decoder device GUIDs\n"); | |
475 | goto fail; | |
476 | } | |
477 | ||
478 | for (i = 0; dxva2_modes[i].guid; i++) { | |
479 | D3DFORMAT *target_list = NULL; | |
480 | unsigned target_count = 0; | |
481 | const dxva2_mode *mode = &dxva2_modes[i]; | |
482 | if (mode->codec != s->codec_id) | |
483 | continue; | |
484 | ||
485 | for (j = 0; j < guid_count; j++) { | |
486 | if (IsEqualGUID(mode->guid, &guid_list[j])) | |
487 | break; | |
488 | } | |
489 | if (j == guid_count) | |
490 | continue; | |
491 | ||
492 | hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, mode->guid, &target_count, &target_list); | |
493 | if (FAILED(hr)) { | |
494 | continue; | |
495 | } | |
496 | for (j = 0; j < target_count; j++) { | |
497 | const D3DFORMAT format = target_list[j]; | |
498 | if (format == MKTAG('N','V','1','2')) { | |
499 | target_format = format; | |
500 | break; | |
501 | } | |
502 | } | |
503 | CoTaskMemFree(target_list); | |
504 | if (target_format) { | |
505 | device_guid = *mode->guid; | |
506 | break; | |
507 | } | |
508 | } | |
509 | CoTaskMemFree(guid_list); | |
510 | ||
511 | if (IsEqualGUID(&device_guid, &GUID_NULL)) { | |
512 | av_log(NULL, loglevel, "No decoder device for codec found\n"); | |
513 | goto fail; | |
514 | } | |
515 | ||
516 | desc.SampleWidth = s->coded_width; | |
517 | desc.SampleHeight = s->coded_height; | |
518 | desc.Format = target_format; | |
519 | ||
520 | ret = dxva2_get_decoder_configuration(s, &device_guid, &desc, &config); | |
521 | if (ret < 0) { | |
522 | goto fail; | |
523 | } | |
524 | ||
525 | /* decoding MPEG-2 requires additional alignment on some Intel GPUs, | |
526 | but it causes issues for H.264 on certain AMD GPUs..... */ | |
527 | if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) | |
528 | surface_alignment = 32; | |
529 | else | |
530 | surface_alignment = 16; | |
531 | ||
532 | /* 4 base work surfaces */ | |
533 | ctx->num_surfaces = 4; | |
534 | ||
535 | /* add surfaces based on number of possible refs */ | |
536 | if (s->codec_id == AV_CODEC_ID_H264) | |
537 | ctx->num_surfaces += 16; | |
538 | else | |
539 | ctx->num_surfaces += 2; | |
540 | ||
541 | /* add extra surfaces for frame threading */ | |
542 | if (s->active_thread_type & FF_THREAD_FRAME) | |
543 | ctx->num_surfaces += s->thread_count; | |
544 | ||
545 | ctx->surfaces = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surfaces)); | |
546 | ctx->surface_infos = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surface_infos)); | |
547 | ||
548 | if (!ctx->surfaces || !ctx->surface_infos) { | |
549 | av_log(NULL, loglevel, "Unable to allocate surface arrays\n"); | |
550 | goto fail; | |
551 | } | |
552 | ||
553 | hr = IDirectXVideoDecoderService_CreateSurface(ctx->decoder_service, | |
554 | FFALIGN(s->coded_width, surface_alignment), | |
555 | FFALIGN(s->coded_height, surface_alignment), | |
556 | ctx->num_surfaces - 1, | |
557 | target_format, D3DPOOL_DEFAULT, 0, | |
558 | DXVA2_VideoDecoderRenderTarget, | |
559 | ctx->surfaces, NULL); | |
560 | if (FAILED(hr)) { | |
561 | av_log(NULL, loglevel, "Failed to create %d video surfaces\n", ctx->num_surfaces); | |
562 | goto fail; | |
563 | } | |
564 | ||
565 | hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid, | |
566 | &desc, &config, ctx->surfaces, | |
567 | ctx->num_surfaces, &ctx->decoder); | |
568 | if (FAILED(hr)) { | |
569 | av_log(NULL, loglevel, "Failed to create DXVA2 video decoder\n"); | |
570 | goto fail; | |
571 | } | |
572 | ||
573 | ctx->decoder_guid = device_guid; | |
574 | ctx->decoder_config = config; | |
575 | ||
576 | dxva_ctx->cfg = &ctx->decoder_config; | |
577 | dxva_ctx->decoder = ctx->decoder; | |
578 | dxva_ctx->surface = ctx->surfaces; | |
579 | dxva_ctx->surface_count = ctx->num_surfaces; | |
580 | ||
581 | if (IsEqualGUID(&ctx->decoder_guid, &DXVADDI_Intel_ModeH264_E)) | |
582 | dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO; | |
583 | ||
584 | return 0; | |
585 | fail: | |
586 | dxva2_destroy_decoder(s); | |
587 | return AVERROR(EINVAL); | |
588 | } | |
589 | ||
590 | int dxva2_init(AVCodecContext *s) | |
591 | { | |
592 | InputStream *ist = s->opaque; | |
593 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; | |
594 | DXVA2Context *ctx; | |
595 | int ret; | |
596 | ||
597 | if (!ist->hwaccel_ctx) { | |
598 | ret = dxva2_alloc(s); | |
599 | if (ret < 0) | |
600 | return ret; | |
601 | } | |
602 | ctx = ist->hwaccel_ctx; | |
603 | ||
604 | if (s->codec_id == AV_CODEC_ID_H264 && | |
605 | (s->profile & ~FF_PROFILE_H264_CONSTRAINED) > FF_PROFILE_H264_HIGH) { | |
606 | av_log(NULL, loglevel, "Unsupported H.264 profile for DXVA2 HWAccel: %d\n", s->profile); | |
607 | return AVERROR(EINVAL); | |
608 | } | |
609 | ||
610 | if (ctx->decoder) | |
611 | dxva2_destroy_decoder(s); | |
612 | ||
613 | ret = dxva2_create_decoder(s); | |
614 | if (ret < 0) { | |
615 | av_log(NULL, loglevel, "Error creating the DXVA2 decoder\n"); | |
616 | return ret; | |
617 | } | |
618 | ||
619 | return 0; | |
620 | } |