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