mf_custom_src.cxx 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593
  1. /*
  2. * Copyright (C) Microsoft Corporation. All rights reserved.
  3. * Copyright (C) 2013 Mamadou DIOP
  4. * Copyright (C) 2013 Doubango Telecom <http://www.doubango.org>
  5. *
  6. * This file is part of Open Source Doubango Framework.
  7. *
  8. * DOUBANGO is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * DOUBANGO is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with DOUBANGO.
  20. */
  21. // Implementing custom source: http://msdn.microsoft.com/en-us/library/windows/desktop/ms700134(v=vs.85).aspx
  22. #include "mf_custom_src.h"
  23. #include "mf_utils.h"
  24. #include "tsk_debug.h"
  25. #include <assert.h>
  26. //
  27. // Locking:
  28. // The source and stream objects both have critical sections. If you
  29. // hold both locks, the source lock must be held FIRST, to avoid
  30. // deadlocks.
  31. //
  32. // Shutdown:
  33. // Most methods start by calling CheckShutdown(). This method
  34. // fails if the source was shut down.
  35. //
  36. template <class T>
  37. T AlignUp(T num, T mult)
  38. {
  39. assert(num >= 0);
  40. T tmp = num + mult - 1;
  41. return tmp - (tmp % mult);
  42. }
  43. // Helper Functions
  44. HRESULT QueueEventWithIUnknown(
  45. IMFMediaEventGenerator *pMEG,
  46. MediaEventType meType,
  47. HRESULT hrStatus,
  48. IUnknown *pUnk);
  49. LONGLONG BufferSizeFromAudioDuration(const WAVEFORMATEX *pWav, LONGLONG duration);
  50. HRESULT CMFSource_CreateInstance(REFIID iid, void **ppMFT)
  51. {
  52. return CMFSource::CreateInstance(iid, ppMFT);
  53. }
  54. //-------------------------------------------------------------------
  55. // Name: CreateInstance
  56. // Description: Static method to create an instance of the source.
  57. //
  58. // iid: IID of the requested interface on the source.
  59. // ppSource: Receives a ref-counted pointer to the source.
  60. //-------------------------------------------------------------------
  61. HRESULT CMFSource::CreateInstance(REFIID iid, void **ppSource) // Called when source used as plugin
  62. {
  63. return CreateInstanceEx(iid, ppSource, NULL);
  64. }
  65. HRESULT CMFSource::CreateInstanceEx(REFIID iid, void **ppSource, IMFMediaType *pMediaType) // Called when source directly called
  66. {
  67. if (ppSource == NULL) {
  68. return E_POINTER;
  69. }
  70. HRESULT hr = S_OK;
  71. CMFSource *pSource = new (std::nothrow) CMFSource(hr, pMediaType); // Created with ref count = 1.
  72. if (pSource == NULL) {
  73. return E_OUTOFMEMORY;
  74. }
  75. if (SUCCEEDED(hr)) {
  76. hr = pSource->QueryInterface(iid, ppSource);
  77. if(SUCCEEDED(hr)) {
  78. ((CMFSource*)(*ppSource))->AddRef();
  79. }
  80. }
  81. SafeRelease(&pSource);
  82. return hr;
  83. }
  84. //-------------------------------------------------------------------
  85. // CMFSource constructor.
  86. //
  87. // hr: If the constructor fails, this value is set to a failure code.
  88. //-------------------------------------------------------------------
  89. CMFSource::CMFSource(HRESULT& hr, IMFMediaType *pMediaType)
  90. : m_nRefCount(1),
  91. m_pEventQueue(NULL),
  92. m_pPresentationDescriptor(NULL),
  93. m_IsShutdown(FALSE),
  94. m_state(STATE_STOPPED),
  95. m_pStream(NULL),
  96. m_pMediaType(NULL)
  97. {
  98. // Create the media event queue.
  99. hr = MFCreateEventQueue(&m_pEventQueue);
  100. if(pMediaType) {
  101. m_pMediaType = pMediaType;
  102. pMediaType->AddRef();
  103. }
  104. InitializeCriticalSection(&m_critSec);
  105. }
  106. //-------------------------------------------------------------------
  107. // CMFSource destructor.
  108. //-------------------------------------------------------------------
  109. CMFSource::~CMFSource()
  110. {
  111. assert(m_IsShutdown);
  112. assert(m_nRefCount == 0);
  113. SafeRelease(&m_pMediaType);
  114. DeleteCriticalSection(&m_critSec);
  115. }
  116. // IMFCustomSource methods
  117. HRESULT CMFSource::CopyVideoBuffer(UINT32 nWidth, UINT32 nHeight, const void* pBufferPtr, UINT32 nBufferSize)
  118. {
  119. if(!pBufferPtr) {
  120. TSK_DEBUG_ERROR("Invalid buffer pointer");
  121. return E_POINTER;
  122. }
  123. if(!nWidth || !nHeight || !nBufferSize) {
  124. TSK_DEBUG_ERROR("Invalid parameter");
  125. return E_INVALIDARG;
  126. }
  127. if(m_pStream) {
  128. return m_pStream->CopyVideoBuffer(nWidth, nHeight, pBufferPtr, nBufferSize);
  129. }
  130. else {
  131. TSK_DEBUG_ERROR("No stream associated to this source");
  132. return E_NOT_VALID_STATE;
  133. }
  134. }
  135. // IUnknown methods
  136. ULONG CMFSource::AddRef()
  137. {
  138. return InterlockedIncrement(&m_nRefCount);
  139. }
  140. ULONG CMFSource::Release()
  141. {
  142. ULONG uCount = InterlockedDecrement(&m_nRefCount);
  143. if (uCount == 0) {
  144. delete this;
  145. }
  146. // For thread safety, return a temporary variable.
  147. return uCount;
  148. }
  149. HRESULT CMFSource::QueryInterface(REFIID iid, void** ppv)
  150. {
  151. static const QITAB qit[] = {
  152. QITABENT(CMFSource, IMFMediaEventGenerator),
  153. QITABENT(CMFSource, IMFMediaSource),
  154. { 0 }
  155. };
  156. return QISearch(this, qit, iid, ppv);
  157. }
  158. // IMFMediaEventGenerator methods
  159. //
  160. // All of the IMFMediaEventGenerator methods do the following:
  161. // 1. Check for shutdown status.
  162. // 2. Call the event generator helper object.
  163. HRESULT CMFSource::BeginGetEvent(IMFAsyncCallback* pCallback, IUnknown* punkState)
  164. {
  165. HRESULT hr = S_OK;
  166. EnterCriticalSection(&m_critSec);
  167. hr = CheckShutdown();
  168. if (SUCCEEDED(hr)) {
  169. hr = m_pEventQueue->BeginGetEvent(pCallback, punkState);
  170. }
  171. LeaveCriticalSection(&m_critSec);
  172. return hr;
  173. }
  174. HRESULT CMFSource::EndGetEvent(IMFAsyncResult* pResult, IMFMediaEvent** ppEvent)
  175. {
  176. HRESULT hr = S_OK;
  177. EnterCriticalSection(&m_critSec);
  178. hr = CheckShutdown();
  179. if (SUCCEEDED(hr)) {
  180. hr = m_pEventQueue->EndGetEvent(pResult, ppEvent);
  181. }
  182. LeaveCriticalSection(&m_critSec);
  183. return hr;
  184. }
  185. HRESULT CMFSource::GetEvent(DWORD dwFlags, IMFMediaEvent** ppEvent)
  186. {
  187. // NOTE: GetEvent can block indefinitely, so we don't hold the
  188. // CMFSource lock. This requires some juggling with the
  189. // event queue pointer.
  190. HRESULT hr = S_OK;
  191. IMFMediaEventQueue *pQueue = NULL;
  192. EnterCriticalSection(&m_critSec);
  193. // Check shutdown
  194. hr = CheckShutdown();
  195. if (SUCCEEDED(hr)) {
  196. pQueue = m_pEventQueue;
  197. pQueue->AddRef();
  198. }
  199. LeaveCriticalSection(&m_critSec);
  200. if (SUCCEEDED(hr)) {
  201. hr = pQueue->GetEvent(dwFlags, ppEvent);
  202. }
  203. SafeRelease(&pQueue);
  204. return hr;
  205. }
  206. HRESULT CMFSource::QueueEvent(MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, const PROPVARIANT* pvValue)
  207. {
  208. HRESULT hr = S_OK;
  209. EnterCriticalSection(&m_critSec);
  210. hr = CheckShutdown();
  211. if (SUCCEEDED(hr)) {
  212. hr = m_pEventQueue->QueueEventParamVar(met, guidExtendedType, hrStatus, pvValue);
  213. }
  214. LeaveCriticalSection(&m_critSec);
  215. return hr;
  216. }
  217. // IMFMediaSource methods
  218. //-------------------------------------------------------------------
  219. // Name: CreatePresentationDescriptor
  220. // Description: Returns a copy of the default presentation descriptor.
  221. //-------------------------------------------------------------------
  222. HRESULT CMFSource::CreatePresentationDescriptor(IMFPresentationDescriptor** ppPresentationDescriptor)
  223. {
  224. if (ppPresentationDescriptor == NULL) {
  225. return E_POINTER;
  226. }
  227. EnterCriticalSection(&m_critSec);
  228. HRESULT hr = S_OK;
  229. hr = CheckShutdown();
  230. if (SUCCEEDED(hr)) {
  231. if (m_pPresentationDescriptor == NULL) {
  232. hr = CreatePresentationDescriptor();
  233. }
  234. }
  235. // Clone our default presentation descriptor.
  236. if (SUCCEEDED(hr)) {
  237. hr = m_pPresentationDescriptor->Clone(ppPresentationDescriptor);
  238. }
  239. LeaveCriticalSection(&m_critSec);
  240. return hr;
  241. }
  242. //-------------------------------------------------------------------
  243. // Name: GetCharacteristics
  244. // Description: Returns flags the describe the source.
  245. //-------------------------------------------------------------------
  246. HRESULT CMFSource::GetCharacteristics(DWORD* pdwCharacteristics)
  247. {
  248. if (pdwCharacteristics == NULL) {
  249. return E_POINTER;
  250. }
  251. EnterCriticalSection(&m_critSec);
  252. HRESULT hr = S_OK;
  253. hr = CheckShutdown();
  254. if (SUCCEEDED(hr)) {
  255. *pdwCharacteristics = MFMEDIASOURCE_CAN_PAUSE | MFMEDIASOURCE_IS_LIVE;
  256. }
  257. LeaveCriticalSection(&m_critSec);
  258. return hr;
  259. }
  260. //-------------------------------------------------------------------
  261. // Name: Start
  262. // Description: Switches to running state.
  263. //-------------------------------------------------------------------
  264. HRESULT CMFSource::Start(
  265. IMFPresentationDescriptor* pPresentationDescriptor,
  266. const GUID* pguidTimeFormat,
  267. const PROPVARIANT* pvarStartPosition
  268. )
  269. {
  270. HRESULT hr = S_OK;
  271. LONGLONG llStartOffset = 0;
  272. BOOL bIsSeek = FALSE;
  273. BOOL bIsRestartFromCurrentPosition = FALSE;
  274. BOOL bQueuedStartEvent = FALSE;
  275. IMFMediaEvent *pEvent = NULL;
  276. PROPVARIANT var;
  277. PropVariantInit(&var);
  278. // Check parameters.
  279. // Start position and presentation descriptor cannot be NULL.
  280. if (pvarStartPosition == NULL || pPresentationDescriptor == NULL) {
  281. return E_INVALIDARG;
  282. }
  283. // Check the time format. Must be "reference time" units.
  284. if ((pguidTimeFormat != NULL) && (*pguidTimeFormat != GUID_NULL)) {
  285. // Unrecognized time format GUID.
  286. return MF_E_UNSUPPORTED_TIME_FORMAT;
  287. }
  288. EnterCriticalSection(&m_critSec);
  289. // Fail if the source is shut down.
  290. CHECK_HR(hr = CheckShutdown());
  291. // Check the start position.
  292. if (pvarStartPosition->vt == VT_I8) {
  293. // Start position is given in pvarStartPosition in 100-ns units.
  294. llStartOffset = pvarStartPosition->hVal.QuadPart;
  295. if (m_state != STATE_STOPPED) {
  296. // Source is running or paused, so this is a seek.
  297. bIsSeek = TRUE;
  298. }
  299. }
  300. else if (pvarStartPosition->vt == VT_EMPTY) {
  301. // Start position is "current position".
  302. // For stopped, that means 0. Otherwise, use the current position.
  303. if (m_state == STATE_STOPPED) {
  304. llStartOffset = 0;
  305. }
  306. else {
  307. llStartOffset = GetCurrentPosition();
  308. bIsRestartFromCurrentPosition = TRUE;
  309. }
  310. }
  311. else {
  312. // We don't support this time format.
  313. hr = MF_E_UNSUPPORTED_TIME_FORMAT;
  314. goto bail;
  315. }
  316. // Validate the caller's presentation descriptor.
  317. CHECK_HR(hr = ValidatePresentationDescriptor(pPresentationDescriptor));
  318. // Sends the MENewStream or MEUpdatedStream event.
  319. CHECK_HR(hr = QueueNewStreamEvent(pPresentationDescriptor));
  320. // Notify the stream of the new start time.
  321. CHECK_HR(hr = m_pStream->SetPosition(llStartOffset));
  322. // Send Started or Seeked events.
  323. var.vt = VT_I8;
  324. var.hVal.QuadPart = llStartOffset;
  325. // Send the source event.
  326. if (bIsSeek) {
  327. CHECK_HR(hr = QueueEvent(MESourceSeeked, GUID_NULL, hr, &var));
  328. }
  329. else {
  330. // For starting, if we are RESTARTING from the current position and our
  331. // previous state was running/paused, then we need to add the
  332. // MF_EVENT_SOURCE_ACTUAL_START attribute to the event. This requires
  333. // creating the event object first.
  334. // Create the event.
  335. CHECK_HR(hr = MFCreateMediaEvent(MESourceStarted, GUID_NULL, hr, &var, &pEvent));
  336. // For restarts, set the actual start time as an attribute.
  337. if (bIsRestartFromCurrentPosition) {
  338. CHECK_HR(hr = pEvent->SetUINT64(MF_EVENT_SOURCE_ACTUAL_START, llStartOffset));
  339. }
  340. // Now queue the event.
  341. CHECK_HR(hr = m_pEventQueue->QueueEvent(pEvent));
  342. }
  343. bQueuedStartEvent = TRUE;
  344. // Send the stream event.
  345. if (m_pStream) {
  346. if (bIsSeek) {
  347. CHECK_HR(hr = m_pStream->QueueEvent(MEStreamSeeked, GUID_NULL, hr, &var));
  348. }
  349. else {
  350. CHECK_HR(hr = m_pStream->QueueEvent(MEStreamStarted, GUID_NULL, hr, &var));
  351. }
  352. }
  353. if (bIsSeek) {
  354. // For seek requests, flush any queued samples.
  355. CHECK_HR(hr = m_pStream->Flush());
  356. }
  357. else {
  358. // Otherwise, deliver any queued samples.
  359. CHECK_HR(hr = m_pStream->DeliverQueuedSamples());
  360. }
  361. // Initialize Stream parameters
  362. CHECK_HR(hr = m_pStream->InitializeParams());
  363. m_state = STATE_STARTED;
  364. bail:
  365. // If a failure occurred and we have not sent the
  366. // MESourceStarted/MESourceSeeked event yet, then it is
  367. // OK just to return an error code from Start().
  368. // If a failure occurred and we have already sent the
  369. // event (with a success code), then we need to raise an
  370. // MEError event.
  371. if (FAILED(hr) && bQueuedStartEvent) {
  372. hr = QueueEvent(MEError, GUID_NULL, hr, &var);
  373. }
  374. PropVariantClear(&var);
  375. SafeRelease(&pEvent);
  376. LeaveCriticalSection(&m_critSec);
  377. return hr;
  378. }
  379. //-------------------------------------------------------------------
  380. // Name: Pause
  381. // Description: Switches to paused state.
  382. //-------------------------------------------------------------------
  383. HRESULT CMFSource::Pause()
  384. {
  385. EnterCriticalSection(&m_critSec);
  386. HRESULT hr = S_OK;
  387. hr = CheckShutdown();
  388. // Pause is only allowed from started state.
  389. if (SUCCEEDED(hr)) {
  390. if (m_state != STATE_STARTED) {
  391. hr = MF_E_INVALID_STATE_TRANSITION;
  392. }
  393. }
  394. // Send the appropriate events.
  395. if (SUCCEEDED(hr)) {
  396. if (m_pStream) {
  397. hr = m_pStream->QueueEvent(MEStreamPaused, GUID_NULL, S_OK, NULL);
  398. }
  399. }
  400. if (SUCCEEDED(hr)) {
  401. hr = QueueEvent(MESourcePaused, GUID_NULL, S_OK, NULL);
  402. }
  403. // Update our state.
  404. if (SUCCEEDED(hr)) {
  405. m_state = STATE_PAUSED;
  406. }
  407. LeaveCriticalSection(&m_critSec);
  408. return hr;
  409. }
  410. //-------------------------------------------------------------------
  411. // Name: Stop
  412. // Description: Switches to stopped state.
  413. //-------------------------------------------------------------------
  414. HRESULT CMFSource::Stop()
  415. {
  416. EnterCriticalSection(&m_critSec);
  417. HRESULT hr = S_OK;
  418. hr = CheckShutdown();
  419. if (SUCCEEDED(hr)) {
  420. // Update our state.
  421. m_state = STATE_STOPPED;
  422. // Flush all queued samples.
  423. hr = m_pStream->Flush();
  424. }
  425. //
  426. // Queue events.
  427. //
  428. if (SUCCEEDED(hr)) {
  429. if (m_pStream) {
  430. hr = m_pStream->QueueEvent(MEStreamStopped, GUID_NULL, S_OK, NULL);
  431. }
  432. }
  433. if (SUCCEEDED(hr)) {
  434. hr = QueueEvent(MESourceStopped, GUID_NULL, S_OK, NULL);
  435. }
  436. LeaveCriticalSection(&m_critSec);
  437. return hr;
  438. }
  439. //-------------------------------------------------------------------
  440. // Name: Shutdown
  441. // Description: Releases resources.
  442. //
  443. // The source and stream objects hold reference counts on each other.
  444. // To avoid memory leaks caused by circular ref. counts, the Shutdown
  445. // method releases the pointer to the stream.
  446. //-------------------------------------------------------------------
  447. HRESULT CMFSource::Shutdown()
  448. {
  449. EnterCriticalSection(&m_critSec);
  450. HRESULT hr = S_OK;
  451. hr = CheckShutdown();
  452. if (SUCCEEDED(hr)) {
  453. // Shut down the stream object.
  454. if (m_pStream) {
  455. (void)m_pStream->Shutdown();
  456. }
  457. // Shut down the event queue.
  458. if (m_pEventQueue) {
  459. (void)m_pEventQueue->Shutdown();
  460. }
  461. // Release objects.
  462. SafeRelease(&m_pStream);
  463. SafeRelease(&m_pEventQueue);
  464. SafeRelease(&m_pPresentationDescriptor);
  465. // Set our shutdown flag.
  466. m_IsShutdown = TRUE;
  467. }
  468. LeaveCriticalSection(&m_critSec);
  469. return hr;
  470. }
  471. /////////////// Private CMFSource methods
  472. // NOTE: These private methods do not hold the source's critical
  473. // section. The caller must ensure the critical section is held.
  474. // Also, these methods do not check for shut-down.
  475. //-------------------------------------------------------------------
  476. // Name: CreatePresentationDescriptor
  477. // Description: Creates the default presentation descriptor.
  478. //-------------------------------------------------------------------
  479. HRESULT CMFSource::CreatePresentationDescriptor()
  480. {
  481. HRESULT hr = S_OK;
  482. IMFStreamDescriptor *pStreamDescriptor = NULL;
  483. IMFMediaTypeHandler *pHandler = NULL;
  484. // Create the stream descriptor.
  485. hr = MFCreateStreamDescriptor(
  486. 0, // stream identifier
  487. 1, // Number of media types.
  488. &m_pMediaType, // Array of media types
  489. &pStreamDescriptor
  490. );
  491. // Set the default media type on the media type handler.
  492. if (SUCCEEDED(hr)) {
  493. hr = pStreamDescriptor->GetMediaTypeHandler(&pHandler);
  494. }
  495. if (SUCCEEDED(hr)) {
  496. hr = pHandler->SetCurrentMediaType(m_pMediaType);
  497. }
  498. // Create the presentation descriptor.
  499. if (SUCCEEDED(hr)) {
  500. hr = MFCreatePresentationDescriptor(
  501. 1, // Number of stream descriptors
  502. &pStreamDescriptor, // Array of stream descriptors
  503. &m_pPresentationDescriptor
  504. );
  505. }
  506. // Select the first stream
  507. if (SUCCEEDED(hr)) {
  508. hr = m_pPresentationDescriptor->SelectStream(0);
  509. }
  510. // Set the file/stream duration as an attribute on the presentation descriptor.
  511. if (SUCCEEDED(hr)) {
  512. hr = m_pPresentationDescriptor->SetUINT64(MF_PD_DURATION, (UINT64)ULLONG_MAX);
  513. }
  514. SafeRelease(&pStreamDescriptor);
  515. SafeRelease(&pHandler);
  516. return hr;
  517. }
  518. //-------------------------------------------------------------------
  519. // Name: ValidatePresentationDescriptor
  520. // Description: Validates the caller's presentation descriptor.
  521. //
  522. // This method is called when Start() is called with a non-NULL
  523. // presentation descriptor. The caller is supposed to give us back
  524. // the same PD that we gave out in CreatePresentationDescriptor().
  525. // This method performs a sanity check on the caller's PD to make
  526. // sure it matches ours.
  527. //
  528. // Note: Because this media source has one stream with single, fixed
  529. // media type, there is not much for the caller to decide. In
  530. // a more complicated source, the caller might select different
  531. // streams, or select from a list of media types.
  532. //-------------------------------------------------------------------
  533. HRESULT CMFSource::ValidatePresentationDescriptor(IMFPresentationDescriptor *pPD)
  534. {
  535. HRESULT hr;
  536. assert(pPD != NULL);
  537. IMFStreamDescriptor *pStreamDescriptor = NULL;
  538. IMFMediaTypeHandler *pHandler = NULL;
  539. IMFMediaType *pMediaType = NULL;
  540. GUID majorType;
  541. DWORD cStreamDescriptors = 0;
  542. BOOL fSelected = FALSE;
  543. // Make sure there is only one stream.
  544. hr = pPD->GetStreamDescriptorCount(&cStreamDescriptors);
  545. if (SUCCEEDED(hr)) {
  546. if (cStreamDescriptors != 1) {
  547. hr = MF_E_UNSUPPORTED_REPRESENTATION;
  548. }
  549. }
  550. // Get the stream descriptor.
  551. if (SUCCEEDED(hr)) {
  552. hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pStreamDescriptor);
  553. }
  554. // Make sure it's selected. (This media source has only one stream, so it
  555. // is not useful to deselect the only stream.)
  556. if (SUCCEEDED(hr)) {
  557. if (!fSelected) {
  558. hr = MF_E_UNSUPPORTED_REPRESENTATION;
  559. }
  560. }
  561. // Get the media type handler, so that we can get the media type.
  562. if (SUCCEEDED(hr)) {
  563. hr = pStreamDescriptor->GetMediaTypeHandler(&pHandler);
  564. }
  565. if (SUCCEEDED(hr)) {
  566. hr = pHandler->GetCurrentMediaType(&pMediaType);
  567. }
  568. hr = pMediaType->GetMajorType(&majorType);
  569. if (SUCCEEDED(hr)) {
  570. if(majorType == MFMediaType_Video) {
  571. if (SUCCEEDED(hr)) {
  572. hr = MFUtils::ValidateVideoFormat(pMediaType);
  573. }
  574. }
  575. else {
  576. WAVEFORMATEX *pFormat = NULL;
  577. UINT32 cbWaveFormat = 0;
  578. if (SUCCEEDED(hr)) {
  579. hr = MFCreateWaveFormatExFromMFMediaType(
  580. pMediaType,
  581. &pFormat,
  582. &cbWaveFormat);
  583. }
  584. if (SUCCEEDED(hr)) {
  585. /*assert(this->WaveFormat() != NULL);
  586. if (cbWaveFormat < this->WaveFormatSize())
  587. {
  588. hr = MF_E_INVALIDMEDIATYPE;
  589. }*/
  590. }
  591. if (SUCCEEDED(hr)) {
  592. /*if (memcmp(pFormat, WaveFormat(), WaveFormatSize()) != 0)
  593. {
  594. hr = MF_E_INVALIDMEDIATYPE;
  595. }*/
  596. }
  597. CoTaskMemFree(pFormat);
  598. }
  599. }
  600. SafeRelease(&pStreamDescriptor);
  601. SafeRelease(&pHandler);
  602. SafeRelease(&pMediaType);
  603. return hr;
  604. }
  605. //-------------------------------------------------------------------
  606. // Name: QueueNewStreamEvent
  607. // Description:
  608. // Queues an MENewStream or MEUpdatedStream event during Start.
  609. //
  610. // pPD: The presentation descriptor.
  611. //
  612. // Precondition: The presentation descriptor is assumed to be valid.
  613. // Call ValidatePresentationDescriptor before calling this method.
  614. //-------------------------------------------------------------------
  615. HRESULT CMFSource::QueueNewStreamEvent(IMFPresentationDescriptor *pPD)
  616. {
  617. assert(pPD != NULL);
  618. HRESULT hr = S_OK;
  619. IMFStreamDescriptor *pSD = NULL;
  620. BOOL fSelected = FALSE;
  621. hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD);
  622. if (SUCCEEDED(hr)) {
  623. // The stream must be selected, because we don't allow the app
  624. // to de-select the stream. See ValidatePresentationDescriptor.
  625. assert(fSelected);
  626. if (m_pStream) {
  627. // The stream already exists, and is still selected.
  628. // Send the MEUpdatedStream event.
  629. hr = QueueEventWithIUnknown(this, MEUpdatedStream, S_OK, m_pStream);
  630. }
  631. else {
  632. // The stream does not exist, and is now selected.
  633. // Create a new stream.
  634. hr = CreateCMFStreamSource(pSD);
  635. if (SUCCEEDED(hr)) {
  636. // CreateCMFStreamSource creates the stream, so m_pStream is no longer NULL.
  637. assert(m_pStream != NULL);
  638. // Send the MENewStream event.
  639. hr = QueueEventWithIUnknown(this, MENewStream, S_OK, m_pStream);
  640. }
  641. }
  642. }
  643. SafeRelease(&pSD);
  644. return hr;
  645. }
  646. //-------------------------------------------------------------------
  647. // Name: CreateCMFStreamSource
  648. // Description: Creates the source's media stream object.
  649. //-------------------------------------------------------------------
  650. HRESULT CMFSource::CreateCMFStreamSource(IMFStreamDescriptor *pSD)
  651. {
  652. HRESULT hr = S_OK;
  653. m_pStream = new (std::nothrow) CMFStreamSource(this, pSD, hr);
  654. if (m_pStream == NULL) {
  655. hr = E_OUTOFMEMORY;
  656. }
  657. if (FAILED(hr)) {
  658. SafeRelease(&m_pStream);
  659. }
  660. return hr;
  661. }
  662. //-------------------------------------------------------------------
  663. // Name: GetCurrentPosition
  664. // Description: Returns the current playback position.
  665. //-------------------------------------------------------------------
  666. LONGLONG CMFSource::GetCurrentPosition() const
  667. {
  668. if (m_pStream) {
  669. return m_pStream->GetCurrentPosition();
  670. }
  671. else {
  672. // If no stream is selected, we are at time 0 by definition.
  673. return 0;
  674. }
  675. }
  676. ////////// AUDIO STREAM
  677. //-------------------------------------------------------------------
  678. // CMFStreamSource constructor.
  679. //
  680. // pSource: Parent media source.
  681. // pSD: Stream descriptor that describes this stream.
  682. // hr: If the constructor fails, this value is set to a failure code.
  683. //-------------------------------------------------------------------
  684. CMFStreamSource::CMFStreamSource(CMFSource *pSource, IMFStreamDescriptor *pSD, HRESULT& hr) :
  685. m_nRefCount(1),
  686. m_pEventQueue(NULL),
  687. m_IsShutdown(FALSE),
  688. m_rtCurrentPosition(0),
  689. m_rtDuration(0),
  690. m_discontinuity(FALSE),
  691. m_EOS(FALSE),
  692. m_pMediaBuffer(NULL),
  693. m_nBufferSize(0)
  694. {
  695. m_pSource = pSource;
  696. m_pSource->AddRef();
  697. m_pStreamDescriptor = pSD;
  698. m_pStreamDescriptor->AddRef();
  699. // Create the media event queue.
  700. CHECK_HR(hr = MFCreateEventQueue(&m_pEventQueue));
  701. //CHECK_HR(hr = InitializeParams());
  702. InitializeCriticalSection(&m_critSec);
  703. bail:
  704. return;
  705. }
  706. //-------------------------------------------------------------------
  707. // CMFStreamSource destructor.
  708. //-------------------------------------------------------------------
  709. CMFStreamSource::~CMFStreamSource()
  710. {
  711. assert(m_IsShutdown);
  712. assert(m_nRefCount == 0);
  713. SafeRelease(&m_pMediaBuffer);
  714. DeleteCriticalSection(&m_critSec);
  715. }
  716. // IMFCustomSource methods
  717. HRESULT CMFStreamSource::CopyVideoBuffer(UINT32 nWidth, UINT32 nHeight, const void* pBufferPtr, UINT32 nBufferSize)
  718. {
  719. // Buffer pointer and size validity already checked by source (caller)
  720. if(m_guidMajorType != MFMediaType_Video) {
  721. TSK_DEBUG_ERROR("Calling CopyVideoBuffer on no-video stream");
  722. #if defined(E_ILLEGAL_METHOD_CALL)
  723. return E_ILLEGAL_METHOD_CALL;
  724. #else
  725. return _HRESULT_TYPEDEF_(0x8000000EL);
  726. #endif
  727. }
  728. if(nWidth != m_structVideoParams.nWidth || nHeight != m_structVideoParams.nHeigh || nBufferSize != m_nBufferSize) {
  729. TSK_DEBUG_ERROR("Invalid argument %u#%u or %u#%u or %u#%u. If the call is from a video consumer then, you can safely ignore this message.", nWidth, m_structVideoParams.nWidth, nHeight, m_structVideoParams.nHeigh, nBufferSize, m_nBufferSize);
  730. #if defined(E_BOUNDS)
  731. return E_BOUNDS;
  732. #else
  733. return _HRESULT_TYPEDEF_(0x8000000BL);
  734. #endif
  735. }
  736. HRESULT hr = S_OK;
  737. BYTE* pMediaBufferPtr = NULL;
  738. DWORD cbMaxLength = nBufferSize, cbCurrentLength = nBufferSize;
  739. CHECK_HR(hr = m_pMediaBuffer->Lock(&pMediaBufferPtr, &cbMaxLength, &cbCurrentLength));
  740. memcpy(pMediaBufferPtr, pBufferPtr, nBufferSize);
  741. CHECK_HR(hr = m_pMediaBuffer->SetCurrentLength(nBufferSize));
  742. CHECK_HR(hr = m_pMediaBuffer->Unlock());
  743. bail:
  744. return hr;
  745. }
  746. // IUnknown methods
  747. ULONG CMFStreamSource::AddRef()
  748. {
  749. return InterlockedIncrement(&m_nRefCount);
  750. }
  751. ULONG CMFStreamSource::Release()
  752. {
  753. ULONG uCount = InterlockedDecrement(&m_nRefCount);
  754. if (uCount == 0) {
  755. delete this;
  756. }
  757. // For thread safety, return a temporary variable.
  758. return uCount;
  759. }
  760. HRESULT CMFStreamSource::QueryInterface(REFIID iid, void** ppv)
  761. {
  762. static const QITAB qit[] = {
  763. QITABENT(CMFStreamSource, IMFMediaEventGenerator),
  764. QITABENT(CMFStreamSource, IMFMediaStream),
  765. { 0 }
  766. };
  767. return QISearch(this, qit, iid, ppv);
  768. }
  769. // IMFMediaEventGenerator methods
  770. // [See note for CMFSource class]
  771. HRESULT CMFStreamSource::BeginGetEvent(IMFAsyncCallback* pCallback, IUnknown* punkState)
  772. {
  773. HRESULT hr = S_OK;
  774. EnterCriticalSection(&m_critSec);
  775. hr = CheckShutdown();
  776. if (SUCCEEDED(hr)) {
  777. hr = m_pEventQueue->BeginGetEvent(pCallback, punkState);
  778. }
  779. LeaveCriticalSection(&m_critSec);
  780. return hr;
  781. }
  782. HRESULT CMFStreamSource::EndGetEvent(IMFAsyncResult* pResult, IMFMediaEvent** ppEvent)
  783. {
  784. HRESULT hr = S_OK;
  785. EnterCriticalSection(&m_critSec);
  786. hr = CheckShutdown();
  787. if (SUCCEEDED(hr)) {
  788. hr = m_pEventQueue->EndGetEvent(pResult, ppEvent);
  789. }
  790. LeaveCriticalSection(&m_critSec);
  791. return hr;
  792. }
  793. HRESULT CMFStreamSource::GetEvent(DWORD dwFlags, IMFMediaEvent** ppEvent)
  794. {
  795. HRESULT hr = S_OK;
  796. IMFMediaEventQueue *pQueue = NULL;
  797. EnterCriticalSection(&m_critSec);
  798. hr = CheckShutdown();
  799. if (SUCCEEDED(hr)) {
  800. pQueue = m_pEventQueue;
  801. pQueue->AddRef();
  802. }
  803. LeaveCriticalSection(&m_critSec);
  804. if (SUCCEEDED(hr)) {
  805. hr = pQueue->GetEvent(dwFlags, ppEvent);
  806. }
  807. SafeRelease(&pQueue);
  808. return hr;
  809. }
  810. HRESULT CMFStreamSource::QueueEvent(MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, const PROPVARIANT* pvValue)
  811. {
  812. HRESULT hr = S_OK;
  813. EnterCriticalSection(&m_critSec);
  814. hr = CheckShutdown();
  815. if (SUCCEEDED(hr)) {
  816. hr = m_pEventQueue->QueueEventParamVar(met, guidExtendedType, hrStatus, pvValue);
  817. }
  818. LeaveCriticalSection(&m_critSec);
  819. return hr;
  820. }
  821. // IMFMediaStream methods.
  822. //-------------------------------------------------------------------
  823. // Name: GetMediaSource
  824. // Description: Returns a pointer to the media source.
  825. //-------------------------------------------------------------------
  826. HRESULT CMFStreamSource::GetMediaSource(IMFMediaSource** ppMediaSource)
  827. {
  828. if (ppMediaSource == NULL) {
  829. return E_POINTER;
  830. }
  831. EnterCriticalSection(&m_critSec);
  832. HRESULT hr = S_OK;
  833. // If called after shutdown, them m_pSource is NULL.
  834. // Otherwise, m_pSource should not be NULL.
  835. hr = CheckShutdown();
  836. if (SUCCEEDED(hr)) {
  837. if (m_pSource == NULL) {
  838. hr = E_UNEXPECTED;
  839. }
  840. }
  841. if (SUCCEEDED(hr)) {
  842. hr = m_pSource->QueryInterface(IID_PPV_ARGS(ppMediaSource));
  843. }
  844. LeaveCriticalSection(&m_critSec);
  845. return hr;
  846. }
  847. //-------------------------------------------------------------------
  848. // Name: GetStreamDescriptor
  849. // Description: Returns the stream descriptor for this stream.
  850. //-------------------------------------------------------------------
  851. HRESULT CMFStreamSource::GetStreamDescriptor(IMFStreamDescriptor** ppStreamDescriptor)
  852. {
  853. if (ppStreamDescriptor == NULL) {
  854. return E_POINTER;
  855. }
  856. if (m_pStreamDescriptor == NULL) {
  857. return E_UNEXPECTED;
  858. }
  859. EnterCriticalSection(&m_critSec);
  860. HRESULT hr = S_OK;
  861. hr = CheckShutdown();
  862. if (SUCCEEDED(hr)) {
  863. *ppStreamDescriptor = m_pStreamDescriptor;
  864. (*ppStreamDescriptor)->AddRef();
  865. }
  866. LeaveCriticalSection(&m_critSec);
  867. return hr;
  868. }
  869. //-------------------------------------------------------------------
  870. // Name: RequestSample
  871. // Description: Requests a new sample.
  872. //
  873. // pToken: Token object. Can be NULL.
  874. //-------------------------------------------------------------------
  875. HRESULT CMFStreamSource::RequestSample(IUnknown* pToken)
  876. {
  877. if (m_pSource == NULL) {
  878. return E_UNEXPECTED;
  879. }
  880. HRESULT hr = S_OK;
  881. IMFMediaSource *pSource = NULL;
  882. IMFSample *pSample = NULL; // Sample to deliver.
  883. EnterCriticalSection(&m_critSec);
  884. // Check if we are shut down.
  885. hr = CheckShutdown();
  886. // Check if we already reached the end of the stream.
  887. if (SUCCEEDED(hr)) {
  888. if (m_EOS) {
  889. hr = MF_E_END_OF_STREAM;
  890. }
  891. }
  892. // Check the source is stopped.
  893. // GetState does not hold the source's critical section. Safe to call.
  894. if (SUCCEEDED(hr)) {
  895. if (m_pSource->GetState() == CMFSource::STATE_STOPPED) {
  896. hr = MF_E_INVALIDREQUEST;
  897. }
  898. }
  899. if (SUCCEEDED(hr)) {
  900. // Create a new audio sample.
  901. hr = CreateSample(&pSample);
  902. }
  903. if (SUCCEEDED(hr)) {
  904. // If the caller provided a token, attach it to the sample as
  905. // an attribute.
  906. // NOTE: If we processed sample requests asynchronously, we would
  907. // need to call AddRef on the token and put the token onto a FIFO
  908. // queue. See documenation for IMFMediaStream::RequestSample.
  909. if (pToken && pSample) {
  910. hr = pSample->SetUnknown(MFSampleExtension_Token, pToken);
  911. }
  912. }
  913. // If paused, queue the sample for later delivery. Otherwise, deliver the sample now.
  914. if (SUCCEEDED(hr) && pSample) {
  915. if (m_pSource->GetState() == CMFSource::STATE_PAUSED) {
  916. hr = m_sampleQueue.Queue(pSample);
  917. }
  918. else {
  919. hr = DeliverSample(pSample);
  920. }
  921. }
  922. // Cache a pointer to the source, prior to leaving the critical section.
  923. if (SUCCEEDED(hr)) {
  924. pSource = m_pSource;
  925. pSource->AddRef();
  926. }
  927. LeaveCriticalSection(&m_critSec);
  928. // We only have one stream, so the end of the stream is also the end of the
  929. // presentation. Therefore, when we reach the end of the stream, we need to
  930. // queue the end-of-presentation event from the source. Logically we would do
  931. // this inside the CheckEndOfStream method. However, we cannot hold the
  932. // source's critical section while holding the stream's critical section, at
  933. // risk of deadlock.
  934. if (SUCCEEDED(hr)) {
  935. if (m_EOS) {
  936. hr = pSource->QueueEvent(MEEndOfPresentation, GUID_NULL, S_OK, NULL);
  937. }
  938. }
  939. SafeRelease(&pSample);
  940. SafeRelease(&pSource);
  941. return hr;
  942. }
  943. ///// Private CMFStreamSource methods
  944. HRESULT CMFStreamSource::InitializeParams()
  945. {
  946. HRESULT hr = S_OK;
  947. IMFMediaTypeHandler *pMediaTypeHandler = NULL;
  948. IMFMediaType* pMediaType = NULL;
  949. CHECK_HR(hr = m_pStreamDescriptor->GetMediaTypeHandler(&pMediaTypeHandler));
  950. CHECK_HR(hr = pMediaTypeHandler->GetCurrentMediaType(&pMediaType));
  951. GUID majorType, subType;
  952. pMediaType->GetMajorType(&majorType);
  953. if(majorType == MFMediaType_Video) {
  954. memset(&m_structVideoParams, 0, sizeof(m_structVideoParams));
  955. CHECK_HR(hr = MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &m_structVideoParams.nWidth, &m_structVideoParams.nHeigh));
  956. CHECK_HR(hr = pMediaType->GetGUID(MF_MT_SUBTYPE, &subType));
  957. m_guidMajorType = MFMediaType_Video;
  958. m_guidSubType = subType;
  959. // Guess video size
  960. UINT32 nBufferSize;
  961. if(subType == MFVideoFormat_RGB32) {
  962. nBufferSize = (m_structVideoParams.nWidth * m_structVideoParams.nHeigh << 2);
  963. }
  964. else if(subType == MFVideoFormat_RGB24) {
  965. nBufferSize = (m_structVideoParams.nWidth * m_structVideoParams.nHeigh << 2);
  966. }
  967. else if(subType == MFVideoFormat_NV12 || subType == MFVideoFormat_I420) {
  968. nBufferSize = (m_structVideoParams.nWidth * m_structVideoParams.nHeigh * 3) >> 1;
  969. }
  970. else {
  971. TSK_DEBUG_ERROR("Video subType not supported");
  972. CHECK_HR(hr = E_NOTIMPL);
  973. }
  974. // Allocate media buffer
  975. SafeRelease(&m_pMediaBuffer);
  976. CHECK_HR(hr = MFCreateMemoryBuffer(nBufferSize, &m_pMediaBuffer));
  977. m_nBufferSize = nBufferSize;
  978. {
  979. //FIXME: DeliverSample() stops if no data
  980. BYTE* pBuffer = NULL;
  981. CHECK_HR(hr = m_pMediaBuffer->Lock(&pBuffer, NULL, NULL));
  982. memset(pBuffer, 0, nBufferSize);
  983. CHECK_HR(hr = m_pMediaBuffer->SetCurrentLength(nBufferSize));
  984. CHECK_HR(hr = m_pMediaBuffer->Unlock());
  985. }
  986. // Retrieve video Frame rate
  987. UINT32 unNumerator, unDenominator;
  988. CHECK_HR(hr = MFGetAttributeRatio(pMediaType, MF_MT_FRAME_RATE, &unNumerator, &unDenominator));
  989. m_structVideoParams.nFps = (unNumerator / unDenominator);
  990. // Retrieve sample duration based on framerate
  991. m_rtCurrentPosition = 0;
  992. CHECK_HR(hr = MFFrameRateToAverageTimePerFrame(m_structVideoParams.nFps, 1, &m_rtDuration));
  993. }
  994. else {
  995. TSK_DEBUG_ERROR("Only video media type is supported");
  996. CHECK_HR(hr = E_NOTIMPL);
  997. }
  998. bail:
  999. SafeRelease(&pMediaTypeHandler);
  1000. SafeRelease(&pMediaType);
  1001. return hr;
  1002. }
  1003. // NOTE: Some of these methods hold the stream's critical section
  1004. // because they are called by the media source object.
  1005. //-------------------------------------------------------------------
  1006. // Name: CreateSample
  1007. // Description: Creates a new audio/video sample.
  1008. //-------------------------------------------------------------------
  1009. HRESULT CMFStreamSource::CreateSample(IMFSample **ppSample)
  1010. {
  1011. *ppSample = NULL;
  1012. HRESULT hr = S_OK;
  1013. IMFSample *pSample = NULL;
  1014. DWORD nCurrentLength = 0;
  1015. CHECK_HR(hr = m_pMediaBuffer->GetCurrentLength(&nCurrentLength));
  1016. if(nCurrentLength > 0) {
  1017. CHECK_HR(hr = MFCreateSample(&pSample));
  1018. CHECK_HR(hr = pSample->SetSampleTime(m_rtCurrentPosition));
  1019. CHECK_HR(hr = pSample->SetSampleDuration(m_rtDuration));
  1020. m_rtCurrentPosition += m_rtDuration;
  1021. CHECK_HR(hr = pSample->AddBuffer(m_pMediaBuffer));
  1022. if((*ppSample = pSample)) {
  1023. (*ppSample)->AddRef();
  1024. }
  1025. }
  1026. bail:
  1027. SafeRelease(&pSample);
  1028. return hr;
  1029. }
  1030. //-------------------------------------------------------------------
  1031. // Name: DeliverSample
  1032. // Description: Delivers a sample by sending an MEMediaSample event.
  1033. //-------------------------------------------------------------------
  1034. HRESULT CMFStreamSource::DeliverSample(IMFSample *pSample)
  1035. {
  1036. HRESULT hr = S_OK;
  1037. if(pSample) {
  1038. // Send the MEMediaSample event with the new sample.
  1039. hr = QueueEventWithIUnknown(this, MEMediaSample, hr, pSample);
  1040. }
  1041. // See if we reached the end of the stream.
  1042. if (SUCCEEDED(hr)) {
  1043. hr = CheckEndOfStream(); // This method sends MEEndOfStream if needed.
  1044. }
  1045. return hr;
  1046. }
  1047. //-------------------------------------------------------------------
  1048. // Name: DeliverQueuedSamples
  1049. // Description: Delivers any samples waiting in the queue.
  1050. //
  1051. // Note: If the client requests a sample while the source is paused,
  1052. // the sample is queued and delivered on the next non-seeking call
  1053. // to Start(). The queue is flushed if the source is seeked or
  1054. // stopped.
  1055. //-------------------------------------------------------------------
  1056. HRESULT CMFStreamSource::DeliverQueuedSamples()
  1057. {
  1058. HRESULT hr = S_OK;
  1059. IMFSample *pSample = NULL;
  1060. EnterCriticalSection(&m_critSec);
  1061. // If we already reached the end of the stream, send the MEEndStream
  1062. // event again.
  1063. if (m_EOS) {
  1064. hr = QueueEvent(MEEndOfStream, GUID_NULL, S_OK, NULL);
  1065. }
  1066. if (SUCCEEDED(hr)) {
  1067. // Deliver any queued samples.
  1068. while (!m_sampleQueue.IsEmpty()) {
  1069. hr = m_sampleQueue.Dequeue(&pSample);
  1070. if (FAILED(hr)) {
  1071. break;
  1072. }
  1073. hr = DeliverSample(pSample);
  1074. if (FAILED(hr)) {
  1075. break;
  1076. }
  1077. SafeRelease(&pSample);
  1078. }
  1079. }
  1080. LeaveCriticalSection(&m_critSec);
  1081. // If we reached the end of the stream, send the end-of-presentation event from
  1082. // the media source.
  1083. if (SUCCEEDED(hr)) {
  1084. if (m_EOS) {
  1085. hr = m_pSource->QueueEvent(MEEndOfPresentation, GUID_NULL, S_OK, NULL);
  1086. }
  1087. }
  1088. SafeRelease(&pSample);
  1089. return hr;
  1090. }
  1091. //-------------------------------------------------------------------
  1092. // Name: Flush
  1093. // Description: Flushes the sample queue.
  1094. //-------------------------------------------------------------------
  1095. HRESULT CMFStreamSource::Flush()
  1096. {
  1097. EnterCriticalSection(&m_critSec);
  1098. m_sampleQueue.Clear();
  1099. LeaveCriticalSection(&m_critSec);
  1100. return S_OK;
  1101. }
  1102. //-------------------------------------------------------------------
  1103. // Name: Shutdown
  1104. // Description: Notifies the stream that the source was shut down.
  1105. //-------------------------------------------------------------------
  1106. HRESULT CMFStreamSource::Shutdown()
  1107. {
  1108. EnterCriticalSection(&m_critSec);
  1109. // Flush queued samples.
  1110. Flush();
  1111. // Shut down the event queue.
  1112. if (m_pEventQueue) {
  1113. m_pEventQueue->Shutdown();
  1114. }
  1115. SafeRelease(&m_pEventQueue);
  1116. SafeRelease(&m_pSource);
  1117. SafeRelease(&m_pStreamDescriptor);
  1118. m_IsShutdown = TRUE;
  1119. LeaveCriticalSection(&m_critSec);
  1120. return S_OK;
  1121. }
  1122. //-------------------------------------------------------------------
  1123. // Name: SetPosition
  1124. // Description: Updates the new stream position.
  1125. //-------------------------------------------------------------------
  1126. HRESULT CMFStreamSource::SetPosition(LONGLONG rtNewPosition)
  1127. {
  1128. EnterCriticalSection(&m_critSec);
  1129. HRESULT hr = S_OK;
  1130. /*
  1131. // Check if the requested position is beyond the end of the stream.
  1132. LONGLONG duration = AudioDurationFromBufferSize(m_pRiff->Format(), m_pRiff->Chunk().DataSize());
  1133. if (rtNewPosition > duration)
  1134. {
  1135. LeaveCriticalSection(&m_critSec);
  1136. return MF_E_INVALIDREQUEST; // Start position is past the end of the presentation.
  1137. }
  1138. if (m_rtCurrentPosition != rtNewPosition)
  1139. {
  1140. LONGLONG offset = BufferSizeFromAudioDuration(m_pRiff->Format(), rtNewPosition);
  1141. // The chunk size is a DWORD. So if our calculations are correct, there is no
  1142. // way that the maximum valid seek position can be larger than a DWORD.
  1143. assert(offset <= MAXDWORD);
  1144. hr = m_pRiff->MoveToChunkOffset((DWORD)offset);
  1145. if (SUCCEEDED(hr))
  1146. {
  1147. m_rtCurrentPosition = rtNewPosition;
  1148. m_discontinuity = TRUE;
  1149. m_EOS = FALSE;
  1150. }
  1151. }
  1152. */
  1153. LeaveCriticalSection(&m_critSec);
  1154. return hr;
  1155. }
  1156. HRESULT CMFStreamSource::CheckEndOfStream()
  1157. {
  1158. HRESULT hr = S_OK;
  1159. /*
  1160. if (m_pRiff->BytesRemainingInChunk() < m_pRiff->Format()->nBlockAlign)
  1161. {
  1162. // The remaining data is smaller than the audio block size. (In theory there shouldn't be
  1163. // partial bits of data at the end, so we should reach an even zero bytes, but the file
  1164. // might not be authored correctly.)
  1165. m_EOS = TRUE;
  1166. // Send the end-of-stream event,
  1167. hr = QueueEvent(MEEndOfStream, GUID_NULL, S_OK, NULL);
  1168. }
  1169. */
  1170. return hr;
  1171. }
  1172. //-------------------------------------------------------------------
  1173. // Name: QueueEventWithIUnknown
  1174. // Description: Helper function to queue an event with an IUnknown
  1175. // pointer value.
  1176. //
  1177. // pMEG: Media event generator that will queue the event.
  1178. // meType: Media event type.
  1179. // hrStatus: Status code for the event.
  1180. // pUnk: IUnknown pointer value.
  1181. //
  1182. //-------------------------------------------------------------------
  1183. HRESULT QueueEventWithIUnknown(
  1184. IMFMediaEventGenerator *pMEG,
  1185. MediaEventType meType,
  1186. HRESULT hrStatus,
  1187. IUnknown *pUnk)
  1188. {
  1189. // Create the PROPVARIANT to hold the IUnknown value.
  1190. PROPVARIANT var;
  1191. var.vt = VT_UNKNOWN;
  1192. var.punkVal = pUnk;
  1193. pUnk->AddRef();
  1194. // Queue the event.
  1195. HRESULT hr = pMEG->QueueEvent(meType, GUID_NULL, hrStatus, &var);
  1196. // Clear the PROPVARIANT.
  1197. PropVariantClear(&var);
  1198. return hr;
  1199. }
  1200. LONGLONG AudioDurationFromBufferSize(const WAVEFORMATEX *pWav, DWORD cbAudioDataSize)
  1201. {
  1202. assert(pWav != NULL);
  1203. if (pWav->nAvgBytesPerSec == 0) {
  1204. return 0;
  1205. }
  1206. return (LONGLONG)cbAudioDataSize * 10000000 / pWav->nAvgBytesPerSec;
  1207. }
  1208. LONGLONG BufferSizeFromAudioDuration(const WAVEFORMATEX *pWav, LONGLONG duration)
  1209. {
  1210. LONGLONG cbSize = duration * pWav->nAvgBytesPerSec / 10000000;
  1211. ULONG ulRemainder = (ULONG)(cbSize % pWav->nBlockAlign);
  1212. // Round up to the next block.
  1213. if(ulRemainder) {
  1214. cbSize += pWav->nBlockAlign - ulRemainder;
  1215. }
  1216. return cbSize;
  1217. }