HSPlayer.cpp
Upload User: geng8029
Upload Date: 2021-01-30
Package Size: 187k
Code Size: 14k
Category:

Audio program

Development Platform:

Visual C++

  1. #include "StdAfx.h"
  2. #include "HSPlayer.h"
  3. //#include "common.h"
  4. #include <mfidl.h>
  5. #include "WavSink.h"
  6. #include <MMsystem.h>
  7. #include <aviriff.h>
  8. //#ifndef SAFE_RELEASE
  9. //template <class T>
  10. //inline void SAFE_RELEASE(T*& p)
  11. //{
  12. // if (p)
  13. // {
  14. // p->Release();
  15. // p = NULL;
  16. // }
  17. //}
  18. //#endif
  19. #ifndef IF_FAILED_BREAK
  20. #define IF_FAILED_BREAK(hr) if (FAILED(hr)) { break; }
  21. #endif
  22. #ifndef CHECK_HR
  23. #define CHECK_HR(hr) IF_FAILED_BREAK(hr)
  24. #endif
  25. #ifndef CheckPointer
  26. #define CheckPointer(x, hr) if (x == NULL) { return hr; }
  27. #endif
  28. struct WAV_FILE_HEADER
  29. {
  30.     RIFFCHUNK       FileHeader;
  31.     DWORD           fccWaveType;    // must be 'WAVE'
  32.     RIFFCHUNK       WaveHeader;
  33.     WAVEFORMATEX    WaveFormat;
  34.     RIFFCHUNK       DataHeader;
  35. };
  36. extern HRESULT CreateWavSink(IMFByteStream *pStream, IMFMediaSink **ppSink, CALLBACK_FOR_CAPTUREDATA cb);
  37. CHSPlayer::CHSPlayer(void):
  38. //m_pBuffer(NULL),
  39. m_pByteStream(NULL),
  40. m_pSource(NULL)
  41. {
  42. }
  43. CHSPlayer::~CHSPlayer(void)
  44. {
  45. if (m_pSource)
  46. {
  47. m_pSource->Shutdown();
  48. }
  49. if (m_pSource)
  50. {
  51. m_pSession->Shutdown();
  52. }
  53. SAFE_RELEASE(m_pSink);
  54. SAFE_RELEASE(m_pSource);
  55. SAFE_RELEASE(m_pTopology);
  56. SAFE_RELEASE(m_pSession);
  57. }
  58. HRESULT CHSPlayer::Initialize(CALLBACK_FOR_CAPTUREDATA cb)
  59. {
  60. HRESULT hr = S_OK;
  61. //m_cb = cb;
  62. do 
  63. {
  64. CHECK_HR(hr = MFStartup(MF_VERSION));
  65. if (SUCCEEDED(hr))
  66. {
  67. hr = CreateWavFile(cb);
  68. }
  69. } while (false);
  70. return hr;
  71. }
  72. HRESULT CHSPlayer::UnInitialize()
  73. {
  74. HRESULT hr = S_OK;
  75. if (m_pSession)
  76. {
  77. m_pSession->Close();
  78. }
  79. return hr;
  80. }
  81. HRESULT CHSPlayer::CreateMediaSourceForDevice(IMFMediaSource **ppSource)//const WCHAR *sURL, 
  82. {   
  83. HRESULT hr = S_OK;
  84. UINT32 count = 0;
  85. IMFAttributes *pConfig = NULL;
  86. IMFActivate **ppDevices = NULL;
  87. IMFMediaSource *pSource = NULL;
  88. // Create an attribute store to hold the search criteria.
  89. do
  90. {
  91. CHECK_HR(hr = MFCreateAttributes(&pConfig, 1));
  92. // Request video capture devices.
  93. CHECK_HR(hr = pConfig->SetGUID(
  94. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, 
  95. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID//MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
  96. ));
  97. // Enumerate the devices,
  98. CHECK_HR(hr = MFEnumDeviceSources(pConfig, &ppDevices, &count));
  99. // Create a media source for the first device in the list.
  100. if (count > 0)
  101. {
  102. CHECK_HR(hr = ppDevices[0]->ActivateObject(
  103. __uuidof(IMFMediaSource), 
  104. (void**)&pSource
  105. ));
  106. // Return the pointer to the caller.
  107. *ppSource = pSource;
  108. (*ppSource)->AddRef();
  109. }
  110. else
  111. {
  112. hr = MF_E_NOT_FOUND;
  113. }
  114. }while(false);
  115. for (DWORD i = 0; i < count; i++)
  116. {
  117. ppDevices[i]->Release();
  118. }
  119. CoTaskMemFree(ppDevices);
  120. SAFE_RELEASE(pSource);
  121. return hr;
  122. }
  123. ///////////////////////////////////////////////////////////////////////
  124. //  Name: CreateWavFile
  125. //  Description:  Creates a .wav file from an input file.
  126. ///////////////////////////////////////////////////////////////////////
  127. HRESULT CHSPlayer::CreateWavFile(CALLBACK_FOR_CAPTUREDATA cb)//const WCHAR *sURL, const WCHAR *sOutputFile
  128. {
  129. IMFByteStream *pStream = NULL;
  130. //IMFMediaSink *pSink = NULL;
  131. //IMFMediaSource *pSource = NULL;
  132. //IMFTopology *pTopology = NULL;
  133. //HRESULT hr = S_OK;
  134. WCHAR *sOutputFile = L"sound2.wav";//C:\Users\EN\Desktop\MediaFoundation1\TextPlayer\Debug
  135. HRESULT hr = MFCreateFile(MF_ACCESSMODE_WRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, sOutputFile, &pStream);
  136. //if (FAILED(hr))
  137. //{
  138. //wprintf(L"MFCreateFile failed!n");
  139. //}
  140. // Create the WavSink object.
  141. if (SUCCEEDED(hr))
  142. {
  143. hr = CreateWavSink(pStream, &m_pSink, cb);
  144. }
  145. // Create the media source from the end point device.
  146. if (SUCCEEDED(hr))
  147. {
  148. hr = CreateMediaSourceForDevice(&m_pSource);
  149. }
  150. // Create the topology.
  151. if (SUCCEEDED(hr))
  152. {
  153. hr = CreateTopology(m_pSource, m_pSink, &m_pTopology);
  154. }
  155. // Run the media session.
  156. if (SUCCEEDED(hr))
  157. {
  158. hr = RunMediaSession(m_pTopology);
  159. if (FAILED(hr))
  160. {
  161. //wprintf(L"RunMediaSession failed!n");
  162. }
  163. }
  164. return hr;
  165. }
  166. void CHSPlayer::OnClearSessionEvent(IMFAsyncResult* pResult)
  167. {
  168. PROPVARIANT varStartPosition;
  169. PropVariantInit(&varStartPosition);
  170. HRESULT hrStatus = S_OK;
  171. IMFMediaEvent *pEvent = NULL;
  172. MediaEventType meType = MEUnknown;
  173. MF_TOPOSTATUS TopoStatus = MF_TOPOSTATUS_INVALID; // Used with MESessionTopologyStatus event.    
  174. //hr = m_pSession->GetEvent(0, &pEvent);
  175. HRESULT hr = S_OK;
  176. //CComPtr<IMFMediaEvent> spEvent;
  177. hr = m_pSession->EndGetEvent(pResult, &pEvent);
  178. if (SUCCEEDED(hr))
  179. {
  180. hr = pEvent->GetStatus(&hrStatus);
  181. }
  182. if (SUCCEEDED(hr))
  183. {
  184. hr = pEvent->GetType(&meType);
  185. }
  186. if (SUCCEEDED(hr) && SUCCEEDED(hrStatus))
  187. {
  188. switch (meType)
  189. {
  190. case MESessionTopologySet:
  191. //wprintf(L"MESessionTopologySetn");
  192. break;
  193. case MESessionTopologyStatus:
  194. // Get the status code.
  195. hr = pEvent->GetUINT32(MF_EVENT_TOPOLOGY_STATUS, (UINT32*)&TopoStatus);
  196. if (SUCCEEDED(hr))
  197. {
  198. switch (TopoStatus)
  199. {
  200. case MF_TOPOSTATUS_READY:
  201. //wprintf(L"MESessionTopologyStatus: MF_TOPOSTATUS_READYn");
  202. hr = m_pSession->Start(&GUID_NULL, &varStartPosition);
  203. break;
  204. case MF_TOPOSTATUS_ENDED:
  205. //wprintf(L"MESessionTopologyStatus: MF_TOPOSTATUS_ENDEDn");
  206. break;
  207. }
  208. }
  209. break;
  210. case MESessionStarted:
  211. //wprintf(L"MESessionStartedn");
  212. break;
  213. case MESessionEnded:
  214. //wprintf(L"MESessionEndedn");
  215. hr = m_pSession->Stop();
  216. break;
  217. case MESessionStopped:
  218. //wprintf(L"MESessionStopped.n");
  219. hr = m_pSession->Close();
  220. break;
  221. case MESessionClosed:
  222. //wprintf(L"MESessionClosedn");
  223. //bGetAnotherEvent = FALSE;
  224. break;
  225. default:
  226. //wprintf(L"Media session event: %dn", meType);
  227. break;
  228. }
  229. }
  230. SAFE_RELEASE(pEvent);
  231. //if (FAILED(hr) || FAILED(hrStatus))
  232. //{
  233. // bGetAnotherEvent = FALSE;
  234. //}
  235. PropVariantClear(&varStartPosition);
  236. SAFE_RELEASE(pEvent);
  237. m_pSession->BeginGetEvent(&m_xOnClearSessionEvent, NULL);
  238. }
  239. ///////////////////////////////////////////////////////////////////////
  240. //  Name: RunMediaSession
  241. //  Description:  
  242. //  Queues the specified topology on the media session and runs the
  243. //  media session until the MESessionEnded event is received.
  244. ///////////////////////////////////////////////////////////////////////
  245. HRESULT CHSPlayer::RunMediaSession(IMFTopology *pTopology)
  246. {
  247. //IMFMediaSession *pSession = NULL;
  248. HRESULT hr = S_OK;
  249. BOOL bGetAnotherEvent = TRUE;
  250. hr = MFCreateMediaSession(NULL, &m_pSession);
  251. if (SUCCEEDED(hr))
  252. {
  253. hr = m_pSession->SetTopology(0, pTopology);
  254. }
  255. if (SUCCEEDED(hr))
  256. {
  257. hr = m_pSession->BeginGetEvent(&m_xOnClearSessionEvent, NULL);
  258. }
  259. //wprintf(L"Shutting down the media session.n");
  260. //m_pSession->Shutdown();
  261. //SAFE_RELEASE(m_pSession);
  262. return hr;
  263. }
  264. ///////////////////////////////////////////////////////////////////////
  265. //  Name: CreateTopology
  266. //  Description:  Creates the topology.
  267. // 
  268. //  Note: The first audio stream is conntected to the media sink.
  269. //        Other streams are deselected.
  270. ///////////////////////////////////////////////////////////////////////
  271. HRESULT CHSPlayer::CreateTopology(IMFMediaSource *pSource, IMFMediaSink *pSink, IMFTopology **ppTopology)
  272. {
  273. IMFTopology *pTopology = NULL;
  274. IMFPresentationDescriptor *pPD = NULL;
  275. IMFStreamDescriptor *pSD = NULL;
  276. HRESULT hr = S_OK;
  277. DWORD cStreams = 0;
  278. hr = MFCreateTopology(&pTopology);
  279. if (SUCCEEDED(hr))
  280. {
  281. hr = pSource->CreatePresentationDescriptor(&pPD);
  282. }
  283. if (SUCCEEDED(hr))
  284. {
  285. hr = pPD->GetStreamDescriptorCount(&cStreams);
  286. }
  287. BOOL fConnected = FALSE;
  288. if (SUCCEEDED(hr))
  289. {
  290. GUID majorType = GUID_NULL;
  291. BOOL fSelected = FALSE;
  292. for (DWORD iStream = 0; iStream < cStreams; iStream++)
  293. {
  294. hr = pPD->GetStreamDescriptorByIndex(iStream, &fSelected, &pSD);
  295. if (FAILED(hr))
  296. {
  297. break;
  298. }
  299. // If the stream is not selected by default, ignore it.
  300. if (!fSelected)
  301. {
  302. continue;
  303. }
  304. // Get the major media type.
  305. hr = GetStreamMajorType(pSD, &majorType);
  306. if (FAILED(hr))
  307. {
  308. break;
  309. }
  310. // If it's not audio, deselect it and continue.
  311. if (majorType != MFMediaType_Audio)
  312. {
  313. // Deselect this stream
  314. hr = pPD->DeselectStream(iStream);
  315. if (FAILED(hr))
  316. {
  317. break;
  318. }
  319. else
  320. {
  321. continue;
  322. }
  323. }
  324. // It's an audio stream, so try to create the topology branch.
  325. hr = CreateTopologyBranch(pTopology, pSource, pPD, pSD, pSink);
  326. // Set our status flag. 
  327. if (SUCCEEDED(hr))
  328. {
  329. fConnected = TRUE;
  330. }
  331. // At this point we have reached the first audio stream in the
  332. // source, so we can stop looking (whether we succeeded or failed).
  333. break;
  334. }
  335. }
  336. if (SUCCEEDED(hr))
  337. {
  338. // Even if we succeeded, if we didn't connect any streams, it's a failure.
  339. // (For example, it might be a video-only source.
  340. if (!fConnected)
  341. {
  342. hr = E_FAIL;
  343. }
  344. }
  345. if (SUCCEEDED(hr))
  346. {
  347. *ppTopology = pTopology;
  348. (*ppTopology)->AddRef();
  349. }
  350. SAFE_RELEASE(pTopology);
  351. SAFE_RELEASE(pPD);
  352. SAFE_RELEASE(pSD);
  353. return hr;
  354. }
  355. ///////////////////////////////////////////////////////////////////////
  356. //  Name: CreateTopologyBranch
  357. //  Description:  Adds a source and sink to the topology and
  358. //                connects them.
  359. //
  360. //  pTopology: The topology.
  361. //  pSource:   The media source.
  362. //  pPD:       The source's presentation descriptor.
  363. //  pSD:       The stream descriptor for the stream.
  364. //  pSink:     The media sink.
  365. //
  366. ///////////////////////////////////////////////////////////////////////
  367. HRESULT CHSPlayer::CreateTopologyBranch(
  368.  IMFTopology *pTopology,
  369.  IMFMediaSource *pSource,          // Media source.
  370.  IMFPresentationDescriptor *pPD,   // Presentation descriptor.
  371.  IMFStreamDescriptor *pSD,         // Stream descriptor.
  372.  IMFMediaSink *pSink
  373.  )
  374. {
  375. IMFTopologyNode *pSourceNode = NULL;
  376. IMFTopologyNode *pOutputNode = NULL;
  377. HRESULT hr = S_OK;
  378. hr = CreateSourceNode(pSource, pPD, pSD, &pSourceNode);
  379. if (SUCCEEDED(hr))
  380. {
  381. hr = CreateOutputNode(pSink, 0, &pOutputNode);
  382. }
  383. if (SUCCEEDED(hr))
  384. {
  385. hr = pTopology->AddNode(pSourceNode);
  386. }
  387. if (SUCCEEDED(hr))
  388. {
  389. hr = pTopology->AddNode(pOutputNode);
  390. }
  391. if (SUCCEEDED(hr))
  392. {
  393. hr = pSourceNode->ConnectOutput(0, pOutputNode, 0);
  394. }
  395. SAFE_RELEASE(pSourceNode);
  396. SAFE_RELEASE(pOutputNode);
  397. return hr;
  398. }
  399. //////////////////////////////////////////////////////////////////////
  400. //  Name: CreateSourceNode
  401. //  Creates a source node for a media stream. 
  402. //
  403. //  pSource:   Pointer to the media source.
  404. //  pSourcePD: Pointer to the source's presentation descriptor.
  405. //  pSourceSD: Pointer to the stream descriptor.
  406. //  ppNode:    Receives the IMFTopologyNode pointer.
  407. ///////////////////////////////////////////////////////////////////////
  408. HRESULT CHSPlayer::CreateSourceNode(
  409.  IMFMediaSource *pSource,          // Media source.
  410.  IMFPresentationDescriptor *pPD,   // Presentation descriptor.
  411.  IMFStreamDescriptor *pSD,         // Stream descriptor.
  412.  IMFTopologyNode **ppNode          // Receives the node pointer.
  413.  )
  414. {
  415. IMFTopologyNode *pNode = NULL;
  416. HRESULT hr = S_OK;
  417. // Create the node.
  418. hr = MFCreateTopologyNode(
  419. MF_TOPOLOGY_SOURCESTREAM_NODE, 
  420. &pNode);
  421. // Set the attributes.
  422. if (SUCCEEDED(hr))
  423. {
  424. hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource);
  425. }
  426. if (SUCCEEDED(hr))
  427. {
  428. hr = pNode->SetUnknown(
  429. MF_TOPONODE_PRESENTATION_DESCRIPTOR, 
  430. pPD);
  431. }
  432. if (SUCCEEDED(hr))
  433. {
  434. hr = pNode->SetUnknown(
  435. MF_TOPONODE_STREAM_DESCRIPTOR, 
  436. pSD);
  437. }
  438. // Return the pointer to the caller.
  439. if (SUCCEEDED(hr))
  440. {
  441. *ppNode = pNode;
  442. (*ppNode)->AddRef();
  443. }
  444. SAFE_RELEASE(pNode);
  445. return hr;
  446. }
  447. ///////////////////////////////////////////////////////////////////////
  448. //  Name: CreateOutputNode
  449. //  Description:  Creates an output node for a stream sink.
  450. //
  451. //  pSink:     The media sink.
  452. //  iStream:   Index of the stream sink on the media sink.
  453. //  ppNode:    Receives a pointer to the topology node.
  454. ///////////////////////////////////////////////////////////////////////
  455. HRESULT CHSPlayer::CreateOutputNode(IMFMediaSink *pSink, DWORD iStream, IMFTopologyNode **ppNode)
  456. {
  457. IMFTopologyNode *pNode = NULL;
  458. IMFStreamSink *pStream = NULL;
  459. HRESULT hr = S_OK;
  460. hr = pSink->GetStreamSinkByIndex(iStream, &pStream);
  461. if (SUCCEEDED(hr))
  462. {
  463. hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode);
  464. }
  465. if (SUCCEEDED(hr))
  466. {
  467. hr = pNode->SetObject(pStream);
  468. }
  469. if (SUCCEEDED(hr))
  470. {
  471. *ppNode = pNode;
  472. (*ppNode)->AddRef();
  473. }
  474. SAFE_RELEASE(pNode);
  475. SAFE_RELEASE(pStream);
  476. return hr;
  477. }
  478. ///////////////////////////////////////////////////////////////////////
  479. //  Name: GetStreamMajorType
  480. //  Description:  Get the major media type from a stream descriptor.
  481. //
  482. //  Note: 
  483. //  To get the major media type from a stream descriptor, you need to go
  484. //  through the stream descriptor's media type handler. Use this helper
  485. //  function if you don't need the type handler for anything else.
  486. // 
  487. /////////////////////////////////////////////////////////////////////////
  488. HRESULT CHSPlayer::GetStreamMajorType(IMFStreamDescriptor *pSD, GUID *pguidMajorType)
  489. {
  490. CheckPointer(pSD, E_POINTER);
  491. CheckPointer(pguidMajorType, E_POINTER);
  492. HRESULT hr = S_OK;
  493. IMFMediaTypeHandler *pHandler = NULL;
  494. hr = pSD->GetMediaTypeHandler(&pHandler);
  495. if (SUCCEEDED(hr))
  496. {
  497. hr = pHandler->GetMajorType(pguidMajorType);
  498. }
  499. SAFE_RELEASE(pHandler);
  500. return hr;
  501. }
  502. // AddRef and Release for callbacks only; not functional
  503. LONG CHSPlayer::AddRef()
  504. {   
  505. return m_cRef;
  506. }
  507. LONG CHSPlayer::Release()
  508. {
  509. return m_cRef;
  510. }