//------------------------------------------------------------------------------
//
// 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
//======================================================================
#ifndef _mp2demux__pin_in_h
#define _mp2demux__pin_in_h
// forward declarations
class CMPEG2Demultiplexer ;
class CMPEG2DemuxInputPin ;
class CStreamPull ;
class CRefCountedCritSec ;
class CMp2PullPin :
public CAMThread
// shamlessly stolen from "old" splitter
//
// CPullPin
//
// object supporting pulling data from an IAsyncReader interface.
// Given a start/stop position, calls a pure Receive method with each
// IMediaSample received.
//
// This is essentially for use in a MemInputPin when it finds itself
// connected to an IAsyncReader pin instead of a pushing pin.
//
{
protected:
IAsyncReader* m_pReader;
REFERENCE_TIME m_tStart;
REFERENCE_TIME m_tStop;
REFERENCE_TIME m_tDuration;
IMemAllocator * m_pAlloc;
BOOL m_bSync;
enum ThreadMsg {
TM_Pause, // stop pulling and wait for next message
TM_Start, // start pulling
TM_Exit, // stop and exit
};
ThreadMsg m_State;
// override pure thread proc from CThread
DWORD ThreadProc(void);
// running pull method (check m_bSync)
void Process(void);
// clean up any cancelled i/o after a flush
void CleanupCancelled(void);
// start thread pulling - create thread if necy
public:
HRESULT StartThread();
// suspend thread from pulling, eg during seek
HRESULT PauseThread();
protected:
// stop and close thread
HRESULT StopThread();
// called from ProcessAsync to queue and collect requests
HRESULT QueueSample(
REFERENCE_TIME& tCurrent,
REFERENCE_TIME tAlignStop,
BOOL bDiscontinuity);
HRESULT CollectAndDeliver(
REFERENCE_TIME tStart,
REFERENCE_TIME tStop);
HRESULT DeliverSample(
IMediaSample* pSample,
REFERENCE_TIME tStart,
REFERENCE_TIME tStop);
public:
CMp2PullPin();
virtual ~CMp2PullPin();
// returns S_OK if successfully connected to an IAsyncReader interface
// from this object
// Optional allocator should be proposed as a preferred allocator if
// necessary
// bSync is TRUE if we are to use sync reads instead of the
// async methods.
HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync);
// disconnect any connection made in Connect
HRESULT Disconnect();
// agree an allocator using RequestAllocator - optional
// props param specifies your requirements (non-zero fields).
// returns an error code if fail to match requirements.
// optional IMemAllocator interface is offered as a preferred allocator
// but no error occurs if it can't be met.
HRESULT DecideAllocator(
IMemAllocator* pAlloc,
ALLOCATOR_PROPERTIES * pProps);
// set start and stop position. if active, will start immediately at
// the new position. Default is 0 to duration
HRESULT Seek(
REFERENCE_TIME tStart,
REFERENCE_TIME tStop);
// return the total duration
HRESULT Duration(REFERENCE_TIME* ptDuration);
// start pulling data
HRESULT Active(void);
// stop pulling data
virtual
HRESULT Inactive(void);
// helper functions
LONGLONG AlignDown(LONGLONG ll, LONG lAlign) {
// aligning downwards is just truncation
return ll & ~(lAlign-1);
};
LONGLONG AlignUp(LONGLONG ll, LONG lAlign) {
// align up: round up to next boundary
return (ll + (lAlign -1)) & ~(lAlign -1);
};
// GetReader returns the (addrefed) IAsyncReader interface
// for SyncRead etc
IAsyncReader* GetReader() {
m_pReader->AddRef();
return m_pReader;
};
// -- pure --
// override this to handle data arrival
// return value other than S_OK will stop data
virtual HRESULT Receive(IMediaSample*) PURE;
// override this to handle end-of-stream
virtual HRESULT EndOfStream(void) PURE;
// called on runtime errors that will have caused pulling
// to stop
// these errors are all returned from the upstream filter, who
// will have already reported any errors to the filtergraph.
virtual void OnError(HRESULT hr) PURE;
// flush this pin and all downstream
virtual HRESULT BeginFlush() PURE;
virtual HRESULT EndFlush() PURE;
// initiate a seek, pausing the thread. Returns TRUE if was active
BOOL StartSeek() {
CAutoLock lock(&m_AccessLock);
if (m_State == TM_Start) {
PauseThread();
return TRUE;
} else {
return FALSE;
}
};
};
class CMPEG2DemuxInputPin
: public CBaseInputPin
{
CStreamPull * m_pPull ;
LONG m_cRefcount ; // this is not the same refcount as
// the base class (m_cRef)
CMpeg2Stats * m_pStats ;
CRefCountedCritSec * m_pcrtSeekingLock ;
public :
CMPEG2DemuxInputPin (
IN TCHAR * pObjectName,
IN CMPEG2Demultiplexer * pOwningFilter,
IN CRefCountedCritSec * pcrtFilterLock,
IN CRefCountedCritSec * pcrtSeekingLock,
IN CMpeg2Stats * pStats,
OUT HRESULT * pHr
) ;
~CMPEG2DemuxInputPin (
void
) ;
DECLARE_IUNKNOWN ;
// Override since the life time of pins and filters are not the same
STDMETHODIMP_(ULONG)
NonDelegatingAddRef (
) ;
STDMETHODIMP_(ULONG)
NonDelegatingRelease (
) ;
// CBaseFilter methods
HRESULT
CheckMediaType (
IN const CMediaType * pmt
) ;
HRESULT
CompleteConnect(
IN IPin *pPin
) ;
HRESULT
Active (
) ;
HRESULT
Inactive (
) ;
STDMETHODIMP
Receive (
IN IMediaSample *
) ;
STDMETHODIMP
BeginFlush (
) ;
STDMETHODIMP
EndFlush (
) ;
STDMETHODIMP
EndOfStream (
)
{
HRESULT hr ;
GetMpeg2DemuxFilter () -> LockReceive () ;
hr = GetMpeg2DemuxFilter () -> EndOfStreamLocked () ;
GetMpeg2DemuxFilter () -> UnlockReceive () ;
return hr ;
}
HRESULT
BreakConnect (
) ;
HRESULT
Seek (
IN REFERENCE_TIME rtStart, // in pull pin time ..
IN REFERENCE_TIME rtStop, // in pull pin time ..
IN double dPlaybackRate
) ;
CMPEG2Demultiplexer * GetMpeg2DemuxFilter () { return ((CMPEG2Demultiplexer *) m_pFilter) ; }
CStreamPull * GetPullPin () { return m_pPull ; }
} ;
class CStreamPull :
public CMp2PullPin
{
CMPEG2DemuxInputPin * m_pOwningPin ;
REFERENCE_TIME m_rtLastProcessedStart ; // stream start of last read
REFERENCE_TIME m_rtLastProcessedStop ; // stream stop of last read
public :
CStreamPull (
IN CMPEG2DemuxInputPin * pOwningPin
) : m_pOwningPin (pOwningPin),
m_rtLastProcessedStart (UNDEFINED),
m_rtLastProcessedStop (UNDEFINED)
{
ASSERT (m_pOwningPin) ;
}
HRESULT
EndOfStream (
)
{
return m_pOwningPin -> EndOfStream () ;
}
REFERENCE_TIME GetLastSentStreamStart () { return m_rtLastProcessedStart ; }
REFERENCE_TIME GetLastSentStreamStop () { return m_rtLastProcessedStop ; }
// translators for illogical to logical err.. CPullPin to bytes
static REFERENCE_TIME BytesToCPullPinTime (IN LONGLONG ll) { return ll * UNITS ; }
static LONGLONG CPullPinTimeToBytes (IN REFERENCE_TIME rt) { return rt / UNITS ; }
HRESULT
Receive (
IN IMediaSample * pISample
)
{
HRESULT hr ;
hr = pISample -> GetTime (& m_rtLastProcessedStart, & m_rtLastProcessedStop) ;
if (FAILED (hr)) {
m_rtLastProcessedStart = UNDEFINED ;
m_rtLastProcessedStop = UNDEFINED ;
}
return m_pOwningPin -> Receive (pISample) ;
}
void
OnError (
IN HRESULT hr
)
{
return ;
}
HRESULT
BeginFlush (
)
{
return m_pOwningPin -> BeginFlush () ;
}
HRESULT
EndFlush (
)
{
return m_pOwningPin -> EndFlush () ;
}
virtual
HRESULT Inactive(void)
{
HRESULT hr ;
hr = CMp2PullPin::Inactive () ;
if (SUCCEEDED (hr)) {
m_rtLastProcessedStart = UNDEFINED ;
}
return hr ;
}
void SetStart (IN REFERENCE_TIME rt) { m_tStart = rt ; }
REFERENCE_TIME GetStart () { return m_tStart ; }
// returns the media time start of the last processed
REFERENCE_TIME GetLastProcessedStart () { return m_rtLastProcessedStart ; }
void SetStop (IN REFERENCE_TIME rt) { m_tStop = rt ; }
REFERENCE_TIME GetStop () { return m_tStop ; }
} ;
#endif // _mp2demux__pin_in_h