MythTV master
dxva2decoder.cpp
Go to the documentation of this file.
1#include <QString>
2#include <QLibrary>
3
5#include "initguid.h"
7#include "dxva2decoder.h"
8
9#ifndef __MINGW32__
11{
12 0xfc51a551, 0xd5e7, 0x11d9, {0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02}
13};
14#endif
15
16static inline QString toString(const GUID& guid)
17{
18 return QString("%1-%2-%3-%4%5-%6%7%8%9%10%11")
19 .arg(guid.Data1, 8, 16, QLatin1Char('0'))
20 .arg(guid.Data2, 4, 16, QLatin1Char('0'))
21 .arg(guid.Data3, 4, 16, QLatin1Char('0'))
22 .arg(guid.Data4[0], 2, 16, QLatin1Char('0'))
23 .arg(guid.Data4[1], 2, 16, QLatin1Char('0'))
24 .arg(guid.Data4[2], 2, 16, QLatin1Char('0'))
25 .arg(guid.Data4[3], 2, 16, QLatin1Char('0'))
26 .arg(guid.Data4[4], 2, 16, QLatin1Char('0'))
27 .arg(guid.Data4[5], 2, 16, QLatin1Char('0'))
28 .arg(guid.Data4[6], 2, 16, QLatin1Char('0'))
29 .arg(guid.Data4[7], 2, 16, QLatin1Char('0')).toUpper();
30}
31
32#define LOC QString("DXVA2: ")
33#define ERR QString("DXVA2 Error: ")
34
35#ifndef __MINGW32__
36DEFINE_GUID(DXVA2_ModeH264_A, 0x1b81be64, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
37DEFINE_GUID(DXVA2_ModeH264_B, 0x1b81be65, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
38DEFINE_GUID(DXVA2_ModeH264_C, 0x1b81be66, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
39DEFINE_GUID(DXVA2_ModeH264_D, 0x1b81be67, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
40DEFINE_GUID(DXVA2_ModeH264_E, 0x1b81be68, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
41DEFINE_GUID(DXVA2_ModeH264_F, 0x1b81be69, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
42
43DEFINE_GUID(DXVA2_ModeWMV8_A, 0x1b81be80, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
44DEFINE_GUID(DXVA2_ModeWMV8_B, 0x1b81be81, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
45
46DEFINE_GUID(DXVA2_ModeWMV9_A, 0x1b81be90, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
47DEFINE_GUID(DXVA2_ModeWMV9_B, 0x1b81be91, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
48DEFINE_GUID(DXVA2_ModeWMV9_C, 0x1b81be94, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
49
50DEFINE_GUID(DXVA2_ModeVC1_A, 0x1b81beA0, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
51DEFINE_GUID(DXVA2_ModeVC1_B, 0x1b81beA1, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
52DEFINE_GUID(DXVA2_ModeVC1_C, 0x1b81beA2, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
53DEFINE_GUID(DXVA2_ModeVC1_D, 0x1b81beA3, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
54
55DEFINE_GUID(DXVA2_ModeMPEG2_MoComp, 0xe6a9f44b, 0x61b0, 0x4563, 0x9e,0xa4,0x63,0xd2,0xa3,0xc6,0xfe,0x66);
56DEFINE_GUID(DXVA2_ModeMPEG2_IDCT, 0xbf22ad00, 0x03ea, 0x4690, 0x80,0x77,0x47,0x33,0x46,0x20,0x9b,0x7e);
57DEFINE_GUID(DXVA2_ModeMPEG2_VLD, 0xee27417f, 0x5e28, 0x4e65, 0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9);
58#endif
59
60#define DXVA2_ModeWMV8_PostProc DXVA2_ModeWMV8_A
61#define DXVA2_ModeWMV8_MoComp DXVA2_ModeWMV8_B
62
63#define DXVA2_ModeWMV9_PostProc DXVA2_ModeWMV9_A
64#define DXVA2_ModeWMV9_MoComp DXVA2_ModeWMV9_B
65#define DXVA2_ModeWMV9_IDCT DXVA2_ModeWMV9_C
66
67#define DXVA2_ModeVC1_PostProc DXVA2_ModeVC1_A
68#define DXVA2_ModeVC1_MoComp DXVA2_ModeVC1_B
69#define DXVA2_ModeVC1_IDCT DXVA2_ModeVC1_C
70#define DXVA2_ModeVC1_VLD DXVA2_ModeVC1_D
71
72#define DXVA2_ModeH264_MoComp_NoFGT DXVA2_ModeH264_A
73#define DXVA2_ModeH264_MoComp_FGT DXVA2_ModeH264_B
74#define DXVA2_ModeH264_IDCT_NoFGT DXVA2_ModeH264_C
75#define DXVA2_ModeH264_IDCT_FGT DXVA2_ModeH264_D
76#define DXVA2_ModeH264_VLD_NoFGT DXVA2_ModeH264_E
77#define DXVA2_ModeH264_VLD_FGT DXVA2_ModeH264_F
78
79DEFINE_GUID(DXVA2_Intel_ModeH264_A, 0x604F8E64, 0x4951, 0x4c54, 0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
80DEFINE_GUID(DXVA2_Intel_ModeH264_C, 0x604F8E66, 0x4951, 0x4c54, 0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
81DEFINE_GUID(DXVA2_Intel_ModeH264_E, 0x604F8E68, 0x4951, 0x4c54, 0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
82DEFINE_GUID(DXVA2_Intel_ModeVC1_E , 0xBCC5DB6D, 0xA2B6, 0x4AF0, 0xAC,0xE4,0xAD,0xB1,0xF7,0x87,0xBC,0x89);
83
84struct dxva2_mode {
85 const QString name;
86 const GUID *guid;
88};
89
90static const dxva2_mode dxva2_modes[] =
91{
92 {"MPEG2 VLD", &DXVA2_ModeMPEG2_VLD, kCodec_MPEG2_DXVA2},
93 {"MPEG2 MoComp", &DXVA2_ModeMPEG2_MoComp, kCodec_NONE},
94 {"MPEG2 IDCT", &DXVA2_ModeMPEG2_IDCT, kCodec_NONE},
95
96 {"H.264 VLD, FGT", &DXVA2_ModeH264_F, kCodec_H264_DXVA2},
97 {"H.264 VLD, no FGT", &DXVA2_ModeH264_E, kCodec_H264_DXVA2},
98 {"H.264 IDCT, FGT", &DXVA2_ModeH264_D, kCodec_NONE},
99 {"H.264 IDCT, no FGT", &DXVA2_ModeH264_C, kCodec_NONE},
100 {"H.264 MoComp, FGT", &DXVA2_ModeH264_B, kCodec_NONE},
101 {"H.264 MoComp, no FGT", &DXVA2_ModeH264_A, kCodec_NONE},
102
103 {"WMV8 MoComp", &DXVA2_ModeWMV8_B, kCodec_NONE},
104 {"WMV8 post processing", &DXVA2_ModeWMV8_A, kCodec_NONE},
105
106 {"WMV9 IDCT", &DXVA2_ModeWMV9_C, kCodec_NONE},
107 {"WMV9 MoComp", &DXVA2_ModeWMV9_B, kCodec_NONE},
108 {"WMV9 post processing", &DXVA2_ModeWMV9_A, kCodec_NONE},
109
110 {"VC-1 VLD", &DXVA2_ModeVC1_D, kCodec_VC1_DXVA2},
111 {"VC-1 VLD", &DXVA2_ModeVC1_D, kCodec_WMV3_DXVA2},
112 {"VC-1 IDCT", &DXVA2_ModeVC1_C, kCodec_NONE},
113 {"VC-1 MoComp", &DXVA2_ModeVC1_B, kCodec_NONE},
114 {"VC-1 post processing", &DXVA2_ModeVC1_A, kCodec_NONE},
115
116 {"Intel H.264 VLD, no FGT", &DXVA2_Intel_ModeH264_E, kCodec_H264_DXVA2},
117 {"Intel H.264 IDCT, no FGT", &DXVA2_Intel_ModeH264_C, kCodec_NONE},
118 {"Intel H.264 MoComp, no FGT", &DXVA2_Intel_ModeH264_A, kCodec_NONE},
119 {"Intel VC-1 VLD", &DXVA2_Intel_ModeVC1_E, kCodec_VC1_DXVA2},
120
121 {"", nullptr, kCodec_NONE}
122};
123
124#define CREATE_CHECK(arg1, arg2) \
125 if (ok) \
126 { \
127 ok = arg1; \
128 if (!ok) \
129 LOG(VB_GENERAL, LOG_ERR, LOC + (arg2)); \
130 }
131
133 uint width, uint height)
134 : m_codec_id(codec_id), m_width(width), m_height(height)
135{
136 memset(&m_format, 0, sizeof(DXVA2_VideoDesc));
137 memset(&m_context, 0, sizeof(dxva_context));
138 memset(&m_config, 0, sizeof(DXVA2_ConfigPictureDecode));
139 m_context.cfg = &m_config;
140 m_context.surface_count = num_bufs;
141 m_context.surface = new IDirect3DSurface9*[num_bufs];
142 for (uint i = 0; i < num_bufs; i++)
143 m_context.surface[i] = nullptr;
144}
145
147{
151}
152
154{
155 bool ok = true;
156 CREATE_CHECK(m_width > 0, "Invalid width.")
157 CREATE_CHECK(m_height > 0, "Invalid height.")
158 CREATE_CHECK(CreateVideoService(render), "Failed to create video service.")
159 CREATE_CHECK(GetInputOutput(), "Failed to find input/output combination.")
160 InitFormat();
161 CREATE_CHECK(GetDecoderConfig(), "Failed to find a raw input bitstream.")
162 CREATE_CHECK(CreateSurfaces(), "Failed to create surfaces.")
163 CREATE_CHECK(CreateDecoder(), "Failed to create decoder.")
164 return ok;
165}
166
167using DXVA2CreateVideoServicePtr = HRESULT (__stdcall *)(IDirect3DDevice9* pDD,
168 REFIID riid,
169 void** ppService);
170
172{
173 // Loads the DXVA2 library
174 DXVA2CreateVideoServicePtr create_video_service =
175 (DXVA2CreateVideoServicePtr)MythRenderD3D9::ResolveAddress("DXVA2", "DXVA2CreateVideoService");
176 if (!create_video_service)
177 return false;
178
180 if (!m_deviceManager)
181 {
182 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get device manager.");
183 return false;
184 }
185
186 HRESULT hr = IDirect3DDeviceManager9_OpenDeviceHandle(m_deviceManager, &m_device);
187 if (FAILED(hr))
188 {
189 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get device handle.");
190 return false;
191 }
192
193 hr = IDirect3DDeviceManager9_GetVideoService(m_deviceManager,
194 m_device,
196 (void**)&m_service);
197 if (FAILED(hr))
198 {
199 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get video service.");
200 return false;
201 }
202
203 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Created DXVA2 video service.");
204 return true;
205}
206
208{
209 if (m_device)
210 IDirect3DDeviceManager9_CloseDeviceHandle(m_deviceManager, m_device);
211 if (m_service)
212 IDirectXVideoDecoderService_Release(m_service);
213 m_deviceManager = nullptr;
214 m_device = nullptr;
215 m_service = nullptr;
216}
217
219{
220 if (!m_service)
221 return false;
222 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Looking for support for %1")
223 .arg(toString(m_codec_id)));
224 uint input_count;
225 GUID *input_list;
226 m_format.Format = D3DFMT_UNKNOWN;
227 IDirectXVideoDecoderService_GetDecoderDeviceGuids(
228 m_service, &input_count, &input_list);
229
230 for (const dxva2_mode* mode = dxva2_modes;
231 !mode->name.isEmpty() && m_format.Format == D3DFMT_UNKNOWN;
232 mode++)
233 {
234 if (mode->codec != m_codec_id)
235 continue;
236 for (uint j = 0; j < input_count; j++)
237 {
238 if (IsEqualGUID(input_list[j], *mode->guid))
239 {
240 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Testing %1")
241 .arg(mode->name));
242 if (TestTarget(input_list[j]))
243 break;
244 }
245 }
246 }
247
248 return m_format.Format != D3DFMT_UNKNOWN;
249}
250
251bool DXVA2Decoder::TestTarget(const GUID &guid)
252{
253 if (!m_service)
254 return false;
255 uint output_count = 0;
256 D3DFORMAT *output_list = nullptr;
257 IDirectXVideoDecoderService_GetDecoderRenderTargets(
258 m_service, guid, &output_count, &output_list);
259 for(uint i = 0; i < output_count; i++)
260 {
261 if(output_list[i] == MAKEFOURCC('Y','V','1','2') ||
262 output_list[i] == MAKEFOURCC('N','V','1','2'))
263 {
264 m_input = guid;
265 m_format.Format = output_list[i];
266 return true;
267 }
268 }
269 return false;
270}
271
273{
274 m_format.SampleWidth = m_width;
275 m_format.SampleHeight = m_height;
276 m_format.InputSampleFreq.Numerator = 0;
277 m_format.InputSampleFreq.Denominator = 0;
278 m_format.OutputFrameFreq = m_format.InputSampleFreq;
279 m_format.UABProtectionLevel = false;
280 m_format.Reserved = 0;
281}
282
284{
285 if (!m_service)
286 return false;
287
288 uint cfg_count = 0;
289 DXVA2_ConfigPictureDecode *cfg_list = nullptr;
290 IDirectXVideoDecoderService_GetDecoderConfigurations(
291 m_service, m_input, &m_format, nullptr, &cfg_count, &cfg_list);
292
293 DXVA2_ConfigPictureDecode config = {};
294 uint bitstream = 1;
295 for (uint i = 0; i < cfg_count; i++)
296 {
297 // select first available
298 if (config.ConfigBitstreamRaw == 0 &&
299 cfg_list[i].ConfigBitstreamRaw != 0)
300 {
301 config = cfg_list[i];
302 }
303 // overide with preferred if found
304 if (config.ConfigBitstreamRaw != bitstream &&
305 cfg_list[i].ConfigBitstreamRaw == bitstream)
306 {
307 config = cfg_list[i];
308 }
309 }
310 //CoTaskMemFree(cfg_list);
311 if(!config.ConfigBitstreamRaw)
312 return false;
313 m_config = config;
314 //*const_cast<DXVA2_ConfigPictureDecode*>(m_context.cfg) = config;
315 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found bitstream type %1")
316 .arg(m_context.cfg->ConfigBitstreamRaw));
317 return true;
318}
319
321{
322 if (!m_service || !m_context.surface)
323 return false;
324
325 HRESULT hr = IDirectXVideoDecoderService_CreateSurface(
326 m_service, (m_width + 15) & ~15, (m_height + 15) & ~15,
327 m_context.surface_count - 1, m_format.Format,
328 D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget,
329 m_context.surface, nullptr);
330
331 if (FAILED(hr))
332 return false;
333
334 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created %1 decoder surfaces.")
335 .arg(m_context.surface_count));
336
337 return true;
338}
339
341{
342 for (uint i = 0; i < m_context.surface_count; i++)
343 {
344 if (m_context.surface[i])
345 {
346 m_context.surface[i]->Release();
347 m_context.surface[i] = nullptr;
348 }
349 }
350 m_context.surface = nullptr;
351 m_context.surface_count = 0;
352}
353
355{
356 if (!m_service || !m_context.surface)
357 return false;
358
359 HRESULT hr = IDirectXVideoDecoderService_CreateVideoDecoder(
361 const_cast<DXVA2_ConfigPictureDecode*>(m_context.cfg),
362 m_context.surface, m_context.surface_count, &m_context.decoder);
363
364 if (FAILED(hr))
365 return false;
366
367 LOG(VB_PLAYBACK, LOG_INFO, LOC +
368 QString("Created decoder: %1->%2x%3 (%4 surfaces)")
369 .arg(toString(m_codec_id)).arg(m_width).arg(m_height)
370 .arg(m_context.surface_count));
371 return true;
372}
373
375{
376 if (m_context.decoder)
377 IDirectXVideoDecoder_Release(m_context.decoder);
378 m_context.decoder = nullptr;
379}
380
382{
383 if (num >= m_context.surface_count)
384 return nullptr;
385 return (void*)m_context.surface[num];
386}
bool CreateDecoder(void)
bool Init(MythRenderD3D9 *render)
MythCodecID m_codec_id
Definition: dxva2decoder.h:39
DXVA2_ConfigPictureDecode m_config
Definition: dxva2decoder.h:38
DXVA2Decoder(uint num_bufs, MythCodecID codec_id, uint width, uint height)
bool CreateSurfaces(void)
void DestroySurfaces(void)
void InitFormat(void)
IDirectXVideoDecoderService * m_service
Definition: dxva2decoder.h:36
bool GetInputOutput(void)
struct dxva_context m_context
Definition: dxva2decoder.h:37
void DestroyDecoder(void)
void * GetSurface(uint num)
void DestroyVideoService(void)
HANDLE m_device
Definition: dxva2decoder.h:35
bool GetDecoderConfig(void)
bool TestTarget(const GUID &guid)
DXVA2_VideoDesc m_format
Definition: dxva2decoder.h:41
bool CreateVideoService(MythRenderD3D9 *render)
IDirect3DDeviceManager9 * m_deviceManager
Definition: dxva2decoder.h:34
static void * ResolveAddress(const char *lib, const char *proc)
IDirect3DDeviceManager9 * GetDeviceManager(void)
HRESULT(__stdcall *)(IDirect3DDevice9 *pDD, REFIID riid, void **ppService) DXVA2CreateVideoServicePtr
#define LOC
static QString toString(const GUID &guid)
#define CREATE_CHECK(arg1, arg2)
static const dxva2_mode dxva2_modes[]
static const GUID IID_IDirectXVideoDecoderService
DEFINE_GUID(DXVA2_ModeH264_A, 0x1b81be64, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5)
unsigned int uint
Definition: freesurround.h:24
MythCodecID
Definition: mythcodecid.h:14
@ kCodec_VC1_DXVA2
Definition: mythcodecid.h:109
@ kCodec_NONE
Definition: mythcodecid.h:17
@ kCodec_MPEG2_DXVA2
Definition: mythcodecid.h:105
@ kCodec_H264_DXVA2
Definition: mythcodecid.h:108
@ kCodec_WMV3_DXVA2
Definition: mythcodecid.h:110
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
const GUID * guid
const QString name
MythCodecID codec