924 lines
27 KiB
C
924 lines
27 KiB
C
|
//------------------------------------------------------------------------------
|
||
|
// 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__
|