//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // The use and distribution terms for this software are covered by the // Microsoft Limited Public License (Ms-LPL) // which can be found in the file MS-LPL.txt at the root of this distribution. // By using this software in any fashion, you are agreeing to be bound by // the terms of this license. // // The software is licensed “as-is.” // // You must not remove this notice, or any other, from this software. // // // // Demux code for Windows CE // //------------------------------------------------------------------------- //====================================================================== // Demux code for Windows CE //====================================================================== /*++ Module Name: bufsrc.h Abstract: This module contains the declarations for buffer sources. These objects are used by parsers to get, recycle, and complete buffers. Revision History: 19-Jul-1999 created 07-Jan-2000 AddRef & Release made virtual 19-Jul-2000 added media sample wrapper class & pool 05-Jun-2001 changed the copy buffer semantics so parsers must call ReleaseCopyBuffer when done with it; old semantics had an implicit release in the CompleteCopyBuffer call Notes: --*/ #ifndef __mp2demux_bufsrc_h #define __mp2demux_bufsrc_h class CBufferSource /*++ This class is the source of destination buffers for parsers. Parsers can either obtain a copy buffer or wrap (and complete) media samples. --*/ { LONG m_lRefCount ; BOOL m_fCopyBufferSource ; protected : CMpeg2Stats * m_pStats ; BOOL m_fReportStats ; // this property is provided because // we really only want to provide stats // on traffic associated with an output // pin; no stats for internals (PSI, etc...) // should be reported public : CBufferSource ( IN BOOL fCopyBufferSource, IN CMpeg2Stats * pStats, IN BOOL fReportStats ) : m_lRefCount (1), m_pStats (pStats), m_fReportStats (fReportStats), m_fCopyBufferSource (fCopyBufferSource) { TRACE_CONSTRUCTOR (TEXT ("CBufferSource")) ; ASSERT (m_pStats) ; m_pStats -> AddRef () ; } virtual ~CBufferSource ( ) { TRACE_DESTRUCTOR (TEXT ("CBufferSource")) ; ASSERT (m_pStats) ; m_pStats -> Release () ; } virtual ULONG AddRef ( ) { return InterlockedIncrement (& m_lRefCount) ; } virtual ULONG Release ( ) { if (InterlockedDecrement (& m_lRefCount) == 0) { delete this ; return 0 ; } ASSERT (m_lRefCount > 0) ; return m_lRefCount ; } BOOL ReportStats ( ) { return m_fReportStats ; } BOOL IsCopyBufferSource () { return m_fCopyBufferSource ; } // gets a new buffer virtual HRESULT GetCopyBuffer ( OUT DWORD_PTR * pdwContext, OUT BYTE ** ppbBuffer, IN OUT int * piBufferLength ) { return E_NOTIMPL ; } // processes a completed buffer; does not release the ref on it; must // call ReleaseCopyBuffer to release the ref virtual HRESULT CompleteCopyBuffer ( IN DWORD_PTR dwContext, IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN CTStickyVal * pReset ) { return E_NOTIMPL ; } // we don't provide the last 2 parameters with default values // in the prototype above because default values don't carry // through to child classes. We do provide a default implementation // so child classes don't have to implement this method; // Child classes that do want to implement this will be media // sample related; they will also have to implement a stub version // of the above, with call into this method. virtual HRESULT CompleteCopyBuffer ( IN DWORD_PTR dwContext, IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN REFERENCE_TIME * pStartTime, // media sample start IN REFERENCE_TIME * pStopTime, // media sample stop IN CTStickyVal * pReset ) { // default implementation ignores last 3 parameters return CompleteCopyBuffer ( dwContext, pbBuffer, iBufferLength, fDiscontinuity, pReset ) ; } // releases the caller's context on the buffer; it's legal to call with // dwContext == 0; if this happens, the call has no effect virtual HRESULT ReleaseCopyBuffer ( IN DWORD_PTR dwContext, IN BYTE * pbBuffer, IN int iBufferLength ) { return E_NOTIMPL ; } virtual HRESULT WrapAndComplete ( IN IMediaSample * pIMediaSample, // wrap this IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN REFERENCE_TIME * pStartTime, // media sample start IN REFERENCE_TIME * pStopTime, // media sample stop IN CTStickyVal * pReset ) { return E_NOTIMPL ; } virtual HRESULT WrapAndComplete ( IN IMediaSample * pIMediaSample, // wrap this IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN CTStickyVal * pReset ) { return E_NOTIMPL ; } } ; /*++ The purpose of this class is to interface to a pin to/from a parser. The buffers it manipulates are media samples associated with the output pin it is given when it is instantiated. --*/ class CMediaSampleCopyBuffer : public CBufferSource { enum { INVALID_PID_TAG_VALUE = -1 } ; CMPEG2DemuxOutputPin * m_pOutputPin ; BOOL m_fReportDiscontinuities ; BOOL m_fSetSyncPoints ; CRefCountedCritSec * m_pMapperLock ; // we have a way of setting a PID on this media // sample buffer source; if it is not INVALID_PID_VALUE // all media samples sent downstream will have the // AM_SAMPLE_PROPERTIES2's dwTypeSpecificFlags field // set to the PID DWORD m_dwPIDTag ; BOOL m_fTagPID ; // TRUE/FALSE if we tag with the PID public : CMediaSampleCopyBuffer ( IN CMPEG2DemuxOutputPin * pPin, IN BOOL fReportDiscontinuities, IN BOOL fSetSyncPoints, IN CRefCountedCritSec * pMapperLock, IN HKEY hkeyRoot, // don't use after constructor ! IN DWORD dwPIDTag, IN CMpeg2Stats * pStats ) ; virtual ~CMediaSampleCopyBuffer ( ) ; virtual HRESULT GetCopyBuffer ( OUT DWORD_PTR * pdwContext, OUT BYTE ** ppbBuffer, IN OUT int * piBufferLength ) ; virtual HRESULT CompleteCopyBuffer ( IN DWORD_PTR dwContext, IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN CTStickyVal * pReset ) { return CompleteCopyBuffer ( dwContext, pbBuffer, iBufferLength, fDiscontinuity, NULL, NULL, pReset ) ; } virtual HRESULT CompleteCopyBuffer ( IN DWORD_PTR dwContext, IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN REFERENCE_TIME * pStartTime, // media sample start IN REFERENCE_TIME * pStopTime, // media sample stop IN CTStickyVal * pReset ) ; virtual HRESULT ReleaseCopyBuffer ( IN DWORD_PTR dwContext, IN BYTE * pbBuffer, IN int iBufferLength ) ; } ; class CScratchMediaSample : public IMediaSample2 { LONG m_lRef ; BYTE * m_pbCopiedBuffer ; int m_iCopiedBufferLength ; public : CScratchMediaSample ( ) : m_pbCopiedBuffer (NULL), m_iCopiedBufferLength (0), m_lRef (1) {} ~CScratchMediaSample ( ) { CoTaskMemFree (m_pbCopiedBuffer) ; } HRESULT Copy ( IN BYTE * pbBuffer, IN int iBufferLength, OUT BYTE ** ppbCopiedBuffer ) { ASSERT (m_pbCopiedBuffer == NULL) ; m_pbCopiedBuffer = reinterpret_cast (CoTaskMemAlloc (iBufferLength * sizeof BYTE)) ; if (m_pbCopiedBuffer) { CopyMemory ( m_pbCopiedBuffer, pbBuffer, iBufferLength ) ; (* ppbCopiedBuffer) = m_pbCopiedBuffer ; m_iCopiedBufferLength = iBufferLength ; return S_OK ; } else { return E_OUTOFMEMORY ; } } // ------------------------------------------------------------------- // IUnknown methods STDMETHODIMP QueryInterface ( IN REFIID riid, OUT void ** ppv ) { if (ppv == NULL) { return E_INVALIDARG ; } if (riid == IID_IUnknown || riid == IID_IMediaSample || riid == IID_IMediaSample2) { * ppv = reinterpret_cast (this) ; } else { return E_NOINTERFACE ; } (reinterpret_cast (* ppv)) -> AddRef () ; return S_OK ; } STDMETHODIMP_(ULONG) AddRef ( ) { return InterlockedIncrement (& m_lRef) ; } STDMETHODIMP_(ULONG) Release ( ) { if (InterlockedDecrement (& m_lRef) == 0) { delete this ; return 0 ; } return m_lRef ; } // ------------------------------------------------------------------- // IMediaSample methods -- all are E_NOTIMPL since we just use it // to feed to our wrapper methods STDMETHODIMP GetPointer (OUT BYTE ** ppBuffer) { return E_NOTIMPL ; } STDMETHODIMP_(LONG) GetSize () { return 0 ; } STDMETHODIMP IsSyncPoint () { return E_NOTIMPL ; } STDMETHODIMP SetSyncPoint (IN BOOL bIsSyncPoint) { return E_NOTIMPL ; } STDMETHODIMP IsPreroll () { return S_FALSE ; } STDMETHODIMP SetPreroll (BOOL bIsPreroll) { return E_NOTIMPL ; } STDMETHODIMP_(LONG) GetActualDataLength () { return 0 ; } STDMETHODIMP SetActualDataLength (IN long) { return E_NOTIMPL ; } STDMETHODIMP GetMediaType (AM_MEDIA_TYPE ** ppMediaType) { return E_NOTIMPL ; } STDMETHODIMP SetMediaType(AM_MEDIA_TYPE * pMediaType) { return E_NOTIMPL ; } STDMETHODIMP IsDiscontinuity () { return FALSE ; } STDMETHODIMP SetDiscontinuity (BOOL bDiscontinuity) { return E_NOTIMPL ; } STDMETHODIMP GetTime ( OUT REFERENCE_TIME * pTimeStart, OUT REFERENCE_TIME * pTimeEnd ) { return E_NOTIMPL ; } STDMETHODIMP SetTime ( IN REFERENCE_TIME * pTimeStart, // put time here IN REFERENCE_TIME * pTimeEnd ) { return E_NOTIMPL ; } STDMETHODIMP GetMediaTime ( OUT LONGLONG * pTimeStart, OUT LONGLONG * pTimeEnd ) { return E_NOTIMPL ; } STDMETHODIMP SetMediaTime ( IN LONGLONG * pTimeStart, IN LONGLONG * pTimeEnd ) { return E_NOTIMPL ; } STDMETHODIMP GetProperties ( IN DWORD cbProperties, OUT BYTE * pbProperties ) { return E_NOTIMPL ; } STDMETHODIMP SetProperties ( IN DWORD cbProperties, IN const BYTE * pbProperties ) { return E_NOTIMPL ; } } ; class CMediaSampleWrapper : public IMediaSample2 { enum { SAMPLE_SYNCPOINT = 0x00000001, SAMPLE_PREROLL = 0x00000002, SAMPLE_DISCONTINUITY = 0x00000004, SAMPLE_TYPECHANGED = 0x00000008, SAMPLE_TIMEVALID = 0x00000010, SAMPLE_MEDIATIMEVALID = 0x00000020, SAMPLE_TIMEDISCONTINUITY = 0x00000040, // not really sure why this is here SAMPLE_STOPVALID = 0x00000080, SAMPLE_VALIDFLAGS = 0x000000ff } ; CMediaSampleWrapperPool * m_pMSPool ; LONG m_lRef ; DWORD m_dwFlags ; // ORed SAMPLE_* values DWORD m_dwTypeSpecificFlags ; BYTE * m_pbPayload ; LONG m_lActual ; REFERENCE_TIME m_rtStart ; REFERENCE_TIME m_rtEnd ; LONGLONG m_llMediaStart ; LONGLONG m_llMediaEnd ; AM_MEDIA_TYPE * m_pMediaType ; DWORD m_dwStreamId ; // // this media sample always wraps something // IMediaSample * m_pCoreIMediaSample ; // we're wrapping another media sample void ResetMS_ ( ) ; public : LIST_ENTRY m_ListEntry ; CMediaSampleWrapper ( IN CMediaSampleWrapperPool * ) ; ~CMediaSampleWrapper ( ) ; // get the flag mask so we can set it on the way back out static HRESULT GetMSProperties ( IN IMediaSample * pIMS, OUT LONGLONG * pllMediaStart, OUT LONGLONG * pllMediaEnd, OUT REFERENCE_TIME * prtStart, OUT REFERENCE_TIME * prtEnd, OUT DWORD * pdwFlags ) ; // ------------------------------------------------------------------- // init HRESULT Init ( IN IMediaSample * pIMS, IN BYTE * pbPayload, IN int iPayloadLength ) ; // ------------------------------------------------------------------- // IUnknown methods STDMETHODIMP QueryInterface ( IN REFIID riid, OUT void ** ppv ) ; STDMETHODIMP_(ULONG) AddRef ( ) ; STDMETHODIMP_(ULONG) Release ( ) ; // ------------------------------------------------------------------- // IMediaSample methods // get me a read/write pointer to this buffer's memory. I will actually // want to use sizeUsed bytes. STDMETHODIMP GetPointer ( OUT BYTE ** ppBuffer ) ; // return the size in bytes of the buffer data area STDMETHODIMP_(LONG) GetSize ( ) ; // get the stream time at which this sample should start and finish. STDMETHODIMP GetTime ( OUT REFERENCE_TIME * pTimeStart, // put time here OUT REFERENCE_TIME * pTimeEnd ) ; // Set the stream time at which this sample should start and finish. // pTimeStart==pTimeEnd==NULL will invalidate the time stamps in // this sample STDMETHODIMP SetTime ( IN REFERENCE_TIME * pTimeStart, // put time here IN REFERENCE_TIME * pTimeEnd ) ; // sync-point property. If true, then the beginning of this // sample is a sync-point. (note that if AM_MEDIA_TYPE.bTemporalCompression // is false then all samples are sync points). A filter can start // a stream at any sync point. S_FALSE if not sync-point, S_OK if true. STDMETHODIMP IsSyncPoint ( ) ; STDMETHODIMP SetSyncPoint ( IN BOOL bIsSyncPoint ) ; // preroll property. If true, this sample is for preroll only and // shouldn't be displayed. STDMETHODIMP IsPreroll ( ) ; STDMETHODIMP SetPreroll ( BOOL bIsPreroll ) ; STDMETHODIMP_(LONG) GetActualDataLength ( ) ; STDMETHODIMP SetActualDataLength ( IN long ) ; // these allow for limited format changes in band - if no format change // has been made when you receive a sample GetMediaType will return S_FALSE STDMETHODIMP GetMediaType ( AM_MEDIA_TYPE ** ppMediaType ) ; STDMETHODIMP SetMediaType( AM_MEDIA_TYPE * pMediaType ) ; // returns S_OK if there is a discontinuity in the data (this frame is // not a continuation of the previous stream of data // - there has been a seek or some dropped samples). STDMETHODIMP IsDiscontinuity ( ) ; // set the discontinuity property - TRUE if this sample is not a // continuation, but a new sample after a seek or a dropped sample. STDMETHODIMP SetDiscontinuity ( BOOL bDiscontinuity ) ; // get the media times for this sample STDMETHODIMP GetMediaTime ( OUT LONGLONG * pTimeStart, OUT LONGLONG * pTimeEnd ) ; // Set the media times for this sample // pTimeStart==pTimeEnd==NULL will invalidate the media time stamps in // this sample STDMETHODIMP SetMediaTime ( IN LONGLONG * pTimeStart, IN LONGLONG * pTimeEnd ) ; // ------------------------------------------------------------------- // IMediaSample methods // Set and get properties (IMediaSample2) STDMETHODIMP GetProperties ( IN DWORD cbProperties, OUT BYTE * pbProperties ) ; STDMETHODIMP SetProperties ( IN DWORD cbProperties, IN const BYTE * pbProperties ) ; } ; class CMediaSampleWrapperPool : public CBufferSource { LIST_ENTRY m_leMSPool ; DWORD m_dwActualPoolSize ; DWORD m_dwMaxPoolSize ; CRITICAL_SECTION m_crt ; HANDLE m_hWait ; // blocking event BOOL m_fCancelWait ; // TRUE/FALSE if we should not wait HRESULT m_hrRet ; // returned hr in case we cancelled wait CMPEG2DemuxOutputPin * m_pOutputPin ; BOOL m_fReportDiscontinuities ; BOOL m_fSetSyncPoints ; CRefCountedCritSec * m_pMapperLock ; void Lock_ () { EnterCriticalSection (& m_crt) ; } void Unlock_ () { LeaveCriticalSection (& m_crt) ; } HRESULT GetMediaSampleWrapper_ ( IN IMediaSample * pIMS, IN BYTE * pbPayload, IN int iPayloadLength, OUT CMediaSampleWrapper ** ppMS ) ; public : CMediaSampleWrapperPool ( IN CMPEG2DemuxOutputPin * pOutputPin, IN BOOL fReportDiscontinuities, IN BOOL fSetSyncPoints, IN CRefCountedCritSec * pMapperLock, IN DWORD dwMaxPoolSize, IN HKEY hkeyRoot, // don't use after constructor ! IN CMpeg2Stats * pStats, OUT HRESULT * phr ) ; virtual ~CMediaSampleWrapperPool ( ) ; virtual HRESULT WrapAndComplete ( IN IMediaSample * pIMediaSample, // wrap this IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN REFERENCE_TIME * pStartTime, // media sample start IN REFERENCE_TIME * pStopTime, // media sample stop IN CTStickyVal * pReset ) ; virtual HRESULT WrapAndComplete ( IN IMediaSample * pIMediaSample, // wrap this IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN CTStickyVal * pReset ) ; HRESULT FailBlockedCalls ( ) { Lock_ () ; m_fCancelWait = TRUE ; SetEvent (m_hWait) ; m_hrRet = E_FAIL ; Unlock_ () ; return S_OK ; } void RecycleMS ( IN CMediaSampleWrapper * ) ; } ; #endif // __mp2demux_bufsrc_h