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
9static inline QString toString(const GUID& guid)
10{
11 return QString("%1-%2-%3-%4%5-%6%7%8%9%10%11")
12 .arg(guid.Data1, 8, 16, QLatin1Char('0'))
13 .arg(guid.Data2, 4, 16, QLatin1Char('0'))
14 .arg(guid.Data3, 4, 16, QLatin1Char('0'))
15 .arg(guid.Data4[0], 2, 16, QLatin1Char('0'))
16 .arg(guid.Data4[1], 2, 16, QLatin1Char('0'))
17 .arg(guid.Data4[2], 2, 16, QLatin1Char('0'))
18 .arg(guid.Data4[3], 2, 16, QLatin1Char('0'))
19 .arg(guid.Data4[4], 2, 16, QLatin1Char('0'))
20 .arg(guid.Data4[5], 2, 16, QLatin1Char('0'))
21 .arg(guid.Data4[6], 2, 16, QLatin1Char('0'))
22 .arg(guid.Data4[7], 2, 16, QLatin1Char('0')).toUpper();
23}
24
25#define LOC QString("DXVA2: ")
26#define ERR QString("DXVA2 Error: ")
27
28#define DXVA2_ModeWMV8_PostProc DXVA2_ModeWMV8_A
29#define DXVA2_ModeWMV8_MoComp DXVA2_ModeWMV8_B
30
31#define DXVA2_ModeWMV9_PostProc DXVA2_ModeWMV9_A
32#define DXVA2_ModeWMV9_MoComp DXVA2_ModeWMV9_B
33#define DXVA2_ModeWMV9_IDCT DXVA2_ModeWMV9_C
34
35#define DXVA2_ModeVC1_PostProc DXVA2_ModeVC1_A
36#define DXVA2_ModeVC1_MoComp DXVA2_ModeVC1_B
37#define DXVA2_ModeVC1_IDCT DXVA2_ModeVC1_C
38#define DXVA2_ModeVC1_VLD DXVA2_ModeVC1_D
39
40#define DXVA2_ModeH264_MoComp_NoFGT DXVA2_ModeH264_A
41#define DXVA2_ModeH264_MoComp_FGT DXVA2_ModeH264_B
42#define DXVA2_ModeH264_IDCT_NoFGT DXVA2_ModeH264_C
43#define DXVA2_ModeH264_IDCT_FGT DXVA2_ModeH264_D
44#define DXVA2_ModeH264_VLD_NoFGT DXVA2_ModeH264_E
45#define DXVA2_ModeH264_VLD_FGT DXVA2_ModeH264_F
46
47DEFINE_GUID(DXVA2_Intel_ModeH264_A, 0x604F8E64, 0x4951, 0x4c54, 0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
48DEFINE_GUID(DXVA2_Intel_ModeH264_C, 0x604F8E66, 0x4951, 0x4c54, 0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
49DEFINE_GUID(DXVA2_Intel_ModeH264_E, 0x604F8E68, 0x4951, 0x4c54, 0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
50DEFINE_GUID(DXVA2_Intel_ModeVC1_E , 0xBCC5DB6D, 0xA2B6, 0x4AF0, 0xAC,0xE4,0xAD,0xB1,0xF7,0x87,0xBC,0x89);
51
52struct dxva2_mode {
53 const QString name;
54 const GUID *guid;
56};
57
58static const dxva2_mode dxva2_modes[] =
59{
60 {"MPEG2 VLD", &DXVA2_ModeMPEG2_VLD, kCodec_MPEG2_DXVA2},
61 {"MPEG2 MoComp", &DXVA2_ModeMPEG2_MoComp, kCodec_NONE},
62 {"MPEG2 IDCT", &DXVA2_ModeMPEG2_IDCT, kCodec_NONE},
63
64 {"H.264 VLD, FGT", &DXVA2_ModeH264_F, kCodec_H264_DXVA2},
65 {"H.264 VLD, no FGT", &DXVA2_ModeH264_E, kCodec_H264_DXVA2},
66 {"H.264 IDCT, FGT", &DXVA2_ModeH264_D, kCodec_NONE},
67 {"H.264 IDCT, no FGT", &DXVA2_ModeH264_C, kCodec_NONE},
68 {"H.264 MoComp, FGT", &DXVA2_ModeH264_B, kCodec_NONE},
69 {"H.264 MoComp, no FGT", &DXVA2_ModeH264_A, kCodec_NONE},
70
71 {"WMV8 MoComp", &DXVA2_ModeWMV8_B, kCodec_NONE},
72 {"WMV8 post processing", &DXVA2_ModeWMV8_A, kCodec_NONE},
73
74 {"WMV9 IDCT", &DXVA2_ModeWMV9_C, kCodec_NONE},
75 {"WMV9 MoComp", &DXVA2_ModeWMV9_B, kCodec_NONE},
76 {"WMV9 post processing", &DXVA2_ModeWMV9_A, kCodec_NONE},
77
78 {"VC-1 VLD", &DXVA2_ModeVC1_D, kCodec_VC1_DXVA2},
79 {"VC-1 VLD", &DXVA2_ModeVC1_D, kCodec_WMV3_DXVA2},
80 {"VC-1 IDCT", &DXVA2_ModeVC1_C, kCodec_NONE},
81 {"VC-1 MoComp", &DXVA2_ModeVC1_B, kCodec_NONE},
82 {"VC-1 post processing", &DXVA2_ModeVC1_A, kCodec_NONE},
83
84 {"Intel H.264 VLD, no FGT", &DXVA2_Intel_ModeH264_E, kCodec_H264_DXVA2},
85 {"Intel H.264 IDCT, no FGT", &DXVA2_Intel_ModeH264_C, kCodec_NONE},
86 {"Intel H.264 MoComp, no FGT", &DXVA2_Intel_ModeH264_A, kCodec_NONE},
87 {"Intel VC-1 VLD", &DXVA2_Intel_ModeVC1_E, kCodec_VC1_DXVA2},
88
89 {"", nullptr, kCodec_NONE}
90};
91
92#define CREATE_CHECK(arg1, arg2) \
93 if (ok) \
94 { \
95 ok = arg1; \
96 if (!ok) \
97 LOG(VB_GENERAL, LOG_ERR, LOC + (arg2)); \
98 }
99
101 uint width, uint height)
102 : m_codec_id(codec_id), m_width(width), m_height(height)
103{
104 memset(&m_format, 0, sizeof(DXVA2_VideoDesc));
105 memset(&m_context, 0, sizeof(dxva_context));
106 memset(&m_config, 0, sizeof(DXVA2_ConfigPictureDecode));
107 m_context.cfg = &m_config;
108 m_context.surface_count = num_bufs;
109 m_context.surface = new IDirect3DSurface9*[num_bufs];
110 for (uint i = 0; i < num_bufs; i++)
111 m_context.surface[i] = nullptr;
112}
113
115{
119}
120
122{
123 bool ok = true;
124 CREATE_CHECK(m_width > 0, "Invalid width.")
125 CREATE_CHECK(m_height > 0, "Invalid height.")
126 CREATE_CHECK(CreateVideoService(render), "Failed to create video service.")
127 CREATE_CHECK(GetInputOutput(), "Failed to find input/output combination.")
128 InitFormat();
129 CREATE_CHECK(GetDecoderConfig(), "Failed to find a raw input bitstream.")
130 CREATE_CHECK(CreateSurfaces(), "Failed to create surfaces.")
131 CREATE_CHECK(CreateDecoder(), "Failed to create decoder.")
132 return ok;
133}
134
135using DXVA2CreateVideoServicePtr = HRESULT (__stdcall *)(IDirect3DDevice9* pDD,
136 REFIID riid,
137 void** ppService);
138
140{
141 // Loads the DXVA2 library
142 DXVA2CreateVideoServicePtr create_video_service =
143 (DXVA2CreateVideoServicePtr)MythRenderD3D9::ResolveAddress("DXVA2", "DXVA2CreateVideoService");
144 if (!create_video_service)
145 return false;
146
148 if (!m_deviceManager)
149 {
150 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get device manager.");
151 return false;
152 }
153
154 HRESULT hr = IDirect3DDeviceManager9_OpenDeviceHandle(m_deviceManager, &m_device);
155 if (FAILED(hr))
156 {
157 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get device handle.");
158 return false;
159 }
160
161 hr = IDirect3DDeviceManager9_GetVideoService(m_deviceManager,
162 m_device,
163 IID_IDirectXVideoDecoderService,
164 (void**)&m_service);
165 if (FAILED(hr))
166 {
167 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get video service.");
168 return false;
169 }
170
171 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Created DXVA2 video service.");
172 return true;
173}
174
176{
177 if (m_device)
178 IDirect3DDeviceManager9_CloseDeviceHandle(m_deviceManager, m_device);
179 if (m_service)
180 IDirectXVideoDecoderService_Release(m_service);
181 m_deviceManager = nullptr;
182 m_device = nullptr;
183 m_service = nullptr;
184}
185
187{
188 if (!m_service)
189 return false;
190 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Looking for support for %1")
191 .arg(toString(m_codec_id)));
192 uint input_count;
193 GUID *input_list;
194 m_format.Format = D3DFMT_UNKNOWN;
195 IDirectXVideoDecoderService_GetDecoderDeviceGuids(
196 m_service, &input_count, &input_list);
197
198 for (const dxva2_mode* mode = dxva2_modes;
199 !mode->name.isEmpty() && m_format.Format == D3DFMT_UNKNOWN;
200 mode++)
201 {
202 if (mode->codec != m_codec_id)
203 continue;
204 for (uint j = 0; j < input_count; j++)
205 {
206 if (IsEqualGUID(input_list[j], *mode->guid))
207 {
208 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Testing %1")
209 .arg(mode->name));
210 if (TestTarget(input_list[j]))
211 break;
212 }
213 }
214 }
215
216 return m_format.Format != D3DFMT_UNKNOWN;
217}
218
219bool DXVA2Decoder::TestTarget(const GUID &guid)
220{
221 if (!m_service)
222 return false;
223 uint output_count = 0;
224 D3DFORMAT *output_list = nullptr;
225 IDirectXVideoDecoderService_GetDecoderRenderTargets(
226 m_service, guid, &output_count, &output_list);
227 for(uint i = 0; i < output_count; i++)
228 {
229 if(output_list[i] == MAKEFOURCC('Y','V','1','2') ||
230 output_list[i] == MAKEFOURCC('N','V','1','2'))
231 {
232 m_input = guid;
233 m_format.Format = output_list[i];
234 return true;
235 }
236 }
237 return false;
238}
239
241{
242 m_format.SampleWidth = m_width;
243 m_format.SampleHeight = m_height;
244 m_format.InputSampleFreq.Numerator = 0;
245 m_format.InputSampleFreq.Denominator = 0;
246 m_format.OutputFrameFreq = m_format.InputSampleFreq;
247 m_format.UABProtectionLevel = false;
248 m_format.Reserved = 0;
249}
250
252{
253 if (!m_service)
254 return false;
255
256 uint cfg_count = 0;
257 DXVA2_ConfigPictureDecode *cfg_list = nullptr;
258 IDirectXVideoDecoderService_GetDecoderConfigurations(
259 m_service, m_input, &m_format, nullptr, &cfg_count, &cfg_list);
260
261 DXVA2_ConfigPictureDecode config = {};
262 uint bitstream = 1;
263 for (uint i = 0; i < cfg_count; i++)
264 {
265 // select first available
266 if (config.ConfigBitstreamRaw == 0 &&
267 cfg_list[i].ConfigBitstreamRaw != 0)
268 {
269 config = cfg_list[i];
270 }
271 // overide with preferred if found
272 if (config.ConfigBitstreamRaw != bitstream &&
273 cfg_list[i].ConfigBitstreamRaw == bitstream)
274 {
275 config = cfg_list[i];
276 }
277 }
278 //CoTaskMemFree(cfg_list);
279 if(!config.ConfigBitstreamRaw)
280 return false;
281 m_config = config;
282 //*const_cast<DXVA2_ConfigPictureDecode*>(m_context.cfg) = config;
283 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found bitstream type %1")
284 .arg(m_context.cfg->ConfigBitstreamRaw));
285 return true;
286}
287
289{
290 if (!m_service || !m_context.surface)
291 return false;
292
293 HRESULT hr = IDirectXVideoDecoderService_CreateSurface(
294 m_service, (m_width + 15) & ~15, (m_height + 15) & ~15,
295 m_context.surface_count - 1, m_format.Format,
296 D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget,
297 m_context.surface, nullptr);
298
299 if (FAILED(hr))
300 return false;
301
302 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created %1 decoder surfaces.")
303 .arg(m_context.surface_count));
304
305 return true;
306}
307
309{
310 for (uint i = 0; i < m_context.surface_count; i++)
311 {
312 if (m_context.surface[i])
313 {
314 m_context.surface[i]->Release();
315 m_context.surface[i] = nullptr;
316 }
317 }
318 m_context.surface = nullptr;
319 m_context.surface_count = 0;
320}
321
323{
324 if (!m_service || !m_context.surface)
325 return false;
326
327 HRESULT hr = IDirectXVideoDecoderService_CreateVideoDecoder(
329 const_cast<DXVA2_ConfigPictureDecode*>(m_context.cfg),
330 m_context.surface, m_context.surface_count, &m_context.decoder);
331
332 if (FAILED(hr))
333 return false;
334
335 LOG(VB_PLAYBACK, LOG_INFO, LOC +
336 QString("Created decoder: %1->%2x%3 (%4 surfaces)")
337 .arg(toString(m_codec_id)).arg(m_width).arg(m_height)
338 .arg(m_context.surface_count));
339 return true;
340}
341
343{
344 if (m_context.decoder)
345 IDirectXVideoDecoder_Release(m_context.decoder);
346 m_context.decoder = nullptr;
347}
348
350{
351 if (num >= m_context.surface_count)
352 return nullptr;
353 return (void*)m_context.surface[num];
354}
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)
unsigned int uint
Definition: compat.h:60
HRESULT(__stdcall *)(IDirect3DDevice9 *pDD, REFIID riid, void **ppService) DXVA2CreateVideoServicePtr
#define LOC
static QString toString(const GUID &guid)
Definition: dxva2decoder.cpp:9
#define CREATE_CHECK(arg1, arg2)
static const dxva2_mode dxva2_modes[]
DEFINE_GUID(DXVA2_Intel_ModeH264_A, 0x604F8E64, 0x4951, 0x4c54, 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6)
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