Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6147 | serge | 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 |
||
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 |
||
29 | |||
30 | #include |
||
31 | #include |
||
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 |
||
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_ModeHEVC_VLD_Main, 0x5b11d51b, 0x2f4c,0x4452,0xbc,0xc3,0x09,0xf2,0xa1,0x16,0x0c,0xc0); |
||
56 | DEFINE_GUID(DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); |
||
57 | DEFINE_GUID(GUID_NULL, 0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00); |
||
58 | |||
59 | typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT); |
||
60 | typedef HRESULT WINAPI pCreateDeviceManager9(UINT *, IDirect3DDeviceManager9 **); |
||
61 | |||
62 | typedef struct dxva2_mode { |
||
63 | const GUID *guid; |
||
64 | enum AVCodecID codec; |
||
65 | } dxva2_mode; |
||
66 | |||
67 | static const dxva2_mode dxva2_modes[] = { |
||
68 | /* MPEG-2 */ |
||
69 | { &DXVA2_ModeMPEG2_VLD, AV_CODEC_ID_MPEG2VIDEO }, |
||
70 | { &DXVA2_ModeMPEG2and1_VLD, AV_CODEC_ID_MPEG2VIDEO }, |
||
71 | |||
72 | /* H.264 */ |
||
73 | { &DXVA2_ModeH264_F, AV_CODEC_ID_H264 }, |
||
74 | { &DXVA2_ModeH264_E, AV_CODEC_ID_H264 }, |
||
75 | /* Intel specific H.264 mode */ |
||
76 | { &DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264 }, |
||
77 | |||
78 | /* VC-1 / WMV3 */ |
||
79 | { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_VC1 }, |
||
80 | { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_WMV3 }, |
||
81 | { &DXVA2_ModeVC1_D, AV_CODEC_ID_VC1 }, |
||
82 | { &DXVA2_ModeVC1_D, AV_CODEC_ID_WMV3 }, |
||
83 | |||
84 | /* HEVC/H.265 */ |
||
85 | { &DXVA2_ModeHEVC_VLD_Main, AV_CODEC_ID_HEVC }, |
||
86 | |||
87 | { NULL, 0 }, |
||
88 | }; |
||
89 | |||
90 | typedef struct surface_info { |
||
91 | int used; |
||
92 | uint64_t age; |
||
93 | } surface_info; |
||
94 | |||
95 | typedef struct DXVA2Context { |
||
96 | HMODULE d3dlib; |
||
97 | HMODULE dxva2lib; |
||
98 | |||
99 | HANDLE deviceHandle; |
||
100 | |||
101 | IDirect3D9 *d3d9; |
||
102 | IDirect3DDevice9 *d3d9device; |
||
103 | IDirect3DDeviceManager9 *d3d9devmgr; |
||
104 | IDirectXVideoDecoderService *decoder_service; |
||
105 | IDirectXVideoDecoder *decoder; |
||
106 | |||
107 | GUID decoder_guid; |
||
108 | DXVA2_ConfigPictureDecode decoder_config; |
||
109 | |||
110 | LPDIRECT3DSURFACE9 *surfaces; |
||
111 | surface_info *surface_infos; |
||
112 | uint32_t num_surfaces; |
||
113 | uint64_t surface_age; |
||
114 | |||
115 | AVFrame *tmp_frame; |
||
116 | } DXVA2Context; |
||
117 | |||
118 | typedef struct DXVA2SurfaceWrapper { |
||
119 | DXVA2Context *ctx; |
||
120 | LPDIRECT3DSURFACE9 surface; |
||
121 | IDirectXVideoDecoder *decoder; |
||
122 | } DXVA2SurfaceWrapper; |
||
123 | |||
124 | static void dxva2_destroy_decoder(AVCodecContext *s) |
||
125 | { |
||
126 | InputStream *ist = s->opaque; |
||
127 | DXVA2Context *ctx = ist->hwaccel_ctx; |
||
128 | int i; |
||
129 | |||
130 | if (ctx->surfaces) { |
||
131 | for (i = 0; i < ctx->num_surfaces; i++) { |
||
132 | if (ctx->surfaces[i]) |
||
133 | IDirect3DSurface9_Release(ctx->surfaces[i]); |
||
134 | } |
||
135 | } |
||
136 | av_freep(&ctx->surfaces); |
||
137 | av_freep(&ctx->surface_infos); |
||
138 | ctx->num_surfaces = 0; |
||
139 | ctx->surface_age = 0; |
||
140 | |||
141 | if (ctx->decoder) { |
||
142 | IDirectXVideoDecoder_Release(ctx->decoder); |
||
143 | ctx->decoder = NULL; |
||
144 | } |
||
145 | } |
||
146 | |||
147 | static void dxva2_uninit(AVCodecContext *s) |
||
148 | { |
||
149 | InputStream *ist = s->opaque; |
||
150 | DXVA2Context *ctx = ist->hwaccel_ctx; |
||
151 | |||
152 | ist->hwaccel_uninit = NULL; |
||
153 | ist->hwaccel_get_buffer = NULL; |
||
154 | ist->hwaccel_retrieve_data = NULL; |
||
155 | |||
156 | if (ctx->decoder) |
||
157 | dxva2_destroy_decoder(s); |
||
158 | |||
159 | if (ctx->decoder_service) |
||
160 | IDirectXVideoDecoderService_Release(ctx->decoder_service); |
||
161 | |||
162 | if (ctx->d3d9devmgr && ctx->deviceHandle != INVALID_HANDLE_VALUE) |
||
163 | IDirect3DDeviceManager9_CloseDeviceHandle(ctx->d3d9devmgr, ctx->deviceHandle); |
||
164 | |||
165 | if (ctx->d3d9devmgr) |
||
166 | IDirect3DDeviceManager9_Release(ctx->d3d9devmgr); |
||
167 | |||
168 | if (ctx->d3d9device) |
||
169 | IDirect3DDevice9_Release(ctx->d3d9device); |
||
170 | |||
171 | if (ctx->d3d9) |
||
172 | IDirect3D9_Release(ctx->d3d9); |
||
173 | |||
174 | if (ctx->d3dlib) |
||
175 | FreeLibrary(ctx->d3dlib); |
||
176 | |||
177 | if (ctx->dxva2lib) |
||
178 | FreeLibrary(ctx->dxva2lib); |
||
179 | |||
180 | av_frame_free(&ctx->tmp_frame); |
||
181 | |||
182 | av_freep(&ist->hwaccel_ctx); |
||
183 | av_freep(&s->hwaccel_context); |
||
184 | } |
||
185 | |||
186 | static void dxva2_release_buffer(void *opaque, uint8_t *data) |
||
187 | { |
||
188 | DXVA2SurfaceWrapper *w = opaque; |
||
189 | DXVA2Context *ctx = w->ctx; |
||
190 | int i; |
||
191 | |||
192 | for (i = 0; i < ctx->num_surfaces; i++) { |
||
193 | if (ctx->surfaces[i] == w->surface) { |
||
194 | ctx->surface_infos[i].used = 0; |
||
195 | break; |
||
196 | } |
||
197 | } |
||
198 | IDirect3DSurface9_Release(w->surface); |
||
199 | IDirectXVideoDecoder_Release(w->decoder); |
||
200 | av_free(w); |
||
201 | } |
||
202 | |||
203 | static int dxva2_get_buffer(AVCodecContext *s, AVFrame *frame, int flags) |
||
204 | { |
||
205 | InputStream *ist = s->opaque; |
||
206 | DXVA2Context *ctx = ist->hwaccel_ctx; |
||
207 | int i, old_unused = -1; |
||
208 | LPDIRECT3DSURFACE9 surface; |
||
209 | DXVA2SurfaceWrapper *w = NULL; |
||
210 | |||
211 | av_assert0(frame->format == AV_PIX_FMT_DXVA2_VLD); |
||
212 | |||
213 | for (i = 0; i < ctx->num_surfaces; i++) { |
||
214 | surface_info *info = &ctx->surface_infos[i]; |
||
215 | if (!info->used && (old_unused == -1 || info->age < ctx->surface_infos[old_unused].age)) |
||
216 | old_unused = i; |
||
217 | } |
||
218 | if (old_unused == -1) { |
||
219 | av_log(NULL, AV_LOG_ERROR, "No free DXVA2 surface!\n"); |
||
220 | return AVERROR(ENOMEM); |
||
221 | } |
||
222 | i = old_unused; |
||
223 | |||
224 | surface = ctx->surfaces[i]; |
||
225 | |||
226 | w = av_mallocz(sizeof(*w)); |
||
227 | if (!w) |
||
228 | return AVERROR(ENOMEM); |
||
229 | |||
230 | frame->buf[0] = av_buffer_create((uint8_t*)surface, 0, |
||
231 | dxva2_release_buffer, w, |
||
232 | AV_BUFFER_FLAG_READONLY); |
||
233 | if (!frame->buf[0]) { |
||
234 | av_free(w); |
||
235 | return AVERROR(ENOMEM); |
||
236 | } |
||
237 | |||
238 | w->ctx = ctx; |
||
239 | w->surface = surface; |
||
240 | IDirect3DSurface9_AddRef(w->surface); |
||
241 | w->decoder = ctx->decoder; |
||
242 | IDirectXVideoDecoder_AddRef(w->decoder); |
||
243 | |||
244 | ctx->surface_infos[i].used = 1; |
||
245 | ctx->surface_infos[i].age = ctx->surface_age++; |
||
246 | |||
247 | frame->data[3] = (uint8_t *)surface; |
||
248 | |||
249 | return 0; |
||
250 | } |
||
251 | |||
252 | static int dxva2_retrieve_data(AVCodecContext *s, AVFrame *frame) |
||
253 | { |
||
254 | LPDIRECT3DSURFACE9 surface = (LPDIRECT3DSURFACE9)frame->data[3]; |
||
255 | InputStream *ist = s->opaque; |
||
256 | DXVA2Context *ctx = ist->hwaccel_ctx; |
||
257 | D3DSURFACE_DESC surfaceDesc; |
||
258 | D3DLOCKED_RECT LockedRect; |
||
259 | HRESULT hr; |
||
260 | int ret; |
||
261 | |||
262 | IDirect3DSurface9_GetDesc(surface, &surfaceDesc); |
||
263 | |||
264 | ctx->tmp_frame->width = frame->width; |
||
265 | ctx->tmp_frame->height = frame->height; |
||
266 | ctx->tmp_frame->format = AV_PIX_FMT_NV12; |
||
267 | |||
268 | ret = av_frame_get_buffer(ctx->tmp_frame, 32); |
||
269 | if (ret < 0) |
||
270 | return ret; |
||
271 | |||
272 | hr = IDirect3DSurface9_LockRect(surface, &LockedRect, NULL, D3DLOCK_READONLY); |
||
273 | if (FAILED(hr)) { |
||
274 | av_log(NULL, AV_LOG_ERROR, "Unable to lock DXVA2 surface\n"); |
||
275 | return AVERROR_UNKNOWN; |
||
276 | } |
||
277 | |||
278 | av_image_copy_plane(ctx->tmp_frame->data[0], ctx->tmp_frame->linesize[0], |
||
279 | (uint8_t*)LockedRect.pBits, |
||
280 | LockedRect.Pitch, frame->width, frame->height); |
||
281 | |||
282 | av_image_copy_plane(ctx->tmp_frame->data[1], ctx->tmp_frame->linesize[1], |
||
283 | (uint8_t*)LockedRect.pBits + LockedRect.Pitch * surfaceDesc.Height, |
||
284 | LockedRect.Pitch, frame->width, frame->height / 2); |
||
285 | |||
286 | IDirect3DSurface9_UnlockRect(surface); |
||
287 | |||
288 | ret = av_frame_copy_props(ctx->tmp_frame, frame); |
||
289 | if (ret < 0) |
||
290 | goto fail; |
||
291 | |||
292 | av_frame_unref(frame); |
||
293 | av_frame_move_ref(frame, ctx->tmp_frame); |
||
294 | |||
295 | return 0; |
||
296 | fail: |
||
297 | av_frame_unref(ctx->tmp_frame); |
||
298 | return ret; |
||
299 | } |
||
300 | |||
301 | static int dxva2_alloc(AVCodecContext *s) |
||
302 | { |
||
303 | InputStream *ist = s->opaque; |
||
304 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; |
||
305 | DXVA2Context *ctx; |
||
306 | pDirect3DCreate9 *createD3D = NULL; |
||
307 | pCreateDeviceManager9 *createDeviceManager = NULL; |
||
308 | HRESULT hr; |
||
309 | D3DPRESENT_PARAMETERS d3dpp = {0}; |
||
310 | D3DDISPLAYMODE d3ddm; |
||
311 | unsigned resetToken = 0; |
||
312 | UINT adapter = D3DADAPTER_DEFAULT; |
||
313 | |||
314 | ctx = av_mallocz(sizeof(*ctx)); |
||
315 | if (!ctx) |
||
316 | return AVERROR(ENOMEM); |
||
317 | |||
318 | ctx->deviceHandle = INVALID_HANDLE_VALUE; |
||
319 | |||
320 | ist->hwaccel_ctx = ctx; |
||
321 | ist->hwaccel_uninit = dxva2_uninit; |
||
322 | ist->hwaccel_get_buffer = dxva2_get_buffer; |
||
323 | ist->hwaccel_retrieve_data = dxva2_retrieve_data; |
||
324 | |||
325 | ctx->d3dlib = LoadLibrary("d3d9.dll"); |
||
326 | if (!ctx->d3dlib) { |
||
327 | av_log(NULL, loglevel, "Failed to load D3D9 library\n"); |
||
328 | goto fail; |
||
329 | } |
||
330 | ctx->dxva2lib = LoadLibrary("dxva2.dll"); |
||
331 | if (!ctx->dxva2lib) { |
||
332 | av_log(NULL, loglevel, "Failed to load DXVA2 library\n"); |
||
333 | goto fail; |
||
334 | } |
||
335 | |||
336 | createD3D = (pDirect3DCreate9 *)GetProcAddress(ctx->d3dlib, "Direct3DCreate9"); |
||
337 | if (!createD3D) { |
||
338 | av_log(NULL, loglevel, "Failed to locate Direct3DCreate9\n"); |
||
339 | goto fail; |
||
340 | } |
||
341 | createDeviceManager = (pCreateDeviceManager9 *)GetProcAddress(ctx->dxva2lib, "DXVA2CreateDirect3DDeviceManager9"); |
||
342 | if (!createDeviceManager) { |
||
343 | av_log(NULL, loglevel, "Failed to locate DXVA2CreateDirect3DDeviceManager9\n"); |
||
344 | goto fail; |
||
345 | } |
||
346 | |||
347 | ctx->d3d9 = createD3D(D3D_SDK_VERSION); |
||
348 | if (!ctx->d3d9) { |
||
349 | av_log(NULL, loglevel, "Failed to create IDirect3D object\n"); |
||
350 | goto fail; |
||
351 | } |
||
352 | |||
353 | if (ist->hwaccel_device) { |
||
354 | adapter = atoi(ist->hwaccel_device); |
||
355 | av_log(NULL, AV_LOG_INFO, "Using HWAccel device %d\n", adapter); |
||
356 | } |
||
357 | |||
358 | IDirect3D9_GetAdapterDisplayMode(ctx->d3d9, adapter, &d3ddm); |
||
359 | d3dpp.Windowed = TRUE; |
||
360 | d3dpp.BackBufferWidth = 640; |
||
361 | d3dpp.BackBufferHeight = 480; |
||
362 | d3dpp.BackBufferCount = 0; |
||
363 | d3dpp.BackBufferFormat = d3ddm.Format; |
||
364 | d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; |
||
365 | d3dpp.Flags = D3DPRESENTFLAG_VIDEO; |
||
366 | |||
367 | hr = IDirect3D9_CreateDevice(ctx->d3d9, adapter, D3DDEVTYPE_HAL, GetDesktopWindow(), |
||
368 | D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, |
||
369 | &d3dpp, &ctx->d3d9device); |
||
370 | if (FAILED(hr)) { |
||
371 | av_log(NULL, loglevel, "Failed to create Direct3D device\n"); |
||
372 | goto fail; |
||
373 | } |
||
374 | |||
375 | hr = createDeviceManager(&resetToken, &ctx->d3d9devmgr); |
||
376 | if (FAILED(hr)) { |
||
377 | av_log(NULL, loglevel, "Failed to create Direct3D device manager\n"); |
||
378 | goto fail; |
||
379 | } |
||
380 | |||
381 | hr = IDirect3DDeviceManager9_ResetDevice(ctx->d3d9devmgr, ctx->d3d9device, resetToken); |
||
382 | if (FAILED(hr)) { |
||
383 | av_log(NULL, loglevel, "Failed to bind Direct3D device to device manager\n"); |
||
384 | goto fail; |
||
385 | } |
||
386 | |||
387 | hr = IDirect3DDeviceManager9_OpenDeviceHandle(ctx->d3d9devmgr, &ctx->deviceHandle); |
||
388 | if (FAILED(hr)) { |
||
389 | av_log(NULL, loglevel, "Failed to open device handle\n"); |
||
390 | goto fail; |
||
391 | } |
||
392 | |||
393 | hr = IDirect3DDeviceManager9_GetVideoService(ctx->d3d9devmgr, ctx->deviceHandle, &IID_IDirectXVideoDecoderService, (void **)&ctx->decoder_service); |
||
394 | if (FAILED(hr)) { |
||
395 | av_log(NULL, loglevel, "Failed to create IDirectXVideoDecoderService\n"); |
||
396 | goto fail; |
||
397 | } |
||
398 | |||
399 | ctx->tmp_frame = av_frame_alloc(); |
||
400 | if (!ctx->tmp_frame) |
||
401 | goto fail; |
||
402 | |||
403 | s->hwaccel_context = av_mallocz(sizeof(struct dxva_context)); |
||
404 | if (!s->hwaccel_context) |
||
405 | goto fail; |
||
406 | |||
407 | return 0; |
||
408 | fail: |
||
409 | dxva2_uninit(s); |
||
410 | return AVERROR(EINVAL); |
||
411 | } |
||
412 | |||
413 | static int dxva2_get_decoder_configuration(AVCodecContext *s, const GUID *device_guid, |
||
414 | const DXVA2_VideoDesc *desc, |
||
415 | DXVA2_ConfigPictureDecode *config) |
||
416 | { |
||
417 | InputStream *ist = s->opaque; |
||
418 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; |
||
419 | DXVA2Context *ctx = ist->hwaccel_ctx; |
||
420 | unsigned cfg_count = 0, best_score = 0; |
||
421 | DXVA2_ConfigPictureDecode *cfg_list = NULL; |
||
422 | DXVA2_ConfigPictureDecode best_cfg = {{0}}; |
||
423 | HRESULT hr; |
||
424 | int i; |
||
425 | |||
426 | hr = IDirectXVideoDecoderService_GetDecoderConfigurations(ctx->decoder_service, device_guid, desc, NULL, &cfg_count, &cfg_list); |
||
427 | if (FAILED(hr)) { |
||
428 | av_log(NULL, loglevel, "Unable to retrieve decoder configurations\n"); |
||
429 | return AVERROR(EINVAL); |
||
430 | } |
||
431 | |||
432 | for (i = 0; i < cfg_count; i++) { |
||
433 | DXVA2_ConfigPictureDecode *cfg = &cfg_list[i]; |
||
434 | |||
435 | unsigned score; |
||
436 | if (cfg->ConfigBitstreamRaw == 1) |
||
437 | score = 1; |
||
438 | else if (s->codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2) |
||
439 | score = 2; |
||
440 | else |
||
441 | continue; |
||
442 | if (IsEqualGUID(&cfg->guidConfigBitstreamEncryption, &DXVA2_NoEncrypt)) |
||
443 | score += 16; |
||
444 | if (score > best_score) { |
||
445 | best_score = score; |
||
446 | best_cfg = *cfg; |
||
447 | } |
||
448 | } |
||
449 | CoTaskMemFree(cfg_list); |
||
450 | |||
451 | if (!best_score) { |
||
452 | av_log(NULL, loglevel, "No valid decoder configuration available\n"); |
||
453 | return AVERROR(EINVAL); |
||
454 | } |
||
455 | |||
456 | *config = best_cfg; |
||
457 | return 0; |
||
458 | } |
||
459 | |||
460 | static int dxva2_create_decoder(AVCodecContext *s) |
||
461 | { |
||
462 | InputStream *ist = s->opaque; |
||
463 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; |
||
464 | DXVA2Context *ctx = ist->hwaccel_ctx; |
||
465 | struct dxva_context *dxva_ctx = s->hwaccel_context; |
||
466 | GUID *guid_list = NULL; |
||
467 | unsigned guid_count = 0, i, j; |
||
468 | GUID device_guid = GUID_NULL; |
||
469 | D3DFORMAT target_format = 0; |
||
470 | DXVA2_VideoDesc desc = { 0 }; |
||
471 | DXVA2_ConfigPictureDecode config; |
||
472 | HRESULT hr; |
||
473 | int surface_alignment; |
||
474 | int ret; |
||
475 | |||
476 | hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list); |
||
477 | if (FAILED(hr)) { |
||
478 | av_log(NULL, loglevel, "Failed to retrieve decoder device GUIDs\n"); |
||
479 | goto fail; |
||
480 | } |
||
481 | |||
482 | for (i = 0; dxva2_modes[i].guid; i++) { |
||
483 | D3DFORMAT *target_list = NULL; |
||
484 | unsigned target_count = 0; |
||
485 | const dxva2_mode *mode = &dxva2_modes[i]; |
||
486 | if (mode->codec != s->codec_id) |
||
487 | continue; |
||
488 | |||
489 | for (j = 0; j < guid_count; j++) { |
||
490 | if (IsEqualGUID(mode->guid, &guid_list[j])) |
||
491 | break; |
||
492 | } |
||
493 | if (j == guid_count) |
||
494 | continue; |
||
495 | |||
496 | hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, mode->guid, &target_count, &target_list); |
||
497 | if (FAILED(hr)) { |
||
498 | continue; |
||
499 | } |
||
500 | for (j = 0; j < target_count; j++) { |
||
501 | const D3DFORMAT format = target_list[j]; |
||
502 | if (format == MKTAG('N','V','1','2')) { |
||
503 | target_format = format; |
||
504 | break; |
||
505 | } |
||
506 | } |
||
507 | CoTaskMemFree(target_list); |
||
508 | if (target_format) { |
||
509 | device_guid = *mode->guid; |
||
510 | break; |
||
511 | } |
||
512 | } |
||
513 | CoTaskMemFree(guid_list); |
||
514 | |||
515 | if (IsEqualGUID(&device_guid, &GUID_NULL)) { |
||
516 | av_log(NULL, loglevel, "No decoder device for codec found\n"); |
||
517 | goto fail; |
||
518 | } |
||
519 | |||
520 | desc.SampleWidth = s->coded_width; |
||
521 | desc.SampleHeight = s->coded_height; |
||
522 | desc.Format = target_format; |
||
523 | |||
524 | ret = dxva2_get_decoder_configuration(s, &device_guid, &desc, &config); |
||
525 | if (ret < 0) { |
||
526 | goto fail; |
||
527 | } |
||
528 | |||
529 | /* decoding MPEG-2 requires additional alignment on some Intel GPUs, |
||
530 | but it causes issues for H.264 on certain AMD GPUs..... */ |
||
531 | if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) |
||
532 | surface_alignment = 32; |
||
533 | /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure |
||
534 | all coding features have enough room to work with */ |
||
535 | else if (s->codec_id == AV_CODEC_ID_HEVC) |
||
536 | surface_alignment = 128; |
||
537 | else |
||
538 | surface_alignment = 16; |
||
539 | |||
540 | /* 4 base work surfaces */ |
||
541 | ctx->num_surfaces = 4; |
||
542 | |||
543 | /* add surfaces based on number of possible refs */ |
||
544 | if (s->codec_id == AV_CODEC_ID_H264 || s->codec_id == AV_CODEC_ID_HEVC) |
||
545 | ctx->num_surfaces += 16; |
||
546 | else |
||
547 | ctx->num_surfaces += 2; |
||
548 | |||
549 | /* add extra surfaces for frame threading */ |
||
550 | if (s->active_thread_type & FF_THREAD_FRAME) |
||
551 | ctx->num_surfaces += s->thread_count; |
||
552 | |||
553 | ctx->surfaces = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surfaces)); |
||
554 | ctx->surface_infos = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surface_infos)); |
||
555 | |||
556 | if (!ctx->surfaces || !ctx->surface_infos) { |
||
557 | av_log(NULL, loglevel, "Unable to allocate surface arrays\n"); |
||
558 | goto fail; |
||
559 | } |
||
560 | |||
561 | hr = IDirectXVideoDecoderService_CreateSurface(ctx->decoder_service, |
||
562 | FFALIGN(s->coded_width, surface_alignment), |
||
563 | FFALIGN(s->coded_height, surface_alignment), |
||
564 | ctx->num_surfaces - 1, |
||
565 | target_format, D3DPOOL_DEFAULT, 0, |
||
566 | DXVA2_VideoDecoderRenderTarget, |
||
567 | ctx->surfaces, NULL); |
||
568 | if (FAILED(hr)) { |
||
569 | av_log(NULL, loglevel, "Failed to create %d video surfaces\n", ctx->num_surfaces); |
||
570 | goto fail; |
||
571 | } |
||
572 | |||
573 | hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid, |
||
574 | &desc, &config, ctx->surfaces, |
||
575 | ctx->num_surfaces, &ctx->decoder); |
||
576 | if (FAILED(hr)) { |
||
577 | av_log(NULL, loglevel, "Failed to create DXVA2 video decoder\n"); |
||
578 | goto fail; |
||
579 | } |
||
580 | |||
581 | ctx->decoder_guid = device_guid; |
||
582 | ctx->decoder_config = config; |
||
583 | |||
584 | dxva_ctx->cfg = &ctx->decoder_config; |
||
585 | dxva_ctx->decoder = ctx->decoder; |
||
586 | dxva_ctx->surface = ctx->surfaces; |
||
587 | dxva_ctx->surface_count = ctx->num_surfaces; |
||
588 | |||
589 | if (IsEqualGUID(&ctx->decoder_guid, &DXVADDI_Intel_ModeH264_E)) |
||
590 | dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO; |
||
591 | |||
592 | return 0; |
||
593 | fail: |
||
594 | dxva2_destroy_decoder(s); |
||
595 | return AVERROR(EINVAL); |
||
596 | } |
||
597 | |||
598 | int dxva2_init(AVCodecContext *s) |
||
599 | { |
||
600 | InputStream *ist = s->opaque; |
||
601 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; |
||
602 | DXVA2Context *ctx; |
||
603 | int ret; |
||
604 | |||
605 | if (!ist->hwaccel_ctx) { |
||
606 | ret = dxva2_alloc(s); |
||
607 | if (ret < 0) |
||
608 | return ret; |
||
609 | } |
||
610 | ctx = ist->hwaccel_ctx; |
||
611 | |||
612 | if (s->codec_id == AV_CODEC_ID_H264 && |
||
613 | (s->profile & ~FF_PROFILE_H264_CONSTRAINED) > FF_PROFILE_H264_HIGH) { |
||
614 | av_log(NULL, loglevel, "Unsupported H.264 profile for DXVA2 HWAccel: %d\n", s->profile); |
||
615 | return AVERROR(EINVAL); |
||
616 | } |
||
617 | |||
618 | if (ctx->decoder) |
||
619 | dxva2_destroy_decoder(s); |
||
620 | |||
621 | ret = dxva2_create_decoder(s); |
||
622 | if (ret < 0) { |
||
623 | av_log(NULL, loglevel, "Error creating the DXVA2 decoder\n"); |
||
624 | return ret; |
||
625 | } |
||
626 | |||
627 | return 0; |
||
628 | }>>>>>>>>>>>> |