//------------------------------------------------------------------------------ // File: CtlUtil.h // // Desc: DirectShow base classes. // // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // Base classes implementing IDispatch parsing for the basic control dual // interfaces. Derive from these and implement just the custom method and // property methods. We also implement CPosPassThru that can be used by // renderers and transforms to pass by IMediaPosition and IMediaSeeking #ifndef __CTLUTIL__ #define __CTLUTIL__ // OLE Automation has different ideas of TRUE and FALSE #define OATRUE (-1) #define OAFALSE (0) // It's possible that we could replace this class with CreateStdDispatch class CBaseDispatch { ITypeInfo * m_pti; public: CBaseDispatch() : m_pti(NULL) {} ~CBaseDispatch(); /* IDispatch methods */ STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); STDMETHODIMP GetTypeInfo( REFIID riid, UINT itinfo, LCID lcid, __deref_out ITypeInfo ** pptinfo); STDMETHODIMP GetIDsOfNames( REFIID riid, __in_ecount(cNames) LPOLESTR * rgszNames, UINT cNames, LCID lcid, __out_ecount(cNames) DISPID * rgdispid); }; class AM_NOVTABLE CMediaControl : public IMediaControl, public CUnknown { CBaseDispatch m_basedisp; public: CMediaControl(const TCHAR *, LPUNKNOWN); DECLARE_IUNKNOWN // override this to publicise our interfaces STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); /* IDispatch methods */ STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); STDMETHODIMP GetTypeInfo( UINT itinfo, LCID lcid, __deref_out ITypeInfo ** pptinfo); STDMETHODIMP GetIDsOfNames( REFIID riid, __in_ecount(cNames) LPOLESTR * rgszNames, UINT cNames, LCID lcid, __out_ecount(cNames) DISPID * rgdispid); STDMETHODIMP Invoke( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, __in DISPPARAMS * pdispparams, __out_opt VARIANT * pvarResult, __out_opt EXCEPINFO * pexcepinfo, __out_opt UINT * puArgErr); }; class AM_NOVTABLE CMediaEvent : public IMediaEventEx, public CUnknown { CBaseDispatch m_basedisp; public: CMediaEvent(__in_opt LPCTSTR, __in_opt LPUNKNOWN); DECLARE_IUNKNOWN // override this to publicise our interfaces STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); /* IDispatch methods */ STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); STDMETHODIMP GetTypeInfo( UINT itinfo, LCID lcid, __deref_out ITypeInfo ** pptinfo); STDMETHODIMP GetIDsOfNames( REFIID riid, __in_ecount(cNames) LPOLESTR * rgszNames, UINT cNames, LCID lcid, __out_ecount(cNames) DISPID * rgdispid); STDMETHODIMP Invoke( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, __in DISPPARAMS * pdispparams, __out_opt VARIANT * pvarResult, __out_opt EXCEPINFO * pexcepinfo, __out_opt UINT * puArgErr); }; class AM_NOVTABLE CMediaPosition : public IMediaPosition, public CUnknown { CBaseDispatch m_basedisp; public: CMediaPosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN); CMediaPosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT *phr); DECLARE_IUNKNOWN // override this to publicise our interfaces STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); /* IDispatch methods */ STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); STDMETHODIMP GetTypeInfo( UINT itinfo, LCID lcid, __deref_out ITypeInfo ** pptinfo); STDMETHODIMP GetIDsOfNames( REFIID riid, __in_ecount(cNames) LPOLESTR * rgszNames, UINT cNames, LCID lcid, __out_ecount(cNames) DISPID * rgdispid); STDMETHODIMP Invoke( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, __in DISPPARAMS * pdispparams, __out_opt VARIANT * pvarResult, __out_opt EXCEPINFO * pexcepinfo, __out_opt UINT * puArgErr); }; // OA-compatibility means that we must use double as the RefTime value, // and REFERENCE_TIME (essentially a LONGLONG) within filters. // this class converts between the two class COARefTime : public CRefTime { public: COARefTime() { }; COARefTime(CRefTime t) : CRefTime(t) { }; COARefTime(REFERENCE_TIME t) : CRefTime(t) { }; COARefTime(double d) { m_time = (LONGLONG) (d * 10000000); }; operator double() { return double(m_time) / 10000000; }; operator REFERENCE_TIME() { return m_time; }; COARefTime& operator=(const double& rd) { m_time = (LONGLONG) (rd * 10000000); return *this; } COARefTime& operator=(const REFERENCE_TIME& rt) { m_time = rt; return *this; } inline BOOL operator==(const COARefTime& rt) { return m_time == rt.m_time; }; inline BOOL operator!=(const COARefTime& rt) { return m_time != rt.m_time; }; inline BOOL operator < (const COARefTime& rt) { return m_time < rt.m_time; }; inline BOOL operator > (const COARefTime& rt) { return m_time > rt.m_time; }; inline BOOL operator >= (const COARefTime& rt) { return m_time >= rt.m_time; }; inline BOOL operator <= (const COARefTime& rt) { return m_time <= rt.m_time; }; inline COARefTime operator+(const COARefTime& rt) { return COARefTime(m_time + rt.m_time); }; inline COARefTime operator-(const COARefTime& rt) { return COARefTime(m_time - rt.m_time); }; inline COARefTime operator*(LONG l) { return COARefTime(m_time * l); }; inline COARefTime operator/(LONG l) { return COARefTime(m_time / l); }; private: // Prevent bugs from constructing from LONG (which gets // converted to double and then multiplied by 10000000 COARefTime(LONG); LONG operator=(LONG); }; // A utility class that handles IMediaPosition and IMediaSeeking on behalf // of single-input pin renderers, or transform filters. // // Renderers will expose this from the filter; transform filters will // expose it from the output pin and not the renderer. // // Create one of these, giving it your IPin* for your input pin, and delegate // all IMediaPosition methods to it. It will query the input pin for // IMediaPosition and respond appropriately. // // Call ForceRefresh if the pin connection changes. // // This class no longer caches the upstream IMediaPosition or IMediaSeeking // it acquires it on each method call. This means ForceRefresh is not needed. // The method is kept for source compatibility and to minimise the changes // if we need to put it back later for performance reasons. class CPosPassThru : public IMediaSeeking, public CMediaPosition { IPin *m_pPin; HRESULT GetPeer(__deref_out IMediaPosition **ppMP); HRESULT GetPeerSeeking(__deref_out IMediaSeeking **ppMS); public: CPosPassThru(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, IPin *); DECLARE_IUNKNOWN HRESULT ForceRefresh() { return S_OK; }; // override to return an accurate current position virtual HRESULT GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime) { return E_FAIL; } STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv); // IMediaSeeking methods STDMETHODIMP GetCapabilities( __out DWORD * pCapabilities ); STDMETHODIMP CheckCapabilities( __inout DWORD * pCapabilities ); STDMETHODIMP SetTimeFormat(const GUID * pFormat); STDMETHODIMP GetTimeFormat(__out GUID *pFormat); STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); STDMETHODIMP IsFormatSupported( const GUID * pFormat); STDMETHODIMP QueryPreferredFormat( __out GUID *pFormat); STDMETHODIMP ConvertTimeFormat(__out LONGLONG * pTarget, __in_opt const GUID * pTargetFormat, LONGLONG Source, __in_opt const GUID * pSourceFormat ); STDMETHODIMP SetPositions( __inout_opt LONGLONG * pCurrent, DWORD CurrentFlags , __inout_opt LONGLONG * pStop, DWORD StopFlags ); STDMETHODIMP GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ); STDMETHODIMP GetCurrentPosition( __out LONGLONG * pCurrent ); STDMETHODIMP GetStopPosition( __out LONGLONG * pStop ); STDMETHODIMP SetRate( double dRate); STDMETHODIMP GetRate( __out double * pdRate); STDMETHODIMP GetDuration( __out LONGLONG *pDuration); STDMETHODIMP GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest ); STDMETHODIMP GetPreroll( __out LONGLONG *pllPreroll ); // IMediaPosition properties STDMETHODIMP get_Duration(__out REFTIME * plength); STDMETHODIMP put_CurrentPosition(REFTIME llTime); STDMETHODIMP get_StopTime(__out REFTIME * pllTime); STDMETHODIMP put_StopTime(REFTIME llTime); STDMETHODIMP get_PrerollTime(__out REFTIME * pllTime); STDMETHODIMP put_PrerollTime(REFTIME llTime); STDMETHODIMP get_Rate(__out double * pdRate); STDMETHODIMP put_Rate(double dRate); STDMETHODIMP get_CurrentPosition(__out REFTIME * pllTime); STDMETHODIMP CanSeekForward(__out LONG *pCanSeekForward); STDMETHODIMP CanSeekBackward(__out LONG *pCanSeekBackward); private: HRESULT GetSeekingLongLong( HRESULT (__stdcall IMediaSeeking::*pMethod)( LONGLONG * ), __out LONGLONG * pll ); }; // Adds the ability to return a current position class CRendererPosPassThru : public CPosPassThru { CCritSec m_PositionLock; // Locks access to our position LONGLONG m_StartMedia; // Start media time last seen LONGLONG m_EndMedia; // And likewise the end media BOOL m_bReset; // Have media times been set public: // Used to help with passing media times through graph CRendererPosPassThru(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, IPin *); HRESULT RegisterMediaTime(IMediaSample *pMediaSample); HRESULT RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime); HRESULT GetMediaTime(__out LONGLONG *pStartTime,__out_opt LONGLONG *pEndTime); HRESULT ResetMediaTime(); HRESULT EOS(); }; STDAPI CreatePosPassThru( __in_opt LPUNKNOWN pAgg, BOOL bRenderer, IPin *pPin, __deref_out IUnknown **ppPassThru ); // A class that handles the IDispatch part of IBasicAudio and leaves the // properties and methods themselves pure virtual. class AM_NOVTABLE CBasicAudio : public IBasicAudio, public CUnknown { CBaseDispatch m_basedisp; public: CBasicAudio(__in_opt LPCTSTR, __in_opt LPUNKNOWN); DECLARE_IUNKNOWN // override this to publicise our interfaces STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); /* IDispatch methods */ STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); STDMETHODIMP GetTypeInfo( UINT itinfo, LCID lcid, __deref_out ITypeInfo ** pptinfo); STDMETHODIMP GetIDsOfNames( REFIID riid, __in_ecount(cNames) LPOLESTR * rgszNames, UINT cNames, LCID lcid, __out_ecount(cNames) DISPID * rgdispid); STDMETHODIMP Invoke( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, __in DISPPARAMS * pdispparams, __out_opt VARIANT * pvarResult, __out_opt EXCEPINFO * pexcepinfo, __out_opt UINT * puArgErr); }; // A class that handles the IDispatch part of IBasicVideo and leaves the // properties and methods themselves pure virtual. class AM_NOVTABLE CBaseBasicVideo : public IBasicVideo2, public CUnknown { CBaseDispatch m_basedisp; public: CBaseBasicVideo(__in_opt LPCTSTR, __in_opt LPUNKNOWN); DECLARE_IUNKNOWN // override this to publicise our interfaces STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); /* IDispatch methods */ STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); STDMETHODIMP GetTypeInfo( UINT itinfo, LCID lcid, __deref_out ITypeInfo ** pptinfo); STDMETHODIMP GetIDsOfNames( REFIID riid, __in_ecount(cNames) LPOLESTR * rgszNames, UINT cNames, LCID lcid, __out_ecount(cNames) DISPID * rgdispid); STDMETHODIMP Invoke( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, __in DISPPARAMS * pdispparams, __out_opt VARIANT * pvarResult, __out_opt EXCEPINFO * pexcepinfo, __out_opt UINT * puArgErr); STDMETHODIMP GetPreferredAspectRatio( __out long *plAspectX, __out long *plAspectY) { return E_NOTIMPL; } }; // A class that handles the IDispatch part of IVideoWindow and leaves the // properties and methods themselves pure virtual. class AM_NOVTABLE CBaseVideoWindow : public IVideoWindow, public CUnknown { CBaseDispatch m_basedisp; public: CBaseVideoWindow(__in_opt LPCTSTR, __in_opt LPUNKNOWN); DECLARE_IUNKNOWN // override this to publicise our interfaces STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); /* IDispatch methods */ STDMETHODIMP GetTypeInfoCount(__out UINT * pctinfo); STDMETHODIMP GetTypeInfo( UINT itinfo, LCID lcid, __deref_out ITypeInfo ** pptinfo); STDMETHODIMP GetIDsOfNames( REFIID riid, __in_ecount(cNames) LPOLESTR * rgszNames, UINT cNames, LCID lcid, __out_ecount(cNames) DISPID * rgdispid); STDMETHODIMP Invoke( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, __in DISPPARAMS * pdispparams, __out_opt VARIANT * pvarResult, __out_opt EXCEPINFO * pexcepinfo, __out_opt UINT * puArgErr); }; // abstract class to help source filters with their implementation // of IMediaPosition. Derive from this and set the duration (and stop // position). Also override NotifyChange to do something when the properties // change. class AM_NOVTABLE CSourcePosition : public CMediaPosition { public: CSourcePosition(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, __in CCritSec *); // IMediaPosition methods STDMETHODIMP get_Duration(__out REFTIME * plength); STDMETHODIMP put_CurrentPosition(REFTIME llTime); STDMETHODIMP get_StopTime(__out REFTIME * pllTime); STDMETHODIMP put_StopTime(REFTIME llTime); STDMETHODIMP get_PrerollTime(__out REFTIME * pllTime); STDMETHODIMP put_PrerollTime(REFTIME llTime); STDMETHODIMP get_Rate(__out double * pdRate); STDMETHODIMP put_Rate(double dRate); STDMETHODIMP CanSeekForward(__out LONG *pCanSeekForward); STDMETHODIMP CanSeekBackward(__out LONG *pCanSeekBackward); // override if you can return the data you are actually working on STDMETHODIMP get_CurrentPosition(__out REFTIME * pllTime) { return E_NOTIMPL; }; protected: // we call this to notify changes. Override to handle them virtual HRESULT ChangeStart() PURE; virtual HRESULT ChangeStop() PURE; virtual HRESULT ChangeRate() PURE; COARefTime m_Duration; COARefTime m_Start; COARefTime m_Stop; double m_Rate; CCritSec * m_pLock; }; class AM_NOVTABLE CSourceSeeking : public IMediaSeeking, public CUnknown { public: DECLARE_IUNKNOWN; STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv); // IMediaSeeking methods STDMETHODIMP IsFormatSupported(const GUID * pFormat); STDMETHODIMP QueryPreferredFormat(__out GUID *pFormat); STDMETHODIMP SetTimeFormat(const GUID * pFormat); STDMETHODIMP IsUsingTimeFormat(const GUID * pFormat); STDMETHODIMP GetTimeFormat(__out GUID *pFormat); STDMETHODIMP GetDuration(__out LONGLONG *pDuration); STDMETHODIMP GetStopPosition(__out LONGLONG *pStop); STDMETHODIMP GetCurrentPosition(__out LONGLONG *pCurrent); STDMETHODIMP GetCapabilities( __out DWORD * pCapabilities ); STDMETHODIMP CheckCapabilities( __inout DWORD * pCapabilities ); STDMETHODIMP ConvertTimeFormat( __out LONGLONG * pTarget, __in_opt const GUID * pTargetFormat, LONGLONG Source, __in_opt const GUID * pSourceFormat ); STDMETHODIMP SetPositions( __inout_opt LONGLONG * pCurrent, DWORD CurrentFlags , __inout_opt LONGLONG * pStop, DWORD StopFlags ); STDMETHODIMP GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ); STDMETHODIMP GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest ); STDMETHODIMP SetRate( double dRate); STDMETHODIMP GetRate( __out double * pdRate); STDMETHODIMP GetPreroll(__out LONGLONG *pPreroll); protected: // ctor CSourceSeeking(__in_opt LPCTSTR, __in_opt LPUNKNOWN, __inout HRESULT*, __in CCritSec *); // we call this to notify changes. Override to handle them virtual HRESULT ChangeStart() PURE; virtual HRESULT ChangeStop() PURE; virtual HRESULT ChangeRate() PURE; CRefTime m_rtDuration; // length of stream CRefTime m_rtStart; // source will start here CRefTime m_rtStop; // source will stop here double m_dRateSeeking; // seeking capabilities DWORD m_dwSeekingCaps; CCritSec * m_pLock; }; // Base classes supporting Deferred commands. // Deferred commands are queued by calls to methods on the IQueueCommand // interface, exposed by the filtergraph and by some filters. A successful // call to one of these methods will return an IDeferredCommand interface // representing the queued command. // // A CDeferredCommand object represents a single deferred command, and exposes // the IDeferredCommand interface as well as other methods permitting time // checks and actual execution. It contains a reference to the CCommandQueue // object on which it is queued. // // CCommandQueue is a base class providing a queue of CDeferredCommand // objects, and methods to add, remove, check status and invoke the queued // commands. A CCommandQueue object would be part of an object that // implemented IQueueCommand. class CCmdQueue; // take a copy of the params and store them. Release any allocated // memory in destructor class CDispParams : public DISPPARAMS { public: CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr = NULL); ~CDispParams(); }; // CDeferredCommand lifetime is controlled by refcounts. Caller of // InvokeAt.. gets a refcounted interface pointer, and the CCmdQueue // object also holds a refcount on us. Calling Cancel or Invoke takes // us off the CCmdQueue and thus reduces the refcount by 1. Once taken // off the queue we cannot be put back on the queue. class CDeferredCommand : public CUnknown, public IDeferredCommand { public: CDeferredCommand( __inout CCmdQueue * pQ, __in_opt LPUNKNOWN pUnk, // aggregation outer unk __inout HRESULT * phr, __in LPUNKNOWN pUnkExecutor, // object that will execute this cmd REFTIME time, __in GUID* iid, long dispidMethod, short wFlags, long cArgs, __in_ecount(cArgs) VARIANT* pDispParams, __out VARIANT* pvarResult, __out short* puArgErr, BOOL bStream ); DECLARE_IUNKNOWN // override this to publicise our interfaces STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __out void **ppv); // IDeferredCommand methods STDMETHODIMP Cancel(); STDMETHODIMP Confidence( __out LONG* pConfidence); STDMETHODIMP Postpone( REFTIME newtime); STDMETHODIMP GetHResult( __out HRESULT* phrResult); // other public methods HRESULT Invoke(); // access methods // returns TRUE if streamtime, FALSE if presentation time BOOL IsStreamTime() { return m_bStream; }; CRefTime GetTime() { return m_time; }; REFIID GetIID() { return *m_iid; }; long GetMethod() { return m_dispidMethod; }; short GetFlags() { return m_wFlags; }; DISPPARAMS* GetParams() { return &m_DispParams; }; VARIANT* GetResult() { return m_pvarResult; }; protected: CCmdQueue* m_pQueue; // pUnk for the interface that we will execute the command on LPUNKNOWN m_pUnk; // stored command data REFERENCE_TIME m_time; GUID* m_iid; long m_dispidMethod; short m_wFlags; VARIANT* m_pvarResult; BOOL m_bStream; CDispParams m_DispParams; DISPID m_DispId; // For get and put // we use this for ITypeInfo access CBaseDispatch m_Dispatch; // save retval here HRESULT m_hrResult; }; // a list of CDeferredCommand objects. this is a base class providing // the basics of access to the list. If you want to use CDeferredCommand // objects then your queue needs to be derived from this class. class AM_NOVTABLE CCmdQueue { public: CCmdQueue(__inout_opt HRESULT *phr = NULL); virtual ~CCmdQueue(); // returns a new CDeferredCommand object that will be initialised with // the parameters and will be added to the queue during construction. // returns S_OK if successfully created otherwise an error and // no object has been queued. virtual HRESULT New( __out CDeferredCommand **ppCmd, __in LPUNKNOWN pUnk, REFTIME time, __in GUID* iid, long dispidMethod, short wFlags, long cArgs, __in_ecount(cArgs) VARIANT* pDispParams, __out VARIANT* pvarResult, __out short* puArgErr, BOOL bStream ); // called by the CDeferredCommand object to add and remove itself // from the queue virtual HRESULT Insert(__in CDeferredCommand* pCmd); virtual HRESULT Remove(__in CDeferredCommand* pCmd); // Command-Due Checking // // There are two schemes of synchronisation: coarse and accurate. In // coarse mode, you wait till the time arrives and then execute the cmd. // In accurate mode, you wait until you are processing the sample that // will appear at the time, and then execute the command. It's up to the // filter which one it will implement. The filtergraph will always // implement coarse mode for commands queued at the filtergraph. // // If you want coarse sync, you probably want to wait until there is a // command due, and then execute it. You can do this by calling // GetDueCommand. If you have several things to wait for, get the // event handle from GetDueHandle() and when this is signalled then call // GetDueCommand. Stream time will only advance between calls to Run and // EndRun. Note that to avoid an extra thread there is no guarantee that // if the handle is set there will be a command ready. Each time the // event is signalled, call GetDueCommand (probably with a 0 timeout); // This may return E_ABORT. // // If you want accurate sync, you must call GetCommandDueFor, passing // as a parameter the stream time of the samples you are about to process. // This will return: // -- a stream-time command due at or before that stream time // -- a presentation-time command due at or before the // time that stream time will be presented (only between Run // and EndRun calls, since outside of this, the mapping from // stream time to presentation time is not known. // -- any presentation-time command due now. // This means that if you want accurate synchronisation on samples that // might be processed during Paused mode, you need to use // stream-time commands. // // In all cases, commands remain queued until Invoked or Cancelled. The // setting and resetting of the event handle is managed entirely by this // queue object. // set the clock used for timing virtual HRESULT SetSyncSource(__in_opt IReferenceClock*); // switch to run mode. Streamtime to Presentation time mapping known. virtual HRESULT Run(REFERENCE_TIME tStreamTimeOffset); // switch to Stopped or Paused mode. Time mapping not known. virtual HRESULT EndRun(); // return a pointer to the next due command. Blocks for msTimeout // milliseconds until there is a due command. // Stream-time commands will only become due between Run and Endrun calls. // The command remains queued until invoked or cancelled. // Returns E_ABORT if timeout occurs, otherwise S_OK (or other error). // Returns an AddRef-ed object virtual HRESULT GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout); // return the event handle that will be signalled whenever // there are deferred commands due for execution (when GetDueCommand // will not block). HANDLE GetDueHandle() { return HANDLE(m_evDue); }; // return a pointer to a command that will be due for a given time. // Pass in a stream time here. The stream time offset will be passed // in via the Run method. // Commands remain queued until invoked or cancelled. // This method will not block. It will report VFW_E_NOT_FOUND if there // are no commands due yet. // Returns an AddRef-ed object virtual HRESULT GetCommandDueFor(REFERENCE_TIME tStream, __out CDeferredCommand**ppCmd); // check if a given time is due (TRUE if it is due yet) BOOL CheckTime(CRefTime time, BOOL bStream) { // if no clock, nothing is due! if (!m_pClock) { return FALSE; } // stream time if (bStream) { // not valid if not running if (!m_bRunning) { return FALSE; } // add on known stream time offset to get presentation time time += m_StreamTimeOffset; } CRefTime Now; m_pClock->GetTime((REFERENCE_TIME*)&Now); return (time <= Now); }; protected: // protect access to lists etc CCritSec m_Lock; // commands queued in presentation time are stored here CGenericList m_listPresentation; // commands queued in stream time are stored here CGenericList m_listStream; // set when any commands are due CAMEvent m_evDue; // creates an advise for the earliest time required, if any void SetTimeAdvise(void); // advise id from reference clock (0 if no outstanding advise) DWORD_PTR m_dwAdvise; // advise time is for this presentation time CRefTime m_tCurrentAdvise; // the reference clock we are using (addrefed) IReferenceClock* m_pClock; // true when running BOOL m_bRunning; // contains stream time offset when m_bRunning is true CRefTime m_StreamTimeOffset; }; #endif // __CTLUTIL__