1 /*****************************************************************************
2 * va.c: Video Acceleration helpers
3 *****************************************************************************
4 * Copyright (C) 2009 Geoffroy Couprie
5 * Copyright (C) 2009 Laurent Aimar
8 * Authors: Geoffroy Couprie <geal@videolan.org>
9 * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_picture.h>
32 #include <vlc_fourcc.h>
36 #ifdef HAVE_LIBAVCODEC_AVCODEC_H
37 # include <libavcodec/avcodec.h>
38 # ifdef HAVE_AVCODEC_DXVA2
39 # define DXVA2API_USE_BITFIELDS
40 # include <libavcodec/dxva2.h>
50 #ifdef HAVE_AVCODEC_DXVA2
60 #define DXVA2_E_NOT_INITIALIZED MAKE_HRESULT(1, 4, 4096)
61 #define DXVA2_E_NEW_VIDEO_DEVICE MAKE_HRESULT(1, 4, 4097)
62 #define DXVA2_E_VIDEO_DEVICE_LOCKED MAKE_HRESULT(1, 4, 4098)
63 #define DXVA2_E_NOT_AVAILABLE MAKE_HRESULT(1, 4, 4099)
65 static const GUID DXVA2_ModeMPEG2_MoComp
= {
66 0xe6a9f44b, 0x61b0,0x4563, {0x9e,0xa4,0x63,0xd2,0xa3,0xc6,0xfe,0x66}
68 static const GUID DXVA2_ModeMPEG2_IDCT
= {
69 0xbf22ad00, 0x03ea,0x4690, {0x80,0x77,0x47,0x33,0x46,0x20,0x9b,0x7e}
71 static const GUID DXVA2_ModeMPEG2_VLD
= {
72 0xee27417f, 0x5e28,0x4e65, {0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9}
75 static const GUID DXVA2_ModeH264_A
= {
76 0x1b81be64, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
78 static const GUID DXVA2_ModeH264_B
= {
79 0x1b81be65, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
81 static const GUID DXVA2_ModeH264_C
= {
82 0x1b81be66, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
84 static const GUID DXVA2_ModeH264_D
= {
85 0x1b81be67, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
87 static const GUID DXVA2_ModeH264_E
= {
88 0x1b81be68, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
90 static const GUID DXVA2_ModeH264_F
= {
91 0x1b81be69, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
93 static const GUID DXVADDI_Intel_ModeH264_A
= {
94 0x604F8E64, 0x4951,0x4c54, {0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6}
96 static const GUID DXVADDI_Intel_ModeH264_C
= {
97 0x604F8E66, 0x4951,0x4c54, {0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6}
99 static const GUID DXVADDI_Intel_ModeH264_E
= {
100 0x604F8E68, 0x4951,0x4c54, {0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6}
102 static const GUID DXVA2_ModeWMV8_A
= {
103 0x1b81be80, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
105 static const GUID DXVA2_ModeWMV8_B
= {
106 0x1b81be81, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
108 static const GUID DXVA2_ModeWMV9_A
= {
109 0x1b81be90, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
111 static const GUID DXVA2_ModeWMV9_B
= {
112 0x1b81be91, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
114 static const GUID DXVA2_ModeWMV9_C
= {
115 0x1b81be94, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
118 static const GUID DXVA2_ModeVC1_A
= {
119 0x1b81beA0, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
121 static const GUID DXVA2_ModeVC1_B
= {
122 0x1b81beA1, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
124 static const GUID DXVA2_ModeVC1_C
= {
125 0x1b81beA2, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
127 static const GUID DXVA2_ModeVC1_D
= {
128 0x1b81beA3, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
131 static const GUID DXVA_NoEncrypt
= {
132 0x1b81bed0, 0xa0c7,0x11d3, {0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5}
141 /* XXX Prefered modes must come first */
142 static const dxva2_mode_t dxva2_modes
[] = {
143 { "MPEG-2 variable-length decoder", &DXVA2_ModeMPEG2_VLD
, CODEC_ID_MPEG2VIDEO
},
144 { "MPEG-2 motion compensation", &DXVA2_ModeMPEG2_MoComp
, 0 },
145 { "MPEG-2 inverse discrete cosine transform", &DXVA2_ModeMPEG2_IDCT
, 0 },
147 { "H.264 variable-length decoder, film grain technology", &DXVA2_ModeH264_F
, CODEC_ID_H264
},
148 { "H.264 variable-length decoder, no film grain technology", &DXVA2_ModeH264_E
, CODEC_ID_H264
},
149 { "H.264 variable-length decoder, no film grain technology (Intel)", &DXVADDI_Intel_ModeH264_E
, CODEC_ID_H264
},
150 { "H.264 inverse discrete cosine transform, film grain technology", &DXVA2_ModeH264_D
, 0 },
151 { "H.264 inverse discrete cosine transform, no film grain technology", &DXVA2_ModeH264_C
, 0 },
152 { "H.264 inverse discrete cosine transform, no film grain technology (Intel)", &DXVADDI_Intel_ModeH264_C
, 0 },
153 { "H.264 motion compensation, film grain technology", &DXVA2_ModeH264_B
, 0 },
154 { "H.264 motion compensation, no film grain technology", &DXVA2_ModeH264_A
, 0 },
155 { "H.264 motion compensation, no film grain technology (Intel)", &DXVADDI_Intel_ModeH264_A
, 0 },
157 { "Windows Media Video 8 motion compensation", &DXVA2_ModeWMV8_B
, 0 },
158 { "Windows Media Video 8 post processing", &DXVA2_ModeWMV8_A
, 0 },
160 { "Windows Media Video 9 IDCT", &DXVA2_ModeWMV9_C
, 0 },
161 { "Windows Media Video 9 motion compensation", &DXVA2_ModeWMV9_B
, 0 },
162 { "Windows Media Video 9 post processing", &DXVA2_ModeWMV9_A
, 0 },
164 { "VC-1 variable-length decoder", &DXVA2_ModeVC1_D
, CODEC_ID_VC1
},
165 { "VC-1 variable-length decoder", &DXVA2_ModeVC1_D
, CODEC_ID_WMV3
},
166 { "VC-1 inverse discrete cosine transform", &DXVA2_ModeVC1_C
, 0 },
167 { "VC-1 motion compensation", &DXVA2_ModeVC1_B
, 0 },
168 { "VC-1 post processing", &DXVA2_ModeVC1_A
, 0 },
173 static const dxva2_mode_t
*Dxva2FindMode(const GUID
*guid
)
175 for (unsigned i
= 0; dxva2_modes
[i
].name
; i
++) {
176 if (IsEqualGUID(dxva2_modes
[i
].guid
, guid
))
177 return &dxva2_modes
[i
];
188 /* XXX Prefered format must come first */
189 static const d3d_format_t d3d_formats
[] = {
190 { "YV12", MAKEFOURCC('Y','V','1','2'), VLC_CODEC_YV12
},
191 { "NV12", MAKEFOURCC('N','V','1','2'), VLC_CODEC_NV12
},
196 static const d3d_format_t
*D3dFindFormat(D3DFORMAT format
)
198 for (unsigned i
= 0; d3d_formats
[i
].name
; i
++) {
199 if (d3d_formats
[i
].format
== format
)
200 return &d3d_formats
[i
];
205 static const GUID IID_IDirectXVideoDecoderService
= {
206 0xfc51a551, 0xd5e7, 0x11d9, {0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02}
208 static const GUID IID_IDirectXVideoAccelerationService
= {
209 0xfc51a550, 0xd5e7, 0x11d9, {0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02}
214 LPDIRECT3DSURFACE9 d3d
;
219 #define VA_DXVA2_MAX_SURFACE_COUNT (64)
233 HINSTANCE hdxva2_dll
;
236 D3DPRESENT_PARAMETERS d3dpp
;
238 D3DADAPTER_IDENTIFIER9 d3dai
;
239 LPDIRECT3DDEVICE9 d3ddev
;
243 IDirect3DDeviceManager9
*devmng
;
247 IDirectXVideoDecoderService
*vs
;
252 DXVA2_ConfigPictureDecode cfg
;
253 IDirectXVideoDecoder
*decoder
;
255 /* Option conversion */
257 copy_cache_t surface_cache
;
260 struct dxva_context hw
;
263 unsigned surface_count
;
264 unsigned surface_order
;
267 vlc_fourcc_t surface_chroma
;
269 vlc_va_surface_t surface
[VA_DXVA2_MAX_SURFACE_COUNT
];
270 LPDIRECT3DSURFACE9 hw_surface
[VA_DXVA2_MAX_SURFACE_COUNT
];
274 static vlc_va_dxva2_t
*vlc_va_dxva2_Get(void *external
)
276 assert(external
== (void*)(&((vlc_va_dxva2_t
*)external
)->va
));
281 static int D3dCreateDevice(vlc_va_dxva2_t
*);
282 static void D3dDestroyDevice(vlc_va_dxva2_t
*);
283 static char *DxDescribe(vlc_va_dxva2_t
*);
285 static int D3dCreateDeviceManager(vlc_va_dxva2_t
*);
286 static void D3dDestroyDeviceManager(vlc_va_dxva2_t
*);
288 static int DxCreateVideoService(vlc_va_dxva2_t
*);
289 static void DxDestroyVideoService(vlc_va_dxva2_t
*);
290 static int DxFindVideoServiceConversion(vlc_va_dxva2_t
*, GUID
*input
, D3DFORMAT
*output
);
292 static int DxCreateVideoDecoder(vlc_va_dxva2_t
*,
293 int codec_id
, const video_format_t
*);
294 static void DxDestroyVideoDecoder(vlc_va_dxva2_t
*);
295 static int DxResetVideoDecoder(vlc_va_dxva2_t
*);
297 static void DxCreateVideoConversion(vlc_va_dxva2_t
*);
298 static void DxDestroyVideoConversion(vlc_va_dxva2_t
*);
301 static int Setup(vlc_va_t
*external
, void **hw
, vlc_fourcc_t
*chroma
,
302 int width
, int height
)
304 vlc_va_dxva2_t
*va
= vlc_va_dxva2_Get(external
);
306 if (va
->width
== width
&& va
->height
== height
&& va
->decoder
)
310 DxDestroyVideoConversion(va
);
311 DxDestroyVideoDecoder(va
);
315 if (width
<= 0 || height
<= 0)
318 /* FIXME transmit a video_format_t by VaSetup directly */
320 memset(&fmt
, 0, sizeof(fmt
));
322 fmt
.i_height
= height
;
324 if (DxCreateVideoDecoder(va
, va
->codec_id
, &fmt
))
327 va
->hw
.decoder
= va
->decoder
;
328 va
->hw
.cfg
= &va
->cfg
;
329 va
->hw
.surface_count
= va
->surface_count
;
330 va
->hw
.surface
= va
->hw_surface
;
331 for (unsigned i
= 0; i
< va
->surface_count
; i
++)
332 va
->hw
.surface
[i
] = va
->surface
[i
].d3d
;
335 DxCreateVideoConversion(va
);
340 const d3d_format_t
*output
= D3dFindFormat(va
->output
);
341 *chroma
= output
->codec
;
346 static int Extract(vlc_va_t
*external
, picture_t
*picture
, AVFrame
*ff
)
348 vlc_va_dxva2_t
*va
= vlc_va_dxva2_Get(external
);
349 LPDIRECT3DSURFACE9 d3d
= (LPDIRECT3DSURFACE9
)(uintptr_t)ff
->data
[3];
351 if (!va
->surface_cache
.buffer
)
355 assert(va
->output
== MAKEFOURCC('Y','V','1','2'));
359 if (FAILED(IDirect3DSurface9_LockRect(d3d
, &lock
, NULL
, D3DLOCK_READONLY
))) {
360 msg_Err(va
->log
, "Failed to lock surface");
364 if (va
->render
== MAKEFOURCC('Y','V','1','2')) {
365 uint8_t *plane
[3] = {
367 (uint8_t*)lock
.pBits
+ lock
.Pitch
* va
->surface_height
,
368 (uint8_t*)lock
.pBits
+ lock
.Pitch
* va
->surface_height
369 + (lock
.Pitch
/2) * (va
->surface_height
/2)
376 CopyFromYv12(picture
, plane
, pitch
,
377 va
->width
, va
->height
,
380 assert(va
->render
== MAKEFOURCC('N','V','1','2'));
381 uint8_t *plane
[2] = {
383 (uint8_t*)lock
.pBits
+ lock
.Pitch
* va
->surface_height
389 CopyFromNv12(picture
, plane
, pitch
,
390 va
->width
, va
->height
,
395 IDirect3DSurface9_UnlockRect(d3d
);
398 /* FIXME it is nearly common with VAAPI */
399 static int Get(vlc_va_t
*external
, AVFrame
*ff
)
401 vlc_va_dxva2_t
*va
= vlc_va_dxva2_Get(external
);
403 /* Check the device */
404 HRESULT hr
= IDirect3DDeviceManager9_TestDevice(va
->devmng
, va
->device
);
405 if (hr
== DXVA2_E_NEW_VIDEO_DEVICE
) {
406 if (DxResetVideoDecoder(va
))
408 } else if (FAILED(hr
)) {
409 msg_Err(va
->log
, "IDirect3DDeviceManager9_TestDevice %u", (unsigned)hr
);
413 /* Grab an unused surface, in case none are, try the oldest
414 * XXX using the oldest is a workaround in case a problem happens with ffmpeg */
416 for (i
= 0, old
= 0; i
< va
->surface_count
; i
++) {
417 vlc_va_surface_t
*surface
= &va
->surface
[i
];
419 if (!surface
->refcount
)
422 if (surface
->order
< va
->surface
[old
].order
)
425 if (i
>= va
->surface_count
)
428 vlc_va_surface_t
*surface
= &va
->surface
[i
];
430 surface
->refcount
= 1;
431 surface
->order
= va
->surface_order
++;
434 for (int i
= 0; i
< 4; i
++) {
438 if (i
== 0 || i
== 3)
439 ff
->data
[i
] = (void*)surface
->d3d
;/* Yummie */
443 static void Release(vlc_va_t
*external
, AVFrame
*ff
)
445 vlc_va_dxva2_t
*va
= vlc_va_dxva2_Get(external
);
446 LPDIRECT3DSURFACE9 d3d
= (LPDIRECT3DSURFACE9
)(uintptr_t)ff
->data
[3];
448 for (unsigned i
= 0; i
< va
->surface_count
; i
++) {
449 vlc_va_surface_t
*surface
= &va
->surface
[i
];
451 if (surface
->d3d
== d3d
)
455 static void Close(vlc_va_t
*external
)
457 vlc_va_dxva2_t
*va
= vlc_va_dxva2_Get(external
);
459 DxDestroyVideoConversion(va
);
460 DxDestroyVideoDecoder(va
);
461 DxDestroyVideoService(va
);
462 D3dDestroyDeviceManager(va
);
463 D3dDestroyDevice(va
);
466 FreeLibrary(va
->hdxva2_dll
);
468 FreeLibrary(va
->hd3d9_dll
);
470 free(va
->va
.description
);
474 vlc_va_t
*vlc_va_NewDxva2(vlc_object_t
*log
, int codec_id
)
476 vlc_va_dxva2_t
*va
= calloc(1, sizeof(*va
));
482 va
->codec_id
= codec_id
;
485 va
->hd3d9_dll
= LoadLibrary(TEXT("D3D9.DLL"));
486 if (!va
->hd3d9_dll
) {
487 msg_Warn(va
->log
, "cannot load d3d9.dll");
490 va
->hdxva2_dll
= LoadLibrary(TEXT("DXVA2.DLL"));
491 if (!va
->hdxva2_dll
) {
492 msg_Warn(va
->log
, "cannot load dxva2.dll");
495 msg_Dbg(va
->log
, "DLLs loaded");
498 if (D3dCreateDevice(va
)) {
499 msg_Err(va
->log
, "Failed to create Direct3D device");
502 msg_Dbg(va
->log
, "D3dCreateDevice succeed");
504 if (D3dCreateDeviceManager(va
)) {
505 msg_Err(va
->log
, "D3dCreateDeviceManager failed");
509 if (DxCreateVideoService(va
)) {
510 msg_Err(va
->log
, "DxCreateVideoService failed");
515 if (DxFindVideoServiceConversion(va
, &va
->input
, &va
->render
)) {
516 msg_Err(va
->log
, "DxFindVideoServiceConversion failed");
520 /* TODO print the hardware name/vendor for debugging purposes */
521 va
->va
.description
= DxDescribe(va
);
522 va
->va
.setup
= Setup
;
524 va
->va
.release
= Release
;
525 va
->va
.extract
= Extract
;
526 va
->va
.close
= Close
;
536 * It creates a Direct3D device usable for DXVA 2
538 static int D3dCreateDevice(vlc_va_dxva2_t
*va
)
541 LPDIRECT3D9 (WINAPI
*Create9
)(UINT SDKVersion
);
542 Create9
= (void *)GetProcAddress(va
->hd3d9_dll
,
543 TEXT("Direct3DCreate9"));
545 msg_Err(va
->log
, "Cannot locate reference to Direct3DCreate9 ABI in DLL");
551 d3dobj
= Create9(D3D_SDK_VERSION
);
553 msg_Err(va
->log
, "Direct3DCreate9 failed");
559 D3DADAPTER_IDENTIFIER9
*d3dai
= &va
->d3dai
;
560 if (FAILED(IDirect3D9_GetAdapterIdentifier(va
->d3dobj
,
561 D3DADAPTER_DEFAULT
, 0, d3dai
))) {
562 msg_Warn(va
->log
, "IDirect3D9_GetAdapterIdentifier failed");
563 ZeroMemory(d3dai
, sizeof(*d3dai
));
567 D3DPRESENT_PARAMETERS
*d3dpp
= &va
->d3dpp
;
568 ZeroMemory(d3dpp
, sizeof(*d3dpp
));
569 d3dpp
->Flags
= D3DPRESENTFLAG_VIDEO
;
570 d3dpp
->Windowed
= TRUE
;
571 d3dpp
->hDeviceWindow
= NULL
;
572 d3dpp
->SwapEffect
= D3DSWAPEFFECT_DISCARD
;
573 d3dpp
->MultiSampleType
= D3DMULTISAMPLE_NONE
;
574 d3dpp
->PresentationInterval
= D3DPRESENT_INTERVAL_DEFAULT
;
575 d3dpp
->BackBufferCount
= 0; /* FIXME what to put here */
576 d3dpp
->BackBufferFormat
= D3DFMT_X8R8G8B8
; /* FIXME what to put here */
577 d3dpp
->BackBufferWidth
= 0;
578 d3dpp
->BackBufferHeight
= 0;
579 d3dpp
->EnableAutoDepthStencil
= FALSE
;
581 /* Direct3D needs a HWND to create a device, even without using ::Present
582 this HWND is used to alert Direct3D when there's a change of focus window.
583 For now, use GetShellWindow, as it looks harmless */
584 LPDIRECT3DDEVICE9 d3ddev
;
585 if (FAILED(IDirect3D9_CreateDevice(d3dobj
, D3DADAPTER_DEFAULT
,
586 D3DDEVTYPE_HAL
, GetShellWindow(),
587 D3DCREATE_SOFTWARE_VERTEXPROCESSING
|
588 D3DCREATE_MULTITHREADED
,
590 msg_Err(va
->log
, "IDirect3D9_CreateDevice failed");
598 * It releases a Direct3D device and its resources.
600 static void D3dDestroyDevice(vlc_va_dxva2_t
*va
)
603 IDirect3DDevice9_Release(va
->d3ddev
);
605 IDirect3D9_Release(va
->d3dobj
);
608 * It describes our Direct3D object
610 static char *DxDescribe(vlc_va_dxva2_t
*va
)
612 static const struct {
617 { 0x10DE, "NVIDIA" },
619 { 0x5333, "S3 Graphics" },
622 D3DADAPTER_IDENTIFIER9
*id
= &va
->d3dai
;
624 const char *vendor
= "Unknown";
625 for (int i
= 0; vendors
[i
].id
!= 0; i
++) {
626 if (vendors
[i
].id
== id
->VendorId
) {
627 vendor
= vendors
[i
].name
;
633 if (asprintf(&description
, "DXVA2 (%.*s, vendor %d(%s), device %d, revision %d)",
634 sizeof(id
->Description
), id
->Description
,
635 id
->VendorId
, vendor
, id
->DeviceId
, id
->Revision
) < 0)
641 * It creates a Direct3D device manager
643 static int D3dCreateDeviceManager(vlc_va_dxva2_t
*va
)
645 HRESULT (WINAPI
*CreateDeviceManager9
)(UINT
*pResetToken
,
646 IDirect3DDeviceManager9
**);
647 CreateDeviceManager9
=
648 (void *)GetProcAddress(va
->hdxva2_dll
,
649 TEXT("DXVA2CreateDirect3DDeviceManager9"));
651 if (!CreateDeviceManager9
) {
652 msg_Err(va
->log
, "cannot load function");
655 msg_Dbg(va
->log
, "OurDirect3DCreateDeviceManager9 Success!");
658 IDirect3DDeviceManager9
*devmng
;
659 if (FAILED(CreateDeviceManager9(&token
, &devmng
))) {
660 msg_Err(va
->log
, " OurDirect3DCreateDeviceManager9 failed");
665 msg_Info(va
->log
, "obtained IDirect3DDeviceManager9");
667 HRESULT hr
= IDirect3DDeviceManager9_ResetDevice(devmng
, va
->d3ddev
, token
);
669 msg_Err(va
->log
, "IDirect3DDeviceManager9_ResetDevice failed: %08x", (unsigned)hr
);
675 * It destroys a Direct3D device manager
677 static void D3dDestroyDeviceManager(vlc_va_dxva2_t
*va
)
680 IDirect3DDeviceManager9_Release(va
->devmng
);
684 * It creates a DirectX video service
686 static int DxCreateVideoService(vlc_va_dxva2_t
*va
)
688 HRESULT (WINAPI
*CreateVideoService
)(IDirect3DDevice9
*,
692 (void *)GetProcAddress(va
->hdxva2_dll
,
693 TEXT("DXVA2CreateVideoService"));
695 if (!CreateVideoService
) {
696 msg_Err(va
->log
, "cannot load function");
699 msg_Info(va
->log
, "DXVA2CreateVideoService Success!");
704 hr
= IDirect3DDeviceManager9_OpenDeviceHandle(va
->devmng
, &device
);
706 msg_Err(va
->log
, "OpenDeviceHandle failed");
711 IDirectXVideoDecoderService
*vs
;
712 hr
= IDirect3DDeviceManager9_GetVideoService(va
->devmng
, device
,
713 &IID_IDirectXVideoDecoderService
,
716 msg_Err(va
->log
, "GetVideoService failed");
724 * It destroys a DirectX video service
726 static void DxDestroyVideoService(vlc_va_dxva2_t
*va
)
729 IDirect3DDeviceManager9_CloseDeviceHandle(va
->devmng
, va
->device
);
731 IDirectXVideoDecoderService_Release(va
->vs
);
734 * Find the best suited decoder mode GUID and render format.
736 static int DxFindVideoServiceConversion(vlc_va_dxva2_t
*va
, GUID
*input
, D3DFORMAT
*output
)
738 /* Retreive supported modes from the decoder service */
739 UINT input_count
= 0;
740 GUID
*input_list
= NULL
;
741 if (FAILED(IDirectXVideoDecoderService_GetDecoderDeviceGuids(va
->vs
,
744 msg_Err(va
->log
, "IDirectXVideoDecoderService_GetDecoderDeviceGuids failed");
747 for (unsigned i
= 0; i
< input_count
; i
++) {
748 const GUID
*g
= &input_list
[i
];
749 const dxva2_mode_t
*mode
= Dxva2FindMode(g
);
751 msg_Dbg(va
->log
, "- '%s' is supported by hardware", mode
->name
);
753 msg_Warn(va
->log
, "- Unknown GUID = %08X-%04x-%04x-XXXX",
754 (unsigned)g
->Data1
, g
->Data2
, g
->Data3
);
758 /* Try all supported mode by our priority */
759 for (unsigned i
= 0; dxva2_modes
[i
].name
; i
++) {
760 const dxva2_mode_t
*mode
= &dxva2_modes
[i
];
761 if (!mode
->codec
|| mode
->codec
!= va
->codec_id
)
765 bool is_suported
= false;
766 for (const GUID
*g
= &input_list
[0]; !is_suported
&& g
< &input_list
[input_count
]; g
++) {
767 is_suported
= IsEqualGUID(mode
->guid
, g
);
773 msg_Dbg(va
->log
, "Trying to use '%s' as input", mode
->name
);
774 UINT output_count
= 0;
775 D3DFORMAT
*output_list
= NULL
;
776 if (FAILED(IDirectXVideoDecoderService_GetDecoderRenderTargets(va
->vs
, mode
->guid
,
779 msg_Err(va
->log
, "IDirectXVideoDecoderService_GetDecoderRenderTargets failed");
782 for (unsigned j
= 0; j
< output_count
; j
++) {
783 const D3DFORMAT f
= output_list
[j
];
784 const d3d_format_t
*format
= D3dFindFormat(f
);
786 msg_Dbg(va
->log
, "%s is supported for output", format
->name
);
788 msg_Dbg(va
->log
, "%d is supported for output (%4.4s)", f
, (const char*)&f
);
793 for (unsigned j
= 0; d3d_formats
[j
].name
; j
++) {
794 const d3d_format_t
*format
= &d3d_formats
[j
];
797 bool is_suported
= false;
798 for (unsigned k
= 0; !is_suported
&& k
< output_count
; k
++) {
799 is_suported
= format
->format
== output_list
[k
];
804 /* We have our solution */
805 msg_Dbg(va
->log
, "Using '%s' to decode to '%s'", mode
->name
, format
->name
);
806 *input
= *mode
->guid
;
807 *output
= format
->format
;
808 CoTaskMemFree(output_list
);
809 CoTaskMemFree(input_list
);
812 CoTaskMemFree(output_list
);
814 CoTaskMemFree(input_list
);
819 * It creates a DXVA2 decoder using the given video format
821 static int DxCreateVideoDecoder(vlc_va_dxva2_t
*va
,
822 int codec_id
, const video_format_t
*fmt
)
825 msg_Dbg(va
->log
, "DxCreateVideoDecoder id %d %dx%d",
826 codec_id
, fmt
->i_width
, fmt
->i_height
);
828 va
->width
= fmt
->i_width
;
829 va
->height
= fmt
->i_height
;
831 /* Allocates all surfaces needed for the decoder */
832 va
->surface_width
= (fmt
->i_width
+ 15) & ~15;
833 va
->surface_height
= (fmt
->i_height
+ 15) & ~15;
836 va
->surface_count
= 16 + 1;
839 va
->surface_count
= 2 + 1;
842 LPDIRECT3DSURFACE9 surface_list
[VA_DXVA2_MAX_SURFACE_COUNT
];
843 if (FAILED(IDirectXVideoDecoderService_CreateSurface(va
->vs
,
846 va
->surface_count
- 1,
850 DXVA2_VideoDecoderRenderTarget
,
853 msg_Err(va
->log
, "IDirectXVideoAccelerationService_CreateSurface failed");
854 va
->surface_count
= 0;
857 for (unsigned i
= 0; i
< va
->surface_count
; i
++) {
858 vlc_va_surface_t
*surface
= &va
->surface
[i
];
859 surface
->d3d
= surface_list
[i
];
860 surface
->refcount
= 0;
863 msg_Dbg(va
->log
, "IDirectXVideoAccelerationService_CreateSurface succeed with %d surfaces (%dx%d)",
864 va
->surface_count
, fmt
->i_width
, fmt
->i_height
);
868 ZeroMemory(&dsc
, sizeof(dsc
));
869 dsc
.SampleWidth
= fmt
->i_width
;
870 dsc
.SampleHeight
= fmt
->i_height
;
871 dsc
.Format
= va
->render
;
872 if (fmt
->i_frame_rate
> 0 && fmt
->i_frame_rate_base
> 0) {
873 dsc
.InputSampleFreq
.Numerator
= fmt
->i_frame_rate
;
874 dsc
.InputSampleFreq
.Denominator
= fmt
->i_frame_rate_base
;
876 dsc
.InputSampleFreq
.Numerator
= 0;
877 dsc
.InputSampleFreq
.Denominator
= 0;
879 dsc
.OutputFrameFreq
= dsc
.InputSampleFreq
;
880 dsc
.UABProtectionLevel
= FALSE
;
883 /* FIXME I am unsure we can let unknown everywhere */
884 DXVA2_ExtendedFormat
*ext
= &dsc
.SampleFormat
;
885 ext
->SampleFormat
= 0;//DXVA2_SampleUnknown;
886 ext
->VideoChromaSubsampling
= 0;//DXVA2_VideoChromaSubsampling_Unknown;
887 ext
->NominalRange
= 0;//DXVA2_NominalRange_Unknown;
888 ext
->VideoTransferMatrix
= 0;//DXVA2_VideoTransferMatrix_Unknown;
889 ext
->VideoLighting
= 0;//DXVA2_VideoLighting_Unknown;
890 ext
->VideoPrimaries
= 0;//DXVA2_VideoPrimaries_Unknown;
891 ext
->VideoTransferFunction
= 0;//DXVA2_VideoTransFunc_Unknown;
893 /* List all configurations available for the decoder */
895 DXVA2_ConfigPictureDecode
*cfg_list
= NULL
;
896 if (FAILED(IDirectXVideoDecoderService_GetDecoderConfigurations(va
->vs
,
902 msg_Err(va
->log
, "IDirectXVideoDecoderService_GetDecoderConfigurations failed");
905 msg_Dbg(va
->log
, "we got %d decoder configurations", cfg_count
);
907 /* Select the best decoder configuration */
909 for (unsigned i
= 0; i
< cfg_count
; i
++) {
910 const DXVA2_ConfigPictureDecode
*cfg
= &cfg_list
[i
];
913 msg_Dbg(va
->log
, "configuration[%d] ConfigBitstreamRaw %d",
914 i
, cfg
->ConfigBitstreamRaw
);
918 if (cfg
->ConfigBitstreamRaw
== 1)
920 else if (codec_id
== CODEC_ID_H264
&& cfg
->ConfigBitstreamRaw
== 2)
924 if (IsEqualGUID(&cfg
->guidConfigBitstreamEncryption
, &DXVA_NoEncrypt
))
927 if (cfg_score
< score
) {
932 CoTaskMemFree(cfg_list
);
933 if (cfg_score
<= 0) {
934 msg_Err(va
->log
, "Failed to find a supported decoder configuration");
938 /* Create the decoder */
939 IDirectXVideoDecoder
*decoder
;
940 if (FAILED(IDirectXVideoDecoderService_CreateVideoDecoder(va
->vs
,
947 msg_Err(va
->log
, "IDirectXVideoDecoderService_CreateVideoDecoder failed");
950 va
->decoder
= decoder
;
951 msg_Dbg(va
->log
, "IDirectXVideoDecoderService_CreateVideoDecoder succeed");
954 static void DxDestroyVideoDecoder(vlc_va_dxva2_t
*va
)
957 IDirectXVideoDecoder_Release(va
->decoder
);
960 for (unsigned i
= 0; i
< va
->surface_count
; i
++)
961 IDirect3DSurface9_Release(va
->surface
[i
].d3d
);
962 va
->surface_count
= 0;
964 static int DxResetVideoDecoder(vlc_va_dxva2_t
*va
)
966 msg_Err(va
->log
, "DxResetVideoDecoder unimplemented");
970 static void DxCreateVideoConversion(vlc_va_dxva2_t
*va
)
972 switch (va
->render
) {
973 case MAKEFOURCC('N','V','1','2'):
974 va
->output
= MAKEFOURCC('Y','V','1','2');
977 va
->output
= va
->render
;
980 CopyInitCache(&va
->surface_cache
, va
->surface_width
);
982 static void DxDestroyVideoConversion(vlc_va_dxva2_t
*va
)
984 CopyCleanCache(&va
->surface_cache
);
987 vlc_va_t
*vlc_va_NewDxva2(vlc_object_t
*log
, int codec_id
)