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