//------------------------------------------------------------------------------
//
// 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