Source code of Windows XP (NT5)
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.

3062 lines
114 KiB

  1. //===========================================================================
  2. //
  3. // VidCtl.cpp : Implementation of CVidCtl the core viewer control class
  4. // Copyright (c) Microsoft Corporation 1999.
  5. //
  6. /////////////////////////////////////////////////////////////////////////////
  7. #include "stdafx.h"
  8. #ifndef TUNING_MODEL_ONLY
  9. #define ENCODERCAT_HACK 1
  10. #include <atlgdi.h>
  11. #include <bdatypes.h>
  12. #include <bdamedia.h>
  13. #include <evcode.h>
  14. #include <wmsdk.h>
  15. #include <wininet.h>
  16. #include "seg.h"
  17. #include "MSVidtvtuner.h"
  18. #include "msvidvideorenderer.h"
  19. #include "msvidwebdvd.h"
  20. #include "VidCtl.h"
  21. #include "msvidsbesink.h"
  22. #include "msvidsbesource.h"
  23. #include "msvidfileplayback.h"
  24. //#include "perfevents.h"
  25. const WCHAR g_kwszDVDURLPrefix[] = L"DVD:";
  26. const WCHAR g_kwszDVDSimpleURL[] = L"DVD";
  27. DEFINE_EXTERN_OBJECT_ENTRY(CLSID_MSVidCtl, CVidCtl)
  28. MediaMajorTypeList CVidCtl::VideoTypes;
  29. MediaMajorTypeList CVidCtl::AudioTypes;
  30. #ifndef KSCATEGORY_ENCODER
  31. #define STATIC_KSCATEGORY_ENCODER \
  32. 0x19689bf6, 0xc384, 0x48fd, 0xad, 0x51, 0x90, 0xe5, 0x8c, 0x79, 0xf7, 0xb
  33. DEFINE_GUIDSTRUCT("19689BF6-C384-48fd-AD51-90E58C79F70B", KSCATEGORY_ENCODER);
  34. #define KSCATEGORY_ENCODER DEFINE_GUIDNAMED(KSCATEGORY_ENCODER)
  35. #endif
  36. /////////////////////////////////////////////////////////////////////////////
  37. // CVidCtl
  38. STDMETHODIMP CVidCtl::get_State(MSVidCtlStateList *lState){
  39. try{
  40. if(lState){
  41. *lState = m_State;
  42. return S_OK;
  43. }
  44. return E_POINTER;
  45. }
  46. catch(HRESULT hres){
  47. return hres;
  48. }
  49. catch(...){
  50. return E_UNEXPECTED;
  51. }
  52. }
  53. CVidCtl::~CVidCtl() {
  54. try {
  55. try {
  56. if (m_pGraph && !m_pGraph.IsStopped()) {
  57. Stop();
  58. }
  59. } catch(...) {
  60. }
  61. m_pSystemEnum.Release();
  62. m_pFilterMapper.Release();
  63. DecomposeAll(); // put_Container(NULL) on all the composition segments
  64. m_pComposites.clear();
  65. if (m_pInput) {
  66. PQGraphSegment(m_pInput)->put_Container(NULL);
  67. m_pInput.Release();
  68. }
  69. if (m_pVideoRenderer) {
  70. PQGraphSegment(m_pVideoRenderer)->put_Container(NULL);
  71. m_pVideoRenderer.Release();
  72. }
  73. if (m_pAudioRenderer) {
  74. PQGraphSegment(m_pAudioRenderer)->put_Container(NULL);
  75. m_pAudioRenderer.Release();
  76. }
  77. {
  78. // chosen devices&Outputs
  79. if (!!m_pOutputsInUse && m_pOutputsInUse.begin() != m_pOutputsInUse.end()) {
  80. VWOutputDevices::iterator i;
  81. for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) {
  82. if ((*i).punkVal) {
  83. PQGraphSegment((*i).punkVal)->put_Container(NULL);
  84. }
  85. }
  86. m_pOutputsInUse.Release();
  87. }
  88. }
  89. {
  90. // chosen devices&features
  91. if(m_pFeaturesInUse && m_pFeaturesInUse.begin() != m_pFeaturesInUse.end()){
  92. VWFeatures::iterator i;
  93. for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) {
  94. if ((*i).punkVal) {
  95. PQGraphSegment((*i).punkVal)->put_Container(NULL);
  96. }
  97. }
  98. m_pFeaturesInUse.Release();
  99. }
  100. }
  101. // available collections
  102. m_pInputs.Release();
  103. m_pOutputs.Release();
  104. m_pFeatures.Release();
  105. m_pVRs.Release();
  106. m_pARs.Release();
  107. if (m_fNotificationSet) {
  108. m_pGraph.SetMediaEventNotificationWindow(0, 0, 0);
  109. }
  110. if (m_pGraph) {
  111. if (m_dwROTCookie) {
  112. m_pGraph.RemoveFromROT(m_dwROTCookie);
  113. }
  114. m_pGraph.Release();
  115. }
  116. if (m_pTopWin && m_pTopWin->m_hWnd && ::IsWindow(m_pTopWin->m_hWnd)) {
  117. m_pTopWin->SendMessage(WM_CLOSE);
  118. delete m_pTopWin;
  119. m_pTopWin = NULL;
  120. }
  121. } catch (...) {
  122. TRACELM(TRACE_ERROR, "CVidCtl::~CVidCtl() catch(...)");
  123. }
  124. }
  125. void CVidCtl::Init()
  126. {
  127. VIDPERF_FUNC;
  128. if (m_fInit) return;
  129. TRACELM(TRACE_DETAIL, "CVidCtl::Init()");
  130. ASSERT(!m_pGraph);
  131. m_pGraph = PQGraphBuilder(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER);
  132. if (!m_pGraph) {
  133. TRACELM(TRACE_ERROR, "CVidCtl::Init() can't create graph object");
  134. THROWCOM(E_UNEXPECTED);
  135. }
  136. PQObjectWithSite pos(m_pGraph);
  137. if (pos) {
  138. pos->SetSite(static_cast<IMSVidCtl*>(this));
  139. }
  140. HRESULT hr = m_pGraph.AddToROT(&m_dwROTCookie);
  141. if (FAILED(hr)) {
  142. m_dwROTCookie = 0;
  143. TRACELM(TRACE_ERROR, "CVidCtl::Init() can't add graph to ROT");
  144. }
  145. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::Init() graph = " << m_pGraph), "");
  146. SetTimer();
  147. SetMediaEventNotification();
  148. if (!m_pSystemEnum) {
  149. m_pSystemEnum = PQCreateDevEnum(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER);
  150. ASSERT(m_pSystemEnum);
  151. }
  152. if (!m_pFilterMapper) {
  153. m_pFilterMapper = m_pGraph;
  154. ASSERT(m_pFilterMapper);
  155. }
  156. m_pFeaturesInUse = static_cast<IMSVidFeatures *>(new CFeatures(false, true));
  157. m_pOutputsInUse = static_cast<IMSVidOutputDevices *>(new COutputDevices(false, true));
  158. m_fInit = true;
  159. }
  160. HRESULT CVidCtl::GetInputs(const GUID2& catguid, VWInputDevices& pInputs)
  161. {
  162. VIDPERF_FUNC;
  163. //undone: look up category guid to segment object mapping in registry
  164. // for now we're just hard coding the few we're testing with
  165. // inputs
  166. if (catguid == KSCATEGORY_TVTUNER) {
  167. CInputDevices *pDev = new CInputDevices(true);
  168. DSDevices TunerList(m_pSystemEnum, catguid);
  169. DSDevices::iterator i;
  170. for (i = TunerList.begin(); i != TunerList.end(); ++i) {
  171. PQGraphSegment p(CLSID_MSVidAnalogTunerDevice);
  172. if (!p) continue;
  173. p->put_Init(*i);
  174. pDev->m_Devices.push_back(PQDevice(p));
  175. }
  176. pDev->Valid = true;
  177. pInputs = static_cast<IMSVidInputDevices *>(pDev);
  178. return NOERROR;
  179. } else if (catguid == KSCATEGORY_BDA_NETWORK_PROVIDER || catguid == KSCATEGORY_BDA_NETWORK_TUNER) {
  180. GUID2 catguid2 = KSCATEGORY_BDA_NETWORK_PROVIDER;
  181. CInputDevices *pDev = new CInputDevices(true);
  182. DSDevices TunerList(m_pSystemEnum, catguid2);
  183. DSDevices::iterator i;
  184. for (i = TunerList.begin(); i != TunerList.end(); ++i) {
  185. PQGraphSegment p(CLSID_MSVidBDATunerDevice);
  186. if (!p) continue;
  187. p->put_Init(*i);
  188. pDev->m_Devices.push_back(PQDevice(p));
  189. }
  190. pDev->Valid = true;
  191. pInputs = static_cast<IMSVidInputDevices *>(pDev);
  192. return NOERROR;
  193. } else if (catguid == GUID_NULL) {
  194. CInputDevices *pDev = new CInputDevices(true);
  195. // non cat enumerated devices
  196. {
  197. PQGraphSegment p(CLSID_MSVidFilePlaybackDevice);
  198. if (!p) {
  199. _ASSERT(false);
  200. pDev->Release();
  201. return E_NOTIMPL;
  202. }
  203. p->put_Init(NULL);
  204. pDev->m_Devices.push_back(PQDevice(p));
  205. pDev->Valid = true;
  206. pInputs = static_cast<IMSVidInputDevices *>(pDev);
  207. }
  208. {
  209. PQGraphSegment p(CLSID_MSVidWebDVD);
  210. if (!p) {
  211. _ASSERT(false);
  212. pDev->Release();
  213. return E_NOTIMPL;
  214. }
  215. p->put_Init(NULL);
  216. pDev->m_Devices.push_back(PQDevice(p));
  217. pDev->Valid = true;
  218. pInputs = static_cast<IMSVidInputDevices *>(pDev);
  219. }
  220. {
  221. PQGraphSegment p(CLSID_MSVidStreamBufferSource);
  222. if (!p) {
  223. _ASSERT(false);
  224. pDev->Release();
  225. return E_NOTIMPL;
  226. }
  227. p->put_Init(NULL);
  228. pDev->m_Devices.push_back(PQDevice(p));
  229. pDev->Valid = true;
  230. pInputs = static_cast<IMSVidInputDevices *>(pDev);
  231. }
  232. return NOERROR;
  233. }
  234. return E_INVALIDARG;
  235. }
  236. HRESULT CVidCtl::GetOutputs(const GUID2& CategoryGuid)
  237. {
  238. VIDPERF_FUNC;
  239. // We only have one output
  240. if (CategoryGuid == GUID_NULL) {
  241. COutputDevices *pDev = new COutputDevices(true);
  242. PQGraphSegment p(CLSID_MSVidStreamBufferSink);
  243. if (!p) {
  244. pDev->Release();
  245. return E_NOTIMPL;
  246. }
  247. p->put_Init(NULL);
  248. pDev->m_Devices.push_back(PQDevice(p));
  249. pDev->Valid = true;
  250. m_pOutputs = static_cast<IMSVidOutputDevices *>(pDev);
  251. }
  252. return S_OK;
  253. }
  254. HRESULT CVidCtl::GetVideoRenderers()
  255. {
  256. VIDPERF_FUNC;
  257. //Video Renderers
  258. CVideoRendererDevices *pDevs = new CVideoRendererDevices(true);
  259. PQGraphSegment p(CLSID_MSVidVideoRenderer);
  260. if (!p) {
  261. pDevs->Release();
  262. return Error(IDS_CANT_CREATE_FILTER, __uuidof(IMSVidCtl), IDS_CANT_CREATE_FILTER);
  263. }
  264. p->put_Init(NULL);
  265. PQDevice pd(p);
  266. if (!pd) {
  267. pDevs->Release();
  268. return E_UNEXPECTED;
  269. }
  270. pDevs->m_Devices.push_back(pd);
  271. pDevs->Valid = true;
  272. m_pVRs = static_cast<IMSVidVideoRendererDevices *>(pDevs);
  273. return NOERROR;
  274. }
  275. HRESULT CVidCtl::GetAudioRenderers()
  276. {
  277. VIDPERF_FUNC;
  278. //Audio Renderers
  279. CAudioRendererDevices *pDevs = new CAudioRendererDevices(true);
  280. PQGraphSegment p(CLSID_MSVidAudioRenderer);
  281. if (!p) {
  282. pDevs->Release();
  283. return Error(IDS_CANT_CREATE_FILTER, __uuidof(IMSVidCtl), IDS_CANT_CREATE_FILTER);
  284. }
  285. p->put_Init(NULL);
  286. PQDevice pd(p);
  287. if (!pd) {
  288. pDevs->Release();
  289. return E_UNEXPECTED;
  290. }
  291. pDevs->m_Devices.push_back(pd);
  292. pDevs->Valid = true;
  293. m_pARs = static_cast<IMSVidAudioRendererDevices *>(pDevs);
  294. return NOERROR;
  295. }
  296. HRESULT CVidCtl::GetFeatures()
  297. {
  298. VIDPERF_FUNC;
  299. // available features
  300. // undone: change hard coded list of features into registry lookup
  301. if (!m_pFeatures) {
  302. CFeatures *pDev = new CFeatures;
  303. if (!pDev) {
  304. return E_OUTOFMEMORY;
  305. }
  306. pDev->Valid = true;
  307. m_pFeatures = static_cast<IMSVidFeatures *>(pDev);
  308. {
  309. PQGraphSegment p(CLSID_MSVidDataServices);
  310. if (p) {
  311. p->put_Init(NULL);
  312. pDev->m_Devices.push_back(PQDevice(p));
  313. } else {
  314. _ASSERT(false);
  315. }
  316. }
  317. {
  318. PQGraphSegment p(CLSID_MSVidClosedCaptioning);
  319. if (p) {
  320. p->put_Init(NULL);
  321. pDev->m_Devices.push_back(PQDevice(p));
  322. } else {
  323. _ASSERT(false);
  324. }
  325. }
  326. {
  327. PQGraphSegment p(CLSID_MSVidXDS);
  328. if (p) {
  329. p->put_Init(NULL);
  330. pDev->m_Devices.push_back(PQDevice(p));
  331. } else {
  332. _ASSERT(false);
  333. }
  334. }
  335. #if ENCODERCAT_HACK
  336. bool AddedMux = false;
  337. #endif
  338. {
  339. // Hardware mux category
  340. DSDevices EncoderList(m_pSystemEnum, KSCATEGORY_MULTIPLEXER);
  341. DSDevices::iterator i;
  342. for (i = EncoderList.begin(); i != EncoderList.end(); ++i) {
  343. PQGraphSegment p(CLSID_MSVidEncoder);
  344. if (!p) continue;
  345. p->put_Init(*i);
  346. pDev->m_Devices.push_back(PQDevice(p));
  347. #if ENCODERCAT_HACK
  348. AddedMux = true;
  349. #endif
  350. }
  351. }
  352. {
  353. // Software mux category
  354. DSDevices EncoderList(m_pSystemEnum, CLSID_MediaMultiplexerCategory);
  355. DSDevices::iterator i;
  356. for (i = EncoderList.begin(); i != EncoderList.end(); ++i) {
  357. PQGraphSegment p(CLSID_MSVidEncoder);
  358. if (!p) continue;
  359. p->put_Init(*i);
  360. pDev->m_Devices.push_back(PQDevice(p));
  361. #if ENCODERCAT_HACK
  362. AddedMux = true;
  363. #endif
  364. }
  365. }
  366. #if ENCODERCAT_HACK
  367. if(!AddedMux){
  368. DSDevices EncoderList(m_pSystemEnum, KSCATEGORY_ENCODER);
  369. DSDevices::iterator i;
  370. for (i = EncoderList.begin(); i != EncoderList.end(); ++i) {
  371. PQGraphSegment p(CLSID_MSVidEncoder);
  372. if (!p) continue;
  373. p->put_Init(*i);
  374. pDev->m_Devices.push_back(PQDevice(p));
  375. }
  376. }
  377. #endif
  378. }
  379. return NOERROR;
  380. }
  381. // Takes a variant input and a list of input devices to attempt to view the input with
  382. HRESULT CVidCtl::SelectViewFromSegmentList(CComVariant &pVar, VWInputDevices& grList, PQInputDevice& pCurInput) {
  383. VIDPERF_FUNC;
  384. VWInputDevices::iterator i = grList.begin();
  385. // skip devices until we're past the current one(if there is a current one)
  386. for (; pCurInput && i != grList.end(); ++i) {
  387. PQInputDevice pInDev((*i).punkVal);
  388. VARIANT_BOOL f = VARIANT_FALSE;
  389. HRESULT hr = pCurInput->IsEqualDevice(pInDev, &f);
  390. if (SUCCEEDED(hr) && f == VARIANT_TRUE){
  391. ++i;
  392. break;
  393. }
  394. }
  395. // run thru to the end of the list
  396. for (; i != grList.end(); ++i) {
  397. PQInputDevice pInDev((*i).punkVal);
  398. HRESULT hr = pInDev->View(&pVar);
  399. if(SUCCEEDED(hr)){
  400. if(m_pInput){
  401. PQGraphSegment(m_pInput)->put_Container(NULL);
  402. }
  403. m_pInput = pInDev;
  404. m_pInputNotify = m_pInput;
  405. m_CurView = pVar;
  406. m_fGraphDirty = true;
  407. return NOERROR;
  408. }
  409. }
  410. if (pCurInput) {
  411. // retry the ones we skipped
  412. i = grList.begin();
  413. for (; i != grList.end(); ++i) {
  414. PQInputDevice pInDev((*i).punkVal);
  415. HRESULT hr = pInDev->View(&pVar);
  416. if(SUCCEEDED(hr)){
  417. if(m_pInput){
  418. PQGraphSegment(m_pInput)->put_Container(NULL);
  419. }
  420. m_pInput = pInDev;
  421. m_pInputNotify = m_pInput;
  422. m_CurView = pVar;
  423. m_fGraphDirty = true;
  424. return NOERROR;
  425. }
  426. }
  427. }
  428. return E_FAIL;
  429. }
  430. // non-interface functions
  431. HRESULT CVidCtl::SelectView(VARIANT *pv, bool fNext) {
  432. VIDPERF_FUNC;
  433. HRESULT hr;
  434. TRACELM(TRACE_DETAIL, "CVidCtl::SelectView()");
  435. if (!m_fInit) {
  436. Init();
  437. }
  438. if (!pv) {
  439. m_CurView = CComVariant();
  440. return NOERROR;
  441. }
  442. CComVariant pVar(*pv);
  443. if(pv->vt & VT_BYREF){
  444. if(pv->vt == (VT_UNKNOWN|VT_BYREF)){
  445. pVar=(*reinterpret_cast<IUnknown**>(pv->punkVal));
  446. }
  447. else if(pv->vt == (VT_DISPATCH|VT_BYREF)){
  448. pVar = (*reinterpret_cast<IDispatch**>(pv->pdispVal));
  449. }
  450. }
  451. if (!pVar) {
  452. m_CurView = CComVariant();
  453. return NOERROR;
  454. }
  455. if (m_pInput && !fNext) {
  456. // && pVar != m_CurView) {
  457. // note: only try different content on current device,
  458. // if app tries to re-view the current view content then we
  459. // attempt to iterate to next available device
  460. hr = m_pInput->View(&pVar);
  461. if (SUCCEEDED(hr)) {
  462. // currently selected device can view this new content
  463. return hr;
  464. }
  465. }
  466. if (m_pGraph.GetState() != State_Stopped) {
  467. return Error(IDS_INVALID_STATE, __uuidof(IMSVidCtl), HRESULT_FROM_WIN32(ERROR_INVALID_STATE));
  468. }
  469. if (m_pInput) {
  470. hr = DecomposeSegment(VWGraphSegment(m_pInput));
  471. if (FAILED(hr)) {
  472. return Error(IDS_CANT_REMOVE_SEG, __uuidof(IMSVidCtl), IDS_CANT_REMOVE_SEG);
  473. }
  474. }
  475. // Try the ATSC tune request
  476. if (pVar.vt == VT_UNKNOWN || pVar.vt == VT_DISPATCH) {
  477. PQTuneRequest ptr(pVar.vt == VT_UNKNOWN ? pVar.punkVal : pVar.pdispVal);
  478. if (ptr) {
  479. VWInputDevices pInputs;
  480. PQChannelTuneRequest ptr2(ptr);
  481. if (ptr2) {
  482. PQATSCChannelTuneRequest ptr3(ptr);
  483. if (!ptr3) {
  484. hr = GetInputs(KSCATEGORY_TVTUNER, pInputs);
  485. if(SUCCEEDED(hr)){
  486. hr = SelectViewFromSegmentList(pVar, pInputs, m_pInput);
  487. if(SUCCEEDED(hr)){
  488. m_CurViewCatGuid = KSCATEGORY_TVTUNER;
  489. return hr;
  490. }
  491. }
  492. }
  493. }
  494. hr = GetInputs(KSCATEGORY_BDA_NETWORK_PROVIDER, pInputs);
  495. if(SUCCEEDED(hr)){
  496. hr = SelectViewFromSegmentList(pVar, pInputs, m_pInput);
  497. if(SUCCEEDED(hr)){
  498. m_CurViewCatGuid = KSCATEGORY_BDA_NETWORK_PROVIDER;
  499. return hr;
  500. }
  501. }
  502. if(FAILED(hr)){
  503. return hr;
  504. }
  505. }
  506. }
  507. // Try to view the File input and DVD Segments
  508. VWInputDevices pInputs;
  509. hr = GetInputs(GUID_NULL, pInputs);
  510. hr = SelectViewFromSegmentList(pVar, pInputs, m_pInput);
  511. if(SUCCEEDED(hr)){
  512. m_CurViewCatGuid = GUID_NULL;
  513. return hr;
  514. }
  515. return Error(IDS_CANT_VIEW, __uuidof(IMSVidCtl), IDS_CANT_VIEW);
  516. }
  517. HRESULT CVidCtl::LoadDefaultVR(void) {
  518. VIDPERF_FUNC;
  519. PQVRGraphSegment pGS;
  520. HRESULT hr = pGS.CoCreateInstance(CLSID_MSVidVideoRenderer);
  521. if (FAILED(hr) || !pGS) {
  522. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultVR() can't instantiate default video renderer. hr = " << std::hex << hr), "");
  523. return Error(IDS_CANT_CREATE_FILTER, __uuidof(IMSVidCtl), IDS_CANT_CREATE_FILTER);
  524. }
  525. hr = pGS->put_Init(NULL);
  526. if (FAILED(hr)) {
  527. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultVR() can't init default video renderer. hr = " << std::hex << hr), "");
  528. return hr;
  529. }
  530. hr = pGS->put_Container(this);
  531. if (FAILED(hr)) {
  532. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultVR() can't load default video renderer. hr = " << std::hex << hr), "");
  533. return hr;
  534. }
  535. if (!m_bNegotiatedWnd) {
  536. if (!m_bInPlaceActive) {
  537. hr = InPlaceActivate(OLEIVERB_INPLACEACTIVATE, NULL);
  538. if (FAILED(hr)) {
  539. return hr;
  540. }
  541. }
  542. }
  543. #if 0
  544. VARIANT_BOOL ov = (m_bWndLess && WindowHasHWOverlay(m_CurrentSurface.Owner())) ? VARIANT_TRUE : VARIANT_FALSE;
  545. #else
  546. // always try to use overlay if we're wndless. vmr will tell us if it isn't available
  547. VARIANT_BOOL ov = m_bWndLess ? VARIANT_TRUE : VARIANT_FALSE;
  548. #endif
  549. hr = pGS->put_UseOverlay(ov);
  550. if (FAILED(hr)) {
  551. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultVR() can't set useoverlay. hr = " << std::hex << hr), "");
  552. return hr;
  553. }
  554. m_pVideoRenderer = pGS;
  555. return NOERROR;
  556. }
  557. HRESULT CVidCtl::LoadDefaultAR(void) {
  558. VIDPERF_FUNC;
  559. PQGraphSegment pGS;
  560. HRESULT hr = pGS.CoCreateInstance(CLSID_MSVidAudioRenderer);
  561. if (FAILED(hr) || !pGS) {
  562. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultAR() can't instantiate default Audio renderer. hr = " << std::hex << hr), "");
  563. return Error(IDS_CANT_CREATE_FILTER, __uuidof(IMSVidCtl), IDS_CANT_CREATE_FILTER);
  564. }
  565. hr = pGS->put_Init(NULL);
  566. if (FAILED(hr)) {
  567. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultAR() can't init default Audio renderer. hr = " << std::hex << hr), "");
  568. return hr;
  569. }
  570. hr = pGS->put_Container(this);
  571. if (FAILED(hr)) {
  572. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::LoadDefaultAR() can't load default Audio renderer. hr = " << std::hex << hr), "");
  573. return hr;
  574. }
  575. m_pAudioRenderer = pGS;
  576. return NOERROR;
  577. }
  578. HRESULT CVidCtl::Compose(VWGraphSegment &Up, VWGraphSegment &Down, int &NewIdx) {
  579. VIDPERF_FUNC;
  580. PQCompositionSegment pCS;
  581. #if 0
  582. // This code is for returning error codes in failure cases for the default composition segment
  583. HRESULT hrExpected = S_OK;
  584. HRESULT hrFailed = E_FAIL;
  585. bool bCheckHR = false;
  586. #endif
  587. _ASSERT(!!Up && !!Down);
  588. // Analog TV to Video Renderer Composition Segment
  589. if (VWGraphSegment(Up).Category() == KSCATEGORY_TVTUNER && VWGraphSegment(Down).ClassID() == CLSID_MSVidVideoRenderer) {
  590. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidAnalogCaptureToOverlayMixer);
  591. if (FAILED(hr) || !pCS) {
  592. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to ov mixer composite. hr = " << std::hex << hr), "");
  593. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  594. }
  595. }
  596. // Analog TV to Stream Buffer Sink Compsition Segment
  597. else if (VWGraphSegment(Up).Category() == KSCATEGORY_TVTUNER && VWGraphSegment(Down).ClassID() == CLSID_MSVidStreamBufferSink) {
  598. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidAnalogCaptureToStreamBufferSink);
  599. if (FAILED(hr) || !pCS) {
  600. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to time shift sink composite. hr = " << std::hex << hr), "");
  601. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  602. }
  603. }
  604. // Digital TV (bda) to Video Renderer Compsition Segment
  605. else if (VWGraphSegment(Up).ClassID() == CLSID_MSVidBDATunerDevice && VWGraphSegment(Down).ClassID() == CLSID_MSVidStreamBufferSink) {
  606. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidDigitalCaptureToStreamBufferSink);
  607. if (FAILED(hr) || !pCS) {
  608. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to time shift sink composite. hr = " << std::hex << hr), "");
  609. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  610. }
  611. }
  612. // Analog TV to Data Services Compsition Segment
  613. else if (VWGraphSegment(Up).Category() == KSCATEGORY_TVTUNER && VWGraphSegment(Down).ClassID() == CLSID_MSVidDataServices) {
  614. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidAnalogCaptureToDataServices);
  615. if (FAILED(hr) || !pCS) {
  616. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog tuner/capture to data services composite. hr = " << std::hex << hr), "");
  617. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  618. }
  619. }
  620. // Digial TV (bda) or DVD to Closed Caption Compsition Segment
  621. else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidBDATunerDevice ||
  622. VWGraphSegment(Up).ClassID() == CLSID_MSVidWebDVD) &&
  623. VWGraphSegment(Down).ClassID() == CLSID_MSVidClosedCaptioning) {
  624. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidMPEG2DecoderToClosedCaptioning);
  625. if (FAILED(hr) || !pCS) {
  626. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate mp2 to CC composite. hr = " << std::hex << hr), "");
  627. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  628. }
  629. }
  630. // File Playback to Video Renderer Compsition Segment
  631. else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidFilePlaybackDevice ) &&
  632. VWGraphSegment(Down).ClassID() == CLSID_MSVidVideoRenderer) {
  633. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidFilePlaybackToVideoRenderer);
  634. if (FAILED(hr) || !pCS) {
  635. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate file playback to video renderer composite. hr = " << std::hex << hr), "");
  636. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  637. }
  638. }
  639. // File Playback to Audio Renderer Compsition Segment
  640. else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidFilePlaybackDevice ) &&
  641. VWGraphSegment(Down).ClassID() == CLSID_MSVidAudioRenderer) {
  642. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidFilePlaybackToAudioRenderer);
  643. if (FAILED(hr) || !pCS) {
  644. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate file playback to audio renderer composite. hr = " << std::hex << hr), "");
  645. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), E_UNEXPECTED);
  646. }
  647. }
  648. // DVD to Video Renderer Compsition Segment
  649. else if (VWGraphSegment(Up).ClassID() == CLSID_MSVidWebDVD && VWGraphSegment(Down).ClassID() == CLSID_MSVidVideoRenderer) {
  650. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidWebDVDToVideoRenderer);
  651. if (FAILED(hr) || !pCS) {
  652. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate webdvd to video renderer, hr = " << std::hex << hr), "");
  653. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  654. }
  655. }
  656. #if 0
  657. else if (VWGraphSegment(Up).ClassID() == CLSID_MSVidWebDVD && VWGraphSegment(Down).ClassID() == CLSID_MSVidAudioRenderer) {
  658. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidWebDVDToAudioRenderer);
  659. if (FAILED(hr) || !pCS) {
  660. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate time shift source to data services composite. hr = " << std::hex << hr), "");
  661. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  662. }
  663. }
  664. #endif
  665. ///////////////////////////////////////////////////
  666. // New Compostion Segments for FreeStyle Endgame //
  667. ///////////////////////////////////////////////////
  668. // XDS to Stream Buffer Sink Compsition Segment
  669. else if (VWGraphSegment(Up).ClassID() == CLSID_MSVidXDS && (VWGraphSegment(Down).ClassID() == CLSID_MSVidStreamBufferSink)) {
  670. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidDataServicesToStreamBufferSink);
  671. if (FAILED(hr) || !pCS) {
  672. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate time shift source to data services composite. hr = " << std::hex << hr), "");
  673. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  674. }
  675. }
  676. // Encoder to Stream Buffer Sink Compsition Segment
  677. else if (VWGraphSegment(Up).ClassID() == CLSID_MSVidEncoder && (VWGraphSegment(Down).ClassID() == CLSID_MSVidStreamBufferSink)) {
  678. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidEncoderToStreamBufferSink);
  679. if (FAILED(hr) || !pCS) {
  680. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate encoder to time shift sink composite. hr = " << std::hex << hr), "");
  681. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  682. }
  683. }
  684. // StreamBufferSource to Video Renderer Compsition Segment
  685. else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidStreamBufferSource ) &&
  686. VWGraphSegment(Down).ClassID() == CLSID_MSVidVideoRenderer) {
  687. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidStreamBufferSourceToVideoRenderer); // name change needed
  688. if (FAILED(hr) || !pCS) {
  689. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate time shift source to CC composite. hr = " << std::hex << hr), "");
  690. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  691. }
  692. }
  693. // Analog Capture to XDS
  694. else if (VWGraphSegment(Up).Category() == KSCATEGORY_TVTUNER && VWGraphSegment(Down).ClassID() == CLSID_MSVidXDS){
  695. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidAnalogCaptureToXDS);
  696. if (FAILED(hr) || !pCS) {
  697. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to XDS composite. hr = " << std::hex << hr), "");
  698. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  699. }
  700. }
  701. // Analog Capture to Encoder
  702. else if (VWGraphSegment(Up).Category() == KSCATEGORY_TVTUNER && VWGraphSegment(Down).ClassID() == CLSID_MSVidEncoder){
  703. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidAnalogTVToEncoder);
  704. if (FAILED(hr) || !pCS) {
  705. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to XDS composite. hr = " << std::hex << hr), "");
  706. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  707. }
  708. }
  709. // StreamBufferSource to CC
  710. else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidStreamBufferSource ) && VWGraphSegment(Down).ClassID() == CLSID_MSVidClosedCaptioning){
  711. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidSBESourceToCC);
  712. if (FAILED(hr) || !pCS) {
  713. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate analog capture to XDS composite. hr = " << std::hex << hr), "");
  714. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  715. }
  716. }
  717. else if ((VWGraphSegment(Up).ClassID() == CLSID_MSVidStreamBufferSource) && (VWGraphSegment(Down).ClassID() == CLSID_MSVidStreamBufferSink)){
  718. return E_FAIL;
  719. }
  720. else {
  721. HRESULT hr = pCS.CoCreateInstance(CLSID_MSVidGenericComposite);
  722. if (FAILED(hr) || !pCS) {
  723. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't instantiate generic composite. hr = " << std::hex << hr), "");
  724. return Error(IDS_CANT_CREATE_CUSTOM_COMPSEG, __uuidof(IMSVidCtl), IDS_CANT_CREATE_CUSTOM_COMPSEG);
  725. }
  726. }
  727. HRESULT hr = pCS->put_Init(NULL);
  728. if (FAILED(hr) && hr != E_NOTIMPL) {
  729. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't init new comp seg. hr = " << std::hex << hr), "");
  730. return hr;
  731. }
  732. VWGraphSegment pSeg(pCS);
  733. ASSERT(pSeg);
  734. m_pComposites.push_back(pSeg);
  735. NewIdx = m_pComposites.size() - 1;
  736. hr = pCS->put_Container(this);
  737. if (FAILED(hr)) {
  738. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't put_continaer for new comp segment. hr = " << std::hex << hr), "");
  739. return hr;
  740. }
  741. hr = pCS->Compose(PQGraphSegment(Up), PQGraphSegment(Down));
  742. #if 0
  743. if(bCheckHR){
  744. if(hr != hrExpected){
  745. return hrFailed;
  746. }
  747. else{
  748. return hr;
  749. }
  750. }
  751. #endif
  752. if (FAILED(hr)) {
  753. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Compose() can't compose up = " << Up << " with down = " << Down << " hr = " << hexdump(hr) ), "");
  754. return hr;
  755. }
  756. return NOERROR;
  757. }
  758. HRESULT CVidCtl::BuildGraph(void) {
  759. CPerfCounter pCounterBuild, pCounterPutC, pCounterCompose, pCounterBuilds, pCounterComp, pCounterB;
  760. pCounterBuild.Reset();
  761. TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph()");
  762. BOOL lRes = 0;
  763. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  764. HRESULT hr;
  765. ASSERT(m_pGraph);
  766. if(m_State != STATE_UNBUILT && m_fGraphDirty != true){
  767. return S_OK; // need a graph already built warning message
  768. }
  769. // make sure any needed default renderer's are selected prior to calling
  770. // build on the other segments so all segments are loaded before any
  771. // build() functions are called.
  772. // make sure required defaultable segments are set or assign a default
  773. // also make sure every segment knows the container
  774. bool fDefVideoRenderer = false;
  775. pCounterPutC.Reset();
  776. if (m_pVideoRenderer) {
  777. hr = PQGraphSegment(m_pVideoRenderer)->put_Container(this);
  778. if (FAILED(hr)) {
  779. TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() put_Container failed for Video Renderer");
  780. return hr;
  781. }
  782. } else if (!m_videoSetNull) {
  783. hr = LoadDefaultVR();
  784. if (FAILED(hr)) {
  785. TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() LoadDefaultVR failed");
  786. return hr;
  787. }
  788. if (!m_pVideoRenderer) {
  789. TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() LoadDefaultVR returned NULL Video Renderer");
  790. return E_UNEXPECTED;
  791. }
  792. fDefVideoRenderer = true;
  793. }
  794. TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() default vr checked");
  795. bool fDefAudioRenderer = false;
  796. if (m_pAudioRenderer) {
  797. hr = PQGraphSegment(m_pAudioRenderer)->put_Container(this);
  798. if (FAILED(hr)) {
  799. TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() put_Container failed for Audio Renderer");
  800. return hr;
  801. }
  802. } else if (!m_audioSetNull) {
  803. hr = LoadDefaultAR();
  804. if (FAILED(hr)) {
  805. TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() LoadDefaultAR failed");
  806. return hr;
  807. }
  808. if (!m_pAudioRenderer) {
  809. TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() LoadDefaultAR returned NULL Audio Renderer");
  810. return E_UNEXPECTED;
  811. }
  812. fDefAudioRenderer = true;
  813. }
  814. TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() default ar checked");
  815. if (!m_pInput) {
  816. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() input segment required" << std::hex << hr), "");
  817. return Error(IDS_INPUT_SEG_REQUIRED, __uuidof(IMSVidCtl), IDS_INPUT_SEG_REQUIRED);
  818. }
  819. hr = PQGraphSegment(m_pInput)->put_Container(this);
  820. if (FAILED(hr)) {
  821. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't load input segment. hr = " << std::hex << hr), "");
  822. return hr;
  823. }
  824. TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() input container set");
  825. {
  826. for (VWFeatures::iterator i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) {
  827. // notify them that we're building
  828. hr = VWGraphSegment(*i)->put_Container(this);
  829. if (FAILED(hr)) {
  830. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't load feature segment: " << (*i) << " hr = " << std::hex << hr), "");
  831. return hr;
  832. }
  833. }
  834. }
  835. {
  836. for (VWOutputDevices::iterator i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) {
  837. // notify them that we're building
  838. hr = VWGraphSegment(*i)->put_Container(this);
  839. if (FAILED(hr)) {
  840. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't load output segment: " << (*i) << " hr = " << std::hex << hr), "");
  841. return hr;
  842. }
  843. }
  844. }
  845. pCounterPutC.Stop();
  846. TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() PutContainer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterPutC.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterPutC.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  847. TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() feature container set");
  848. pCounterBuilds.Reset();
  849. // Notify all of the output segments that we are about to build
  850. pCounterB.Reset();
  851. // Notify everyone that composition is about to start
  852. hr = VWGraphSegment(m_pInput)->Build();
  853. if (FAILED(hr) && hr != E_NOTIMPL) {
  854. TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() Build call for input failed");
  855. return hr;
  856. }
  857. pCounterB.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build call to Input: " << (unsigned long)(pCounterB.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterB.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterB.Reset();
  858. {
  859. VWFeatures::iterator i;
  860. for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) {
  861. // notify them that we're building
  862. hr = VWGraphSegment(*i)->Build();
  863. if (FAILED(hr) && hr != E_NOTIMPL) {
  864. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't build feature segment: " << (*i) << " hr = " << std::hex << hr), "");
  865. return hr;
  866. }
  867. pCounterB.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build call to Feature " << (*i) << " : " << (unsigned long)(pCounterB.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterB.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterB.Reset();
  868. }
  869. }
  870. {
  871. VWOutputDevices::iterator i;
  872. for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) {
  873. // notify them that we're building
  874. hr = VWGraphSegment(*i)->Build();
  875. if (FAILED(hr) && hr != E_NOTIMPL) {
  876. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't build output segment: " << (*i) << " hr = " << std::hex << hr), "");
  877. return hr;
  878. }
  879. pCounterB.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build call to Output " << (*i) << " : " << (unsigned long)(pCounterB.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterB.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterB.Reset();
  880. }
  881. }
  882. if (m_pVideoRenderer) {
  883. hr = VWGraphSegment(m_pVideoRenderer)->Build();
  884. if (FAILED(hr) && hr != E_NOTIMPL) {
  885. TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() Build call to Video Renderer Failed");
  886. return hr;
  887. }
  888. pCounterB.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build call to VideoRenderer: " << (unsigned long)(pCounterB.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterB.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterB.Reset();
  889. }
  890. if (m_pAudioRenderer) {
  891. hr = VWGraphSegment(m_pAudioRenderer)->Build();
  892. if (FAILED(hr) && hr != E_NOTIMPL) {
  893. TRACELM(TRACE_ERROR, "CVidCtl::BuildGraph() Build call to Audio Renderer Failed");
  894. return hr;
  895. }
  896. pCounterB.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build call to Audio Renderer: " << (unsigned long)(pCounterB.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterB.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterB.Reset();
  897. }
  898. pCounterBuilds.Stop();
  899. TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Build Calls to segments " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterBuilds.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterBuilds.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  900. TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() build notifications issued");
  901. pCounterCompose.Reset();
  902. pCounterComp.Reset();
  903. {
  904. VWFeatures::iterator i;
  905. // composing input w/ features
  906. TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() Composing Input w/ Features");
  907. for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) {
  908. int NewCompositionSegmentIdx = -1;
  909. hr = Compose(VWGraphSegment(m_pInput), VWGraphSegment(*i), NewCompositionSegmentIdx);
  910. if (FAILED(hr)) {
  911. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose input segment with feature segment: " << (*i) << " hr = " << std::hex << hr), "");
  912. return hr;
  913. }
  914. }
  915. }
  916. pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Composing Input w/ Features " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
  917. // compose input w/ renderers
  918. TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() Composing Input w/ Video Renderer");
  919. if (m_pVideoRenderer) {
  920. if (m_iCompose_Input_Video == -1) {
  921. hr = Compose(VWGraphSegment(m_pInput), VWGraphSegment(m_pVideoRenderer), m_iCompose_Input_Video);
  922. if (FAILED(hr) /*&& !fDefVideoRenderer*/ ) { // this should fail even if it is the default video renderer
  923. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose input and video. hr = " << std::hex << hr), "");
  924. return hr;
  925. }
  926. }
  927. ASSERT(m_iCompose_Input_Video != -1);
  928. PQCompositionSegment pCS(m_pComposites[m_iCompose_Input_Video]);
  929. }
  930. pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Input w/ Video Renderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
  931. TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() Composing Input w/ Audio Renderer");
  932. if (m_pAudioRenderer) {
  933. if (m_iCompose_Input_Audio == -1) {
  934. hr = Compose(VWGraphSegment(m_pInput), VWGraphSegment(m_pAudioRenderer), m_iCompose_Input_Audio);
  935. if (FAILED(hr) && !fDefAudioRenderer) {
  936. // didn't work and the client explicitly specificed they want an audio renderer
  937. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose input and audio. hr = " << std::hex << hr), "");
  938. return hr;
  939. }
  940. }
  941. }
  942. pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Input w/ Audio Renderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
  943. // compose input w/ outputs
  944. {
  945. TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() Composing Input w/ Outputs");
  946. for (VWOutputDevices::iterator i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) {
  947. int NewCompositionSegmentIdx = -1;
  948. hr = Compose(VWGraphSegment(m_pInput),VWGraphSegment(*i), NewCompositionSegmentIdx);
  949. if (FAILED(hr)) {
  950. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose output segment with input: " << (*i) << " hr = " << std::hex << hr), "");
  951. return hr;
  952. }
  953. }
  954. }
  955. pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() inputs w/ Outputs " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
  956. // composing Features w/ Renderers
  957. TRACELM(TRACE_DETAIL, "CVidCtl::BuildGraph() Composing Features w/ Renderers");
  958. for (VWFeatures::iterator i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) {
  959. int NewCompositionSegmentIdx = -1;
  960. if (m_pVideoRenderer) {
  961. hr = Compose(VWGraphSegment(*i), VWGraphSegment(m_pVideoRenderer), NewCompositionSegmentIdx);
  962. if (FAILED(hr)) {
  963. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose feature segment: " << (*i) << " w/ video renderer. hr = " << std::hex << hr), "");
  964. // note: this is not a fatal error for building. many features won't
  965. // connect to vr(such as data services)
  966. }
  967. }
  968. pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Features w/ Video Renderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
  969. if (m_pAudioRenderer) {
  970. hr = Compose(VWGraphSegment(*i), VWGraphSegment(m_pAudioRenderer), NewCompositionSegmentIdx);
  971. if (FAILED(hr)) {
  972. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose feature segment: " << (*i) << " w/ Audio renderer. hr = " << std::hex << hr), "");
  973. // note: this is not a fatal error for building. many features won't
  974. // connect to ar(such as data services)
  975. }
  976. }
  977. pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Features w/ Audio Renderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
  978. {
  979. for (VWOutputDevices::iterator oi = m_pOutputsInUse.begin(); oi != m_pOutputsInUse.end(); ++oi) {
  980. hr = Compose(VWGraphSegment(*i),VWGraphSegment(*oi), NewCompositionSegmentIdx);
  981. if (FAILED(hr)) {
  982. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() can't compose output segment with feature: " << (*i) << " hr = " << std::hex << hr), "");
  983. return hr;
  984. }
  985. }
  986. }
  987. pCounterComp.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() Features w/ Outputs " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterComp.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterComp.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterComp.Reset();
  988. }
  989. pCounterCompose.Stop();
  990. TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::BuildGraph() compose segments " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterCompose.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterCompose.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  991. RouteStreams();
  992. SetExtents();
  993. m_fGraphDirty = false;
  994. // m_State = STATE_STOP;
  995. //SetMediaEventNotification();
  996. // fire state change at client
  997. PQMediaEventSink mes(m_pGraph);
  998. hr = mes->Notify(EC_BUILT, 0, 0);
  999. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  1000. _ASSERT(m_State == STATE_STOP);
  1001. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::BuildGraph() Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterBuild.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterBuild.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  1002. pCounterBuild.Stop();
  1003. return NOERROR;
  1004. }
  1005. HRESULT CVidCtl::RunGraph(void)
  1006. {
  1007. VIDPERF_FUNC;
  1008. TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph()");
  1009. CPerfCounter pCounterMCRun, pCounterPostRun, pCounterPreRun, pCounterRunGraph, pCounterEachPreRun;
  1010. pCounterRunGraph.Reset();
  1011. if (!m_pInput || !m_pGraph) {
  1012. return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidCtl), CO_E_NOTINITIALIZED);
  1013. }
  1014. BOOL lRes = 0;
  1015. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  1016. HRESULT hr;
  1017. if (m_pGraph.IsPlaying()) {
  1018. TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() already playing");
  1019. return NOERROR;
  1020. }
  1021. else if (m_pGraph.IsPaused() && m_State == STATE_PAUSE) {
  1022. TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() is paused");
  1023. PQMediaControl pmc(m_pGraph);
  1024. if (!pmc) {
  1025. return Error(IDS_NO_MEDIA_CONTROL, __uuidof(IMSVidCtl), IDS_NO_MEDIA_CONTROL);
  1026. }
  1027. hr = pmc->Run();
  1028. if (FAILED(hr)) {
  1029. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Run() hr = " << hexdump(hr)), "");
  1030. return Error(IDS_CANT_START_GRAPH, __uuidof(IMSVidCtl), hr);
  1031. }
  1032. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  1033. return NOERROR;
  1034. }
  1035. else {
  1036. TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() build/prerun");
  1037. // Rebuild the graph if necessary
  1038. if (m_fGraphDirty) {
  1039. TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() building");
  1040. hr = BuildGraph();
  1041. if (FAILED(hr)) {
  1042. return hr;
  1043. }
  1044. }
  1045. OAFilterState graphState = m_pGraph.GetState();
  1046. TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() prerun notifications");
  1047. // Notify all segments graph is about to run
  1048. pCounterPreRun.Reset();
  1049. pCounterEachPreRun.Reset();
  1050. ASSERT(m_pInput);
  1051. hr = VWGraphSegment(m_pInput)->PreRun();
  1052. if (FAILED(hr) && hr != E_NOTIMPL) {
  1053. return hr;
  1054. }
  1055. pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun Input " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset();
  1056. if (m_pVideoRenderer) {
  1057. hr = VWGraphSegment(m_pVideoRenderer)->PreRun();
  1058. if (FAILED(hr) && hr != E_NOTIMPL) {
  1059. return hr;
  1060. }
  1061. }
  1062. pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun VideoRenderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset();
  1063. if (m_pAudioRenderer) {
  1064. hr = VWGraphSegment(m_pAudioRenderer)->PreRun();
  1065. if (FAILED(hr) && hr != E_NOTIMPL) {
  1066. return hr;
  1067. }
  1068. }
  1069. pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun AudioRenderer " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset();
  1070. {
  1071. VWOutputDevices::iterator i;
  1072. for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) {
  1073. hr = VWGraphSegment(*i)->PreRun();
  1074. if (FAILED(hr) && hr != E_NOTIMPL) {
  1075. return hr;
  1076. }
  1077. }
  1078. }
  1079. pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun Output " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset();
  1080. {
  1081. VWFeatures::iterator i;
  1082. for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) {
  1083. hr = VWGraphSegment(*i)->PreRun();
  1084. if (FAILED(hr) && hr != E_NOTIMPL) {
  1085. return hr;
  1086. }
  1087. }
  1088. }
  1089. pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun Features " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset();
  1090. {
  1091. VWSegmentList::iterator i;
  1092. for(i = m_pComposites.begin(); i != m_pComposites.end(); ++i){
  1093. hr = VWGraphSegment(*i)->PreRun();
  1094. if (FAILED(hr) && hr != E_NOTIMPL) {
  1095. return hr;
  1096. }
  1097. }
  1098. }
  1099. pCounterEachPreRun.Stop(); TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun Composites " << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterEachPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterEachPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), ""); pCounterEachPreRun.Reset();
  1100. // Make sure graph state hasn't changed
  1101. ASSERT(graphState == m_pGraph.GetState());
  1102. Refresh(); // make sure we're in place active etc.
  1103. pCounterPreRun.Stop();
  1104. TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() PreRun Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterPreRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterPreRun.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  1105. // Start the graph running
  1106. PQMediaControl pmc(m_pGraph);
  1107. if (!pmc) {
  1108. return Error(IDS_NO_MEDIA_CONTROL, __uuidof(IMSVidCtl), IDS_NO_MEDIA_CONTROL);
  1109. }
  1110. pCounterMCRun.Reset();
  1111. hr = pmc->Run();
  1112. pCounterMCRun.Stop();
  1113. #if 0
  1114. if(FAILED(hr)){
  1115. hr = pmc->Run();
  1116. }
  1117. #endif
  1118. TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() MediaControl Run Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterMCRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterMCRun.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  1119. if (FAILED(hr)) {
  1120. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Run() hr = " << hexdump(hr)), "");
  1121. return Error(IDS_CANT_START_GRAPH, __uuidof(IMSVidCtl), hr);
  1122. }
  1123. }
  1124. TRACELM(TRACE_DETAIL, "CVidCtl::RunGraph() postrun");
  1125. // Notify all segments graph is running
  1126. pCounterPostRun.Reset();
  1127. ASSERT(m_pInput);
  1128. hr = VWGraphSegment(m_pInput)->PostRun();
  1129. if (FAILED(hr) && hr != E_NOTIMPL) {
  1130. return hr;
  1131. }
  1132. if (m_pVideoRenderer) {
  1133. hr = VWGraphSegment(m_pVideoRenderer)->PostRun();
  1134. if (FAILED(hr) && hr != E_NOTIMPL) {
  1135. return hr;
  1136. }
  1137. }
  1138. if (m_pAudioRenderer) {
  1139. hr = VWGraphSegment(m_pAudioRenderer)->PostRun();
  1140. if (FAILED(hr) && hr != E_NOTIMPL) {
  1141. return hr;
  1142. }
  1143. }
  1144. {
  1145. VWOutputDevices::iterator i;
  1146. for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) {
  1147. hr = VWGraphSegment(*i)->PostRun();
  1148. if (FAILED(hr) && hr != E_NOTIMPL) {
  1149. return hr;
  1150. }
  1151. }
  1152. }
  1153. {
  1154. VWFeatures::iterator i;
  1155. for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) {
  1156. hr = VWGraphSegment(*i)->PostRun();
  1157. if (FAILED(hr) && hr != E_NOTIMPL) {
  1158. return hr;
  1159. }
  1160. }
  1161. }
  1162. {
  1163. VWSegmentList::iterator i;
  1164. for (i = m_pComposites.begin(); i != m_pComposites.end(); ++i){
  1165. hr = VWGraphSegment(*i)->PostRun();
  1166. if (FAILED(hr) && hr != E_NOTIMPL) {
  1167. return hr;
  1168. }
  1169. }
  1170. }
  1171. Refresh();
  1172. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  1173. pCounterPostRun.Stop();
  1174. pCounterRunGraph.Stop();
  1175. TRACELSM(TRACE_ERROR, (dbgDump << " CVidCtl::RunGraph() Post Run Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterPostRun.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterPostRun.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  1176. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::RunGraph() RunGraph Total Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterRunGraph.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterRunGraph.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  1177. return NOERROR;
  1178. }
  1179. HRESULT CVidCtl::DecomposeAll() {
  1180. CPerfCounter pCounterDecompose;
  1181. pCounterDecompose.Reset();
  1182. HRESULT hr;
  1183. if (!m_pGraph) {
  1184. return NOERROR;
  1185. }
  1186. BOOL lRes = 0;
  1187. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  1188. if (m_pGraph.GetState() != State_Stopped) {
  1189. hr = Stop();
  1190. if (FAILED(hr)) {
  1191. return Error(IDS_CANT_DECOMPOSE_GRAPH, __uuidof(IMSVidCtl), hr);
  1192. }
  1193. }
  1194. {
  1195. // decompose all the composites
  1196. VWSegmentList::iterator i;
  1197. for (i = m_pComposites.begin(); i != m_pComposites.end(); ++i) {
  1198. hr = (*i)->put_Container(NULL);
  1199. ASSERT(SUCCEEDED(hr));
  1200. }
  1201. m_pComposites.clear();
  1202. }
  1203. // Notify everyone to decompose
  1204. if(!!m_pInput){
  1205. hr = VWGraphSegment(m_pInput)->Decompose();
  1206. if (FAILED(hr) && hr != E_NOTIMPL) {
  1207. return hr;
  1208. }
  1209. }
  1210. {
  1211. // decompose all the features
  1212. VWFeatures::iterator i;
  1213. for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) {
  1214. // notify them that we're decomposing
  1215. hr = VWGraphSegment(*i)->Decompose();
  1216. if (FAILED(hr) && hr != E_NOTIMPL) {
  1217. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::DecomposeAll() can't decompose feature segment: " << (*i) << " hr = " << std::hex << hr), "");
  1218. return hr;
  1219. }
  1220. }
  1221. }
  1222. {
  1223. // decompose all the outputs
  1224. VWOutputDevices::iterator i;
  1225. for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) {
  1226. // notify them that we're decomposing
  1227. hr = VWGraphSegment(*i)->Decompose();
  1228. if (FAILED(hr) && hr != E_NOTIMPL) {
  1229. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::DecomposeAll() can't decompose output segment: " << (*i) << " hr = " << std::hex << hr), "");
  1230. return hr;
  1231. }
  1232. }
  1233. }
  1234. if (!!m_pVideoRenderer) {
  1235. hr = VWGraphSegment(m_pVideoRenderer)->Decompose();
  1236. if (FAILED(hr) && hr != E_NOTIMPL) {
  1237. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::DecomposeAll() can't decompose videorenderer segment: " << " hr = " << std::hex << hr), "");
  1238. return hr;
  1239. }
  1240. }
  1241. if (!!m_pAudioRenderer) {
  1242. hr = VWGraphSegment(m_pAudioRenderer)->Decompose();
  1243. if (FAILED(hr) && hr != E_NOTIMPL) {
  1244. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::DecomposeAll() can't decompose audiorenderer segment: " << " hr = " << std::hex << hr), "");
  1245. return hr;
  1246. }
  1247. }
  1248. TRACELM(TRACE_DETAIL, "CVidCtl::Decomose() decompose notifications issued");
  1249. m_iCompose_Input_Video = -1;
  1250. m_iCompose_Input_Audio = -1;
  1251. m_fGraphDirty = true;
  1252. PQMediaEventSink mes(m_pGraph);
  1253. hr = mes->Notify(EC_UNBUILT, 0, 0);
  1254. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  1255. _ASSERT(m_State == STATE_UNBUILT);
  1256. pCounterDecompose.Stop();
  1257. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::DecomposeAll() Death Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterDecompose.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterDecompose.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  1258. return NOERROR;
  1259. }
  1260. HRESULT CVidCtl::DecomposeSegment(VWGraphSegment& pSegment) {
  1261. if (m_pGraph.GetState() != State_Stopped) {
  1262. return HRESULT_FROM_WIN32(ERROR_INVALID_STATE);
  1263. }
  1264. return DecomposeAll();
  1265. }
  1266. // interface functions
  1267. STDMETHODIMP CVidCtl::get_InputsAvailable(BSTR CategoryGuid, IMSVidInputDevices * * pVal)
  1268. {
  1269. try {
  1270. GUID2 catguid(CategoryGuid);
  1271. return get__InputsAvailable(&catguid, pVal);
  1272. } catch(ComException &e) {
  1273. return e;
  1274. } catch(...) {
  1275. return E_UNEXPECTED;
  1276. }
  1277. }
  1278. STDMETHODIMP CVidCtl::get__InputsAvailable(LPCGUID CategoryGuid, IMSVidInputDevices * * pVal)
  1279. {
  1280. if (pVal == NULL)
  1281. return E_POINTER;
  1282. try {
  1283. if (!m_fInit) {
  1284. Init();
  1285. }
  1286. } catch(ComException &e) {
  1287. return e;
  1288. } catch(...) {
  1289. return E_UNEXPECTED;
  1290. }
  1291. try {
  1292. *pVal = NULL;
  1293. } catch(...) {
  1294. return E_POINTER;
  1295. }
  1296. try {
  1297. CInputDevices *p = NULL;
  1298. if(m_InputsCatGuid == CategoryGuid){
  1299. p = static_cast<CInputDevices *>(m_pInputs.p);
  1300. }
  1301. if (!p || !p->Valid) {
  1302. HRESULT hr = GetInputs(GUID2(CategoryGuid), m_pInputs);
  1303. if (FAILED(hr)) {
  1304. return hr;
  1305. }
  1306. m_InputsCatGuid = CategoryGuid;
  1307. }
  1308. CInputDevices *d = new CInputDevices(m_pInputs);
  1309. *pVal = PQInputDevices(d).Detach();
  1310. } catch(ComException &e) {
  1311. return e;
  1312. } catch(...) {
  1313. return E_UNEXPECTED;
  1314. }
  1315. return NOERROR;
  1316. }
  1317. STDMETHODIMP CVidCtl::get_OutputsAvailable(BSTR CategoryGuid, IMSVidOutputDevices * * pVal)
  1318. {
  1319. try {
  1320. GUID2 catguid(CategoryGuid);
  1321. return get__OutputsAvailable(&catguid, pVal);
  1322. } catch(ComException &e) {
  1323. return e;
  1324. } catch(...) {
  1325. return E_UNEXPECTED;
  1326. }
  1327. }
  1328. STDMETHODIMP CVidCtl::get__OutputsAvailable(LPCGUID CategoryGuid, IMSVidOutputDevices * * pVal)
  1329. {
  1330. if (pVal == NULL)
  1331. return E_POINTER;
  1332. try {
  1333. if (!m_fInit) {
  1334. Init();
  1335. }
  1336. } catch(ComException &e) {
  1337. return e;
  1338. } catch(...) {
  1339. return Error(IDS_CANT_INIT, __uuidof(IMSVidCtl), IDS_CANT_INIT);
  1340. }
  1341. try {
  1342. *pVal = NULL;
  1343. } catch(...) {
  1344. return E_POINTER;
  1345. }
  1346. try {
  1347. COutputDevices *p = static_cast<COutputDevices *>(m_pOutputs.p);
  1348. if (!p || !p->Valid) {
  1349. HRESULT hr = GetOutputs(GUID2(CategoryGuid));
  1350. if (FAILED(hr)) {
  1351. return hr;
  1352. }
  1353. }
  1354. COutputDevices *d = new COutputDevices(m_pOutputs);
  1355. *pVal = PQOutputDevices(d).Detach();
  1356. } catch(ComException &e) {
  1357. return e;
  1358. } catch(...) {
  1359. return E_UNEXPECTED;
  1360. }
  1361. return NOERROR;
  1362. }
  1363. STDMETHODIMP CVidCtl::get_VideoRenderersAvailable(IMSVidVideoRendererDevices * * pVal)
  1364. {
  1365. if (pVal == NULL)
  1366. return E_POINTER;
  1367. try {
  1368. if (!m_fInit) {
  1369. Init();
  1370. }
  1371. } catch(ComException &e) {
  1372. return e;
  1373. } catch(...) {
  1374. return Error(IDS_CANT_INIT, __uuidof(IMSVidCtl), IDS_CANT_INIT);
  1375. }
  1376. try {
  1377. *pVal = NULL;
  1378. } catch(...) {
  1379. return E_POINTER;
  1380. }
  1381. try {
  1382. CVideoRendererDevices *p = static_cast<CVideoRendererDevices *>(m_pVRs.p);
  1383. if (!p || !p->Valid) {
  1384. HRESULT hr = GetVideoRenderers();
  1385. if (FAILED(hr)) {
  1386. return hr;
  1387. }
  1388. }
  1389. CVideoRendererDevices *d = new CVideoRendererDevices(m_pVRs);
  1390. if (!d) {
  1391. return E_OUTOFMEMORY;
  1392. }
  1393. *pVal = PQVideoRendererDevices(d).Detach();
  1394. if (!*pVal) {
  1395. return E_UNEXPECTED;
  1396. }
  1397. } catch(ComException &e) {
  1398. return e;
  1399. } catch(...) {
  1400. return E_UNEXPECTED;
  1401. }
  1402. return NOERROR;
  1403. }
  1404. STDMETHODIMP CVidCtl::get_AudioRenderersAvailable(IMSVidAudioRendererDevices * * pVal)
  1405. {
  1406. if (pVal == NULL)
  1407. return E_POINTER;
  1408. try {
  1409. if (!m_fInit) {
  1410. Init();
  1411. }
  1412. } catch(ComException &e) {
  1413. return e;
  1414. } catch(...) {
  1415. return Error(IDS_CANT_INIT, __uuidof(IMSVidCtl), IDS_CANT_INIT);
  1416. }
  1417. try {
  1418. *pVal = NULL;
  1419. } catch(...) {
  1420. return E_POINTER;
  1421. }
  1422. try {
  1423. CAudioRendererDevices *p = static_cast<CAudioRendererDevices *>(m_pARs.p);
  1424. if (!p || !p->Valid) {
  1425. HRESULT hr = GetAudioRenderers();
  1426. if (FAILED(hr)) {
  1427. return hr;
  1428. }
  1429. }
  1430. CAudioRendererDevices *d = new CAudioRendererDevices(m_pARs);
  1431. if (!d) {
  1432. return E_OUTOFMEMORY;
  1433. }
  1434. *pVal = PQAudioRendererDevices(d).Detach();
  1435. if (!*pVal) {
  1436. return E_UNEXPECTED;
  1437. }
  1438. return NOERROR;
  1439. } catch(ComException &e) {
  1440. return e;
  1441. } catch(...) {
  1442. return E_UNEXPECTED;
  1443. }
  1444. }
  1445. STDMETHODIMP CVidCtl::get_FeaturesAvailable(IMSVidFeatures * * pVal)
  1446. {
  1447. if (pVal == NULL)
  1448. return E_POINTER;
  1449. try {
  1450. if (!m_fInit) {
  1451. Init();
  1452. }
  1453. } catch(ComException &e) {
  1454. return e;
  1455. } catch(...) {
  1456. return Error(IDS_CANT_INIT, __uuidof(IMSVidCtl), IDS_CANT_INIT);
  1457. }
  1458. try {
  1459. *pVal = NULL;
  1460. } catch(...) {
  1461. return E_POINTER;
  1462. }
  1463. try {
  1464. CFeatures *p = static_cast<CFeatures *>(m_pFeatures.p);
  1465. if (!p || !p->Valid) {
  1466. HRESULT hr = GetFeatures();
  1467. if (FAILED(hr)) {
  1468. return hr;
  1469. }
  1470. }
  1471. CFeatures *d = new CFeatures(m_pFeatures);
  1472. *pVal = PQFeatures(d).Detach();
  1473. return NOERROR;
  1474. } catch(ComException &e) {
  1475. return e;
  1476. } catch(...) {
  1477. return E_UNEXPECTED;
  1478. }
  1479. }
  1480. HRESULT CVidCtl::Pause(void)
  1481. {
  1482. VIDPERF_FUNC;
  1483. try {
  1484. if (!m_pInput || !m_pGraph) {
  1485. return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidCtl), IDS_OBJ_NO_INIT);
  1486. }
  1487. BOOL lRes = 0;
  1488. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  1489. if (m_pGraph.IsPaused()) {
  1490. return NOERROR;
  1491. }
  1492. HRESULT hr = S_OK;
  1493. if (m_fGraphDirty) {
  1494. hr = BuildGraph();
  1495. }
  1496. if (FAILED(hr)) {
  1497. return hr;
  1498. }
  1499. PQMediaControl pmc(m_pGraph);
  1500. if (!pmc) {
  1501. return Error(IDS_NO_MEDIA_CONTROL, __uuidof(IMSVidCtl), IDS_NO_MEDIA_CONTROL);
  1502. }
  1503. hr = pmc->Pause();
  1504. if (FAILED(hr)) {
  1505. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Pause() hr = " << std::hex << hr), "");
  1506. return Error(IDS_CANT_PAUSE_GRAPH, __uuidof(IMSVidCtl), hr);
  1507. }
  1508. // This is to force the pause event to get thrown up to apps.
  1509. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  1510. return NOERROR;
  1511. } catch(ComException &e) {
  1512. return e;
  1513. } catch(...) {
  1514. return E_UNEXPECTED;
  1515. }
  1516. }
  1517. HRESULT CVidCtl::Stop(void)
  1518. {
  1519. VIDPERF_FUNC;
  1520. CPerfCounter pCounterStop;
  1521. pCounterStop.Reset();
  1522. try {
  1523. TRACELM(TRACE_DETAIL, "CVidCtl::Stop()");
  1524. if (!m_pInput || !m_pGraph) {
  1525. return Error(IDS_OBJ_NO_INIT, __uuidof(IMSVidCtl), CO_E_NOTINITIALIZED);
  1526. }
  1527. BOOL lRes = 0;
  1528. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  1529. HRESULT hr;
  1530. if (!m_pGraph.IsStopped()) {
  1531. OAFilterState graphState = m_pGraph.GetState();
  1532. // Notify all segments graph is about to stop
  1533. ASSERT(m_pInput);
  1534. hr = VWGraphSegment(m_pInput)->PreStop();
  1535. if (FAILED(hr) && hr != E_NOTIMPL) {
  1536. return hr;
  1537. }
  1538. if (!!m_pVideoRenderer) {
  1539. hr = VWGraphSegment(m_pVideoRenderer)->PreStop();
  1540. if (FAILED(hr) && hr != E_NOTIMPL) {
  1541. return hr;
  1542. }
  1543. }
  1544. if (!!m_pAudioRenderer) {
  1545. hr = VWGraphSegment(m_pAudioRenderer)->PreStop();
  1546. if (FAILED(hr) && hr != E_NOTIMPL) {
  1547. return hr;
  1548. }
  1549. }
  1550. {
  1551. VWOutputDevices::iterator i;
  1552. for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) {
  1553. hr = VWGraphSegment(*i)->PreStop();
  1554. if (FAILED(hr) && hr != E_NOTIMPL) {
  1555. return hr;
  1556. }
  1557. }
  1558. }
  1559. {
  1560. VWFeatures::iterator i;
  1561. for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) {
  1562. hr = VWGraphSegment(*i)->PreStop();
  1563. if (FAILED(hr) && hr != E_NOTIMPL) {
  1564. return hr;
  1565. }
  1566. }
  1567. }
  1568. {
  1569. VWSegmentList::iterator i;
  1570. for(i = m_pComposites.begin(); i != m_pComposites.end(); ++i){
  1571. hr = VWGraphSegment(*i)->PreStop();
  1572. if (FAILED(hr) && hr != E_NOTIMPL) {
  1573. return hr;
  1574. }
  1575. }
  1576. }
  1577. if (!!m_pVideoRenderer) {
  1578. m_pVideoRenderer->put_Visible(false);
  1579. m_pVideoRenderer->put_Owner(0);
  1580. }
  1581. // Stop the graph
  1582. PQMediaControl pmc(m_pGraph);
  1583. if (!pmc) {
  1584. return Error(IDS_NO_MEDIA_CONTROL, __uuidof(IMSVidCtl), IDS_NO_MEDIA_CONTROL);
  1585. }
  1586. hr = pmc->Stop();
  1587. if (FAILED(hr)) {
  1588. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Stop() hr = " << std::hex << hr), "");
  1589. return Error(IDS_CANT_PAUSE_GRAPH, __uuidof(IMSVidCtl), hr);
  1590. }
  1591. }
  1592. // Notify all segments graph is stopped
  1593. ASSERT(m_pInput);
  1594. hr = VWGraphSegment(m_pInput)->PostStop();
  1595. if (FAILED(hr) && hr != E_NOTIMPL) {
  1596. return hr;
  1597. }
  1598. if (!!m_pVideoRenderer) {
  1599. hr = VWGraphSegment(m_pVideoRenderer)->PostStop();
  1600. if (FAILED(hr) && hr != E_NOTIMPL) {
  1601. return hr;
  1602. }
  1603. }
  1604. if (!!m_pAudioRenderer) {
  1605. hr = VWGraphSegment(m_pAudioRenderer)->PostStop();
  1606. if (FAILED(hr) && hr != E_NOTIMPL) {
  1607. return hr;
  1608. }
  1609. }
  1610. {
  1611. VWOutputDevices::iterator i;
  1612. for (i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) {
  1613. hr = VWGraphSegment(*i)->PostStop();
  1614. if (FAILED(hr) && hr != E_NOTIMPL) {
  1615. return hr;
  1616. }
  1617. }
  1618. }
  1619. {
  1620. VWFeatures::iterator i;
  1621. for (i = m_pFeaturesInUse.begin(); i != m_pFeaturesInUse.end(); ++i) {
  1622. hr = VWGraphSegment(*i)->PostStop();
  1623. if (FAILED(hr) && hr != E_NOTIMPL) {
  1624. return hr;
  1625. }
  1626. }
  1627. }
  1628. {
  1629. VWSegmentList::iterator i;
  1630. for(i = m_pComposites.begin(); i != m_pComposites.end(); ++i){
  1631. hr = VWGraphSegment(*i)->PostStop();
  1632. if (FAILED(hr) && hr != E_NOTIMPL) {
  1633. return hr;
  1634. }
  1635. }
  1636. }
  1637. FireViewChange(); // force refresh to repaint background immediately(black)
  1638. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  1639. pCounterStop.Stop();
  1640. TRACELSM(TRACE_ERROR, (dbgDump << "CVidCtl::Stop() Stop Time" << (PQGraphSegment(m_pInput)) << ": " << (unsigned long)(pCounterStop.GetLastTime() / _100NS_IN_MS) << "." << (unsigned long)(pCounterStop.GetLastTime() % _100NS_IN_MS) << " ms"), "");
  1641. return NOERROR;
  1642. } catch(ComException &e) {
  1643. return e;
  1644. } catch(...) {
  1645. return E_UNEXPECTED;
  1646. }
  1647. }
  1648. // Setup events handling
  1649. // If we have a window, then send notification messages to it
  1650. // If we are windowless, then set up a timer to process the messages
  1651. void CVidCtl::SetMediaEventNotification() {
  1652. SetTimer();
  1653. if (!m_fNotificationSet) {
  1654. // If graph is built and notification hasn't been set
  1655. // then set it here
  1656. if (m_pGraph) {
  1657. // Setup notification window for WM_MEDIAEVENT
  1658. HRESULT hr = m_pGraph.SetMediaEventNotificationWindow(m_pTopWin->m_hWnd, WM_MEDIAEVENT, 0);
  1659. if (FAILED(hr)) {
  1660. THROWCOM(E_UNEXPECTED);
  1661. }
  1662. m_fNotificationSet = true;
  1663. }
  1664. }
  1665. return;
  1666. }
  1667. // actually submit changes to VR
  1668. bool CVidCtl::RefreshVRSurfaceState() {
  1669. TRACELM(TRACE_PAINT, "CVidCtl::RefreshVRSurfaceState()");
  1670. if (m_pVideoRenderer) {
  1671. HWND hOwner(m_CurrentSurface.Owner());
  1672. HRESULT hr = m_pVideoRenderer->put_Owner(hOwner);
  1673. if (FAILED(hr) || hOwner == INVALID_HWND || !::IsWindow(hOwner)) {
  1674. TRACELM(TRACE_PAINT, "CVidCtl::RefreshVRSurfaceState() unowned, vis false");
  1675. hr = m_pVideoRenderer->put_Visible(false);
  1676. if (FAILED(hr)) {
  1677. return false;
  1678. }
  1679. } else {
  1680. hr = m_pVideoRenderer->put_Destination(m_CurrentSurface);
  1681. if (FAILED(hr)) {
  1682. return false;
  1683. }
  1684. hr = m_pVideoRenderer->put_Visible(m_CurrentSurface.IsVisible() ? VARIANT_TRUE : VARIANT_FALSE);
  1685. if (FAILED(hr) && hr == E_FAIL) {
  1686. return false;
  1687. }
  1688. }
  1689. m_CurrentSurface.Dirty(false);
  1690. }
  1691. return true;
  1692. }
  1693. HRESULT CVidCtl::Refresh() {
  1694. try {
  1695. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::Refresh() owner = " << m_CurrentSurface.Owner()), "");
  1696. BOOL temp;
  1697. if (!m_bInPlaceActive) {
  1698. HRESULT hr = InPlaceActivate(OLEIVERB_INPLACEACTIVATE, NULL);
  1699. if (FAILED(hr)) {
  1700. return hr;
  1701. }
  1702. }
  1703. CheckMouseCursor(temp);
  1704. ComputeDisplaySize();
  1705. SetExtents();
  1706. if (m_pVideoRenderer) {
  1707. RefreshVRSurfaceState();
  1708. m_pVideoRenderer->Refresh();
  1709. }
  1710. FireViewChange();
  1711. return NOERROR;
  1712. } catch (...) {
  1713. return E_UNEXPECTED;
  1714. }
  1715. }
  1716. #if 0
  1717. // old flawed OnDraw saved for reference
  1718. HRESULT CVidCtl::OnDraw(ATL_DRAWINFO& di)
  1719. {
  1720. try {
  1721. SetTimer();
  1722. //SetMediaEventNotification();
  1723. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" );
  1724. bool fOverlay = false;
  1725. if (m_pVideoRenderer) {
  1726. VARIANT_BOOL fo = VARIANT_FALSE;
  1727. HRESULT hr = m_pVideoRenderer->get_UseOverlay(&fo);
  1728. if (FAILED(hr)) {
  1729. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't get useoverlay flag");
  1730. }
  1731. fOverlay = !!fo;
  1732. hr = m_pVideoRenderer->put_ColorKey(m_clrColorKey);
  1733. if (FAILED(hr)) {
  1734. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set color key on vr");
  1735. }
  1736. #ifdef 0
  1737. hr = m_pVideoRenderer->put_BorderColor(0x0000ff);
  1738. #else
  1739. hr = m_pVideoRenderer->put_BorderColor(m_clrBackColor);
  1740. #endif
  1741. if (FAILED(hr)) {
  1742. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set border color on vr");
  1743. }
  1744. hr = m_pVideoRenderer->put_MaintainAspectRatio(m_fMaintainAspectRatio);
  1745. if (FAILED(hr)) {
  1746. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set fMaintainAspectRatio on vr");
  1747. }
  1748. }
  1749. // undone: if we're straddling a monitor edge in the multimon case, then we treat the smaller
  1750. // portion as part of the border/background
  1751. // undone: if we're on a monitor that our input device cannot reach(video port case) then we need
  1752. // to paint the background color
  1753. // we only force overlay and tell vmr not to paint color key if we're windowless
  1754. // this allows us to put the color key in the correct z-order amongst a stack of
  1755. // multiple windowless controls. when we do this we also need to paint the letter box
  1756. // border otherwise it won't z-order right since it isn't colorkeyed.
  1757. // if we're windowed then gdi, ddraw, and the vmr deal
  1758. // with the z-order correctly so we let the vmr do the color key and border for us and we
  1759. // fill rect the bg color
  1760. // so, we have three cases
  1761. // 1: paint the whole rect the color key color
  1762. // 2: paint the whole rect the bg color
  1763. // 3: paint the video portion colorkey and the borders bg
  1764. if (di.dwDrawAspect != DVASPECT_CONTENT) {
  1765. return DV_E_DVASPECT;
  1766. }
  1767. if (!di.hdcDraw) {
  1768. return NOERROR;
  1769. }
  1770. CDC pdc(di.hdcDraw);
  1771. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() di.prcBounds " << *(reinterpret_cast<LPCRECT>(di.prcBounds))), "");
  1772. CRect rcBounds(reinterpret_cast<LPCRECT>(di.prcBounds));
  1773. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rcBounds = " << rcBounds << " w = " << rcBounds.Width() << " h = " << rcBounds.Height()), "");
  1774. long lBGColor = m_clrBackColor;
  1775. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() wndless = " << m_bWndLess << " active = " << m_bInPlaceActive << " !stopped = " << (m_pGraph ? !m_pGraph.IsStopped() : 0)), "");
  1776. if (m_bNegotiatedWnd) {
  1777. if (m_bWndLess) {
  1778. HWND hwndParent;
  1779. if (m_spInPlaceSite && m_spInPlaceSite->GetWindow(&hwndParent) == S_OK) {
  1780. m_CurrentSurface.Owner(hwndParent);
  1781. }
  1782. CheckSurfaceStateChanged(CScalingRect(m_rcPos));
  1783. } else {
  1784. m_CurrentSurface.Owner(m_hWndCD);
  1785. CScalingRect r(::GetDesktopWindow());
  1786. if (!::GetWindowRect(m_hWndCD, &r)) {
  1787. return HRESULT_FROM_WIN32(GetLastError());
  1788. }
  1789. CheckSurfaceStateChanged(r);
  1790. }
  1791. } else {
  1792. m_CurrentSurface.Site(PQSiteWindowless(m_spInPlaceSite));
  1793. CheckSurfaceStateChanged(CScalingRect(m_rcPos));
  1794. }
  1795. if (m_bInPlaceActive && fOverlay) {
  1796. if (m_pGraph && !m_pGraph.IsStopped()) {
  1797. TRACELSM(TRACE_PAINT, (dbgDump << "CVidCtl::OnDraw() m_rcPos = " << m_rcPos << " m_cursurf = " << m_CurrentSurface), "");
  1798. TRACELSM(TRACE_PAINT, (dbgDump << "CVidCtl::OnDraw() m_cursurf rounded = " << m_CurrentSurface), "");
  1799. // get the color from the current video renderer because we always notify it
  1800. // if we've received a colorkey change but it may not notify us if one went directly to
  1801. // the vr object.
  1802. if (m_fMaintainAspectRatio) {
  1803. AspectRatio src(SourceAspect());
  1804. AspectRatio surf(m_rcPos);
  1805. TRACELSM(TRACE_PAINT, (dbgDump << "CVidCtl::OnDraw() Checking AR() src = " << src << " surf = " << surf), "");
  1806. if (src != surf) {
  1807. CBrush hb;
  1808. HBRUSH hbrc = hb.CreateSolidBrush(m_clrBackColor);
  1809. if (!hbrc) {
  1810. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't create brush for letterbox");
  1811. THROWCOM(E_UNEXPECTED);
  1812. }
  1813. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rcBounds at border paint = " << rcBounds << " w = " << rcBounds.Width() << " h = " << rcBounds.Height()), "");
  1814. if (!pdc.FillRect(&rcBounds, hb)) {
  1815. DWORD er = GetLastError();
  1816. TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't fill top/left letterbox rect er = " << er), "");
  1817. return HRESULT_FROM_WIN32(er);
  1818. }
  1819. }
  1820. }
  1821. lBGColor = m_clrColorKey;
  1822. CRect SurfDP(m_CurrentSurface);
  1823. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() SurfDP before LPtoDP = " << SurfDP << " w = " << SurfDP.Width() << " h = " << SurfDP.Height()), "");
  1824. if (di.hicTargetDev == di.hdcDraw) {
  1825. // ATL has a weird bug in the windowless case where they reset the transform
  1826. // origins of hicTargetDev inadvertently. this happens because in the windowless
  1827. // non metafile case ATLCreateTargetDC returns the existing hdcDraw instead
  1828. // of creatin a new dc so after that in CComControlBase::OnDrawAdvanced
  1829. // when the save hdcDraw and reset the origins, they change hicTargetDev
  1830. // too(since they're the same ptr).
  1831. // we undo this so that we can map in the same space and then put it back
  1832. // the way it was just to be safe
  1833. // currently, this works because in the non-metafile case atl always
  1834. // does a prior SaveDC everywhere they call the derived control's OnDraw
  1835. // since we already reject non-metafile above(it doesn't make sense for video)
  1836. // we can just check for pointer equality and temporarily undo their
  1837. // origin change and then put it back the way it was. if atl ever calls
  1838. // our ondraw for non-metafiles anywhere without doing a savedc then this
  1839. // will break bigtime.
  1840. ::RestoreDC(di.hdcDraw, -1);
  1841. }
  1842. if (!::LPtoDP(di.hicTargetDev, reinterpret_cast<LPPOINT>(&SurfDP), 2)) {
  1843. DWORD er = GetLastError();
  1844. TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't LPToDP current surf er = " << er), "");
  1845. return HRESULT_FROM_WIN32(er);
  1846. }
  1847. if (di.hicTargetDev == di.hdcDraw) {
  1848. // restore the window state as per the above comment block
  1849. SaveDC(di.hdcDraw);
  1850. SetMapMode(di.hdcDraw, MM_TEXT);
  1851. SetWindowOrgEx(di.hdcDraw, 0, 0, NULL);
  1852. SetViewportOrgEx(di.hdcDraw, 0, 0, NULL);
  1853. }
  1854. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() SurfDP after LPtoDP = " << SurfDP << " w = " << SurfDP.Width() << " h = " << SurfDP.Height()), "");
  1855. #if 1
  1856. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rcBounds prior to boundary intersect = " << rcBounds << " w = " << rcBounds.Width() << " h = " << rcBounds.Height()), "");
  1857. rcBounds.IntersectRect(&SurfDP);
  1858. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rcBounds after to boundary intersect = " << rcBounds << " w = " << rcBounds.Width() << " h = " << rcBounds.Height()), "");
  1859. #endif
  1860. }
  1861. } else {
  1862. if (m_pGraph && !m_pGraph.IsStopped()) {
  1863. lBGColor = m_clrColorKey;
  1864. if (m_pVideoRenderer) {
  1865. m_pVideoRenderer->RePaint(di.hdcDraw);
  1866. pdc = NULL; // don't delete the DC, it isn't ours
  1867. return S_OK;
  1868. }
  1869. }
  1870. }
  1871. CBrush hb;
  1872. HBRUSH hbrc = hb.CreateSolidBrush(lBGColor);
  1873. if (!hbrc) {
  1874. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't create brush for mainrect");
  1875. THROWCOM(E_UNEXPECTED);
  1876. }
  1877. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rcBounds at main paint = " << rcBounds << " w = " << rcBounds.Width() << " h = " << rcBounds.Height()), "");
  1878. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() bkcolor = " << hexdump(lBGColor)), "");
  1879. if (!pdc.FillRect(&rcBounds, hb)) {
  1880. DWORD er = GetLastError();
  1881. TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't fill main video rect er = " << er), "");
  1882. return HRESULT_FROM_WIN32(er);
  1883. }
  1884. pdc = NULL; // don't delete the DC, it isn't ours
  1885. return S_OK;
  1886. } catch(...) {
  1887. return E_UNEXPECTED;
  1888. }
  1889. }
  1890. #else
  1891. HRESULT CVidCtl::OnDrawAdvanced(ATL_DRAWINFO& di)
  1892. {
  1893. try {
  1894. SetTimer();
  1895. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" );
  1896. bool fOverlay = false;
  1897. if (m_pVideoRenderer) {
  1898. VARIANT_BOOL fo = VARIANT_FALSE;
  1899. HRESULT hr = m_pVideoRenderer->get_UseOverlay(&fo);
  1900. if (FAILED(hr)) {
  1901. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't get useoverlay flag");
  1902. }
  1903. fOverlay = !!fo;
  1904. hr = m_pVideoRenderer->put_ColorKey(m_clrColorKey);
  1905. if (FAILED(hr)) {
  1906. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set color key on vr");
  1907. }
  1908. #if 0
  1909. hr = m_pVideoRenderer->put_BorderColor(0x0000ff);
  1910. #else
  1911. hr = m_pVideoRenderer->put_BorderColor(m_clrBackColor);
  1912. #endif
  1913. if (FAILED(hr)) {
  1914. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set border color on vr");
  1915. }
  1916. hr = m_pVideoRenderer->put_MaintainAspectRatio(m_fMaintainAspectRatio);
  1917. if (FAILED(hr)) {
  1918. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't set fMaintainAspectRatio on vr");
  1919. }
  1920. }
  1921. if (di.dwDrawAspect != DVASPECT_CONTENT) {
  1922. return DV_E_DVASPECT;
  1923. }
  1924. if (!di.hdcDraw) {
  1925. return NOERROR;
  1926. }
  1927. // we only default to force overlay if we're windowless, but overlay is an independently controllable
  1928. // boolean property that can be overriden. based on this, if we're in useoverlay == true mode
  1929. // then we tell vmr not to paint color key. if we don't have an rgb overlay available that vmr
  1930. // event causes useoverlay to go false.
  1931. // when we have the overlay, this allows us to put the color key in the correct z-order
  1932. // amongst a stack of multiple windowless controls such as html page elements in IE.
  1933. // when we do this we also need to paint the letter box
  1934. // border otherwise it won't z-order right since it isn't colorkeyed.
  1935. // if we're windowed then gdi, ddraw, and the vmr deal
  1936. // with the z-order correctly so we let the vmr do the color key and border for us and we
  1937. // fill rect the bg color
  1938. // so, we have three cases
  1939. // 1: paint the whole rect the color key color
  1940. // 2: paint the whole rect the bg color
  1941. // 3: paint the video portion colorkey and the borders bg
  1942. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() wndless = " << m_bWndLess << " active = " << m_bInPlaceActive << " !stopped = " << (m_pGraph ? !m_pGraph.IsStopped() : 0) << " mar = " << m_fMaintainAspectRatio), "");
  1943. CSize szSrc;
  1944. GetSourceSize(szSrc);
  1945. CRect rctSrc(0, 0, szSrc.cx, szSrc.cy); // rectangle representing the actual source size(and aspect ratio)
  1946. // in zero top-left coords
  1947. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rctSrc = " << rctSrc), "");
  1948. CScalingRect rctOuterDst(reinterpret_cast<LPCRECT>(di.prcBounds)); // rectangle representing our paint area in client device coords
  1949. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rctOuterDst = " << rctOuterDst), "");
  1950. CScalingRect rctInnerDst(rctOuterDst); // rectangle representing where the video goes that we pass through
  1951. // to the VMR in client logical coords. assume its the whole
  1952. // paint area for now
  1953. CScalingRect rctTLBorder(0, 0, 0, 0); // rectangle representing our top/left letter box(if necessary) in client logical coords
  1954. CScalingRect rctBRBorder(0, 0, 0, 0); // rectangle representing our bottom/left letter box(if necessary) in client logical coords
  1955. CDC pdc(di.hdcDraw);
  1956. long lInnerColor = m_clrBackColor;
  1957. #if 0
  1958. if (!m_bNegotiatedWnd) {
  1959. if (!rctOuterDst) {
  1960. // pull rctOuterDst from site
  1961. // m_CurrentSurface.Site(PQSiteWindowless(m_spInPlaceSite));
  1962. // CheckSurfaceStateChanged(CScalingRect(m_rcPos));
  1963. }
  1964. }
  1965. #endif
  1966. if (m_bInPlaceActive) {
  1967. if (fOverlay) {
  1968. if (m_pGraph && !m_pGraph.IsStopped()) {
  1969. TRACELM(TRACE_PAINT, "CVidCtl::OnDraw() letterboxing");
  1970. // get the color from the current video renderer because we always notify it
  1971. // if we've received a colorkey change but it may not notify us if one went directly to
  1972. // the vr object.
  1973. lInnerColor = m_clrColorKey;
  1974. if (m_fMaintainAspectRatio) {
  1975. ComputeAspectRatioAdjustedRects(rctSrc, rctOuterDst, rctInnerDst, rctTLBorder, rctBRBorder);
  1976. ASSERT((!rctTLBorder && !rctBRBorder) || (rctTLBorder && rctBRBorder)); // both zero or both valid
  1977. if (rctTLBorder && rctBRBorder) {
  1978. CBrush lb;
  1979. HBRUSH hbrc = lb.CreateSolidBrush(m_clrBackColor);
  1980. if (!hbrc) {
  1981. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't create brush for letterbox borders");
  1982. THROWCOM(E_UNEXPECTED);
  1983. }
  1984. if (!pdc.FillRect(rctTLBorder, lb)) {
  1985. DWORD er = GetLastError();
  1986. TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't fill rctTLBorder er = " << er), "");
  1987. return HRESULT_FROM_WIN32(er);
  1988. }
  1989. if (!pdc.FillRect(rctBRBorder, lb)) {
  1990. DWORD er = GetLastError();
  1991. TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't fill rctBRBorder er = " << er), "");
  1992. return HRESULT_FROM_WIN32(er);
  1993. }
  1994. }
  1995. }
  1996. }
  1997. } else {
  1998. if (m_pGraph && !m_pGraph.IsStopped()) {
  1999. TRACELM(TRACE_PAINT, "CVidctrl::OnDraw() vmr repaint");
  2000. lInnerColor = m_clrColorKey;
  2001. if (m_pVideoRenderer) {
  2002. CheckSurfaceStateChanged(rctInnerDst);
  2003. m_pVideoRenderer->RePaint(di.hdcDraw);
  2004. pdc = NULL; // don't delete the DC, it isn't ours
  2005. return S_OK;
  2006. }
  2007. }
  2008. }
  2009. }
  2010. CheckSurfaceStateChanged(rctInnerDst);
  2011. CBrush hb;
  2012. HBRUSH hbrc = hb.CreateSolidBrush(lInnerColor);
  2013. if (!hbrc) {
  2014. TRACELM(TRACE_ERROR, "CVidctrl::OnDraw() can't create brush for mainrect");
  2015. THROWCOM(E_UNEXPECTED);
  2016. }
  2017. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() rctInnerDst at main paint = " << rctInnerDst), "");
  2018. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::OnDraw() innercolor = " << hexdump(lInnerColor)), "");
  2019. if (!pdc.FillRect(rctInnerDst, hb)) {
  2020. DWORD er = GetLastError();
  2021. TRACELSM(TRACE_ERROR, (dbgDump << "CVidctrl::OnDraw() can't fill main video rect er = " << er), "");
  2022. return HRESULT_FROM_WIN32(er);
  2023. }
  2024. pdc = NULL; // don't delete the DC, it isn't ours
  2025. return S_OK;
  2026. } catch(...) {
  2027. return E_UNEXPECTED;
  2028. }
  2029. }
  2030. #endif
  2031. // this code is taken from the vmr utility library alloclib function LetterBoxDstRect().
  2032. // its been modified to match my variable names, do inline __int64 arithmetic, use ATL CRect references,
  2033. // and always compute borders.
  2034. void CVidCtl::ComputeAspectRatioAdjustedRects(const CRect& rctSrc, const CRect& rctOuterDst, CRect& rctInnerDst, CRect& rctTLBorder, CRect& rctBRBorder) {
  2035. // figure out src/dest scale ratios
  2036. int iSrcWidth = rctSrc.Width();
  2037. int iSrcHeight = rctSrc.Height();
  2038. int iOuterDstWidth = rctOuterDst.Width();
  2039. int iOuterDstHeight = rctOuterDst.Height();
  2040. int iInnerDstWidth;
  2041. int iInnerDstHeight;
  2042. //
  2043. // work out if we are Column or Row letter boxing
  2044. //
  2045. __int64 iWHTerm = iSrcWidth * (__int64)iOuterDstHeight;
  2046. iWHTerm /= iSrcHeight;
  2047. if (iWHTerm <= iOuterDstWidth) {
  2048. //
  2049. // column letter boxing - we add border color bars to the
  2050. // left and right of the video image to fill the destination
  2051. // rectangle.
  2052. //
  2053. iWHTerm = iOuterDstHeight * (__int64)iSrcWidth;
  2054. iInnerDstWidth = iWHTerm / iSrcHeight;
  2055. iInnerDstHeight = iOuterDstHeight;
  2056. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::ComputeAspectRatioAdjustedRects() col lb iw = " << iInnerDstWidth << " ih = " << iInnerDstHeight), "");
  2057. }
  2058. else {
  2059. //
  2060. // row letter boxing - we add border color bars to the top
  2061. // and bottom of the video image to fill the destination
  2062. // rectangle
  2063. //
  2064. iWHTerm = iOuterDstWidth * (__int64)iSrcHeight;
  2065. iInnerDstHeight = iWHTerm / iSrcWidth;
  2066. iInnerDstWidth = iOuterDstWidth;
  2067. TRACELSM(TRACE_PAINT, (dbgDump << "CVidctrl::ComputeAspectRatioAdjustedRects() row lb iw = " << iInnerDstWidth << " ih = " << iInnerDstHeight), "");
  2068. }
  2069. //
  2070. // now create a centered inner letter-boxed rectangle within the current outer destination rect
  2071. //
  2072. rctInnerDst.left = rctOuterDst.left + ((iOuterDstWidth - iInnerDstWidth) / 2);
  2073. rctInnerDst.right = rctInnerDst.left + iInnerDstWidth;
  2074. rctInnerDst.top = rctOuterDst.top + ((iOuterDstHeight - iInnerDstHeight) / 2);
  2075. rctInnerDst.bottom = rctInnerDst.top + iInnerDstHeight;
  2076. //
  2077. // Fill out the border rects
  2078. //
  2079. if (rctOuterDst.top != rctInnerDst.top) {
  2080. // border is on the top
  2081. rctTLBorder = CRect(rctOuterDst.left, rctOuterDst.top,
  2082. rctInnerDst.right, rctInnerDst.top);
  2083. }
  2084. else {
  2085. // border is on the left
  2086. rctTLBorder = CRect(rctOuterDst.left, rctOuterDst.top,
  2087. rctInnerDst.left, rctInnerDst.bottom);
  2088. }
  2089. if (rctOuterDst.top != rctInnerDst.top) {
  2090. // border is on the bottom
  2091. rctBRBorder = CRect(rctInnerDst.left, rctInnerDst.bottom,
  2092. rctOuterDst.right, rctOuterDst.bottom);
  2093. }
  2094. else {
  2095. // border is on the right
  2096. rctBRBorder = CRect(rctInnerDst.right, rctInnerDst.top,
  2097. rctOuterDst.right, rctOuterDst.bottom);
  2098. }
  2099. return;
  2100. }
  2101. LRESULT CVidCtl::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2102. bHandled = false;
  2103. m_CurrentSurface.Visible(wParam != 0);
  2104. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidctrl::OnShowWindow() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" );
  2105. RefreshVRSurfaceState();
  2106. return 0;
  2107. }
  2108. LRESULT CVidCtl::OnMoveWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2109. bHandled = false;
  2110. CSize cursize(m_CurrentSurface.Width(), m_CurrentSurface.Height());
  2111. HWND parent = ::GetParent(m_CurrentSurface.Owner());
  2112. POINTS p(MAKEPOINTS(lParam));
  2113. CPoint pt(p.x, p.y);
  2114. CScalingRect newpos(pt, cursize, parent);
  2115. ::InvalidateRect(m_CurrentSurface.Owner(), newpos, false); // force repaint to recalc letterboxing, etc.
  2116. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidctrl::OnMoveWindow() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" );
  2117. return 0;
  2118. }
  2119. LRESULT CVidCtl::OnSizeWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2120. bHandled = false;
  2121. CScalingRect newsize(m_CurrentSurface.TopLeft(), CSize(lParam), m_CurrentSurface.Owner());
  2122. ::InvalidateRect(m_CurrentSurface.Owner(), newsize, false); // force repaint to recalc letterboxing, etc.
  2123. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidctrl::OnSizeWindow() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" );
  2124. return 0;
  2125. }
  2126. LRESULT CVidCtl::OnWindowPosChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2127. bHandled = false;
  2128. m_CurrentSurface.WindowPos(reinterpret_cast<LPWINDOWPOS>(lParam));
  2129. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidctrl::OnWindowPosChanged() visible = " << m_CurrentSurface.IsVisible() << "surf = " << m_CurrentSurface), "" );
  2130. ::InvalidateRect(m_CurrentSurface.Owner(), m_CurrentSurface, false); // force repaint to recalc letterboxing, etc.
  2131. return 0;
  2132. }
  2133. LRESULT CVidCtl::OnTerminate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2134. Stop();
  2135. KillTimer();
  2136. bHandled = false;
  2137. return 0;
  2138. }
  2139. #if 0
  2140. [id(DISPID_CLICK)] void Click();
  2141. [id(DISPID_DBLCLICK)] void DblClick();
  2142. [id(DISPID_KEYDOWN)] void KeyDown(short* KeyCode, short Shift);
  2143. [id(DISPID_KEYPRESS)] void KeyPress(short* KeyAscii);
  2144. [id(DISPID_KEYUP)] void KeyUp(short* KeyCode, short Shift);
  2145. [id(DISPID_MOUSEDOWN)] void MouseDown(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);
  2146. [id(DISPID_MOUSEMOVE)] void MouseMove(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);
  2147. [id(DISPID_MOUSEUP)] void MouseUp(short Button, short Shift, OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y);
  2148. [id(DISPID_ERROREVENT)] void Error(short Number, BSTR* Description, long Scode, BSTR Source, BSTR HelpFile, long HelpContext, boolean* CancelDisplay);
  2149. #endif
  2150. LRESULT CVidCtl::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2151. if (m_TimerID == wParam) {
  2152. if (m_bNegotiatedWnd) {
  2153. if (!m_bWndLess) {
  2154. if (m_CurrentSurface.Width() && m_CurrentSurface.Height()) {
  2155. CScalingRect prevpos(m_CurrentSurface);
  2156. prevpos.Owner(::GetDesktopWindow());
  2157. CScalingRect curpos(::GetDesktopWindow());
  2158. if (!::GetWindowRect(m_CurrentSurface.Owner(), &curpos)) {
  2159. return HRESULT_FROM_WIN32(GetLastError());
  2160. }
  2161. if (curpos != prevpos) {
  2162. FireViewChange(); // force a repaint
  2163. }
  2164. }
  2165. }
  2166. }
  2167. BOOL lRes = 0;
  2168. if (m_pGraph) {
  2169. // as long as we're here, check for events too.
  2170. OnMediaEvent(WM_MEDIAEVENT, 0, 0, lRes);
  2171. }
  2172. bHandled = true;
  2173. } else {
  2174. bHandled = false;
  2175. }
  2176. return 0;
  2177. }
  2178. LRESULT CVidCtl::OnPNP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2179. // undone: implement pnp support
  2180. return 0;
  2181. }
  2182. LRESULT CVidCtl::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2183. return CheckMouseCursor(bHandled);
  2184. }
  2185. LRESULT CVidCtl::OnPower(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2186. // undone: implement rational power management support
  2187. return 0;
  2188. }
  2189. LRESULT CVidCtl::OnDisplayChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2190. if (m_pVideoRenderer) {
  2191. m_pVideoRenderer->DisplayChange();
  2192. FireViewChange();
  2193. }
  2194. return 0;
  2195. }
  2196. HRESULT CVidCtl::OnPreEventNotify(LONG lEvent, LONG_PTR LParam1, LONG_PTR LParam2){
  2197. try{
  2198. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify ev = " << hexdump(lEvent)), "");
  2199. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify lp1 = " << hexdump(LParam1)), "");
  2200. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify lp2 = " << hexdump(LParam2)), "");
  2201. MSVidCtlStateList prevstate = m_State;
  2202. MSVidCtlStateList newstate = m_State;
  2203. // Events where stop is the new state
  2204. if (lEvent == EC_BUILT) {
  2205. prevstate = STATE_UNBUILT;
  2206. newstate = STATE_STOP;
  2207. }
  2208. if (lEvent == EC_STATE_CHANGE && LParam1 == State_Stopped) {
  2209. newstate = STATE_STOP;
  2210. }
  2211. // Events where play is the new state
  2212. if (lEvent == EC_STATE_CHANGE && LParam1 == State_Running) {
  2213. newstate = STATE_PLAY;
  2214. }
  2215. // Events where unbuilt is the new state
  2216. if( lEvent == EC_UNBUILT ) {
  2217. newstate = STATE_UNBUILT;
  2218. }
  2219. // Events where paused is the new state
  2220. if( lEvent == EC_STATE_CHANGE && LParam1 == State_Paused ) {
  2221. newstate = STATE_PAUSE;
  2222. }
  2223. if( lEvent == EC_PAUSED ){
  2224. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify EC_PAUSED"), "");
  2225. }
  2226. if (newstate != prevstate) {
  2227. m_State = newstate;
  2228. Fire_StateChange(prevstate, m_State);
  2229. }
  2230. if (lEvent == EC_DISPLAY_CHANGED) {
  2231. ComputeDisplaySize();
  2232. }
  2233. if (lEvent == EC_VMR_RECONNECTION_FAILED){
  2234. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify EC_VMR_RECONNECTION_FAILED"), "");
  2235. HRESULT hr = Stop();
  2236. if(FAILED(hr)){
  2237. return hr;
  2238. }
  2239. return Error(IDS_NOT_ENOUGH_VIDEO_MEMORY, __uuidof(IMSVidCtl), IDS_NOT_ENOUGH_VIDEO_MEMORY);
  2240. }
  2241. if(lEvent == EC_COMPLETE){
  2242. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::PreEventNotify EC_COMPLETE"), "");
  2243. }
  2244. // undone: recompute displaysize if video source changes
  2245. }
  2246. catch (HRESULT hr){
  2247. return hr;
  2248. }
  2249. catch (...){
  2250. return E_UNEXPECTED;
  2251. }
  2252. return E_NOTIMPL;
  2253. }
  2254. HRESULT CVidCtl::OnPostEventNotify(LONG lEvent, LONG_PTR LParam1, LONG_PTR LParam2){
  2255. try{
  2256. if (lEvent == EC_VMR_RENDERDEVICE_SET) {
  2257. #if 0
  2258. CSize s;
  2259. GetSourceSize(s);
  2260. TRACELSM(TRACE_DEBUG, (dbgDump << "CVidCtl::OnPostEventNotify() VMR_RENDERDEVICE_SET srcrect = " << s), "");
  2261. #endif
  2262. Refresh();
  2263. }
  2264. }
  2265. catch (HRESULT hr){
  2266. return hr;
  2267. }
  2268. catch (...){
  2269. return E_UNEXPECTED;
  2270. }
  2271. return E_NOTIMPL;
  2272. }
  2273. LRESULT CVidCtl::OnMediaEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2274. PQMediaEventEx pme(m_pGraph);
  2275. LONG lEvent;
  2276. LONG_PTR lParam1, lParam2;
  2277. HRESULT hr2;
  2278. try{
  2279. if (!pme) {
  2280. return E_UNEXPECTED;
  2281. }
  2282. hr2 = pme->GetEvent(&lEvent, &lParam1, &lParam2, 0);
  2283. while (SUCCEEDED(hr2)){
  2284. TRACELSM(TRACE_DETAIL, (dbgDump << "CVidCtl::OnMediaevent ev = " << hexdump(lEvent) << " lp1 = " << hexdump(lParam1) << " lp2 = " << hexdump(lParam2)), "");
  2285. HRESULT hr;
  2286. /*** Check who wants the Event ***/
  2287. /*** If they want it should return something other than E_NOTIMPL ***/
  2288. // Does CVidCtl want it?
  2289. hr = OnPreEventNotify(lEvent, lParam1, lParam2);
  2290. //Does the input want it?
  2291. if(hr == E_NOTIMPL){
  2292. PQGraphSegment pSeg(m_pInput);
  2293. if (pSeg) {
  2294. hr = pSeg->OnEventNotify(lEvent, lParam1, lParam2);
  2295. }
  2296. }
  2297. // Do any of the features want it?
  2298. if (hr == E_NOTIMPL) {
  2299. for ( VWFeatures::iterator i = m_pFeaturesInUse.begin(); hr == E_NOTIMPL && i != m_pFeaturesInUse.end(); ++i) {
  2300. hr = PQGraphSegment((*i).punkVal)->OnEventNotify(lEvent, lParam1, lParam2);
  2301. }
  2302. }
  2303. //Does the video renderer want it?
  2304. if(hr == E_NOTIMPL){
  2305. PQGraphSegment pSeg(m_pVideoRenderer);
  2306. if(pSeg){
  2307. hr = pSeg->OnEventNotify(lEvent, lParam1, lParam2);
  2308. }
  2309. }
  2310. // Does the audio renderer want it?
  2311. if(hr == E_NOTIMPL){
  2312. PQGraphSegment pSeg(m_pAudioRenderer);
  2313. if(pSeg){
  2314. hr = pSeg->OnEventNotify(lEvent, lParam1, lParam2);
  2315. }
  2316. }
  2317. // Do any of the outputs want it?
  2318. if(hr == E_NOTIMPL){
  2319. if (!!m_pOutputsInUse && m_pOutputsInUse.begin() != m_pOutputsInUse.end()) {
  2320. for (VWOutputDevices::iterator i = m_pOutputs.begin(); hr == E_NOTIMPL && i != m_pOutputs.end(); ++i) {
  2321. hr = PQGraphSegment((*i).punkVal)->OnEventNotify(lEvent, lParam1, lParam2);
  2322. }
  2323. }
  2324. }
  2325. // Finally do any of the composites want it?
  2326. if(hr == E_NOTIMPL){
  2327. for(VWSegmentList::iterator i = m_pComposites.begin(); hr == E_NOTIMPL && i != m_pComposites.end(); i++){
  2328. hr = PQGraphSegment(*i)->OnEventNotify(lEvent, lParam1, lParam2);
  2329. }
  2330. }
  2331. // Check again to see if CVidCtl want to do anything else regardless of whether or not
  2332. // it got handled by a segment
  2333. hr = OnPostEventNotify(lEvent, lParam1, lParam2);
  2334. //
  2335. // Remember to free the event params
  2336. //
  2337. pme->FreeEventParams(lEvent, lParam1, lParam2) ;
  2338. hr2 = pme->GetEvent(&lEvent, &lParam1, &lParam2, 0);
  2339. }
  2340. }
  2341. catch (HRESULT hr){
  2342. return hr;
  2343. }
  2344. catch (...){
  2345. return E_UNEXPECTED;
  2346. }
  2347. return 0;
  2348. }
  2349. // rev2: if we ever redist to 9x then we need to examine the mfc dbcs processing
  2350. // and adapt it.
  2351. LRESULT CVidCtl::OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2352. //(UINT nChar, UINT nRepCnt, UINT nFlags)
  2353. SHORT nCharShort = LOWORD(wParam);
  2354. HRESULT hr = NOERROR;
  2355. if (m_pInputNotify) {
  2356. hr = m_pInputNotify->KeyPress(&nCharShort);
  2357. }
  2358. if (hr != S_FALSE) {
  2359. Fire_KeyPress(&nCharShort);
  2360. }
  2361. if (!nCharShort) {
  2362. return 0;
  2363. }
  2364. return 1;
  2365. }
  2366. LRESULT CVidCtl::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2367. if (!(KF_REPEAT & HIWORD(lParam))) {
  2368. short keycode = LOWORD(wParam);
  2369. short shiftstate = GetShiftState();
  2370. HRESULT hr = NOERROR;
  2371. if (m_pInputNotify) {
  2372. hr = m_pInputNotify->KeyDown(&keycode, shiftstate);
  2373. }
  2374. if (hr != S_FALSE) {
  2375. Fire_KeyDown(&keycode, shiftstate);
  2376. }
  2377. if (!keycode) {
  2378. return 0;
  2379. }
  2380. }
  2381. return 1;
  2382. }
  2383. LRESULT CVidCtl::OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2384. short keycode = LOWORD(wParam);
  2385. short shiftstate = GetShiftState();
  2386. HRESULT hr = NOERROR;
  2387. if (m_pInputNotify) {
  2388. hr = m_pInputNotify->KeyUp(&keycode, shiftstate);
  2389. }
  2390. if (hr != S_FALSE) {
  2391. Fire_KeyUp(&keycode, shiftstate);
  2392. }
  2393. if (!keycode) {
  2394. return 0;
  2395. }
  2396. return 1;
  2397. }
  2398. // undone: syskey stuff
  2399. LRESULT CVidCtl::OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2400. if (!m_bUIActive) {
  2401. m_bPendingUIActivation = true;
  2402. }
  2403. return 1;
  2404. }
  2405. LRESULT CVidCtl::OnCancelMode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
  2406. SetControlFocus(false);
  2407. SetControlCapture(false);
  2408. m_bPendingUIActivation = false;
  2409. return 1;
  2410. }
  2411. LRESULT CVidCtl::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2412. //(UINT /*nFlags*/, CPoint point)
  2413. {
  2414. CheckMouseCursor(bHandled);
  2415. CPoint point(lParam);
  2416. HRESULT hr = NOERROR;
  2417. if (m_pInputNotify) {
  2418. hr = m_pInputNotify->MouseMove(m_usButtonState, m_usShiftState, point.x, point.y);
  2419. }
  2420. if (hr != S_FALSE) {
  2421. Fire_MouseMove(m_usButtonState, m_usShiftState, point.x, point.y);
  2422. }
  2423. return 1;
  2424. }
  2425. LRESULT CVidCtl::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2426. //(UINT nFlags, CPoint point)
  2427. {
  2428. OnButtonDown(MSVIDCTL_LEFT_BUTTON, wParam, lParam);
  2429. return 1;
  2430. }
  2431. LRESULT CVidCtl::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2432. //(UINT nFlags, CPoint point)
  2433. {
  2434. OnButtonUp(MSVIDCTL_LEFT_BUTTON, wParam, lParam);
  2435. return 1;
  2436. }
  2437. LRESULT CVidCtl::OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2438. //(UINT nFlags, CPoint point)
  2439. {
  2440. OnButtonDblClk(MSVIDCTL_LEFT_BUTTON, wParam, lParam);
  2441. return 1;
  2442. }
  2443. LRESULT CVidCtl::OnMButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2444. //(UINT nFlags, CPoint point)
  2445. {
  2446. OnButtonDown(MSVIDCTL_MIDDLE_BUTTON, wParam, lParam);
  2447. return 1;
  2448. }
  2449. LRESULT CVidCtl::OnMButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2450. //(UINT nFlags, CPoint point)
  2451. {
  2452. OnButtonUp(MSVIDCTL_MIDDLE_BUTTON, wParam, lParam);
  2453. return 1;
  2454. }
  2455. LRESULT CVidCtl::OnMButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2456. //(UINT nFlags, CPoint point)
  2457. {
  2458. OnButtonDblClk(MSVIDCTL_MIDDLE_BUTTON, wParam, lParam);
  2459. return 1;
  2460. }
  2461. LRESULT CVidCtl::OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2462. //(UINT nFlags, CPoint point)
  2463. {
  2464. OnButtonDown(MSVIDCTL_RIGHT_BUTTON, wParam, lParam);
  2465. return 1;
  2466. }
  2467. LRESULT CVidCtl::OnRButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2468. //(UINT nFlags, CPoint point)
  2469. {
  2470. OnButtonUp(MSVIDCTL_RIGHT_BUTTON, wParam, lParam);
  2471. return 1;
  2472. }
  2473. LRESULT CVidCtl::OnRButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2474. //(UINT nFlags, CPoint point)
  2475. {
  2476. OnButtonDblClk(MSVIDCTL_RIGHT_BUTTON, wParam, lParam);
  2477. return 1;
  2478. }
  2479. LRESULT CVidCtl::OnXButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2480. //(UINT nFlags, CPoint point)
  2481. {
  2482. UINT button = HIWORD(wParam);
  2483. if (button & XBUTTON1) {
  2484. OnButtonDown(MSVIDCTL_X_BUTTON1, wParam, lParam);
  2485. } else {
  2486. OnButtonDown(MSVIDCTL_X_BUTTON2, wParam, lParam);
  2487. }
  2488. return 1;
  2489. }
  2490. LRESULT CVidCtl::OnXButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2491. //(UINT nFlags, CPoint point)
  2492. {
  2493. UINT button = HIWORD(wParam);
  2494. if (button & XBUTTON1) {
  2495. OnButtonUp(MSVIDCTL_X_BUTTON1, wParam, lParam);
  2496. } else {
  2497. OnButtonUp(MSVIDCTL_X_BUTTON2, wParam, lParam);
  2498. }
  2499. return 1;
  2500. }
  2501. LRESULT CVidCtl::OnXButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  2502. //(UINT nFlags, CPoint point)
  2503. {
  2504. UINT button = HIWORD(wParam);
  2505. if (button & XBUTTON1) {
  2506. OnButtonDblClk(MSVIDCTL_X_BUTTON1, wParam, lParam);
  2507. } else {
  2508. OnButtonDblClk(MSVIDCTL_X_BUTTON2, wParam, lParam);
  2509. }
  2510. return 1;
  2511. }
  2512. void CVidCtl::OnButtonDown(USHORT nButton, UINT nFlags, CPoint point)
  2513. {
  2514. if (nButton == MSVIDCTL_LEFT_BUTTON) {
  2515. if (m_bWndLess || m_bUIActive || m_bPendingUIActivation) {
  2516. SetControlFocus(true);
  2517. }
  2518. }
  2519. if (!m_usButtonState && (m_bUIActive || m_bPendingUIActivation)) {
  2520. SetControlCapture(true);
  2521. }
  2522. m_usButtonState |= nButton;
  2523. HRESULT hr = NOERROR;
  2524. if (m_pInputNotify) {
  2525. hr = m_pInputNotify->MouseDown(m_usButtonState, m_usShiftState, point.x, point.y);
  2526. }
  2527. if (hr != S_FALSE) {
  2528. Fire_MouseDown(m_usButtonState, m_usShiftState, point.x, point.y);
  2529. }
  2530. m_iDblClkState &= ~nButton;
  2531. return;
  2532. }
  2533. void CVidCtl::OnButtonUp(USHORT nButton, UINT nFlags, CPoint point)
  2534. {
  2535. m_usButtonState &= nButton;
  2536. if (!m_usButtonState) {
  2537. SetControlCapture(false);
  2538. }
  2539. HRESULT hr = NOERROR;
  2540. if (m_pInputNotify) {
  2541. hr = m_pInputNotify->MouseUp(m_usButtonState, m_usShiftState, point.x, point.y);
  2542. }
  2543. if (hr != S_FALSE) {
  2544. Fire_MouseUp(m_usButtonState, m_usShiftState, point.x, point.y);
  2545. }
  2546. if (!(m_iDblClkState & nButton))
  2547. {
  2548. bool bHitUs = false;
  2549. if (m_bWndLess) {
  2550. bHitUs = !!::PtInRect(&m_rcPos, point);
  2551. } else if (m_hWnd && ::IsWindow(m_hWnd)) {
  2552. CRect rect;
  2553. GetClientRect(&rect);
  2554. bHitUs = !!rect.PtInRect(point);
  2555. }
  2556. if (!bHitUs) {
  2557. return;
  2558. }
  2559. hr = NOERROR;
  2560. if (m_pInputNotify) {
  2561. hr = m_pInputNotify->Click();
  2562. }
  2563. if (hr != S_FALSE) {
  2564. Fire_Click();
  2565. }
  2566. if (!m_bInPlaceActive) {
  2567. InPlaceActivate(OLEIVERB_INPLACEACTIVATE, NULL);
  2568. } else if (!m_bUIActive && m_bPendingUIActivation)
  2569. {
  2570. InPlaceActivate(OLEIVERB_UIACTIVATE, NULL);
  2571. }
  2572. m_bPendingUIActivation = FALSE;
  2573. } else {
  2574. m_iDblClkState &= ~nButton;
  2575. }
  2576. return;
  2577. }
  2578. void CVidCtl::OnButtonDblClk(USHORT nButton, UINT nFlags, CPoint point)
  2579. {
  2580. HRESULT hr = NOERROR;
  2581. if (m_pInputNotify) {
  2582. hr = m_pInputNotify->DblClick();
  2583. }
  2584. if (hr != S_FALSE) {
  2585. Fire_DblClick();
  2586. }
  2587. m_iDblClkState |= nButton;
  2588. if (!m_bInPlaceActive) {
  2589. InPlaceActivate(OLEIVERB_INPLACEACTIVATE, NULL);
  2590. } else if (!m_bUIActive && m_bPendingUIActivation){
  2591. InPlaceActivate(OLEIVERB_UIACTIVATE, NULL);
  2592. }
  2593. m_bPendingUIActivation = FALSE;
  2594. return;
  2595. }
  2596. // this routine sets up all the crossbar routing so the streams coming out of the
  2597. // input get where they're supposed to go
  2598. HRESULT CVidCtl::RouteStreams() {
  2599. VIDPERF_FUNC;
  2600. int isEncoder = -1;
  2601. VWStream vpath;
  2602. VWStream apath;
  2603. // See how far we have to route the audio/video
  2604. CComQIPtr<IMSVidAnalogTuner> qiITV(m_pInput);
  2605. if(!!qiITV){
  2606. CComQIPtr<ITuneRequest> qiTR;
  2607. HRESULT hr = qiITV->get_Tune(&qiTR);
  2608. if(SUCCEEDED(hr)){
  2609. qiITV->put_Tune(qiTR);
  2610. }
  2611. }
  2612. // undone: in win64 size() is really __int64. fix output operator for
  2613. // that type and remove cast
  2614. {
  2615. if (!!m_pOutputsInUse && m_pOutputsInUse.begin() != m_pOutputsInUse.end()) {
  2616. for (VWOutputDevices::iterator i = m_pOutputsInUse.begin(); i != m_pOutputsInUse.end(); ++i) {
  2617. CComQIPtr<IMSVidOutputDevice> pqODev = VWGraphSegment(*i);
  2618. if(!pqODev){
  2619. return E_UNEXPECTED;
  2620. }
  2621. GUID2 outputID;
  2622. HRESULT hr = pqODev->get__ClassID(&outputID);
  2623. if(FAILED(hr)){
  2624. return hr;
  2625. }
  2626. if(outputID == CLSID_MSVidStreamBufferSink){
  2627. CComQIPtr<IMSVidStreamBufferSink> pqTSSink(pqODev);
  2628. hr = pqTSSink->NameSetLock();
  2629. if(FAILED(hr)){
  2630. return hr;
  2631. }
  2632. }
  2633. }
  2634. }
  2635. }
  2636. // undone: other dest segments
  2637. return NOERROR;
  2638. }
  2639. #if 0
  2640. CString CVidCtl::GetMonitorName(HMONITOR hm) {
  2641. MONITORINFOEX mi;
  2642. mi.cbSize = sizeof(mi);
  2643. if (!GetMonitorInfo(hm, &mi)) {
  2644. THROWCOM(HRESULT_FROM_WIN32(GetLastError()));
  2645. }
  2646. return CString(mi.szDevice);
  2647. }
  2648. HRESULT CVidCtl::GetDDrawNameForMonitor(HMONITOR hm, VMRGUID& guid) {
  2649. PQVMRMonitorConfig pmc(m_pVideoRenderer);
  2650. if (!pmc) {
  2651. return E_UNEXPECTED; // should always exist by now
  2652. }
  2653. DWORD dwCount;
  2654. HRESULT hr = pmc->GetAvailableMonitors(NULL, 0, &dwCount);
  2655. if (FAILED(hr)) {
  2656. return hr;
  2657. }
  2658. VMRMONITORINFO* pInfo = reinterpret_cast<VMRMONITORINFO*>(_alloca(sizeof(VMRMONITORINFO) * dwCount));
  2659. if (!pInfo) {
  2660. return E_OUTOFMEMORY;
  2661. }
  2662. hr = pmc->GetAvailableMonitors(pInfo, dwCount, &dwCount);
  2663. if (FAILED(hr)) {
  2664. return hr;
  2665. }
  2666. CString csMonitorName(GetMonitorName(hm));
  2667. for (int i = 0; i < dwCount; ++i) {
  2668. CString csDevName(pInfo[i].szDevice);
  2669. if (csDevName == csMonitorName) break;
  2670. }
  2671. if (i >= dwCount) {
  2672. // no ddraw device exist with a name which matches the monitor name
  2673. return HRESULT_FROM_WIN32(ERROR_DEV_NOT_EXIST);
  2674. }
  2675. guid = pInfo[i].guid;
  2676. return NOERROR;
  2677. }
  2678. HRESULT CVidCtl::GetCapsForMonitor(HMONITOR hm, LPDDCAPS pDDCaps) {
  2679. VMRGUID ddname;
  2680. HRESULT hr = GetDDrawNameForMonitor(hm, ddname);
  2681. if (FAILED(hr)) {
  2682. return hr;
  2683. }
  2684. PQDirectDraw7 pDD;
  2685. hr = DirectDrawCreateEx(ddname.pGUID, reinterpret_cast<LPVOID*>(&pDD), IID_IDirectDraw7, NULL);
  2686. if (FAILED(hr)) {
  2687. return hr;
  2688. }
  2689. return pDD->GetCaps(pDDCaps, NULL);
  2690. }
  2691. bool CVidCtl::MonitorHasHWOverlay(HMONITOR hm) {
  2692. DDCAPS caps;
  2693. HRESULT hr = GetCapsForMonitor(hm, &caps);
  2694. if (SUCCEEDED(hr)) {
  2695. // undone: if caps include hw overlay {
  2696. // return true;
  2697. // }
  2698. }
  2699. return false;
  2700. }
  2701. bool CVidCtl::WindowHasHWOverlay(HWND hWnd) {
  2702. #if 0 // undone: turn on when finished
  2703. DWORD dwFlags = MONITOR_DEFAULT_TO_NEAREST
  2704. if (hWnd == INVALID_HWND_VALUE) {
  2705. // if we don't have an hwnd yet, assume the primary
  2706. hWnd = HWND_DESKTOP;
  2707. dwFlags = MONITOR_DEFAULT_TO_PRIMARY;
  2708. }
  2709. HMONITOR hm = ::MonitorFromWindow(hWnd, dwFlags);
  2710. return MonitorHasHWOverlay(hm);
  2711. #else
  2712. return true; // mimic current behavior
  2713. #endif
  2714. }
  2715. #endif
  2716. // ISupportsErrorInfo
  2717. STDMETHODIMP CVidCtl::InterfaceSupportsErrorInfo(REFIID riid)
  2718. {
  2719. static const IID* arr[] =
  2720. {
  2721. &__uuidof(IMSVidCtl),
  2722. };
  2723. for (int i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
  2724. {
  2725. if (InlineIsEqualGUID(*arr[i], riid))
  2726. return S_OK;
  2727. }
  2728. return S_FALSE;
  2729. }
  2730. STDMETHODIMP CVidCtl::put_ServiceProvider(/*[in]*/ IUnknown * pServiceP){
  2731. if(!pServiceP){
  2732. punkCert.Release();
  2733. return S_FALSE;
  2734. }
  2735. punkCert = pServiceP;
  2736. if(!punkCert){
  2737. return E_NOINTERFACE;
  2738. }
  2739. return S_OK;
  2740. }
  2741. STDMETHODIMP CVidCtl::QueryService(REFIID service, REFIID iface, LPVOID* ppv) {
  2742. if (service == __uuidof(IWMReader) && iface == IID_IUnknown &&
  2743. (VWGraphSegment(m_pInput).ClassID() == CLSID_MSVidFilePlaybackDevice ||
  2744. VWGraphSegment(m_pInput).ClassID() == CLSID_MSVidStreamBufferSource)) {
  2745. if (!!punkCert) {
  2746. return punkCert.CopyTo(ppv);
  2747. }
  2748. }
  2749. PQServiceProvider psp(m_spInPlaceSite);
  2750. if (!psp) {
  2751. if (m_spClientSite) {
  2752. HRESULT hr = m_spClientSite->QueryInterface(IID_IServiceProvider, reinterpret_cast<LPVOID*>(&psp));
  2753. if (FAILED(hr)) {
  2754. return E_FAIL;
  2755. }
  2756. } else {
  2757. return E_FAIL;
  2758. }
  2759. }
  2760. return psp->QueryService(service, iface, ppv);
  2761. }
  2762. HRESULT CVidCtl::SetClientSite(IOleClientSite *pClientSite){
  2763. if(!!pClientSite){
  2764. HRESULT hr = IsSafeSite(pClientSite);
  2765. if(FAILED(hr)){
  2766. return hr;
  2767. }
  2768. }
  2769. return IOleObjectImpl<CVidCtl>::SetClientSite(pClientSite);
  2770. }
  2771. #if 0
  2772. HRESULT CVidCtl::DoVerb(LONG iVerb, LPMSG pMsg, IOleClientSite* pActiveSite, LONG linddex,
  2773. HWND hwndParent, LPCRECT lprcPosRect){
  2774. if(!m_spClientSite){
  2775. return E_FAIL;
  2776. }
  2777. else{
  2778. return IOleObjectImpl<CVidCtl>::DoVerb(iVerb, pMsg, pActiveSite, linddex, hwndParent, lprcPosRect);
  2779. }
  2780. }
  2781. #endif
  2782. #endif //TUNING_MODEL_ONLY
  2783. // end of file - VidCtl.cpp