Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3869 lines
138 KiB

  1. // Copyright (c) 1994 - 2000 Microsoft Corporation. All Rights Reserved.
  2. #include <streams.h>
  3. #include <vfwmsgs.h>
  4. #ifdef FILTER_DLL
  5. // define the GUIDs for streams and my CLSID in this file
  6. #include <initguid.h>
  7. #endif
  8. #include <dvdmedia.h>
  9. #include <IL21Dec.h>
  10. #include "dvdgb.h"
  11. #include "..\image2\inc\vmrp.h"
  12. // setup data
  13. #ifdef FILTER_DLL
  14. // list of class ids and creator functions for class factory
  15. CFactoryTemplate g_Templates[] = {
  16. { L"DVD Graph Builder"
  17. , &CLSID_DvdGraphBuilder
  18. , CDvdGraphBuilder::CreateInstance
  19. , NULL
  20. , NULL } // self-registering info
  21. };
  22. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
  23. // exported entry points for registration and
  24. // unregistration (in this case they only call
  25. // through to default implmentations).
  26. //
  27. STDAPI DllRegisterServer()
  28. {
  29. return AMovieDllRegisterServer2( TRUE );
  30. }
  31. STDAPI DllUnregisterServer()
  32. {
  33. return AMovieDllRegisterServer2( FALSE );
  34. }
  35. #endif
  36. CDvdGraphBuilder::CDvdGraphBuilder(TCHAR *pName, LPUNKNOWN pUnk, HRESULT * phr)
  37. : CUnknown(pName, pUnk),
  38. m_pGB(NULL),
  39. m_pMapper(NULL),
  40. m_ListFilters(20, 10),
  41. m_ListHWDecs(10, 10),
  42. m_pDVDNav(NULL),
  43. m_pOvM(NULL),
  44. m_pAR(NULL),
  45. m_pVR(NULL),
  46. m_pVMR(NULL),
  47. m_pVPM(NULL),
  48. m_pL21Dec(NULL),
  49. m_bGraphDone(FALSE),
  50. m_bUseVPE(TRUE),
  51. m_bPinNotRendered(FALSE),
  52. m_bDDrawExclMode(FALSE),
  53. m_bTryVMR(TRUE)
  54. {
  55. DbgLog((LOG_TRACE, 3, TEXT("CDvdGraphBuilder::CDvdGraphBuilder()"))) ;
  56. *phr = CreateGraph() ;
  57. }
  58. CDvdGraphBuilder::~CDvdGraphBuilder(void)
  59. {
  60. DbgLog((LOG_TRACE, 3, TEXT("CDvdGraphBuilder::~CDvdGraphBuilder() entering"))) ;
  61. // If we have a graph object
  62. if (m_pGB)
  63. {
  64. StopGraph() ; // make sure the graph is REALYY stopped
  65. // Break the connections and remove all the filters we added from the graph
  66. ClearGraph() ;
  67. // Remove and release OverlayMixer now, if it was there
  68. if (m_pOvM)
  69. {
  70. EXECUTE_ASSERT(SUCCEEDED(m_pGB->RemoveFilter(m_pOvM))) ;
  71. m_pOvM->Release() ;
  72. m_pOvM = NULL ;
  73. }
  74. // Remove and release VMR, if it was there
  75. if (m_pVMR)
  76. {
  77. EXECUTE_ASSERT(SUCCEEDED(m_pGB->RemoveFilter(m_pVMR))) ;
  78. m_pVMR->Release() ;
  79. m_pVMR = NULL ;
  80. }
  81. m_pGB->Release() ; // free it
  82. m_pGB = NULL ;
  83. }
  84. DbgLog((LOG_TRACE, 3, TEXT("CDvdGraphBuilder::~CDvdGraphBuilder() ending"))) ;
  85. }
  86. // this goes in the factory template table to create new instances
  87. CUnknown * CDvdGraphBuilder::CreateInstance(LPUNKNOWN pUnk, HRESULT * phr)
  88. {
  89. return new CDvdGraphBuilder(TEXT("DVD Graph Builder II"), pUnk, phr) ;
  90. }
  91. STDMETHODIMP CDvdGraphBuilder::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  92. {
  93. DbgLog((LOG_TRACE, 3, TEXT("CDvdGraphBuilder::NonDelegatingQueryInterface()"))) ;
  94. if (ppv)
  95. *ppv = NULL;
  96. if (riid == IID_IDvdGraphBuilder)
  97. {
  98. DbgLog((LOG_TRACE, 5, TEXT("QI for IDvdGraphBuilder"))) ;
  99. return GetInterface((IDvdGraphBuilder *) this, ppv) ;
  100. }
  101. else // more interfaces
  102. {
  103. return CUnknown::NonDelegatingQueryInterface(riid, ppv) ;
  104. }
  105. }
  106. // -----------------------------
  107. // IDvdGraphBuilder stuff ....
  108. // -----------------------------
  109. //
  110. // What filtergraph is graph building being done in?
  111. //
  112. HRESULT CDvdGraphBuilder::GetFiltergraph(IGraphBuilder **ppGB)
  113. {
  114. DbgLog((LOG_TRACE, 3, TEXT("CDvdGraphBuilder::GetFiltergraph(0x%lx)"), ppGB)) ;
  115. if (ppGB == NULL)
  116. return E_POINTER ;
  117. EnsureGraphExists() ;
  118. *ppGB = m_pGB ;
  119. if (NULL == m_pGB)
  120. {
  121. return E_UNEXPECTED ;
  122. }
  123. m_pGB->AddRef() ; // app owns a copy now
  124. return NOERROR ;
  125. }
  126. DEFINE_GUID(IID_IDDrawNonExclModeVideo,
  127. 0xec70205c, 0x45a3, 0x4400, 0xa3, 0x65, 0xc4, 0x47, 0x65, 0x78, 0x45, 0xc7) ;
  128. DEFINE_GUID(IID_IAMSpecifyDDrawConnectionDevice,
  129. 0xc5265dba, 0x3de3, 0x4919, 0x94, 0x0b, 0x5a, 0xc6, 0x61, 0xc8, 0x2e, 0xf4) ;
  130. //
  131. // Get a specified interface off of a filter in the DVD playback graph
  132. //
  133. HRESULT CDvdGraphBuilder::GetDvdInterface(REFIID riid, void **ppvIF)
  134. {
  135. DbgLog((LOG_TRACE, 3, TEXT("CDvdGraphBuilder::GetDvdInterface(%s, 0x%lx)"),
  136. (LPCTSTR)CDisp(riid), ppvIF)) ;
  137. HRESULT hr ;
  138. if (IsBadWritePtr(ppvIF, sizeof(LPVOID)))
  139. return E_INVALIDARG ;
  140. *ppvIF = NULL ;
  141. // We should be able to provide the IDDrawExclModeVideo interface even
  142. // before the graph is built so that apps can specify their own DDraw
  143. // params to be used by OvMixer to build the graph.
  144. if (IID_IDDrawExclModeVideo == riid ||
  145. IID_IDDrawNonExclModeVideo == riid ||
  146. IID_IAMSpecifyDDrawConnectionDevice == riid)
  147. {
  148. if (NULL == m_pVMR) // if we are already NOT using VMR
  149. {
  150. hr = EnsureOverlayMixerExists() ;
  151. ASSERT(SUCCEEDED(hr) && m_pOvM) ;
  152. if (SUCCEEDED(hr) && m_pOvM)
  153. {
  154. SetVMRUse(FALSE) ; // can't use VMR anymore
  155. return m_pOvM->QueryInterface(riid, (LPVOID *)ppvIF) ;
  156. }
  157. }
  158. return E_NOINTERFACE ;
  159. }
  160. // We should be able to provide the IVMR* interfaces even before the graph
  161. // is built so that apps can specify their own rendering settings to be
  162. // used by VMR whille building the graph.
  163. if (IID_IVMRMixerBitmap == riid ||
  164. IID_IVMRFilterConfig == riid ||
  165. IID_IVMRWindowlessControl == riid ||
  166. IID_IVMRMonitorConfig == riid)
  167. {
  168. if (NULL == m_pOvM) // if we are already NOT using OvMixer
  169. {
  170. hr = EnsureVMRExists() ;
  171. ASSERT(SUCCEEDED(hr) && m_pVMR) ;
  172. if (SUCCEEDED(hr) && m_pVMR)
  173. {
  174. // SetVMRUse(TRUE) ; // should try to use VMR for sure
  175. return m_pVMR->QueryInterface(riid, (LPVOID *)ppvIF) ;
  176. }
  177. }
  178. return E_NOINTERFACE ;
  179. }
  180. // We don't return IVMRPinConfig pointer. If needed the app can get the
  181. // VMR interface and get the pin config interface for the needed pin.
  182. // We can't return ANY OTHER internal filter interface pointers before
  183. // building the whole graph.
  184. if (! m_bGraphDone )
  185. return VFW_E_DVD_GRAPHNOTREADY ;
  186. if (IID_IDvdControl == riid)
  187. {
  188. return m_pDVDNav->QueryInterface(IID_IDvdControl, (LPVOID *)ppvIF) ;
  189. }
  190. else if (IID_IDvdControl2 == riid)
  191. {
  192. return m_pDVDNav->QueryInterface(IID_IDvdControl2, (LPVOID *)ppvIF) ;
  193. }
  194. else if (IID_IDvdInfo == riid)
  195. {
  196. return m_pDVDNav->QueryInterface(IID_IDvdInfo, (LPVOID *)ppvIF) ;
  197. }
  198. else if (IID_IDvdInfo2 == riid)
  199. {
  200. return m_pDVDNav->QueryInterface(IID_IDvdInfo2, (LPVOID *)ppvIF) ;
  201. }
  202. else if (IID_IVideoWindow == riid)
  203. {
  204. if (m_pVR || m_pVMR)
  205. return m_pGB->QueryInterface(IID_IVideoWindow, (LPVOID *)ppvIF) ;
  206. else
  207. return E_NOINTERFACE ;
  208. }
  209. else if (IID_IBasicVideo == riid)
  210. {
  211. if (m_pVR)
  212. return m_pVR->QueryInterface(IID_IBasicVideo, (LPVOID *)ppvIF) ;
  213. else if (m_pVMR)
  214. return m_pVMR->QueryInterface(IID_IBasicVideo, (LPVOID *)ppvIF) ;
  215. else
  216. return E_NOINTERFACE ;
  217. }
  218. else if (IID_IBasicAudio == riid)
  219. {
  220. return m_pGB->QueryInterface(IID_IBasicAudio, (LPVOID *)ppvIF) ;
  221. }
  222. else if (IID_IAMLine21Decoder == riid)
  223. {
  224. if (m_pL21Dec)
  225. return m_pL21Dec->QueryInterface(IID_IAMLine21Decoder, (LPVOID *)ppvIF) ;
  226. else
  227. return E_NOINTERFACE ;
  228. }
  229. else if (IID_IMixerPinConfig == riid || IID_IMixerPinConfig2 == riid)
  230. {
  231. // First check if VMR is already being used. In that case we don't use
  232. // OvMixer, and hence no such interface.
  233. if (m_pVMR)
  234. {
  235. DbgLog((LOG_TRACE, 3, TEXT("VMR being used. Can't get IMixerPinConfig(2)."))) ;
  236. return E_NOINTERFACE ;
  237. }
  238. // In all likelihood, this app wants to use the OvMixer. So we'll go on
  239. // that path (create OvMixer, if it's not there) and return the interface.
  240. *ppvIF = NULL ; // initially
  241. hr = EnsureOverlayMixerExists() ;
  242. ASSERT(SUCCEEDED(hr) && m_pOvM) ;
  243. if (SUCCEEDED(hr) && m_pOvM)
  244. {
  245. IEnumPins *pEnumPins ;
  246. IPin *pPin = NULL ;
  247. PIN_DIRECTION pd ;
  248. ULONG ul ;
  249. hr = m_pOvM->EnumPins(&pEnumPins) ;
  250. ASSERT(SUCCEEDED(hr) && pEnumPins) ;
  251. // Get the 1st input pin
  252. while (S_OK == pEnumPins->Next(1, &pPin, &ul) && 1 == ul)
  253. {
  254. pPin->QueryDirection(&pd) ;
  255. if (PINDIR_INPUT == pd)
  256. {
  257. hr = pPin->QueryInterface(riid, (LPVOID *)ppvIF) ;
  258. pPin->Release() ;
  259. break ; // we got it
  260. }
  261. pPin->Release() ;
  262. }
  263. pEnumPins->Release() ; // release before returning
  264. if (*ppvIF)
  265. return S_OK ;
  266. }
  267. return E_NOINTERFACE ;
  268. }
  269. else
  270. return E_NOINTERFACE ;
  271. }
  272. //
  273. // Build the whole graph for playing back the specifed or default DVD volume
  274. //
  275. HRESULT CDvdGraphBuilder::RenderDvdVideoVolume(LPCWSTR lpcwszPathName, DWORD dwFlags,
  276. AM_DVD_RENDERSTATUS *pStatus)
  277. {
  278. DbgLog((LOG_TRACE, 3, TEXT("CDvdGraphBuilder::RenderDvdVideoVolume(0x%lx, 0x%lx, 0x%lx)"),
  279. lpcwszPathName, dwFlags, pStatus)) ;
  280. HRESULT hr ;
  281. hr = EnsureGraphExists() ; // make sure that a graph exists; if not create one
  282. if (FAILED(hr))
  283. {
  284. DbgLog((LOG_ERROR, 0, TEXT("WARNING: Couldn't create a filter graph object"))) ;
  285. return VFW_E_DVD_RENDERFAIL ;
  286. }
  287. if (m_bGraphDone) // if graph was built before,
  288. StopGraph() ; // just make sure the graph is in Stopped state first
  289. ClearGraph() ;
  290. m_bPinNotRendered = FALSE ; // reset the flag
  291. ZeroMemory(pStatus, sizeof(AM_DVD_RENDERSTATUS)) ; // clear status
  292. m_bUseVPE = (0 == (dwFlags & AM_DVD_NOVPE)) ; // is VPE needed?
  293. DbgLog((LOG_TRACE, 3, TEXT("Flag: VPE is '%s'"), m_bUseVPE ? "On" : "Off")) ;
  294. dwFlags &= DVDGRAPH_FLAGSVALIDDEC ; // mask off the VPE flag now
  295. if (0 == dwFlags) // 0 by default means HW max
  296. {
  297. DbgLog((LOG_TRACE, 3, TEXT("dwFlags specified as 0x%lx; added .._HWDEC_PREFER"), dwFlags)) ;
  298. dwFlags |= AM_DVD_HWDEC_PREFER ; // use HW Decs maxm
  299. }
  300. if (AM_DVD_HWDEC_PREFER != dwFlags && AM_DVD_HWDEC_ONLY != dwFlags &&
  301. AM_DVD_SWDEC_PREFER != dwFlags && AM_DVD_SWDEC_ONLY != dwFlags)
  302. {
  303. DbgLog((LOG_TRACE, 3, TEXT("Invalid dwFlags (0x%lx) specified "), dwFlags)) ;
  304. return E_INVALIDARG ;
  305. }
  306. HRESULT hrFinal = S_OK ;
  307. m_ListFilters.SetGraph(m_pGB) ; // specify graph in which all filters will be added
  308. CheckDDrawExclMode() ; // check if we are building for DDraw exclusive mode
  309. // If we are in DDraw (non-)exclusive mode, we are supposed to use only
  310. // the OvMixer, and not the VMR. We update the flag here and check it in
  311. // the stream render functions.
  312. SetVMRUse(GetVMRUse() && !IsDDrawExclMode()) ;
  313. //
  314. // Instantiate DVD Nav filter first
  315. //
  316. hr = CreateFilterInGraph(CLSID_DVDNavigator, L"DVD Navigator", &m_pDVDNav) ;
  317. if (FAILED(hr) || NULL == m_pDVDNav)
  318. {
  319. DbgLog((LOG_ERROR, 1, TEXT("WARNING: DVD Nav couldn't be instantiated (Error 0x%lx)"), hr)) ;
  320. return VFW_E_DVD_RENDERFAIL ;
  321. }
  322. //
  323. // If .._SWDEC_ONLY flag was NOT specified, instantiate all the useful HW
  324. // decoders and maintain a list.
  325. //
  326. if (AM_DVD_SWDEC_ONLY != dwFlags)
  327. {
  328. DbgLog((LOG_TRACE, 5, TEXT(".._SWDEC_ONLY flag has NOT been specified. Enum-ing HW dec filters..."))) ;
  329. hr = CreateDVDHWDecoders() ;
  330. if (FAILED(hr))
  331. {
  332. DbgLog((LOG_TRACE, 5, TEXT("HW DVD decoder enumeration failed (Error 0x%lx)"), hr)) ;
  333. }
  334. }
  335. // Create filter mapper here to use it in the following calls
  336. hr = CoCreateInstance(CLSID_FilterMapper, NULL, CLSCTX_INPROC,
  337. IID_IFilterMapper, (LPVOID *)&m_pMapper) ;
  338. ASSERT(SUCCEEDED(hr) && m_pMapper) ;
  339. // First render the video stream
  340. hr = RenderNavVideoOutPin(dwFlags, pStatus) ;
  341. if (S_OK != hr) // everything isn't good
  342. {
  343. //
  344. // Video stream rendering also includes line21 rendering. If that
  345. // fails due to any reason, including the reason that video decoder
  346. // doesn't have a line21 output pin, we don't want to mark it as a
  347. // video stream rendering failure. The line21 rendering failure
  348. // flags are set deep inside. We set the video decode/render failure
  349. // flags also in the video decode/rendering code. We just downgrade
  350. // the overall result here.
  351. //
  352. DbgLog((LOG_TRACE, 3, TEXT("Something wrong with video stream rendering"))) ;
  353. if (SUCCEEDED(hrFinal)) // was perfect so far
  354. {
  355. DbgLog((LOG_TRACE, 3, TEXT("Overall result downgraded from 0x%lx to 0x%lx"), hrFinal, hr)) ;
  356. hrFinal = hr ;
  357. }
  358. }
  359. // Then render the subpicture stream
  360. hr = RenderNavSubpicOutPin(dwFlags, pStatus) ;
  361. if (S_OK != hr)
  362. {
  363. pStatus->iNumStreamsFailed++ ;
  364. pStatus->dwFailedStreamsFlag |= AM_DVD_STREAM_SUBPIC ;
  365. if (SUCCEEDED(hrFinal)) // was perfect so far
  366. {
  367. DbgLog((LOG_TRACE, 3, TEXT("Overall result downgraded from 0x%lx to 0x%lx"), hrFinal, hr)) ;
  368. hrFinal = hr ;
  369. }
  370. }
  371. // And then render the audio stream
  372. hr = RenderNavAudioOutPin(dwFlags, pStatus) ;
  373. if (S_OK != hr)
  374. {
  375. pStatus->iNumStreamsFailed++ ;
  376. pStatus->dwFailedStreamsFlag |= AM_DVD_STREAM_AUDIO ;
  377. if (SUCCEEDED(hrFinal)) // was perfect so far
  378. {
  379. DbgLog((LOG_TRACE, 3, TEXT("Overall result downgraded from 0x%lx to 0x%lx"), hrFinal, hr)) ;
  380. hrFinal = hr ;
  381. }
  382. }
  383. DbgLog((LOG_TRACE, 5, TEXT("Setting number of DVD streams to 3"))) ;
  384. pStatus->iNumStreams = 3 ; // so far 3 DVD streams
  385. //
  386. // In case any output pin was not rendered because we had more than one decoded
  387. // output pin for one stream, we try to locate that pin and render it as a last
  388. // ditch effort.
  389. //
  390. if (m_bPinNotRendered)
  391. {
  392. hr = RenderRemainingPins() ;
  393. if (S_OK != hr) // some problem in rendering
  394. {
  395. if (SUCCEEDED(hrFinal)) // was perfect so far
  396. {
  397. DbgLog((LOG_TRACE, 3, TEXT("Overall result downgraded from 0x%lx to 0x%lx"), hrFinal, hr)) ;
  398. hrFinal = hr ;
  399. }
  400. }
  401. }
  402. //
  403. // Now render any additional streams, e.g, the ASF stream, if any.
  404. //
  405. // Currently does NOT do anything.
  406. //
  407. hr = RenderNavASFOutPin(dwFlags, pStatus) ;
  408. ASSERT(SUCCEEDED(hr)) ;
  409. hr = RenderNavOtherOutPin(dwFlags, pStatus) ;
  410. ASSERT(SUCCEEDED(hr)) ;
  411. // Done with the filter mapper. Let it go now.
  412. m_pMapper->Release() ;
  413. m_pMapper = NULL ;
  414. m_ListHWDecs.ClearList() ; // don't need the extra HW filters anymore
  415. if (pStatus->iNumStreamsFailed >= pStatus->iNumStreams)
  416. {
  417. DbgLog((LOG_TRACE, 1, TEXT("Failed to render %d out of %d main DVD streams (Error 0x%lx)"),
  418. pStatus->iNumStreamsFailed, pStatus->iNumStreams, hrFinal)) ;
  419. return VFW_E_DVD_DECNOTENOUGH; // VFW_E_DVD_RENDERFAIL ;
  420. }
  421. if (FAILED(hrFinal))
  422. {
  423. DbgLog((LOG_TRACE, 1, TEXT("DVD graph building failed with error 0x%lx"),
  424. hrFinal)) ;
  425. return VFW_E_DVD_RENDERFAIL ;
  426. }
  427. //
  428. // Set the specified root file name/DVD volume name (even NULL because
  429. // that causes the DVD Nav to search for one)
  430. //
  431. IDvdControl *pDvdC ;
  432. hr = m_pDVDNav->QueryInterface(IID_IDvdControl, (LPVOID *)&pDvdC) ;
  433. if (FAILED(hr) || NULL == pDvdC)
  434. {
  435. DbgLog((LOG_ERROR, 0, TEXT("WARNING: Couldn't get IDvdControl interface (Error 0x%lx)"), hr)) ;
  436. return hr ;
  437. }
  438. //
  439. // Set the specified DVD volume path
  440. //
  441. // Does the SetRoot() function handle the NULL properly?
  442. //
  443. hr = pDvdC->SetRoot(lpcwszPathName) ;
  444. if (FAILED(hr))
  445. {
  446. DbgLog((LOG_TRACE, 2,
  447. TEXT("IDvdControl::SetRoot(%S) call couldn't use specified volume (Error 0x%lx)"),
  448. lpcwszPathName ? L"NULL" : lpcwszPathName, hr)) ;
  449. if (lpcwszPathName)
  450. pStatus->bDvdVolInvalid = TRUE ;
  451. else
  452. pStatus->bDvdVolUnknown = TRUE ;
  453. if (SUCCEEDED(hrFinal)) // if we were so far perfect, ...
  454. hrFinal = S_FALSE ; // ...we aren't so anymore
  455. }
  456. pDvdC->Release() ; // done with this interface
  457. // Only if we haven't entirely failed, set the graph built flag and
  458. // return overall result.
  459. if (SUCCEEDED(hrFinal))
  460. m_bGraphDone = TRUE ;
  461. m_bPinNotRendered = FALSE ; // should reset on success too
  462. return hrFinal ;
  463. }
  464. // private: internal helper methods
  465. //
  466. // Make sure a filter graph has been created; if not create one here
  467. //
  468. HRESULT CDvdGraphBuilder::EnsureGraphExists(void)
  469. {
  470. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::EnsureGraphExists()"))) ;
  471. if (m_pGB)
  472. return S_OK ;
  473. return CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
  474. IID_IGraphBuilder, (LPVOID *)&m_pGB) ;
  475. }
  476. //
  477. // Make sure OverlayMixer has been created; if not create one here.
  478. //
  479. HRESULT CDvdGraphBuilder::EnsureOverlayMixerExists(void)
  480. {
  481. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::EnsureOverlayMixerExists()"))) ;
  482. if (m_pOvM)
  483. return S_OK ;
  484. return CreateFilterInGraph(CLSID_OverlayMixer, L"Overlay Mixer", &m_pOvM) ;
  485. }
  486. //
  487. // Make sure VMR has already been created; if not create one here.
  488. //
  489. HRESULT CDvdGraphBuilder::EnsureVMRExists(void)
  490. {
  491. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::EnsureVMRExists()"))) ;
  492. if (m_pVMR)
  493. return S_OK ;
  494. HRESULT hr ;
  495. hr = CreateFilterInGraph(CLSID_VideoMixingRenderer, L"Video Mixing Renderer", &m_pVMR) ;
  496. ASSERT(m_pVMR) ;
  497. if (SUCCEEDED(hr))
  498. {
  499. IVMRFilterConfigInternal* pVMRConfigInternal;
  500. hr = m_pVMR->QueryInterface(IID_IVMRFilterConfigInternal, (void **) &pVMRConfigInternal);
  501. if( SUCCEEDED( hr )) {
  502. pVMRConfigInternal->SetAspectRatioModePrivate( VMR_ARMODE_LETTER_BOX );
  503. pVMRConfigInternal->Release();
  504. }
  505. // Create three in pins for VMR
  506. hr = CreateVMRInputPins() ;
  507. if (FAILED(hr))
  508. {
  509. DbgLog((LOG_ERROR, 1, TEXT("WARNING: Couldn't ensure VMR's 3 in pins"))) ;
  510. SetVMRUse(FALSE) ; // we shouldn't use VMR as it cannot go into mixing mode.
  511. // Should we return some error code to help the app indicate this to the user??
  512. hr = S_FALSE ; // a little problem at least
  513. }
  514. }
  515. return hr ;
  516. }
  517. #define ATI_VENDOR_CODE 0x1002
  518. #define ATI_RAGE_PRO_DEVICE_CODE 0X4742
  519. #define ATI_RAGE_MOBILITY_DEVICE_CODE 0x4C4D
  520. #define INTEL_VENDOR_CODE 0x8086
  521. #define INTEL_810_DEVICE_CODE_1 0x1132
  522. #define INTEL_810_DEVICE_CODE_2 0x7121
  523. #define INTEL_810_DEVICE_CODE_3 0x7123
  524. #define INTEL_810_DEVICE_CODE_4 0x7125
  525. const GUID OUR_IID_IDirectDraw7 =
  526. {
  527. 0x15e65ec0, 0x3b9c, 0x11d2,
  528. {
  529. 0xb9, 0x2f, 0x00, 0x60, 0x97, 0x97, 0xea, 0x5b
  530. }
  531. };
  532. HRESULT CheckVGADriverIsVMRFriendly(
  533. IBaseFilter* pVMR
  534. )
  535. {
  536. IVMRMonitorConfig* pMon;
  537. if (S_OK != pVMR->QueryInterface(IID_IVMRMonitorConfig, (LPVOID*)&pMon)) {
  538. return E_FAIL;
  539. }
  540. const DWORD dwMAX_MONITORS = 8;
  541. VMRMONITORINFO mi[dwMAX_MONITORS];
  542. DWORD dwNumMonitors;
  543. //
  544. // Get information about all the monitors in the system.
  545. //
  546. if (S_OK != pMon->GetAvailableMonitors(mi, dwMAX_MONITORS, &dwNumMonitors)) {
  547. pMon->Release();
  548. return E_FAIL;
  549. }
  550. //
  551. // Get the current monitors GUID.
  552. //
  553. VMRGUID gu;
  554. HRESULT hr = pMon->GetMonitor(&gu);
  555. pMon->Release();
  556. if (S_OK != hr) {
  557. return E_FAIL;
  558. }
  559. //
  560. // Search for the current monitor in the array of available monitors
  561. //
  562. VMRMONITORINFO* pmi = &mi[0];
  563. for (DWORD i = 0; i < dwNumMonitors; i++, pmi++) {
  564. if (gu.pGUID == NULL && pmi->guid.pGUID == NULL) {
  565. break;
  566. }
  567. if (gu.pGUID != NULL && pmi->guid.pGUID != NULL) {
  568. if (gu.GUID == pmi->guid.GUID) {
  569. break;
  570. }
  571. }
  572. }
  573. //
  574. // Make sure we found a monitor - we should always find a monitor!
  575. //
  576. if (i == dwNumMonitors) {
  577. return E_FAIL;
  578. }
  579. //
  580. // ATi chip sets that don't work with the VMR for DVD playback.
  581. //
  582. if (pmi->dwVendorId == ATI_VENDOR_CODE)
  583. {
  584. switch(pmi->dwDeviceId) {
  585. case ATI_RAGE_PRO_DEVICE_CODE:
  586. return E_FAIL;
  587. case ATI_RAGE_MOBILITY_DEVICE_CODE:
  588. {
  589. IVMRMixerControl* lpMixControl = NULL;
  590. hr = pVMR->QueryInterface(IID_IVMRMixerControl, (LPVOID*)&lpMixControl);
  591. if (SUCCEEDED(hr)) {
  592. DWORD dw;
  593. hr = lpMixControl->GetMixingPrefs(&dw);
  594. if (SUCCEEDED(hr)) {
  595. dw &= ~ MixerPref_FilteringMask;
  596. dw |= MixerPref_PointFiltering;
  597. hr = lpMixControl->SetMixingPrefs(dw);
  598. }
  599. lpMixControl->Release();
  600. }
  601. }
  602. break;
  603. }
  604. }
  605. //
  606. // Intel chip sets that don't work well with the VMR for DVD playback.
  607. // These chipsets do work but the VMR needs to be configured correctly
  608. // to get the best perf form the chipset.
  609. //
  610. else if (pmi->dwVendorId == INTEL_VENDOR_CODE)
  611. {
  612. switch(pmi->dwDeviceId) {
  613. case INTEL_810_DEVICE_CODE_1:
  614. case INTEL_810_DEVICE_CODE_2:
  615. case INTEL_810_DEVICE_CODE_3:
  616. case INTEL_810_DEVICE_CODE_4:
  617. {
  618. //
  619. // We should check the processor speed before
  620. // using the VMR - we need at least 500MHz for
  621. // good quality playback.
  622. //
  623. IVMRMixerControl* lpMixControl = NULL;
  624. hr = pVMR->QueryInterface(IID_IVMRMixerControl, (LPVOID*)&lpMixControl);
  625. if (SUCCEEDED(hr)) {
  626. DWORD dw;
  627. hr = lpMixControl->GetMixingPrefs(&dw);
  628. if (SUCCEEDED(hr)) {
  629. dw &= ~ MixerPref_RenderTargetMask;
  630. dw |= MixerPref_RenderTargetIntelIMC3;
  631. hr = lpMixControl->SetMixingPrefs(dw);
  632. }
  633. lpMixControl->Release();
  634. }
  635. }
  636. break;
  637. }
  638. }
  639. return S_OK;
  640. }
  641. //
  642. // Make sure VMR has at least 3 in pins.
  643. //
  644. HRESULT CDvdGraphBuilder::CreateVMRInputPins(void)
  645. {
  646. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::CreateVMRInputPins()"))) ;
  647. if (NULL == m_pVMR)
  648. return E_UNEXPECTED ;
  649. // Create three (3) in pins for the VMR so that it can accommodate video,
  650. // SP and CC streams coming in. By default VMR has only one in pin.
  651. HRESULT hr ;
  652. IVMRFilterConfig *pVMRConfig ;
  653. hr = m_pVMR->QueryInterface(IID_IVMRFilterConfig, (LPVOID *) &pVMRConfig) ;
  654. if (SUCCEEDED(hr))
  655. {
  656. DWORD dwStreams = 0 ;
  657. pVMRConfig->GetNumberOfStreams(&dwStreams) ;
  658. if (dwStreams < 3) // if not enough in pins...
  659. {
  660. hr = pVMRConfig->SetNumberOfStreams(3) ;
  661. if (FAILED(hr))
  662. {
  663. DbgLog((LOG_TRACE, 3, TEXT("Couldn't create 3 in pins for VMR"))) ;
  664. hr = E_FAIL ; // This is possible now. We need to turn off VMR use...
  665. }
  666. }
  667. pVMRConfig->Release() ;
  668. if (SUCCEEDED(hr)) {
  669. hr = CheckVGADriverIsVMRFriendly(m_pVMR);
  670. if (FAILED(hr)) {
  671. DbgLog((LOG_TRACE, 3, TEXT("This VGA driver is not compatible with the VMR"))) ;
  672. hr = E_FAIL ; // This is not possible now. We need to turn off VMR use...
  673. }
  674. }
  675. }
  676. else
  677. {
  678. ASSERT(pVMRConfig) ;
  679. DbgLog((LOG_ERROR, 1, TEXT("WARNING: Couldn't get IVMRFilterConfig from VMR!!!"))) ;
  680. hr = S_FALSE ; // a little problem at least
  681. }
  682. return hr ;
  683. }
  684. //
  685. // Create a fresh filter graph
  686. //
  687. HRESULT CDvdGraphBuilder::CreateGraph(void)
  688. {
  689. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::CreateGraph()"))) ;
  690. return CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
  691. IID_IGraphBuilder, (LPVOID *)&m_pGB) ;
  692. }
  693. //
  694. // Delete the existing filter graph's contents
  695. //
  696. HRESULT CDvdGraphBuilder::DeleteGraph(void)
  697. {
  698. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::DeleteGraph()"))) ;
  699. m_pGB->Release() ;
  700. m_pGB = NULL ;
  701. return NOERROR ;
  702. }
  703. //
  704. // Clear all the existing filters from the graph
  705. //
  706. HRESULT CDvdGraphBuilder::ClearGraph(void)
  707. {
  708. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::ClearGraph()"))) ;
  709. // Just paranoia...
  710. if (NULL == m_pGB)
  711. {
  712. ASSERT(FALSE) ; // so that we know
  713. DbgLog((LOG_ERROR, 0, TEXT("WARNING: How are we Clearing w/o a graph???"))) ;
  714. return E_FAIL ;
  715. }
  716. // If by any chance, the filter mapper object remained, delete it now
  717. if (m_pMapper)
  718. {
  719. m_pMapper->Release() ;
  720. m_pMapper = NULL ;
  721. }
  722. #pragma message("WARNING: Should we remove the decoder filters first?")
  723. // Remove all filters in our list from the graph
  724. // m_ListFilters.RemoveAllFromGraph() ;
  725. HRESULT hr ;
  726. IEnumPins *pEnumPins ;
  727. IPin *pPin ;
  728. IPin *pPin2 ;
  729. ULONG ul ;
  730. //
  731. // Remove the filters we know about specifically
  732. //
  733. // We don't want to remove OvMixer -- it may have external DDraw params set.
  734. // Just break the connections.
  735. if (m_pOvM)
  736. {
  737. hr = m_pOvM->EnumPins(&pEnumPins) ;
  738. ASSERT(SUCCEEDED(hr) && pEnumPins) ;
  739. while (S_OK == pEnumPins->Next(1, &pPin, &ul) && 1 == ul)
  740. {
  741. hr = pPin->ConnectedTo(&pPin2) ;
  742. if (SUCCEEDED(hr) && pPin2)
  743. {
  744. hr = m_pGB->Disconnect(pPin) ;
  745. ASSERT(SUCCEEDED(hr)) ;
  746. hr = m_pGB->Disconnect(pPin2) ;
  747. ASSERT(SUCCEEDED(hr)) ;
  748. pPin2->Release() ;
  749. }
  750. pPin->Release() ; // done with this pin
  751. }
  752. pEnumPins->Release() ;
  753. }
  754. if (m_pDVDNav)
  755. {
  756. EXECUTE_ASSERT(SUCCEEDED(m_pGB->RemoveFilter(m_pDVDNav))) ;
  757. m_pDVDNav->Release() ;
  758. m_pDVDNav = NULL ;
  759. }
  760. // We don't want to remove VMR (only), because it might have been instantiated
  761. // for an app when it QI-ed for a VMR interface -- just like OvMixer case.
  762. if (m_pVMR)
  763. {
  764. hr = m_pVMR->EnumPins(&pEnumPins) ;
  765. ASSERT(SUCCEEDED(hr) && pEnumPins) ;
  766. while (S_OK == pEnumPins->Next(1, &pPin, &ul) && 1 == ul)
  767. {
  768. hr = pPin->ConnectedTo(&pPin2) ;
  769. if (SUCCEEDED(hr) && pPin2)
  770. {
  771. hr = m_pGB->Disconnect(pPin) ;
  772. ASSERT(SUCCEEDED(hr)) ;
  773. hr = m_pGB->Disconnect(pPin2) ;
  774. ASSERT(SUCCEEDED(hr)) ;
  775. pPin2->Release() ;
  776. }
  777. pPin->Release() ; // done with this pin
  778. }
  779. pEnumPins->Release() ;
  780. }
  781. if (m_pVPM)
  782. {
  783. EXECUTE_ASSERT(SUCCEEDED(m_pGB->RemoveFilter(m_pVPM))) ;
  784. m_pVPM->Release() ;
  785. m_pVPM = NULL ;
  786. }
  787. if (m_pL21Dec)
  788. {
  789. EXECUTE_ASSERT(SUCCEEDED(m_pGB->RemoveFilter(m_pL21Dec))) ;
  790. m_pL21Dec->Release() ;
  791. m_pL21Dec = NULL ;
  792. }
  793. if (m_pAR)
  794. {
  795. EXECUTE_ASSERT(SUCCEEDED(m_pGB->RemoveFilter(m_pAR))) ;
  796. m_pAR->Release() ;
  797. m_pAR = NULL ;
  798. }
  799. if (m_pVR)
  800. {
  801. EXECUTE_ASSERT(SUCCEEDED(m_pGB->RemoveFilter(m_pVR))) ;
  802. m_pVR->Release() ;
  803. m_pVR = NULL ;
  804. }
  805. // Remove all filters in our list from the graph
  806. m_ListFilters.RemoveAllFromGraph() ;
  807. // Enumerate any remaining filters and remove them -- make sure to skip OvMixer
  808. IEnumFilters *pEnumFilters ;
  809. // ULONG ul ; -- defined at the top
  810. IBaseFilter *pFilter ;
  811. m_pGB->EnumFilters(&pEnumFilters) ;
  812. ASSERT(pEnumFilters) ;
  813. while (S_OK == pEnumFilters->Next(1, &pFilter, &ul) && 1 == ul)
  814. {
  815. if (m_pOvM && IsEqualObject(m_pOvM, pFilter) ||
  816. m_pVMR && IsEqualObject(m_pVMR, pFilter))
  817. {
  818. DbgLog((LOG_TRACE, 3,
  819. TEXT("Got OverlayMixer/VMR through filter enum. Not removing from graph."))) ;
  820. }
  821. else
  822. {
  823. EXECUTE_ASSERT(SUCCEEDED(m_pGB->RemoveFilter(pFilter))) ;
  824. }
  825. pFilter->Release() ; // done with this filter
  826. }
  827. pEnumFilters->Release() ; // done enum-ing
  828. m_bGraphDone = FALSE ; // reset the "graph already built" flag
  829. return NOERROR ;
  830. }
  831. void CDvdGraphBuilder::StopGraph(void)
  832. {
  833. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::StopGraph()"))) ;
  834. // Just paranoia
  835. if (NULL == m_pGB)
  836. {
  837. ASSERT(FALSE) ; // so that we know
  838. DbgLog((LOG_ERROR, 0, TEXT("WARNING: How are we doing a Stop w/o a graph???"))) ;
  839. return ;
  840. }
  841. //
  842. // Check that the graph has stopped; otherwise stop it here. Because a
  843. // playing graph can't be cleaned up or rebuilt.
  844. //
  845. IMediaControl *pMC ;
  846. LONG lState ;
  847. HRESULT hr = m_pGB->QueryInterface(IID_IMediaControl, (LPVOID *)&pMC) ;
  848. ASSERT(SUCCEEDED(hr) && pMC) ;
  849. pMC->GetState(INFINITE, &lState) ;
  850. if (State_Stopped != lState)
  851. {
  852. hr = pMC->Stop() ;
  853. ASSERT(SUCCEEDED(hr)) ;
  854. while (State_Stopped != lState)
  855. {
  856. Sleep(10) ;
  857. hr = pMC->GetState(INFINITE, &lState) ;
  858. ASSERT(SUCCEEDED(hr)) ;
  859. }
  860. }
  861. pMC->Release() ;
  862. DbgLog((LOG_TRACE, 4, TEXT("DVD-Video playback graph has stopped"))) ;
  863. }
  864. // 5 output pins of decoder of matching type is enough
  865. #define MAX_DEC_OUT_PINS 5
  866. void CDvdGraphBuilder::ResetPinInterface(IPin **apPin, int iCount)
  867. {
  868. for (int i = 0 ; i < iCount ; i++)
  869. apPin[i] = NULL ;
  870. }
  871. void CDvdGraphBuilder::ReleasePinInterface(IPin **apPin)
  872. {
  873. // Done with decoded video pin(s) -- release it/them
  874. int i = 0 ;
  875. while (apPin[i])
  876. {
  877. apPin[i]->Release() ;
  878. i++ ;
  879. }
  880. }
  881. HRESULT CDvdGraphBuilder::RenderNavVideoOutPin(DWORD dwDecFlag, AM_DVD_RENDERSTATUS *pStatus)
  882. {
  883. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderNavVideoOutPin(0x%lx, 0x%lx)"),
  884. dwDecFlag, pStatus)) ;
  885. HRESULT hr ;
  886. IPin *pPin ;
  887. IPin *apPinOutDec[MAX_DEC_OUT_PINS + 1] ; // 1 for terminating NULL
  888. ResetPinInterface(apPinOutDec, NUMELMS(apPinOutDec)) ;
  889. hr = FindMatchingPin(m_pDVDNav, AM_DVD_STREAM_VIDEO, PINDIR_OUTPUT, TRUE, 0, &pPin) ;
  890. if (FAILED(hr) || NULL == pPin)
  891. {
  892. DbgLog((LOG_ERROR, 1, TEXT("No open video output pin found on the DVDNav"))) ;
  893. return VFW_E_DVD_RENDERFAIL ;
  894. }
  895. // The dwDecFlag out param is largely ignored, except being passed as an in
  896. // param to the method RenderDecodedVideo() to indicate if the video is
  897. // decoded in HW, so that VPM is used before VMR.
  898. hr = DecodeDVDStream(pPin, AM_DVD_STREAM_VIDEO, &dwDecFlag, pStatus, apPinOutDec) ;
  899. pPin->Release() ; // release DVDNav's video out pin
  900. if (FAILED(hr)) // couldn't find video decoder
  901. {
  902. DbgLog((LOG_TRACE, 1, TEXT("Could not find a decoder for video stream!!!"))) ;
  903. // For video stream, any decode/rendering problem has to be flagged here
  904. // as we just downgrade the final result in the caller, but not set any
  905. // flag there.
  906. pStatus->iNumStreamsFailed++ ;
  907. pStatus->dwFailedStreamsFlag |= AM_DVD_STREAM_VIDEO ;
  908. return S_FALSE ; // just a stream will not be rendered
  909. }
  910. //
  911. // Decoding the video stream succeeded. Now if we got a decoded output pin,
  912. // we need to render that too.
  913. //
  914. HRESULT hrFinal = S_OK ;
  915. if (apPinOutDec[0]) // if video decoding is handled and we got a valid output pin
  916. {
  917. //
  918. // Render the decoded video stream (and line21) ONLY IF the user wants that
  919. //
  920. if (m_bUseVPE)
  921. {
  922. hr = RenderDecodedVideo(apPinOutDec, pStatus, dwDecFlag) ;
  923. //
  924. // If the above rendering attempt is successful then we'll
  925. // try to render the line21 output. If the the video decoder
  926. // doesn't have a video output pin, then there is very little
  927. // chance, well no chance, of having a line21 output.
  928. //
  929. if (SUCCEEDED(hr))
  930. {
  931. //
  932. // The Line21 data comes out of the video decoder filter.
  933. // So get the filter from the above decoded video output
  934. // pin and then get to the line21 output pin.
  935. //
  936. //
  937. // We render the line21 out pin of the video decoder
  938. // ONLY IF we are NOT in DDraw exclusive mode.
  939. //
  940. if (IsDDrawExclMode())
  941. {
  942. DbgLog((LOG_TRACE, 3, TEXT("*** Line21 out pin is not rendered in DDraw excl mode"))) ;
  943. pStatus->bNoLine21In = FALSE ; // no problem with line21
  944. pStatus->bNoLine21Out = FALSE ; // ... ... ... ... ...
  945. }
  946. else // normal mode
  947. {
  948. // Now we are free to render the line21 out pin...
  949. IPin *pPinL21Out ;
  950. PIN_INFO pi ;
  951. hr = apPinOutDec[0]->QueryPinInfo(&pi) ; // the first out pin is fine
  952. ASSERT(SUCCEEDED(hr) && pi.pFilter) ;
  953. hr = FindMatchingPin(pi.pFilter, AM_DVD_STREAM_LINE21,
  954. PINDIR_OUTPUT, TRUE, 0, &pPinL21Out) ;
  955. if (SUCCEEDED(hr) && pPinL21Out)
  956. {
  957. pStatus->bNoLine21In = FALSE ; // there is line21 output pin
  958. hr = RenderLine21Stream(pPinL21Out, pStatus) ;
  959. if (SUCCEEDED(hr))
  960. pStatus->bNoLine21Out = FALSE ; // line21 rendering is OK
  961. else
  962. {
  963. pStatus->bNoLine21Out = TRUE ; // line21 rendering failed
  964. hrFinal = S_FALSE ; // not complete success
  965. }
  966. pPinL21Out->Release() ; // done with line21 pin -- release it now
  967. }
  968. else // video decoder doesn't have line21 output at all
  969. {
  970. DbgLog((LOG_TRACE, 3, TEXT("No line21 output pin on the video decoder."))) ;
  971. pStatus->bNoLine21In = TRUE ; // no line21 data from video decoder
  972. hrFinal = S_FALSE ; // not complete success
  973. }
  974. pi.pFilter->Release() ; // otherwise we'll leak it
  975. }
  976. } // end of if (SUCCEEDED(hr))
  977. else
  978. {
  979. DbgLog((LOG_TRACE, 3, TEXT("Rendering video stream failed (Error 0x%lx)"), hr)) ;
  980. hrFinal = S_FALSE ; // major problem -- video stream failed to render
  981. }
  982. } // end of if (m_bUseVPE)
  983. else
  984. {
  985. DbgLog((LOG_TRACE, 3, TEXT("Video Stream: RenderDvdVideoVolume() was called with no VPE flag"))) ;
  986. }
  987. ReleasePinInterface(apPinOutDec) ; // done with decoded video pin(s) -- release it
  988. }
  989. return hrFinal ;
  990. }
  991. HRESULT CDvdGraphBuilder::RenderNavAudioOutPin(DWORD dwDecFlag, AM_DVD_RENDERSTATUS *pStatus)
  992. {
  993. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderNavAudioOutPin(0x%lx, 0x%lx)"),
  994. dwDecFlag, pStatus)) ;
  995. HRESULT hr ;
  996. IPin *pPin ;
  997. IPin *apPinOutDec[MAX_DEC_OUT_PINS + 1] ; // 1 for terminating NULL
  998. ResetPinInterface(apPinOutDec, NUMELMS(apPinOutDec)) ;
  999. hr = FindMatchingPin(m_pDVDNav, AM_DVD_STREAM_AUDIO, PINDIR_OUTPUT, TRUE, 0, &pPin) ;
  1000. if (FAILED(hr) || NULL == pPin)
  1001. {
  1002. DbgLog((LOG_ERROR, 1, TEXT("No audio output pin found on the DVDNav"))) ;
  1003. return VFW_E_DVD_RENDERFAIL ;
  1004. }
  1005. hr = DecodeDVDStream(pPin, AM_DVD_STREAM_AUDIO, &dwDecFlag, // we ignore returned dwDecFlag here
  1006. pStatus, apPinOutDec) ;
  1007. pPin->Release() ; // release DVDNav's audio out pin
  1008. if (FAILED(hr)) // couldn't find audio decoder
  1009. {
  1010. DbgLog((LOG_TRACE, 1, TEXT("Could not find a decoder for audio stream!!!"))) ;
  1011. return S_FALSE ; // just a stream will not be rendered
  1012. }
  1013. //
  1014. // Decoding the audio stream succeeded. Now if we got a decoded output pin,
  1015. // we need to render that too.
  1016. //
  1017. if (apPinOutDec[0]) // if audio decoding is handled and we got a valid output pin
  1018. {
  1019. hr = RenderDecodedAudio(apPinOutDec, pStatus) ;
  1020. if (S_OK != hr)
  1021. {
  1022. DbgLog((LOG_TRACE, 3, TEXT("Could not render decoded audio stream"))) ;
  1023. hr = S_FALSE ; // partial failure to be returned
  1024. }
  1025. ReleasePinInterface(apPinOutDec) ; // done with decoded audio pin -- release it
  1026. }
  1027. return hr ;
  1028. }
  1029. HRESULT CDvdGraphBuilder::RenderNavSubpicOutPin(DWORD dwDecFlag, AM_DVD_RENDERSTATUS *pStatus)
  1030. {
  1031. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderNavSubpicOutPin(0x%lx, 0x%lx)"),
  1032. dwDecFlag, pStatus)) ;
  1033. HRESULT hr ;
  1034. IPin *pPin ;
  1035. IPin *apPinOutDec[MAX_DEC_OUT_PINS + 1] ; // 1 for terminating NULL
  1036. ResetPinInterface(apPinOutDec, NUMELMS(apPinOutDec)) ;
  1037. hr = FindMatchingPin(m_pDVDNav, AM_DVD_STREAM_SUBPIC, PINDIR_OUTPUT, TRUE, 0, &pPin) ;
  1038. if (FAILED(hr) || NULL == pPin)
  1039. {
  1040. DbgLog((LOG_ERROR, 1, TEXT("No subpicture output pin found on the DVDNav"))) ;
  1041. return VFW_E_DVD_RENDERFAIL ;
  1042. }
  1043. // Pass dwDecFlag as a in/out param to get back what kind of SP decoder was
  1044. // actually used. We'll use that to hack below.
  1045. hr = DecodeDVDStream(pPin, AM_DVD_STREAM_SUBPIC, &dwDecFlag,
  1046. pStatus, apPinOutDec) ;
  1047. pPin->Release() ; // release DVDNav's subpic out pin
  1048. if (FAILED(hr)) // couldn't find SP decoder
  1049. {
  1050. DbgLog((LOG_TRACE, 1, TEXT("Could not find a decoder for SP stream!!!"))) ;
  1051. return S_FALSE ; // just a stream will not be rendered
  1052. }
  1053. //
  1054. // Decoding the SP stream succeeded. Now if we got a decoded output pin,
  1055. // we need to render that too.
  1056. //
  1057. if (apPinOutDec[0]) // there is a decoded SP out pin
  1058. {
  1059. hr = RenderDecodedSubpic(apPinOutDec, pStatus) ;
  1060. //
  1061. // HACK HACK HACK:
  1062. // In general HW decoders mix the SP and video in HW rather than popping a
  1063. // SP output pin. We may land up getting a (seemingly) video out pin, which
  1064. // for SW decoders may mean a decoded SP output pin, but for HW decoders it's
  1065. // certainly some other thing (c-cube DVXplorer) and it will not connect to
  1066. // OvMixer/VPM+VMR.
  1067. // We don't avoid trying to connect such a pin to OvMixer/VPM+VMR (done above),
  1068. // but in case it fails (as it is expected to), we just ignore the error and do
  1069. // NOT consider it as a SP stream rendering failure.
  1070. //
  1071. if (AM_DVD_HWDEC_ONLY == dwDecFlag) // here means HW decoder was used for SP
  1072. {
  1073. DbgLog((LOG_TRACE, 3,
  1074. TEXT("SP stream is decoded in HW. We ignore any error in rendering (0x%lx)"),
  1075. hr)) ;
  1076. hr = S_OK ;
  1077. }
  1078. else // for SW decoder
  1079. {
  1080. if (FAILED(hr)) // connection to renderer's in pin failed => no SP
  1081. {
  1082. DbgLog((LOG_TRACE, 3, TEXT("Decoded SP out pin could NOT connect to renderer"))) ;
  1083. // propagate only S_FALSE to the caller
  1084. hr = S_FALSE ; // because just a stream is not rendered right
  1085. }
  1086. }
  1087. ReleasePinInterface(apPinOutDec) ; // done with decoded SP pin -- release it
  1088. }
  1089. return hr ;
  1090. }
  1091. //
  1092. // *** NOT YET IMPLEMENTED ***
  1093. //
  1094. HRESULT CDvdGraphBuilder::RenderNavASFOutPin(DWORD dwDecFlag, AM_DVD_RENDERSTATUS *pStatus)
  1095. {
  1096. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderNavASFOutPin(0x%lx, 0x%lx) -- ** Not Implemented **"),
  1097. dwDecFlag, pStatus)) ;
  1098. return S_OK ;
  1099. }
  1100. //
  1101. // *** NOT YET IMPLEMENTED ***
  1102. //
  1103. HRESULT CDvdGraphBuilder::RenderNavOtherOutPin(DWORD dwDecFlag, AM_DVD_RENDERSTATUS *pStatus)
  1104. {
  1105. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderNavOtherOutPin(0x%lx, 0x%lx) -- ** Not Implemented **"),
  1106. dwDecFlag, pStatus)) ;
  1107. return S_OK ;
  1108. }
  1109. HRESULT CDvdGraphBuilder::RenderRemainingPins(void)
  1110. {
  1111. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderRemainingPins() -- ** Not Implemented **"))) ;
  1112. ASSERT(FALSE) ; // so that we know about it
  1113. return S_FALSE ; // so that graph building doesn't fail completely
  1114. }
  1115. HRESULT CDvdGraphBuilder::DecodeDVDStream(IPin *pPinOut, DWORD dwStream, DWORD *pdwDecFlag,
  1116. AM_DVD_RENDERSTATUS *pStatus, IPin **apPinOutDec)
  1117. {
  1118. DbgLog((LOG_TRACE, 4,
  1119. TEXT("CDvdGraphBuilder::DecodeDVDStream(%s, 0x%lx, 0x%lx, 0x%lx, 0x%lx)"),
  1120. (LPCTSTR)CDisp(pPinOut), dwStream, *pdwDecFlag, pStatus, apPinOutDec)) ;
  1121. HRESULT hr ;
  1122. IPin *pPinIn ; // the (end) pin we finally connected to
  1123. DWORD dwNewDecFlag = *pdwDecFlag ; // let's start with what we have
  1124. // ResetPinInterface(apPinOutDec, NUMELMS(apPinOutDec)) ;
  1125. //
  1126. // We'll note what decoder option we actually use, but will not update the
  1127. // value at the passed in pointer until we have checked that the stream has
  1128. // really been decoded completely. So the new flag is assigned way below
  1129. // when we verify that the output stream gives decoded output.
  1130. //
  1131. // Also H/SWDecodeDVDStream() methods will try to detect if the video/SP
  1132. // decoder is VMR-compatible, and if not, set a flag (m_bTryVMR to FALSE),
  1133. // so that RenderDecodedVideo() method can determine which renderer to use.
  1134. //
  1135. switch (*pdwDecFlag) // based on the user-specified decoding option
  1136. {
  1137. case AM_DVD_HWDEC_ONLY:
  1138. hr = HWDecodeDVDStream(pPinOut, dwStream, &pPinIn, pStatus) ;
  1139. if (FAILED(hr))
  1140. return hr ;
  1141. // *pdwDecFlag = AM_DVD_HWDEC_ONLY ; -- unchanged
  1142. break ;
  1143. case AM_DVD_HWDEC_PREFER:
  1144. hr = HWDecodeDVDStream(pPinOut, dwStream, &pPinIn, pStatus) ;
  1145. if (FAILED(hr)) // if didn't succeed, try SW decode too
  1146. {
  1147. hr = SWDecodeDVDStream(pPinOut, dwStream, &pPinIn, pStatus) ;
  1148. if (FAILED(hr)) // now we give up
  1149. return hr ;
  1150. else
  1151. dwNewDecFlag = AM_DVD_SWDEC_ONLY ; // we preferred HW, but did it in SW
  1152. }
  1153. else
  1154. dwNewDecFlag = AM_DVD_HWDEC_ONLY ; // we preferred HW and got HW
  1155. break ;
  1156. case AM_DVD_SWDEC_ONLY:
  1157. hr = SWDecodeDVDStream(pPinOut, dwStream, &pPinIn, pStatus) ;
  1158. if (FAILED(hr))
  1159. return hr ;
  1160. break ;
  1161. case AM_DVD_SWDEC_PREFER:
  1162. hr = SWDecodeDVDStream(pPinOut, dwStream, &pPinIn, pStatus) ;
  1163. if (FAILED(hr)) // if didn't succeed, try SW decode too
  1164. {
  1165. hr = HWDecodeDVDStream(pPinOut, dwStream, &pPinIn, pStatus) ;
  1166. if (FAILED(hr)) // now we give up
  1167. return hr ;
  1168. else
  1169. dwNewDecFlag = AM_DVD_HWDEC_ONLY ; // we preferred SW, but got HW
  1170. }
  1171. else
  1172. dwNewDecFlag = AM_DVD_SWDEC_ONLY ; // we preferred SW and got SW
  1173. break ;
  1174. default:
  1175. DbgLog((LOG_ERROR, 1, TEXT("ERROR: How did dwFlags=0x%lx get passed in?"), *pdwDecFlag)) ;
  1176. return E_INVALIDARG ;
  1177. } // end of switch(*pdwDecFlag)
  1178. //
  1179. // Now see if the stream has been completely decoded
  1180. //
  1181. ASSERT(pPinIn) ; // so that otherwise we know
  1182. if (NULL == pPinIn)
  1183. {
  1184. DbgLog((LOG_ERROR, 1, TEXT("ERROR: How can the connected to pin be NULL after connection?"))) ;
  1185. return E_FAIL ;
  1186. }
  1187. IPin *pPinOut2 ;
  1188. PIN_INFO pi ;
  1189. pPinIn->QueryPinInfo(&pi) ;
  1190. pPinIn->Release() ; // don't need the in pin anymore
  1191. DWORD dw ; // temp variable for stream type
  1192. int iPos = 0 ; // which instance of pin of the filter
  1193. int iCount = 0 ; // how many decoded output pins have we found (expected only 1)
  1194. while (SUCCEEDED(hr = FindMatchingPin(pi.pFilter, 0, PINDIR_OUTPUT, TRUE, iPos, &pPinOut2)) &&
  1195. NULL != pPinOut2)
  1196. {
  1197. if (dwStream != (dw = GetPinStreamType(pPinOut2)))
  1198. {
  1199. //
  1200. // Hack: The mediatype for decoded subpicture is video. So while rendering
  1201. // the subpicture stream, if we don't find a subpicture out pin, look for a
  1202. // video out pin too.
  1203. //
  1204. if (AM_DVD_STREAM_SUBPIC == dwStream)
  1205. {
  1206. DbgLog((LOG_TRACE, 3, TEXT("No open out pin for SP stream"))) ;
  1207. //
  1208. // If the output pin is of type video then it's OK --
  1209. // it's the out pin for decoded SP content.
  1210. //
  1211. if (AM_DVD_STREAM_VIDEO != dw)
  1212. {
  1213. DbgLog((LOG_TRACE, 3,
  1214. TEXT("*** Could NOT find open out pin #%d of type 0x%lx for filter of pin %s (SP) ***"),
  1215. iPos, dw, (LPCTSTR)CDisp(pPinIn))) ;
  1216. pPinOut2->Release() ; // otherwise we'll leak!!!
  1217. iPos++ ;
  1218. continue ; // check for other out pins
  1219. }
  1220. DbgLog((LOG_TRACE, 3, TEXT("Found open video out pin %s for the SP stream"),
  1221. (LPCTSTR)CDisp(pPinOut2))) ;
  1222. } // end of if (subpic)
  1223. else // non-subpicture stream
  1224. {
  1225. DbgLog((LOG_TRACE, 1,
  1226. TEXT("*** Could NOT find open out pin #%d of type 0x%lx for filter of pin %s ***"),
  1227. iPos, dw, (LPCTSTR)CDisp(pPinIn))) ;
  1228. pPinOut2->Release() ; // otherwise we'll leak!!!
  1229. iPos++ ;
  1230. continue ; // check for other out pins
  1231. }
  1232. }
  1233. else
  1234. DbgLog((LOG_TRACE, 3, TEXT("Found open out pin %s of matching type 0x%lx"),
  1235. (LPCTSTR)CDisp(pPinOut2), dwStream)) ;
  1236. // Is the output decoded now?
  1237. if (IsOutputDecoded(pPinOut2))
  1238. {
  1239. DbgLog((LOG_TRACE, 1,
  1240. TEXT("Pin %s is going to be returned as decoded out pin #%ld of stream type %ld"),
  1241. (LPCTSTR)CDisp(pPinOut2), iCount+1, dwStream)) ;
  1242. if (iCount < MAX_DEC_OUT_PINS)
  1243. {
  1244. apPinOutDec[iCount] = pPinOut2 ;
  1245. iCount++ ;
  1246. //
  1247. // This is the right place to update the actually used decoder flag
  1248. //
  1249. // NOTE: There is this bleak chance of having multiple output pins etc.
  1250. // but that's a pathological case and we do this for the SP stream only.
  1251. //
  1252. if (*pdwDecFlag != dwNewDecFlag)
  1253. {
  1254. DbgLog((LOG_TRACE, 2,
  1255. TEXT("Decoding option changed from 0x%lx to 0x%lx for stream 0x%lx on out pin %s"),
  1256. *pdwDecFlag, dwNewDecFlag, dwStream, (LPCTSTR)CDisp(pPinOut2))) ;
  1257. *pdwDecFlag = dwNewDecFlag ;
  1258. }
  1259. }
  1260. else
  1261. {
  1262. DbgLog((LOG_TRACE, 1, TEXT("WARNING: Way too many out pins to be returned. Ignoring now..."))) ;
  1263. }
  1264. }
  1265. else // not yet fully decoded -- try more
  1266. {
  1267. hr = DecodeDVDStream(pPinOut2, dwStream, pdwDecFlag, pStatus, apPinOutDec) ;
  1268. if (FAILED(hr))
  1269. {
  1270. DbgLog((LOG_TRACE, 3, TEXT("Decoding of pin %s failed (Error 0x%lx)"),
  1271. (LPCTSTR)CDisp(pPinOut2), hr)) ;
  1272. pPinOut2->Release() ;
  1273. pi.pFilter->Release() ; // else we leak!!!
  1274. return hr ;
  1275. }
  1276. pPinOut2->Release() ; // done with this pin
  1277. }
  1278. iPos++ ; // look for the next open out pin
  1279. DbgLog((LOG_TRACE, 5, TEXT("Going to look for open out pin #%d..."), iPos)) ;
  1280. } // end of while (FindMatchingPin()) loop
  1281. pi.pFilter->Release() ; // else we leak!!!
  1282. return S_OK ; // success!!!
  1283. }
  1284. //
  1285. // There is an assumption in this function that we don't need to create multiple
  1286. // instances of a WDM filter to get a suitable input pin on it. If we have to
  1287. // ever do that there has to be substantial changes in this function and/or
  1288. // CreateDVDHWDecoders() function.
  1289. //
  1290. HRESULT CDvdGraphBuilder::HWDecodeDVDStream(IPin *pPinOut, DWORD dwStream, IPin **ppPinIn,
  1291. AM_DVD_RENDERSTATUS *pStatus)
  1292. {
  1293. DbgLog((LOG_TRACE, 4,
  1294. TEXT("CDvdGraphBuilder::HWDecodeDVDStream(%s, 0x%lx, 0x%lx, 0x%lx)"),
  1295. (LPCTSTR)CDisp(pPinOut), dwStream, ppPinIn, pStatus)) ;
  1296. *ppPinIn = NULL ; // to start with
  1297. int iCount = m_ListHWDecs.GetCount() ;
  1298. if (0 == iCount)
  1299. return VFW_E_DVD_DECNOTENOUGH ;
  1300. HRESULT hr ;
  1301. BOOL bConnected = FALSE ; // to start with
  1302. int i ;
  1303. int j ;
  1304. BOOL bNewlyAdded ;
  1305. LPWSTR lpszwName ;
  1306. IBaseFilter *pFilter ;
  1307. IPin *pPinIn ;
  1308. for (i = 0 ; !bConnected && i < iCount ; i++)
  1309. {
  1310. // Get the next HW decoder filter
  1311. if (! m_ListHWDecs.GetFilter(i, &pFilter, &lpszwName) )
  1312. {
  1313. DbgLog((LOG_ERROR, 0, TEXT("ERROR: m_ListHWDecs.GetFilter(%d, ...) failed"), i)) ;
  1314. ASSERT(FALSE) ; // so we don't ignore itd
  1315. break ;
  1316. }
  1317. DbgLog((LOG_TRACE, 3, TEXT("HW Dec filter %S will be tried."), lpszwName)) ;
  1318. // If this HW decoder filter is already not in the graph, add it
  1319. if (! m_ListFilters.IsInList(pFilter) )
  1320. {
  1321. DbgLog((LOG_TRACE, 5, TEXT("Filter %S is NOT already in use"), lpszwName)) ;
  1322. hr = m_pGB->AddFilter(pFilter, lpszwName) ;
  1323. ASSERT(SUCCEEDED(hr)) ;
  1324. bNewlyAdded = TRUE ;
  1325. }
  1326. else
  1327. bNewlyAdded = FALSE ;
  1328. // Try every input pin of the required mediatype
  1329. j = 0 ;
  1330. while ( // !bConnected && -- we 'break' out of this loop on connection
  1331. SUCCEEDED(hr = FindMatchingPin(pFilter, dwStream, PINDIR_INPUT,
  1332. TRUE, j, &pPinIn)) &&
  1333. pPinIn)
  1334. {
  1335. // We got an input pin of the required mediatype
  1336. hr = ConnectPins(pPinOut, pPinIn, AM_DVD_CONNECT_DIRECTFIRST) ;
  1337. if (SUCCEEDED(hr))
  1338. {
  1339. if (bNewlyAdded)
  1340. {
  1341. DbgLog((LOG_TRACE, 5, TEXT("Filter %S added to list of filters"), lpszwName)) ;
  1342. m_ListFilters.AddFilter(pFilter, lpszwName, NULL) ; // add to list
  1343. pFilter->AddRef() ; // we need an extra AddRef() here
  1344. }
  1345. EnumFiltersBetweenPins(dwStream, pPinOut, pPinIn, pStatus) ;
  1346. *ppPinIn = pPinIn ; // return this input pin to the caller
  1347. bConnected = TRUE ;
  1348. break ; // connected -- get out of this loop
  1349. // REMEMBER: release the returned pin in the caller
  1350. }
  1351. pPinIn->Release() ; // done with this in pin
  1352. j++ ; // go for the next pin...
  1353. } // end of while (!bConnected && FindMatchingPin())
  1354. // If we couldn't make any connection in the above while() loop then
  1355. // remove the filter, ONLY IF it was added just before the loop.
  1356. if (!bConnected && bNewlyAdded)
  1357. {
  1358. DbgLog((LOG_TRACE, 5,
  1359. TEXT("Couldn't connect to newly added filter %S. Removing it."), lpszwName)) ;
  1360. hr = m_pGB->RemoveFilter(pFilter) ;
  1361. ASSERT(SUCCEEDED(hr)) ;
  1362. }
  1363. } // end of for (i)
  1364. if (! bConnected )
  1365. return VFW_E_DVD_DECNOTENOUGH ;
  1366. return S_OK ; // success!!
  1367. }
  1368. HRESULT CDvdGraphBuilder::SWDecodeDVDStream(IPin *pPinOut, DWORD dwStream, IPin **ppPinIn,
  1369. AM_DVD_RENDERSTATUS *pStatus)
  1370. {
  1371. DbgLog((LOG_TRACE, 4,
  1372. TEXT("CDvdGraphBuilder::SWDecodeDVDStream(%s, 0x%lx, 0x%lx, 0x%lx)"),
  1373. (LPCTSTR)CDisp(pPinOut), dwStream, ppPinIn, pStatus)) ;
  1374. HRESULT hr ;
  1375. IBaseFilter *pFilter ;
  1376. IEnumRegFilters *pEnumFilters ;
  1377. REGFILTER *pRegFilter ;
  1378. IEnumMediaTypes *pEnumMT ;
  1379. AM_MEDIA_TYPE *pmt = NULL;
  1380. IPin *pPinIn ;
  1381. BOOL bConnected = FALSE ; // to start with
  1382. BOOL bNewlyAdded ;
  1383. ULONG ul ;
  1384. int iPos ;
  1385. int j ;
  1386. PIN_INFO pi ;
  1387. *ppPinIn = NULL ; // to start with
  1388. pPinOut->EnumMediaTypes(&pEnumMT) ;
  1389. ASSERT(pEnumMT) ;
  1390. // HACK (kind of) to avoid the Duck filter getting picked up for the SP decoding.
  1391. // First try the existing filters in the graph to see if any of those will take
  1392. // this output pin.
  1393. hr = pPinOut->QueryPinInfo(&pi) ;
  1394. ASSERT(SUCCEEDED(hr)) ;
  1395. while (!bConnected &&
  1396. S_OK == pEnumMT->Next(1, &pmt, &ul) && 1 == ul)
  1397. {
  1398. if (pPinIn = GetFilterForMediaType(dwStream, pmt, pi.pFilter))
  1399. {
  1400. hr = ConnectPins(pPinOut, pPinIn, AM_DVD_CONNECT_DIRECTONLY) ; // .._DIRECTFIRST
  1401. if (SUCCEEDED(hr))
  1402. {
  1403. bConnected = TRUE ;
  1404. *ppPinIn = pPinIn ; // return this input pin to the caller
  1405. }
  1406. else
  1407. pPinIn->Release() ; // release interface only if connection failed
  1408. }
  1409. DeleteMediaType(pmt) ; // done with this mediatype
  1410. pmt = NULL;
  1411. } // end of while() loop
  1412. if (pi.pFilter) // just being cautious
  1413. pi.pFilter->Release() ; // release now; else we leak.
  1414. if (bConnected) // if succeeded in connecting, we are done here
  1415. {
  1416. pEnumMT->Release() ; // done with the MT enumerator
  1417. return S_OK ; // success!!!
  1418. }
  1419. //
  1420. // This output pin does NOT connect to any of the existing filters in the graph.
  1421. // Try to pick one from the regsitry, i.e., the standard process.
  1422. //
  1423. pEnumMT->Reset() ; // start from the beginning again
  1424. while (!bConnected &&
  1425. S_OK == pEnumMT->Next(1, &pmt, &ul) && 1 == ul)
  1426. {
  1427. hr = m_pMapper->EnumMatchingFilters(&pEnumFilters, MERIT_DO_NOT_USE+1,
  1428. TRUE, pmt->majortype, pmt->subtype,
  1429. FALSE, TRUE, GUID_NULL, GUID_NULL) ;
  1430. if (FAILED(hr) || NULL == pEnumFilters)
  1431. {
  1432. DbgLog((LOG_ERROR, 1, TEXT("ERROR: No matching filter enum found (Error 0x%lx)"), hr)) ;
  1433. DeleteMediaType(pmt) ;
  1434. return VFW_E_DVD_RENDERFAIL ;
  1435. }
  1436. while (!bConnected &&
  1437. S_OK == pEnumFilters->Next(1, &pRegFilter, &ul) && 1 == ul)
  1438. {
  1439. bNewlyAdded = FALSE ; // to start the loop with...
  1440. iPos = 0 ;
  1441. // Until connected and we can locate an existing (in use) filter from our list
  1442. while (!bConnected &&
  1443. m_ListFilters.GetFilter(&pRegFilter->Clsid, iPos, &pFilter)) // already in use
  1444. {
  1445. j = 0 ;
  1446. while (SUCCEEDED(hr = FindMatchingPin(pFilter, 0, PINDIR_INPUT, TRUE, j, &pPinIn)) &&
  1447. pPinIn) // got an(other) open in pin
  1448. {
  1449. DbgLog((LOG_TRACE, 5, TEXT("Got in pin %s (%d) of filter %S (old). Try to connect..."),
  1450. (LPCTSTR)CDisp(pPinIn), j, pRegFilter->Name)) ;
  1451. hr = ConnectPins(pPinOut, pPinIn, AM_DVD_CONNECT_DIRECTONLY) ; // .._DIRECTFIRST
  1452. if (SUCCEEDED(hr))
  1453. {
  1454. if (bNewlyAdded)
  1455. m_ListFilters.AddFilter(pFilter, NULL, &(pRegFilter->Clsid)) ;
  1456. // Don't need AddRef() here as it has just been CoCreateInstance()-ed above
  1457. // and is NOT shared between 2 lists.
  1458. bConnected = TRUE ;
  1459. // pPinIn->Release() ; // done with this pin -- release in the caller
  1460. *ppPinIn = pPinIn ; // return this input pin to the caller
  1461. break ; // connection happened -- out of this loop
  1462. // REMEMBER: Release the returned pin in the caller function
  1463. }
  1464. else // couldn't connect
  1465. {
  1466. pPinIn->Release() ; // done with this pin
  1467. j++ ; // try next in pin of this filter
  1468. }
  1469. } // end of while ()
  1470. iPos++ ; // for next filter in list
  1471. }
  1472. if (bConnected) // already succeeded -- we are done!!!
  1473. {
  1474. CoTaskMemFree(pRegFilter) ;
  1475. break ;
  1476. }
  1477. DbgLog((LOG_TRACE, 5, TEXT("Instance %d of filter %S is being created"),
  1478. iPos, pRegFilter->Name)) ;
  1479. hr = CreateFilterInGraph(pRegFilter->Clsid, pRegFilter->Name, &pFilter) ;
  1480. if (FAILED(hr))
  1481. {
  1482. DbgLog((LOG_TRACE, 3, TEXT("Failed to create filter %S (Error 0x%lx)"), pRegFilter->Name, hr)) ;
  1483. CoTaskMemFree(pRegFilter) ; // release this reg filter's info
  1484. continue ; // try the next one
  1485. }
  1486. bNewlyAdded = TRUE ;
  1487. j = 0 ;
  1488. while (!bConnected && // not connected AND ...
  1489. SUCCEEDED(hr = FindMatchingPin(pFilter, 0, PINDIR_INPUT, TRUE, j, &pPinIn)) &&
  1490. pPinIn) // ...got an open in pin
  1491. {
  1492. DbgLog((LOG_TRACE, 5, TEXT("Got in pin %s (%d) of filter %S (new). Try to connect..."),
  1493. (LPCTSTR)CDisp(pPinIn), j, pRegFilter->Name)) ;
  1494. hr = ConnectPins(pPinOut, pPinIn, AM_DVD_CONNECT_DIRECTONLY) ; // .._DIRECTFIRST
  1495. if (SUCCEEDED(hr))
  1496. {
  1497. if (bNewlyAdded)
  1498. m_ListFilters.AddFilter(pFilter, NULL, &(pRegFilter->Clsid)) ;
  1499. // Don't need AddRef() here as it has just been CoCreateInstance()-ed above
  1500. // and is NOT shared between 2 lists.
  1501. bConnected = TRUE ;
  1502. *ppPinIn = pPinIn ; // return this input pin to the caller
  1503. // REMEMBER: release the returned pin in the caller function
  1504. }
  1505. else // couldn't connect
  1506. {
  1507. pPinIn->Release() ; // done with this pin
  1508. j++ ; // try next in pin of this filter
  1509. }
  1510. // pPinIn->Release() ; // done with this pin
  1511. } // end of while (FindMatchingPin())
  1512. if (bConnected) // Nav -> Filter (this) succeeded
  1513. {
  1514. // Video and SP stream: check for VMR compatibility
  1515. if (AM_DVD_STREAM_VIDEO == dwStream ||
  1516. AM_DVD_STREAM_SUBPIC == dwStream)
  1517. {
  1518. // Filter, hopefully decoder, has been connected to the Nav.
  1519. // Now check if it's VMR ompatible.
  1520. BOOL bUseVMR = IsFilterVMRCompatible(pFilter) ;
  1521. SetVMRUse(GetVMRUse() && bUseVMR) ;
  1522. DbgLog((LOG_TRACE, 3, TEXT("Filter %S is %s VMR compatible"),
  1523. pRegFilter->Name, bUseVMR ? TEXT("") : TEXT("*NOT*"))) ;
  1524. }
  1525. }
  1526. else // connection failed
  1527. {
  1528. // If the failed filter was just added then remove it from
  1529. // graph and release it now.
  1530. if (bNewlyAdded)
  1531. {
  1532. DbgLog((LOG_TRACE, 3, TEXT("Couldn't connect to filter %S. Removing it."),
  1533. pRegFilter->Name)) ;
  1534. m_pGB->RemoveFilter(pFilter) ; // not in this graph
  1535. pFilter->Release() ; // don't need this filter
  1536. }
  1537. }
  1538. CoTaskMemFree(pRegFilter) ; // done with this registered filter
  1539. } // end of while (!bConnected && pEnumFilters->Next())
  1540. pEnumFilters->Release() ; // done with filter enumerator
  1541. // release last media type
  1542. DeleteMediaType(pmt) ;
  1543. pmt = NULL;
  1544. } // end of while (enum MTs)
  1545. pEnumMT->Release() ; // done with the MT enumerator
  1546. if (!bConnected)
  1547. return VFW_E_DVD_DECNOTENOUGH ;
  1548. return S_OK ; // success!!
  1549. }
  1550. BOOL CDvdGraphBuilder::IsFilterVMRCompatible(IBaseFilter *pFilter)
  1551. {
  1552. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::IsFilterVMRCompatible(0x%lx)"), pFilter)) ;
  1553. BOOL bResult = FALSE ; // assume old decoder
  1554. //
  1555. // Updated DVD decoders implement IAMDecoderCaps interface to indicate their
  1556. // VMR compatibility.
  1557. //
  1558. IAMDecoderCaps *pDecCaps ;
  1559. HRESULT hr = pFilter->QueryInterface(IID_IAMDecoderCaps, (LPVOID *) &pDecCaps) ;
  1560. if (SUCCEEDED(hr))
  1561. {
  1562. DWORD dwCaps = 0 ;
  1563. hr = pDecCaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR_SUPPORT, &dwCaps) ;
  1564. if (SUCCEEDED(hr))
  1565. {
  1566. bResult = (dwCaps & VMR_SUPPORTED) != 0 ;
  1567. }
  1568. else
  1569. DbgLog((LOG_TRACE, 1, TEXT("IAMDecoderCaps::GetDecoderCaps() failed (error 0x%lx)"), hr)) ;
  1570. pDecCaps->Release() ; // done with it
  1571. }
  1572. else
  1573. DbgLog((LOG_TRACE, 5, TEXT("(Old) Decoder does NOT support IAMDecoderCaps interface"))) ;
  1574. return bResult ;
  1575. }
  1576. #if 0
  1577. void PrintPinRefCount(LPCSTR lpszStr, IPin *pPin)
  1578. {
  1579. #pragma message("WARNING: Should we remove PrintPinRefCount()?")
  1580. #pragma message("WARNING: or at least #ifdef DEBUG?")
  1581. pPin->AddRef() ;
  1582. LONG l = pPin->Release() ;
  1583. DbgLog((LOG_TRACE, 5, TEXT("Ref Count of %s -- %hs: %ld"),
  1584. (LPCTSTR) CDisp(pPin), lpszStr, l)) ;
  1585. }
  1586. #endif // #if 0
  1587. HRESULT CDvdGraphBuilder::ConnectPins(IPin *pPinOut, IPin *pPinIn, DWORD dwOption)
  1588. {
  1589. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::ConnectPins(%s, %s, 0x%lx)"),
  1590. (LPCTSTR)CDisp(pPinOut), (LPCTSTR)CDisp(pPinIn), dwOption)) ;
  1591. // #pragma message("WARNING: Should we remove calls to PrintPinRefCount()?")
  1592. // PrintPinRefCount("Before connection", pPinOut) ;
  1593. // PrintPinRefCount("Before connection", pPinIn) ;
  1594. HRESULT hr ;
  1595. switch (dwOption)
  1596. {
  1597. case AM_DVD_CONNECT_DIRECTONLY:
  1598. case AM_DVD_CONNECT_DIRECTFIRST:
  1599. hr = m_pGB->ConnectDirect(pPinOut, pPinIn, NULL) ;
  1600. if (SUCCEEDED(hr))
  1601. {
  1602. DbgLog((LOG_TRACE, 3, TEXT("Pin %s *directly* connected to pin %s"),
  1603. (LPCTSTR)CDisp(pPinOut), (LPCTSTR)CDisp(pPinIn))) ;
  1604. // PrintPinRefCount("After connection", pPinOut) ;
  1605. // PrintPinRefCount("After connection", pPinIn) ;
  1606. return hr ;
  1607. }
  1608. else // couldn't connect directly
  1609. {
  1610. if (AM_DVD_CONNECT_DIRECTONLY == dwOption)
  1611. {
  1612. // PrintPinRefCount("After connection failed", pPinOut) ;
  1613. // PrintPinRefCount("After connection failed", pPinIn) ;
  1614. return hr ;
  1615. }
  1616. // else let it fall through to try indirect connect next
  1617. }
  1618. case AM_DVD_CONNECT_INDIRECT:
  1619. hr = m_pGB->Connect(pPinOut, pPinIn) ;
  1620. if (SUCCEEDED(hr))
  1621. {
  1622. DbgLog((LOG_TRACE, 3, TEXT("Pin %s *indirectly* connected to pin %s"),
  1623. (LPCTSTR)CDisp(pPinOut), (LPCTSTR)CDisp(pPinIn))) ;
  1624. }
  1625. else
  1626. {
  1627. DbgLog((LOG_TRACE, 5, TEXT("Pin %s did NOT even *indirectly* connect to pin %s"),
  1628. (LPCTSTR)CDisp(pPinOut), (LPCTSTR)CDisp(pPinIn))) ;
  1629. }
  1630. // PrintPinRefCount("After connection attempt", pPinOut) ;
  1631. // PrintPinRefCount("After connection attempt", pPinIn) ;
  1632. return hr ; // whatever it is
  1633. default:
  1634. return E_UNEXPECTED ;
  1635. }
  1636. }
  1637. HRESULT CDvdGraphBuilder::RenderVideoUsingOvMixer(IPin **apPinOut,
  1638. AM_DVD_RENDERSTATUS *pStatus)
  1639. {
  1640. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderVideoUsingOvMixer(0x%lx, 0x%lx)"),
  1641. apPinOut, pStatus)) ;
  1642. HRESULT hr ;
  1643. IPin *pPinIn ;
  1644. BOOL bConnected = FALSE ; // until connects
  1645. //
  1646. // If VMR has somehow been instantiated, we need to remove and release it now.
  1647. //
  1648. if (m_pVMR)
  1649. {
  1650. DbgLog((LOG_TRACE, 3, TEXT("VMR was somehow created and not in use. Removing it..."))) ;
  1651. // Remove it from graph and release it
  1652. m_pGB->RemoveFilter(m_pVMR) ;
  1653. m_pVMR->Release() ;
  1654. m_pVMR = NULL ;
  1655. }
  1656. // IMPORTANT NOTE:
  1657. // For video stream, any decode/rendering problem has to be flagged here
  1658. // as we just downgrade the final result in the caller, but not set any
  1659. // flag there. Also in RenderDecodedVideo(), we may try to use VMR, and
  1660. // if that fails, we fall back on OvMixer. If rendering through OvMixer
  1661. // also fails, then only we set the rendering error status and code.
  1662. //
  1663. hr = EnsureOverlayMixerExists() ;
  1664. if (FAILED(hr))
  1665. {
  1666. // pStatus->hrVPEStatus = hr ; -- actually VPE/Overlay wasn't tried even
  1667. DbgLog((LOG_TRACE, 3, TEXT("Overlay Mixer couldn't be started!!!"))) ;
  1668. pStatus->iNumStreamsFailed++ ;
  1669. pStatus->dwFailedStreamsFlag |= AM_DVD_STREAM_VIDEO ;
  1670. return VFW_E_DVD_RENDERFAIL ;
  1671. }
  1672. // Connect given output pin to OverlayMixer's first input pin
  1673. hr = FindMatchingPin(m_pOvM, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ;
  1674. if (FAILED(hr))
  1675. {
  1676. DbgLog((LOG_ERROR, 1, TEXT("WARNING: No open input pin found on OverlayMixer (Error 0x%lx)"), hr)) ;
  1677. ASSERT(FALSE) ; // so that we know of this weird case
  1678. DbgLog((LOG_TRACE, 3, TEXT("No input pin found on Overlay Mixer!!!"))) ;
  1679. pStatus->iNumStreamsFailed++ ;
  1680. pStatus->dwFailedStreamsFlag |= AM_DVD_STREAM_VIDEO ;
  1681. return VFW_E_DVD_RENDERFAIL ;
  1682. }
  1683. int i = 0 ;
  1684. while (!bConnected && i < MAX_DEC_OUT_PINS && apPinOut[i])
  1685. {
  1686. hr = ConnectPins(apPinOut[i], pPinIn, AM_DVD_CONNECT_DIRECTFIRST) ;
  1687. if (FAILED(hr))
  1688. {
  1689. pStatus->hrVPEStatus = hr ;
  1690. i++ ;
  1691. ASSERT(i <= MAX_DEC_OUT_PINS) ;
  1692. }
  1693. else
  1694. {
  1695. bConnected = TRUE ;
  1696. pStatus->hrVPEStatus = S_OK ; // make sure we don't return any error code
  1697. }
  1698. }
  1699. pPinIn->Release() ; // done with the pin
  1700. if (!bConnected) // if connection to OvMixer's in pin failed => no video on screen
  1701. {
  1702. DbgLog((LOG_TRACE, 3, TEXT("None of the %d video output pins could be connected to OvMixer"), i)) ;
  1703. pStatus->iNumStreamsFailed++ ;
  1704. pStatus->dwFailedStreamsFlag |= AM_DVD_STREAM_VIDEO ;
  1705. return S_FALSE ;
  1706. }
  1707. // Now see if OverlayMixer has an output pin (no out pin in DDraw excl mode).
  1708. // If it has, connect that to the Video Renderer.
  1709. IPin *pPinOutOvM ;
  1710. hr = FindMatchingPin(m_pOvM, 0, PINDIR_OUTPUT, TRUE, 0, &pPinOutOvM) ;
  1711. if (FAILED(hr) || NULL == pPinOutOvM)
  1712. {
  1713. DbgLog((LOG_TRACE, 1, TEXT("No output pin of OverlayMixer -- in DDraw excl mode?"))) ;
  1714. //ASSERT(IsDDrawExclMode()) ;
  1715. return S_OK ; // nothing more to do
  1716. }
  1717. // Create the Video Renderer filter and connect OvMixer's out pin to that
  1718. bConnected = FALSE ; // until connected
  1719. hr = CreateFilterInGraph(CLSID_VideoRenderer, L"Video Renderer", &m_pVR) ;
  1720. if (SUCCEEDED(hr) && m_pVR)
  1721. {
  1722. hr = FindMatchingPin(m_pVR, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ; // Caution: re-using pPinIn
  1723. if (SUCCEEDED(hr) && pPinIn)
  1724. {
  1725. hr = ConnectPins(pPinOutOvM, pPinIn, AM_DVD_CONNECT_DIRECTONLY) ;
  1726. if (FAILED(hr)) // what?!?
  1727. {
  1728. ASSERT(FALSE) ; // so that we notice
  1729. DbgLog((LOG_TRACE, 1, TEXT("No video out pin connected to pin %s -- no video on screen"),
  1730. (LPCTSTR)CDisp(pPinIn))) ;
  1731. }
  1732. else
  1733. {
  1734. bConnected = TRUE ;
  1735. }
  1736. pPinIn->Release() ; // done with VR's in pin
  1737. }
  1738. else // what?!?
  1739. {
  1740. DbgLog((LOG_TRACE, 1, TEXT("No input pin of VideoRenderer?!?"))) ;
  1741. // Remove it from graph; else a useless window will pop up
  1742. m_pGB->RemoveFilter(m_pVR) ;
  1743. m_pVR->Release() ;
  1744. m_pVR = NULL ;
  1745. }
  1746. }
  1747. else // what?!?
  1748. {
  1749. ASSERT(FALSE) ; // so that we notice
  1750. DbgLog((LOG_TRACE, 1,
  1751. TEXT("WARNING: Can't start Video Renderer (Error 0x%lx) -- no video on screen"),
  1752. hr)) ;
  1753. // bConnected = FALSE ;
  1754. }
  1755. pPinOutOvM->Release() ; // done with OvMixer's out pin
  1756. if (! bConnected ) // if connection to OvMixer's in pin failed => no video on screen
  1757. {
  1758. DbgLog((LOG_TRACE, 1, TEXT("WARNING: Couldn't render Video stream using OvMixer"))) ;
  1759. pStatus->iNumStreamsFailed++ ;
  1760. pStatus->dwFailedStreamsFlag |= AM_DVD_STREAM_VIDEO ;
  1761. return S_FALSE ;
  1762. }
  1763. return S_OK ;
  1764. }
  1765. HRESULT CDvdGraphBuilder::RenderVideoUsingVMR(IPin **apPinOut,
  1766. AM_DVD_RENDERSTATUS *pStatus)
  1767. {
  1768. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderVideoUsingVMR(0x%lx, 0x%lx)"),
  1769. apPinOut, pStatus)) ;
  1770. HRESULT hr ;
  1771. IPin *pPinIn ;
  1772. BOOL bConnected = FALSE ; // until connects
  1773. //
  1774. // If OvMixer has somehow been instantiated, we need to remove and release it now.
  1775. //
  1776. if (m_pOvM)
  1777. {
  1778. DbgLog((LOG_TRACE, 3, TEXT("OvMixer was somehow created. Can't use VMR now."))) ;
  1779. return E_FAIL ;
  1780. // DbgLog((LOG_TRACE, 3, TEXT("OvMixer was somehow created and not in use. Removing it..."))) ;
  1781. // Remove it from graph and release it
  1782. // m_pGB->RemoveFilter(m_pOvM) ;
  1783. // m_pOvM->Release() ;
  1784. // m_pOvM = NULL ;
  1785. }
  1786. //
  1787. // Now instantiate VMR and try to render using it
  1788. //
  1789. hr = EnsureVMRExists() ;
  1790. if (S_OK != hr)
  1791. {
  1792. DbgLog((LOG_TRACE, 3, TEXT("Video Mixing Renderer couldn't be started or configured"))) ;
  1793. // pStatus->iNumStreamsFailed++ ;
  1794. // pStatus->dwFailedStreamsFlag |= AM_DVD_STREAM_VIDEO ;
  1795. return E_FAIL ; // caught by RenderDecodedVideo()
  1796. }
  1797. // Connect given output pin to VMR's first input pin
  1798. hr = FindMatchingPin(m_pVMR, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ;
  1799. if (FAILED(hr))
  1800. {
  1801. DbgLog((LOG_ERROR, 1, TEXT("WARNING: No open input pin found on VMR (Error 0x%lx)"), hr)) ;
  1802. ASSERT(FALSE) ; // so that we know of this weird case
  1803. // Remove it from graph; it's useless now
  1804. m_pGB->RemoveFilter(m_pVMR) ;
  1805. m_pVMR->Release() ;
  1806. m_pVMR = NULL ;
  1807. // pStatus->iNumStreamsFailed++ ;
  1808. // pStatus->dwFailedStreamsFlag |= AM_DVD_STREAM_VIDEO ;
  1809. return E_UNEXPECTED ; // caught by RenderDecodedVideo(), but unexpected
  1810. }
  1811. // Try to connect the first out pin of the video decoder to VMR's 1st in pin
  1812. int i = 0 ;
  1813. while (!bConnected && i < MAX_DEC_OUT_PINS && apPinOut[i])
  1814. {
  1815. hr = ConnectPins(apPinOut[i], pPinIn, AM_DVD_CONNECT_DIRECTFIRST) ;
  1816. if (FAILED(hr))
  1817. {
  1818. pStatus->hrVPEStatus = hr ;
  1819. i++ ;
  1820. ASSERT(i <= MAX_DEC_OUT_PINS) ;
  1821. }
  1822. else
  1823. {
  1824. bConnected = TRUE ;
  1825. pStatus->hrVPEStatus = S_OK ; // make sure we don't return any error code
  1826. }
  1827. }
  1828. pPinIn->Release() ; // done with the pin
  1829. if (! bConnected ) // if connection to VMR's in pin failed => no video on screen
  1830. {
  1831. DbgLog((LOG_TRACE, 1, TEXT("WARNING: Couldn't render Video stream using VMR"))) ;
  1832. // Remove it from graph; it's useless now
  1833. m_pGB->RemoveFilter(m_pVMR) ;
  1834. m_pVMR->Release() ;
  1835. m_pVMR = NULL ;
  1836. // pStatus->iNumStreamsFailed++ ;
  1837. // pStatus->dwFailedStreamsFlag |= AM_DVD_STREAM_VIDEO ;
  1838. return E_UNEXPECTED ; // S_FALSE ;
  1839. }
  1840. return S_OK ;
  1841. }
  1842. HRESULT CDvdGraphBuilder::RenderVideoUsingVPM(IPin **apPinOut,
  1843. AM_DVD_RENDERSTATUS *pStatus,
  1844. IPin **apPinOutVPM)
  1845. {
  1846. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderVideoUsingVPM(0x%lx, 0x%lx, 0x%lx)"),
  1847. apPinOut, pStatus, apPinOutVPM)) ;
  1848. HRESULT hr ;
  1849. IPin *pPinIn ;
  1850. IPin *pPinOut ;
  1851. BOOL bConnected = FALSE ; // until connects
  1852. // Filter, hopefully decoder, has been connected to the Nav.
  1853. // Now try to connect it to VPM (and later to VMR).
  1854. ASSERT(NULL == m_pVPM) ;
  1855. // *apPinOutVPM = NULL ; // to start with
  1856. hr = CreateFilterInGraph(CLSID_VideoPortManager, L"Video Port Manager", &m_pVPM) ;
  1857. if (FAILED(hr))
  1858. {
  1859. DbgLog((LOG_TRACE, 3, TEXT("VPM couldn't be started!!!"))) ;
  1860. return E_FAIL ; // caught by RenderDecodedVideo()
  1861. }
  1862. // Connect given output pin to VPM's first input pin
  1863. hr = FindMatchingPin(m_pVPM, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ;
  1864. if (FAILED(hr))
  1865. {
  1866. DbgLog((LOG_ERROR, 1, TEXT("WARNING: No open input pin found on VPM (Error 0x%lx)"), hr)) ;
  1867. ASSERT(FALSE) ; // so that we know of this weird case
  1868. // Remove it from graph; it's useless now
  1869. m_pGB->RemoveFilter(m_pVPM) ;
  1870. m_pVPM->Release() ;
  1871. m_pVPM= NULL ;
  1872. return E_UNEXPECTED ; // caught by RenderDecodedVideo()
  1873. }
  1874. // Try to connect the first out pin of the HW video decoder to VPM's in pin
  1875. int i = 0 ;
  1876. while (!bConnected && i < MAX_DEC_OUT_PINS && apPinOut[i])
  1877. {
  1878. hr = ConnectPins(apPinOut[i], pPinIn, AM_DVD_CONNECT_DIRECTFIRST) ;
  1879. if (FAILED(hr))
  1880. {
  1881. pStatus->hrVPEStatus = hr ;
  1882. i++ ;
  1883. ASSERT(i <= MAX_DEC_OUT_PINS) ;
  1884. }
  1885. else
  1886. {
  1887. bConnected = TRUE ;
  1888. pStatus->hrVPEStatus = S_OK ; // make sure we don't return any error code
  1889. }
  1890. }
  1891. pPinIn->Release() ; // done with the pin
  1892. if (! bConnected ) // if connection to VPM's in pin failed => no video on screen
  1893. {
  1894. DbgLog((LOG_TRACE, 1, TEXT("WARNING: Couldn't render (HW) Video stream using VPM"))) ;
  1895. // Remove it from graph; it's useless now
  1896. m_pGB->RemoveFilter(m_pVPM) ;
  1897. m_pVPM->Release() ;
  1898. m_pVPM = NULL ;
  1899. return E_FAIL ;
  1900. }
  1901. // Connected!! Now find the first out pin of the VPM (to connect to VMR).
  1902. hr = FindMatchingPin(m_pVPM, 0, PINDIR_OUTPUT, TRUE, 0, &pPinOut) ;
  1903. ASSERT(SUCCEEDED(hr)) ;
  1904. apPinOutVPM[0] = pPinOut ; // only one pin returned; release in the caller
  1905. return hr ;
  1906. }
  1907. HRESULT CDvdGraphBuilder::RenderDecodedVideo(IPin **apPinOut,
  1908. AM_DVD_RENDERSTATUS *pStatus,
  1909. DWORD dwDecFlag)
  1910. {
  1911. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderDecodedVideo(0x%lx, 0x%lx, 0x%lx)"),
  1912. apPinOut, pStatus, dwDecFlag)) ;
  1913. HRESULT hr = S_OK ;
  1914. // SWDecodeDVDStream() method tried to detect if the video/SP decoder is
  1915. // VMR-compatible. If not, it has set a flag (m_bTryVMR to FALSE), so here
  1916. // we know which renderer to use.
  1917. //
  1918. // For hardware decoders that work with VPE, we don't check the VMR-compatibility.
  1919. // We just try to connect it to VPM and VMR. If that doesn't work, use OvMixer. We
  1920. // avoid trying to connect the non-VPE decoders to VPM, because we know that DXR2,
  1921. // which uses analog overlay, gets completely messed up if it's even attempted to
  1922. // connect to VPM (which fails anyway).
  1923. //
  1924. // We first try to use VMR, if we are supposed to, i.e.,
  1925. // a) DDraw (non-)exclusive mode is NOT being used
  1926. // b) the decoder(s) is VMR compatible
  1927. // c) no one has asked us not to (in some other way)
  1928. // If that succeeds, Great!!! Otherwise we fall back on using OvMixer, so
  1929. // that we can at least play the DVD.
  1930. // In case we try to use OvMixer, and that for some reason fails to connect,
  1931. // the error flags and code are set in RenderVideoUsingOvMixer() method.
  1932. //
  1933. if (GetVMRUse()) // VMR can be used (so far)
  1934. {
  1935. //
  1936. // We should try to use VMR first....
  1937. //
  1938. // If HW decoder filter is being used, we check if the output type is VPVideo,
  1939. // and then only we'll try to use VPM for VMR first. If that works, we'll
  1940. // return the out pin of VPM. If it fails, we'll set a flag so that
  1941. // RenderDecodedVideo() method knows and uses OvMixer as a fallback option.
  1942. // If the output mediatype is non-VPE (e.g., analog overlay), we do NOT even
  1943. // try to connect to VPM, and fall back to OvMixer.
  1944. //
  1945. if (AM_DVD_HWDEC_ONLY == dwDecFlag) // video decoded in HW
  1946. {
  1947. DbgLog((LOG_TRACE, 5, TEXT("HW decoder used for Video. Is it VMR-compatible?"))) ;
  1948. if (IsOutputTypeVPVideo(apPinOut[0])) // output type is VPE => use VPM
  1949. { // Checking the first out pin should be fine
  1950. // VPVideo stream: Try to use VPM and VMR for rendering
  1951. DbgLog((LOG_TRACE, 5, TEXT("HW decoder with VPE -- connect to VPM+VMR"))) ;
  1952. IPin *apPinOutVPM[2] ; // There is only one out pin of VPM (one for NULL)
  1953. ResetPinInterface(apPinOutVPM, NUMELMS(apPinOutVPM)) ;
  1954. hr = RenderVideoUsingVPM(apPinOut, pStatus, apPinOutVPM) ; // returns VPM's out pin
  1955. // If the success status is still maintained, use the VMR.
  1956. if (SUCCEEDED(hr))
  1957. {
  1958. DbgLog((LOG_TRACE, 5, TEXT("HW decoder connected to VPM. Now connect to VMR."))) ;
  1959. hr = RenderVideoUsingVMR(apPinOutVPM, pStatus) ; // render VPM's out pin via VMR
  1960. ReleasePinInterface(apPinOutVPM) ; // done with VPM out pin interface
  1961. if (FAILED(hr))
  1962. {
  1963. DbgLog((LOG_TRACE, 5, TEXT("VPM - VMR connection failed. Removing VPM..."))) ;
  1964. if (m_pVPM)
  1965. {
  1966. EXECUTE_ASSERT(SUCCEEDED(m_pGB->RemoveFilter(m_pVPM))) ;
  1967. m_pVPM->Release() ;
  1968. m_pVPM = NULL ;
  1969. }
  1970. }
  1971. }
  1972. else
  1973. {
  1974. ReleasePinInterface(apPinOutVPM) ; // shouldn't be needed, but...
  1975. }
  1976. } // end of if (VPVideo)
  1977. else // output type is not VPE => use OvMixer (Not VPM+VMR)
  1978. {
  1979. DbgLog((LOG_TRACE, 5, TEXT("Non-VPE HW decoder -- didn't try VPM+VMR"))) ;
  1980. hr = E_FAIL ; // set failure code so that it's tried with OvMixer below
  1981. }
  1982. } // end of if (HW decoder used)
  1983. else // we are using SW video decoder -- render directly using VMR
  1984. {
  1985. DbgLog((LOG_TRACE, 5, TEXT("HW decoder not used. Directly connect to VMR..."))) ;
  1986. hr = RenderVideoUsingVMR(apPinOut, pStatus) ;
  1987. }
  1988. // In case anything above failed, ditch VMR, and go for OvMixer.
  1989. if (FAILED(hr))
  1990. {
  1991. DbgLog((LOG_TRACE, 4, TEXT("Render using VMR failed. Falling back on OvMixer..."))) ;
  1992. //
  1993. // NOTE: If we can't use VMR for video, no point trying it for SP stream
  1994. //
  1995. SetVMRUse(FALSE) ;
  1996. hr = RenderVideoUsingOvMixer(apPinOut, pStatus) ;
  1997. }
  1998. }
  1999. else // we are not supposed to use VMR; that means use OvMixer
  2000. {
  2001. hr = RenderVideoUsingOvMixer(apPinOut, pStatus) ;
  2002. }
  2003. return hr ;
  2004. }
  2005. HRESULT CDvdGraphBuilder::RenderDecodedAudio(IPin **apPinOut, AM_DVD_RENDERSTATUS *pStatus)
  2006. {
  2007. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderDecodedAudio(0x%lx, 0x%lx)"),
  2008. apPinOut, pStatus)) ;
  2009. HRESULT hr ;
  2010. HRESULT hrFinal = S_OK ;
  2011. BOOL bConnected = FALSE ; // until connected
  2012. IPin *pPinIn = NULL ;
  2013. ASSERT(NULL == m_pAR) ; // so that we know
  2014. // Create the Audio Renderer filter and connect decoder's audio out pin to that
  2015. hr = CreateFilterInGraph(CLSID_DSoundRender, L"DSound Renderer", &m_pAR) ;
  2016. if (SUCCEEDED(hr))
  2017. {
  2018. // Get an input pin to Audio Renderer
  2019. hr = FindMatchingPin(m_pAR, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ;
  2020. ASSERT(SUCCEEDED(hr) && pPinIn) ;
  2021. }
  2022. else
  2023. {
  2024. ASSERT(! TEXT("Coundn't start Audio Renderer") ) ; // so that we notice
  2025. DbgLog((LOG_TRACE, 1,
  2026. TEXT("WARNING: Can't start Audio Renderer (Error 0x%lx) -- no audio from speakers"),
  2027. hr)) ;
  2028. hrFinal = S_FALSE ; // no audio from speakers -- result downgraded
  2029. }
  2030. //
  2031. // We'll try to render all the decoded audio out pins
  2032. //
  2033. for (int i = 0 ; i < MAX_DEC_OUT_PINS && apPinOut[i]; i++)
  2034. {
  2035. if (pPinIn) // if we have an open input pin of Audio Renderer
  2036. {
  2037. hr = m_pGB->Connect(apPinOut[i], pPinIn) ;
  2038. if (SUCCEEDED(hr)) // decoded audio connected to audio renderer
  2039. {
  2040. DbgLog((LOG_TRACE, 5, TEXT("Pin %s connected to pin %s"),
  2041. (LPCTSTR)CDisp(apPinOut[i]), (LPCTSTR)CDisp(pPinIn))) ;
  2042. EnumFiltersBetweenPins(AM_DVD_STREAM_AUDIO, apPinOut[i], pPinIn, pStatus) ;
  2043. bConnected = TRUE ;
  2044. pPinIn->Release() ; // done with this pin interface
  2045. pPinIn = NULL ;
  2046. // Let's try the next out pin, if any...
  2047. continue ;
  2048. }
  2049. ASSERT(!TEXT("Couldn't connect audio pin")) ; // so that we notice
  2050. DbgLog((LOG_TRACE, 1, TEXT("Pin %s (#%ld) did NOT connect to pin %s"),
  2051. (LPCTSTR)CDisp(apPinOut[i]), i, (LPCTSTR)CDisp(pPinIn))) ;
  2052. }
  2053. //
  2054. // We could come here, because either
  2055. // 1. DSound Renderer didn't start (no audio device)
  2056. // 2. we couldn't get an in pin to DSound Renderer (impossible, but...)
  2057. //
  2058. // Couldn't connect the outout pin to a known renderer. Let's try to
  2059. // just render, and see if any filter (S/PDIF?) connects to it.
  2060. //
  2061. hr = m_pGB->Render(apPinOut[i]) ;
  2062. if (FAILED(hr))
  2063. {
  2064. ASSERT(!TEXT("Audio out pin didn't render at all")) ; // so that we notice
  2065. DbgLog((LOG_TRACE, 1, TEXT("Pin %s (#%ld) did NOT render at all"),
  2066. (LPCTSTR)CDisp(apPinOut[i]), i)) ;
  2067. }
  2068. // Now onto the next decoded audio out pin, if any...
  2069. } // end of while (i ...) loop
  2070. if (! bConnected ) // connection to Audio Renderer failed => no audio on speakers
  2071. {
  2072. DbgLog((LOG_TRACE, 1,
  2073. TEXT("No decoded audio pin connect to AudioRenderer -- no audio from speakers"))) ;
  2074. if (m_pAR) // if we had an Audio Renderer
  2075. {
  2076. if (pPinIn) // if we had an in pin that we couldn't connect to,
  2077. pPinIn->Release() ; // let it go now.
  2078. // Remove Audio Renderer from graph
  2079. m_pGB->RemoveFilter(m_pAR) ;
  2080. m_pAR->Release() ;
  2081. m_pAR = NULL ;
  2082. }
  2083. hrFinal = S_FALSE ;
  2084. }
  2085. return hrFinal ;
  2086. }
  2087. HRESULT CDvdGraphBuilder::RenderSubpicUsingOvMixer(IPin **apPinOut,
  2088. AM_DVD_RENDERSTATUS *pStatus)
  2089. {
  2090. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderSubpicUsingOvMixer(0x%lx, 0x%lx)"),
  2091. apPinOut, pStatus)) ;
  2092. HRESULT hr ;
  2093. BOOL bConnected = FALSE ; // until connected
  2094. IPin *pPinIn ;
  2095. int i = 0 ;
  2096. ASSERT(m_pOvM) ; // it must be there, if video stream was rendered
  2097. // Now connect the given out pin to the next available in pin of OvMixer
  2098. hr = FindMatchingPin(m_pOvM, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ;
  2099. if (SUCCEEDED(hr) && pPinIn)
  2100. {
  2101. while (!bConnected && i < MAX_DEC_OUT_PINS && apPinOut[i])
  2102. {
  2103. hr = ConnectPins(apPinOut[i], pPinIn, AM_DVD_CONNECT_DIRECTONLY) ;
  2104. if (FAILED(hr)) // what?!?
  2105. {
  2106. // ASSERT(FALSE) ; // so that we notice
  2107. DbgLog((LOG_TRACE, 1, TEXT("Pin %s (#%ld) did NOT connect to pin %s -- no SP"),
  2108. (LPCTSTR)CDisp(apPinOut[i]), i, (LPCTSTR)CDisp(pPinIn))) ;
  2109. i++ ;
  2110. ASSERT(i <= MAX_DEC_OUT_PINS) ;
  2111. }
  2112. else
  2113. {
  2114. DbgLog((LOG_TRACE, 5, TEXT("Pin %s is directly connected to pin %s"),
  2115. (LPCTSTR)CDisp(apPinOut[i]), (LPCTSTR)CDisp(pPinIn))) ;
  2116. bConnected = TRUE ;
  2117. }
  2118. }
  2119. pPinIn->Release() ; // done with OvMixer's in pin
  2120. }
  2121. else // what?!?
  2122. {
  2123. DbgLog((LOG_TRACE, 1, TEXT("WARNING: No more input pin of OverlayMixer?!?"))) ;
  2124. }
  2125. return (bConnected ? S_OK : hr) ; // this should be the same as "return hr ;"
  2126. }
  2127. HRESULT CDvdGraphBuilder::RenderSubpicUsingVMR(IPin **apPinOut,
  2128. AM_DVD_RENDERSTATUS *pStatus)
  2129. {
  2130. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderSubpicUsingVMR(0x%lx, 0x%lx)"),
  2131. apPinOut, pStatus)) ;
  2132. HRESULT hr ;
  2133. BOOL bConnected = FALSE ; // until connected
  2134. IPin *pPinIn ;
  2135. int i = 0 ;
  2136. ASSERT(m_pVMR) ; // it must be there, if video stream was rendered
  2137. // Now connect the given out pin to the next available in pin of VMR
  2138. hr = FindMatchingPin(m_pVMR, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ;
  2139. if (SUCCEEDED(hr) && pPinIn)
  2140. {
  2141. while (!bConnected && i < MAX_DEC_OUT_PINS && apPinOut[i])
  2142. {
  2143. hr = ConnectPins(apPinOut[i], pPinIn, AM_DVD_CONNECT_DIRECTONLY) ;
  2144. if (FAILED(hr)) // what?!?
  2145. {
  2146. // ASSERT(FALSE) ; // so that we notice
  2147. DbgLog((LOG_TRACE, 1, TEXT("Pin %s (#%ld) did NOT connect to pin %s -- no SP"),
  2148. (LPCTSTR)CDisp(apPinOut[i]), i, (LPCTSTR)CDisp(pPinIn))) ;
  2149. i++ ;
  2150. ASSERT(i <= MAX_DEC_OUT_PINS) ;
  2151. }
  2152. else
  2153. {
  2154. DbgLog((LOG_TRACE, 5, TEXT("Pin %s is directly connected to pin %s"),
  2155. (LPCTSTR)CDisp(apPinOut[i]), (LPCTSTR)CDisp(pPinIn))) ;
  2156. bConnected = TRUE ;
  2157. }
  2158. }
  2159. pPinIn->Release() ; // done with VMR's in pin
  2160. }
  2161. else // what?!?
  2162. {
  2163. DbgLog((LOG_TRACE, 1, TEXT("WARNING: No more input pin of VMR?!?"))) ;
  2164. }
  2165. return (bConnected ? S_OK : hr) ; // this should be the same as "return hr ;"
  2166. }
  2167. HRESULT CDvdGraphBuilder::RenderDecodedSubpic(IPin **apPinOut, AM_DVD_RENDERSTATUS *pStatus)
  2168. {
  2169. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderDecodedSubpic(0x%lx, 0x%lx)"),
  2170. apPinOut, pStatus)) ;
  2171. HRESULT hr ;
  2172. //
  2173. // Render the decoded subpicture stream ONLY IF the user wants that
  2174. //
  2175. if (!m_bUseVPE || IsDDrawExclMode())
  2176. {
  2177. DbgLog((LOG_TRACE, 1, TEXT("SP Stream: RenderDvdVideoVolume() skipped for %s and %s"),
  2178. m_bUseVPE ? "VPE" : "no VPE", IsDDrawExclMode() ? "DDraw excl mode" : "normal mode")) ;
  2179. return S_OK ;
  2180. }
  2181. // We have already attempted to render the video straem. If that has failed,
  2182. // there is no point trying to render the subpicture stream -- just indicate
  2183. // that this stream didn't render and return.
  2184. if (pStatus->dwFailedStreamsFlag & AM_DVD_STREAM_VIDEO)
  2185. {
  2186. DbgLog((LOG_TRACE, 1, TEXT("WARNING: Video stream didn't render. Skipping SP rendering."))) ;
  2187. return S_FALSE ;
  2188. }
  2189. if (GetVMRUse()) // if VMR is to be used
  2190. {
  2191. DbgLog((LOG_TRACE, 5, TEXT("Rendering SP stream using VMR"))) ;
  2192. hr = RenderSubpicUsingVMR(apPinOut, pStatus) ;
  2193. }
  2194. else // OvMixer is being used
  2195. {
  2196. DbgLog((LOG_TRACE, 5, TEXT("Rendering SP stream using OvMixer"))) ;
  2197. hr = RenderSubpicUsingOvMixer(apPinOut, pStatus) ;
  2198. }
  2199. //
  2200. // We don't set the following flag and values anymore as part of the hack
  2201. // to ignore failure to connect *some* decoded-SP-ish out pin in the case
  2202. // of HW decoders. The caller of this method knows if the decoder being
  2203. // used is HW or SW and based on that it will ignore any failure or not.
  2204. //
  2205. if (FAILED(hr)) // if connection to OvMixer's in pin failed => no SP (weird!!)
  2206. {
  2207. DbgLog((LOG_TRACE, 1, TEXT("WARNING: Subpic pin could NOT connect to renderer"))) ;
  2208. return hr ; // S_FALSE ;
  2209. }
  2210. return S_OK ; // complete success!!!
  2211. }
  2212. HRESULT CDvdGraphBuilder::RenderLine21Stream(IPin *pPinOut, AM_DVD_RENDERSTATUS *pStatus)
  2213. {
  2214. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderLine21Stream(%s, 0x%lx)"),
  2215. (LPCTSTR)CDisp(pPinOut), pStatus)) ;
  2216. HRESULT hr ;
  2217. BOOL bConnected = FALSE ; // until connected
  2218. IPin *pPinIn ;
  2219. ASSERT(NULL == m_pL21Dec) ; // so that we know
  2220. //
  2221. // Create the Line21 Decoder filter and connect given out pin to that
  2222. //
  2223. if (GetVMRUse()) // for VMR use Line21 Decoder2
  2224. {
  2225. hr = CreateFilterInGraph(CLSID_Line21Decoder2, L"Line21 Decoder2", &m_pL21Dec) ;
  2226. }
  2227. else // for OvMixer, keep using the old one
  2228. {
  2229. hr = CreateFilterInGraph(CLSID_Line21Decoder, L"Line21 Decoder", &m_pL21Dec) ;
  2230. }
  2231. if (SUCCEEDED(hr))
  2232. {
  2233. hr = FindMatchingPin(m_pL21Dec, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ;
  2234. if (SUCCEEDED(hr) && pPinIn)
  2235. {
  2236. hr = ConnectPins(pPinOut, pPinIn, AM_DVD_CONNECT_DIRECTONLY) ;
  2237. if (FAILED(hr)) // what?!?
  2238. {
  2239. ASSERT(FALSE) ;
  2240. DbgLog((LOG_TRACE, 1, TEXT("Pin %s did NOT connect to pin %s -- no CC"),
  2241. (LPCTSTR)CDisp(pPinOut), (LPCTSTR)CDisp(pPinIn))) ;
  2242. pPinIn->Release() ; // release pin before removing filter
  2243. m_pGB->RemoveFilter(m_pL21Dec) ;
  2244. m_pL21Dec->Release() ;
  2245. m_pL21Dec = NULL ;
  2246. }
  2247. else
  2248. {
  2249. bConnected = TRUE ;
  2250. pPinIn->Release() ; // because we do so for the failure case
  2251. }
  2252. }
  2253. else // what?!?
  2254. {
  2255. DbgLog((LOG_TRACE, 1, TEXT("No input pin of Line21 Decoder(2)?!?"))) ;
  2256. // Remove it from graph
  2257. m_pGB->RemoveFilter(m_pL21Dec) ;
  2258. m_pL21Dec->Release() ;
  2259. m_pL21Dec = NULL ;
  2260. }
  2261. }
  2262. else // what?!?
  2263. {
  2264. // ASSERT(FALSE) ; // so that we notice -- not until lin21dec2 is done
  2265. DbgLog((LOG_TRACE, 1,
  2266. TEXT("WARNING: Can't start Line21 Decoder(2) (Error 0x%lx) -- no CC"),
  2267. hr)) ;
  2268. }
  2269. if (! bConnected ) // if connection to OvMixer's in pin failed => no video on screen
  2270. {
  2271. DbgLog((LOG_TRACE, 1, TEXT("WARNING: Pin %s could NOT connect to Line21 Decoder(2)"),
  2272. (LPCTSTR)CDisp(pPinOut))) ;
  2273. return hr ;
  2274. }
  2275. // Now connect line21 decoder(2)'s output to OvMixer/VMR's in pin
  2276. bConnected = FALSE ; // until connected again
  2277. IPin *pPinOutL21 ;
  2278. hr = FindMatchingPin(m_pL21Dec, 0, PINDIR_OUTPUT, TRUE, 0, &pPinOutL21) ;
  2279. ASSERT(SUCCEEDED(hr)) ;
  2280. if (GetVMRUse()) // find VMR's in pin
  2281. {
  2282. hr = FindMatchingPin(m_pVMR, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ; // Caution: reusing pPinIn
  2283. }
  2284. else // find OvMixer's in pin
  2285. {
  2286. hr = FindMatchingPin(m_pOvM, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ; // Caution: reusing pPinIn
  2287. }
  2288. ASSERT(SUCCEEDED(hr)) ;
  2289. if (pPinOutL21 && pPinIn)
  2290. {
  2291. hr = ConnectPins(pPinOutL21, pPinIn, AM_DVD_CONNECT_DIRECTONLY) ;
  2292. if (FAILED(hr)) // what?!?
  2293. {
  2294. ASSERT(FALSE) ; // so that we notice
  2295. DbgLog((LOG_TRACE, 1, TEXT("Pin %s did NOT connect to pin %s -- no CC"),
  2296. (LPCTSTR)CDisp(pPinOutL21), (LPCTSTR)CDisp(pPinIn))) ;
  2297. pPinOutL21->Release() ; // release pin before removing filter
  2298. m_pGB->RemoveFilter(m_pL21Dec) ;
  2299. m_pL21Dec->Release() ;
  2300. m_pL21Dec = NULL ;
  2301. }
  2302. else
  2303. {
  2304. bConnected = TRUE ;
  2305. pPinOutL21->Release() ; // because we do so in the failure case
  2306. }
  2307. pPinIn->Release() ; // done with OvMixer's in pin
  2308. }
  2309. else
  2310. {
  2311. DbgLog((LOG_TRACE, 1, TEXT("WARNING: Couldn't get necessary in/out pin"))) ;
  2312. if (pPinIn)
  2313. pPinIn->Release() ;
  2314. if (pPinOutL21)
  2315. pPinOutL21->Release() ;
  2316. // Remove it from graph
  2317. m_pGB->RemoveFilter(m_pL21Dec) ;
  2318. m_pL21Dec->Release() ;
  2319. m_pL21Dec = NULL ;
  2320. }
  2321. if (! bConnected ) // if connection to OvMixer's in pin failed => no CC
  2322. {
  2323. DbgLog((LOG_TRACE, 1, TEXT("WARNING: Line21Dec output could NOT connect to OvMixer/VMR"))) ;
  2324. return hr ;
  2325. }
  2326. return S_OK ; // complete success!!!
  2327. }
  2328. BOOL CDvdGraphBuilder::IsOutputDecoded(IPin *pPinOut)
  2329. {
  2330. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::IsOutputDecoded(%s)"),
  2331. (LPCTSTR)CDisp(pPinOut))) ;
  2332. HRESULT hr ;
  2333. IEnumMediaTypes *pEnumMT ;
  2334. AM_MEDIA_TYPE *pmt ;
  2335. ULONG ul ;
  2336. BOOL bMTDecoded = FALSE ; // unless found otherwise
  2337. hr = pPinOut->EnumMediaTypes(&pEnumMT) ;
  2338. ASSERT(SUCCEEDED(hr) && pEnumMT) ;
  2339. while ( !bMTDecoded &&
  2340. S_OK == pEnumMT->Next(1, &pmt, &ul) && 1 == ul)
  2341. {
  2342. #if 1 // we'll use the following procedure
  2343. bMTDecoded = (MEDIATYPE_Video == pmt->majortype && // major type Video,
  2344. MEDIASUBTYPE_MPEG2_VIDEO != pmt->subtype && // subtype is NOT MPEG2Video
  2345. MEDIASUBTYPE_DVD_SUBPICTURE != pmt->subtype) || // subtype is NOT DVDSubPicture OR
  2346. (MEDIATYPE_Audio == pmt->majortype && // major type Audio
  2347. MEDIASUBTYPE_MPEG2_AUDIO != pmt->subtype && // subtype is NOT MPEG2Audio
  2348. MEDIASUBTYPE_DOLBY_AC3 != pmt->subtype && // subtype is NOT Dolby AC3
  2349. MEDIASUBTYPE_DVD_LPCM_AUDIO != pmt->subtype) || // subtype is NOT DVD-LPCMAudio
  2350. (MEDIATYPE_AUXLine21Data == pmt->majortype) ; // majortype is Line21
  2351. #else // not this procedure
  2352. bMTDecoded = (MEDIATYPE_DVD_ENCRYPTED_PACK != pmt->majortype && // majortype is NOT DVD_ENCRYPTED_PACK
  2353. MEDIATYPE_MPEG2_PES != pmt->majortype && // majortype is NOT MPEG2_PES
  2354. MEDIASUBTYPE_MPEG2_VIDEO != pmt->subtype && // subtype is NOT MPEG2Video
  2355. MEDIASUBTYPE_MPEG2_AUDIO != pmt->subtype && // subtype is NOT MPEG2Audio
  2356. MEDIASUBTYPE_DOLBY_AC3 != pmt->subtype && // subtype is NOT DolbyAC3
  2357. MEDIASUBTYPE_DVD_LPCM_AUDIO != pmt->subtype && // subtype is NOT DVD_LPCMAudio
  2358. MEDIASUBTYPE_DVD_SUBPICTURE != pmt->subtype) ; // subtype is NOT DVD_SUBPICTURE
  2359. #endif // #if 1
  2360. DeleteMediaType(pmt) ; // otherwise
  2361. }
  2362. pEnumMT->Release() ;
  2363. return bMTDecoded ;
  2364. }
  2365. BOOL CDvdGraphBuilder::IsOutputTypeVPVideo(IPin *pPinOut)
  2366. {
  2367. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::IsOutputTypeVPVideo(%s)"),
  2368. (LPCTSTR)CDisp(pPinOut))) ;
  2369. HRESULT hr ;
  2370. IEnumMediaTypes *pEnumMT ;
  2371. AM_MEDIA_TYPE *pmt ;
  2372. ULONG ul ;
  2373. BOOL bVPVideo = FALSE ; // unless found otherwise
  2374. hr = pPinOut->EnumMediaTypes(&pEnumMT) ;
  2375. ASSERT(SUCCEEDED(hr) && pEnumMT) ;
  2376. while ( !bVPVideo &&
  2377. S_OK == pEnumMT->Next(1, &pmt, &ul) && 1 == ul)
  2378. {
  2379. bVPVideo = MEDIATYPE_Video == pmt->majortype && // major type Video,
  2380. MEDIASUBTYPE_VPVideo == pmt->subtype ; // subtype is VPVideo
  2381. DeleteMediaType(pmt) ; // otherwise
  2382. }
  2383. pEnumMT->Release() ;
  2384. return bVPVideo ;
  2385. }
  2386. //
  2387. // Create a filter and add it to the filter graph
  2388. //
  2389. HRESULT CDvdGraphBuilder::CreateFilterInGraph(CLSID Clsid,
  2390. LPCWSTR lpszwFilterName,
  2391. IBaseFilter **ppFilter)
  2392. {
  2393. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::CreateFilterInGraph(%s, %S, 0x%lx)"),
  2394. (LPCTSTR) CDisp(Clsid), lpszwFilterName, ppFilter)) ;
  2395. if (NULL == m_pGB)
  2396. {
  2397. DbgLog((LOG_ERROR, 1, TEXT("WARNING: Filter graph object hasn't been created yet"))) ;
  2398. return E_FAIL ;
  2399. }
  2400. HRESULT hr ;
  2401. hr = CoCreateInstance(Clsid, NULL, CLSCTX_INPROC, IID_IBaseFilter,
  2402. (LPVOID *)ppFilter) ;
  2403. if (FAILED(hr) || NULL == *ppFilter)
  2404. {
  2405. DbgLog((LOG_ERROR, 1, TEXT("WARNING: Couldn't create filter %s (Error 0x%lx)"),
  2406. (LPCTSTR)CDisp(Clsid), hr)) ;
  2407. return hr ;
  2408. }
  2409. // Add it to the filter graph
  2410. hr = m_pGB->AddFilter(*ppFilter, lpszwFilterName) ;
  2411. if (FAILED(hr))
  2412. {
  2413. DbgLog((LOG_ERROR, 1, TEXT("WARNING: Couldn't add filter %s to graph (Error 0x%lx)"),
  2414. (LPCTSTR)CDisp(Clsid), hr)) ;
  2415. (*ppFilter)->Release() ; // release filter too
  2416. *ppFilter = NULL ; // and set it to NULL
  2417. return hr ;
  2418. }
  2419. return NOERROR ;
  2420. }
  2421. //
  2422. // Instantiate all the HW decoders registered under DVD Hardware Decoder
  2423. // group under the Active Filters category.
  2424. //
  2425. // Qn: Do we need to also pick up the HW filters under any other category,
  2426. // specially for filters like the external AC3 decoder etc.?
  2427. //
  2428. HRESULT CDvdGraphBuilder::CreateDVDHWDecoders(void)
  2429. {
  2430. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::CreateDVDHWDecoders()"))) ;
  2431. HRESULT hr ;
  2432. ICreateDevEnum *pCreateDevEnum ;
  2433. hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
  2434. IID_ICreateDevEnum, (void**)&pCreateDevEnum) ;
  2435. if (FAILED(hr))
  2436. {
  2437. DbgLog((LOG_ERROR, 0, TEXT("WARNING: Couldn't create system dev enum (Error 0x%lx)"), hr)) ;
  2438. return hr ;
  2439. }
  2440. IEnumMoniker *pEnumMon ;
  2441. hr = pCreateDevEnum->CreateClassEnumerator(CLSID_DVDHWDecodersCategory,
  2442. &pEnumMon, 0) ;
  2443. pCreateDevEnum->Release() ;
  2444. if (S_OK != hr)
  2445. {
  2446. DbgLog((LOG_ERROR, 0,
  2447. TEXT("WARNING: Couldn't create class enum for DVD HW Dec category (Error 0x%lx)"),
  2448. hr)) ;
  2449. return E_FAIL ;
  2450. }
  2451. hr = pEnumMon->Reset() ;
  2452. ULONG ul ;
  2453. IMoniker *pMon ;
  2454. while (S_OK == pEnumMon->Next(1, &pMon, &ul) && 1 == ul)
  2455. {
  2456. #ifdef DEBUG
  2457. WCHAR *wszName ;
  2458. pMon->GetDisplayName(0, 0, &wszName) ;
  2459. DbgLog((LOG_TRACE, 5, TEXT("Moniker enum: %S"), wszName)) ;
  2460. CoTaskMemFree(wszName) ;
  2461. #endif // DEBUG
  2462. IBaseFilter *pFilter ;
  2463. hr = pMon->BindToObject(0, 0, IID_IBaseFilter, (void**)&pFilter) ;
  2464. if (FAILED(hr) || NULL == pFilter)
  2465. {
  2466. DbgLog((LOG_ERROR, 1, TEXT("WARNING: Couldn't create HW dec filter (Error 0x%lx)"), hr)) ;
  2467. pMon->Release() ;
  2468. continue ;
  2469. }
  2470. DbgLog((LOG_TRACE, 5, TEXT("HW decoder filter found"))) ;
  2471. IPropertyBag *pPropBag ;
  2472. pMon->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag) ;
  2473. if(pPropBag)
  2474. {
  2475. #ifdef DEBUG
  2476. {
  2477. VARIANT var ;
  2478. var.vt = VT_EMPTY ;
  2479. hr = pPropBag->Read(L"DevicePath", &var, 0) ;
  2480. ASSERT(SUCCEEDED(hr)) ;
  2481. DbgLog((LOG_TRACE, 5, TEXT("DevicePath: %S"), var.bstrVal)) ;
  2482. VariantClear(&var) ;
  2483. }
  2484. {
  2485. VARIANT var ;
  2486. var.vt = VT_EMPTY ;
  2487. hr = pPropBag->Read(L"CLSID", &var, 0) ;
  2488. ASSERT(SUCCEEDED(hr)) ;
  2489. DbgLog((LOG_TRACE, 5, TEXT("CLSID: %S"), var.bstrVal)) ;
  2490. VariantClear(&var) ;
  2491. }
  2492. #endif // DEBUG
  2493. {
  2494. VARIANT var ;
  2495. var.vt = VT_EMPTY ;
  2496. hr = pPropBag->Read(L"FriendlyName", &var, 0) ;
  2497. if (SUCCEEDED(hr))
  2498. {
  2499. DbgLog((LOG_TRACE, 5, TEXT("FriendlyName: %S"), var.bstrVal)) ;
  2500. //
  2501. // We have got a device under the required category. The proxy
  2502. // for it is already instantiated. So add to the list of HW
  2503. // decoders to be used for building the graph.
  2504. //
  2505. m_ListHWDecs.AddFilter(pFilter, var.bstrVal, NULL) ;
  2506. VariantClear(&var) ;
  2507. }
  2508. else
  2509. {
  2510. DbgLog((LOG_ERROR, 1, TEXT("WARNING: Failed to get FriendlyName (Error 0x%lx)"), hr)) ;
  2511. ASSERT(SUCCEEDED(hr)) ; // so that we know
  2512. }
  2513. }
  2514. pPropBag->Release() ;
  2515. }
  2516. else
  2517. {
  2518. DbgLog((LOG_ERROR, 1, TEXT("WARNING: BindToStorage failed"))) ;
  2519. }
  2520. pMon->Release() ;
  2521. } // end of while()
  2522. pEnumMon->Release() ;
  2523. DbgLog((LOG_TRACE, 5, TEXT("Found total %d HW decoders"), m_ListHWDecs.GetCount())) ;
  2524. return NOERROR ;
  2525. }
  2526. HRESULT CDvdGraphBuilder::FindMatchingPin(IBaseFilter *pFilter, DWORD dwStream, PIN_DIRECTION pdWanted,
  2527. BOOL bOpen, int iIndex, IPin **ppPin)
  2528. {
  2529. DbgLog((LOG_TRACE, 4,
  2530. TEXT("CDvdGraphBuilder::FindMatchingPin(0x%lx, 0x%lx, %s, %s, %d, 0x%lx)"),
  2531. pFilter, dwStream, pdWanted == PINDIR_INPUT ? "In" : "Out",
  2532. bOpen ? "T" : "F", iIndex, ppPin)) ;
  2533. HRESULT hr = E_FAIL ;
  2534. IEnumPins *pEnumPins ;
  2535. IPin *pPin ;
  2536. IPin *pPin2 ;
  2537. PIN_DIRECTION pdFound ;
  2538. ULONG ul ;
  2539. *ppPin = NULL ;
  2540. if (NULL == pFilter)
  2541. {
  2542. DbgLog((LOG_ERROR, 1, TEXT("WARNING: Can't find a pin from NULL filter!!!"))) ;
  2543. return E_INVALIDARG ;
  2544. }
  2545. EXECUTE_ASSERT(SUCCEEDED(pFilter->EnumPins(&pEnumPins))) ;
  2546. ASSERT(pEnumPins) ;
  2547. while (S_OK == pEnumPins->Next(1, &pPin, &ul) && 1 == ul)
  2548. {
  2549. EXECUTE_ASSERT(SUCCEEDED(pPin->QueryDirection(&pdFound))) ;
  2550. if (pdWanted != pdFound)
  2551. {
  2552. pPin->Release() ; // don't need this pin
  2553. continue ;
  2554. }
  2555. HRESULT hr1 = pPin->ConnectedTo(&pPin2) ;
  2556. ASSERT((SUCCEEDED(hr1) && pPin2) || (FAILED(hr1) && !pPin2)) ;
  2557. if (bOpen) // we looking for an open pin
  2558. {
  2559. if (SUCCEEDED(hr1) && pPin2) // pin already connected -- skip it
  2560. {
  2561. pPin2->Release() ; // not interested in this pin actually
  2562. pPin->Release() ; // this pin is already connected -- skip it
  2563. continue ; // try next one
  2564. }
  2565. // Otherwise we have got an open pin -- onto the mediatypes...
  2566. // Check mediatype only if a streamtype was specified
  2567. if (0 != dwStream && dwStream != GetPinStreamType(pPin) ) // not a mediatype match
  2568. {
  2569. DbgLog((LOG_TRACE, 5, TEXT("Pin %s is not of stream type 0x%lx"),
  2570. (LPCTSTR) CDisp(pPin), dwStream)) ;
  2571. pPin->Release() ; // this pin is already connected -- skip it
  2572. continue ; // try next one
  2573. }
  2574. }
  2575. else // we looking for a connected pin
  2576. {
  2577. if (FAILED(hr1) || NULL == pPin2) // pin NOT connected -- skip it
  2578. {
  2579. pPin->Release() ; // this pin is NOT connected -- skip it
  2580. continue ; // try next one
  2581. }
  2582. // Otherwise we have got a connected pin
  2583. pPin2->Release() ; // else we leak!!!
  2584. // Check mediatype only if a streamtype was specified
  2585. if (0 != dwStream)
  2586. {
  2587. AM_MEDIA_TYPE mt ;
  2588. pPin->ConnectionMediaType(&mt) ;
  2589. if (dwStream != GetStreamFromMediaType(&mt))
  2590. {
  2591. DbgLog((LOG_TRACE, 5, TEXT("Pin %s is not of stream type 0x%lx"),
  2592. (LPCTSTR) CDisp(pPin), dwStream)) ;
  2593. FreeMediaType(mt) ; // else we leak
  2594. pPin->Release() ; // this pin is already connected -- skip it
  2595. continue ; // try next one
  2596. }
  2597. FreeMediaType(mt) ; // anyway have to free this
  2598. }
  2599. }
  2600. if (0 == iIndex)
  2601. {
  2602. // Got the reqd pin in the right direction
  2603. *ppPin = pPin ;
  2604. hr = S_OK ;
  2605. break ;
  2606. }
  2607. else // some more to go
  2608. {
  2609. iIndex-- ; // one more down...
  2610. pPin->Release() ; // this is not the pin we are looking for
  2611. }
  2612. }
  2613. pEnumPins->Release() ;
  2614. return hr ; // whatever it is
  2615. }
  2616. DWORD CDvdGraphBuilder::GetStreamFromMediaType(AM_MEDIA_TYPE *pmt)
  2617. {
  2618. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::GetStreamFromMediaType(0x%lx)"), pmt)) ;
  2619. DWORD dwStream = 0 ;
  2620. // Decipher the mediatype
  2621. if (pmt->majortype == MEDIATYPE_MPEG2_PES ||
  2622. pmt->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK)
  2623. {
  2624. DbgLog((LOG_TRACE, 5, TEXT("Mediatype is MPEG2_PES/DVD_ENCRYPTED_PACK"))) ;
  2625. if (pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO)
  2626. {
  2627. DbgLog((LOG_TRACE, 5, TEXT("Subtype is MPEG2_VIDEO"))) ;
  2628. dwStream = AM_DVD_STREAM_VIDEO ;
  2629. }
  2630. else if (pmt->subtype == MEDIASUBTYPE_DOLBY_AC3)
  2631. {
  2632. DbgLog((LOG_TRACE, 5, TEXT("Subtype is DOLBY_AC3"))) ;
  2633. dwStream = AM_DVD_STREAM_AUDIO ;
  2634. }
  2635. else if (pmt->subtype == MEDIASUBTYPE_DVD_SUBPICTURE)
  2636. {
  2637. DbgLog((LOG_TRACE, 5, TEXT("Subtype is DVD_Subpicture"))) ;
  2638. dwStream = AM_DVD_STREAM_SUBPIC ;
  2639. }
  2640. else
  2641. {
  2642. DbgLog((LOG_ERROR, 1, TEXT("WARNING: Unknown subtype %s"),
  2643. (LPCTSTR) CDisp(pmt->subtype))) ;
  2644. }
  2645. }
  2646. else if (pmt->majortype == MEDIATYPE_Video) // elementary stream
  2647. {
  2648. DbgLog((LOG_TRACE, 5, TEXT("Mediatype is Video elementary"))) ;
  2649. if (pmt->subtype == MEDIASUBTYPE_DVD_SUBPICTURE)
  2650. {
  2651. DbgLog((LOG_TRACE, 5, TEXT("Subtype is DVD_SUBPICTURE"))) ;
  2652. dwStream = AM_DVD_STREAM_SUBPIC ;
  2653. }
  2654. else if (pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO)
  2655. {
  2656. DbgLog((LOG_TRACE, 5, TEXT("Subtype is MPEG2_VIDEO"))) ;
  2657. dwStream = AM_DVD_STREAM_VIDEO ;
  2658. }
  2659. else if (pmt->subtype == MEDIASUBTYPE_RGB8 ||
  2660. pmt->subtype == MEDIASUBTYPE_RGB565 ||
  2661. pmt->subtype == MEDIASUBTYPE_RGB555 ||
  2662. pmt->subtype == MEDIASUBTYPE_RGB24 ||
  2663. pmt->subtype == MEDIASUBTYPE_RGB32)
  2664. {
  2665. DbgLog((LOG_TRACE, 5, TEXT("Subtype is RGB8/16/24/32"))) ;
  2666. dwStream = AM_DVD_STREAM_VIDEO ;
  2667. }
  2668. else
  2669. {
  2670. DbgLog((LOG_TRACE, 5, TEXT("Unknown subtype %s for Video -- assuming decoded video"),
  2671. (LPCTSTR) CDisp(pmt->subtype))) ;
  2672. dwStream = AM_DVD_STREAM_VIDEO ;
  2673. }
  2674. }
  2675. else if (pmt->majortype == MEDIATYPE_Audio) // elementary stream
  2676. {
  2677. DbgLog((LOG_TRACE, 5, TEXT("Mediatype is Audio elementary"))) ;
  2678. if (pmt->subtype == MEDIASUBTYPE_DOLBY_AC3)
  2679. {
  2680. DbgLog((LOG_TRACE, 5, TEXT("Subtype is AC3"))) ;
  2681. dwStream = AM_DVD_STREAM_AUDIO ;
  2682. }
  2683. if (pmt->subtype == MEDIASUBTYPE_MPEG2_AUDIO)
  2684. {
  2685. DbgLog((LOG_TRACE, 5, TEXT("Subtype is MPEG2_AUDIO"))) ;
  2686. dwStream = AM_DVD_STREAM_AUDIO ;
  2687. }
  2688. if (pmt->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO)
  2689. {
  2690. DbgLog((LOG_TRACE, 5, TEXT("Subtype is DVD_LPCM Audio"))) ;
  2691. dwStream = AM_DVD_STREAM_AUDIO ;
  2692. }
  2693. else
  2694. {
  2695. DbgLog((LOG_TRACE, 5, TEXT("Unknown subtype %s for Audio -- assuming decoded audio"),
  2696. (LPCTSTR) CDisp(pmt->subtype))) ;
  2697. dwStream = AM_DVD_STREAM_AUDIO ;
  2698. }
  2699. }
  2700. else if (pmt->majortype == MEDIATYPE_AUXLine21Data) // line21 stream
  2701. {
  2702. ASSERT(pmt->subtype == MEDIASUBTYPE_Line21_GOPPacket) ; // just checking
  2703. DbgLog((LOG_TRACE, 5, TEXT("Mediatype is Line21 GOPPacket"))) ;
  2704. dwStream = AM_DVD_STREAM_LINE21 ;
  2705. }
  2706. else if (pmt->majortype == MEDIATYPE_Stream) // some stream format
  2707. {
  2708. if (pmt->subtype == MEDIASUBTYPE_Asf) // ASF stream
  2709. {
  2710. DbgLog((LOG_TRACE, 5, TEXT("Mediatype is ASF stream"))) ;
  2711. dwStream = AM_DVD_STREAM_ASF ;
  2712. }
  2713. else // some other stream format
  2714. {
  2715. DbgLog((LOG_TRACE, 5, TEXT("Mediatype is some OTHER stream format"))) ;
  2716. dwStream = AM_DVD_STREAM_ADDITIONAL ;
  2717. }
  2718. }
  2719. //
  2720. // There is a chance that some IHV/ISV creates a private mediatype
  2721. // (major or sub) as in the case of IBM (for CSS filter). We have to
  2722. // search the parts of the mediatype to locate something we recognize.
  2723. //
  2724. else
  2725. {
  2726. DbgLog((LOG_TRACE, 2,
  2727. TEXT("Unknown mediatype %s:%s. But we won't give up..."),
  2728. (LPCTSTR) CDisp(pmt->majortype), (LPCTSTR) CDisp(pmt->subtype))) ;
  2729. if (pmt->subtype == MEDIASUBTYPE_DOLBY_AC3 ||
  2730. pmt->subtype == MEDIASUBTYPE_MPEG2_AUDIO ||
  2731. pmt->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO)
  2732. {
  2733. DbgLog((LOG_TRACE, 5, TEXT("Mediatype is ISV/IHV-specific Audio"))) ;
  2734. dwStream = AM_DVD_STREAM_AUDIO ;
  2735. }
  2736. else if (pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO)
  2737. {
  2738. DbgLog((LOG_TRACE, 5, TEXT("Mediatype is ISV/IHV-specific Video"))) ;
  2739. dwStream = AM_DVD_STREAM_VIDEO ;
  2740. }
  2741. else if (pmt->subtype == MEDIASUBTYPE_DVD_SUBPICTURE)
  2742. {
  2743. DbgLog((LOG_TRACE, 5, TEXT("Mediatype is ISV/IHV-specific Subpicture"))) ;
  2744. dwStream = AM_DVD_STREAM_SUBPIC ;
  2745. }
  2746. else
  2747. {
  2748. DbgLog((LOG_TRACE, 2, TEXT("WARNING: Unknown mediatype. Couldn't detect at all."))) ;
  2749. }
  2750. }
  2751. return dwStream ;
  2752. }
  2753. DWORD CDvdGraphBuilder::GetPinStreamType(IPin *pPin)
  2754. {
  2755. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::GetPinStreamType(%s)"),
  2756. (LPCTSTR) CDisp(pPin))) ;
  2757. DWORD dwStream = 0 ;
  2758. AM_MEDIA_TYPE *pmt ;
  2759. IEnumMediaTypes *pEnumMT ;
  2760. ULONG ul ;
  2761. HRESULT hr = pPin->EnumMediaTypes(&pEnumMT) ;
  2762. ASSERT(SUCCEEDED(hr) && pEnumMT) ;
  2763. while (0 == dwStream &&
  2764. S_OK == pEnumMT->Next(1, &pmt, &ul) && 1 == ul) // more mediatypes
  2765. {
  2766. dwStream = GetStreamFromMediaType(pmt) ;
  2767. DeleteMediaType(pmt) ;
  2768. } // end of while()
  2769. pEnumMT->Release() ;
  2770. return dwStream ; // whatever we found
  2771. }
  2772. HRESULT CDvdGraphBuilder::GetFilterCLSID(IBaseFilter *pFilter, DWORD dwStream,
  2773. LPCWSTR lpszwName, GUID *pClsid)
  2774. {
  2775. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::GetFilterCLSID(0x%lx, 0x%lx, %S, 0x%lx)"),
  2776. pFilter, dwStream, lpszwName, pClsid)) ;
  2777. HRESULT hr ;
  2778. IEnumRegFilters *pEnumFilters ;
  2779. REGFILTER *pRegFilter ;
  2780. IEnumMediaTypes *pEnumMT ;
  2781. AM_MEDIA_TYPE mtIn ;
  2782. AM_MEDIA_TYPE mtOut ;
  2783. IPin *pPinIn ;
  2784. IPin *pPinOut ;
  2785. ULONG ul ;
  2786. DWORD dw ;
  2787. int iPos ;
  2788. BOOL bInOK = FALSE ; // initially
  2789. BOOL bOutOK = FALSE ; // initially
  2790. BOOL bFound = FALSE ; // initially
  2791. *pClsid = GUID_NULL ; // to start with
  2792. // First get the in and out pins' mediatypes
  2793. iPos = 0 ;
  2794. do { // for Input pin
  2795. hr = FindMatchingPin(pFilter, 0, PINDIR_INPUT, FALSE, iPos, &pPinIn) ; // want connected in pin
  2796. if (FAILED(hr) || NULL == pPinIn)
  2797. {
  2798. DbgLog((LOG_TRACE, 3,
  2799. TEXT("No connected In pin #%d for intermediate filter %S"),
  2800. iPos, lpszwName)) ;
  2801. return E_UNEXPECTED ; // no point trying anymore
  2802. }
  2803. pPinIn->ConnectionMediaType(&mtIn) ;
  2804. dw = GetStreamFromMediaType(&mtIn) ;
  2805. if (dwStream != dw)
  2806. {
  2807. DbgLog((LOG_TRACE, 3, TEXT("In pin %s is of stream type 0x%lx; looking for 0x%lx"),
  2808. (LPCTSTR) CDisp(pPinIn), dw, dwStream)) ;
  2809. FreeMediaType(mtIn) ;
  2810. }
  2811. else
  2812. {
  2813. DbgLog((LOG_TRACE, 3, TEXT("In pin %s matches required stream type 0x%lx"),
  2814. (LPCTSTR) CDisp(pPinIn), dwStream)) ;
  2815. bInOK = TRUE ;
  2816. }
  2817. pPinIn->Release() ; // don't need it anymore
  2818. iPos++ ; // try the next pin
  2819. } while (!bInOK) ;
  2820. // If we come here, we must have got a matching connected input pin
  2821. iPos = 0 ;
  2822. do { // for Output pin
  2823. hr = FindMatchingPin(pFilter, 0, PINDIR_OUTPUT, FALSE, iPos, &pPinOut) ; // want connected out pin
  2824. if (FAILED(hr) || NULL == pPinOut)
  2825. {
  2826. DbgLog((LOG_TRACE, 3,
  2827. TEXT("No connected Out pin #%d for intermediate filter %S"),
  2828. iPos, lpszwName)) ;
  2829. FreeMediaType(mtIn) ; // else we leak!!!
  2830. return E_UNEXPECTED ; // no point trying anymore
  2831. }
  2832. pPinOut->ConnectionMediaType(&mtOut) ;
  2833. dw = GetStreamFromMediaType(&mtOut) ;
  2834. if (dwStream != dw)
  2835. {
  2836. DbgLog((LOG_TRACE, 3, TEXT("Out pin %s is of stream type 0x%lx; looking for 0x%lx"),
  2837. (LPCTSTR) CDisp(pPinOut), dw, dwStream)) ;
  2838. FreeMediaType(mtOut) ;
  2839. }
  2840. else
  2841. {
  2842. DbgLog((LOG_TRACE, 3, TEXT("Out pin %s matches required stream type 0x%lx"),
  2843. (LPCTSTR) CDisp(pPinOut), dwStream)) ;
  2844. bOutOK = TRUE ;
  2845. }
  2846. pPinOut->Release() ; // don't need it anymore
  2847. iPos++ ; // try the next pin
  2848. } while (!bOutOK) ;
  2849. // If we come here, we must have got a matching connected output pin
  2850. // Get the filter enumerator based on the in and out mediatypes
  2851. hr = m_pMapper->EnumMatchingFilters(&pEnumFilters, MERIT_DO_NOT_USE+1,
  2852. TRUE, mtIn.majortype, mtIn.subtype,
  2853. FALSE, TRUE, mtOut.majortype, mtOut.subtype) ;
  2854. if (FAILED(hr) || NULL == pEnumFilters)
  2855. {
  2856. DbgLog((LOG_ERROR, 1, TEXT("ERROR: No matching filter enum found (Error 0x%lx)"), hr)) ;
  2857. FreeMediaType(mtIn) ;
  2858. FreeMediaType(mtOut) ;
  2859. return E_UNEXPECTED ;
  2860. }
  2861. // Now pick the right filter (we only have the "Name" to do the matching)
  2862. while (! bFound &&
  2863. S_OK == pEnumFilters->Next(1, &pRegFilter, &ul) && 1 == ul)
  2864. {
  2865. if (0 == lstrcmpW(pRegFilter->Name, lpszwName)) // we got a match!!!
  2866. {
  2867. DbgLog((LOG_TRACE, 3, TEXT("Found a matching registered filter for %S"), lpszwName)) ;
  2868. *pClsid = pRegFilter->Clsid ;
  2869. bFound = TRUE ;
  2870. }
  2871. CoTaskMemFree(pRegFilter) ; // done with this filter's info
  2872. }
  2873. // Now release everything (whether we got anything or not)
  2874. pEnumFilters->Release() ;
  2875. FreeMediaType(mtIn) ;
  2876. FreeMediaType(mtOut) ;
  2877. return bFound ? S_OK : E_FAIL ;
  2878. }
  2879. HRESULT CDvdGraphBuilder::RenderIntermediateOutPin(IBaseFilter *pFilter, DWORD dwStream,
  2880. AM_DVD_RENDERSTATUS *pStatus)
  2881. {
  2882. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::RenderIntermediateOutPin(0x%lx, 0x%lx, 0x%lx)"),
  2883. pFilter, dwStream, pStatus)) ;
  2884. HRESULT hr ;
  2885. IPin *pPinOut ;
  2886. IPin *apPinOutDec[MAX_DEC_OUT_PINS + 1] ; // 1 for terminating NULL
  2887. IPin *pPinIn ;
  2888. ULONG ul ;
  2889. DWORD dwDecFlag ;
  2890. HRESULT hrFinal = S_OK ;
  2891. BOOL bConnected ;
  2892. while (SUCCEEDED(hr = FindMatchingPin(pFilter, dwStream, PINDIR_OUTPUT, TRUE, 0, &pPinOut)))
  2893. {
  2894. DbgLog((LOG_TRACE, 3, TEXT("Open out pin %s found on intermediate filter"),
  2895. (LPCTSTR) CDisp(pPinOut))) ;
  2896. ResetPinInterface(apPinOutDec, NUMELMS(apPinOutDec)) ; // set i/f ptrs to NULL
  2897. dwDecFlag = AM_DVD_SWDEC_PREFER ; // we intentionally prefer SWDEC here
  2898. hr = DecodeDVDStream(pPinOut, dwStream, &dwDecFlag, pStatus, apPinOutDec) ;
  2899. if (SUCCEEDED(hr) && apPinOutDec[0]) // first element is good enough
  2900. {
  2901. DbgLog((LOG_TRACE, 3, TEXT("Out pin %s is %s decoded (to out pin %s) (stream 0x%lx)"),
  2902. (LPCTSTR) CDisp(pPinOut), AM_DVD_SWDEC_ONLY == dwDecFlag ? TEXT("SW") : TEXT("HW"),
  2903. (LPCTSTR) CDisp(apPinOutDec[0]), dwStream)) ;
  2904. switch (dwStream)
  2905. {
  2906. case AM_DVD_STREAM_VIDEO:
  2907. DbgLog((LOG_TRACE, 5, TEXT("Going to render intermediate filter's additional 'Video' stream"))) ;
  2908. // So far I don't know of anyone coming here. But IBM's stuff
  2909. // goes to the audio case. So I am not ignoring the video case,
  2910. // just in case someone is that much insane!!!
  2911. //
  2912. // Only if we have been able to render primary video...
  2913. if (0 == (pStatus->dwFailedStreamsFlag & AM_DVD_STREAM_VIDEO))
  2914. {
  2915. pPinIn = NULL ;
  2916. hr = E_FAIL ; // assume we'll fail
  2917. if (m_pOvM) // ... using OvMixer
  2918. {
  2919. hr = FindMatchingPin(m_pOvM, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ;
  2920. }
  2921. else if (m_pVMR) // ... using VMR
  2922. {
  2923. hr = FindMatchingPin(m_pVMR, 0, PINDIR_INPUT, TRUE, 0, &pPinIn) ;
  2924. }
  2925. // ASSERT(SUCCEEDED(hr) && pPinIn) ;
  2926. if (SUCCEEDED(hr) && pPinIn)
  2927. {
  2928. bConnected = FALSE ; // reset flag every time
  2929. int i = 0 ;
  2930. while (!bConnected && i < MAX_DEC_OUT_PINS && apPinOutDec[i])
  2931. {
  2932. hr = ConnectPins(apPinOutDec[i], pPinIn, AM_DVD_CONNECT_DIRECTFIRST) ;
  2933. if (FAILED(hr)) // what?!?
  2934. {
  2935. DbgLog((LOG_TRACE, 1, TEXT("Pin %s (#%ld) did NOT connect to pin %s"),
  2936. (LPCTSTR)CDisp(apPinOutDec[i]), i, (LPCTSTR)CDisp(pPinIn))) ;
  2937. i++ ;
  2938. ASSERT(i <= MAX_DEC_OUT_PINS) ;
  2939. }
  2940. else
  2941. {
  2942. DbgLog((LOG_TRACE, 5, TEXT("Pin %s connected to pin %s"),
  2943. (LPCTSTR)CDisp(apPinOutDec[i]), (LPCTSTR)CDisp(pPinIn))) ;
  2944. // Intentionally ignoring any intermediate filters coming in here -- I am tired
  2945. // EnumFiltersBetweenPins(dwStream, pPinOut, pPinIn, pStatus) ;
  2946. bConnected = TRUE ;
  2947. }
  2948. } // end of while (!bConnected ...)
  2949. if (!bConnected)
  2950. {
  2951. DbgLog((LOG_TRACE, 3, TEXT("Couldn't connect any of the %d intermediate video out pins"), i)) ;
  2952. hrFinal = hr ; // last error is good enough
  2953. }
  2954. pPinIn->Release() ; // done with the pin
  2955. }
  2956. } // end of if (0 == (pStatus->dwFailedStreamsFlag ...))
  2957. else
  2958. {
  2959. ASSERT(FALSE) ; // so that we know about it
  2960. DbgLog((LOG_TRACE, 5, TEXT("OvM/VMR is not usable. Will skip rendering this stream."))) ;
  2961. hrFinal = E_UNEXPECTED ;
  2962. }
  2963. break ;
  2964. case AM_DVD_STREAM_AUDIO:
  2965. DbgLog((LOG_TRACE, 5, TEXT("Going to render intermediate filter's additional 'Audio' stream"))) ;
  2966. hr = RenderDecodedAudio(apPinOutDec, pStatus) ;
  2967. if (FAILED(hr))
  2968. {
  2969. DbgLog((LOG_TRACE, 3, TEXT("Couldn't connect the intermediate audio out pin"))) ;
  2970. hrFinal = hr ;
  2971. }
  2972. else
  2973. DbgLog((LOG_TRACE, 5, TEXT("XXX's SW AC3 must have been rendered now"))) ; // XXX = IBM
  2974. break ;
  2975. case AM_DVD_STREAM_SUBPIC:
  2976. DbgLog((LOG_TRACE, 5, TEXT("Skip rendering intermediate filter's additional 'Subpicture' stream"))) ;
  2977. // hr = RenderDecodedSubpic(apPinOutDec, pStatus) ;
  2978. ASSERT(FALSE) ; // not expected here at all
  2979. break ;
  2980. case AM_DVD_STREAM_LINE21:
  2981. DbgLog((LOG_TRACE, 5, TEXT("Skip rendering intermediate filter's additional 'CC' stream"))) ;
  2982. // hr = RenderLine21Stream(apPinOutDec[0], pStatus) ; -- hopefully only one L21 out pin
  2983. ASSERT(FALSE) ; // not expected here at all
  2984. break ;
  2985. } // end of switch()
  2986. ReleasePinInterface(apPinOutDec) ; // done with the decoded out pin(s)
  2987. } // end of if (SUCCEEDED(hr) && apPinOutDec[0])
  2988. else
  2989. DbgLog((LOG_TRACE, 1, TEXT("Intermediate out pin %s could NOT decoded (stream 0x%lx)"),
  2990. (LPCTSTR) CDisp(pPinOut), dwStream)) ;
  2991. pPinOut->Release() ; // done with the pin
  2992. } // end of while ()
  2993. return hrFinal ;
  2994. }
  2995. HRESULT CDvdGraphBuilder::EnumFiltersBetweenPins(DWORD dwStream, IPin *pPinOut, IPin *pPinIn,
  2996. AM_DVD_RENDERSTATUS *pStatus)
  2997. {
  2998. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::EnumFiltersBetweenPins(0x%lx, Out=%s, In=%s, 0x%lx)"),
  2999. dwStream, (LPCTSTR)CDisp(pPinOut), (LPCTSTR)CDisp(pPinIn), pStatus)) ;
  3000. if (NULL == pPinOut || NULL == pPinIn) // what!!!
  3001. return E_UNEXPECTED ;
  3002. GUID Clsid ;
  3003. int iCount = 0 ;
  3004. PIN_INFO pi ;
  3005. FILTER_INFO fi ;
  3006. IEnumPins *pEnumPins ;
  3007. IBaseFilter *pFilter = NULL ;
  3008. IPin *pPinIn2 = NULL ; // init so that we don't have junk
  3009. IPin *pPinOut2 = NULL ; // init so that we don't have junk
  3010. HRESULT hr = pPinIn->ConnectedTo(&pPinOut2) ;
  3011. while (SUCCEEDED(hr) && pPinOut2 && !IsEqualObject(pPinOut, pPinOut2))
  3012. {
  3013. pPinOut2->QueryPinInfo(&pi) ;
  3014. pFilter = pi.pFilter ;
  3015. ASSERT(pFilter && PINDIR_OUTPUT == pi.dir) ;
  3016. //
  3017. // We intentionally keep the extra ref count because this is an intermediate
  3018. // filter and other intermediate filters picked up through registry based
  3019. // filter enum (for SW decoding case) will have the extra ref count. We
  3020. // release the IBaseFilter interface pointer in CListFilters::ClearList() or
  3021. // CListFilters::RemoveAllFromGraph() and if we don't keep this extra ref
  3022. // count here, we'll fault. On the other hand we must do Release() on
  3023. // CListFilters elements, because SW enum-ed filters will not otherwise be
  3024. // unloaded.
  3025. //
  3026. // if (pi.pFilter)
  3027. // pi.pFilter->Release() ; // it has an extra ref count from QueryPinInfo()
  3028. pFilter->QueryFilterInfo(&fi) ;
  3029. if (! m_ListFilters.IsInList(pFilter) ) // not yet in list
  3030. {
  3031. hr = GetFilterCLSID(pFilter, dwStream, fi.achName, &Clsid) ;
  3032. ASSERT(SUCCEEDED(hr)) ;
  3033. m_ListFilters.AddFilter(pFilter, NULL /* fi.achName */, &Clsid) ; // presumably it's a SW filter
  3034. DbgLog((LOG_TRACE, 5, TEXT("Intermediate filter %S added to our list"), fi.achName)) ;
  3035. }
  3036. else
  3037. DbgLog((LOG_TRACE, 5, TEXT("Intermediate filter %S is already in our list"), fi.achName)) ;
  3038. fi.pGraph->Release() ; // else we leak!!
  3039. pPinOut2->Release() ; // done with the pin for now
  3040. pPinOut2 = NULL ;
  3041. iCount++ ;
  3042. // Check for any open out pin on the intermediate filter. We may find
  3043. // one such on IBM's CSS filter for the SW AC3 decoder.
  3044. hr = RenderIntermediateOutPin(pFilter, dwStream, pStatus) ;
  3045. if (FAILED(hr))
  3046. {
  3047. DbgLog((LOG_TRACE, 3,
  3048. TEXT("Failed to render intermediate filter's open out pin of type 0x%lx (Error 0x%lx)"),
  3049. dwStream, hr)) ;
  3050. ASSERT(FALSE) ; // so that we know of this weird case
  3051. }
  3052. // Now get the (stream-matching) input pin of this filter to traverse the chain
  3053. hr = FindMatchingPin(pFilter, dwStream, PINDIR_INPUT, FALSE, 0, &pPinIn2) ; // want connected pin
  3054. if (FAILED(hr) || NULL == pPinIn2)
  3055. {
  3056. DbgLog((LOG_ERROR, 1, TEXT("Filter %S does NOT have any connected pin of type 0x%lx"),
  3057. fi.achName, dwStream)) ;
  3058. ASSERT(pPinIn2) ;
  3059. DbgLog((LOG_TRACE, 5, TEXT("(Incomplete) %d filter(s) found between pin %s and pin %s"),
  3060. iCount, (LPCTSTR)CDisp(pPinOut), (LPCTSTR)CDisp(pPinIn))) ;
  3061. return hr ; // we are hopefully not leaking anything
  3062. }
  3063. hr = pPinIn2->ConnectedTo(&pPinOut2) ;
  3064. pPinIn2->Release() ; // done with this in pin
  3065. } // end of while () loop
  3066. if (pPinOut2) // if valid IPin interface
  3067. pPinOut2->Release() ; // release it
  3068. DbgLog((LOG_TRACE, 5, TEXT("Total %d filter(s) found between pin %s and pin %s"),
  3069. iCount, (LPCTSTR)CDisp(pPinOut), (LPCTSTR)CDisp(pPinIn))) ;
  3070. return S_OK ; // successfuly done
  3071. }
  3072. void CDvdGraphBuilder::CheckDDrawExclMode(void)
  3073. {
  3074. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::CheckDDrawExclMode()"))) ;
  3075. HRESULT hr ;
  3076. #if 0
  3077. hr = EnsureOverlayMixerExists() ;
  3078. if (FAILED(hr))
  3079. {
  3080. return ;
  3081. }
  3082. ASSERT(m_pOvM) ;
  3083. #endif // #if 0
  3084. // If OvMixer has already been created, it's most probably by a query for
  3085. // the DDraw (non-)exclusive mode interfaces. Otherwise the app doesn't
  3086. // want to use those interfaces, and hence it does NOT need OvMixer.
  3087. if (NULL == m_pOvM)
  3088. {
  3089. DbgLog((LOG_TRACE, 5,
  3090. TEXT("CheckDDrawExclMode(): OverlayMixer does NOT exist => no excl mode."))) ;
  3091. m_bDDrawExclMode = FALSE ;
  3092. return ;
  3093. }
  3094. // Get the IDDrawExclModeVideo interface
  3095. IDDrawExclModeVideo *pDDXMV ;
  3096. hr = m_pOvM->QueryInterface(IID_IDDrawExclModeVideo, (LPVOID *) &pDDXMV) ;
  3097. if (FAILED(hr) || NULL == pDDXMV)
  3098. {
  3099. DbgLog((LOG_ERROR, 1,
  3100. TEXT("WARNING: Can't get IDDrawExclModeVideo on OverlayMixer (Error 0x%lx)"), hr)) ;
  3101. return ;
  3102. }
  3103. // Get the DDraw object and surface info from OverlayMixer (and release too)
  3104. IDirectDraw *pDDObj ;
  3105. IDirectDrawSurface *pDDSurface ;
  3106. BOOL bExtDDObj ;
  3107. BOOL bExtDDSurface ;
  3108. hr = pDDXMV->GetDDrawObject(&pDDObj, &bExtDDObj) ;
  3109. ASSERT(SUCCEEDED(hr)) ;
  3110. hr = pDDXMV->GetDDrawSurface(&pDDSurface, &bExtDDSurface) ;
  3111. ASSERT(SUCCEEDED(hr)) ;
  3112. if (pDDObj)
  3113. pDDObj->Release() ;
  3114. if (pDDSurface)
  3115. pDDSurface->Release() ;
  3116. pDDXMV->Release() ; // release before returning
  3117. // Both true means we are really in excl mode
  3118. m_bDDrawExclMode = bExtDDObj && bExtDDSurface ;
  3119. }
  3120. IPin * CDvdGraphBuilder::GetFilterForMediaType(DWORD dwStream, AM_MEDIA_TYPE *pmt, IBaseFilter *pOutFilter)
  3121. {
  3122. DbgLog((LOG_TRACE, 4, TEXT("CDvdGraphBuilder::GetFilterForMediaType(0x%lx, 0x%lx, 0x%lx)"),
  3123. dwStream, pmt, pOutFilter)) ;
  3124. IBaseFilter *pInFilter ;
  3125. IPin *pPinIn ;
  3126. LPWSTR lpszwName ;
  3127. HRESULT hr ;
  3128. for (int i = 0 ; i < m_ListFilters.GetCount() ; i++)
  3129. {
  3130. // I could have checked if the filter from list is a HW filter, but I decided not to.
  3131. m_ListFilters.GetFilter(i, &pInFilter, &lpszwName) ;
  3132. // Don't want to connect to the out pin's filter's in pin (cyclic graph)
  3133. if (pOutFilter && IsEqualObject(pOutFilter, pInFilter))
  3134. continue ;
  3135. hr = FindMatchingPin(pInFilter, dwStream, PINDIR_INPUT, TRUE, 0, &pPinIn) ;
  3136. if (SUCCEEDED(hr) && pPinIn)
  3137. {
  3138. hr = pPinIn->QueryAccept(pmt) ;
  3139. if (SUCCEEDED(hr)) // input pin seems to accept mediatype
  3140. {
  3141. DbgLog((LOG_TRACE, 5, TEXT("Input pin %s of type %d matches mediatype"),
  3142. (LPCTSTR)CDisp(pPinIn), dwStream)) ;
  3143. return pPinIn ; // return matching in pin
  3144. }
  3145. // Otherwise not a matching mediatype -- skip this one.
  3146. DbgLog((LOG_TRACE, 5, TEXT("Input pin %s of type %d didn't like mediatype"),
  3147. (LPCTSTR)CDisp(pPinIn), dwStream)) ;
  3148. pPinIn->Release() ;
  3149. pPinIn = NULL ;
  3150. }
  3151. else
  3152. DbgLog((LOG_TRACE, 5, TEXT("No open input pin of type %d found on %S"),
  3153. dwStream, lpszwName)) ;
  3154. } // end of for (i)
  3155. return NULL ; // didn't match any
  3156. }
  3157. // ---------------------------------------------
  3158. // Implementation of the CListFilters class...
  3159. // ---------------------------------------------
  3160. CListFilters::CListFilters(int iMax /* = FILTERLIST_DEFAULT_MAX*/ ,
  3161. int iInc /* = FILTERLIST_DEFAULT_INC */)
  3162. {
  3163. DbgLog((LOG_TRACE, 4, TEXT("CListFilters::CListFilters(%d, %d)"), iMax, iInc)) ;
  3164. m_iCount = 0 ;
  3165. m_iMax = iMax ;
  3166. m_iInc = iInc ;
  3167. m_pGraph = NULL ;
  3168. m_pFilters = new CFilterData [m_iMax] ;
  3169. ASSERT(m_pFilters) ;
  3170. }
  3171. CListFilters::~CListFilters(void)
  3172. {
  3173. DbgLog((LOG_TRACE, 4, TEXT("CListFilters::~CListFilters()"))) ;
  3174. if (m_pFilters)
  3175. delete [] m_pFilters ;
  3176. m_iCount = 0 ;
  3177. }
  3178. void CListFilters::RemoveAllFromGraph(void)
  3179. {
  3180. DbgLog((LOG_TRACE, 4, TEXT("CListFilters::RemoveAllFromGraph()"))) ;
  3181. IBaseFilter *pFilter ;
  3182. for (int i = 0 ; i < m_iCount ; i++)
  3183. {
  3184. if (pFilter = m_pFilters[i].GetInterface())
  3185. {
  3186. #ifdef DEBUG
  3187. FILTER_INFO fi ;
  3188. pFilter->QueryFilterInfo(&fi) ;
  3189. DbgLog((LOG_TRACE, 5, TEXT("Removing filter %S..."), fi.achName)) ;
  3190. if (fi.pGraph)
  3191. fi.pGraph->Release() ;
  3192. #endif // DEBUG
  3193. EXECUTE_ASSERT(SUCCEEDED(m_pGraph->RemoveFilter(pFilter))) ;
  3194. // pFilter->Release() ; -- done in ResetElement() below
  3195. m_pFilters[i].ResetElement() ;
  3196. }
  3197. }
  3198. m_iCount = 0 ;
  3199. m_pGraph = NULL ; // no filter in list, why have the graph??
  3200. }
  3201. BOOL CListFilters::AddFilter(IBaseFilter *pFilter, LPCWSTR lpszwName, GUID *pClsid)
  3202. {
  3203. DbgLog((LOG_TRACE, 4, TEXT("CListFilters::AddFilter(0x%lx, %S, 0x%lx)"),
  3204. pFilter, lpszwName ? lpszwName : L"NULL", pClsid)) ;
  3205. if (NULL == pFilter)
  3206. {
  3207. DbgLog((LOG_ERROR, 1, TEXT("Internal Error: NULL pFilter param passed to AddFilter()"))) ;
  3208. return FALSE ;
  3209. }
  3210. if (m_iCount >= m_iMax)
  3211. {
  3212. if (! ExpandList() ) // couldn't expand list
  3213. {
  3214. DbgLog((LOG_ERROR, 1, TEXT("INTERNAL ERROR: Too many filters added to CListFilters"))) ;
  3215. return FALSE ;
  3216. }
  3217. DbgLog((LOG_TRACE, 5, TEXT("CListFilters list has been extended"))) ;
  3218. }
  3219. m_pFilters[m_iCount].SetElement(pFilter, lpszwName, pClsid) ;
  3220. m_iCount++ ;
  3221. return TRUE ;
  3222. }
  3223. BOOL CListFilters::GetFilter(int iIndex, IBaseFilter **ppFilter, LPWSTR *lpszwName)
  3224. {
  3225. DbgLog((LOG_TRACE, 4, TEXT("CListFilters::GetFilter(%d, 0x%lx, 0x%lx)"),
  3226. iIndex, ppFilter, lpszwName)) ;
  3227. if (iIndex > m_iCount)
  3228. {
  3229. DbgLog((LOG_ERROR, 1,
  3230. TEXT("INTERNAL ERROR: Bad index (%d) for CListDecoders::GetFilter()"), iIndex)) ;
  3231. *ppFilter = NULL ;
  3232. return FALSE ;
  3233. }
  3234. *ppFilter = m_pFilters[iIndex].GetInterface() ;
  3235. *lpszwName = m_pFilters[iIndex].GetName() ;
  3236. return TRUE ;
  3237. }
  3238. BOOL CListFilters::GetFilter(GUID *pClsid, int iIndex, IBaseFilter **ppFilter)
  3239. {
  3240. DbgLog((LOG_TRACE, 4, TEXT("CListFilters::GetFilter(0x%lx, %d, 0x%lx)"),
  3241. pClsid, iIndex, ppFilter)) ;
  3242. GUID *pFilterClsid ;
  3243. for (int i = 0 ; i < m_iCount ; i++)
  3244. {
  3245. if ((pFilterClsid = m_pFilters[i].GetClsid()) &&
  3246. IsEqualGUID(*pClsid, *pFilterClsid))
  3247. {
  3248. if (0 == iIndex)
  3249. {
  3250. *ppFilter = m_pFilters[i].GetInterface() ;
  3251. return TRUE ;
  3252. }
  3253. else // skip this one -- we want a later one
  3254. iIndex-- ;
  3255. }
  3256. }
  3257. *ppFilter = NULL ;
  3258. return FALSE ;
  3259. }
  3260. BOOL CListFilters::IsInList(IBaseFilter *pFilter)
  3261. {
  3262. DbgLog((LOG_TRACE, 4, TEXT("CListFilters::IsInList(0x%lx)"), pFilter)) ;
  3263. for (int i = 0 ; i < m_iCount ; i++)
  3264. {
  3265. if (IsEqualObject(pFilter, m_pFilters[i].GetInterface()))
  3266. return TRUE ;
  3267. }
  3268. return FALSE ; // didn't match any
  3269. }
  3270. void CListFilters::ClearList(void)
  3271. {
  3272. DbgLog((LOG_TRACE, 4, TEXT("CListFilters::ClearList()"))) ;
  3273. for (int i = 0 ; i < m_iCount ; i++)
  3274. {
  3275. #ifdef DEBUG
  3276. FILTER_INFO fi ;
  3277. m_pFilters[i].GetInterface()->QueryFilterInfo(&fi) ;
  3278. DbgLog((LOG_TRACE, 5, TEXT("Removing filter %S..."), fi.achName)) ;
  3279. if (fi.pGraph)
  3280. fi.pGraph->Release() ;
  3281. #endif // DEBUG
  3282. m_pFilters[i].ResetElement() ;
  3283. }
  3284. m_iCount = 0 ;
  3285. }
  3286. BOOL CListFilters::ExpandList(void)
  3287. {
  3288. return FALSE ; // not implemented for now
  3289. }
  3290. // -------------------------------------
  3291. // CFilterData class implementation...
  3292. // -------------------------------------
  3293. CFilterData::CFilterData(void)
  3294. {
  3295. DbgLog((LOG_TRACE, 4, TEXT("CFilterData::CFilterData()"))) ;
  3296. m_pFilter = NULL ;
  3297. m_lpszwName = NULL ;
  3298. m_pClsid = NULL ;
  3299. }
  3300. CFilterData::~CFilterData(void)
  3301. {
  3302. DbgLog((LOG_TRACE, 4, TEXT("CFilterData::~CFilterData()"))) ;
  3303. ResetElement() ;
  3304. }
  3305. void CFilterData::SetElement(IBaseFilter *pFilter, LPCWSTR lpszwName, GUID *pClsid)
  3306. {
  3307. DbgLog((LOG_TRACE, 4, TEXT("CFilterData::SetElement(0x%lx, 0x%lx, 0x%lx)"),
  3308. pFilter, lpszwName, pClsid)) ;
  3309. m_pFilter = pFilter ; // should we AddRef() too?
  3310. if (lpszwName)
  3311. {
  3312. m_lpszwName = new WCHAR [sizeof(WCHAR) * (lstrlenW(lpszwName) + 1)] ;
  3313. ASSERT(m_lpszwName) ;
  3314. if (NULL == m_lpszwName) // bad situation...
  3315. return ; // ...just bail out
  3316. lstrcpyW(m_lpszwName, lpszwName) ;
  3317. }
  3318. if (pClsid)
  3319. {
  3320. m_pClsid = (GUID *) new BYTE[sizeof(GUID)] ;
  3321. ASSERT(m_pClsid) ;
  3322. if (NULL == m_pClsid) // bad situation...
  3323. return ; // ...just bail out
  3324. *m_pClsid = *pClsid ;
  3325. }
  3326. }
  3327. void CFilterData::ResetElement(void)
  3328. {
  3329. DbgLog((LOG_TRACE, 4, TEXT("CFilterData::ResetElement()"))) ;
  3330. LONG l ;
  3331. if (m_pFilter)
  3332. {
  3333. l = m_pFilter->Release() ;
  3334. DbgLog((LOG_TRACE, 3, TEXT("post Release() ref count is %ld"), l)) ;
  3335. m_pFilter = NULL ;
  3336. }
  3337. if (m_lpszwName)
  3338. {
  3339. DbgLog((LOG_TRACE, 5, TEXT("Filter %S has just been released"), m_lpszwName)) ;
  3340. delete [] m_lpszwName ;
  3341. m_lpszwName = NULL ;
  3342. }
  3343. if (m_pClsid)
  3344. {
  3345. delete [] ((BYTE *) m_pClsid) ;
  3346. m_pClsid = NULL ;
  3347. }
  3348. }