Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1161 lines
30 KiB

  1. /*
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. */
  4. #ifndef __MEDIA_TERMINAL_FILTER__
  5. #define __MEDIA_TERMINAL_FILTER__
  6. // include header files for the amovie types
  7. #include "Stream.h"
  8. #include "Sample.h"
  9. // number of internal buffers allocated by default
  10. // (for write terminal)
  11. const DWORD DEFAULT_AM_MST_NUM_BUFFERS = 5;
  12. // while this is a LONG, it should actually be a positive value that'll
  13. // fit in a LONG (the buffer size and data size variables of the sample)
  14. // are LONG, so this is long as well
  15. const LONG DEFAULT_AM_MST_SAMPLE_SIZE = 640;
  16. // alignment of buffers allocated
  17. const LONG DEFAULT_AM_MST_BUFFER_ALIGNMENT = 1;
  18. // number of prefix bytes in buffers allocated
  19. const LONG DEFAULT_AM_MST_BUFFER_PREFIX = 0;
  20. ///////////////////////////////////////////////////////////////////////////////
  21. ///////////////////////////////////////////////////////////////////////////////
  22. //
  23. // CNBQueue
  24. //
  25. // Non blocking version of active movie queue class. Very basic Q built
  26. // entirely on Win32.
  27. //
  28. ///////////////////////////////////////////////////////////////////////////////
  29. ///////////////////////////////////////////////////////////////////////////////
  30. template <class T> class CNBQueue {
  31. private:
  32. HANDLE hSemPut; // Semaphore controlling queue "putting"
  33. HANDLE hSemGet; // Semaphore controlling queue "getting"
  34. CRITICAL_SECTION CritSect; // Thread seriallization
  35. int nMax; // Max objects allowed in queue
  36. int iNextPut; // Array index of next "PutMsg"
  37. int iNextGet; // Array index of next "GetMsg"
  38. T **QueueObjects; // Array of objects (ptr's to void)
  39. public:
  40. BOOL InitializeQ(int n)
  41. {
  42. LOG((MSP_TRACE, "CNBQueue::InitializeQ[%p] - enter", this));
  43. //
  44. // the argument had better be valid
  45. //
  46. if (0 > n)
  47. {
  48. TM_ASSERT(FALSE);
  49. return FALSE;
  50. }
  51. if (QueueObjects != NULL)
  52. {
  53. //
  54. // already initialized. this is a bug.
  55. //
  56. TM_ASSERT(FALSE);
  57. return FALSE;
  58. }
  59. iNextPut = 0;
  60. iNextGet = 0;
  61. //
  62. // attempt to create critical section
  63. //
  64. try
  65. {
  66. InitializeCriticalSection(&CritSect);
  67. }
  68. catch(...)
  69. {
  70. //
  71. // failed to create critical section
  72. //
  73. LOG((MSP_ERROR, "CNBQueue::InitializeQ - failed to initialize critical section"));
  74. return FALSE;
  75. }
  76. //
  77. // attempt to create a semaphore
  78. //
  79. TCHAR *ptczSemaphoreName = NULL;
  80. #if DBG
  81. //
  82. // in debug build, use named semaphores.
  83. //
  84. TCHAR tszPutSemaphoreName[MAX_PATH];
  85. _stprintf(tszPutSemaphoreName,
  86. _T("CNBQueuePutSemaphore_pid[0x%lx]_CNBQueue[%p]_"),
  87. GetCurrentProcessId(), this);
  88. LOG((MSP_TRACE, "CNBQueue::InitializeQ - creating put semaphore [%S]",
  89. tszPutSemaphoreName));
  90. ptczSemaphoreName = &tszPutSemaphoreName[0];
  91. #endif
  92. hSemPut = CreateSemaphore(NULL, n, n, ptczSemaphoreName);
  93. if (NULL == hSemPut)
  94. {
  95. //
  96. // cleanup and exit
  97. //
  98. DeleteCriticalSection(&CritSect);
  99. LOG((MSP_ERROR, "CNBQueue::InitializeQ - failed to create put semaphore"));
  100. return FALSE;
  101. }
  102. #if DBG
  103. //
  104. // in debug build, use named semaphores.
  105. //
  106. TCHAR tszGetSemaphoreName[MAX_PATH];
  107. _stprintf(tszGetSemaphoreName,
  108. _T("CNBQueueGetSemaphore_pid[0x%lx]_CNBQueue[%p]_"),
  109. GetCurrentProcessId(), this);
  110. LOG((MSP_TRACE, "CNBQueue::InitializeQ - creating get semaphore [%S]",
  111. tszGetSemaphoreName));
  112. ptczSemaphoreName = &tszGetSemaphoreName[0];
  113. #endif
  114. hSemGet = CreateSemaphore(NULL, 0, n, ptczSemaphoreName);
  115. if (NULL == hSemGet)
  116. {
  117. //
  118. // cleanup and exit
  119. //
  120. CloseHandle(hSemPut);
  121. hSemPut = NULL;
  122. DeleteCriticalSection(&CritSect);
  123. LOG((MSP_ERROR, "CNBQueue::InitializeQ - failed to create get semaphore"));
  124. return FALSE;
  125. }
  126. //
  127. // attempt to allocate queue
  128. //
  129. QueueObjects = new T*[n];
  130. if (NULL == QueueObjects)
  131. {
  132. //
  133. // cleanup and exit
  134. //
  135. CloseHandle(hSemPut);
  136. hSemPut = NULL;
  137. CloseHandle(hSemGet);
  138. hSemGet = NULL;
  139. DeleteCriticalSection(&CritSect);
  140. LOG((MSP_ERROR, "CNBQueue::InitializeQ - failed to allocate queue objects"));
  141. return FALSE;
  142. }
  143. nMax = n;
  144. LOG((MSP_TRACE, "CNBQueue::InitializeQ - exit"));
  145. return TRUE;
  146. }
  147. void ShutdownQ()
  148. {
  149. //
  150. // QueueObjects also doubles as "Object Initialized" flag
  151. //
  152. // if object is initialized, _all_ its resource data members must
  153. // be released
  154. //
  155. if (NULL != QueueObjects)
  156. {
  157. delete [] QueueObjects;
  158. QueueObjects = NULL;
  159. DeleteCriticalSection(&CritSect);
  160. CloseHandle(hSemPut);
  161. hSemPut = NULL;
  162. CloseHandle(hSemGet);
  163. hSemGet = NULL;
  164. }
  165. }
  166. public:
  167. CNBQueue()
  168. : QueueObjects(NULL),
  169. hSemPut(NULL),
  170. hSemGet(NULL),
  171. iNextPut(0),
  172. iNextGet(0),
  173. nMax(0)
  174. {}
  175. ~CNBQueue()
  176. {
  177. //
  178. // deallocate resources if needed
  179. //
  180. ShutdownQ();
  181. }
  182. T *DeQueue(BOOL fBlock = TRUE)
  183. {
  184. if (NULL == QueueObjects)
  185. {
  186. //
  187. // the queue is not initialized
  188. //
  189. return NULL;
  190. }
  191. //
  192. // block as needed
  193. //
  194. if (fBlock)
  195. {
  196. DWORD dwr = WaitForSingleObject(hSemGet, INFINITE);
  197. if ( WAIT_OBJECT_0 != dwr)
  198. {
  199. //
  200. // something's wrong
  201. //
  202. return NULL;
  203. }
  204. }
  205. else
  206. {
  207. //
  208. // Check for something on the queue but don't wait. If there
  209. // is nothing in the queue then we'll let the caller deal with
  210. // it.
  211. //
  212. DWORD dwr = WaitForSingleObject(hSemGet, 0);
  213. if (dwr == WAIT_TIMEOUT)
  214. {
  215. return NULL;
  216. }
  217. }
  218. //
  219. // get an object from the queue
  220. //
  221. EnterCriticalSection(&CritSect);
  222. int iSlot = iNextGet++ % nMax;
  223. T *pObject = QueueObjects[iSlot];
  224. LeaveCriticalSection(&CritSect);
  225. // Release anyone waiting to put an object onto our queue as there
  226. // is now space available in the queue.
  227. //
  228. ReleaseSemaphore(hSemPut, 1L, NULL);
  229. return pObject;
  230. }
  231. BOOL EnQueue(T *pObject)
  232. {
  233. if (NULL == QueueObjects)
  234. {
  235. //
  236. // the queue is not initialized
  237. //
  238. return FALSE;
  239. }
  240. // Wait for someone to get something from our queue, returns straight
  241. // away is there is already an empty slot on the queue.
  242. //
  243. DWORD dwr = WaitForSingleObject(hSemPut, INFINITE);
  244. if ( WAIT_OBJECT_0 != dwr)
  245. {
  246. //
  247. // something's wrong
  248. //
  249. return FALSE;
  250. }
  251. EnterCriticalSection(&CritSect);
  252. int iSlot = iNextPut++ % nMax;
  253. QueueObjects[iSlot] = pObject;
  254. LeaveCriticalSection(&CritSect);
  255. // Release anyone waiting to remove an object from our queue as there
  256. // is now an object available to be removed.
  257. //
  258. ReleaseSemaphore(hSemGet, 1L, NULL);
  259. return TRUE;
  260. }
  261. };
  262. ///////////////////////////////////////////////////////////////////////////////
  263. ///////////////////////////////////////////////////////////////////////////////
  264. //
  265. // define class CTMStreamSample - this is used by CMediaTerminalFilter
  266. // currently, the actual buffer used by the sample is created dynamically on
  267. // the heap and when the sample is destroyed the buffer is also destroyed
  268. // this may be changed to using a fixed size buffer pool in future
  269. //
  270. ///////////////////////////////////////////////////////////////////////////////
  271. ///////////////////////////////////////////////////////////////////////////////
  272. class CTMStreamSample : public CSample
  273. {
  274. friend class CMediaTerminalFilter;
  275. public:
  276. inline CTMStreamSample();
  277. // needs to be virtual, or the derived classes' destructor may not
  278. // be called when a CTMStreamSample * is deleted
  279. virtual ~CTMStreamSample()
  280. {}
  281. // calls CSample::InitSample(pStream, bIsInternalSample)
  282. // sets member variables
  283. HRESULT Init(
  284. CStream &Stream,
  285. bool bIsInternalSample,
  286. PBYTE pBuffer,
  287. LONG BufferSize
  288. );
  289. inline void SetBufferInfo(
  290. DWORD BufferSize,
  291. BYTE *pBuffer,
  292. DWORD DataSize
  293. );
  294. inline void GetBufferInfo(
  295. DWORD &BufferSize,
  296. BYTE *&pBuffer,
  297. DWORD &DataSize
  298. );
  299. // copy the contents of the src media sample into this instance
  300. // CSample::CopyFrom doesn't set time (start/stop) valid flags
  301. // this fixes the problem.
  302. void CopyFrom(
  303. IN IMediaSample *pSrcMediaSample
  304. );
  305. protected:
  306. PBYTE m_pBuffer;
  307. LONG m_BufferSize;
  308. LONG m_DataSize;
  309. private:
  310. // Methods forwarded from MediaSample object.
  311. HRESULT MSCallback_GetPointer(BYTE ** ppBuffer) { *ppBuffer = m_pBuffer; return NOERROR; }
  312. LONG MSCallback_GetSize(void) { return m_BufferSize; }
  313. LONG MSCallback_GetActualDataLength(void) { return m_DataSize; }
  314. HRESULT MSCallback_SetActualDataLength(LONG lActual)
  315. {
  316. if (lActual <= m_BufferSize) {
  317. m_DataSize = lActual;
  318. return NOERROR;
  319. }
  320. return E_INVALIDARG;
  321. };
  322. };
  323. inline
  324. CTMStreamSample::CTMStreamSample(
  325. )
  326. : m_pBuffer(NULL),
  327. m_BufferSize(0),
  328. m_DataSize(0)
  329. {
  330. }
  331. inline void
  332. CTMStreamSample::SetBufferInfo(
  333. DWORD BufferSize,
  334. BYTE *pBuffer,
  335. DWORD DataSize
  336. )
  337. {
  338. m_BufferSize = BufferSize;
  339. m_pBuffer = pBuffer;
  340. m_DataSize = DataSize;
  341. }
  342. inline void
  343. CTMStreamSample::GetBufferInfo(
  344. DWORD &BufferSize,
  345. BYTE *&pBuffer,
  346. DWORD &DataSize
  347. )
  348. {
  349. BufferSize = m_BufferSize;
  350. pBuffer = m_pBuffer;
  351. DataSize = m_DataSize;
  352. }
  353. class CQueueMediaSample : public CTMStreamSample
  354. {
  355. public:
  356. inline CQueueMediaSample();
  357. #if DBG
  358. virtual ~CQueueMediaSample();
  359. #endif // DBG
  360. // calls CTMStreamSample::Init, sets members
  361. HRESULT Init(
  362. IN CStream &pStream,
  363. IN CNBQueue<CQueueMediaSample> &pQueue
  364. );
  365. void HoldFragment(
  366. IN DWORD FragSize,
  367. IN BYTE *pbData,
  368. IN IMediaSample &FragMediaSample
  369. );
  370. inline DWORD GetDataSize() { return m_DataSize; }
  371. protected:
  372. // pointer to a queue that contains us!
  373. CNBQueue<CQueueMediaSample> *m_pSampleQueue;
  374. // ptr to the sample being fragmented
  375. CComPtr<IMediaSample> m_pFragMediaSample;
  376. // Overridden to provide different behavior
  377. void FinalMediaSampleRelease();
  378. };
  379. inline
  380. CQueueMediaSample::CQueueMediaSample(
  381. )
  382. : m_pSampleQueue(NULL)
  383. {
  384. }
  385. class CUserMediaSample :
  386. protected CTMStreamSample,
  387. public IMemoryData,
  388. public ITAMMediaFormat
  389. {
  390. public:
  391. BEGIN_COM_MAP(CUserMediaSample)
  392. COM_INTERFACE_ENTRY2(IUnknown, IStreamSample)
  393. COM_INTERFACE_ENTRY(IStreamSample)
  394. COM_INTERFACE_ENTRY(IMemoryData)
  395. COM_INTERFACE_ENTRY(ITAMMediaFormat)
  396. COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pFTM)
  397. END_COM_MAP()
  398. inline CUserMediaSample();
  399. virtual ~CUserMediaSample();
  400. // if asked to allocate buffers, verify allocator properties
  401. static BOOL VerifyAllocatorProperties(
  402. IN BOOL bAllocateBuffers,
  403. IN const ALLOCATOR_PROPERTIES &AllocProps
  404. );
  405. // calls CTMStreamSample::Init, sets members
  406. HRESULT Init(
  407. IN CStream &Stream,
  408. IN BOOL bAllocateBuffer,
  409. IN DWORD ReqdBufferSize,
  410. IN const ALLOCATOR_PROPERTIES &AllocProps
  411. );
  412. void BeginFragment(
  413. IN BOOL bNoteCurrentTime
  414. );
  415. // assign fragment to CQueueMediaSample
  416. void Fragment(
  417. IN BOOL bFragment,
  418. IN LONG AllocBufferSize,
  419. IN OUT CQueueMediaSample &QueueMediaSample,
  420. OUT BOOL &bDone
  421. );
  422. // copy fragment to downstream allocator's IMediaSample
  423. HRESULT CopyFragment(
  424. IN BOOL bFragment,
  425. IN LONG AllocBufferSize,
  426. IN OUT IMediaSample * pDestMediaSample,
  427. OUT BOOL & bDone
  428. );
  429. // computes the time to wait. it checks the time at which the last
  430. // fragmented byte would be due and determines the time to wait using
  431. // the time delay since the beginning of fragmentation
  432. DWORD GetTimeToWait(
  433. IN DOUBLE DelayPerByte
  434. );
  435. // when we are decommitted/aborted while being fragmented, we
  436. // need to get rid of our refcnt on internal IMediaSample and set
  437. // the error code to E_ABORT. this will be signaled to the user
  438. // only when the last refcnt on IMediaSample is released
  439. // (possibly by an outstanding queue sample)
  440. void AbortDuringFragmentation();
  441. // copy the contents of the src media sample into this instance
  442. HRESULT CopyFrom(
  443. IN IMediaSample *pSrcMediaSample
  444. );
  445. HRESULT CopyFrom(
  446. IN IMediaSample *pSrcMediaSample,
  447. IN OUT BYTE *&pBuffer,
  448. IN OUT LONG &DataLength
  449. );
  450. // over-ridden to check if the instance is committed before
  451. // adding the sample to the CStream buffer pool
  452. virtual HRESULT SetCompletionStatus(HRESULT hrCompletionStatus);
  453. // IStreamSample
  454. // this method is over-ridden from the base class so that we can
  455. // decrement the refcnt on a sample if stealing it from the CStream
  456. // free buffer pool is successful
  457. STDMETHODIMP CompletionStatus(
  458. IN DWORD dwFlags,
  459. IN /* [optional] */ DWORD dwMilliseconds
  460. );
  461. // IMemoryData
  462. STDMETHOD(SetBuffer)(
  463. IN DWORD cbSize,
  464. IN BYTE * pbData,
  465. IN DWORD dwFlags
  466. );
  467. STDMETHOD(GetInfo)(
  468. OUT DWORD *pdwLength,
  469. OUT BYTE **ppbData,
  470. OUT DWORD *pcbActualData
  471. );
  472. STDMETHOD(SetActual)(
  473. IN DWORD cbDataValid
  474. );
  475. // ITAMMediaFormat
  476. // redirect this call to ((CMediaTerminalFilter *)m_pStream)
  477. STDMETHOD(get_MediaFormat)(
  478. OUT /* [optional] */ AM_MEDIA_TYPE **ppFormat
  479. );
  480. // this is not allowed
  481. STDMETHOD(put_MediaFormat)(
  482. IN const AM_MEDIA_TYPE *pFormat
  483. );
  484. protected:
  485. // marshaller
  486. IUnknown *m_pFTM;
  487. // TRUE if we allocated the buffer (then, we need to destroy it too)
  488. BOOL m_bWeAllocatedBuffer;
  489. // time at which BeginFragment was called (value returned
  490. // by timeGetTime)
  491. DWORD m_BeginFragmentTime;
  492. // these many bytes of the buffer have already been fragmented
  493. LONG m_NumBytesFragmented;
  494. // TRUE if being fragmented
  495. BOOL m_bBeingFragmented;
  496. // size of the buffer that the application will have to provide, if app
  497. // does its own memory allocation
  498. DWORD m_dwRequiredBufferSize;
  499. // this calls the base class FinalMediaSampleRelease and
  500. // then releases reference to self obtained in BeginFragment
  501. virtual void FinalMediaSampleRelease();
  502. private:
  503. virtual HRESULT InternalUpdate(
  504. DWORD dwFlags,
  505. HANDLE hEvent,
  506. PAPCFUNC pfnAPC,
  507. DWORD_PTR dwptrAPCData
  508. );
  509. };
  510. inline
  511. CUserMediaSample::CUserMediaSample(
  512. )
  513. : m_bWeAllocatedBuffer(FALSE),
  514. m_NumBytesFragmented(0),
  515. m_bBeingFragmented(FALSE),
  516. m_BeginFragmentTime(0),
  517. m_dwRequiredBufferSize(0)
  518. {
  519. // can fail
  520. CoCreateFreeThreadedMarshaler(
  521. GetControllingUnknown(),
  522. &m_pFTM
  523. );
  524. }
  525. inline
  526. CUserMediaSample::~CUserMediaSample(
  527. )
  528. {
  529. if (m_bWeAllocatedBuffer)
  530. {
  531. if (NULL != m_pBuffer)
  532. {
  533. delete m_pBuffer;
  534. }
  535. }
  536. // if there is an outstanding APC call and the user handle
  537. // (the targe thread handle) has not been closed, close it
  538. if ((NULL != m_UserAPC) && (NULL != m_hUserHandle))
  539. {
  540. CloseHandle(m_hUserHandle);
  541. }
  542. if (NULL != m_pFTM)
  543. {
  544. m_pFTM->Release();
  545. m_pFTM = NULL;
  546. }
  547. }
  548. /* The media stream terminal filter */
  549. // uses class CMediaPumpPool
  550. class CMediaPumpPool;
  551. // friend
  552. class CMediaTerminal;
  553. class CMediaTerminalFilter :
  554. public CStream,
  555. public ITAllocatorProperties
  556. {
  557. friend CMediaTerminal;
  558. public:
  559. DECLARE_AGGREGATABLE(CMediaTerminalFilter)
  560. DECLARE_GET_CONTROLLING_UNKNOWN()
  561. BEGIN_COM_MAP(CMediaTerminalFilter)
  562. COM_INTERFACE_ENTRY(ITAllocatorProperties)
  563. COM_INTERFACE_ENTRY_CHAIN(CStream)
  564. END_COM_MAP()
  565. // set the member variables
  566. inline CMediaTerminalFilter();
  567. virtual ~CMediaTerminalFilter();
  568. // calls the IAMMediaStream::Initialize(NULL, 0, PurposeId, StreamType),
  569. // sets certain member variables
  570. // ex. m_pAmovieMajorType
  571. virtual HRESULT Init(
  572. IN REFMSPID PurposeId,
  573. IN const STREAM_TYPE StreamType,
  574. IN const GUID &AmovieMajorType
  575. );
  576. // the thread pump calls the filter back during the registration
  577. // to tell it that registration succeeded and that the pump will be
  578. // waiting on the m_hWaitFreeSem handle
  579. HRESULT SignalRegisteredAtPump();
  580. // this method only makes sense for a write terminal and is used by CMediaPump
  581. // to obtain a filled buffer for passing downstream
  582. virtual HRESULT GetFilledBuffer(
  583. OUT IMediaSample *&pMediaSample,
  584. OUT DWORD &WaitTime
  585. );
  586. // the caller is supposed to call DeleteMediaType(*ppmt) (on success)
  587. HRESULT GetFormat(
  588. OUT AM_MEDIA_TYPE **ppmt
  589. );
  590. // This method can only be called after initialization when the stream
  591. // is not connected. It can only be called if the stream is writeable.
  592. // it is used in writeable filters to set the media format to negotiate
  593. // when connected to the filter graph.
  594. HRESULT SetFormat(
  595. IN AM_MEDIA_TYPE *pmt
  596. );
  597. // checks if the filter is committed before adding the sample
  598. // to the CStream buffer pool
  599. HRESULT AddToPoolIfCommitted(
  600. IN CSample *pSample
  601. );
  602. // first check if this sample is the one being fragmented currently,
  603. // then check the free pool
  604. BOOL StealSample(
  605. IN CSample *pSample
  606. );
  607. // ITAllocatorProperties -
  608. // exposes the allocator properties of the Media Streaming Terminal
  609. // (MST) to a user. A user only needs to use this interface when he
  610. // needs to use his own buffers or needs to operate with a fixed set
  611. // of samples
  612. // this method may only be called before connection and will
  613. // force the MST to use these values during filter negotiation
  614. // if the connecting filter doesn't accept these, the connection
  615. // shall not be established
  616. STDMETHOD(SetAllocatorProperties)(
  617. IN ALLOCATOR_PROPERTIES *pAllocProperties
  618. );
  619. // gets current values for the allocator properties
  620. // after connection, this provides the negotiated values
  621. // it is invalid before connection. The MST will accept
  622. // any values suggested by the filters it connects to
  623. STDMETHOD(GetAllocatorProperties)(
  624. OUT ALLOCATOR_PROPERTIES *pAllocProperties
  625. );
  626. // TRUE by default. when set to FALSE, the sample allocated
  627. // by the MST don't have any buffers and they must be supplied
  628. // before Update is called on the samples
  629. STDMETHOD(SetAllocateBuffers)(
  630. IN BOOL bAllocBuffers
  631. );
  632. // returns the current value of this boolean configuration parameter
  633. STDMETHOD(GetAllocateBuffers)(
  634. OUT BOOL *pbAllocBuffers
  635. );
  636. // this size is used for allocating buffers when AllocateSample is
  637. // called. this is only valid when we have been told to allocate buffers
  638. STDMETHOD(SetBufferSize)(
  639. IN DWORD BufferSize
  640. );
  641. // returns the value used to allocate buffers when AllocateSample is
  642. // called. this is only valid when we have been told to allocate buffers
  643. STDMETHOD(GetBufferSize)(
  644. OUT DWORD *pBufferSize
  645. );
  646. // over-ridden base class methods
  647. // CStream
  648. // IAMMediaStream
  649. // over-ride this to return failure. we don't allow it to join a multi-media
  650. // stream because the multi-media stream thinks it owns the stream
  651. STDMETHOD(JoinAMMultiMediaStream)(
  652. IN IAMMultiMediaStream *pAMMultiMediaStream
  653. );
  654. // over-ride this to return failure if the filter is anything other than the internally
  655. // created filter. The internally created media stream filter has only one IAMMediaStream
  656. // (this one) in it
  657. STDMETHOD(JoinFilter)(
  658. IN IMediaStreamFilter *pMediaStreamFilter
  659. );
  660. STDMETHOD(AllocateSample)(
  661. IN DWORD dwFlags,
  662. OUT IStreamSample **ppSample
  663. );
  664. STDMETHOD(CreateSharedSample)(
  665. IN IStreamSample *pExistingSample,
  666. IN DWORD dwFlags,
  667. OUT IStreamSample **ppNewSample
  668. );
  669. STDMETHOD(SetSameFormat)(
  670. IN IMediaStream *pStream,
  671. IN DWORD dwFlags
  672. );
  673. // CStream over-ride - this method had to be replaced because
  674. // of references to CPump which itself is being replaced by CMediaPump
  675. STDMETHODIMP SetState(
  676. IN FILTER_STATE State
  677. );
  678. // CStream - end
  679. // IMemInputPin
  680. STDMETHOD(GetAllocatorRequirements)(
  681. IN ALLOCATOR_PROPERTIES*pProps
  682. );
  683. STDMETHOD(Receive)(
  684. IN IMediaSample *pSample
  685. );
  686. // supports IAMBufferNegotiation interface on TERMINAL
  687. // this is necessary because ITAllocatorProperties also
  688. // has an identical GetAllocatorProperties method!
  689. STDMETHOD(SuggestAllocatorProperties)(
  690. IN const ALLOCATOR_PROPERTIES *pProperties
  691. );
  692. // IMemAllocator
  693. STDMETHOD(GetBuffer)(IMediaSample **ppBuffer, REFERENCE_TIME * pStartTime,
  694. REFERENCE_TIME * pEndTime, DWORD dwFlags);
  695. // ** figure out what needs to be done for this allocator interface
  696. // since the number of buffers that can be created is unbounded
  697. STDMETHOD(SetProperties)(ALLOCATOR_PROPERTIES* pRequest, ALLOCATOR_PROPERTIES* pActual);
  698. STDMETHOD(GetProperties)(ALLOCATOR_PROPERTIES* pProps);
  699. STDMETHOD(Commit)();
  700. STDMETHOD(Decommit)();
  701. // IPin
  702. STDMETHOD(Connect)(IPin * pReceivePin, const AM_MEDIA_TYPE *pmt);
  703. STDMETHOD(ReceiveConnection)(IPin * pConnector, const AM_MEDIA_TYPE *pmt);
  704. // the base class implementation doesn't validate the parameter
  705. STDMETHOD(ConnectionMediaType)(AM_MEDIA_TYPE *pmt);
  706. // should accept all media types which match the major type corresponding to the purpose id
  707. STDMETHOD(QueryAccept)(const AM_MEDIA_TYPE *pmt);
  708. // over-ridden from CStream to set the end of stream flag to false
  709. // this is done instead of setting it in Connect and ReceiveConnection
  710. STDMETHODIMP Disconnect();
  711. //
  712. // this is called by media pump when it has a sample for us to process
  713. //
  714. STDMETHODIMP ProcessSample(IMediaSample *pSample);
  715. protected:
  716. // last sample ended at this (calculated) time
  717. REFERENCE_TIME m_rtLastSampleEndedAt;
  718. //
  719. // calculated duration of the sample that was last submitted
  720. //
  721. REFERENCE_TIME m_rtLastSampleDuration;
  722. //
  723. // real (measured) time of submission of the last sample
  724. //
  725. REFERENCE_TIME m_rtRealTimeOfLastSample;
  726. // flag to check if this is an audio filter, the CStream member
  727. // m_PurposeId is a guiid and this just provides a less expensive
  728. // way of checking the same thing
  729. BOOL m_bIsAudio;
  730. // contains the samples that will be passed to downstream filters.
  731. CNBQueue<CQueueMediaSample> m_SampleQueue;
  732. // These datamembers provide some fragmentation support
  733. // for buffers going downstream
  734. CUserMediaSample *m_pSampleBeingFragmented;
  735. // flag for allocating buffers for samples when AllocateSample is
  736. // called. Its TRUE by default, but the user can set it before
  737. // connection
  738. BOOL m_bAllocateBuffers;
  739. // size of buffers to allocate in AllocateSample if m_bAllocateBuffers
  740. // is TRUE. if this isn't set (i.e. set to 0), the negotiated
  741. // allocator properties buffer size is used in its place
  742. DWORD m_AllocateSampleBufferSize;
  743. // FALSE by default. This is set to TRUE if the user specifies
  744. // allocator properties for them to see.
  745. // (we used to insist on our own allocator properties when this
  746. // was TRUE, but now this just means that we need to translate
  747. // between disjoint buffer sizes if needed)
  748. BOOL m_bUserAllocProps;
  749. ALLOCATOR_PROPERTIES m_UserAllocProps;
  750. // allocator properties negotiated -- if none suggested (by msp) and
  751. // none requested by user, we use whatever the other filter has
  752. BOOL m_bSuggestedAllocProps;
  753. ALLOCATOR_PROPERTIES m_AllocProps;
  754. // per byte delay for audio samples - only valid for write filter
  755. DOUBLE m_AudioDelayPerByte;
  756. // per frame delay for video samples - only valid for write filter
  757. DWORD m_VideoDelayPerFrame;
  758. // the filter restricts the acceptable media types to those that match the major type
  759. // this corresponds to the purpose id of the IAMMediaStream (set in Init)
  760. const GUID *m_pAmovieMajorType;
  761. // this is the media type suggested by a user of the terminal
  762. // it is only valid for writeable streams if put_MediaType was called
  763. // (i.e. not valid for readable streams)
  764. // this needs to be freed in the destructor
  765. // cstream - cbaseterm gets\sets it through methods
  766. AM_MEDIA_TYPE *m_pSuggestedMediaType;
  767. // this pump replaces the CStream related implementation of CPump
  768. // CPump uses a separate thread for each write terminal,
  769. // it uses IMemAllocator::GetBuffer to get a user written media
  770. // sample (for passing on downstream). This method should only be
  771. // used to get the next free buffer to write into.
  772. // CStream methods
  773. // this is only used during Connect and ReceiveConnect to supply the optional media type
  774. // since we over-ride Connect and ReceiveConnection methods, this should never get called
  775. virtual HRESULT GetMediaType(ULONG Index, AM_MEDIA_TYPE **ppMediaType);
  776. // others
  777. // sets the time to delay - per byte for audio, per frame for video
  778. void GetTimingInfo(
  779. IN const AM_MEDIA_TYPE &MediaType
  780. );
  781. // timestamps the sample
  782. HRESULT SetTime(
  783. IN IMediaSample *pMediaSample
  784. );
  785. // set discontinuity flag on the sample it the sample came too late -- we
  786. // assume that if the application stopped feeding mst with data, this is
  787. // because there was a gap in the actual data flow
  788. HRESULT SetDiscontinuityIfNeeded(
  789. IN IMediaSample *pMediaSample
  790. );
  791. // set the default allocator properties
  792. void SetDefaultAllocatorProperties();
  793. //
  794. // Helper methods for GetFilledBuffer.
  795. //
  796. virtual HRESULT FillDownstreamAllocatorBuffer(
  797. OUT IMediaSample *& pMediaSample,
  798. OUT DWORD & WaitTime,
  799. OUT BOOL * pfDone
  800. );
  801. virtual HRESULT FillMyBuffer(
  802. OUT IMediaSample *& pMediaSample,
  803. OUT DWORD & WaitTime,
  804. OUT BOOL * pfDone
  805. );
  806. private :
  807. // this is a weak reference and should not be a CComPtr
  808. // this tells us that we should only accept this media stream filter
  809. // when a non-null value is proposed in JoinFilter
  810. IMediaStreamFilter *m_pMediaStreamFilterToAccept;
  811. // sets the media stream filter that may be acceptable
  812. inline void SetMediaStreamFilter(
  813. IN IMediaStreamFilter *pMediaStreamFilter
  814. )
  815. {
  816. m_pMediaStreamFilterToAccept = pMediaStreamFilter;
  817. }
  818. public:
  819. // implements single thread pump for all write terminal filters
  820. // it uses GetFilledBuffer to obtain filled samples to write downstream
  821. // and to detect when to remove this filter from its list of filters to
  822. // service
  823. // ZoltanS: must be public so we can access it in DllMain
  824. // ZoltanS: no longer single thread pump; it is a wrapper which delegated
  825. // to one or more single thread pumps
  826. static CMediaPumpPool ms_MediaPumpPool;
  827. };
  828. // set the member variables
  829. inline
  830. CMediaTerminalFilter::CMediaTerminalFilter(
  831. )
  832. : m_bIsAudio(TRUE),
  833. m_bAllocateBuffers(TRUE),
  834. m_AllocateSampleBufferSize(0),
  835. m_bUserAllocProps(FALSE),
  836. m_bSuggestedAllocProps(FALSE),
  837. m_AudioDelayPerByte(0),
  838. m_VideoDelayPerFrame(0),
  839. m_pAmovieMajorType(NULL),
  840. m_pSuggestedMediaType(NULL),
  841. m_pSampleBeingFragmented(NULL),
  842. m_pMediaStreamFilterToAccept(NULL),
  843. m_rtLastSampleEndedAt(0),
  844. m_rtLastSampleDuration(0),
  845. m_rtRealTimeOfLastSample(0)
  846. {
  847. }
  848. #endif // __MEDIA_TERMINAL_FILTER__