00001 #include <QString>
00002 #include <QLibrary>
00003
00004 #include "mythlogging.h"
00005 #include "initguid.h"
00006 #include "mythrender_d3d9.h"
00007 #include "dxva2decoder.h"
00008
00009 static const GUID IID_IDirectXVideoDecoderService =
00010 {
00011 0xfc51a551, 0xd5e7, 0x11d9, {0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02}
00012 };
00013
00014 static inline QString toString(const GUID& guid)
00015 {
00016 return QString("%1-%2-%3-%4%5-%6%7%8%9%10%11")
00017 .arg(guid.Data1, 8, 16, QLatin1Char('0'))
00018 .arg(guid.Data2, 4, 16, QLatin1Char('0'))
00019 .arg(guid.Data3, 4, 16, QLatin1Char('0'))
00020 .arg(guid.Data4[0], 2, 16, QLatin1Char('0'))
00021 .arg(guid.Data4[1], 2, 16, QLatin1Char('0'))
00022 .arg(guid.Data4[2], 2, 16, QLatin1Char('0'))
00023 .arg(guid.Data4[3], 2, 16, QLatin1Char('0'))
00024 .arg(guid.Data4[4], 2, 16, QLatin1Char('0'))
00025 .arg(guid.Data4[5], 2, 16, QLatin1Char('0'))
00026 .arg(guid.Data4[6], 2, 16, QLatin1Char('0'))
00027 .arg(guid.Data4[7], 2, 16, QLatin1Char('0')).toUpper();
00028 }
00029
00030 #define LOC QString("DXVA2: ")
00031 #define ERR QString("DXVA2 Error: ")
00032
00033 DEFINE_GUID(DXVA2_ModeH264_A, 0x1b81be64, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00034 DEFINE_GUID(DXVA2_ModeH264_B, 0x1b81be65, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00035 DEFINE_GUID(DXVA2_ModeH264_C, 0x1b81be66, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00036 DEFINE_GUID(DXVA2_ModeH264_D, 0x1b81be67, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00037 DEFINE_GUID(DXVA2_ModeH264_E, 0x1b81be68, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00038 DEFINE_GUID(DXVA2_ModeH264_F, 0x1b81be69, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00039
00040 DEFINE_GUID(DXVA2_ModeWMV8_A, 0x1b81be80, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00041 DEFINE_GUID(DXVA2_ModeWMV8_B, 0x1b81be81, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00042
00043 DEFINE_GUID(DXVA2_ModeWMV9_A, 0x1b81be90, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00044 DEFINE_GUID(DXVA2_ModeWMV9_B, 0x1b81be91, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00045 DEFINE_GUID(DXVA2_ModeWMV9_C, 0x1b81be94, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00046
00047 DEFINE_GUID(DXVA2_ModeVC1_A, 0x1b81beA0, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00048 DEFINE_GUID(DXVA2_ModeVC1_B, 0x1b81beA1, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00049 DEFINE_GUID(DXVA2_ModeVC1_C, 0x1b81beA2, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00050 DEFINE_GUID(DXVA2_ModeVC1_D, 0x1b81beA3, 0xa0c7, 0x11d3, 0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
00051
00052 DEFINE_GUID(DXVA2_ModeMPEG2_MoComp, 0xe6a9f44b, 0x61b0, 0x4563, 0x9e,0xa4,0x63,0xd2,0xa3,0xc6,0xfe,0x66);
00053 DEFINE_GUID(DXVA2_ModeMPEG2_IDCT, 0xbf22ad00, 0x03ea, 0x4690, 0x80,0x77,0x47,0x33,0x46,0x20,0x9b,0x7e);
00054 DEFINE_GUID(DXVA2_ModeMPEG2_VLD, 0xee27417f, 0x5e28, 0x4e65, 0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9);
00055
00056 #define DXVA2_ModeWMV8_PostProc DXVA2_ModeWMV8_A
00057 #define DXVA2_ModeWMV8_MoComp DXVA2_ModeWMV8_B
00058
00059 #define DXVA2_ModeWMV9_PostProc DXVA2_ModeWMV9_A
00060 #define DXVA2_ModeWMV9_MoComp DXVA2_ModeWMV9_B
00061 #define DXVA2_ModeWMV9_IDCT DXVA2_ModeWMV9_C
00062
00063 #define DXVA2_ModeVC1_PostProc DXVA2_ModeVC1_A
00064 #define DXVA2_ModeVC1_MoComp DXVA2_ModeVC1_B
00065 #define DXVA2_ModeVC1_IDCT DXVA2_ModeVC1_C
00066 #define DXVA2_ModeVC1_VLD DXVA2_ModeVC1_D
00067
00068 #define DXVA2_ModeH264_MoComp_NoFGT DXVA2_ModeH264_A
00069 #define DXVA2_ModeH264_MoComp_FGT DXVA2_ModeH264_B
00070 #define DXVA2_ModeH264_IDCT_NoFGT DXVA2_ModeH264_C
00071 #define DXVA2_ModeH264_IDCT_FGT DXVA2_ModeH264_D
00072 #define DXVA2_ModeH264_VLD_NoFGT DXVA2_ModeH264_E
00073 #define DXVA2_ModeH264_VLD_FGT DXVA2_ModeH264_F
00074
00075 DEFINE_GUID(DXVA2_Intel_ModeH264_A, 0x604F8E64, 0x4951, 0x4c54, 0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
00076 DEFINE_GUID(DXVA2_Intel_ModeH264_C, 0x604F8E66, 0x4951, 0x4c54, 0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
00077 DEFINE_GUID(DXVA2_Intel_ModeH264_E, 0x604F8E68, 0x4951, 0x4c54, 0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
00078 DEFINE_GUID(DXVA2_Intel_ModeVC1_E , 0xBCC5DB6D, 0xA2B6, 0x4AF0, 0xAC,0xE4,0xAD,0xB1,0xF7,0x87,0xBC,0x89);
00079
00080 typedef struct {
00081 const QString name;
00082 const GUID *guid;
00083 MythCodecID codec;
00084 } dxva2_mode;
00085
00086 static const dxva2_mode dxva2_modes[] =
00087 {
00088 {"MPEG2 VLD", &DXVA2_ModeMPEG2_VLD, kCodec_MPEG2_DXVA2},
00089 {"MPEG2 MoComp", &DXVA2_ModeMPEG2_MoComp, kCodec_NONE},
00090 {"MPEG2 IDCT", &DXVA2_ModeMPEG2_IDCT, kCodec_NONE},
00091
00092 {"H.264 VLD, FGT", &DXVA2_ModeH264_F, kCodec_H264_DXVA2},
00093 {"H.264 VLD, no FGT", &DXVA2_ModeH264_E, kCodec_H264_DXVA2},
00094 {"H.264 IDCT, FGT", &DXVA2_ModeH264_D, kCodec_NONE},
00095 {"H.264 IDCT, no FGT", &DXVA2_ModeH264_C, kCodec_NONE},
00096 {"H.264 MoComp, FGT", &DXVA2_ModeH264_B, kCodec_NONE},
00097 {"H.264 MoComp, no FGT", &DXVA2_ModeH264_A, kCodec_NONE},
00098
00099 {"WMV8 MoComp", &DXVA2_ModeWMV8_B, kCodec_NONE},
00100 {"WMV8 post processing", &DXVA2_ModeWMV8_A, kCodec_NONE},
00101
00102 {"WMV9 IDCT", &DXVA2_ModeWMV9_C, kCodec_NONE},
00103 {"WMV9 MoComp", &DXVA2_ModeWMV9_B, kCodec_NONE},
00104 {"WMV9 post processing", &DXVA2_ModeWMV9_A, kCodec_NONE},
00105
00106 {"VC-1 VLD", &DXVA2_ModeVC1_D, kCodec_VC1_DXVA2},
00107 {"VC-1 VLD", &DXVA2_ModeVC1_D, kCodec_WMV3_DXVA2},
00108 {"VC-1 IDCT", &DXVA2_ModeVC1_C, kCodec_NONE},
00109 {"VC-1 MoComp", &DXVA2_ModeVC1_B, kCodec_NONE},
00110 {"VC-1 post processing", &DXVA2_ModeVC1_A, kCodec_NONE},
00111
00112 {"Intel H.264 VLD, no FGT", &DXVA2_Intel_ModeH264_E, kCodec_H264_DXVA2},
00113 {"Intel H.264 IDCT, no FGT", &DXVA2_Intel_ModeH264_C, kCodec_NONE},
00114 {"Intel H.264 MoComp, no FGT", &DXVA2_Intel_ModeH264_A, kCodec_NONE},
00115 {"Intel VC-1 VLD", &DXVA2_Intel_ModeVC1_E, kCodec_VC1_DXVA2},
00116
00117 {"", NULL, kCodec_NONE}
00118 };
00119
00120 #define CREATE_CHECK(arg1, arg2) \
00121 if (ok) \
00122 { \
00123 ok = arg1; \
00124 if (!ok) \
00125 LOG(VB_GENERAL, LOG_ERR, LOC + arg2); \
00126 }
00127
00128 DXVA2Decoder::DXVA2Decoder(uint num_bufs, MythCodecID codec_id,
00129 uint width, uint height)
00130 : m_deviceManager(NULL), m_device(NULL), m_service(NULL),
00131 m_codec_id(codec_id), m_width(width), m_height(height)
00132 {
00133 memset(&m_format, 0, sizeof(DXVA2_VideoDesc));
00134 memset(&m_context, 0, sizeof(dxva_context));
00135 memset(&m_config, 0, sizeof(DXVA2_ConfigPictureDecode));
00136 m_context.cfg = &m_config;
00137 m_context.surface_count = num_bufs;
00138 m_context.surface = new IDirect3DSurface9*[num_bufs];
00139 for (uint i = 0; i < num_bufs; i++)
00140 m_context.surface[i] = NULL;
00141 }
00142
00143 DXVA2Decoder::~DXVA2Decoder(void)
00144 {
00145 DestroyDecoder();
00146 DestroySurfaces();
00147 DestroyVideoService();
00148 }
00149
00150 bool DXVA2Decoder::Init(MythRenderD3D9* render)
00151 {
00152 bool ok = true;
00153 CREATE_CHECK(m_width > 0, "Invalid width.")
00154 CREATE_CHECK(m_height > 0, "Invalid height.")
00155 CREATE_CHECK(CreateVideoService(render), "Failed to create video service.")
00156 CREATE_CHECK(GetInputOutput(), "Failed to find input/output combination.")
00157 InitFormat();
00158 CREATE_CHECK(GetDecoderConfig(), "Failed to find a raw input bitstream.")
00159 CREATE_CHECK(CreateSurfaces(), "Failed to create surfaces.")
00160 CREATE_CHECK(CreateDecoder(), "Failed to create decoder.")
00161 return ok;
00162 }
00163
00164 typedef HRESULT (__stdcall *DXVA2CreateVideoServicePtr)(IDirect3DDevice9* pDD,
00165 REFIID riid,
00166 void** ppService);
00167
00168 bool DXVA2Decoder::CreateVideoService(MythRenderD3D9* render)
00169 {
00170
00171 DXVA2CreateVideoServicePtr create_video_service =
00172 (DXVA2CreateVideoServicePtr)MythRenderD3D9::ResolveAddress("DXVA2", "DXVA2CreateVideoService");
00173 if (!create_video_service)
00174 return false;
00175
00176 m_deviceManager = render->GetDeviceManager();
00177 if (!m_deviceManager)
00178 {
00179 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get device manager.");
00180 return false;
00181 }
00182
00183 HRESULT hr = IDirect3DDeviceManager9_OpenDeviceHandle(m_deviceManager, &m_device);
00184 if (FAILED(hr))
00185 {
00186 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get device handle.");
00187 return false;
00188 }
00189
00190 hr = IDirect3DDeviceManager9_GetVideoService(m_deviceManager,
00191 m_device,
00192 IID_IDirectXVideoDecoderService,
00193 (void**)&m_service);
00194 if (FAILED(hr))
00195 {
00196 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get video service.");
00197 return false;
00198 }
00199
00200 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Created DXVA2 video service.");
00201 return true;
00202 }
00203
00204 void DXVA2Decoder::DestroyVideoService(void)
00205 {
00206 if (m_device)
00207 IDirect3DDeviceManager9_CloseDeviceHandle(m_deviceManager, m_device);
00208 if (m_service)
00209 IDirectXVideoDecoderService_Release(m_service);
00210 m_deviceManager = NULL;
00211 m_device = NULL;
00212 m_service = NULL;
00213 }
00214
00215 bool DXVA2Decoder::GetInputOutput(void)
00216 {
00217 if (!m_service)
00218 return false;
00219 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Looking for support for %1")
00220 .arg(toString(m_codec_id)));
00221 uint input_count;
00222 GUID *input_list;
00223 m_format.Format = D3DFMT_UNKNOWN;
00224 IDirectXVideoDecoderService_GetDecoderDeviceGuids(
00225 m_service, &input_count, &input_list);
00226
00227 for (const dxva2_mode* mode = dxva2_modes;
00228 !mode->name.isEmpty() && m_format.Format == D3DFMT_UNKNOWN;
00229 mode++)
00230 {
00231 if (mode->codec != m_codec_id)
00232 continue;
00233 for (uint j = 0; j < input_count; j++)
00234 {
00235 if (IsEqualGUID(input_list[j], *mode->guid))
00236 {
00237 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Testing %1")
00238 .arg(mode->name));
00239 if (TestTarget(input_list[j]))
00240 break;
00241 }
00242 }
00243 }
00244
00245 return m_format.Format != D3DFMT_UNKNOWN;
00246 }
00247
00248 bool DXVA2Decoder::TestTarget(const GUID &guid)
00249 {
00250 if (!m_service)
00251 return false;
00252 uint output_count = 0;
00253 D3DFORMAT *output_list = NULL;
00254 IDirectXVideoDecoderService_GetDecoderRenderTargets(
00255 m_service, guid, &output_count, &output_list);
00256 for(uint i = 0; i < output_count; i++)
00257 {
00258 if(output_list[i] == MAKEFOURCC('Y','V','1','2') ||
00259 output_list[i] == MAKEFOURCC('N','V','1','2'))
00260 {
00261 m_input = guid;
00262 m_format.Format = output_list[i];
00263 return true;
00264 }
00265 }
00266 return false;
00267 }
00268
00269 void DXVA2Decoder::InitFormat(void)
00270 {
00271 m_format.SampleWidth = m_width;
00272 m_format.SampleHeight = m_height;
00273 m_format.InputSampleFreq.Numerator = 0;
00274 m_format.InputSampleFreq.Denominator = 0;
00275 m_format.OutputFrameFreq = m_format.InputSampleFreq;
00276 m_format.UABProtectionLevel = false;
00277 m_format.Reserved = 0;
00278 }
00279
00280 bool DXVA2Decoder::GetDecoderConfig(void)
00281 {
00282 if (!m_service)
00283 return false;
00284
00285 uint cfg_count = 0;
00286 DXVA2_ConfigPictureDecode *cfg_list = NULL;
00287 IDirectXVideoDecoderService_GetDecoderConfigurations(
00288 m_service, m_input, &m_format, NULL, &cfg_count, &cfg_list);
00289
00290 DXVA2_ConfigPictureDecode config = {};
00291 uint bitstream = 1;
00292 for (uint i = 0; i < cfg_count; i++)
00293 {
00294
00295 if (config.ConfigBitstreamRaw == 0 &&
00296 cfg_list[i].ConfigBitstreamRaw != 0)
00297 {
00298 config = cfg_list[i];
00299 }
00300
00301 if (config.ConfigBitstreamRaw != bitstream &&
00302 cfg_list[i].ConfigBitstreamRaw == bitstream)
00303 {
00304 config = cfg_list[i];
00305 }
00306 }
00307
00308 if(!config.ConfigBitstreamRaw)
00309 return false;
00310 m_config = config;
00311
00312 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found bitstream type %1")
00313 .arg(m_context.cfg->ConfigBitstreamRaw));
00314 return true;
00315 }
00316
00317 bool DXVA2Decoder::CreateSurfaces(void)
00318 {
00319 if (!m_service || !m_context.surface)
00320 return false;
00321
00322 HRESULT hr = IDirectXVideoDecoderService_CreateSurface(
00323 m_service, (m_width + 15) & ~15, (m_height + 15) & ~15,
00324 m_context.surface_count, m_format.Format,
00325 D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget,
00326 m_context.surface, NULL);
00327
00328 if (FAILED(hr))
00329 return false;
00330
00331 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created %1 decoder surfaces.")
00332 .arg(m_context.surface_count));
00333
00334 for (uint i = 0; i < m_context.surface_count; i++)
00335 m_context.surface[i]->AddRef();
00336 return true;
00337 }
00338
00339 void DXVA2Decoder::DestroySurfaces(void)
00340 {
00341 for (uint i = 0; i < m_context.surface_count; i++)
00342 if (m_context.surface[i])
00343 m_context.surface[i]->Release();
00344 m_context.surface = NULL;
00345 m_context.surface_count = 0;
00346 }
00347
00348 bool DXVA2Decoder::CreateDecoder(void)
00349 {
00350 if (!m_service || !m_context.surface)
00351 return false;
00352
00353 HRESULT hr = IDirectXVideoDecoderService_CreateVideoDecoder(
00354 m_service, m_input, &m_format,
00355 const_cast<DXVA2_ConfigPictureDecode*>(m_context.cfg),
00356 m_context.surface, m_context.surface_count, &m_context.decoder);
00357
00358 if (FAILED(hr))
00359 return false;
00360
00361 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00362 QString("Created decoder: %1->%2x%3 (%4 surfaces)")
00363 .arg(toString(m_codec_id)).arg(m_width).arg(m_height)
00364 .arg(m_context.surface_count));
00365 return true;
00366 }
00367
00368 void DXVA2Decoder::DestroyDecoder(void)
00369 {
00370 if (m_context.decoder)
00371 IDirectXVideoDecoder_Release(m_context.decoder);
00372 m_context.decoder = NULL;
00373 }
00374
00375 void* DXVA2Decoder::GetSurface(uint num)
00376 {
00377 if (num < 0 || num >= m_context.surface_count)
00378 return NULL;
00379 return (void*)m_context.surface[num];
00380 }