PageRenderTime 55ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/Core/Dependencies/Media SDK 2012/samples/sample_dshow_player/src/dshowplayer.cpp

https://bitbucket.org/barakianc/nvidia-physx-and-apex-in-gge
C++ | 1327 lines | 871 code | 269 blank | 187 comment | 175 complexity | b0fa05b82ced392ce02c0881180a9443 MD5 | raw file
  1. /* /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // INTEL CORPORATION PROPRIETARY INFORMATION
  4. // This software is supplied under the terms of a license agreement or
  5. // nondisclosure agreement with Intel Corporation and may not be copied
  6. // or disclosed except in accordance with the terms of that agreement.
  7. // Copyright(c) 2008-2011 Intel Corporation. All Rights Reserved.
  8. //
  9. //
  10. */
  11. //////////////////////////////////////////////////////////////////////////
  12. // DShowPlayer.cpp: Implements DirectShow playback functionality.
  13. //
  14. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  15. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  16. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  17. // PARTICULAR PURPOSE.
  18. //
  19. // Copyright (c) Microsoft Corporation. All rights reserved.
  20. //
  21. //////////////////////////////////////////////////////////////////////////
  22. #include "stdafx.h"
  23. #include "DShowPlayer.h"
  24. #include "DshowUtil.h"
  25. #include "dvdmedia.h"
  26. #include "wmsysprf.h"
  27. #include <dshow.h>
  28. #include <initguid.h>
  29. #include <qnetwork.h>
  30. HRESULT RemoveUnconnectedRenderer(IGraphBuilder *pGraph, IBaseFilter *pRenderer, BOOL *pbRemoved);
  31. HRESULT InitWindowlessVMR(IBaseFilter *pVMR, HWND hwnd, IMFVideoDisplayControl** ppWc);
  32. //-----------------------------------------------------------------------------
  33. // DShowPlayer constructor.
  34. //-----------------------------------------------------------------------------
  35. DShowPlayer::DShowPlayer(HWND hwndVideo) :
  36. m_state(STATE_CLOSED),
  37. m_hwndVideo(hwndVideo),
  38. m_hwndEvent(NULL),
  39. m_EventMsg(0),
  40. m_pGraph(NULL),
  41. m_pControl(NULL),
  42. m_pEvent(NULL),
  43. m_pSeek(NULL),
  44. m_pWindowless(NULL),
  45. m_pCustomPresenter(NULL),
  46. m_pAudio(NULL),
  47. m_seekCaps(0),
  48. m_bMute(FALSE),
  49. m_lVolume(MAX_VOLUME)
  50. {
  51. }
  52. //-----------------------------------------------------------------------------
  53. // DShowPlayer destructor.
  54. //-----------------------------------------------------------------------------
  55. DShowPlayer::~DShowPlayer()
  56. {
  57. TearDownGraph();
  58. }
  59. //-----------------------------------------------------------------------------
  60. // DShowPlayer::SetEventWindow
  61. // Description: Set the window to receive graph events.
  62. //
  63. // hwnd: Window to receive the events.
  64. // msg: Private window message that window will receive whenever a
  65. // graph event occurs. (Must be in the range WM_APP through 0xBFFF.)
  66. //-----------------------------------------------------------------------------
  67. HRESULT DShowPlayer::SetEventWindow(HWND hwnd, UINT msg)
  68. {
  69. m_hwndEvent = hwnd;
  70. m_EventMsg = msg;
  71. return S_OK;
  72. }
  73. HRESULT DShowPlayer::TranscodeFile(const WCHAR* sSrcFileName, const WCHAR* sDstFileName, INT nType)
  74. {
  75. HRESULT hr = S_OK;
  76. IBaseFilter *pSource = NULL;
  77. IBaseFilter* pSplitter = NULL;
  78. IBaseFilter* pVideoDecoder = NULL;
  79. IBaseFilter* pAudioDecoder = NULL;
  80. IBaseFilter* pVideoEncoder = NULL;
  81. IBaseFilter* pAudioEncoder = NULL;
  82. IBaseFilter* pMuxer = NULL;
  83. IBaseFilter* pFileWriter = NULL;
  84. IFileSourceFilter *pFileSourceAsync = NULL;
  85. IFileSourceFilter* pWNMASFReader = NULL;
  86. // Create a new filter graph. (This also closes the old one, if any.)
  87. hr = InitializeGraph();
  88. // Add the source filter to the graph.
  89. if (SUCCEEDED(hr))
  90. {
  91. hr = AddFilterByCLSID(m_pGraph, CLSID_AsyncReader, &pSource, L"File Source Async");
  92. }
  93. if (SUCCEEDED(hr))
  94. {
  95. pSource->QueryInterface(IID_IFileSourceFilter, (void**)&pFileSourceAsync);
  96. hr = pFileSourceAsync->Load(sSrcFileName, NULL);
  97. MSDK_SAFE_RELEASE(pFileSourceAsync);
  98. }
  99. //connect source to splitter
  100. if (SUCCEEDED(hr))
  101. {
  102. hr = ConnectFilterToFilter(pSource, &pSplitter, SPLITTER);
  103. }
  104. //if connect to splitter failed suppose that file is wmv
  105. if (FAILED(hr) && pSource)
  106. {
  107. LPOLESTR strFileName = NULL;
  108. hr = pSource->QueryInterface(IID_IFileSourceFilter, (void**)&pWNMASFReader);
  109. if (SUCCEEDED(hr))
  110. {
  111. hr = pWNMASFReader->GetCurFile(&strFileName, NULL);
  112. MSDK_SAFE_RELEASE(pWNMASFReader);
  113. }
  114. if (SUCCEEDED(hr))
  115. {
  116. hr = m_pGraph->RemoveFilter(pSource);
  117. }
  118. if (SUCCEEDED(hr))
  119. {
  120. hr = AddFilterByCLSID(m_pGraph, CLSID_WMAsfReader, &pSplitter, L"ASF Reader");
  121. }
  122. if (SUCCEEDED(hr))
  123. {
  124. hr = pSplitter->QueryInterface(IID_IFileSourceFilter, (void**)&pWNMASFReader);
  125. }
  126. if (SUCCEEDED(hr))
  127. {
  128. hr = pWNMASFReader->Load(strFileName, NULL);
  129. }
  130. }
  131. //connect splitter to video, audio
  132. if (SUCCEEDED(hr))
  133. {
  134. HRESULT hr2 = E_FAIL;
  135. hr = E_FAIL;
  136. //video
  137. hr2 = ConnectFilterToFilter(pSplitter, &pVideoDecoder, VIDEO_DECODER);
  138. if (SUCCEEDED(hr2))
  139. {
  140. hr = S_OK;
  141. }
  142. else
  143. {
  144. MSDK_SAFE_RELEASE(pVideoDecoder);
  145. }
  146. hr2 = E_FAIL;
  147. //audio
  148. hr2 = ConnectFilterToFilter(pSplitter, &pAudioDecoder, AUDIO_DECODER);
  149. //try to connect with WMAudio DMO
  150. if (FAILED(hr2))
  151. {
  152. hr2 = ConnectToDMOAudio(pSplitter, &pAudioDecoder);
  153. }
  154. if (SUCCEEDED(hr2))
  155. {
  156. hr = S_OK;
  157. }
  158. else
  159. {
  160. MSDK_SAFE_RELEASE(pAudioDecoder);
  161. }
  162. }
  163. //connect decoders to encoders
  164. if (SUCCEEDED(hr))
  165. {
  166. HRESULT hr2 = E_FAIL;
  167. hr = E_FAIL;
  168. if (pVideoDecoder)
  169. {
  170. hr2 = AddFilterByCLSID(m_pGraph, guidVideoEncoders[nType-1], &pVideoEncoder, L"Video Encoder");
  171. if (SUCCEEDED(hr2))
  172. {
  173. hr2 = ConnectFilters(m_pGraph, pVideoDecoder, pVideoEncoder);
  174. if (FAILED(hr2))
  175. {
  176. m_pGraph->RemoveFilter(pVideoEncoder);
  177. MSDK_SAFE_RELEASE(pVideoEncoder);
  178. }
  179. }
  180. }
  181. if (SUCCEEDED(hr2))
  182. {
  183. hr = S_OK;
  184. }
  185. hr2 = E_FAIL;
  186. if (pAudioDecoder)
  187. {
  188. hr2 = AddFilterByCLSID(m_pGraph, guidAudioEncoders[nType-1], &pAudioEncoder, L"Audio Encoder");
  189. if (SUCCEEDED(hr2))
  190. {
  191. hr2 = ConnectFilters(m_pGraph, pAudioDecoder, pAudioEncoder);
  192. if (FAILED(hr2))
  193. {
  194. m_pGraph->RemoveFilter(pAudioEncoder);
  195. MSDK_SAFE_RELEASE(pAudioEncoder);
  196. }
  197. }
  198. }
  199. if (SUCCEEDED(hr2))
  200. {
  201. hr = S_OK;
  202. }
  203. }
  204. //connect encoders to muxer
  205. if (SUCCEEDED(hr))
  206. {
  207. HRESULT hr2 = E_FAIL;
  208. hr = AddFilterByCLSID(m_pGraph, guidMuxers[nType-1], &pMuxer, L"Muxer");
  209. if (SUCCEEDED(hr))
  210. {
  211. hr2 = E_FAIL;
  212. if (SUCCEEDED(hr) && pAudioEncoder)
  213. {
  214. hr2 = ConnectFilters(m_pGraph, pAudioEncoder, pMuxer);
  215. }
  216. if (SUCCEEDED(hr2))
  217. {
  218. hr = S_OK;
  219. }
  220. else if (pAudioDecoder)
  221. {
  222. MessageBox(NULL,_T("Audio decoder to encoder connection failed"), _T("Warning"), 0);
  223. }
  224. hr2 = E_FAIL;
  225. if (SUCCEEDED(hr) && pVideoEncoder)
  226. {
  227. hr2 = ConnectFilters(m_pGraph, pVideoEncoder, pMuxer);
  228. }
  229. else if (pVideoDecoder)
  230. {
  231. MessageBox(NULL,_T("Video decoder to encoder connection failed"), _T("Warning"), 0);
  232. }
  233. DWORD pRegister;
  234. AddGraphToRot(m_pGraph, &pRegister);
  235. if (SUCCEEDED(hr2))
  236. {
  237. hr = S_OK;
  238. }
  239. }
  240. }
  241. //connect muxer to file writer
  242. if (SUCCEEDED(hr))
  243. {
  244. IFileSinkFilter* pFileSinkFilter = NULL;
  245. hr = AddFilterByCLSID(m_pGraph, CLSID_FileWriter, &pFileWriter, L"File Writer");
  246. if (SUCCEEDED(hr))
  247. {
  248. hr = pFileWriter->QueryInterface(IID_IFileSinkFilter, (void**)&pFileSinkFilter);
  249. }
  250. if (SUCCEEDED(hr))
  251. {
  252. hr = pFileSinkFilter->SetFileName(sDstFileName, NULL);
  253. }
  254. MSDK_SAFE_RELEASE(pFileSinkFilter);
  255. if (SUCCEEDED(hr))
  256. {
  257. hr = ConnectFilters(m_pGraph, pMuxer, pFileWriter);
  258. }
  259. }
  260. m_pEncoder = pVideoEncoder;
  261. MSDK_SAFE_RELEASE(pSource);
  262. MSDK_SAFE_RELEASE(pSplitter);
  263. MSDK_SAFE_RELEASE(pVideoDecoder);
  264. MSDK_SAFE_RELEASE(pAudioDecoder);
  265. MSDK_SAFE_RELEASE(pVideoEncoder);
  266. MSDK_SAFE_RELEASE(pAudioEncoder);
  267. MSDK_SAFE_RELEASE(pMuxer);
  268. MSDK_SAFE_RELEASE(pFileWriter);
  269. MSDK_SAFE_RELEASE(pWNMASFReader);
  270. // Update our state.
  271. if (SUCCEEDED(hr))
  272. {
  273. m_state = STATE_STOPPED;
  274. }
  275. return hr;
  276. };
  277. //-----------------------------------------------------------------------------
  278. // DShowPlayer::OpenFile
  279. // Description: Open a new file for playback.
  280. //-----------------------------------------------------------------------------
  281. HRESULT DShowPlayer::OpenFile(const WCHAR* sFileName, INT nType)
  282. {
  283. HRESULT hr = S_OK;
  284. IBaseFilter *pSource = NULL;
  285. IFileSourceFilter *pFileSourceAsync = NULL;
  286. // Create a new filter graph. (This also closes the old one, if any.)
  287. hr = InitializeGraph();
  288. // Add the source filter to the graph.
  289. if (SUCCEEDED(hr))
  290. {
  291. hr = AddFilterByCLSID(m_pGraph, CLSID_AsyncReader, &pSource, L"File Source Async");
  292. }
  293. if (SUCCEEDED(hr))
  294. {
  295. pSource->QueryInterface(IID_IFileSourceFilter, (void**)&pFileSourceAsync);
  296. hr = pFileSourceAsync->Load(sFileName, NULL);
  297. MSDK_SAFE_RELEASE(pFileSourceAsync);
  298. }
  299. // Try to render the streams.
  300. if (SUCCEEDED(hr))
  301. {
  302. if (0 == nType)
  303. {
  304. hr = RenderStreams(pSource);
  305. }
  306. else
  307. {
  308. hr = RenderStreamsS3D(pSource);
  309. }
  310. }
  311. // Get the seeking capabilities.
  312. if (SUCCEEDED(hr))
  313. {
  314. hr = m_pSeek->GetCapabilities(&m_seekCaps);
  315. }
  316. // Set the volume.
  317. if (SUCCEEDED(hr))
  318. {
  319. hr = UpdateVolume();
  320. }
  321. // Update our state.
  322. if (SUCCEEDED(hr))
  323. {
  324. m_state = STATE_STOPPED;
  325. }
  326. MSDK_SAFE_RELEASE(pSource);
  327. return hr;
  328. }
  329. //-----------------------------------------------------------------------------
  330. // DShowPlayer::HandleGraphEvent
  331. // Description: Respond to a graph event.
  332. //
  333. // The owning window should call this method when it receives the window
  334. // message that the application specified when it called SetEventWindow.
  335. //
  336. // pCB: Pointer to the GraphEventCallback callback, implemented by
  337. // the application. This callback is invoked once for each event
  338. // in the queue.
  339. //
  340. // Caution: Do not tear down the graph from inside the callback.
  341. //-----------------------------------------------------------------------------
  342. HRESULT DShowPlayer::HandleGraphEvent(GraphEventCallback *pCB)
  343. {
  344. if (pCB == NULL)
  345. {
  346. return E_POINTER;
  347. }
  348. if (!m_pEvent)
  349. {
  350. return E_UNEXPECTED;
  351. }
  352. long evCode = 0;
  353. LONG_PTR param1 = 0, param2 = 0;
  354. HRESULT hr = S_OK;
  355. // Get the events from the queue.
  356. while (SUCCEEDED(m_pEvent->GetEvent(&evCode, &param1, &param2, 0)))
  357. {
  358. // Invoke the callback.
  359. pCB->OnGraphEvent(evCode, param1, param2);
  360. // Free the event data.
  361. hr = m_pEvent->FreeEventParams(evCode, param1, param2);
  362. if (FAILED(hr))
  363. {
  364. break;
  365. }
  366. }
  367. return hr;
  368. }
  369. // state changes
  370. HRESULT DShowPlayer::Play()
  371. {
  372. HRESULT hr = S_OK;
  373. if (m_state != STATE_PAUSED && m_state != STATE_STOPPED)
  374. {
  375. return VFW_E_WRONG_STATE;
  376. }
  377. if (m_pControl == NULL || m_pSeek == NULL)
  378. {
  379. return E_UNEXPECTED;
  380. }
  381. assert(m_pGraph); // If state is correct, the graph should exist.
  382. hr = m_pControl->Run();
  383. if (SUCCEEDED(hr))
  384. {
  385. m_state = STATE_RUNNING;
  386. }
  387. return hr;
  388. }
  389. HRESULT DShowPlayer::Pause()
  390. {
  391. if (m_state != STATE_RUNNING)
  392. {
  393. return VFW_E_WRONG_STATE;
  394. }
  395. assert(m_pGraph); // If state is correct, the graph should exist.
  396. HRESULT hr = m_pControl->Pause();
  397. if (SUCCEEDED(hr))
  398. {
  399. m_state = STATE_PAUSED;
  400. }
  401. return hr;
  402. }
  403. HRESULT DShowPlayer::Stop()
  404. {
  405. if (m_state != STATE_RUNNING && m_state != STATE_PAUSED)
  406. {
  407. return VFW_E_WRONG_STATE;
  408. }
  409. assert(m_pGraph); // If state is correct, the graph should exist.
  410. HRESULT hr = m_pControl->Stop();
  411. if (SUCCEEDED(hr))
  412. {
  413. m_state = STATE_STOPPED;
  414. }
  415. return hr;
  416. }
  417. // VMR functionality
  418. //-----------------------------------------------------------------------------
  419. // DShowPlayer::UpdateVideoWindow
  420. // Description: Sets the destination rectangle for the video.
  421. //-----------------------------------------------------------------------------
  422. HRESULT DShowPlayer::UpdateVideoWindow(const LPRECT prc)
  423. {
  424. if (m_pWindowless == NULL)
  425. {
  426. return S_OK; // no-op
  427. }
  428. RECT rc;
  429. GetClientRect(m_hwndVideo, &rc);
  430. return m_pWindowless->SetVideoPosition(NULL, &rc);
  431. }
  432. //-----------------------------------------------------------------------------
  433. // DShowPlayer::Repaint
  434. // Description: Repaints the video.
  435. //
  436. // Call this method when the application receives WM_PAINT.
  437. //-----------------------------------------------------------------------------
  438. HRESULT DShowPlayer::Repaint(HDC hdc)
  439. {
  440. if (m_pWindowless)
  441. {
  442. return m_pWindowless->RepaintVideo();
  443. }
  444. else
  445. {
  446. return S_OK;
  447. }
  448. }
  449. // Seeking
  450. //-----------------------------------------------------------------------------
  451. // DShowPlayer::CanSeek
  452. // Description: Returns TRUE if the current file is seekable.
  453. //-----------------------------------------------------------------------------
  454. BOOL DShowPlayer::CanSeek() const
  455. {
  456. const DWORD caps = AM_SEEKING_CanSeekAbsolute;
  457. return ((m_seekCaps & caps) == caps);
  458. }
  459. //-----------------------------------------------------------------------------
  460. // DShowPlayer::SetPosition
  461. // Description: Seeks to a new position.
  462. //-----------------------------------------------------------------------------
  463. HRESULT DShowPlayer::SetPosition(REFERENCE_TIME pos)
  464. {
  465. if (m_pControl == NULL || m_pSeek == NULL || m_pEncoder)
  466. {
  467. return E_UNEXPECTED;
  468. }
  469. HRESULT hr = S_OK;
  470. hr = m_pSeek->SetPositions(&pos, AM_SEEKING_AbsolutePositioning,
  471. NULL, AM_SEEKING_NoPositioning);
  472. if (SUCCEEDED(hr))
  473. {
  474. // If playback is stopped, we need to put the graph into the paused
  475. // state to update the video renderer with the new frame, and then stop
  476. // the graph again. The IMediaControl::StopWhenReady does this.
  477. if (m_state == STATE_STOPPED)
  478. {
  479. hr = m_pControl->StopWhenReady();
  480. }
  481. }
  482. return hr;
  483. }
  484. //-----------------------------------------------------------------------------
  485. // DShowPlayer::GetDuration
  486. // Description: Gets the duration of the current file.
  487. //-----------------------------------------------------------------------------
  488. HRESULT DShowPlayer::GetDuration(LONGLONG *pDuration)
  489. {
  490. if (m_pSeek == NULL)
  491. {
  492. return E_UNEXPECTED;
  493. }
  494. return m_pSeek->GetDuration(pDuration);
  495. }
  496. //-----------------------------------------------------------------------------
  497. // DShowPlayer::GetCurrentPosition
  498. // Description: Gets the current playback position.
  499. //-----------------------------------------------------------------------------
  500. HRESULT DShowPlayer::GetCurrentPosition(LONGLONG *pTimeNow)
  501. {
  502. if (m_pSeek == NULL)
  503. {
  504. return E_UNEXPECTED;
  505. }
  506. return m_pSeek->GetCurrentPosition(pTimeNow);
  507. }
  508. // Audio
  509. //-----------------------------------------------------------------------------
  510. // DShowPlayer::Mute
  511. // Description: Mutes or unmutes the audio.
  512. //-----------------------------------------------------------------------------
  513. HRESULT DShowPlayer::Mute(BOOL bMute)
  514. {
  515. m_bMute = bMute;
  516. return UpdateVolume();
  517. }
  518. //-----------------------------------------------------------------------------
  519. // DShowPlayer::SetVolume
  520. // Description: Sets the volume.
  521. //-----------------------------------------------------------------------------
  522. HRESULT DShowPlayer::SetVolume(long lVolume)
  523. {
  524. m_lVolume = lVolume;
  525. return UpdateVolume();
  526. }
  527. //-----------------------------------------------------------------------------
  528. // DShowPlayer::UpdateVolume
  529. // Description: Update the volume after a call to Mute() or SetVolume().
  530. //-----------------------------------------------------------------------------
  531. HRESULT DShowPlayer::UpdateVolume()
  532. {
  533. HRESULT hr = S_OK;
  534. if (m_bAudioStream && m_pAudio)
  535. {
  536. // If the audio is muted, set the minimum volume.
  537. if (m_bMute)
  538. {
  539. hr = m_pAudio->put_Volume(MIN_VOLUME);
  540. }
  541. else
  542. {
  543. // Restore previous volume setting
  544. hr = m_pAudio->put_Volume(m_lVolume);
  545. }
  546. }
  547. return hr;
  548. }
  549. // Graph building
  550. //-----------------------------------------------------------------------------
  551. // DShowPlayer::InitializeGraph
  552. // Description: Create a new filter graph. (Tears down the old graph.)
  553. //-----------------------------------------------------------------------------
  554. HRESULT DShowPlayer::InitializeGraph()
  555. {
  556. HRESULT hr = S_OK;
  557. TearDownGraph();
  558. // Create the Filter Graph Manager.
  559. hr = CoCreateInstance(
  560. CLSID_FilterGraph,
  561. NULL,
  562. CLSCTX_INPROC_SERVER,
  563. IID_IGraphBuilder,
  564. (void**)&m_pGraph
  565. );
  566. // Query for graph interfaces.
  567. if (SUCCEEDED(hr))
  568. {
  569. hr = m_pGraph->QueryInterface(IID_IMediaControl, (void**)&m_pControl);
  570. }
  571. if (SUCCEEDED(hr))
  572. {
  573. hr = m_pGraph->QueryInterface(IID_IMediaEventEx, (void**)&m_pEvent);
  574. }
  575. if (SUCCEEDED(hr))
  576. {
  577. hr = m_pGraph->QueryInterface(IID_IMediaSeeking, (void**)&m_pSeek);
  578. }
  579. if (SUCCEEDED(hr))
  580. {
  581. hr = m_pGraph->QueryInterface(IID_IBasicAudio, (void**)&m_pAudio);
  582. }
  583. // Set up event notification.
  584. if (SUCCEEDED(hr))
  585. {
  586. hr = m_pEvent->SetNotifyWindow((OAHWND)m_hwndEvent, m_EventMsg, NULL);
  587. }
  588. return hr;
  589. }
  590. //-----------------------------------------------------------------------------
  591. // DShowPlayer::TearDownGraph
  592. // Description: Tear down the filter graph and release resources.
  593. //-----------------------------------------------------------------------------
  594. void DShowPlayer::TearDownGraph()
  595. {
  596. // Stop sending event messages
  597. if (m_pEvent)
  598. {
  599. m_pEvent->SetNotifyWindow((OAHWND)NULL, NULL, NULL);
  600. }
  601. MSDK_SAFE_RELEASE(m_pGraph);
  602. MSDK_SAFE_RELEASE(m_pControl);
  603. MSDK_SAFE_RELEASE(m_pEvent);
  604. MSDK_SAFE_RELEASE(m_pSeek);
  605. MSDK_SAFE_RELEASE(m_pWindowless);
  606. MSDK_SAFE_RELEASE(m_pAudio);
  607. m_pEncoder.Release();
  608. m_pVMR.Release();
  609. MSDK_SAFE_RELEASE(m_pCustomPresenter);
  610. m_state = STATE_CLOSED;
  611. m_seekCaps = 0;
  612. m_bAudioStream = FALSE;
  613. }
  614. HRESULT DShowPlayer::ConnectFilterToFilter(IBaseFilter *pSrc, IBaseFilter** pDst, FilterType nType)
  615. {
  616. HRESULT hr = E_FAIL;
  617. IEnumPins* pEnum = NULL;
  618. IPin* pPin = NULL;
  619. PIN_DIRECTION dir;
  620. GUID guidFilters[10];
  621. INT nArraySize = 0;
  622. TCHAR strFilterName[64];
  623. if ((m_pGraph == NULL) || (pSrc == NULL))
  624. {
  625. return E_POINTER;
  626. }
  627. if (*pDst != NULL)
  628. {
  629. return E_INVALIDARG;
  630. }
  631. memset(guidFilters, 0, sizeof(GUID) * 10);
  632. switch (nType)
  633. {
  634. case SPLITTER:
  635. nArraySize = ARRAYSIZE(guidSplitters);
  636. _tcscpy_s(strFilterName, L"Splitter");
  637. memcpy(guidFilters, guidSplitters, sizeof(GUID) * nArraySize);
  638. break;
  639. case VIDEO_DECODER:
  640. nArraySize = ARRAYSIZE(guidVideoDecoders);
  641. _tcscpy_s(strFilterName, L"Video Decoder");
  642. memcpy(guidFilters, guidVideoDecoders, sizeof(GUID) * nArraySize);
  643. break;
  644. case VIDEO_DECODER3D:
  645. nArraySize = ARRAYSIZE(guidVideoDecodersS3D);
  646. _tcscpy_s(strFilterName, L"Video Decoder");
  647. memcpy(guidFilters, guidVideoDecodersS3D, sizeof(GUID) * nArraySize);
  648. break;
  649. case AUDIO_DECODER:
  650. nArraySize = ARRAYSIZE(guidAudioDecoders);
  651. _tcscpy_s(strFilterName, L"Audio Decoder");
  652. memcpy(guidFilters, guidAudioDecoders, sizeof(GUID) * nArraySize);
  653. break;
  654. }
  655. for (int i = 0; i < nArraySize; i++)
  656. {
  657. hr = AddFilterByCLSID(m_pGraph, guidFilters[i], pDst, strFilterName);
  658. if (SUCCEEDED(hr))
  659. {
  660. // Enumerate the pins on the source filter.
  661. hr = pSrc->EnumPins(&pEnum);
  662. if (SUCCEEDED(hr))
  663. {
  664. while (S_OK == pEnum->Next(1, &pPin, NULL))
  665. {
  666. hr = pPin->QueryDirection(&dir);
  667. if (FAILED(hr) || dir == PINDIR_INPUT)
  668. {
  669. MSDK_SAFE_RELEASE(pPin);
  670. continue;
  671. }
  672. hr = ConnectFilters(m_pGraph, pPin, *pDst);
  673. MSDK_SAFE_RELEASE(pPin);
  674. if (SUCCEEDED(hr))
  675. {
  676. break;
  677. }
  678. }
  679. MSDK_SAFE_RELEASE(pEnum);
  680. }
  681. }
  682. if (SUCCEEDED(hr))
  683. {
  684. break;
  685. }
  686. if (NULL != *pDst)
  687. {
  688. m_pGraph->RemoveFilter(*pDst);
  689. MSDK_SAFE_RELEASE((*pDst));
  690. }
  691. }
  692. return hr;
  693. };
  694. HRESULT DShowPlayer::ConnectToDMOAudio(IBaseFilter *pSrc, IBaseFilter** pDst)
  695. {
  696. HRESULT hr = S_OK;
  697. IDMOWrapperFilter *pWraperFilter = NULL;
  698. // Create the DMO Wrapper filter.
  699. hr = CoCreateInstance(CLSID_DMOWrapperFilter, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)pDst);
  700. if (SUCCEEDED(hr))
  701. {
  702. hr = (*pDst)->QueryInterface(IID_IDMOWrapperFilter, (void **)&pWraperFilter);
  703. }
  704. if(SUCCEEDED(hr))
  705. {
  706. // Initialize the filter.
  707. hr = pWraperFilter->Init(CLSID_CWMADecMediaObject, DMOCATEGORY_AUDIO_DECODER);
  708. }
  709. if(SUCCEEDED(hr))
  710. {
  711. hr = m_pGraph->AddFilter(*pDst, L"Audio Decoder");
  712. }
  713. if (SUCCEEDED(hr))
  714. {
  715. hr = ConnectFilters(m_pGraph, pSrc, *pDst);
  716. }
  717. if (FAILED(hr) && NULL != *pDst)
  718. {
  719. m_pGraph->RemoveFilter(*pDst);
  720. MSDK_SAFE_RELEASE((*pDst));
  721. }
  722. MSDK_SAFE_RELEASE(pWraperFilter);
  723. return hr;
  724. };
  725. //-----------------------------------------------------------------------------
  726. // DShowPlayer::RenderStreams
  727. // Description: Render the streams from a source filter.
  728. //-----------------------------------------------------------------------------
  729. HRESULT DShowPlayer::RenderStreams(IBaseFilter *pSource)
  730. {
  731. HRESULT hr = S_OK;
  732. BOOL bRenderedAnyPin = FALSE;
  733. IBaseFilter *pAudioRenderer = NULL;
  734. IBaseFilter* pSplitter = NULL;
  735. IBaseFilter* pVideoDecoder = NULL;
  736. IBaseFilter* pAudioDecoder = NULL;
  737. IFileSourceFilter* pWNMASFReader = NULL;
  738. // Add the VMR-9 to the graph.
  739. if (SUCCEEDED(hr))
  740. {
  741. hr = AddFilterByCLSID(m_pGraph, CLSID_EnhancedVideoRenderer, &m_pVMR, L"Video Rendered");
  742. }
  743. // Set windowless mode on the VMR. This must be done before the VMR is connected.
  744. if (SUCCEEDED(hr))
  745. {
  746. hr = InitWindowlessVMR(m_pVMR, m_hwndVideo, &m_pWindowless);
  747. }
  748. // Add the DSound Renderer to the graph.
  749. if (SUCCEEDED(hr))
  750. {
  751. hr = AddFilterByCLSID(m_pGraph, CLSID_DSoundRender, &pAudioRenderer, L"Audio Renderer");
  752. }
  753. //connect source to splitter
  754. if (SUCCEEDED(hr))
  755. {
  756. hr = ConnectFilterToFilter(pSource, &pSplitter, SPLITTER);
  757. }
  758. //if connect to splitter failed suppose that file is wmv
  759. if (FAILED(hr))
  760. {
  761. LPOLESTR strFileName = NULL;
  762. hr = pSource->QueryInterface(IID_IFileSourceFilter, (void**)&pWNMASFReader);
  763. if (SUCCEEDED(hr))
  764. {
  765. hr = pWNMASFReader->GetCurFile(&strFileName, NULL);
  766. MSDK_SAFE_RELEASE(pWNMASFReader);
  767. }
  768. if (SUCCEEDED(hr))
  769. {
  770. hr = m_pGraph->RemoveFilter(pSource);
  771. }
  772. if (SUCCEEDED(hr))
  773. {
  774. hr = AddFilterByCLSID(m_pGraph, CLSID_WMAsfReader, &pSplitter, L"ASF Reader");
  775. }
  776. if (SUCCEEDED(hr))
  777. {
  778. hr = pSplitter->QueryInterface(IID_IFileSourceFilter, (void**)&pWNMASFReader);
  779. }
  780. if (SUCCEEDED(hr))
  781. {
  782. hr = pWNMASFReader->Load(strFileName, NULL);
  783. }
  784. }
  785. //connect splitter to video and to render
  786. if (SUCCEEDED(hr))
  787. {
  788. //video
  789. hr = ConnectFilterToFilter(pSplitter, &pVideoDecoder, VIDEO_DECODER);
  790. if (SUCCEEDED(hr))
  791. {
  792. hr=ConnectFilters(m_pGraph, pVideoDecoder, m_pVMR);
  793. }
  794. if (SUCCEEDED(hr))
  795. {
  796. bRenderedAnyPin = true;
  797. }
  798. else
  799. {
  800. MSDK_SAFE_RELEASE(pVideoDecoder);
  801. }
  802. //audio
  803. hr = ConnectFilterToFilter(pSplitter, &pAudioDecoder, AUDIO_DECODER);
  804. //try to connect with WMAudio DMO
  805. if (FAILED(hr))
  806. {
  807. hr = ConnectToDMOAudio(pSplitter, &pAudioDecoder);
  808. }
  809. if (SUCCEEDED(hr))
  810. {
  811. hr=ConnectFilters(m_pGraph, pAudioDecoder, pAudioRenderer);
  812. }
  813. if (SUCCEEDED(hr))
  814. {
  815. bRenderedAnyPin = true;
  816. }
  817. else
  818. {
  819. MSDK_SAFE_RELEASE(pAudioDecoder);
  820. }
  821. if (bRenderedAnyPin)
  822. {
  823. hr = S_OK;
  824. }
  825. }
  826. // Remove un-used renderers.
  827. // Try to remove the VMR.
  828. if (SUCCEEDED(hr) && m_pVMR)
  829. {
  830. BOOL bRemoved = FALSE;
  831. hr = RemoveUnconnectedRenderer(m_pGraph, m_pVMR, &bRemoved);
  832. // If we removed the VMR, then we also need to release our
  833. // pointer to the VMR's windowless control interface.
  834. if (bRemoved)
  835. {
  836. MSDK_SAFE_RELEASE(m_pWindowless);
  837. }
  838. }
  839. // Try to remove the audio renderer.
  840. if (SUCCEEDED(hr) && pAudioRenderer)
  841. {
  842. BOOL bRemoved = FALSE;
  843. hr = RemoveUnconnectedRenderer(m_pGraph, pAudioRenderer, &bRemoved);
  844. if (bRemoved)
  845. {
  846. m_bAudioStream = FALSE;
  847. }
  848. else
  849. {
  850. m_bAudioStream = TRUE;
  851. }
  852. }
  853. MSDK_SAFE_RELEASE(pSplitter);
  854. MSDK_SAFE_RELEASE(pVideoDecoder);
  855. MSDK_SAFE_RELEASE(pAudioDecoder);
  856. MSDK_SAFE_RELEASE(pAudioRenderer);
  857. // If we succeeded to this point, make sure we rendered at least one
  858. // stream.
  859. if (SUCCEEDED(hr))
  860. {
  861. if (!bRenderedAnyPin)
  862. {
  863. hr = VFW_E_CANNOT_RENDER;
  864. }
  865. }
  866. return hr;
  867. }
  868. HRESULT DShowPlayer::RenderStreamsS3D(IBaseFilter *pSource)
  869. {
  870. HRESULT hr = S_OK;
  871. BOOL bRenderedAnyPin = FALSE;
  872. IBaseFilter *pAudioRenderer = NULL;
  873. IBaseFilter* pSplitter = NULL;
  874. IBaseFilter* pVideoDecoder = NULL;
  875. IBaseFilter* pAudioDecoder = NULL;
  876. CComPtr<IMFGetService> pGetService = NULL;
  877. CComPtr<IMFVideoRenderer> pVideoRenderer = NULL;
  878. // Add the VMR-9 to the graph.
  879. if (SUCCEEDED(hr))
  880. {
  881. hr = AddFilterByCLSID(m_pGraph, CLSID_EnhancedVideoRenderer, &m_pVMR, L"Video Rendered");
  882. }
  883. // Create custom presenter for EVR
  884. if (SUCCEEDED(hr))
  885. {
  886. hr = CoCreateInstance(CLSID_CustomEVRPresenter, NULL, CLSCTX_INPROC_SERVER, __uuidof(IMFVideoPresenter), (void **)&m_pCustomPresenter);
  887. }
  888. if (SUCCEEDED(hr))
  889. {
  890. hr = m_pVMR->QueryInterface(__uuidof(IMFGetService), (void**)&pGetService);
  891. }
  892. if (SUCCEEDED(hr))
  893. {
  894. hr = m_pVMR->QueryInterface(__uuidof(IMFVideoRenderer),(void**)&pVideoRenderer);
  895. }
  896. // Set custom presenter on EVR
  897. if (SUCCEEDED(hr))
  898. {
  899. hr = pVideoRenderer->InitializeRenderer(NULL, m_pCustomPresenter);
  900. }
  901. // Set windowless mode on the VMR. This must be done before the VMR is connected.
  902. if (SUCCEEDED(hr))
  903. {
  904. hr = InitWindowlessVMR(m_pVMR, m_hwndVideo, &m_pWindowless);
  905. }
  906. // Add the DSound Renderer to the graph.
  907. if (SUCCEEDED(hr))
  908. {
  909. hr = AddFilterByCLSID(m_pGraph, CLSID_DSoundRender, &pAudioRenderer, L"Audio Renderer");
  910. }
  911. //connect source to splitter
  912. if (SUCCEEDED(hr))
  913. {
  914. hr = ConnectFilterToFilter(pSource, &pSplitter, SPLITTER);
  915. }
  916. //connect splitter to video and to render
  917. if (SUCCEEDED(hr))
  918. {
  919. //video
  920. hr = ConnectFilterToFilter(pSplitter, &pVideoDecoder, VIDEO_DECODER3D);
  921. if (SUCCEEDED(hr))
  922. {
  923. hr=ConnectFilters(m_pGraph, pVideoDecoder, m_pVMR);
  924. }
  925. if (SUCCEEDED(hr))
  926. {
  927. bRenderedAnyPin = true;
  928. }
  929. else
  930. {
  931. MSDK_SAFE_RELEASE(pVideoDecoder);
  932. }
  933. //audio
  934. hr = ConnectFilterToFilter(pSplitter, &pAudioDecoder, AUDIO_DECODER);
  935. //try to connect with WMAudio DMO
  936. if (FAILED(hr))
  937. {
  938. hr = ConnectToDMOAudio(pSplitter, &pAudioDecoder);
  939. }
  940. if (SUCCEEDED(hr))
  941. {
  942. hr=ConnectFilters(m_pGraph, pAudioDecoder, pAudioRenderer);
  943. }
  944. if (SUCCEEDED(hr))
  945. {
  946. bRenderedAnyPin = true;
  947. }
  948. else
  949. {
  950. MSDK_SAFE_RELEASE(pAudioDecoder);
  951. }
  952. if (bRenderedAnyPin)
  953. {
  954. hr = S_OK;
  955. }
  956. }
  957. // Remove un-used renderers.
  958. // Try to remove the VMR.
  959. if (SUCCEEDED(hr) && m_pVMR)
  960. {
  961. BOOL bRemoved = FALSE;
  962. hr = RemoveUnconnectedRenderer(m_pGraph, m_pVMR, &bRemoved);
  963. // If we removed the VMR, then we also need to release our
  964. // pointer to the VMR's windowless control interface.
  965. if (bRemoved)
  966. {
  967. MSDK_SAFE_RELEASE(m_pWindowless);
  968. }
  969. }
  970. // Try to remove the audio renderer.
  971. if (SUCCEEDED(hr) && pAudioRenderer)
  972. {
  973. BOOL bRemoved = FALSE;
  974. hr = RemoveUnconnectedRenderer(m_pGraph, pAudioRenderer, &bRemoved);
  975. if (bRemoved)
  976. {
  977. m_bAudioStream = FALSE;
  978. }
  979. else
  980. {
  981. m_bAudioStream = TRUE;
  982. }
  983. }
  984. MSDK_SAFE_RELEASE(pSplitter);
  985. MSDK_SAFE_RELEASE(pVideoDecoder);
  986. MSDK_SAFE_RELEASE(pAudioDecoder);
  987. MSDK_SAFE_RELEASE(pAudioRenderer);
  988. // If we succeeded to this point, make sure we rendered at least one
  989. // stream.
  990. if (SUCCEEDED(hr))
  991. {
  992. if (!bRenderedAnyPin)
  993. {
  994. hr = VFW_E_CANNOT_RENDER;
  995. }
  996. }
  997. return hr;
  998. }
  999. //-----------------------------------------------------------------------------
  1000. // DShowPlayer::RemoveUnconnectedRenderer
  1001. // Description: Remove a renderer filter from the graph if the filter is
  1002. // not connected.
  1003. //-----------------------------------------------------------------------------
  1004. HRESULT RemoveUnconnectedRenderer(IGraphBuilder *pGraph, IBaseFilter *pRenderer, BOOL *pbRemoved)
  1005. {
  1006. IPin *pPin = NULL;
  1007. BOOL bRemoved = FALSE;
  1008. // Look for a connected input pin on the renderer.
  1009. HRESULT hr = FindConnectedPin(pRenderer, PINDIR_INPUT, &pPin);
  1010. MSDK_SAFE_RELEASE(pPin);
  1011. // If this function succeeds, the renderer is connected, so we don't remove it.
  1012. // If it fails, it means the renderer is not connected to anything, so
  1013. // we remove it.
  1014. if (FAILED(hr))
  1015. {
  1016. hr = pGraph->RemoveFilter(pRenderer);
  1017. bRemoved = TRUE;
  1018. }
  1019. if (SUCCEEDED(hr))
  1020. {
  1021. *pbRemoved = bRemoved;
  1022. }
  1023. return hr;
  1024. }
  1025. //-----------------------------------------------------------------------------
  1026. // DShowPlayer::InitWindowlessVMR
  1027. // Description: Initialize the VMR-9 for windowless mode.
  1028. //-----------------------------------------------------------------------------
  1029. HRESULT InitWindowlessVMR(
  1030. IBaseFilter *pVMR, // Pointer to the render
  1031. HWND hwnd, // Clipping window
  1032. IMFVideoDisplayControl** ppWC // Receives a pointer to the render config.
  1033. )
  1034. {
  1035. HRESULT hr = S_OK;
  1036. CComPtr<IMFGetService> pGetService = NULL;
  1037. CComPtr<IMFVideoDisplayControl> pConfig = NULL;
  1038. hr = pVMR->QueryInterface(__uuidof(IMFGetService), (void**)&pGetService);
  1039. if (SUCCEEDED(hr))
  1040. {
  1041. hr = pGetService->GetService(MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl, (void**)&pConfig);
  1042. }
  1043. if (SUCCEEDED(hr))
  1044. {
  1045. hr = pConfig->SetVideoWindow(hwnd);
  1046. }
  1047. if (SUCCEEDED(hr))
  1048. {
  1049. pConfig->SetAspectRatioMode(MFVideoARMode_PreservePicture);
  1050. }
  1051. // Return the IVMRWindowlessControl pointer to the caller.
  1052. if (SUCCEEDED(hr))
  1053. {
  1054. *ppWC = pConfig;
  1055. (*ppWC)->AddRef();
  1056. }
  1057. return hr;
  1058. }