| //------------------------------------------------------------------------------ | |
| // 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<CDeferredCommand> m_listPresentation; | |
| // commands queued in stream time are stored here | |
| CGenericList<CDeferredCommand> 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__ |