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