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

2339 lines
70 KiB

  1. /*****************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1999-2000
  4. *
  5. * TITLE: PrvGrph.cpp
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: OrenR
  10. *
  11. * DATE: 2000/10/25
  12. *
  13. * DESCRIPTION: Implements preview graph for capture still images
  14. *
  15. *****************************************************************************/
  16. #include <precomp.h>
  17. #pragma hdrstop
  18. ///////////////////////////////
  19. //
  20. // Constants
  21. //
  22. ///////////////////////////////
  23. //
  24. // Amount of time we are willing to wait to take a picture
  25. //
  26. const UINT TIMEOUT_TAKE_PICTURE = 1000 * 5; // 5 seconds
  27. //
  28. // These 2 values define how many media sample packets the still
  29. // filter should cache
  30. //
  31. const UINT CAPTURE_NUM_SAMPLES_TO_CACHE = 6;
  32. const UINT STILL_NUM_SAMPLES_TO_CACHE = 1;
  33. //
  34. // Max amount of time we wait for us to transition into a running state
  35. //
  36. const UINT STATE_TRANSITION_TIMEOUT = 1000 * 2; // 2 seconds
  37. //
  38. // Video size preferrences. This will not affect DV devices, only
  39. // USB WebCams that support changing their format.
  40. //
  41. const GUID DEFAULT_MEDIASUBTYPE = MEDIASUBTYPE_IYUV;
  42. const LONG MIN_VIDEO_WIDTH = 176;
  43. const LONG MIN_VIDEO_HEIGHT = 144;
  44. const LONG MAX_VIDEO_WIDTH = 640;
  45. const LONG MAX_VIDEO_HEIGHT = 480;
  46. const LONG PREFERRED_VIDEO_WIDTH = 176;
  47. const LONG PREFERRED_VIDEO_HEIGHT = 144;
  48. const LONG PREFERRED_FRAME_RATE = 30; // ideal frame rate
  49. const LONG BACKUP_FRAME_RATE = 15; // less than ideal frame rate.
  50. ///////////////////////////////
  51. // CPreviewGraph Constructor
  52. //
  53. CPreviewGraph::CPreviewGraph() :
  54. m_hwndParent(NULL),
  55. m_lStillPinCaps(0),
  56. m_lStyle(0),
  57. m_bPreviewVisible(TRUE),
  58. m_CurrentState(WIAVIDEO_NO_VIDEO),
  59. m_pWiaVideo(NULL),
  60. m_bSizeVideoToWindow(FALSE),
  61. m_pVideoProperties(NULL)
  62. {
  63. DBG_FN("CPreviewGraph::CPreviewGraph");
  64. }
  65. ///////////////////////////////
  66. // CPreviewGraph Destructor
  67. //
  68. CPreviewGraph::~CPreviewGraph()
  69. {
  70. DBG_FN("CPreviewGraph::~CPreviewGraph");
  71. //
  72. // Term the object if it is not already terminated.
  73. //
  74. Term();
  75. }
  76. ///////////////////////////////
  77. // Init
  78. //
  79. HRESULT CPreviewGraph::Init(CWiaVideo *pWiaVideo)
  80. {
  81. HRESULT hr = S_OK;
  82. if (pWiaVideo == NULL)
  83. {
  84. hr = E_POINTER;
  85. CHECK_S_OK2(hr, ("CPreviewGraph::Init, received NULL CWiaVideo "
  86. "param, this should never happen"));
  87. }
  88. if (pWiaVideo)
  89. {
  90. m_pWiaVideo = pWiaVideo;
  91. }
  92. m_StillProcessor.Init(this);
  93. CreateHiddenWindow();
  94. return hr;
  95. }
  96. ///////////////////////////////
  97. // Term
  98. //
  99. HRESULT CPreviewGraph::Term()
  100. {
  101. HRESULT hr = S_OK;
  102. m_StillProcessor.Term();
  103. if (GetState() != WIAVIDEO_NO_VIDEO)
  104. {
  105. DestroyVideo();
  106. }
  107. DestroyHiddenWindow();
  108. m_pWiaVideo = NULL;
  109. return hr;
  110. }
  111. ///////////////////////////////
  112. // GetImagesDirectory
  113. //
  114. HRESULT CPreviewGraph::GetImagesDirectory(CSimpleString *pImagesDirectory)
  115. {
  116. DBG_FN("CPreviewGraph::GetImagesDirectory");
  117. ASSERT(pImagesDirectory != NULL);
  118. HRESULT hr = S_OK;
  119. if (pImagesDirectory == NULL)
  120. {
  121. hr = E_POINTER;
  122. CHECK_S_OK2(hr, ("CPreviewGraph::GetImagesDirectory received a "
  123. "NULL parameter"));
  124. }
  125. if (hr == S_OK)
  126. {
  127. *pImagesDirectory = m_strImagesDirectory;
  128. }
  129. return hr;
  130. }
  131. ///////////////////////////////
  132. // SetImagesDirectory
  133. //
  134. HRESULT CPreviewGraph::SetImagesDirectory(
  135. const CSimpleString *pImagesDirectory)
  136. {
  137. DBG_FN("CPreviewGraph::SetImagesDirectory");
  138. ASSERT(pImagesDirectory != NULL);
  139. HRESULT hr = S_OK;
  140. if (pImagesDirectory == NULL)
  141. {
  142. hr = E_POINTER;
  143. CHECK_S_OK2(hr, ("CPreviewGraph::SetImagesDirectory received a "
  144. "NULL parameter"));
  145. }
  146. if (hr == S_OK)
  147. {
  148. m_strImagesDirectory = *pImagesDirectory;
  149. //
  150. // If the graph is created, then we should set the image directory
  151. // so that the next image captured will be saved to the new directory.
  152. //
  153. if (GetState() == WIAVIDEO_NO_VIDEO)
  154. {
  155. hr = m_StillProcessor.CreateImageDir(&m_strImagesDirectory);
  156. CHECK_S_OK2(hr,
  157. ("CPreviewGraph::SetImagesDirectory, failed to "
  158. "create images directory '%ls'",
  159. CSimpleStringConvert::WideString(m_strImagesDirectory)));
  160. }
  161. }
  162. return hr;
  163. }
  164. ///////////////////////////////
  165. // GetState
  166. //
  167. WIAVIDEO_STATE CPreviewGraph::GetState()
  168. {
  169. return m_CurrentState;
  170. }
  171. ///////////////////////////////
  172. // SetState
  173. //
  174. HRESULT CPreviewGraph::SetState(WIAVIDEO_STATE NewState)
  175. {
  176. m_CurrentState = NewState;
  177. return S_OK;
  178. }
  179. ///////////////////////////////
  180. // CreateVideo
  181. //
  182. HRESULT CPreviewGraph::CreateVideo(const TCHAR *pszOptionalWiaDeviceID,
  183. IMoniker *pCaptureDeviceMoniker,
  184. HWND hwndParent,
  185. BOOL bStretchToFitParent,
  186. BOOL bAutoPlay)
  187. {
  188. DBG_FN("CPreviewGraph::CreateVideo");
  189. HRESULT hr = S_OK;
  190. WIAVIDEO_STATE State = GetState();
  191. if ((m_strImagesDirectory.Length() == 0) ||
  192. (pCaptureDeviceMoniker == NULL))
  193. {
  194. hr = E_POINTER;
  195. CHECK_S_OK2(hr, ("CPreviewGraph::CreateVideo, received NULL param"));
  196. return hr;
  197. }
  198. else if ((State == WIAVIDEO_DESTROYING_VIDEO) ||
  199. (State == WIAVIDEO_CREATING_VIDEO))
  200. {
  201. hr = E_FAIL;
  202. CHECK_S_OK2(hr, ("CPreviewGraph::CreateVideo, cannot create video, "
  203. "still in the process of creating or destroying "
  204. "it, CurrentState = '%lu'", State));
  205. return hr;
  206. }
  207. else if (State != WIAVIDEO_NO_VIDEO)
  208. {
  209. //
  210. // If we are not in the process of creating or destorying the
  211. // video, and our state is not NO_VIDEO, then assume everything
  212. // is okay, and return S_OK.
  213. //
  214. return S_OK;
  215. }
  216. ASSERT(m_strImagesDirectory.Length() != 0);
  217. ASSERT(pCaptureDeviceMoniker != NULL);
  218. //
  219. // Set our state to indicate we are creating the video
  220. //
  221. SetState(WIAVIDEO_CREATING_VIDEO);
  222. //
  223. // Create our image directory
  224. //
  225. if (SUCCEEDED(hr))
  226. {
  227. //
  228. // Save the parent window handle.
  229. //
  230. m_hwndParent = hwndParent;
  231. m_bSizeVideoToWindow = bStretchToFitParent;
  232. }
  233. if (SUCCEEDED(hr))
  234. {
  235. m_pVideoProperties = new CWiaVideoProperties(pszOptionalWiaDeviceID);
  236. if (m_pVideoProperties == NULL)
  237. {
  238. hr = E_OUTOFMEMORY;
  239. CHECK_S_OK2(hr, ("CPreviewGraph::CreateVideo, failed to allocate memory "
  240. "for CWiaVideoProperties. Cannot create video"));
  241. }
  242. }
  243. //
  244. // Build the DirectShow video preview graph
  245. //
  246. if (SUCCEEDED(hr))
  247. {
  248. hr = BuildPreviewGraph(pCaptureDeviceMoniker, bStretchToFitParent);
  249. CHECK_S_OK2(hr, ("CPreviewGraph::CreateVideo failed to build the "
  250. "preview graph"));
  251. }
  252. if (SUCCEEDED(hr))
  253. {
  254. //
  255. // Video graph exists, update our state
  256. //
  257. SetState(WIAVIDEO_VIDEO_CREATED);
  258. //
  259. // Begin playback automatically
  260. //
  261. if (bAutoPlay)
  262. {
  263. hr = Play();
  264. CHECK_S_OK2(hr, ("CPreviewGraph::CreateVideo failed begin "
  265. "playback"));
  266. }
  267. }
  268. if (FAILED(hr))
  269. {
  270. CHECK_S_OK2(hr, ("CreateVideo failed to build the graph, tearing it "
  271. "down"));
  272. DestroyVideo();
  273. }
  274. return hr;
  275. }
  276. ///////////////////////////////
  277. // DestroyVideo
  278. //
  279. HRESULT CPreviewGraph::DestroyVideo()
  280. {
  281. DBG_FN("CPreviewGraph::DestroyVideo");
  282. HRESULT hr = S_OK;
  283. SetState(WIAVIDEO_DESTROYING_VIDEO);
  284. //
  285. // Stop the graph first
  286. //
  287. Stop();
  288. //
  289. // Delete the video properties object.
  290. //
  291. if (m_pVideoProperties)
  292. {
  293. delete m_pVideoProperties;
  294. m_pVideoProperties = NULL;
  295. }
  296. //
  297. // Destroys the preview graph and all DShow components associated with it.
  298. // Even if these are already gone, there is no harm in calling it.
  299. //
  300. TeardownPreviewGraph();
  301. m_hwndParent = NULL;
  302. m_pVideoControl = NULL;
  303. m_pStillPin = NULL;
  304. m_pCapturePinSnapshot = NULL;
  305. m_pStillPinSnapshot = NULL;
  306. m_pPreviewVW = NULL;
  307. m_pCaptureGraphBuilder = NULL;
  308. m_pGraphBuilder = NULL;
  309. m_pCaptureFilter = NULL;
  310. m_lStillPinCaps = 0;
  311. m_lStyle = 0;
  312. SetState(WIAVIDEO_NO_VIDEO);
  313. //
  314. // We purposely put this here so that it does NOT get reset after
  315. // destroying the video. This should remain the lifetime of this
  316. // object instance, unless changed by the user via the
  317. // get/put_PreviewVisible properties in CWiaVideo.
  318. //
  319. m_bPreviewVisible = m_bPreviewVisible;
  320. return hr;
  321. }
  322. ///////////////////////////////
  323. // TakePicture
  324. //
  325. HRESULT CPreviewGraph::TakePicture(CSimpleString *pstrNewImageFileName)
  326. {
  327. DBG_FN("CPreviewGraph::TakePicture");
  328. WIAVIDEO_STATE State = GetState();
  329. HRESULT hr = S_OK;
  330. CSimpleString strNewImageFullPath;
  331. if ((State != WIAVIDEO_VIDEO_PLAYING) &&
  332. (State != WIAVIDEO_VIDEO_PAUSED))
  333. {
  334. hr = E_FAIL;
  335. CHECK_S_OK2(hr, ("CPreviewGraph::TakePicture, cannot take a picture "
  336. "because we are in an incorrect state, "
  337. "current state = '%lu'", State));
  338. return hr;
  339. }
  340. ASSERT((State == WIAVIDEO_VIDEO_PLAYING) ||
  341. (State == WIAVIDEO_VIDEO_PAUSED));
  342. //
  343. // Set this to TRUE. We reset it when we return from our
  344. // WaitForNewImage fn. This allows us to distinguish between
  345. // a user initiated take picture event, and an async take picture
  346. // event generated by a hardware button push.
  347. //
  348. m_StillProcessor.SetTakePicturePending(TRUE);
  349. //
  350. // If the device is internal triggerable, trigger it
  351. // The triggered image will be delivered to the still pin and will
  352. // then travel down stream until it reaches the WIA StreamSnapshot filter,
  353. // which will process the image.
  354. //
  355. if (m_pVideoControl && (m_lStillPinCaps & VideoControlFlag_Trigger))
  356. {
  357. //
  358. // ignore the time stamp here since we do not need it.
  359. //
  360. hr = m_pVideoControl->SetMode(m_pStillPin, VideoControlFlag_Trigger);
  361. CHECK_S_OK2(hr, ("CPreviewGraph::TakePicture, attempted to trigger "
  362. "the still pin on the capture filter to take a "
  363. "picture, but it failed"));
  364. }
  365. else
  366. {
  367. if (m_pCapturePinSnapshot)
  368. {
  369. hr = m_pCapturePinSnapshot->Snapshot(GetMessageTime());
  370. CHECK_S_OK2(hr, ("CPreviewGraph::TakePicture, attempted to "
  371. "trigger the WIA Image filter to take a "
  372. "snapshot of the video stream, but it "
  373. "failed"));
  374. }
  375. else
  376. {
  377. hr = E_FAIL;
  378. CHECK_S_OK2(hr, ("CPreviewGraph::TakePicture, attempted to call "
  379. "snapshot on the WIA Image filter, but the "
  380. "filter pointer is NULL"));
  381. }
  382. }
  383. //
  384. // If we are taking the picture via the still pin, then taking a
  385. // picture is an asynchronous operation, and we have to wait for
  386. // the StillProcessor's callback function to complete its work.
  387. // It will signal us when it's done. If we are taking the picture
  388. // via the WIA image filter, then the operation is synchronous,
  389. // in which case this wait function will return immediately.
  390. //
  391. hr = m_StillProcessor.WaitForNewImage(TIMEOUT_TAKE_PICTURE,
  392. &strNewImageFullPath);
  393. CHECK_S_OK2(hr, ("CPreviewGraph::TakePicture failed waiting for new "
  394. "still image to arrive, our timeout was '%d'",
  395. TIMEOUT_TAKE_PICTURE));
  396. //
  397. // Set this to TRUE. We reset it when we return from our
  398. // WaitForNewImage fn.
  399. //
  400. m_StillProcessor.SetTakePicturePending(FALSE);
  401. if ((pstrNewImageFileName) && (strNewImageFullPath.Length() > 0))
  402. {
  403. *pstrNewImageFileName = strNewImageFullPath;
  404. }
  405. CHECK_S_OK(hr);
  406. return hr;
  407. }
  408. ///////////////////////////////
  409. // ResizeVideo
  410. //
  411. HRESULT CPreviewGraph::ResizeVideo(BOOL bSizeVideoToWindow)
  412. {
  413. DBG_FN("CPreviewGraph::ResizeVideo");
  414. RECT rc = {0};
  415. HRESULT hr = S_OK;
  416. //
  417. // Check for invalid args
  418. //
  419. if ((m_hwndParent) && (m_pPreviewVW))
  420. {
  421. hr = CDShowUtil::SizeVideoToWindow(m_hwndParent,
  422. m_pPreviewVW,
  423. bSizeVideoToWindow);
  424. m_bSizeVideoToWindow = bSizeVideoToWindow;
  425. CHECK_S_OK2(hr, ("CPreviewGraph::ResizeVideo, failed to resize "
  426. "video window"));
  427. }
  428. else
  429. {
  430. hr = E_FAIL;
  431. CHECK_S_OK2(hr, ("CPreviewGraph::ResizeVideo, either the parent "
  432. "window is NULL (0x%08lx), or the Video Preview "
  433. "pointer is NULL (0x%08lx)",
  434. m_hwndParent, m_pPreviewVW));
  435. }
  436. return hr;
  437. }
  438. ///////////////////////////////
  439. // ShowVideo
  440. //
  441. HRESULT CPreviewGraph::ShowVideo(BOOL bShow)
  442. {
  443. DBG_FN("CPreviewGraph::ShowVideo");
  444. HRESULT hr = S_OK;
  445. if (m_pPreviewVW)
  446. {
  447. hr = CDShowUtil::ShowVideo(bShow, m_pPreviewVW);
  448. CHECK_S_OK2(hr, ("CPreviewGraph::ShowVideo failed"));
  449. }
  450. m_bPreviewVisible = bShow;
  451. return hr;
  452. }
  453. ///////////////////////////////
  454. // Play
  455. //
  456. HRESULT CPreviewGraph::Play()
  457. {
  458. DBG_FN("CPreviewGraph::Play");
  459. HRESULT hr = S_OK;
  460. WIAVIDEO_STATE State = GetState();
  461. if ((State != WIAVIDEO_VIDEO_CREATED) &&
  462. (State != WIAVIDEO_VIDEO_PAUSED))
  463. {
  464. hr = E_FAIL;
  465. CHECK_S_OK2(hr, ("CPreviewGraph::Play, cannot begin playback "
  466. "because we are in an incorrect state, "
  467. "current state = '%lu'", State));
  468. return hr;
  469. }
  470. else if (State == WIAVIDEO_VIDEO_PLAYING)
  471. {
  472. DBG_WRN(("CPreviewGraph::Play, play was called, but we are already "
  473. "playing, doing nothing."));
  474. return hr;
  475. }
  476. ASSERT(m_pGraphBuilder != NULL);
  477. if (m_pGraphBuilder == NULL)
  478. {
  479. hr = E_FAIL;
  480. CHECK_S_OK2(hr, ("CPreviewGraph::Play, m_pGraphBuilder is NULL"));
  481. }
  482. if (hr == S_OK)
  483. {
  484. CComQIPtr<IMediaControl, &IID_IMediaControl> pMC(m_pGraphBuilder);
  485. if (pMC)
  486. {
  487. DBG_TRC(("CPreviewGraph::Play ***Beginning Playback ***"));
  488. //
  489. // Set the graph running...
  490. //
  491. hr = pMC->Run();
  492. if (hr == S_OK)
  493. {
  494. DBG_TRC(("CPreviewGraph::Play, graph is running..."));
  495. SetState(WIAVIDEO_VIDEO_PLAYING);
  496. }
  497. else if (hr == S_FALSE)
  498. {
  499. OAFilterState FilterState;
  500. DBG_TRC(("CPreviewGraph::Play, Waiting '%lu' millisec for "
  501. "graph to transition to running state",
  502. STATE_TRANSITION_TIMEOUT));
  503. //
  504. // Give the graph a chance to transition into the running
  505. // state. Note that this function will wait for
  506. // STATE_TRANSITION_TIMEOUT milliseconds, so make sure that
  507. // this is not a long wait, otherwise the caller could
  508. // appear unresponsive.
  509. //
  510. hr = pMC->GetState(STATE_TRANSITION_TIMEOUT, &FilterState);
  511. if ((hr == S_OK) && (FilterState == State_Running))
  512. {
  513. SetState(WIAVIDEO_VIDEO_PLAYING);
  514. DBG_TRC(("CPreviewGraph::Play, graph is running..."));
  515. }
  516. else if (hr == VFW_S_STATE_INTERMEDIATE)
  517. {
  518. //
  519. // We fudge our state a little here on the assumption
  520. // that the transition to the run state by DShow is
  521. // taking a little longer, but eventually will transition
  522. // to running.
  523. //
  524. SetState(WIAVIDEO_VIDEO_PLAYING);
  525. DBG_TRC(("CPreviewGraph::Play, still transitioning to "
  526. "play state..."));
  527. }
  528. else
  529. {
  530. CHECK_S_OK2(hr, ("CPreviewGraph::Play, "
  531. "IMediaControl::GetState failed..."));
  532. }
  533. hr = S_OK;
  534. }
  535. else
  536. {
  537. CHECK_S_OK2(hr, ("CPreviewGraph::Play, "
  538. "IMediaControl::Run failed"));
  539. }
  540. }
  541. else
  542. {
  543. DBG_ERR(("CPreviewGraph::Play, Unable to get "
  544. "MediaControl interface"));
  545. }
  546. }
  547. //
  548. // If the user of this object specified in the past that the video window
  549. // should be visible, then show it, otherwise, make sure it is hidden.
  550. //
  551. ResizeVideo(m_bSizeVideoToWindow);
  552. ShowVideo(m_bPreviewVisible);
  553. return hr;
  554. }
  555. ///////////////////////////////
  556. // Stop
  557. //
  558. HRESULT CPreviewGraph::Stop()
  559. {
  560. DBG_FN("CPreviewGraph::Stop");
  561. HRESULT hr = S_OK;
  562. if (m_pGraphBuilder)
  563. {
  564. CComQIPtr<IMediaControl, &IID_IMediaControl> pMC(m_pGraphBuilder);
  565. if (pMC)
  566. {
  567. hr = pMC->Stop();
  568. CHECK_S_OK2(hr, ("CPreviewGraph::Stop, IMediaControl::Stop "
  569. "failed"));
  570. }
  571. else
  572. {
  573. hr = E_FAIL;
  574. DBG_ERR(("CPreviewGraph::Stop unable to get MediaControl "
  575. "interface, returning hr = 0x%08lx", hr));
  576. }
  577. }
  578. CHECK_S_OK(hr);
  579. return hr;
  580. }
  581. ///////////////////////////////
  582. // Pause
  583. //
  584. HRESULT CPreviewGraph::Pause()
  585. {
  586. DBG_FN("CPreviewGraph::Pause");
  587. HRESULT hr = S_OK;
  588. WIAVIDEO_STATE State = GetState();
  589. if ((State != WIAVIDEO_VIDEO_CREATED) &&
  590. (State != WIAVIDEO_VIDEO_PLAYING))
  591. {
  592. hr = E_FAIL;
  593. CHECK_S_OK2(hr, ("CPreviewGraph::Pause, cannot begin pause "
  594. "because we are in an incorrect state, "
  595. "current state = '%lu'", State));
  596. return hr;
  597. }
  598. else if (State == WIAVIDEO_VIDEO_PAUSED)
  599. {
  600. DBG_WRN(("CPreviewGraph::Pause, pause was called, but we are already "
  601. "paused, doing nothing."));
  602. return hr;
  603. }
  604. CComQIPtr<IMediaControl, &IID_IMediaControl> pMC(m_pGraphBuilder);
  605. if (pMC)
  606. {
  607. hr = pMC->Pause();
  608. if (SUCCEEDED(hr))
  609. {
  610. SetState(WIAVIDEO_VIDEO_PAUSED);
  611. }
  612. CHECK_S_OK2(hr, ("CPreviewGraph::Pause, failed to pause video"));
  613. }
  614. else
  615. {
  616. DBG_ERR(("CPreviewGraph::Pause unable to get MediaControl interface"));
  617. }
  618. return hr;
  619. }
  620. ///////////////////////////////
  621. // ProcessAsyncImage
  622. //
  623. // Called by CPreviewGraph
  624. // when user presses hardware
  625. // button and it is delivered to
  626. // Still Pin.
  627. //
  628. HRESULT CPreviewGraph::ProcessAsyncImage(const CSimpleString *pNewImage)
  629. {
  630. DBG_FN("CPreviewGraph::ProcessAsyncImage");
  631. HRESULT hr = S_OK;
  632. if (m_pWiaVideo)
  633. {
  634. hr = m_pWiaVideo->ProcessAsyncImage(pNewImage);
  635. }
  636. else
  637. {
  638. DBG_WRN(("CPreviewGraph::ProcessAsyncImage failed, m_pWiaVideo "
  639. "is NULL"));
  640. }
  641. return hr;
  642. }
  643. ///////////////////////////////
  644. // GetStillPinCaps
  645. //
  646. HRESULT CPreviewGraph::GetStillPinCaps(IBaseFilter *pCaptureFilter,
  647. IPin **ppStillPin,
  648. IAMVideoControl **ppVideoControl,
  649. LONG *plCaps)
  650. {
  651. DBG_FN("CPreviewGraph::GetStillPinCaps");
  652. HRESULT hr = S_OK;
  653. ASSERT(pCaptureFilter != NULL);
  654. ASSERT(ppStillPin != NULL);
  655. ASSERT(ppVideoControl != NULL);
  656. ASSERT(plCaps != NULL);
  657. if ((pCaptureFilter == NULL) ||
  658. (ppStillPin == NULL) ||
  659. (ppVideoControl == NULL) ||
  660. (plCaps == NULL))
  661. {
  662. hr = E_POINTER;
  663. CHECK_S_OK2(hr, ("CPreviewGraph::GetStillPinCaps received a NULL "
  664. "param"));
  665. }
  666. if (hr == S_OK)
  667. {
  668. //
  669. // Attempt to find the still pin on the capture filter
  670. // This will decide the type of graph we are going to build
  671. //
  672. hr = m_pCaptureGraphBuilder->FindInterface(&PIN_CATEGORY_STILL,
  673. &MEDIATYPE_Video,
  674. pCaptureFilter,
  675. IID_IPin,
  676. (void **)ppStillPin);
  677. }
  678. if (hr == S_OK)
  679. {
  680. // determine if it is triggerable or not.
  681. hr = m_pCaptureGraphBuilder->FindInterface(&PIN_CATEGORY_STILL,
  682. &MEDIATYPE_Video,
  683. pCaptureFilter,
  684. IID_IAMVideoControl,
  685. (void **)ppVideoControl);
  686. if ((hr == S_OK) && (*ppVideoControl) && (*ppStillPin))
  687. {
  688. hr = (*ppVideoControl)->GetCaps(*ppStillPin, plCaps);
  689. }
  690. if (hr == S_OK)
  691. {
  692. //
  693. // If the still pin cannot be triggered externally or internally
  694. // then it is useless to us, so just ignore it.
  695. //
  696. if (!(*plCaps &
  697. (VideoControlFlag_ExternalTriggerEnable |
  698. VideoControlFlag_Trigger)))
  699. {
  700. *plCaps = 0;
  701. *ppStillPin = NULL;
  702. *ppVideoControl = NULL;
  703. }
  704. }
  705. }
  706. else
  707. {
  708. DBG_PRT(("CPreviewGraph::GetStillPinCaps, Capture Filter does not "
  709. "have a still pin"));
  710. }
  711. return hr;
  712. }
  713. ///////////////////////////////
  714. // AddStillFilterToGraph
  715. //
  716. // Add the WIA Stream Snapshot
  717. // filter to our graph
  718. //
  719. HRESULT CPreviewGraph::AddStillFilterToGraph(LPCWSTR pwszFilterName,
  720. IBaseFilter **ppFilter,
  721. IStillSnapshot **ppSnapshot)
  722. {
  723. DBG_FN("CPreviewGraph::AddStillFilterToGraph");
  724. HRESULT hr = S_OK;
  725. ASSERT(pwszFilterName != NULL);
  726. ASSERT(ppFilter != NULL);
  727. ASSERT(ppSnapshot != NULL);
  728. if ((pwszFilterName == NULL) ||
  729. (ppFilter == NULL) ||
  730. (ppSnapshot == NULL))
  731. {
  732. hr = E_POINTER;
  733. CHECK_S_OK2(hr, ("CPreviewGraph::AddStillFilterToGraph received "
  734. "NULL params"));
  735. }
  736. if (hr == S_OK)
  737. {
  738. //
  739. // Create the still filter
  740. //
  741. hr = CoCreateInstance(CLSID_STILL_FILTER,
  742. NULL,
  743. CLSCTX_INPROC_SERVER,
  744. IID_IBaseFilter,
  745. (void**)ppFilter);
  746. CHECK_S_OK2(hr, ("CPreviewGraph::AddStillFilterToGraph failed to "
  747. "CoCreate Still Image Filter"));
  748. }
  749. if (hr == S_OK)
  750. {
  751. //
  752. // Add the still filter to the graph.
  753. //
  754. hr = m_pGraphBuilder->AddFilter(*ppFilter, pwszFilterName);
  755. CHECK_S_OK2(hr, ("CPreviewGraph::AddStillFilterToGraph failed to "
  756. "add '%ls' filter to the graph", pwszFilterName));
  757. }
  758. if (hr == S_OK)
  759. {
  760. hr = (*ppFilter)->QueryInterface(IID_IStillSnapshot,
  761. (void **)ppSnapshot);
  762. CHECK_S_OK2(hr, ("CPreviewGraph::AddStillFilterToGraph, failed "
  763. "to get IStillSnapshot interface on still filter"));
  764. }
  765. return hr;
  766. }
  767. ///////////////////////////////
  768. // AddColorConverterToGraph
  769. //
  770. // Creates the capture filter
  771. // identified by the device ID
  772. // and returns it.
  773. //
  774. HRESULT CPreviewGraph::AddColorConverterToGraph(LPCWSTR pwszFilterName,
  775. IBaseFilter **ppColorSpaceConverter)
  776. {
  777. HRESULT hr = S_OK;
  778. ASSERT(pwszFilterName != NULL);
  779. ASSERT(ppColorSpaceConverter != NULL);
  780. if ((pwszFilterName == NULL) ||
  781. (ppColorSpaceConverter == NULL))
  782. {
  783. hr = E_POINTER;
  784. CHECK_S_OK2(hr, ("CPreviewGraph::AddColorConverterToGraph, "
  785. "received a NULL pointer"));
  786. return hr;
  787. }
  788. //
  789. // Create the Color Converter filter.
  790. //
  791. if (hr == S_OK)
  792. {
  793. hr = CoCreateInstance(CLSID_Colour,
  794. NULL,
  795. CLSCTX_INPROC_SERVER,
  796. IID_IBaseFilter,
  797. (void**) ppColorSpaceConverter);
  798. CHECK_S_OK2(hr, ("CPreviewGraph::AddColorConverterToGraph failed to "
  799. "create the DShow Color Converter Filter"));
  800. }
  801. if (hr == S_OK)
  802. {
  803. hr = m_pGraphBuilder->AddFilter(*ppColorSpaceConverter, pwszFilterName);
  804. CHECK_S_OK2(hr, ("CPreviewGraph::AddColorConverterToGraph failed to "
  805. "add '%ls' filter to the graph", pwszFilterName));
  806. }
  807. return hr;
  808. }
  809. ///////////////////////////////
  810. // AddVideoRendererToGraph
  811. //
  812. //
  813. HRESULT CPreviewGraph::AddVideoRendererToGraph(LPCWSTR pwszFilterName,
  814. IBaseFilter **ppVideoRenderer)
  815. {
  816. HRESULT hr = S_OK;
  817. ASSERT(pwszFilterName != NULL);
  818. ASSERT(ppVideoRenderer != NULL);
  819. if ((pwszFilterName == NULL) ||
  820. (ppVideoRenderer == NULL))
  821. {
  822. hr = E_POINTER;
  823. CHECK_S_OK2(hr, ("CPreviewGraph::AddVideoRendererToGraph, "
  824. "received a NULL pointer"));
  825. return hr;
  826. }
  827. //
  828. // Create the Video Renderer filter.
  829. //
  830. if (hr == S_OK)
  831. {
  832. BOOL bUseVMR = FALSE;
  833. //
  834. // even if we fail, in the worst case we don't use the vmr filter.
  835. // Not the end of the world.
  836. //
  837. CWiaUtil::GetUseVMR(&bUseVMR);
  838. if (bUseVMR)
  839. {
  840. hr = CoCreateInstance(CLSID_VideoMixingRenderer,
  841. NULL,
  842. CLSCTX_INPROC_SERVER,
  843. IID_IBaseFilter,
  844. (void**) ppVideoRenderer);
  845. }
  846. else
  847. {
  848. hr = CoCreateInstance(CLSID_VideoRenderer,
  849. NULL,
  850. CLSCTX_INPROC_SERVER,
  851. IID_IBaseFilter,
  852. (void**) ppVideoRenderer);
  853. }
  854. CHECK_S_OK2(hr, ("CPreviewGraph::AddVideoRendererToGraph failed to "
  855. "create the DShow Video Renderer Filter"));
  856. }
  857. if (hr == S_OK)
  858. {
  859. hr = m_pGraphBuilder->AddFilter(*ppVideoRenderer, pwszFilterName);
  860. CHECK_S_OK2(hr, ("CPreviewGraph::AddVideoRenderer failed to "
  861. "add '%ls' filter to the graph", pwszFilterName));
  862. }
  863. return hr;
  864. }
  865. ///////////////////////////////
  866. // InitVideoWindows
  867. //
  868. // Initialize the video windows
  869. // so that they don't have
  870. // an owner, and they are not
  871. // visible.
  872. //
  873. HRESULT CPreviewGraph::InitVideoWindows(HWND hwndParent,
  874. IBaseFilter *pCaptureFilter,
  875. IVideoWindow **ppPreviewVideoWindow,
  876. BOOL bStretchToFitParent)
  877. {
  878. DBG_FN("CPreviewGraph::InitVideoWindows");
  879. HRESULT hr = S_OK;
  880. ASSERT(pCaptureFilter != NULL);
  881. ASSERT(ppPreviewVideoWindow != NULL);
  882. if ((pCaptureFilter == NULL) ||
  883. (ppPreviewVideoWindow == NULL))
  884. {
  885. hr = E_POINTER;
  886. CHECK_S_OK2(hr, ("CPreviewGraph::InitVideoWindows received NULL "
  887. "params"));
  888. }
  889. //
  890. // If the still pin exists, make sure that the video renderer hanging
  891. // off of this path in the graph is NOT visible.
  892. //
  893. if (hr == S_OK)
  894. {
  895. if (m_pStillPin)
  896. {
  897. CComPtr<IVideoWindow> pStillVW;
  898. hr = m_pCaptureGraphBuilder->FindInterface(&PIN_CATEGORY_STILL,
  899. &MEDIATYPE_Video,
  900. pCaptureFilter,
  901. IID_IVideoWindow,
  902. (void**)&pStillVW);
  903. CHECK_S_OK2(hr, ("CPreviewGraph::InitVideoWindows failed to "
  904. "find video renderer off of the still "
  905. "filter pin"));
  906. //
  907. // We hide the video renderer attached to the still pin stream
  908. // since it will contain the still image, which we save to a
  909. // file, rather than show it on the desktop.
  910. //
  911. if (hr == S_OK)
  912. {
  913. CDShowUtil::ShowVideo(FALSE, pStillVW);
  914. CDShowUtil::SetVideoWindowParent(NULL, pStillVW, NULL);
  915. }
  916. }
  917. //
  918. // If this fails, it is not fatal
  919. //
  920. hr = S_OK;
  921. }
  922. if (hr == S_OK)
  923. {
  924. //
  925. // Find the video renderer hanging off of the capture pin path in
  926. // the graph and make sure that it is made the child of the
  927. // parent window.
  928. hr = m_pCaptureGraphBuilder->FindInterface(
  929. &PIN_CATEGORY_CAPTURE,
  930. &MEDIATYPE_Video,
  931. pCaptureFilter,
  932. IID_IVideoWindow,
  933. (void **)ppPreviewVideoWindow);
  934. CHECK_S_OK2(hr, ("CPreviewGraph::InitVideoWindows, failed to "
  935. "find video renderer off of capture/preview pin"));
  936. }
  937. if (hr == S_OK)
  938. {
  939. //
  940. // Hide the video window before we set it's parent.
  941. //
  942. CDShowUtil::ShowVideo(FALSE, *ppPreviewVideoWindow);
  943. //
  944. // Set the video window's parent.
  945. //
  946. CDShowUtil::SetVideoWindowParent(hwndParent,
  947. *ppPreviewVideoWindow,
  948. &m_lStyle);
  949. }
  950. return hr;
  951. }
  952. ///////////////////////////////
  953. // CreateCaptureFilter
  954. //
  955. // Creates the capture filter
  956. // identified by the device ID
  957. // and returns it.
  958. //
  959. HRESULT CPreviewGraph::CreateCaptureFilter(IMoniker *pCaptureDeviceMoniker,
  960. IBaseFilter **ppCaptureFilter)
  961. {
  962. DBG_FN("CPreviewGraph::CreateCaptureFilter");
  963. ASSERT(pCaptureDeviceMoniker != NULL);
  964. ASSERT(ppCaptureFilter != NULL);
  965. HRESULT hr = S_OK;
  966. if ((pCaptureDeviceMoniker == NULL) ||
  967. (ppCaptureFilter == NULL))
  968. {
  969. hr = E_POINTER;
  970. CHECK_S_OK2(hr, ("CPreviewGraph::CreateCaptureFilter received NULL "
  971. "params"));
  972. }
  973. #ifdef DEBUG
  974. CDShowUtil::DumpCaptureMoniker(pCaptureDeviceMoniker);
  975. #endif
  976. if (hr == S_OK)
  977. {
  978. hr = pCaptureDeviceMoniker->BindToObject(0,
  979. 0,
  980. IID_IBaseFilter,
  981. (void**)ppCaptureFilter);
  982. CHECK_S_OK2(hr, ("CPreviewGraph::CreateCaptureFilter failed to bind "
  983. "to device's moniker."));
  984. }
  985. return hr;
  986. }
  987. ///////////////////////////////
  988. // AddCaptureFilterToGraph
  989. //
  990. HRESULT CPreviewGraph::AddCaptureFilterToGraph(IBaseFilter *pCaptureFilter,
  991. IPin **ppCapturePin)
  992. {
  993. HRESULT hr = S_OK;
  994. CComPtr<IPin> pCapturePin;
  995. GUID *pMediaSubType = NULL;
  996. LONG lWidth = 0;
  997. LONG lHeight = 0;
  998. LONG lFrameRate = 0;
  999. ASSERT(pCaptureFilter != NULL);
  1000. ASSERT(ppCapturePin != NULL);
  1001. if ((pCaptureFilter == NULL) ||
  1002. (ppCapturePin == NULL))
  1003. {
  1004. hr = E_POINTER;
  1005. CHECK_S_OK2(hr, ("CPreviewGraph::AddCaptureFilterToGraph, received "
  1006. "a NULL pointer"));
  1007. return hr;
  1008. }
  1009. if (SUCCEEDED(hr))
  1010. {
  1011. hr = m_pGraphBuilder->AddFilter(pCaptureFilter,
  1012. L"Capture Filter");
  1013. CHECK_S_OK2(hr, ("CPreviewGraph::AddCaptureFilterToGraph, failed to "
  1014. "add capture filter to graph"));
  1015. }
  1016. //
  1017. // Find the capture pin so we can render it.
  1018. //
  1019. if (SUCCEEDED(hr))
  1020. {
  1021. hr = m_pCaptureGraphBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
  1022. &MEDIATYPE_Video,
  1023. pCaptureFilter,
  1024. IID_IPin,
  1025. (void **)&pCapturePin);
  1026. CHECK_S_OK2(hr, ("CPreviewGraph::AddCaptureFilterToGraph failed to "
  1027. "find Capture pin on capture filter"));
  1028. }
  1029. //
  1030. // Get all the video properties we can about this filter.
  1031. //
  1032. if (SUCCEEDED(hr))
  1033. {
  1034. hr = CDShowUtil::GetVideoProperties(pCaptureFilter,
  1035. pCapturePin,
  1036. m_pVideoProperties);
  1037. }
  1038. //
  1039. // We set the video width and height to the preferred setting size if
  1040. // the driver's inf specifies these settings. If it does not,
  1041. // then if the registery tells us to override the capture filter's
  1042. // default settings, then attempt to set it to 176x144 YUV.
  1043. //
  1044. // This is the order we attempt to set preferences:
  1045. //
  1046. // Preferred Settings --> If don't exist --> Set to Driver Default if within MIN/MAX range
  1047. // --> otherwise attempt to set to MINIMUM width/height.
  1048. //
  1049. if (SUCCEEDED(hr))
  1050. {
  1051. GUID *pDefaultMediaSubType = &m_pVideoProperties->pMediaType->subtype;
  1052. LONG lDefaultWidth = m_pVideoProperties->pVideoInfoHeader->bmiHeader.biWidth;
  1053. LONG lDefaultHeight = m_pVideoProperties->pVideoInfoHeader->bmiHeader.biHeight;
  1054. //
  1055. // Validate default values are valid.
  1056. //
  1057. if ((lDefaultWidth <= MIN_VIDEO_WIDTH) || (lDefaultHeight <= MIN_VIDEO_HEIGHT))
  1058. {
  1059. lDefaultWidth = MIN_VIDEO_WIDTH;
  1060. lDefaultHeight = MIN_VIDEO_HEIGHT;
  1061. }
  1062. else if ((lDefaultWidth > MAX_VIDEO_WIDTH) || (lDefaultHeight > MAX_VIDEO_HEIGHT))
  1063. {
  1064. lDefaultWidth = MIN_VIDEO_WIDTH;
  1065. lDefaultHeight = MIN_VIDEO_HEIGHT;
  1066. }
  1067. //
  1068. // If a preferred media subtype exists, use it, otherwise, use the
  1069. // default specified by the capture filter.
  1070. //
  1071. if (m_pVideoProperties->PreferredSettingsMask & PREFERRED_SETTING_MASK_MEDIASUBTYPE)
  1072. {
  1073. pMediaSubType = &m_pVideoProperties->PreferredMediaSubType;
  1074. DBG_TRC(("Settings: Using preferred media subtype -> dump of actual type is below"));
  1075. }
  1076. else
  1077. {
  1078. pMediaSubType = pDefaultMediaSubType;
  1079. DBG_TRC(("Settings: Using default media subtype, no preferred media subtype "
  1080. "found -> dump of actual type is below"));
  1081. }
  1082. //
  1083. // If the default width and height exist, use it, otherwise use the
  1084. // default width and height, provided they are valid values
  1085. //
  1086. if (m_pVideoProperties->PreferredSettingsMask & PREFERRED_SETTING_MASK_VIDEO_WIDTH_HEIGHT)
  1087. {
  1088. lWidth = m_pVideoProperties->PreferredWidth;
  1089. lHeight = m_pVideoProperties->PreferredHeight;
  1090. //
  1091. // Validate preferred settings are valid. If they are not, then
  1092. // set to default value.
  1093. //
  1094. if ((lWidth < MIN_VIDEO_WIDTH) ||
  1095. (lHeight < MIN_VIDEO_HEIGHT) ||
  1096. (lWidth > MAX_VIDEO_WIDTH) ||
  1097. (lHeight > MAX_VIDEO_HEIGHT))
  1098. {
  1099. DBG_TRC(("Settings: Using default video width and height, preferred settings were invalid "
  1100. "-> Invalid Width = %lu, Invalid Height = %lu", lWidth, lHeight));
  1101. lWidth = lDefaultWidth;
  1102. lHeight = lDefaultHeight;
  1103. }
  1104. else
  1105. {
  1106. DBG_TRC(("Settings: Using preferred settings of video width and height "
  1107. "-> dump of actual size is below"));
  1108. }
  1109. }
  1110. else
  1111. {
  1112. lWidth = lDefaultWidth;
  1113. lHeight = lDefaultHeight;
  1114. }
  1115. hr = CDShowUtil::SetPreferredVideoFormat(pCapturePin,
  1116. pMediaSubType,
  1117. lWidth,
  1118. lHeight,
  1119. m_pVideoProperties);
  1120. if (hr != S_OK)
  1121. {
  1122. DBG_TRC(("Failed to set width = '%lu' and height = '%lu', "
  1123. "attempting to set it to its default settings of "
  1124. "width = '%lu', height = '%lu'",
  1125. lWidth, lHeight, lDefaultWidth, lDefaultHeight));
  1126. hr = CDShowUtil::SetPreferredVideoFormat(pCapturePin,
  1127. pDefaultMediaSubType,
  1128. lDefaultWidth,
  1129. lDefaultHeight,
  1130. m_pVideoProperties);
  1131. }
  1132. if (hr != S_OK)
  1133. {
  1134. hr = S_OK;
  1135. DBG_WRN(("Failed on all attempts to set the preferrences of "
  1136. "the video properties (MediaSubType, width, height). "
  1137. "Attempting to continue anyway"));
  1138. }
  1139. }
  1140. //
  1141. // 6. Attempt to set the frame rate to 30 frames per second. If this
  1142. // fails for some reason, try 15 frames per second. If that fails,
  1143. // then just accept the default and keep going.
  1144. //
  1145. if (SUCCEEDED(hr))
  1146. {
  1147. LONG lDefaultFrameRate = m_pVideoProperties->dwFrameRate;
  1148. if (lDefaultFrameRate < BACKUP_FRAME_RATE)
  1149. {
  1150. lDefaultFrameRate = PREFERRED_FRAME_RATE;
  1151. }
  1152. if (m_pVideoProperties->PreferredSettingsMask & PREFERRED_SETTING_MASK_VIDEO_FRAMERATE)
  1153. {
  1154. lFrameRate = m_pVideoProperties->PreferredFrameRate;
  1155. if (lFrameRate < BACKUP_FRAME_RATE)
  1156. {
  1157. lFrameRate = lDefaultFrameRate;
  1158. }
  1159. }
  1160. else
  1161. {
  1162. lFrameRate = PREFERRED_FRAME_RATE;
  1163. }
  1164. hr = CDShowUtil::SetFrameRate(pCapturePin,
  1165. lFrameRate,
  1166. m_pVideoProperties);
  1167. if (hr != S_OK)
  1168. {
  1169. DBG_WRN(("WARNING: Failed to set frame rate to %lu. "
  1170. "This is not fatal, attempting to set it to %lu, "
  1171. "hr = 0x%08lx",
  1172. lFrameRate,
  1173. BACKUP_FRAME_RATE,
  1174. hr));
  1175. hr = CDShowUtil::SetFrameRate(pCapturePin,
  1176. lDefaultFrameRate,
  1177. m_pVideoProperties);
  1178. if (hr != S_OK)
  1179. {
  1180. DBG_WRN(("WARNING: Failed to set frame rate to %lu. "
  1181. "This is not fatal, continuing to build graph, "
  1182. "hr = 0x%08lx", lDefaultFrameRate, hr));
  1183. }
  1184. }
  1185. //
  1186. // This is a nice to have, but if we can't then continue
  1187. // anyway, better low quality video than no video at all.
  1188. //
  1189. hr = S_OK;
  1190. }
  1191. //
  1192. // Set the picture and camera attributes to our preferred settings,
  1193. // if we can.
  1194. //
  1195. if (SUCCEEDED(hr))
  1196. {
  1197. //
  1198. // If this camera supports setting the picture attributes, then
  1199. // lets make sure that we set the ones we are interested in.
  1200. //
  1201. // This uses the DShow IAMVideoProcAmp interface
  1202. //
  1203. if (m_pVideoProperties->bPictureAttributesUsed)
  1204. {
  1205. //
  1206. // Make sure we are outputing color video (as opposed to black and white)
  1207. //
  1208. hr = CDShowUtil::SetPictureAttribute(pCaptureFilter,
  1209. &m_pVideoProperties->ColorEnable,
  1210. (LONG) TRUE,
  1211. VideoProcAmp_Flags_Manual);
  1212. //
  1213. // Turn on backlight compensation, to get the best video we can.
  1214. //
  1215. hr = CDShowUtil::SetPictureAttribute(pCaptureFilter,
  1216. &m_pVideoProperties->BacklightCompensation,
  1217. (LONG) TRUE,
  1218. VideoProcAmp_Flags_Manual);
  1219. //
  1220. // Make sure white balance is set to auto
  1221. //
  1222. hr = CDShowUtil::SetPictureAttribute(pCaptureFilter,
  1223. &m_pVideoProperties->WhiteBalance,
  1224. m_pVideoProperties->WhiteBalance.lCurrentValue,
  1225. VideoProcAmp_Flags_Auto);
  1226. }
  1227. //
  1228. // If the camera supports setting the camera attributes, then set the
  1229. // camera attributes we are interested in.
  1230. //
  1231. if (m_pVideoProperties->bCameraAttributesUsed)
  1232. {
  1233. //
  1234. // Turn on auto exposure.
  1235. //
  1236. hr = CDShowUtil::SetCameraAttribute(pCaptureFilter,
  1237. &m_pVideoProperties->Exposure,
  1238. m_pVideoProperties->Exposure.lCurrentValue,
  1239. CameraControl_Flags_Auto);
  1240. }
  1241. hr = S_OK;
  1242. }
  1243. //
  1244. // Dump the video properties
  1245. //
  1246. CDShowUtil::MyDumpVideoProperties(m_pVideoProperties);
  1247. if (SUCCEEDED(hr))
  1248. {
  1249. *ppCapturePin = pCapturePin;
  1250. (*ppCapturePin)->AddRef();
  1251. }
  1252. return hr;
  1253. }
  1254. ///////////////////////////////
  1255. // ConnectFilters
  1256. //
  1257. // This function connects the
  1258. // capture filter's still pin
  1259. // or it's capture pin to the
  1260. // color space converter. It
  1261. // then connects the color space
  1262. // converter to the WIA Stream
  1263. // snapshot filter. Last, it
  1264. // renders the WIA Stream Snapshot
  1265. // filter to bring in any remaining
  1266. // required filters (such as the
  1267. // video renderer)
  1268. //
  1269. HRESULT CPreviewGraph::ConnectFilters(IGraphBuilder *pGraphBuilder,
  1270. IPin *pMediaSourceOutputPin,
  1271. IBaseFilter *pColorSpaceFilter,
  1272. IBaseFilter *pWiaFilter,
  1273. IBaseFilter *pVideoRenderer)
  1274. {
  1275. HRESULT hr = S_OK;
  1276. CComPtr<IPin> pOutputPinToConnect;
  1277. ASSERT(pGraphBuilder != NULL);
  1278. ASSERT(pMediaSourceOutputPin != NULL);
  1279. ASSERT(pVideoRenderer != NULL);
  1280. if ((pGraphBuilder == NULL) ||
  1281. (pMediaSourceOutputPin == NULL) ||
  1282. (pVideoRenderer == NULL))
  1283. {
  1284. hr = E_POINTER;
  1285. CHECK_S_OK2(hr, ("CPreviewGraph::ConnectFilters received a NULL pointer"));
  1286. }
  1287. pOutputPinToConnect = pMediaSourceOutputPin;
  1288. DBG_TRC(("CPreviewGraph::ConnectFilters, PinToRender is the "
  1289. "Capture Filter's Output Pin"));
  1290. if (pColorSpaceFilter)
  1291. {
  1292. CComPtr<IPin> pColorInputPin;
  1293. CComPtr<IPin> pColorOutputPin;
  1294. //
  1295. // Get the input pin on the color space filter.
  1296. //
  1297. if (hr == S_OK)
  1298. {
  1299. hr = CDShowUtil::GetPin(pColorSpaceFilter,
  1300. PINDIR_INPUT,
  1301. &pColorInputPin);
  1302. CHECK_S_OK2(hr, ("CPreviewGraph::ConnectFilters, failed to get the "
  1303. "color space converter's input pin"));
  1304. }
  1305. //
  1306. // Connect the Capture Filter's output pin to the color space
  1307. // converter's input pin.
  1308. //
  1309. if (hr == S_OK)
  1310. {
  1311. hr = pGraphBuilder->Connect(pMediaSourceOutputPin,
  1312. pColorInputPin);
  1313. CHECK_S_OK2(hr, ("CPreviewGraph::ConnectFilters, failed to connect the "
  1314. "capture filter's pin to the color space converter pin"));
  1315. }
  1316. //
  1317. // Get the output pin on the color space converter.
  1318. //
  1319. if (hr == S_OK)
  1320. {
  1321. hr = CDShowUtil::GetPin(pColorSpaceFilter,
  1322. PINDIR_OUTPUT,
  1323. &pColorOutputPin);
  1324. CHECK_S_OK2(hr, ("CPreviewGraph::ConnectFilters, failed to get the "
  1325. "color space converter's output pin"));
  1326. }
  1327. if (hr == S_OK)
  1328. {
  1329. pOutputPinToConnect = pColorOutputPin;
  1330. DBG_TRC(("CPreviewGraph::ConnectFilters, PinToRender is the "
  1331. "Color Space Converter's Output Pin"));
  1332. }
  1333. //
  1334. // If this fails, so what. Try to connect WIA Stream Snapshot
  1335. // filter anyway.
  1336. //
  1337. hr = S_OK;
  1338. }
  1339. if (pWiaFilter)
  1340. {
  1341. CComPtr<IPin> pWiaInputPin;
  1342. CComPtr<IPin> pWiaOutputPin;
  1343. //
  1344. // Get the input pin on the WIA Stream Snapshot filter.
  1345. //
  1346. if (hr == S_OK)
  1347. {
  1348. hr = CDShowUtil::GetPin(pWiaFilter,
  1349. PINDIR_INPUT,
  1350. &pWiaInputPin);
  1351. CHECK_S_OK2(hr, ("CPreviewGraph::ConnectFilters, failed to get the "
  1352. "WIA Stream Snapshot filter's input pin"));
  1353. }
  1354. //
  1355. // Connect the output pin of the color space converter to the input
  1356. // pin on the WIA Stream Snapshot filter.
  1357. //
  1358. if (hr == S_OK)
  1359. {
  1360. hr = pGraphBuilder->Connect(pOutputPinToConnect,
  1361. pWiaInputPin);
  1362. CHECK_S_OK2(hr, ("CPreviewGraph::ConnectFilters, failed to connect the "
  1363. "pin to render to the WIA Stream Snapshot "
  1364. "input pin"));
  1365. }
  1366. //
  1367. // Get the output pin on the WIA Stream Snapshot filter.
  1368. //
  1369. if (hr == S_OK)
  1370. {
  1371. hr = CDShowUtil::GetPin(pWiaFilter,
  1372. PINDIR_OUTPUT,
  1373. &pWiaOutputPin);
  1374. CHECK_S_OK2(hr, ("CPreviewGraph::ConnectFilters, failed to get the "
  1375. "WIA Stream Snapshot filter's output pin"));
  1376. }
  1377. if (hr == S_OK)
  1378. {
  1379. pOutputPinToConnect = pWiaOutputPin;
  1380. DBG_TRC(("CPreviewGraph::ConnectFilters, PinToRender is the "
  1381. "WIA Stream Snapshot Filter's Output Pin"));
  1382. }
  1383. }
  1384. //
  1385. // Render the output pin of the WIA Stream Snapshot filter.
  1386. // This completes the graph building process.
  1387. //
  1388. if (hr == S_OK)
  1389. {
  1390. CComPtr<IPin> pVideoRendererInputPin;
  1391. //
  1392. // Get the input pin on the WIA Stream Snapshot filter.
  1393. //
  1394. if (hr == S_OK)
  1395. {
  1396. hr = CDShowUtil::GetPin(pVideoRenderer,
  1397. PINDIR_INPUT,
  1398. &pVideoRendererInputPin);
  1399. CHECK_S_OK2(hr, ("CPreviewGraph::ConnectFilters, failed to get the "
  1400. "WIA Stream Snapshot filter's input pin"));
  1401. }
  1402. //
  1403. // Connect the output pin of the color space converter to the input
  1404. // pin on the WIA Stream Snapshot filter.
  1405. //
  1406. if (hr == S_OK)
  1407. {
  1408. hr = pGraphBuilder->Connect(pOutputPinToConnect,
  1409. pVideoRendererInputPin);
  1410. CHECK_S_OK2(hr, ("CPreviewGraph::ConnectFilters, failed to connect the "
  1411. "pin to render to the Video Renderer "
  1412. "input pin"));
  1413. }
  1414. }
  1415. pOutputPinToConnect = NULL;
  1416. return hr;
  1417. }
  1418. ///////////////////////////////
  1419. // BuildPreviewGraph
  1420. //
  1421. // This builds the preview graph
  1422. // based on the device ID we
  1423. // pass it.
  1424. //
  1425. HRESULT CPreviewGraph::BuildPreviewGraph(IMoniker *pCaptureDeviceMoniker,
  1426. BOOL bStretchToFitParent)
  1427. {
  1428. DBG_FN("CPreviewGraph::BuildPreviewGraph");
  1429. ASSERT(pCaptureDeviceMoniker != NULL);
  1430. HRESULT hr = S_OK;
  1431. CComPtr<IPin> pCapturePin;
  1432. if (pCaptureDeviceMoniker == NULL)
  1433. {
  1434. hr = E_POINTER;
  1435. CHECK_S_OK2(hr, ("ERROR: CPreviewGraph::BuildPreviewGraph "
  1436. "received a NULL param"));
  1437. return hr;
  1438. }
  1439. //
  1440. // This function will build one of three possible graphs.
  1441. //
  1442. // (1) The capture filter does NOT have a
  1443. // still pin on it (or if it does it is useless because
  1444. // it is not triggerable either via hardware, or programmatically)
  1445. //
  1446. // CaptureFilter(Capture Pin) -> Decoder -> Color Converter -> WIA StreamSnapshot -> Renderer
  1447. //
  1448. // (2) The capture filter has a still pin that is programmatically
  1449. // triggerable.
  1450. //
  1451. // CaptureFilter(CapturePin) -> Decoder -> Video Renderer
  1452. // (StillPin) -> Decoder -> Color Converter -> WIA StreamSnapshot -> Renderer
  1453. //
  1454. // (3) The capture filter has a still pin, but it is only
  1455. // triggered via external hardware button. In this case, if we
  1456. // trigger a snapshot programmatically, the image comes from
  1457. // the WIA Snapshot filter off of the Capture/Preview Pin.
  1458. // If the hardware button is pressed, the image comes from the
  1459. // WIA snapshot filter off of the StillPin.
  1460. //
  1461. // CaptureFilter(CapturePin) -> Decoder -> Color Converter -> WIA StreamSnapshot -> Renderer
  1462. // (StillPin) -> Decoder -> Color Converter -> WIA StreamSnapshot -> Renderer
  1463. //
  1464. //
  1465. DBG_TRC(("CPreviewGraph::BuildPreviewGraph - Starting to build preview "
  1466. "graph"));
  1467. //
  1468. // 1. Create the capture filter based on the device ID we were given.
  1469. //
  1470. if (SUCCEEDED(hr))
  1471. {
  1472. hr = CreateCaptureFilter(pCaptureDeviceMoniker,
  1473. &m_pCaptureFilter); // passed by ref
  1474. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1475. "create capture filter"));
  1476. }
  1477. //
  1478. // 2. Create the DShow graph builder objects allowing us to
  1479. // manipulate the graph.
  1480. //
  1481. if (SUCCEEDED(hr))
  1482. {
  1483. hr = CDShowUtil::CreateGraphBuilder(&m_pCaptureGraphBuilder,
  1484. &m_pGraphBuilder);
  1485. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1486. "create DShow graph builder object"));
  1487. }
  1488. //
  1489. // 3. Add the capture filter to the graph.
  1490. //
  1491. if (SUCCEEDED(hr))
  1492. {
  1493. hr = AddCaptureFilterToGraph(m_pCaptureFilter, &pCapturePin);
  1494. }
  1495. //
  1496. // 4. Get the Still Pin capabilities of the capture filter (if it has a
  1497. // still pin at all)
  1498. //
  1499. if (SUCCEEDED(hr))
  1500. {
  1501. hr = GetStillPinCaps(m_pCaptureFilter,
  1502. &m_pStillPin,
  1503. &m_pVideoControl,
  1504. &m_lStillPinCaps);
  1505. if (hr != S_OK)
  1506. {
  1507. //
  1508. // This is not an error condition, it simply means that the
  1509. // capture filter does not have a still pin on it. That's
  1510. // okay, we can deal with that below.
  1511. //
  1512. hr = S_OK;
  1513. }
  1514. }
  1515. //
  1516. // Render the preview/capture stream.
  1517. // ==================================
  1518. //
  1519. // If we don't have a still pin, or the still pin cannot be internally
  1520. // triggered, we build the following preview graph.
  1521. //
  1522. // CaptureFilter(Capture Pin) -> Decoder -> WIA StreamSnapshot -> Renderer
  1523. //
  1524. // If we do have a still pin, and it is internally triggerable, then
  1525. // we build the following preview graph (and add the still filter to the
  1526. // still pin)
  1527. //
  1528. // CaptureFilter(CapturePin) -> Decoder -> WIA StreamSnapshot -> Renderer
  1529. // (StillPin) -> Decoder -> WIA StreamSnapshot -> Renderer
  1530. //
  1531. //
  1532. // 5. If we don't have a still pin, or it is only externally triggerable
  1533. // then add the WIA StreamSnapshot Filter to the preview/capture pin.
  1534. //
  1535. if ((m_pStillPin == NULL) ||
  1536. (m_lStillPinCaps & VideoControlFlag_Trigger) == 0)
  1537. {
  1538. CComPtr<IBaseFilter> pWiaFilter;
  1539. CComPtr<IBaseFilter> pColorSpaceConverter;
  1540. CComPtr<IBaseFilter> pVideoRenderer;
  1541. DBG_TRC(("CPreviewGraph::BuildPreviewGraph, capture filter does NOT have "
  1542. "a still pin, image captures will be triggered "
  1543. "through the WIA Snapshot filter"));
  1544. if (hr == S_OK)
  1545. {
  1546. hr = AddColorConverterToGraph(L"Color Converter on Capture Pin Graph",
  1547. &pColorSpaceConverter);
  1548. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1549. "add Color Converter to graph"));
  1550. //
  1551. // Even if this fails, we still may be able to successfully build
  1552. // a graph, so attempt to continue.
  1553. //
  1554. hr = S_OK;
  1555. }
  1556. if (hr == S_OK)
  1557. {
  1558. hr = AddStillFilterToGraph(L"Still Filter On Capture",
  1559. &pWiaFilter,
  1560. &m_pCapturePinSnapshot);
  1561. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1562. "add 'Still Filter On Capture' to graph"));
  1563. }
  1564. if (hr == S_OK)
  1565. {
  1566. hr = AddVideoRendererToGraph(L"Video Renderer On Capture",
  1567. &pVideoRenderer);
  1568. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1569. "add 'Video Renderer On Capture' to graph"));
  1570. }
  1571. if (hr == S_OK)
  1572. {
  1573. //
  1574. // Connect as follows:
  1575. //
  1576. // Capture Filter --> Color Space Converter --> WIA Stream Snapshot Filter
  1577. //
  1578. hr = ConnectFilters(m_pGraphBuilder,
  1579. pCapturePin,
  1580. pColorSpaceConverter,
  1581. pWiaFilter,
  1582. pVideoRenderer);
  1583. }
  1584. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1585. "add still filter to graph off of the capture pin"));
  1586. }
  1587. else
  1588. {
  1589. CComPtr<IBaseFilter> pColorSpaceConverter;
  1590. CComPtr<IBaseFilter> pVideoRenderer;
  1591. if (hr == S_OK)
  1592. {
  1593. hr = AddColorConverterToGraph(L"Color Converter on Capture Pin Graph",
  1594. &pColorSpaceConverter);
  1595. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1596. "add Color Converter to graph"));
  1597. //
  1598. // Even if this fails, we still should be able to build the graph,
  1599. // so continue.
  1600. //
  1601. hr = S_OK;
  1602. }
  1603. if (hr == S_OK)
  1604. {
  1605. hr = AddVideoRendererToGraph(L"Video Renderer On Capture",
  1606. &pVideoRenderer);
  1607. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1608. "add 'Video Renderer On Capture' to graph"));
  1609. }
  1610. //
  1611. // Still Pin exists, and it is triggerable, so simply render
  1612. // the capture pin. We connect the Still Pin below
  1613. //
  1614. hr = ConnectFilters(m_pGraphBuilder,
  1615. pCapturePin,
  1616. pColorSpaceConverter,
  1617. NULL,
  1618. pVideoRenderer);
  1619. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to connect "
  1620. "filters to render capture pin, therefore won't see video"));
  1621. }
  1622. CDShowUtil::MyDumpGraph(TEXT("Capture Graph before processing Still Pin (if exists)"),
  1623. m_pGraphBuilder);
  1624. //
  1625. // Render the Still Pin stream
  1626. // ===========================
  1627. //
  1628. // If we have a still pin, then add the still filter to the
  1629. // graph, and render the still pin. This will produce the
  1630. // following graph:
  1631. //
  1632. // CaptureFilter(StillPin) -> Decoder -> StillFilter -> Renderer (hidden)
  1633. //
  1634. // 6. Now add the WIA Stream Snapshot filter to the still pin if it
  1635. // exists.
  1636. //
  1637. if (SUCCEEDED(hr) && (m_pStillPin))
  1638. {
  1639. CComPtr<IBaseFilter> pWiaFilter;
  1640. CComPtr<IBaseFilter> pColorSpaceConverter;
  1641. CComPtr<IBaseFilter> pVideoRenderer;
  1642. if (hr == S_OK)
  1643. {
  1644. hr = AddColorConverterToGraph(L"Color Converter on Still Pin Graph",
  1645. &pColorSpaceConverter);
  1646. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1647. "add Color Converter to graph"));
  1648. //
  1649. // This is not fatail if we fail. Ideally we would like it in
  1650. // here, but try going on anyway, in case we can succeed without
  1651. // this filter.
  1652. //
  1653. hr = S_OK;
  1654. }
  1655. if (hr == S_OK)
  1656. {
  1657. hr = AddStillFilterToGraph(L"Still filter on Still",
  1658. &pWiaFilter,
  1659. &m_pStillPinSnapshot);
  1660. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to add "
  1661. "'Still filter on Still' filter to the graph. "
  1662. "Probably won't be able to capture still images"));
  1663. }
  1664. if (hr == S_OK)
  1665. {
  1666. hr = AddVideoRendererToGraph(L"Video Renderer On Still",
  1667. &pVideoRenderer);
  1668. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1669. "add 'Video Renderer On Still' to graph"));
  1670. }
  1671. if (hr == S_OK)
  1672. {
  1673. //
  1674. // Connect as follows:
  1675. //
  1676. // Capture Filter --> Color Space Converter --> WIA Stream Snapshot Filter
  1677. //
  1678. hr = ConnectFilters(m_pGraphBuilder,
  1679. m_pStillPin,
  1680. pColorSpaceConverter,
  1681. pWiaFilter,
  1682. pVideoRenderer);
  1683. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1684. "connect graph to Still Pin on Capture Filter. "
  1685. "This will prevent us from capturing still images"));
  1686. }
  1687. }
  1688. CDShowUtil::MyDumpGraph(TEXT("*** Complete Graph ***"), m_pGraphBuilder);
  1689. //
  1690. // 7. Turn off the graph's clock. We do this in case some frames are
  1691. // delivered late, at least they will still be delivered, the graph
  1692. // won't drop them. Since we don't have any sound, we can do this
  1693. // without worrying about losing sync with our sound.
  1694. //
  1695. if (SUCCEEDED(hr))
  1696. {
  1697. hr = CDShowUtil::TurnOffGraphClock(m_pGraphBuilder);
  1698. if (hr != S_OK)
  1699. {
  1700. DBG_WRN(("CPreviewGraph::BuildPreviewGraph, failed to turn off the "
  1701. "graph clock. This is not fatal, continuing..., hr = 0x%lx",
  1702. hr));
  1703. hr = S_OK;
  1704. }
  1705. }
  1706. //
  1707. // 8. Register ourselves with the WIA StreamSnapshot Filter so that
  1708. // a callback of ours will be called if a still image is available.
  1709. //
  1710. if (SUCCEEDED(hr))
  1711. {
  1712. //
  1713. // the graph is ready to run. Initialize still filter and
  1714. // register callback to get notification for new snapshots.
  1715. //
  1716. if (m_pCapturePinSnapshot)
  1717. {
  1718. m_pCapturePinSnapshot->SetSamplingSize(
  1719. CAPTURE_NUM_SAMPLES_TO_CACHE);
  1720. }
  1721. if (m_pStillPinSnapshot)
  1722. {
  1723. m_pStillPinSnapshot->SetSamplingSize(STILL_NUM_SAMPLES_TO_CACHE);
  1724. }
  1725. hr = m_StillProcessor.RegisterStillProcessor(m_pCapturePinSnapshot,
  1726. m_pStillPinSnapshot);
  1727. CHECK_S_OK2(hr, ("CPreviewGraph::BuildPreviewGraph, failed to "
  1728. "register our still processor's callback fn"));
  1729. }
  1730. //
  1731. // 9. Get the Video Renderer window off of the preview/capture pin.
  1732. // This will allow us to control the renderer position, size, etc.
  1733. //
  1734. if (SUCCEEDED(hr))
  1735. {
  1736. hr = InitVideoWindows(m_hwndParent,
  1737. m_pCaptureFilter,
  1738. &m_pPreviewVW,
  1739. bStretchToFitParent);
  1740. }
  1741. return hr;
  1742. }
  1743. ///////////////////////////////
  1744. // TeardownPreviewGraph
  1745. //
  1746. HRESULT CPreviewGraph::TeardownPreviewGraph()
  1747. {
  1748. DBG_FN("CPreviewGraph::TeardownPreviewGraph");
  1749. HRESULT hr = S_OK;
  1750. m_pStillPin = NULL;
  1751. m_pVideoControl = NULL;
  1752. m_pStillPinSnapshot = NULL;
  1753. m_pCapturePinSnapshot = NULL;
  1754. if (m_pPreviewVW)
  1755. {
  1756. CDShowUtil::ShowVideo(FALSE, m_pPreviewVW);
  1757. CDShowUtil::SetVideoWindowParent(NULL, m_pPreviewVW, &m_lStyle);
  1758. m_pPreviewVW = NULL;
  1759. }
  1760. //
  1761. // Remove all the filters from the graph.
  1762. //
  1763. if (m_pGraphBuilder)
  1764. {
  1765. RemoveAllFilters();
  1766. }
  1767. CDShowUtil::MyDumpGraph(TEXT("Graph after removing all filters ")
  1768. TEXT("(should be empty)"),
  1769. m_pGraphBuilder);
  1770. m_pCaptureGraphBuilder = NULL;
  1771. m_pGraphBuilder = NULL;
  1772. m_pCaptureFilter = NULL;
  1773. return hr;
  1774. }
  1775. ///////////////////////////////
  1776. // RemoveAllFilters
  1777. //
  1778. // Notice this function makes no
  1779. // attempt to disconnect each filter
  1780. // before removing it. According to
  1781. // MSDN, you do not need to disconnect
  1782. // a filter before removing it, you only
  1783. // need to ensure that the graph is stopped.
  1784. //
  1785. HRESULT CPreviewGraph::RemoveAllFilters()
  1786. {
  1787. ASSERT(m_pGraphBuilder != NULL);
  1788. HRESULT hr = S_OK;
  1789. CComPtr<IEnumFilters> pEnum = NULL;
  1790. DWORD dwRefCount = 0;
  1791. BOOL bDone = FALSE;
  1792. if (m_pGraphBuilder == NULL)
  1793. {
  1794. hr = E_POINTER;
  1795. CHECK_S_OK2(hr, ("CPreviewGraph::RemoveAllFilters, m_pGraphBuilder "
  1796. "is NULL, cannot remove filters"));
  1797. }
  1798. if (hr == S_OK)
  1799. {
  1800. hr = m_pGraphBuilder->EnumFilters(&pEnum);
  1801. }
  1802. if (pEnum)
  1803. {
  1804. // enumerate each filter.
  1805. while (!bDone)
  1806. {
  1807. CComPtr<IBaseFilter> pFilter = NULL;
  1808. DWORD dwNumFetched = 0;
  1809. //
  1810. // Notice we reset our enumeration on every iteration since
  1811. // the act of removing a filter from the graph may do some
  1812. // funny things, so we really want to always remove the first
  1813. // filter we get from the list until the list is empty.
  1814. //
  1815. hr = pEnum->Reset();
  1816. if (hr == S_OK)
  1817. {
  1818. hr = pEnum->Next(1, &pFilter, &dwNumFetched);
  1819. }
  1820. if (hr == S_OK)
  1821. {
  1822. //
  1823. // This will disconnect the filter's pins and remove
  1824. // it from the graph. If this fails, we want to get out
  1825. // of the loop because otherwise we'll be in an endless loop
  1826. // since we failed to remove the filter, then we reset our
  1827. // enum and get the next filter, which will be this
  1828. // filter again.
  1829. //
  1830. hr = m_pGraphBuilder->RemoveFilter(pFilter);
  1831. CHECK_S_OK2(hr, ("CPreviewGraph::RemoveAllFilters, "
  1832. "RemoveFilter failed"));
  1833. //
  1834. // Release our ref count.
  1835. //
  1836. pFilter = NULL;
  1837. }
  1838. if (hr != S_OK)
  1839. {
  1840. bDone = TRUE;
  1841. }
  1842. }
  1843. }
  1844. hr = S_OK;
  1845. return hr;
  1846. }
  1847. //////////////////////////////////////////////////////////////////////
  1848. // HandlePowerEvent
  1849. //
  1850. LRESULT CPreviewGraph::HandlePowerEvent(WPARAM wParam,
  1851. LPARAM lParam)
  1852. {
  1853. LRESULT iReturn = TRUE;
  1854. if (wParam == PBT_APMQUERYSUSPEND)
  1855. {
  1856. if (GetState() != WIAVIDEO_NO_VIDEO)
  1857. {
  1858. iReturn = BROADCAST_QUERY_DENY;
  1859. }
  1860. }
  1861. return iReturn;
  1862. }
  1863. ///////////////////////////////
  1864. // CreateHiddenWindow
  1865. //
  1866. // Used to handle power management
  1867. // messages.
  1868. //
  1869. HRESULT CPreviewGraph::CreateHiddenWindow()
  1870. {
  1871. HRESULT hr = S_OK;
  1872. WNDCLASSEX wc = {0};
  1873. wc.style = 0;
  1874. wc.cbSize = sizeof(wc);
  1875. wc.lpfnWndProc = HiddenWndProc;
  1876. wc.cbClsExtra = 0;
  1877. wc.cbWndExtra = sizeof(this);
  1878. wc.hInstance = _Module.GetModuleInstance();
  1879. wc.hIcon = NULL;
  1880. wc.hIconSm = NULL;
  1881. wc.hCursor = 0;
  1882. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  1883. wc.lpszMenuName = 0;
  1884. wc.lpszClassName = TEXT("WIAVIDEO_POWERMGMT");
  1885. RegisterClassEx(&wc);
  1886. m_hwndPowerMgmt = CreateWindowEx(0,
  1887. TEXT("WIAVIDEO_POWERMGMT"),
  1888. TEXT("WIAVIDEO_POWERMGMT"),
  1889. 0,
  1890. 0,
  1891. 0,
  1892. 0,
  1893. 0,
  1894. NULL,
  1895. NULL,
  1896. _Module.GetModuleInstance(),
  1897. this);
  1898. return hr;
  1899. }
  1900. ///////////////////////////////
  1901. // DestroyHiddenWindow
  1902. //
  1903. HRESULT CPreviewGraph::DestroyHiddenWindow()
  1904. {
  1905. HRESULT hr = S_OK;
  1906. if (m_hwndPowerMgmt)
  1907. {
  1908. SendMessage(m_hwndPowerMgmt, WM_CLOSE, 0, 0);
  1909. }
  1910. m_hwndPowerMgmt = NULL;
  1911. return hr;
  1912. }
  1913. //////////////////////////////////////////////////////////////////////
  1914. // HiddenWndProc
  1915. //
  1916. // Static Function
  1917. //
  1918. LRESULT CALLBACK CPreviewGraph::HiddenWndProc(HWND hwnd,
  1919. UINT uiMessage,
  1920. WPARAM wParam,
  1921. LPARAM lParam)
  1922. {
  1923. LRESULT iReturn = 0;
  1924. switch (uiMessage)
  1925. {
  1926. case WM_CREATE:
  1927. {
  1928. CREATESTRUCT *pCreateInfo = reinterpret_cast<CREATESTRUCT*>(lParam);
  1929. if (pCreateInfo)
  1930. {
  1931. SetWindowLongPtr(hwnd, 0, reinterpret_cast<LONG_PTR>(pCreateInfo->lpCreateParams));
  1932. }
  1933. }
  1934. break;
  1935. case WM_POWERBROADCAST:
  1936. {
  1937. CPreviewGraph *pPreviewGraph = NULL;
  1938. pPreviewGraph = reinterpret_cast<CPreviewGraph*>(GetWindowLongPtr(hwnd, 0));
  1939. if (pPreviewGraph)
  1940. {
  1941. iReturn = pPreviewGraph->HandlePowerEvent(wParam, lParam);
  1942. }
  1943. }
  1944. break;
  1945. case WM_CLOSE:
  1946. DestroyWindow(hwnd);
  1947. break;
  1948. default:
  1949. iReturn = DefWindowProc(hwnd,
  1950. uiMessage,
  1951. wParam,
  1952. lParam);
  1953. break;
  1954. }
  1955. return iReturn;
  1956. }