blob: 1a391f82f3ef019989848308f3a42b153e46d4c2
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 | #include "libavutil/hwcontext.h" |
44 | #include "libavutil/hwcontext_dxva2.h" |
45 | |
46 | /* define all the GUIDs used directly here, |
47 | to avoid problems with inconsistent dxva2api.h versions in mingw-w64 and different MSVC version */ |
48 | #include <initguid.h> |
49 | DEFINE_GUID(IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02); |
50 | |
51 | DEFINE_GUID(DXVA2_ModeMPEG2_VLD, 0xee27417f, 0x5e28,0x4e65,0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9); |
52 | DEFINE_GUID(DXVA2_ModeMPEG2and1_VLD, 0x86695f12, 0x340e,0x4f04,0x9f,0xd3,0x92,0x53,0xdd,0x32,0x74,0x60); |
53 | DEFINE_GUID(DXVA2_ModeH264_E, 0x1b81be68, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); |
54 | DEFINE_GUID(DXVA2_ModeH264_F, 0x1b81be69, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); |
55 | DEFINE_GUID(DXVADDI_Intel_ModeH264_E, 0x604F8E68, 0x4951,0x4C54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6); |
56 | DEFINE_GUID(DXVA2_ModeVC1_D, 0x1b81beA3, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); |
57 | DEFINE_GUID(DXVA2_ModeVC1_D2010, 0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); |
58 | DEFINE_GUID(DXVA2_ModeHEVC_VLD_Main, 0x5b11d51b, 0x2f4c,0x4452,0xbc,0xc3,0x09,0xf2,0xa1,0x16,0x0c,0xc0); |
59 | DEFINE_GUID(DXVA2_ModeHEVC_VLD_Main10,0x107af0e0, 0xef1a,0x4d19,0xab,0xa8,0x67,0xa1,0x63,0x07,0x3d,0x13); |
60 | DEFINE_GUID(DXVA2_ModeVP9_VLD_Profile0, 0x463707f8, 0xa1d0,0x4585,0x87,0x6d,0x83,0xaa,0x6d,0x60,0xb8,0x9e); |
61 | DEFINE_GUID(DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); |
62 | DEFINE_GUID(GUID_NULL, 0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00); |
63 | |
64 | typedef struct dxva2_mode { |
65 | const GUID *guid; |
66 | enum AVCodecID codec; |
67 | } dxva2_mode; |
68 | |
69 | static const dxva2_mode dxva2_modes[] = { |
70 | /* MPEG-2 */ |
71 | { &DXVA2_ModeMPEG2_VLD, AV_CODEC_ID_MPEG2VIDEO }, |
72 | { &DXVA2_ModeMPEG2and1_VLD, AV_CODEC_ID_MPEG2VIDEO }, |
73 | |
74 | /* H.264 */ |
75 | { &DXVA2_ModeH264_F, AV_CODEC_ID_H264 }, |
76 | { &DXVA2_ModeH264_E, AV_CODEC_ID_H264 }, |
77 | /* Intel specific H.264 mode */ |
78 | { &DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264 }, |
79 | |
80 | /* VC-1 / WMV3 */ |
81 | { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_VC1 }, |
82 | { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_WMV3 }, |
83 | { &DXVA2_ModeVC1_D, AV_CODEC_ID_VC1 }, |
84 | { &DXVA2_ModeVC1_D, AV_CODEC_ID_WMV3 }, |
85 | |
86 | /* HEVC/H.265 */ |
87 | { &DXVA2_ModeHEVC_VLD_Main, AV_CODEC_ID_HEVC }, |
88 | { &DXVA2_ModeHEVC_VLD_Main10,AV_CODEC_ID_HEVC }, |
89 | |
90 | /* VP8/9 */ |
91 | { &DXVA2_ModeVP9_VLD_Profile0, AV_CODEC_ID_VP9 }, |
92 | |
93 | { NULL, 0 }, |
94 | }; |
95 | |
96 | typedef struct DXVA2Context { |
97 | IDirectXVideoDecoder *decoder; |
98 | |
99 | GUID decoder_guid; |
100 | DXVA2_ConfigPictureDecode decoder_config; |
101 | IDirectXVideoDecoderService *decoder_service; |
102 | |
103 | AVFrame *tmp_frame; |
104 | |
105 | AVBufferRef *hw_device_ctx; |
106 | AVBufferRef *hw_frames_ctx; |
107 | } DXVA2Context; |
108 | |
109 | static void dxva2_uninit(AVCodecContext *s) |
110 | { |
111 | InputStream *ist = s->opaque; |
112 | DXVA2Context *ctx = ist->hwaccel_ctx; |
113 | |
114 | ist->hwaccel_uninit = NULL; |
115 | ist->hwaccel_get_buffer = NULL; |
116 | ist->hwaccel_retrieve_data = NULL; |
117 | |
118 | if (ctx->decoder_service) |
119 | IDirectXVideoDecoderService_Release(ctx->decoder_service); |
120 | |
121 | av_buffer_unref(&ctx->hw_frames_ctx); |
122 | av_buffer_unref(&ctx->hw_device_ctx); |
123 | |
124 | av_frame_free(&ctx->tmp_frame); |
125 | |
126 | av_freep(&ist->hwaccel_ctx); |
127 | av_freep(&s->hwaccel_context); |
128 | } |
129 | |
130 | static int dxva2_get_buffer(AVCodecContext *s, AVFrame *frame, int flags) |
131 | { |
132 | InputStream *ist = s->opaque; |
133 | DXVA2Context *ctx = ist->hwaccel_ctx; |
134 | |
135 | return av_hwframe_get_buffer(ctx->hw_frames_ctx, frame, 0); |
136 | } |
137 | |
138 | static int dxva2_retrieve_data(AVCodecContext *s, AVFrame *frame) |
139 | { |
140 | InputStream *ist = s->opaque; |
141 | DXVA2Context *ctx = ist->hwaccel_ctx; |
142 | int ret; |
143 | |
144 | ret = av_hwframe_transfer_data(ctx->tmp_frame, frame, 0); |
145 | if (ret < 0) |
146 | return ret; |
147 | |
148 | ret = av_frame_copy_props(ctx->tmp_frame, frame); |
149 | if (ret < 0) { |
150 | av_frame_unref(ctx->tmp_frame); |
151 | return ret; |
152 | } |
153 | |
154 | av_frame_unref(frame); |
155 | av_frame_move_ref(frame, ctx->tmp_frame); |
156 | |
157 | return 0; |
158 | } |
159 | |
160 | static int dxva2_alloc(AVCodecContext *s) |
161 | { |
162 | InputStream *ist = s->opaque; |
163 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; |
164 | DXVA2Context *ctx; |
165 | HANDLE device_handle; |
166 | HRESULT hr; |
167 | |
168 | AVHWDeviceContext *device_ctx; |
169 | AVDXVA2DeviceContext *device_hwctx; |
170 | int ret; |
171 | |
172 | ctx = av_mallocz(sizeof(*ctx)); |
173 | if (!ctx) |
174 | return AVERROR(ENOMEM); |
175 | |
176 | ist->hwaccel_ctx = ctx; |
177 | ist->hwaccel_uninit = dxva2_uninit; |
178 | ist->hwaccel_get_buffer = dxva2_get_buffer; |
179 | ist->hwaccel_retrieve_data = dxva2_retrieve_data; |
180 | |
181 | ret = av_hwdevice_ctx_create(&ctx->hw_device_ctx, AV_HWDEVICE_TYPE_DXVA2, |
182 | ist->hwaccel_device, NULL, 0); |
183 | if (ret < 0) |
184 | goto fail; |
185 | device_ctx = (AVHWDeviceContext*)ctx->hw_device_ctx->data; |
186 | device_hwctx = device_ctx->hwctx; |
187 | |
188 | hr = IDirect3DDeviceManager9_OpenDeviceHandle(device_hwctx->devmgr, |
189 | &device_handle); |
190 | if (FAILED(hr)) { |
191 | av_log(NULL, loglevel, "Failed to open a device handle\n"); |
192 | goto fail; |
193 | } |
194 | |
195 | hr = IDirect3DDeviceManager9_GetVideoService(device_hwctx->devmgr, device_handle, |
196 | &IID_IDirectXVideoDecoderService, |
197 | (void **)&ctx->decoder_service); |
198 | IDirect3DDeviceManager9_CloseDeviceHandle(device_hwctx->devmgr, device_handle); |
199 | if (FAILED(hr)) { |
200 | av_log(NULL, loglevel, "Failed to create IDirectXVideoDecoderService\n"); |
201 | goto fail; |
202 | } |
203 | |
204 | ctx->tmp_frame = av_frame_alloc(); |
205 | if (!ctx->tmp_frame) |
206 | goto fail; |
207 | |
208 | s->hwaccel_context = av_mallocz(sizeof(struct dxva_context)); |
209 | if (!s->hwaccel_context) |
210 | goto fail; |
211 | |
212 | return 0; |
213 | fail: |
214 | dxva2_uninit(s); |
215 | return AVERROR(EINVAL); |
216 | } |
217 | |
218 | static int dxva2_get_decoder_configuration(AVCodecContext *s, const GUID *device_guid, |
219 | const DXVA2_VideoDesc *desc, |
220 | DXVA2_ConfigPictureDecode *config) |
221 | { |
222 | InputStream *ist = s->opaque; |
223 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; |
224 | DXVA2Context *ctx = ist->hwaccel_ctx; |
225 | unsigned cfg_count = 0, best_score = 0; |
226 | DXVA2_ConfigPictureDecode *cfg_list = NULL; |
227 | DXVA2_ConfigPictureDecode best_cfg = {{0}}; |
228 | HRESULT hr; |
229 | int i; |
230 | |
231 | hr = IDirectXVideoDecoderService_GetDecoderConfigurations(ctx->decoder_service, device_guid, desc, NULL, &cfg_count, &cfg_list); |
232 | if (FAILED(hr)) { |
233 | av_log(NULL, loglevel, "Unable to retrieve decoder configurations\n"); |
234 | return AVERROR(EINVAL); |
235 | } |
236 | |
237 | for (i = 0; i < cfg_count; i++) { |
238 | DXVA2_ConfigPictureDecode *cfg = &cfg_list[i]; |
239 | |
240 | unsigned score; |
241 | if (cfg->ConfigBitstreamRaw == 1) |
242 | score = 1; |
243 | else if (s->codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2) |
244 | score = 2; |
245 | else |
246 | continue; |
247 | if (IsEqualGUID(&cfg->guidConfigBitstreamEncryption, &DXVA2_NoEncrypt)) |
248 | score += 16; |
249 | if (score > best_score) { |
250 | best_score = score; |
251 | best_cfg = *cfg; |
252 | } |
253 | } |
254 | CoTaskMemFree(cfg_list); |
255 | |
256 | if (!best_score) { |
257 | av_log(NULL, loglevel, "No valid decoder configuration available\n"); |
258 | return AVERROR(EINVAL); |
259 | } |
260 | |
261 | *config = best_cfg; |
262 | return 0; |
263 | } |
264 | |
265 | static int dxva2_create_decoder(AVCodecContext *s) |
266 | { |
267 | InputStream *ist = s->opaque; |
268 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; |
269 | DXVA2Context *ctx = ist->hwaccel_ctx; |
270 | struct dxva_context *dxva_ctx = s->hwaccel_context; |
271 | GUID *guid_list = NULL; |
272 | unsigned guid_count = 0, i, j; |
273 | GUID device_guid = GUID_NULL; |
274 | const D3DFORMAT surface_format = (s->sw_pix_fmt == AV_PIX_FMT_YUV420P10) ? MKTAG('P','0','1','0') : MKTAG('N','V','1','2'); |
275 | D3DFORMAT target_format = 0; |
276 | DXVA2_VideoDesc desc = { 0 }; |
277 | DXVA2_ConfigPictureDecode config; |
278 | HRESULT hr; |
279 | int surface_alignment, num_surfaces; |
280 | int ret; |
281 | |
282 | AVDXVA2FramesContext *frames_hwctx; |
283 | AVHWFramesContext *frames_ctx; |
284 | |
285 | hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list); |
286 | if (FAILED(hr)) { |
287 | av_log(NULL, loglevel, "Failed to retrieve decoder device GUIDs\n"); |
288 | goto fail; |
289 | } |
290 | |
291 | for (i = 0; dxva2_modes[i].guid; i++) { |
292 | D3DFORMAT *target_list = NULL; |
293 | unsigned target_count = 0; |
294 | const dxva2_mode *mode = &dxva2_modes[i]; |
295 | if (mode->codec != s->codec_id) |
296 | continue; |
297 | |
298 | for (j = 0; j < guid_count; j++) { |
299 | if (IsEqualGUID(mode->guid, &guid_list[j])) |
300 | break; |
301 | } |
302 | if (j == guid_count) |
303 | continue; |
304 | |
305 | hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, mode->guid, &target_count, &target_list); |
306 | if (FAILED(hr)) { |
307 | continue; |
308 | } |
309 | for (j = 0; j < target_count; j++) { |
310 | const D3DFORMAT format = target_list[j]; |
311 | if (format == surface_format) { |
312 | target_format = format; |
313 | break; |
314 | } |
315 | } |
316 | CoTaskMemFree(target_list); |
317 | if (target_format) { |
318 | device_guid = *mode->guid; |
319 | break; |
320 | } |
321 | } |
322 | CoTaskMemFree(guid_list); |
323 | |
324 | if (IsEqualGUID(&device_guid, &GUID_NULL)) { |
325 | av_log(NULL, loglevel, "No decoder device for codec found\n"); |
326 | goto fail; |
327 | } |
328 | |
329 | desc.SampleWidth = s->coded_width; |
330 | desc.SampleHeight = s->coded_height; |
331 | desc.Format = target_format; |
332 | |
333 | ret = dxva2_get_decoder_configuration(s, &device_guid, &desc, &config); |
334 | if (ret < 0) { |
335 | goto fail; |
336 | } |
337 | |
338 | /* decoding MPEG-2 requires additional alignment on some Intel GPUs, |
339 | but it causes issues for H.264 on certain AMD GPUs..... */ |
340 | if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) |
341 | surface_alignment = 32; |
342 | /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure |
343 | all coding features have enough room to work with */ |
344 | else if (s->codec_id == AV_CODEC_ID_HEVC) |
345 | surface_alignment = 128; |
346 | else |
347 | surface_alignment = 16; |
348 | |
349 | /* 4 base work surfaces */ |
350 | num_surfaces = 4; |
351 | |
352 | /* add surfaces based on number of possible refs */ |
353 | if (s->codec_id == AV_CODEC_ID_H264 || s->codec_id == AV_CODEC_ID_HEVC) |
354 | num_surfaces += 16; |
355 | else if (s->codec_id == AV_CODEC_ID_VP9) |
356 | num_surfaces += 8; |
357 | else |
358 | num_surfaces += 2; |
359 | |
360 | /* add extra surfaces for frame threading */ |
361 | if (s->active_thread_type & FF_THREAD_FRAME) |
362 | num_surfaces += s->thread_count; |
363 | |
364 | ctx->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->hw_device_ctx); |
365 | if (!ctx->hw_frames_ctx) |
366 | goto fail; |
367 | frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data; |
368 | frames_hwctx = frames_ctx->hwctx; |
369 | |
370 | frames_ctx->format = AV_PIX_FMT_DXVA2_VLD; |
371 | frames_ctx->sw_format = (target_format == MKTAG('P','0','1','0') ? AV_PIX_FMT_P010 : AV_PIX_FMT_NV12); |
372 | frames_ctx->width = FFALIGN(s->coded_width, surface_alignment); |
373 | frames_ctx->height = FFALIGN(s->coded_height, surface_alignment); |
374 | frames_ctx->initial_pool_size = num_surfaces; |
375 | |
376 | frames_hwctx->surface_type = DXVA2_VideoDecoderRenderTarget; |
377 | |
378 | ret = av_hwframe_ctx_init(ctx->hw_frames_ctx); |
379 | if (ret < 0) { |
380 | av_log(NULL, loglevel, "Failed to initialize the HW frames context\n"); |
381 | goto fail; |
382 | } |
383 | |
384 | hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid, |
385 | &desc, &config, frames_hwctx->surfaces, |
386 | frames_hwctx->nb_surfaces, &frames_hwctx->decoder_to_release); |
387 | if (FAILED(hr)) { |
388 | av_log(NULL, loglevel, "Failed to create DXVA2 video decoder\n"); |
389 | goto fail; |
390 | } |
391 | |
392 | ctx->decoder_guid = device_guid; |
393 | ctx->decoder_config = config; |
394 | |
395 | dxva_ctx->cfg = &ctx->decoder_config; |
396 | dxva_ctx->decoder = frames_hwctx->decoder_to_release; |
397 | dxva_ctx->surface = frames_hwctx->surfaces; |
398 | dxva_ctx->surface_count = frames_hwctx->nb_surfaces; |
399 | |
400 | if (IsEqualGUID(&ctx->decoder_guid, &DXVADDI_Intel_ModeH264_E)) |
401 | dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO; |
402 | |
403 | return 0; |
404 | fail: |
405 | av_buffer_unref(&ctx->hw_frames_ctx); |
406 | return AVERROR(EINVAL); |
407 | } |
408 | |
409 | int dxva2_init(AVCodecContext *s) |
410 | { |
411 | InputStream *ist = s->opaque; |
412 | int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; |
413 | DXVA2Context *ctx; |
414 | int ret; |
415 | |
416 | if (!ist->hwaccel_ctx) { |
417 | ret = dxva2_alloc(s); |
418 | if (ret < 0) |
419 | return ret; |
420 | } |
421 | ctx = ist->hwaccel_ctx; |
422 | |
423 | if (s->codec_id == AV_CODEC_ID_H264 && |
424 | (s->profile & ~FF_PROFILE_H264_CONSTRAINED) > FF_PROFILE_H264_HIGH) { |
425 | av_log(NULL, loglevel, "Unsupported H.264 profile for DXVA2 HWAccel: %d\n", s->profile); |
426 | return AVERROR(EINVAL); |
427 | } |
428 | |
429 | if (s->codec_id == AV_CODEC_ID_HEVC && |
430 | s->profile != FF_PROFILE_HEVC_MAIN && s->profile != FF_PROFILE_HEVC_MAIN_10) { |
431 | av_log(NULL, loglevel, "Unsupported HEVC profile for DXVA2 HWAccel: %d\n", s->profile); |
432 | return AVERROR(EINVAL); |
433 | } |
434 | |
435 | av_buffer_unref(&ctx->hw_frames_ctx); |
436 | |
437 | ret = dxva2_create_decoder(s); |
438 | if (ret < 0) { |
439 | av_log(NULL, loglevel, "Error creating the DXVA2 decoder\n"); |
440 | return ret; |
441 | } |
442 | |
443 | return 0; |
444 | } |
445 |