//------------------------------------------------------------------------------ // // 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: tsctrlr.h Abstract: This module contains the class declarations for the controller. Revision History: 13-Jul-1999 created 07-Jan-1999 modified for PSI parsing support 26-Jun-2000 significantly revampted to accept either mpeg-2 transport or mpeg-2 program streams 14-Nov-2000 pull-mode support for program streams Notes: --*/ #ifndef __mp2demux_tsctrlr_h #define __mp2demux_tsctrlr_h // describes a controller-tracked mpeg-2 stream (transport or program) to // output pin mapping class CStreamToPinMap { CDemuxBaseParser * m_pPayloadParser ; DWORD m_dwStream ; DWORD m_MediaSampleContent ; CMPEG2DemuxOutputPin * m_pDemuxOutputPin ; BYTE * m_pParserArg ; public : // a/v list entry LIST_ENTRY m_ListEntry ; CStreamToPinMap ( IN CDemuxBaseParser * pPayloadParser, IN DWORD dwMediaSampleContent, IN DWORD dwStream, IN CMPEG2DemuxOutputPin * pDemuxOutputPin, IN LPVOID pvParserArg, OUT HRESULT * phr ) : m_pPayloadParser (pPayloadParser), m_dwStream (dwStream), m_MediaSampleContent (dwMediaSampleContent), m_pDemuxOutputPin (pDemuxOutputPin), m_pParserArg (NULL) { int iParserArgSize ; (* phr) = S_OK ; ASSERT (m_pPayloadParser) ; m_pPayloadParser -> AddRef () ; ASSERT (pDemuxOutputPin) ; pDemuxOutputPin -> AddRef () ; if (pvParserArg != NULL) { iParserArgSize = ParserArgSize (m_MediaSampleContent) ; ASSERT (iParserArgSize > 0) ; m_pParserArg = new BYTE [iParserArgSize] ; if (m_pParserArg) { CopyMemory ( m_pParserArg, pvParserArg, iParserArgSize ) ; } else { (* phr) = E_OUTOFMEMORY ; return ; } } } ~CStreamToPinMap ( ) { RELEASE_AND_CLEAR (m_pPayloadParser) ; RELEASE_AND_CLEAR (m_pDemuxOutputPin) ; delete [] m_pParserArg ; } CDemuxBaseParser * GetNonRefdParser () { return m_pPayloadParser ; } DWORD GetStream () { return m_dwStream ; } DWORD GetSampleContent () { return m_MediaSampleContent ; } CMPEG2DemuxOutputPin * GetNonRefdPin () { return m_pDemuxOutputPin ; } LPVOID GetParserArg () { return m_pParserArg ; } void Active (IN BOOL fInPullMode) { m_pPayloadParser -> Active (fInPullMode) ; } void Inactive () { m_pPayloadParser -> Inactive () ; } static int __cdecl CompareMapRecordValues ( IN const CMPEG2DemuxOutputPin * pDemuxOutputPin1, IN const CMPEG2DemuxOutputPin * pDemuxOutputPin2 ) // compare based ONLY on pins; we use this to search for all // Stream maps to a specific pin; this gets us into the ballpark { if (pDemuxOutputPin1 < pDemuxOutputPin2) return -1 ; else if (pDemuxOutputPin1 > pDemuxOutputPin2) return 1 ; // equal return 0 ; } static int __cdecl CompareMapRecordValues ( IN const CMPEG2DemuxOutputPin * pDemuxOutputPin1, IN const DWORD dwStream1, IN const CMPEG2DemuxOutputPin * pDemuxOutputPin2, IN const DWORD dwStream2 ) { ASSERT (pDemuxOutputPin1) ; ASSERT (pDemuxOutputPin2) ; if (pDemuxOutputPin1 < pDemuxOutputPin2) return -1 ; else if (pDemuxOutputPin1 > pDemuxOutputPin2) return 1 ; else if (dwStream1 < dwStream2) return -1 ; else if (dwStream1 > dwStream2) return 1 ; // equal return 0 ; } static int __cdecl Compare ( IN const void * pv1, IN const void * pv2 ) // return values // -1 pv1 < pv2 // 0 pv1 == pv2 // 1 pv2 > pv2 { ASSERT (pv1) ; ASSERT (pv2) ; return CompareMapRecordValues ( (* (CStreamToPinMap **) pv1) -> GetNonRefdPin (), (* (CStreamToPinMap **) pv1) -> GetStream (), (* (CStreamToPinMap **) pv2) -> GetNonRefdPin (), (* (CStreamToPinMap **) pv2) -> GetStream () ) ; } } ; class CMPEG2Controller { enum { MAX_WRAPPER_POOL_SIZE = 64 } ; CStreamMapper * m_pStreamMapper ; TSimpleVector m_PinStreamMaps ; // vector of Stream mappings to pins; sorted by Stream, then pin CMpeg2Stats * m_pStats ; HKEY m_hkeyRoot ; CMPEG2PushClock * m_pCMPEG2PushClock ; CMPEG2Demultiplexer * m_pCMPEG2Demultiplexer ; DWORD m_StreamType ; CMpeg2StreamContentManager * m_pMpeg2StreamContentManager ; BOOL m_fReportDiscontinuities ; BOOL m_fSetSyncPoints ; DWORD m_dwMaxWrapperPoolSize ; LIST_ENTRY m_AVStreamMapsList ; BOOL m_fInPullMode ; CRefCountedCritSec * m_pMapperLock ; LONGLONG m_llTotalFileLength ; REFERENCE_TIME m_rtTotalFileDuration ; void AvStreamPush_ ( IN CStreamToPinMap * pStreamToPinMap ) { ASSERT (pStreamToPinMap -> GetSampleContent () == MPEG2_MEDIA_ELEMENTARY_STREAM) ; InsertHeadList (& (m_AVStreamMapsList), & (pStreamToPinMap -> m_ListEntry)) ; } void AVStreamPop_ ( IN CStreamToPinMap * pStreamToPinMap ) { ASSERT (pStreamToPinMap -> GetSampleContent () == MPEG2_MEDIA_ELEMENTARY_STREAM) ; RemoveEntryList (& (pStreamToPinMap -> m_ListEntry)) ; } void AVStreamsResetAll_ ( ) ; // prevent copies CMPEG2Controller () ; HRESULT UnmapAllStreamsLocked_ ( IN CMPEG2DemuxOutputPin * pDemuxOutputPin = NULL ) ; HRESULT FindPinStreamMapRecordLocked_ ( IN CMPEG2DemuxOutputPin * pDemuxOutputPin, OUT DWORD * pcPinStreamMaps = NULL, // number of Stream maps to the specified pin OUT DWORD * pdwIndex = NULL // optional; index ) ; HRESULT FindPinStreamMapRecordLocked_ ( IN CMPEG2DemuxOutputPin * pDemuxOutputPin, IN DWORD dwStream, // Stream OUT DWORD * pdwIndex = NULL // optional; index ) ; HRESULT FindPinAndContentRecordLocked_ ( IN DWORD MediaSampleContent, IN CMPEG2DemuxOutputPin * pDemuxOutputPin, OUT CDemuxBaseParser ** ppParser ) ; void GetQPCBufferAndLocalTime_ ( IN IMediaSample *, OUT LONGLONG * pqpcBuffer, OUT LONGLONG * pqpcLocal ) ; HRESULT GetPayloadParser_ ( IN DWORD dwStreamIdentifier, IN DWORD MediaSampleContent, IN CMPEG2DemuxOutputPin * pDemuxOutputPin, IN CBufferSource * pBufferSource, IN LPVOID pvParserArg, // depends on the type of parser; can be NULL OUT CDemuxBaseParser ** ppParser ) ; protected : // don't want this to be instantiated by anyone but the children CMPEG2Controller ( IN HKEY, IN CMPEG2Demultiplexer *, IN CMpeg2Stats *, IN CMPEG2PushClock *, IN DWORD, OUT HRESULT * ) ; void SetStreamMapper_ (CStreamMapper * pStreamMapper) { m_pStreamMapper = pStreamMapper ; } CStreamMapper * GetStreamMapper_ () { return m_pStreamMapper ; } CMPEG2Demultiplexer * Mpeg2Demultiplexer_ () { return m_pCMPEG2Demultiplexer ; } CMpeg2Stats * Stats_ () { return m_pStats ; } void LockMapper_ () { m_pMapperLock -> Lock () ; } void UnlockMapper_ () { m_pMapperLock -> Unlock () ; } void LockRecv_ () ; void UnlockRecv_ () ; void SetContentManager_ (CMpeg2StreamContentManager * pMPEG2ContentManager) { m_pMpeg2StreamContentManager = pMPEG2ContentManager ; } virtual CMpeg2StreamAnalyzer * GetAnalyzer_ (IN CMPEG2Demultiplexer *, IN IAsyncReader *) { return NULL ; } virtual void RecycleAnalyzer_ (IN CMpeg2StreamAnalyzer *) {} virtual BOOL IsCopyBufferSource_ ( IN DWORD dwTypeParser, IN CMediaType * pmtPin ) = 0 ; virtual BOOL IsValidStream ( IN DWORD dwStream ) = 0 ; void SetPullModeState (IN BOOL f) { m_fInPullMode = f ; } public : virtual ~CMPEG2Controller () ; CMpeg2StreamContentManager * GetStreamContentManager () { return m_pMpeg2StreamContentManager ; } virtual HRESULT ClearConfig ( ) ; virtual HRESULT Initialize ( ) ; // clears any existing config; reinitializes HRESULT Reset ( ) { HRESULT hr ; hr = ClearConfig () ; if (SUCCEEDED (hr)) { hr = Initialize () ; } return hr ; } // transitions to active (preroll) state virtual HRESULT Active ( ) ; // transitions to inactive state virtual HRESULT Inactive ( ) ; // -------------------------------------------------------------------- virtual void SetStrideLengths ( IN int iPreStrideLength, IN int iPostStrideLength ) { return ; } // -------------------------------------------------------------------- // process buffer of packets // must hold the receiver lock HRESULT ProcessMediaSampleLocked ( IN IMediaSample * pIMediaSample ) ; // -------------------------------------------------------------------- DWORD GetStreamType ( ) { return m_StreamType ; } // -------------------------------------------------------------------- // create a stream mapping to a pin HRESULT MapStream ( IN DWORD dwStreamIdentifier, IN CMPEG2DemuxOutputPin * pDemuxOutputPin, IN DWORD MediaSampleContent, IN LPVOID pvParserArg ) ; // unmap a stream from a pin HRESULT UnmapStream ( IN DWORD dwStreamIdentifier, IN CMPEG2DemuxOutputPin * pDemuxOutputPin ) ; // internal to the demux; expects external entity to keep track of // stream map and unmap it when it is done HRESULT MapStreamInternal ( IN DWORD dwStreamIdentifier, IN CBufferSource * pBufferSource, IN DWORD dwTypeParser, // MPEG2_PSI_PAT, MPEG2_PSI_CAT, MPEG2_PSI_PMT, ..; see mp2const.h IN LPVOID pvParserArg, // depends on the type of parser; can be NULL OUT DWORD_PTR * pdwpContext ) ; // internal to the demux; unmap a stream from a pin HRESULT UnmapStreamInternal ( IN DWORD dwStream, IN DWORD_PTR pdwpContext ) ; // unmap all streams associated with the specified pin HRESULT UnmapAllStreams ( IN CMPEG2DemuxOutputPin * pDemuxOutputPin ) ; HRESULT EnumStreamMap ( IN CMPEG2DemuxOutputPin * pDemuxOutputPin, IN OUT CEnumStreamMapBase * pCEnumStreamMapBase ) ; // flushes all partially filled buffers; this is not the same as Reset HRESULT AbortBuffers ( ) ; // input stream discontinuity HRESULT OnInputStreamDiscontinuity ( ) ; // -------------------------------------------------------------------- BOOL IsInPullMode () { return m_fInPullMode ; } virtual BOOL CanOperateInPullMode () { return FALSE ; } HRESULT InitPullModeStream ( IN IAsyncReader * pIAsyncReader ) ; virtual void SetPullMode (IN BOOL f) {;} } ; class CMPEG2TransportController : public CMPEG2Controller { protected : virtual BOOL IsValidStream ( IN DWORD dwStream ) ; virtual BOOL IsCopyBufferSource_ ( IN DWORD dwTypeParser, IN CMediaType * pmtPin ) ; public : CMPEG2TransportController ( IN HKEY, IN CMPEG2Demultiplexer *, IN CMpeg2Stats *, IN CMPEG2PushClock *, OUT HRESULT * ) ; ~CMPEG2TransportController ( ) ; virtual void SetStrideLengths ( IN int iPreStrideLength, IN int iPostStrideLength ) ; } ; class CMPEG2ProgramController : public CMPEG2Controller { class CMpeg2AnalogCopyProtection : public CAnalogCopyProtection, public CBufferSource { ANALOGCOPYPROTECTION_RECORD m_ACPRecord ; public : CMpeg2AnalogCopyProtection ( IN IBaseFilter * pIBaseFilter, IN CMpeg2Stats * pStats, IN BOOL fReportStats ) ; virtual ~CMpeg2AnalogCopyProtection ( ) ; // ---------------------------------------------------------------- // CBufferSource methods // gets a new buffer virtual HRESULT GetCopyBuffer ( OUT DWORD_PTR * pdwContext, OUT BYTE ** ppbBuffer, IN OUT int * piBufferLength ) ; // processes a completed buffer; this is a handoff virtual HRESULT CompleteCopyBuffer ( IN DWORD_PTR dwContext, IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN CTStickyVal * pReset // OUT: true if the demux needs a reset ) ; // recycles the buffer; only called when something has failed // and a buffer that was obtained via GetCopyBuffer is no longer // needed virtual HRESULT ReleaseCopyBuffer ( IN DWORD_PTR dwContext, IN BYTE * pbBuffer, IN int iBufferLength ) ; } ; CMpeg2AnalogCopyProtection * m_pAnalogCopyProtection ; DWORD_PTR m_dwpACPStreamIdMap ; HRESULT CreateAnalogCopyProtectionMap_ () ; HRESULT DeleteAnalogCopyProtectionMap_ () ; protected : virtual CMpeg2StreamAnalyzer * GetAnalyzer_ (IN CMPEG2Demultiplexer *, IN IAsyncReader *) ; virtual void RecycleAnalyzer_ (IN CMpeg2StreamAnalyzer *) ; virtual BOOL IsCopyBufferSource_ ( IN DWORD dwTypeParser, IN CMediaType * pmtPin ) ; virtual BOOL IsValidStream ( IN DWORD dwStream ) ; public : CMPEG2ProgramController ( IN HKEY, IN CMPEG2Demultiplexer *, IN CMpeg2Stats *, IN CMPEG2PushClock *, OUT HRESULT * ) ; ~CMPEG2ProgramController ( ) ; // -------------------------------------------------------------------- // can operate in pull mode virtual BOOL CanOperateInPullMode () { return TRUE ; } virtual void SetPullMode (IN BOOL f) ; virtual HRESULT Active ( ) ; // transitions to inactive state virtual HRESULT Inactive ( ) ; } ; class CMpeg2StreamAnalyzer { CMPEG2Demultiplexer * m_pMpeg2Demultiplexer ; protected : // declare only, don't define CMpeg2StreamAnalyzer ( ) ; CMpeg2StreamAnalyzer ( CMPEG2Demultiplexer * pMpeg2Demultiplexer ) : m_pMpeg2Demultiplexer (pMpeg2Demultiplexer) {} HRESULT CreateAVStream_ ( IN LPWSTR pszPinName, IN AM_MEDIA_TYPE * pMediaType, IN BYTE bStreamId, IN BYTE bFilterValue = 0xff, IN int iDataOffset = 0, IN DWORD dwMediaSampleContent = MPEG2_MEDIA_ELEMENTARY_STREAM ) ; public : virtual ~CMpeg2StreamAnalyzer ( ) {} virtual BOOL ValidStream ( ) = 0 ; virtual HRESULT AnalyzeStream ( ) = 0 ; virtual HRESULT GetStreamDuration ( OUT LONGLONG * pllStreamBytes, OUT REFERENCE_TIME * prtStreamDuration ) = 0 ; } ; class CMpeg2ProgramStreamAnalyzer : public CMpeg2StreamAnalyzer /*++ This class analyzes a program stream and configures the demultiplexer for replay of audio and video. It will seek through the stream up to a max for both. Stopping as soon as it is configured properly. --*/ { enum { // -------------------------------------------------------------------- // this number is the backwards step size we take when we compute // the stream duration; we start from end - STREAM_DURATION_SEEK_STEP, // look forward for the last pack header; if it's not found, we repeat // the step until we find the last pack; we step by this amount each // time STREAM_DURATION_SEEK_STEP = 0x1000, // -------------------------------------------------------------------- // this number is pure legacy; we try to detect in as little as // READ_BUFFER_SIZE, but we don't want to read an entire stream sifting // for both audio and video, so we read up to this amount and then // call it; we fail if we've found neither at that point, but succeed // if we've even found 1; if we find both before, we return without // reading more MAX_LENGTH_ANALYZED = 1024 * 1024 * 3, } ; CMpeg2ProgramStreamSniffer m_Mpeg2Sniffer ; LONGLONG m_llFirstSCR ; // first SCR we see LONGLONG m_llFirstPackOffset ; // stream offset to first pack BOOL m_fVideoConfigured ; // TRUE: pin and mapping done BOOL m_fAudioConfigured ; // TRUE: pin and mapping done BYTE m_bVideoStreamId ; // stream_id for video BYTE m_bAudioStreamId ; // stream_id for audio HRESULT AnalyzePESPacket_ ( IN BYTE * pbPacket ) ; BYTE * GetFirstPackHeader_ ( ) ; HRESULT InitVideoStream_ ( IN UCHAR uStreamId, IN BYTE * pbPESPayload, IN int iLen ) ; HRESULT InitMpeg1AudioStream_ ( IN UCHAR uStreamId, IN BYTE * pbPESPayload, IN int iLen ) ; HRESULT InitAC3AudioStream_ ( IN UCHAR uStreamId, IN BYTE * pbPESPayload, IN int iLen ) ; HRESULT InitLPCMAudioStream_ ( IN UCHAR uStreamId, IN BYTE * pbPESPayload, IN int iLen ) ; BOOL AnalysisComplete_ () { return m_fVideoConfigured == TRUE && m_fAudioConfigured == TRUE && m_llFirstSCR != UNDEFINED ; } public : CMpeg2ProgramStreamAnalyzer ( CMPEG2Demultiplexer * pMpeg2Demultiplexer, IAsyncReader * pIAsyncReader ) : CMpeg2StreamAnalyzer (pMpeg2Demultiplexer), m_Mpeg2Sniffer (pIAsyncReader), m_fVideoConfigured (FALSE), m_bVideoStreamId (UNDEFINED), m_fAudioConfigured (FALSE), m_bAudioStreamId (UNDEFINED), m_llFirstSCR (UNDEFINED), m_llFirstPackOffset (UNDEFINED) {} // -------------------------------------------------------------------- // CMpeg2StreamAnalyzer methods virtual BOOL ValidStream ( ) ; virtual HRESULT AnalyzeStream ( ) ; virtual HRESULT GetStreamDuration ( OUT LONGLONG * pllStreamBytes, OUT REFERENCE_TIME * prtStreamDuration ) ; } ; #endif // __mp2demux_tsctrlr_h