2 * This file is part of FFmpeg.
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.
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.
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
24 #define _WIN32_WINNT 0x0600
25 #define DXVA2API_USE_BITFIELDS
35 #include "libavcodec/dxva2.h"
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"
43 /* define all the GUIDs used directly here,
44 to avoid problems with inconsistent dxva2api.h versions in mingw-w64 and different MSVC version */
46 DEFINE_GUID(IID_IDirectXVideoDecoderService
, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02);
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);
58 typedef IDirect3D9
* WINAPI
pDirect3DCreate9(UINT
);
59 typedef HRESULT WINAPI
pCreateDeviceManager9(UINT
*, IDirect3DDeviceManager9
**);
61 typedef struct dxva2_mode
{
66 static const dxva2_mode dxva2_modes
[] = {
68 { &DXVA2_ModeMPEG2_VLD
, AV_CODEC_ID_MPEG2VIDEO
},
69 { &DXVA2_ModeMPEG2and1_VLD
, AV_CODEC_ID_MPEG2VIDEO
},
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
},
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
},
86 typedef struct surface_info
{
91 typedef struct DXVA2Context
{
98 IDirect3DDevice9
*d3d9device
;
99 IDirect3DDeviceManager9
*d3d9devmgr
;
100 IDirectXVideoDecoderService
*decoder_service
;
101 IDirectXVideoDecoder
*decoder
;
104 DXVA2_ConfigPictureDecode decoder_config
;
106 LPDIRECT3DSURFACE9
*surfaces
;
107 surface_info
*surface_infos
;
108 uint32_t num_surfaces
;
109 uint64_t surface_age
;
114 typedef struct DXVA2SurfaceWrapper
{
116 LPDIRECT3DSURFACE9 surface
;
117 IDirectXVideoDecoder
*decoder
;
118 } DXVA2SurfaceWrapper
;
120 static void dxva2_destroy_decoder(AVCodecContext
*s
)
122 InputStream
*ist
= s
->opaque
;
123 DXVA2Context
*ctx
= ist
->hwaccel_ctx
;
127 for (i
= 0; i
< ctx
->num_surfaces
; i
++) {
128 if (ctx
->surfaces
[i
])
129 IDirect3DSurface9_Release(ctx
->surfaces
[i
]);
132 av_freep(&ctx
->surfaces
);
133 av_freep(&ctx
->surface_infos
);
134 ctx
->num_surfaces
= 0;
135 ctx
->surface_age
= 0;
138 IDirectXVideoDecoder_Release(ctx
->decoder
);
143 static void dxva2_uninit(AVCodecContext
*s
)
145 InputStream
*ist
= s
->opaque
;
146 DXVA2Context
*ctx
= ist
->hwaccel_ctx
;
148 ist
->hwaccel_uninit
= NULL
;
149 ist
->hwaccel_get_buffer
= NULL
;
150 ist
->hwaccel_retrieve_data
= NULL
;
153 dxva2_destroy_decoder(s
);
155 if (ctx
->decoder_service
)
156 IDirectXVideoDecoderService_Release(ctx
->decoder_service
);
158 if (ctx
->d3d9devmgr
&& ctx
->deviceHandle
!= INVALID_HANDLE_VALUE
)
159 IDirect3DDeviceManager9_CloseDeviceHandle(ctx
->d3d9devmgr
, ctx
->deviceHandle
);
162 IDirect3DDeviceManager9_Release(ctx
->d3d9devmgr
);
165 IDirect3DDevice9_Release(ctx
->d3d9device
);
168 IDirect3D9_Release(ctx
->d3d9
);
171 FreeLibrary(ctx
->d3dlib
);
174 FreeLibrary(ctx
->dxva2lib
);
176 av_frame_free(&ctx
->tmp_frame
);
178 av_freep(&ist
->hwaccel_ctx
);
179 av_freep(&s
->hwaccel_context
);
182 static void dxva2_release_buffer(void *opaque
, uint8_t *data
)
184 DXVA2SurfaceWrapper
*w
= opaque
;
185 DXVA2Context
*ctx
= w
->ctx
;
188 for (i
= 0; i
< ctx
->num_surfaces
; i
++) {
189 if (ctx
->surfaces
[i
] == w
->surface
) {
190 ctx
->surface_infos
[i
].used
= 0;
194 IDirect3DSurface9_Release(w
->surface
);
195 IDirectXVideoDecoder_Release(w
->decoder
);
199 static int dxva2_get_buffer(AVCodecContext
*s
, AVFrame
*frame
, int flags
)
201 InputStream
*ist
= s
->opaque
;
202 DXVA2Context
*ctx
= ist
->hwaccel_ctx
;
203 int i
, old_unused
= -1;
204 LPDIRECT3DSURFACE9 surface
;
205 DXVA2SurfaceWrapper
*w
= NULL
;
207 av_assert0(frame
->format
== AV_PIX_FMT_DXVA2_VLD
);
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
))
214 if (old_unused
== -1) {
215 av_log(NULL
, AV_LOG_ERROR
, "No free DXVA2 surface!\n");
216 return AVERROR(ENOMEM
);
220 surface
= ctx
->surfaces
[i
];
222 w
= av_mallocz(sizeof(*w
));
224 return AVERROR(ENOMEM
);
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]) {
231 return AVERROR(ENOMEM
);
235 w
->surface
= surface
;
236 IDirect3DSurface9_AddRef(w
->surface
);
237 w
->decoder
= ctx
->decoder
;
238 IDirectXVideoDecoder_AddRef(w
->decoder
);
240 ctx
->surface_infos
[i
].used
= 1;
241 ctx
->surface_infos
[i
].age
= ctx
->surface_age
++;
243 frame
->data
[3] = (uint8_t *)surface
;
248 static int dxva2_retrieve_data(AVCodecContext
*s
, AVFrame
*frame
)
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
;
258 IDirect3DSurface9_GetDesc(surface
, &surfaceDesc
);
260 ctx
->tmp_frame
->width
= frame
->width
;
261 ctx
->tmp_frame
->height
= frame
->height
;
262 ctx
->tmp_frame
->format
= AV_PIX_FMT_NV12
;
264 ret
= av_frame_get_buffer(ctx
->tmp_frame
, 32);
268 hr
= IDirect3DSurface9_LockRect(surface
, &LockedRect
, NULL
, D3DLOCK_READONLY
);
270 av_log(NULL
, AV_LOG_ERROR
, "Unable to lock DXVA2 surface\n");
271 return AVERROR_UNKNOWN
;
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
);
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);
282 IDirect3DSurface9_UnlockRect(surface
);
284 ret
= av_frame_copy_props(ctx
->tmp_frame
, frame
);
288 av_frame_unref(frame
);
289 av_frame_move_ref(frame
, ctx
->tmp_frame
);
293 av_frame_unref(ctx
->tmp_frame
);
297 static int dxva2_alloc(AVCodecContext
*s
)
299 InputStream
*ist
= s
->opaque
;
300 int loglevel
= (ist
->hwaccel_id
== HWACCEL_AUTO
) ? AV_LOG_VERBOSE
: AV_LOG_ERROR
;
302 pDirect3DCreate9
*createD3D
= NULL
;
303 pCreateDeviceManager9
*createDeviceManager
= NULL
;
305 D3DPRESENT_PARAMETERS d3dpp
= {0};
306 D3DDISPLAYMODE d3ddm
;
307 unsigned resetToken
= 0;
308 UINT adapter
= D3DADAPTER_DEFAULT
;
310 ctx
= av_mallocz(sizeof(*ctx
));
312 return AVERROR(ENOMEM
);
314 ctx
->deviceHandle
= INVALID_HANDLE_VALUE
;
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
;
321 ctx
->d3dlib
= LoadLibrary("d3d9.dll");
323 av_log(NULL
, loglevel
, "Failed to load D3D9 library\n");
326 ctx
->dxva2lib
= LoadLibrary("dxva2.dll");
327 if (!ctx
->dxva2lib
) {
328 av_log(NULL
, loglevel
, "Failed to load DXVA2 library\n");
332 createD3D
= (pDirect3DCreate9
*)GetProcAddress(ctx
->d3dlib
, "Direct3DCreate9");
334 av_log(NULL
, loglevel
, "Failed to locate Direct3DCreate9\n");
337 createDeviceManager
= (pCreateDeviceManager9
*)GetProcAddress(ctx
->dxva2lib
, "DXVA2CreateDirect3DDeviceManager9");
338 if (!createDeviceManager
) {
339 av_log(NULL
, loglevel
, "Failed to locate DXVA2CreateDirect3DDeviceManager9\n");
343 ctx
->d3d9
= createD3D(D3D_SDK_VERSION
);
345 av_log(NULL
, loglevel
, "Failed to create IDirect3D object\n");
349 if (ist
->hwaccel_device
) {
350 adapter
= atoi(ist
->hwaccel_device
);
351 av_log(NULL
, AV_LOG_INFO
, "Using HWAccel device %d\n", adapter
);
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
;
363 hr
= IDirect3D9_CreateDevice(ctx
->d3d9
, adapter
, D3DDEVTYPE_HAL
, GetShellWindow(),
364 D3DCREATE_SOFTWARE_VERTEXPROCESSING
| D3DCREATE_MULTITHREADED
| D3DCREATE_FPU_PRESERVE
,
365 &d3dpp
, &ctx
->d3d9device
);
367 av_log(NULL
, loglevel
, "Failed to create Direct3D device\n");
371 hr
= createDeviceManager(&resetToken
, &ctx
->d3d9devmgr
);
373 av_log(NULL
, loglevel
, "Failed to create Direct3D device manager\n");
377 hr
= IDirect3DDeviceManager9_ResetDevice(ctx
->d3d9devmgr
, ctx
->d3d9device
, resetToken
);
379 av_log(NULL
, loglevel
, "Failed to bind Direct3D device to device manager\n");
383 hr
= IDirect3DDeviceManager9_OpenDeviceHandle(ctx
->d3d9devmgr
, &ctx
->deviceHandle
);
385 av_log(NULL
, loglevel
, "Failed to open device handle\n");
389 hr
= IDirect3DDeviceManager9_GetVideoService(ctx
->d3d9devmgr
, ctx
->deviceHandle
, &IID_IDirectXVideoDecoderService
, (void **)&ctx
->decoder_service
);
391 av_log(NULL
, loglevel
, "Failed to create IDirectXVideoDecoderService\n");
395 ctx
->tmp_frame
= av_frame_alloc();
399 s
->hwaccel_context
= av_mallocz(sizeof(struct dxva_context
));
400 if (!s
->hwaccel_context
)
406 return AVERROR(EINVAL
);
409 static int dxva2_get_decoder_configuration(AVCodecContext
*s
, const GUID
*device_guid
,
410 const DXVA2_VideoDesc
*desc
,
411 DXVA2_ConfigPictureDecode
*config
)
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}};
422 hr
= IDirectXVideoDecoderService_GetDecoderConfigurations(ctx
->decoder_service
, device_guid
, desc
, NULL
, &cfg_count
, &cfg_list
);
424 av_log(NULL
, loglevel
, "Unable to retrieve decoder configurations\n");
425 return AVERROR(EINVAL
);
428 for (i
= 0; i
< cfg_count
; i
++) {
429 DXVA2_ConfigPictureDecode
*cfg
= &cfg_list
[i
];
432 if (cfg
->ConfigBitstreamRaw
== 1)
434 else if (s
->codec_id
== AV_CODEC_ID_H264
&& cfg
->ConfigBitstreamRaw
== 2)
438 if (IsEqualGUID(&cfg
->guidConfigBitstreamEncryption
, &DXVA2_NoEncrypt
))
440 if (score
> best_score
) {
445 CoTaskMemFree(cfg_list
);
448 av_log(NULL
, loglevel
, "No valid decoder configuration available\n");
449 return AVERROR(EINVAL
);
456 static int dxva2_create_decoder(AVCodecContext
*s
)
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
;
469 int surface_alignment
;
472 hr
= IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx
->decoder_service
, &guid_count
, &guid_list
);
474 av_log(NULL
, loglevel
, "Failed to retrieve decoder device GUIDs\n");
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
)
485 for (j
= 0; j
< guid_count
; j
++) {
486 if (IsEqualGUID(mode
->guid
, &guid_list
[j
]))
492 hr
= IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx
->decoder_service
, mode
->guid
, &target_count
, &target_list
);
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
;
503 CoTaskMemFree(target_list
);
505 device_guid
= *mode
->guid
;
509 CoTaskMemFree(guid_list
);
511 if (IsEqualGUID(&device_guid
, &GUID_NULL
)) {
512 av_log(NULL
, loglevel
, "No decoder device for codec found\n");
516 desc
.SampleWidth
= s
->coded_width
;
517 desc
.SampleHeight
= s
->coded_height
;
518 desc
.Format
= target_format
;
520 ret
= dxva2_get_decoder_configuration(s
, &device_guid
, &desc
, &config
);
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;
530 surface_alignment
= 16;
532 /* 4 base work surfaces */
533 ctx
->num_surfaces
= 4;
535 /* add surfaces based on number of possible refs */
536 if (s
->codec_id
== AV_CODEC_ID_H264
)
537 ctx
->num_surfaces
+= 16;
539 ctx
->num_surfaces
+= 2;
541 /* add extra surfaces for frame threading */
542 if (s
->active_thread_type
& FF_THREAD_FRAME
)
543 ctx
->num_surfaces
+= s
->thread_count
;
545 ctx
->surfaces
= av_mallocz(ctx
->num_surfaces
* sizeof(*ctx
->surfaces
));
546 ctx
->surface_infos
= av_mallocz(ctx
->num_surfaces
* sizeof(*ctx
->surface_infos
));
548 if (!ctx
->surfaces
|| !ctx
->surface_infos
) {
549 av_log(NULL
, loglevel
, "Unable to allocate surface arrays\n");
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
);
561 av_log(NULL
, loglevel
, "Failed to create %d video surfaces\n", ctx
->num_surfaces
);
565 hr
= IDirectXVideoDecoderService_CreateVideoDecoder(ctx
->decoder_service
, &device_guid
,
566 &desc
, &config
, ctx
->surfaces
,
567 ctx
->num_surfaces
, &ctx
->decoder
);
569 av_log(NULL
, loglevel
, "Failed to create DXVA2 video decoder\n");
573 ctx
->decoder_guid
= device_guid
;
574 ctx
->decoder_config
= config
;
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
;
581 if (IsEqualGUID(&ctx
->decoder_guid
, &DXVADDI_Intel_ModeH264_E
))
582 dxva_ctx
->workaround
|= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO
;
586 dxva2_destroy_decoder(s
);
587 return AVERROR(EINVAL
);
590 int dxva2_init(AVCodecContext
*s
)
592 InputStream
*ist
= s
->opaque
;
593 int loglevel
= (ist
->hwaccel_id
== HWACCEL_AUTO
) ? AV_LOG_VERBOSE
: AV_LOG_ERROR
;
597 if (!ist
->hwaccel_ctx
) {
598 ret
= dxva2_alloc(s
);
602 ctx
= ist
->hwaccel_ctx
;
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
);
611 dxva2_destroy_decoder(s
);
613 ret
= dxva2_create_decoder(s
);
615 av_log(NULL
, loglevel
, "Error creating the DXVA2 decoder\n");