2 * This file is part of Libav.
4 * Libav 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 * Libav 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 Libav; 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
30 /* initguid.h needs to be above d3d/dxva to ensure
31 the GUIDs are initialized properly */
39 #include "libavcodec/dxva2.h"
41 #include "libavutil/avassert.h"
42 #include "libavutil/buffer.h"
43 #include "libavutil/frame.h"
44 #include "libavutil/imgutils.h"
45 #include "libavutil/pixfmt.h"
47 typedef IDirect3D9
* WINAPI
pDirect3DCreate9(UINT
);
48 typedef HRESULT WINAPI
pCreateDeviceManager9(UINT
*, IDirect3DDeviceManager9
**);
50 /* GUIDs not defined in the common dxva2api.h in mingw-w64 */
52 DEFINE_GUID(DXVA2_ModeMPEG2and1_VLD
, 0x86695f12, 0x340e,0x4f04,0x9f,0xd3,0x92,0x53,0xdd,0x32,0x74,0x60);
53 DEFINE_GUID(DXVA2_ModeVC1_D2010
, 0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
54 DEFINE_GUID(DXVA2_NoEncrypt
, 0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
57 DEFINE_GUID(DXVADDI_Intel_ModeH264_E
, 0x604F8E68, 0x4951,0x4C54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
58 DEFINE_GUID(GUID_NULL
, 0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
60 typedef struct dxva2_mode
{
65 static const dxva2_mode dxva2_modes
[] = {
67 { &DXVA2_ModeMPEG2_VLD
, AV_CODEC_ID_MPEG2VIDEO
},
68 { &DXVA2_ModeMPEG2and1_VLD
, AV_CODEC_ID_MPEG2VIDEO
},
71 { &DXVA2_ModeH264_F
, AV_CODEC_ID_H264
},
72 { &DXVA2_ModeH264_E
, AV_CODEC_ID_H264
},
73 /* Intel specific H.264 mode */
74 { &DXVADDI_Intel_ModeH264_E
, AV_CODEC_ID_H264
},
77 { &DXVA2_ModeVC1_D2010
, AV_CODEC_ID_VC1
},
78 { &DXVA2_ModeVC1_D2010
, AV_CODEC_ID_WMV3
},
79 { &DXVA2_ModeVC1_D
, AV_CODEC_ID_VC1
},
80 { &DXVA2_ModeVC1_D
, AV_CODEC_ID_WMV3
},
85 typedef struct surface_info
{
90 typedef struct DXVA2Context
{
97 IDirect3DDevice9
*d3d9device
;
98 IDirect3DDeviceManager9
*d3d9devmgr
;
99 IDirectXVideoDecoderService
*decoder_service
;
100 IDirectXVideoDecoder
*decoder
;
103 DXVA2_ConfigPictureDecode decoder_config
;
105 LPDIRECT3DSURFACE9
*surfaces
;
106 surface_info
*surface_infos
;
107 uint32_t num_surfaces
;
108 uint64_t surface_age
;
113 typedef struct DXVA2SurfaceWrapper
{
115 LPDIRECT3DSURFACE9 surface
;
116 IDirectXVideoDecoder
*decoder
;
117 } DXVA2SurfaceWrapper
;
119 static void dxva2_destroy_decoder(AVCodecContext
*s
)
121 InputStream
*ist
= s
->opaque
;
122 DXVA2Context
*ctx
= ist
->hwaccel_ctx
;
125 for (int i
= 0; i
< ctx
->num_surfaces
; i
++) {
126 if (ctx
->surfaces
[i
])
127 IDirect3DSurface9_Release(ctx
->surfaces
[i
]);
130 av_freep(&ctx
->surfaces
);
131 av_freep(&ctx
->surface_infos
);
132 ctx
->num_surfaces
= 0;
133 ctx
->surface_age
= 0;
136 IDirectXVideoDecoder_Release(ctx
->decoder
);
141 static void dxva2_uninit(AVCodecContext
*s
)
143 InputStream
*ist
= s
->opaque
;
144 DXVA2Context
*ctx
= ist
->hwaccel_ctx
;
146 ist
->hwaccel_uninit
= NULL
;
147 ist
->hwaccel_get_buffer
= NULL
;
148 ist
->hwaccel_retrieve_data
= NULL
;
151 dxva2_destroy_decoder(s
);
153 if (ctx
->decoder_service
)
154 IDirectXVideoDecoderService_Release(ctx
->decoder_service
);
156 if (ctx
->d3d9devmgr
&& ctx
->deviceHandle
!= INVALID_HANDLE_VALUE
)
157 IDirect3DDeviceManager9_CloseDeviceHandle(ctx
->d3d9devmgr
, ctx
->deviceHandle
);
160 IDirect3DDeviceManager9_Release(ctx
->d3d9devmgr
);
163 IDirect3DDevice9_Release(ctx
->d3d9device
);
166 IDirect3D9_Release(ctx
->d3d9
);
169 FreeLibrary(ctx
->d3dlib
);
172 FreeLibrary(ctx
->dxva2lib
);
174 av_frame_free(&ctx
->tmp_frame
);
176 av_freep(&ist
->hwaccel_ctx
);
177 av_freep(&s
->hwaccel_context
);
180 static void dxva2_release_buffer(void *opaque
, uint8_t *data
)
182 DXVA2SurfaceWrapper
*w
= opaque
;
183 DXVA2Context
*ctx
= w
->ctx
;
186 for (i
= 0; i
< ctx
->num_surfaces
; i
++) {
187 if (ctx
->surfaces
[i
] == w
->surface
) {
188 ctx
->surface_infos
[i
].used
= 0;
192 IDirect3DSurface9_Release(w
->surface
);
193 IDirectXVideoDecoder_Release(w
->decoder
);
197 static int dxva2_get_buffer(AVCodecContext
*s
, AVFrame
*frame
, int flags
)
199 InputStream
*ist
= s
->opaque
;
200 DXVA2Context
*ctx
= ist
->hwaccel_ctx
;
201 int i
, old_unused
= -1;
202 LPDIRECT3DSURFACE9 surface
;
203 DXVA2SurfaceWrapper
*w
= NULL
;
205 av_assert0(frame
->format
== AV_PIX_FMT_DXVA2_VLD
);
207 for (i
= 0; i
< ctx
->num_surfaces
; i
++) {
208 surface_info
*info
= &ctx
->surface_infos
[i
];
209 if (!info
->used
&& (old_unused
== -1 || info
->age
< ctx
->surface_infos
[old_unused
].age
))
212 if (old_unused
== -1) {
213 av_log(NULL
, AV_LOG_ERROR
, "No free DXVA2 surface!\n");
214 return AVERROR(ENOMEM
);
218 surface
= ctx
->surfaces
[i
];
220 w
= av_mallocz(sizeof(*w
));
222 return AVERROR(ENOMEM
);
224 frame
->buf
[0] = av_buffer_create((uint8_t*)surface
, 0,
225 dxva2_release_buffer
, w
,
226 AV_BUFFER_FLAG_READONLY
);
227 if (!frame
->buf
[0]) {
229 return AVERROR(ENOMEM
);
233 w
->surface
= surface
;
234 IDirect3DSurface9_AddRef(w
->surface
);
235 w
->decoder
= ctx
->decoder
;
236 IDirectXVideoDecoder_AddRef(w
->decoder
);
238 ctx
->surface_infos
[i
].used
= 1;
239 ctx
->surface_infos
[i
].age
= ctx
->surface_age
++;
241 frame
->data
[3] = (uint8_t *)surface
;
246 static int dxva2_retrieve_data(AVCodecContext
*s
, AVFrame
*frame
)
248 LPDIRECT3DSURFACE9 surface
= (LPDIRECT3DSURFACE9
)frame
->data
[3];
249 InputStream
*ist
= s
->opaque
;
250 DXVA2Context
*ctx
= ist
->hwaccel_ctx
;
251 D3DSURFACE_DESC surfaceDesc
;
252 D3DLOCKED_RECT LockedRect
;
256 IDirect3DSurface9_GetDesc(surface
, &surfaceDesc
);
258 ctx
->tmp_frame
->width
= frame
->width
;
259 ctx
->tmp_frame
->height
= frame
->height
;
260 ctx
->tmp_frame
->format
= AV_PIX_FMT_NV12
;
262 ret
= av_frame_get_buffer(ctx
->tmp_frame
, 32);
266 hr
= IDirect3DSurface9_LockRect(surface
, &LockedRect
, NULL
, D3DLOCK_READONLY
);
268 av_log(NULL
, AV_LOG_ERROR
, "Unable to lock DXVA2 surface\n");
269 return AVERROR_UNKNOWN
;
272 av_image_copy_plane(ctx
->tmp_frame
->data
[0], ctx
->tmp_frame
->linesize
[0],
273 (uint8_t*)LockedRect
.pBits
,
274 LockedRect
.Pitch
, frame
->width
, frame
->height
);
276 av_image_copy_plane(ctx
->tmp_frame
->data
[1], ctx
->tmp_frame
->linesize
[1],
277 (uint8_t*)LockedRect
.pBits
+ LockedRect
.Pitch
* surfaceDesc
.Height
,
278 LockedRect
.Pitch
, frame
->width
, frame
->height
/ 2);
280 IDirect3DSurface9_UnlockRect(surface
);
282 ret
= av_frame_copy_props(ctx
->tmp_frame
, frame
);
286 av_frame_unref(frame
);
287 av_frame_move_ref(frame
, ctx
->tmp_frame
);
291 av_frame_unref(ctx
->tmp_frame
);
295 static int dxva2_alloc(AVCodecContext
*s
)
297 InputStream
*ist
= s
->opaque
;
298 int loglevel
= (ist
->hwaccel_id
== HWACCEL_AUTO
) ? AV_LOG_VERBOSE
: AV_LOG_ERROR
;
300 pDirect3DCreate9
*createD3D
= NULL
;
301 pCreateDeviceManager9
*createDeviceManager
= NULL
;
303 D3DPRESENT_PARAMETERS d3dpp
= {0};
304 D3DDISPLAYMODE d3ddm
;
305 unsigned resetToken
= 0;
306 UINT adapter
= D3DADAPTER_DEFAULT
;
308 ctx
= av_mallocz(sizeof(*ctx
));
310 return AVERROR(ENOMEM
);
312 ctx
->deviceHandle
= INVALID_HANDLE_VALUE
;
314 ist
->hwaccel_ctx
= ctx
;
315 ist
->hwaccel_uninit
= dxva2_uninit
;
316 ist
->hwaccel_get_buffer
= dxva2_get_buffer
;
317 ist
->hwaccel_retrieve_data
= dxva2_retrieve_data
;
319 ctx
->d3dlib
= LoadLibrary("d3d9.dll");
321 av_log(NULL
, loglevel
, "Failed to load D3D9 library\n");
324 ctx
->dxva2lib
= LoadLibrary("dxva2.dll");
325 if (!ctx
->dxva2lib
) {
326 av_log(NULL
, loglevel
, "Failed to load DXVA2 library\n");
330 createD3D
= (pDirect3DCreate9
*)GetProcAddress(ctx
->d3dlib
, "Direct3DCreate9");
332 av_log(NULL
, loglevel
, "Failed to locate Direct3DCreate9\n");
335 createDeviceManager
= (pCreateDeviceManager9
*)GetProcAddress(ctx
->dxva2lib
, "DXVA2CreateDirect3DDeviceManager9");
336 if (!createDeviceManager
) {
337 av_log(NULL
, loglevel
, "Failed to locate DXVA2CreateDirect3DDeviceManager9\n");
341 ctx
->d3d9
= createD3D(D3D_SDK_VERSION
);
343 av_log(NULL
, loglevel
, "Failed to create IDirect3D object\n");
347 if (ist
->hwaccel_device
) {
348 adapter
= atoi(ist
->hwaccel_device
);
349 av_log(NULL
, AV_LOG_INFO
, "Using HWAccel device %d\n", adapter
);
352 IDirect3D9_GetAdapterDisplayMode(ctx
->d3d9
, adapter
, &d3ddm
);
353 d3dpp
.Windowed
= TRUE
;
354 d3dpp
.BackBufferWidth
= 640;
355 d3dpp
.BackBufferHeight
= 480;
356 d3dpp
.BackBufferCount
= 0;
357 d3dpp
.BackBufferFormat
= d3ddm
.Format
;
358 d3dpp
.SwapEffect
= D3DSWAPEFFECT_DISCARD
;
359 d3dpp
.Flags
= D3DPRESENTFLAG_VIDEO
;
361 hr
= IDirect3D9_CreateDevice(ctx
->d3d9
, adapter
, D3DDEVTYPE_HAL
, GetShellWindow(),
362 D3DCREATE_SOFTWARE_VERTEXPROCESSING
| D3DCREATE_MULTITHREADED
| D3DCREATE_FPU_PRESERVE
,
363 &d3dpp
, &ctx
->d3d9device
);
365 av_log(NULL
, loglevel
, "Failed to create Direct3D device\n");
369 hr
= createDeviceManager(&resetToken
, &ctx
->d3d9devmgr
);
371 av_log(NULL
, loglevel
, "Failed to create Direct3D device manager\n");
375 hr
= IDirect3DDeviceManager9_ResetDevice(ctx
->d3d9devmgr
, ctx
->d3d9device
, resetToken
);
377 av_log(NULL
, loglevel
, "Failed to bind Direct3D device to device manager\n");
381 hr
= IDirect3DDeviceManager9_OpenDeviceHandle(ctx
->d3d9devmgr
, &ctx
->deviceHandle
);
383 av_log(NULL
, loglevel
, "Failed to open device handle\n");
387 hr
= IDirect3DDeviceManager9_GetVideoService(ctx
->d3d9devmgr
, ctx
->deviceHandle
, &IID_IDirectXVideoDecoderService
, (void **)&ctx
->decoder_service
);
389 av_log(NULL
, loglevel
, "Failed to create IDirectXVideoDecoderService\n");
393 ctx
->tmp_frame
= av_frame_alloc();
397 s
->hwaccel_context
= av_mallocz(sizeof(struct dxva_context
));
398 if (!s
->hwaccel_context
)
404 return AVERROR(EINVAL
);
407 static int dxva2_get_decoder_configuration(AVCodecContext
*s
, const GUID
*device_guid
,
408 const DXVA2_VideoDesc
*desc
,
409 DXVA2_ConfigPictureDecode
*config
)
411 InputStream
*ist
= s
->opaque
;
412 int loglevel
= (ist
->hwaccel_id
== HWACCEL_AUTO
) ? AV_LOG_VERBOSE
: AV_LOG_ERROR
;
413 DXVA2Context
*ctx
= ist
->hwaccel_ctx
;
414 unsigned cfg_count
= 0, best_score
= 0;
415 DXVA2_ConfigPictureDecode
*cfg_list
= NULL
;
416 DXVA2_ConfigPictureDecode best_cfg
= {{0}};
420 hr
= IDirectXVideoDecoderService_GetDecoderConfigurations(ctx
->decoder_service
, device_guid
, desc
, NULL
, &cfg_count
, &cfg_list
);
422 av_log(NULL
, loglevel
, "Unable to retrieve decoder configurations\n");
423 return AVERROR(EINVAL
);
426 for (i
= 0; i
< cfg_count
; i
++) {
427 DXVA2_ConfigPictureDecode
*cfg
= &cfg_list
[i
];
430 if (cfg
->ConfigBitstreamRaw
== 1)
432 else if (s
->codec_id
== AV_CODEC_ID_H264
&& cfg
->ConfigBitstreamRaw
== 2)
436 if (IsEqualGUID(&cfg
->guidConfigBitstreamEncryption
, &DXVA2_NoEncrypt
))
438 if (score
> best_score
) {
443 CoTaskMemFree(cfg_list
);
446 av_log(NULL
, loglevel
, "No valid decoder configuration available\n");
447 return AVERROR(EINVAL
);
454 static int dxva2_create_decoder(AVCodecContext
*s
)
456 InputStream
*ist
= s
->opaque
;
457 int loglevel
= (ist
->hwaccel_id
== HWACCEL_AUTO
) ? AV_LOG_VERBOSE
: AV_LOG_ERROR
;
458 DXVA2Context
*ctx
= ist
->hwaccel_ctx
;
459 struct dxva_context
*dxva_ctx
= s
->hwaccel_context
;
460 GUID
*guid_list
= NULL
;
461 unsigned guid_count
= 0, i
, j
;
462 GUID device_guid
= GUID_NULL
;
463 D3DFORMAT target_format
= 0;
464 DXVA2_VideoDesc desc
= { 0 };
465 DXVA2_ConfigPictureDecode config
;
467 int surface_alignment
;
470 hr
= IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx
->decoder_service
, &guid_count
, &guid_list
);
472 av_log(NULL
, loglevel
, "Failed to retrieve decoder device GUIDs\n");
476 for (i
= 0; dxva2_modes
[i
].guid
; i
++) {
477 D3DFORMAT
*target_list
= NULL
;
478 unsigned target_count
= 0;
479 const dxva2_mode
*mode
= &dxva2_modes
[i
];
480 if (mode
->codec
!= s
->codec_id
)
483 for (j
= 0; j
< guid_count
; j
++) {
484 if (IsEqualGUID(mode
->guid
, &guid_list
[j
]))
490 hr
= IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx
->decoder_service
, mode
->guid
, &target_count
, &target_list
);
494 for (j
= 0; j
< target_count
; j
++) {
495 const D3DFORMAT format
= target_list
[j
];
496 if (format
== MKTAG('N','V','1','2')) {
497 target_format
= format
;
501 CoTaskMemFree(target_list
);
503 device_guid
= *mode
->guid
;
507 CoTaskMemFree(guid_list
);
509 if (IsEqualGUID(&device_guid
, &GUID_NULL
)) {
510 av_log(NULL
, loglevel
, "No decoder device for codec found\n");
514 desc
.SampleWidth
= s
->coded_width
;
515 desc
.SampleHeight
= s
->coded_height
;
516 desc
.Format
= target_format
;
518 ret
= dxva2_get_decoder_configuration(s
, &device_guid
, &desc
, &config
);
523 /* decoding MPEG-2 requires additional alignment on some Intel GPUs,
524 but it causes issues for H.264 on certain AMD GPUs..... */
525 if (s
->codec_id
== AV_CODEC_ID_MPEG2VIDEO
)
526 surface_alignment
= 32;
528 surface_alignment
= 16;
530 /* 4 base work surfaces */
531 ctx
->num_surfaces
= 4;
533 /* add surfaces based on number of possible refs */
534 if (s
->codec_id
== AV_CODEC_ID_H264
)
535 ctx
->num_surfaces
+= 16;
537 ctx
->num_surfaces
+= 2;
539 /* add extra surfaces for frame threading */
540 if (s
->active_thread_type
& FF_THREAD_FRAME
)
541 ctx
->num_surfaces
+= s
->thread_count
;
543 ctx
->surfaces
= av_mallocz(ctx
->num_surfaces
* sizeof(*ctx
->surfaces
));
544 ctx
->surface_infos
= av_mallocz(ctx
->num_surfaces
* sizeof(*ctx
->surface_infos
));
546 if (!ctx
->surfaces
|| !ctx
->surface_infos
) {
547 av_log(NULL
, loglevel
, "Unable to allocate surface arrays\n");
551 hr
= IDirectXVideoDecoderService_CreateSurface(ctx
->decoder_service
,
552 FFALIGN(s
->coded_width
, surface_alignment
),
553 FFALIGN(s
->coded_height
, surface_alignment
),
554 ctx
->num_surfaces
- 1,
555 target_format
, D3DPOOL_DEFAULT
, 0,
556 DXVA2_VideoDecoderRenderTarget
,
557 ctx
->surfaces
, NULL
);
559 av_log(NULL
, loglevel
, "Failed to create %d video surfaces\n", ctx
->num_surfaces
);
563 hr
= IDirectXVideoDecoderService_CreateVideoDecoder(ctx
->decoder_service
, &device_guid
,
564 &desc
, &config
, ctx
->surfaces
,
565 ctx
->num_surfaces
, &ctx
->decoder
);
567 av_log(NULL
, loglevel
, "Failed to create DXVA2 video decoder\n");
571 ctx
->decoder_guid
= device_guid
;
572 ctx
->decoder_config
= config
;
574 dxva_ctx
->cfg
= &ctx
->decoder_config
;
575 dxva_ctx
->decoder
= ctx
->decoder
;
576 dxva_ctx
->surface
= ctx
->surfaces
;
577 dxva_ctx
->surface_count
= ctx
->num_surfaces
;
579 if (IsEqualGUID(&ctx
->decoder_guid
, &DXVADDI_Intel_ModeH264_E
))
580 dxva_ctx
->workaround
|= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO
;
584 dxva2_destroy_decoder(s
);
585 return AVERROR(EINVAL
);
588 int dxva2_init(AVCodecContext
*s
)
590 InputStream
*ist
= s
->opaque
;
591 int loglevel
= (ist
->hwaccel_id
== HWACCEL_AUTO
) ? AV_LOG_VERBOSE
: AV_LOG_ERROR
;
595 if (!ist
->hwaccel_ctx
) {
596 ret
= dxva2_alloc(s
);
600 ctx
= ist
->hwaccel_ctx
;
602 if (s
->codec_id
== AV_CODEC_ID_H264
&&
603 (s
->profile
& ~FF_PROFILE_H264_CONSTRAINED
) > FF_PROFILE_H264_HIGH
) {
604 av_log(NULL
, loglevel
, "Unsupported H.264 profile for DXVA2 HWAccel: %d\n", s
->profile
);
605 return AVERROR(EINVAL
);
609 dxva2_destroy_decoder(s
);
611 ret
= dxva2_create_decoder(s
);
613 av_log(NULL
, loglevel
, "Error creating the DXVA2 decoder\n");