forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			2542 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			2542 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | //------------------------------------------------------------------------------
 | ||
|  | // File: CtlUtil.cpp
 | ||
|  | //
 | ||
|  | // 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
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #include <streams.h>
 | ||
|  | #include <limits.h>
 | ||
|  | #include "seekpt.h"
 | ||
|  | 
 | ||
|  | // 'bool' non standard reserved word
 | ||
|  | #pragma warning(disable:4237)
 | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- CBaseDispatch implementation ----------
 | ||
|  | CBaseDispatch::~CBaseDispatch() | ||
|  | { | ||
|  |     if (m_pti) { | ||
|  | 	m_pti->Release(); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // return 1 if we support GetTypeInfo
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseDispatch::GetTypeInfoCount(__out UINT * pctinfo) | ||
|  | { | ||
|  |     CheckPointer(pctinfo,E_POINTER); | ||
|  |     ValidateReadWritePtr(pctinfo,sizeof(UINT *)); | ||
|  |     *pctinfo = 1; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)( | ||
|  | 			    const OLECHAR FAR *szFile, | ||
|  | 			    __deref_out ITypeLib FAR* FAR* pptlib); | ||
|  | 
 | ||
|  | typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid, | ||
|  | 			    WORD wVerMajor, | ||
|  | 			    WORD wVerMinor, | ||
|  | 			    LCID lcid, | ||
|  | 			    __deref_out ITypeLib FAR* FAR* pptlib); | ||
|  | 
 | ||
|  | // attempt to find our type library
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseDispatch::GetTypeInfo( | ||
|  |   REFIID riid, | ||
|  |   UINT itinfo, | ||
|  |   LCID lcid, | ||
|  |   __deref_out ITypeInfo ** pptinfo) | ||
|  | { | ||
|  |     CheckPointer(pptinfo,E_POINTER); | ||
|  |     ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *)); | ||
|  |     HRESULT hr; | ||
|  | 
 | ||
|  |     *pptinfo = NULL; | ||
|  | 
 | ||
|  |     // we only support one type element
 | ||
|  |     if (0 != itinfo) { | ||
|  | 	return TYPE_E_ELEMENTNOTFOUND; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (NULL == pptinfo) { | ||
|  | 	return E_POINTER; | ||
|  |     } | ||
|  | 
 | ||
|  |     // always look for neutral
 | ||
|  |     if (NULL == m_pti) { | ||
|  | 
 | ||
|  | 	LPLOADTYPELIB	    lpfnLoadTypeLib; | ||
|  | 	LPLOADREGTYPELIB    lpfnLoadRegTypeLib; | ||
|  | 	ITypeLib	    *ptlib; | ||
|  | 	HINSTANCE	    hInst; | ||
|  | 
 | ||
|  | 	static const char  szTypeLib[]	  = "LoadTypeLib"; | ||
|  | 	static const char  szRegTypeLib[] = "LoadRegTypeLib"; | ||
|  | 	static const WCHAR szControl[]	  = L"control.tlb"; | ||
|  | 
 | ||
|  | 	//
 | ||
|  | 	// Try to get the Ole32Aut.dll module handle.
 | ||
|  | 	//
 | ||
|  | 
 | ||
|  | 	hInst = LoadOLEAut32(); | ||
|  | 	if (hInst == NULL) { | ||
|  | 	    DWORD dwError = GetLastError(); | ||
|  | 	    return AmHresultFromWin32(dwError); | ||
|  | 	} | ||
|  | 	lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst, | ||
|  | 							      szRegTypeLib); | ||
|  | 	if (lpfnLoadRegTypeLib == NULL) { | ||
|  | 	    DWORD dwError = GetLastError(); | ||
|  | 	    return AmHresultFromWin32(dwError); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0
 | ||
|  | 				   lcid, &ptlib); | ||
|  | 
 | ||
|  | 	if (FAILED(hr)) { | ||
|  | 
 | ||
|  | 	    // attempt to load directly - this will fill the
 | ||
|  | 	    // registry in if it finds it
 | ||
|  | 
 | ||
|  | 	    lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib); | ||
|  | 	    if (lpfnLoadTypeLib == NULL) { | ||
|  | 		DWORD dwError = GetLastError(); | ||
|  | 		return AmHresultFromWin32(dwError); | ||
|  | 	    } | ||
|  | 
 | ||
|  | 	    hr = (*lpfnLoadTypeLib)(szControl, &ptlib); | ||
|  | 	    if (FAILED(hr)) { | ||
|  | 		return hr; | ||
|  | 	    } | ||
|  | 	} | ||
|  | 
 | ||
|  | 	hr = ptlib->GetTypeInfoOfGuid( | ||
|  | 		    riid, | ||
|  | 		    &m_pti); | ||
|  | 
 | ||
|  | 	ptlib->Release(); | ||
|  | 
 | ||
|  | 	if (FAILED(hr)) { | ||
|  | 	    return hr; | ||
|  | 	} | ||
|  |     } | ||
|  | 
 | ||
|  |     *pptinfo = m_pti; | ||
|  |     m_pti->AddRef(); | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseDispatch::GetIDsOfNames( | ||
|  |   REFIID riid, | ||
|  |   __in_ecount(cNames) LPOLESTR * rgszNames, | ||
|  |   UINT cNames, | ||
|  |   LCID lcid, | ||
|  |   __out_ecount(cNames) DISPID * rgdispid) | ||
|  | { | ||
|  |     // although the IDispatch riid is dead, we use this to pass from
 | ||
|  |     // the interface implementation class to us the iid we are talking about.
 | ||
|  | 
 | ||
|  |     ITypeInfo * pti; | ||
|  |     HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti); | ||
|  | 
 | ||
|  |     if (SUCCEEDED(hr)) { | ||
|  | 	hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid); | ||
|  | 
 | ||
|  | 	pti->Release(); | ||
|  |     } | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- CMediaControl implementation ---------
 | ||
|  | 
 | ||
|  | CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) : | ||
|  |     CUnknown(name, pUnk) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | // expose our interfaces IMediaControl and IUnknown
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaControl::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) | ||
|  | { | ||
|  |     ValidateReadWritePtr(ppv,sizeof(PVOID)); | ||
|  |     if (riid == IID_IMediaControl) { | ||
|  | 	return GetInterface( (IMediaControl *) this, ppv); | ||
|  |     } else { | ||
|  | 	return CUnknown::NonDelegatingQueryInterface(riid, ppv); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // return 1 if we support GetTypeInfo
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaControl::GetTypeInfoCount(__out UINT * pctinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfoCount(pctinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // attempt to find our type library
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaControl::GetTypeInfo( | ||
|  |   UINT itinfo, | ||
|  |   LCID lcid, | ||
|  |   __deref_out ITypeInfo ** pptinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfo( | ||
|  | 		IID_IMediaControl, | ||
|  | 		itinfo, | ||
|  | 		lcid, | ||
|  | 		pptinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaControl::GetIDsOfNames( | ||
|  |   REFIID riid, | ||
|  |   __in_ecount(cNames) LPOLESTR * rgszNames, | ||
|  |   UINT cNames, | ||
|  |   LCID lcid, | ||
|  |   __out_ecount(cNames) DISPID * rgdispid) | ||
|  | { | ||
|  |     return m_basedisp.GetIDsOfNames( | ||
|  | 			IID_IMediaControl, | ||
|  | 			rgszNames, | ||
|  | 			cNames, | ||
|  | 			lcid, | ||
|  | 			rgdispid); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaControl::Invoke( | ||
|  |   DISPID dispidMember, | ||
|  |   REFIID riid, | ||
|  |   LCID lcid, | ||
|  |   WORD wFlags, | ||
|  |   __in DISPPARAMS * pdispparams, | ||
|  |   __out_opt VARIANT * pvarResult, | ||
|  |   __out_opt EXCEPINFO * pexcepinfo, | ||
|  |   __out_opt UINT * puArgErr) | ||
|  | { | ||
|  |     // this parameter is a dead leftover from an earlier interface
 | ||
|  |     if (IID_NULL != riid) { | ||
|  | 	return DISP_E_UNKNOWNINTERFACE; | ||
|  |     } | ||
|  | 
 | ||
|  |     ITypeInfo * pti; | ||
|  |     HRESULT hr = GetTypeInfo(0, lcid, &pti); | ||
|  | 
 | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pti->Invoke( | ||
|  | 	    (IMediaControl *)this, | ||
|  | 	    dispidMember, | ||
|  | 	    wFlags, | ||
|  | 	    pdispparams, | ||
|  | 	    pvarResult, | ||
|  | 	    pexcepinfo, | ||
|  | 	    puArgErr); | ||
|  | 
 | ||
|  |     pti->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- CMediaEvent implementation ----------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | CMediaEvent::CMediaEvent(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) : | ||
|  |     CUnknown(name, pUnk) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // expose our interfaces IMediaEvent and IUnknown
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaEvent::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) | ||
|  | { | ||
|  |     ValidateReadWritePtr(ppv,sizeof(PVOID)); | ||
|  |     if (riid == IID_IMediaEvent || riid == IID_IMediaEventEx) { | ||
|  | 	return GetInterface( (IMediaEventEx *) this, ppv); | ||
|  |     } else { | ||
|  | 	return CUnknown::NonDelegatingQueryInterface(riid, ppv); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // return 1 if we support GetTypeInfo
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaEvent::GetTypeInfoCount(__out UINT * pctinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfoCount(pctinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // attempt to find our type library
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaEvent::GetTypeInfo( | ||
|  |   UINT itinfo, | ||
|  |   LCID lcid, | ||
|  |   __deref_out ITypeInfo ** pptinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfo( | ||
|  | 		IID_IMediaEvent, | ||
|  | 		itinfo, | ||
|  | 		lcid, | ||
|  | 		pptinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaEvent::GetIDsOfNames( | ||
|  |   REFIID riid, | ||
|  |   __in_ecount(cNames) LPOLESTR * rgszNames, | ||
|  |   UINT cNames, | ||
|  |   LCID lcid, | ||
|  |   __out_ecount(cNames) DISPID * rgdispid) | ||
|  | { | ||
|  |     return m_basedisp.GetIDsOfNames( | ||
|  | 			IID_IMediaEvent, | ||
|  | 			rgszNames, | ||
|  | 			cNames, | ||
|  | 			lcid, | ||
|  | 			rgdispid); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaEvent::Invoke( | ||
|  |   DISPID dispidMember, | ||
|  |   REFIID riid, | ||
|  |   LCID lcid, | ||
|  |   WORD wFlags, | ||
|  |   __in DISPPARAMS * pdispparams, | ||
|  |   __out_opt VARIANT * pvarResult, | ||
|  |   __out_opt EXCEPINFO * pexcepinfo, | ||
|  |   __out_opt UINT * puArgErr) | ||
|  | { | ||
|  |     // this parameter is a dead leftover from an earlier interface
 | ||
|  |     if (IID_NULL != riid) { | ||
|  | 	return DISP_E_UNKNOWNINTERFACE; | ||
|  |     } | ||
|  | 
 | ||
|  |     ITypeInfo * pti; | ||
|  |     HRESULT hr = GetTypeInfo(0, lcid, &pti); | ||
|  | 
 | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pti->Invoke( | ||
|  | 	    (IMediaEvent *)this, | ||
|  | 	    dispidMember, | ||
|  | 	    wFlags, | ||
|  | 	    pdispparams, | ||
|  | 	    pvarResult, | ||
|  | 	    pexcepinfo, | ||
|  | 	    puArgErr); | ||
|  | 
 | ||
|  |     pti->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- CMediaPosition implementation ----------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | CMediaPosition::CMediaPosition(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) : | ||
|  |     CUnknown(name, pUnk) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | CMediaPosition::CMediaPosition(__in_opt LPCTSTR name, | ||
|  |                                __in_opt LPUNKNOWN pUnk, | ||
|  |                                __inout HRESULT * phr) : | ||
|  |     CUnknown(name, pUnk) | ||
|  | { | ||
|  |     UNREFERENCED_PARAMETER(phr); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // expose our interfaces IMediaPosition and IUnknown
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaPosition::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) | ||
|  | { | ||
|  |     ValidateReadWritePtr(ppv,sizeof(PVOID)); | ||
|  |     if (riid == IID_IMediaPosition) { | ||
|  | 	return GetInterface( (IMediaPosition *) this, ppv); | ||
|  |     } else { | ||
|  | 	return CUnknown::NonDelegatingQueryInterface(riid, ppv); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // return 1 if we support GetTypeInfo
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaPosition::GetTypeInfoCount(__out UINT * pctinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfoCount(pctinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // attempt to find our type library
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaPosition::GetTypeInfo( | ||
|  |   UINT itinfo, | ||
|  |   LCID lcid, | ||
|  |   __deref_out ITypeInfo ** pptinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfo( | ||
|  | 		IID_IMediaPosition, | ||
|  | 		itinfo, | ||
|  | 		lcid, | ||
|  | 		pptinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaPosition::GetIDsOfNames( | ||
|  |   REFIID riid, | ||
|  |   __in_ecount(cNames) LPOLESTR * rgszNames, | ||
|  |   UINT cNames, | ||
|  |   LCID lcid, | ||
|  |   __out_ecount(cNames) DISPID * rgdispid) | ||
|  | { | ||
|  |     return m_basedisp.GetIDsOfNames( | ||
|  | 			IID_IMediaPosition, | ||
|  | 			rgszNames, | ||
|  | 			cNames, | ||
|  | 			lcid, | ||
|  | 			rgdispid); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CMediaPosition::Invoke( | ||
|  |   DISPID dispidMember, | ||
|  |   REFIID riid, | ||
|  |   LCID lcid, | ||
|  |   WORD wFlags, | ||
|  |   __in DISPPARAMS * pdispparams, | ||
|  |   __out_opt VARIANT * pvarResult, | ||
|  |   __out_opt EXCEPINFO * pexcepinfo, | ||
|  |   __out_opt UINT * puArgErr) | ||
|  | { | ||
|  |     // this parameter is a dead leftover from an earlier interface
 | ||
|  |     if (IID_NULL != riid) { | ||
|  | 	return DISP_E_UNKNOWNINTERFACE; | ||
|  |     } | ||
|  | 
 | ||
|  |     ITypeInfo * pti; | ||
|  |     HRESULT hr = GetTypeInfo(0, lcid, &pti); | ||
|  | 
 | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pti->Invoke( | ||
|  | 	    (IMediaPosition *)this, | ||
|  | 	    dispidMember, | ||
|  | 	    wFlags, | ||
|  | 	    pdispparams, | ||
|  | 	    pvarResult, | ||
|  | 	    pexcepinfo, | ||
|  | 	    puArgErr); | ||
|  | 
 | ||
|  |     pti->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- IMediaPosition and IMediaSeeking pass through class ----------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | CPosPassThru::CPosPassThru(__in_opt LPCTSTR pName, | ||
|  | 			   __in_opt LPUNKNOWN pUnk, | ||
|  | 			   __inout HRESULT *phr, | ||
|  | 			   IPin *pPin) : | ||
|  |     CMediaPosition(pName,pUnk), | ||
|  |     m_pPin(pPin) | ||
|  | { | ||
|  |     if (pPin == NULL) { | ||
|  | 	*phr = E_POINTER; | ||
|  | 	return; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // Expose our IMediaSeeking and IMediaPosition interfaces
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv) | ||
|  | { | ||
|  |     CheckPointer(ppv,E_POINTER); | ||
|  |     *ppv = NULL; | ||
|  | 
 | ||
|  |     if (riid == IID_IMediaSeeking) { | ||
|  | 	return GetInterface( static_cast<IMediaSeeking *>(this), ppv); | ||
|  |     } | ||
|  |     return CMediaPosition::NonDelegatingQueryInterface(riid,ppv); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // Return the IMediaPosition interface from our peer
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CPosPassThru::GetPeer(IMediaPosition ** ppMP) | ||
|  | { | ||
|  |     *ppMP = NULL; | ||
|  | 
 | ||
|  |     IPin *pConnected; | ||
|  |     HRESULT hr = m_pPin->ConnectedTo(&pConnected); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return E_NOTIMPL; | ||
|  |     } | ||
|  |     IMediaPosition * pMP; | ||
|  |     hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP); | ||
|  |     pConnected->Release(); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return E_NOTIMPL; | ||
|  |     } | ||
|  | 
 | ||
|  |     *ppMP = pMP; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // Return the IMediaSeeking interface from our peer
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CPosPassThru::GetPeerSeeking(__deref_out IMediaSeeking ** ppMS) | ||
|  | { | ||
|  |     *ppMS = NULL; | ||
|  | 
 | ||
|  |     IPin *pConnected; | ||
|  |     HRESULT hr = m_pPin->ConnectedTo(&pConnected); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return E_NOTIMPL; | ||
|  |     } | ||
|  |     IMediaSeeking * pMS; | ||
|  |     hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS); | ||
|  |     pConnected->Release(); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return E_NOTIMPL; | ||
|  |     } | ||
|  | 
 | ||
|  |     *ppMS = pMS; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- IMediaSeeking methods ----------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::GetCapabilities(__out DWORD * pCaps) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMS->GetCapabilities(pCaps); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::CheckCapabilities(__inout DWORD * pCaps) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMS->CheckCapabilities(pCaps); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::IsFormatSupported(const GUID * pFormat) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMS->IsFormatSupported(pFormat); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::QueryPreferredFormat(__out GUID *pFormat) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMS->QueryPreferredFormat(pFormat); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::SetTimeFormat(const GUID * pFormat) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMS->SetTimeFormat(pFormat); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::GetTimeFormat(__out GUID *pFormat) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMS->GetTimeFormat(pFormat); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::IsUsingTimeFormat(const GUID * pFormat) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMS->IsUsingTimeFormat(pFormat); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::ConvertTimeFormat(__out LONGLONG * pTarget,  | ||
|  |                                 __in_opt const GUID * pTargetFormat, | ||
|  | 				LONGLONG Source,  | ||
|  |                                 __in_opt const GUID * pSourceFormat ) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat ); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::SetPositions( __inout_opt LONGLONG * pCurrent,  | ||
|  |                             DWORD CurrentFlags,  | ||
|  |                             __inout_opt LONGLONG * pStop,  | ||
|  |                             DWORD StopFlags ) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags ); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::GetPositions(__out_opt LONGLONG *pCurrent, __out_opt LONGLONG * pStop) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMS->GetPositions(pCurrent,pStop); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CPosPassThru::GetSeekingLongLong | ||
|  | ( HRESULT (__stdcall IMediaSeeking::*pMethod)( __out LONGLONG * ) | ||
|  | , LONGLONG * pll | ||
|  | ) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (SUCCEEDED(hr)) | ||
|  |     { | ||
|  | 	hr = (pMS->*pMethod)(pll); | ||
|  | 	pMS->Release(); | ||
|  |     } | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | // If we don't have a current position then ask upstream
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::GetCurrentPosition(__out LONGLONG *pCurrent) | ||
|  | { | ||
|  |     // Can we report the current position
 | ||
|  |     HRESULT hr = GetMediaTime(pCurrent,NULL); | ||
|  |     if (SUCCEEDED(hr)) hr = NOERROR; | ||
|  |     else hr = GetSeekingLongLong( &IMediaSeeking::GetCurrentPosition, pCurrent ); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::GetStopPosition(__out LONGLONG *pStop) | ||
|  | { | ||
|  |     return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop );; | ||
|  | } | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::GetDuration(__out LONGLONG *pDuration) | ||
|  | { | ||
|  |     return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration );; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::GetPreroll(__out LONGLONG *pllPreroll) | ||
|  | { | ||
|  |     return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll );; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest ) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMS->GetAvailable( pEarliest, pLatest ); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::GetRate(__out double * pdRate) | ||
|  | { | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMS->GetRate(pdRate); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::SetRate(double dRate) | ||
|  | { | ||
|  |     if (0.0 == dRate) { | ||
|  | 		return E_INVALIDARG; | ||
|  |     } | ||
|  | 
 | ||
|  |     IMediaSeeking* pMS; | ||
|  |     HRESULT hr = GetPeerSeeking(&pMS); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMS->SetRate(dRate); | ||
|  |     pMS->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- IMediaPosition methods ----------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::get_Duration(__out REFTIME * plength) | ||
|  | { | ||
|  |     IMediaPosition* pMP; | ||
|  |     HRESULT hr = GetPeer(&pMP); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pMP->get_Duration(plength); | ||
|  |     pMP->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::get_CurrentPosition(__out REFTIME * pllTime) | ||
|  | { | ||
|  |     IMediaPosition* pMP; | ||
|  |     HRESULT hr = GetPeer(&pMP); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMP->get_CurrentPosition(pllTime); | ||
|  |     pMP->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::put_CurrentPosition(REFTIME llTime) | ||
|  | { | ||
|  |     IMediaPosition* pMP; | ||
|  |     HRESULT hr = GetPeer(&pMP); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMP->put_CurrentPosition(llTime); | ||
|  |     pMP->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::get_StopTime(__out REFTIME * pllTime) | ||
|  | { | ||
|  |     IMediaPosition* pMP; | ||
|  |     HRESULT hr = GetPeer(&pMP); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMP->get_StopTime(pllTime); | ||
|  |     pMP->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::put_StopTime(REFTIME llTime) | ||
|  | { | ||
|  |     IMediaPosition* pMP; | ||
|  |     HRESULT hr = GetPeer(&pMP); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMP->put_StopTime(llTime); | ||
|  |     pMP->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::get_PrerollTime(__out REFTIME * pllTime) | ||
|  | { | ||
|  |     IMediaPosition* pMP; | ||
|  |     HRESULT hr = GetPeer(&pMP); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMP->get_PrerollTime(pllTime); | ||
|  |     pMP->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::put_PrerollTime(REFTIME llTime) | ||
|  | { | ||
|  |     IMediaPosition* pMP; | ||
|  |     HRESULT hr = GetPeer(&pMP); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMP->put_PrerollTime(llTime); | ||
|  |     pMP->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::get_Rate(__out double * pdRate) | ||
|  | { | ||
|  |     IMediaPosition* pMP; | ||
|  |     HRESULT hr = GetPeer(&pMP); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMP->get_Rate(pdRate); | ||
|  |     pMP->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::put_Rate(double dRate) | ||
|  | { | ||
|  |     if (0.0 == dRate) { | ||
|  | 		return E_INVALIDARG; | ||
|  |     } | ||
|  | 
 | ||
|  |     IMediaPosition* pMP; | ||
|  |     HRESULT hr = GetPeer(&pMP); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMP->put_Rate(dRate); | ||
|  |     pMP->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::CanSeekForward(__out LONG *pCanSeekForward) | ||
|  | { | ||
|  |     IMediaPosition* pMP; | ||
|  |     HRESULT hr = GetPeer(&pMP); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMP->CanSeekForward(pCanSeekForward); | ||
|  |     pMP->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CPosPassThru::CanSeekBackward(__out LONG *pCanSeekBackward) | ||
|  | { | ||
|  |     IMediaPosition* pMP; | ||
|  |     HRESULT hr = GetPeer(&pMP); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  |     hr = pMP->CanSeekBackward(pCanSeekBackward); | ||
|  |     pMP->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- Implements the CRendererPosPassThru class ----------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | // Media times (eg current frame, field, sample etc) are passed through the
 | ||
|  | // filtergraph in media samples. When a renderer gets a sample with media
 | ||
|  | // times in it, it will call one of the RegisterMediaTime methods we expose
 | ||
|  | // (one takes an IMediaSample, the other takes the media times direct). We
 | ||
|  | // store the media times internally and return them in GetCurrentPosition.
 | ||
|  | 
 | ||
|  | CRendererPosPassThru::CRendererPosPassThru(__in_opt LPCTSTR pName, | ||
|  | 					   __in_opt LPUNKNOWN pUnk, | ||
|  | 					   __inout HRESULT *phr, | ||
|  | 					   IPin *pPin) : | ||
|  |     CPosPassThru(pName,pUnk,phr,pPin), | ||
|  |     m_StartMedia(0), | ||
|  |     m_EndMedia(0), | ||
|  |     m_bReset(TRUE) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // Sets the media times the object should report
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample) | ||
|  | { | ||
|  |     ASSERT(pMediaSample); | ||
|  |     LONGLONG StartMedia; | ||
|  |     LONGLONG EndMedia; | ||
|  | 
 | ||
|  |     CAutoLock cAutoLock(&m_PositionLock); | ||
|  | 
 | ||
|  |     // Get the media times from the sample
 | ||
|  | 
 | ||
|  |     HRESULT hr = pMediaSample->GetTime(&StartMedia,&EndMedia); | ||
|  |     if (FAILED(hr)) | ||
|  |     { | ||
|  | 	ASSERT(hr == VFW_E_SAMPLE_TIME_NOT_SET); | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     m_StartMedia = StartMedia; | ||
|  |     m_EndMedia = EndMedia; | ||
|  |     m_bReset = FALSE; | ||
|  |     return NOERROR; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // Sets the media times the object should report
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime) | ||
|  | { | ||
|  |     CAutoLock cAutoLock(&m_PositionLock); | ||
|  |     m_StartMedia = StartTime; | ||
|  |     m_EndMedia = EndTime; | ||
|  |     m_bReset = FALSE; | ||
|  |     return NOERROR; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // Return the current media times registered in the object
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CRendererPosPassThru::GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime) | ||
|  | { | ||
|  |     ASSERT(pStartTime); | ||
|  | 
 | ||
|  |     CAutoLock cAutoLock(&m_PositionLock); | ||
|  |     if (m_bReset == TRUE) { | ||
|  | 	return E_FAIL; | ||
|  |     } | ||
|  | 
 | ||
|  |     // We don't have to return the end time
 | ||
|  | 
 | ||
|  |     HRESULT hr = ConvertTimeFormat( pStartTime, 0, m_StartMedia, &TIME_FORMAT_MEDIA_TIME ); | ||
|  |     if (pEndTime && SUCCEEDED(hr)) { | ||
|  | 	hr = ConvertTimeFormat( pEndTime, 0, m_EndMedia, &TIME_FORMAT_MEDIA_TIME ); | ||
|  |     } | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // Resets the media times we hold
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CRendererPosPassThru::ResetMediaTime() | ||
|  | { | ||
|  |     CAutoLock cAutoLock(&m_PositionLock); | ||
|  |     m_StartMedia = 0; | ||
|  |     m_EndMedia = 0; | ||
|  |     m_bReset = TRUE; | ||
|  |     return NOERROR; | ||
|  | } | ||
|  | 
 | ||
|  | // Intended to be called by the owing filter during EOS processing so
 | ||
|  | // that the media times can be adjusted to the stop time.  This ensures
 | ||
|  | // that the GetCurrentPosition will actully get to the stop position.
 | ||
|  | HRESULT | ||
|  | CRendererPosPassThru::EOS() | ||
|  | { | ||
|  |     HRESULT hr; | ||
|  | 
 | ||
|  |     if ( m_bReset == TRUE ) hr = E_FAIL; | ||
|  |     else | ||
|  |     { | ||
|  | 	LONGLONG llStop; | ||
|  | 	if SUCCEEDED(hr=GetStopPosition(&llStop)) | ||
|  | 	{ | ||
|  | 	    CAutoLock cAutoLock(&m_PositionLock); | ||
|  | 	    m_StartMedia = | ||
|  | 	    m_EndMedia	 = llStop; | ||
|  | 	} | ||
|  |     } | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | // -- CSourceSeeking implementation ------------
 | ||
|  | 
 | ||
|  | CSourceSeeking::CSourceSeeking( | ||
|  |     __in_opt LPCTSTR pName, | ||
|  |     __in_opt LPUNKNOWN pUnk, | ||
|  |     __inout HRESULT* phr, | ||
|  |     __in CCritSec * pLock) : | ||
|  |         CUnknown(pName, pUnk), | ||
|  |         m_pLock(pLock), | ||
|  |         m_rtStart((long)0) | ||
|  | { | ||
|  |     m_rtStop = _I64_MAX / 2; | ||
|  |     m_rtDuration = m_rtStop; | ||
|  |     m_dRateSeeking = 1.0; | ||
|  | 
 | ||
|  |     m_dwSeekingCaps = AM_SEEKING_CanSeekForwards | ||
|  |         | AM_SEEKING_CanSeekBackwards | ||
|  |         | AM_SEEKING_CanSeekAbsolute | ||
|  |         | AM_SEEKING_CanGetStopPos | ||
|  |         | AM_SEEKING_CanGetDuration; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) | ||
|  | { | ||
|  |     if(riid == IID_IMediaSeeking) { | ||
|  |         CheckPointer(ppv, E_POINTER); | ||
|  |         return GetInterface(static_cast<IMediaSeeking *>(this), ppv); | ||
|  |     } | ||
|  |     else { | ||
|  |         return CUnknown::NonDelegatingQueryInterface(riid, ppv); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::IsFormatSupported(const GUID * pFormat) | ||
|  | { | ||
|  |     CheckPointer(pFormat, E_POINTER); | ||
|  |     // only seeking in time (REFERENCE_TIME units) is supported
 | ||
|  |     return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::QueryPreferredFormat(__out GUID *pFormat) | ||
|  | { | ||
|  |     CheckPointer(pFormat, E_POINTER); | ||
|  |     *pFormat = TIME_FORMAT_MEDIA_TIME; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::SetTimeFormat(const GUID * pFormat) | ||
|  | { | ||
|  |     CheckPointer(pFormat, E_POINTER); | ||
|  | 
 | ||
|  |     // nothing to set; just check that it's TIME_FORMAT_TIME
 | ||
|  |     return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat) | ||
|  | { | ||
|  |     CheckPointer(pFormat, E_POINTER); | ||
|  |     return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::GetTimeFormat(__out GUID *pFormat) | ||
|  | { | ||
|  |     CheckPointer(pFormat, E_POINTER); | ||
|  |     *pFormat = TIME_FORMAT_MEDIA_TIME; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::GetDuration(__out LONGLONG *pDuration) | ||
|  | { | ||
|  |     CheckPointer(pDuration, E_POINTER); | ||
|  |     CAutoLock lock(m_pLock); | ||
|  |     *pDuration = m_rtDuration; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::GetStopPosition(__out LONGLONG *pStop) | ||
|  | { | ||
|  |     CheckPointer(pStop, E_POINTER); | ||
|  |     CAutoLock lock(m_pLock); | ||
|  |     *pStop = m_rtStop; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::GetCurrentPosition(__out LONGLONG *pCurrent) | ||
|  | { | ||
|  |     // GetCurrentPosition is typically supported only in renderers and
 | ||
|  |     // not in source filters.
 | ||
|  |     return E_NOTIMPL; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::GetCapabilities( __out DWORD * pCapabilities ) | ||
|  | { | ||
|  |     CheckPointer(pCapabilities, E_POINTER); | ||
|  |     *pCapabilities = m_dwSeekingCaps; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::CheckCapabilities( __inout DWORD * pCapabilities ) | ||
|  | { | ||
|  |     CheckPointer(pCapabilities, E_POINTER); | ||
|  | 
 | ||
|  |     // make sure all requested capabilities are in our mask
 | ||
|  |     return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::ConvertTimeFormat( __out LONGLONG * pTarget,  | ||
|  |                                            __in_opt const GUID * pTargetFormat, | ||
|  |                                            LONGLONG Source,  | ||
|  |                                            __in_opt const GUID * pSourceFormat ) | ||
|  | { | ||
|  |     CheckPointer(pTarget, E_POINTER); | ||
|  |     // format guids can be null to indicate current format
 | ||
|  | 
 | ||
|  |     // since we only support TIME_FORMAT_MEDIA_TIME, we don't really
 | ||
|  |     // offer any conversions.
 | ||
|  |     if(pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME) | ||
|  |     { | ||
|  |         if(pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME) | ||
|  |         { | ||
|  |             *pTarget = Source; | ||
|  |             return S_OK; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return E_INVALIDARG; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::SetPositions( __inout_opt LONGLONG * pCurrent,   | ||
|  |                                       DWORD CurrentFlags,  | ||
|  |                                       __inout_opt LONGLONG * pStop,   | ||
|  |                                       DWORD StopFlags ) | ||
|  | { | ||
|  |     DWORD StopPosBits = StopFlags & AM_SEEKING_PositioningBitsMask; | ||
|  |     DWORD StartPosBits = CurrentFlags & AM_SEEKING_PositioningBitsMask; | ||
|  | 
 | ||
|  |     if(StopFlags) { | ||
|  |         CheckPointer(pStop, E_POINTER); | ||
|  | 
 | ||
|  |         // accept only relative, incremental, or absolute positioning
 | ||
|  |         if(StopPosBits != StopFlags) { | ||
|  |             return E_INVALIDARG; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     if(CurrentFlags) { | ||
|  |         CheckPointer(pCurrent, E_POINTER); | ||
|  |         if(StartPosBits != AM_SEEKING_AbsolutePositioning && | ||
|  |            StartPosBits != AM_SEEKING_RelativePositioning) { | ||
|  |             return E_INVALIDARG; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     // scope for autolock
 | ||
|  |     { | ||
|  |         CAutoLock lock(m_pLock); | ||
|  | 
 | ||
|  |         // set start position
 | ||
|  |         if(StartPosBits == AM_SEEKING_AbsolutePositioning) | ||
|  |         { | ||
|  |             m_rtStart = *pCurrent; | ||
|  |         } | ||
|  |         else if(StartPosBits == AM_SEEKING_RelativePositioning) | ||
|  |         { | ||
|  |             m_rtStart += *pCurrent; | ||
|  |         } | ||
|  | 
 | ||
|  |         // set stop position
 | ||
|  |         if(StopPosBits == AM_SEEKING_AbsolutePositioning) | ||
|  |         { | ||
|  |             m_rtStop = *pStop; | ||
|  |         } | ||
|  |         else if(StopPosBits == AM_SEEKING_IncrementalPositioning) | ||
|  |         { | ||
|  |             m_rtStop = m_rtStart + *pStop; | ||
|  |         } | ||
|  |         else if(StopPosBits == AM_SEEKING_RelativePositioning) | ||
|  |         { | ||
|  |             m_rtStop = m_rtStop + *pStop; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     HRESULT hr = S_OK; | ||
|  |     if(SUCCEEDED(hr) && StopPosBits) { | ||
|  |         hr = ChangeStop(); | ||
|  |     } | ||
|  |     if(StartPosBits) { | ||
|  |         hr = ChangeStart(); | ||
|  |     } | ||
|  | 
 | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop ) | ||
|  | { | ||
|  |     if(pCurrent) { | ||
|  |         *pCurrent = m_rtStart; | ||
|  |     } | ||
|  |     if(pStop) { | ||
|  |         *pStop = m_rtStop; | ||
|  |     } | ||
|  | 
 | ||
|  |     return S_OK;; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest ) | ||
|  | { | ||
|  |     if(pEarliest) { | ||
|  |         *pEarliest = 0; | ||
|  |     } | ||
|  |     if(pLatest) { | ||
|  |         CAutoLock lock(m_pLock); | ||
|  |         *pLatest = m_rtDuration; | ||
|  |     } | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::SetRate( double dRate) | ||
|  | { | ||
|  |     { | ||
|  |         CAutoLock lock(m_pLock); | ||
|  |         m_dRateSeeking = dRate; | ||
|  |     } | ||
|  |     return ChangeRate(); | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::GetRate( __out double * pdRate) | ||
|  | { | ||
|  |     CheckPointer(pdRate, E_POINTER); | ||
|  |     CAutoLock lock(m_pLock); | ||
|  |     *pdRate = m_dRateSeeking; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CSourceSeeking::GetPreroll(__out LONGLONG *pPreroll) | ||
|  | { | ||
|  |     CheckPointer(pPreroll, E_POINTER); | ||
|  |     *pPreroll = 0; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- CSourcePosition implementation ----------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | CSourcePosition::CSourcePosition(__in_opt LPCTSTR pName, | ||
|  | 				 __in_opt LPUNKNOWN pUnk, | ||
|  | 				 __inout HRESULT* phr, | ||
|  | 				 __in CCritSec * pLock) : | ||
|  |     CMediaPosition(pName, pUnk), | ||
|  |     m_pLock(pLock), | ||
|  |     m_Start(CRefTime((LONGLONG)0)) | ||
|  | { | ||
|  |     m_Stop = _I64_MAX; | ||
|  |     m_Rate = 1.0; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CSourcePosition::get_Duration(__out REFTIME * plength) | ||
|  | { | ||
|  |     CheckPointer(plength,E_POINTER); | ||
|  |     ValidateReadWritePtr(plength,sizeof(REFTIME)); | ||
|  |     CAutoLock lock(m_pLock); | ||
|  | 
 | ||
|  |     *plength = m_Duration; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CSourcePosition::put_CurrentPosition(REFTIME llTime) | ||
|  | { | ||
|  |     m_pLock->Lock(); | ||
|  |     m_Start = llTime; | ||
|  |     m_pLock->Unlock(); | ||
|  | 
 | ||
|  |     return ChangeStart(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CSourcePosition::get_StopTime(__out REFTIME * pllTime) | ||
|  | { | ||
|  |     CheckPointer(pllTime,E_POINTER); | ||
|  |     ValidateReadWritePtr(pllTime,sizeof(REFTIME)); | ||
|  |     CAutoLock lock(m_pLock); | ||
|  | 
 | ||
|  |     *pllTime = m_Stop; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CSourcePosition::put_StopTime(REFTIME llTime) | ||
|  | { | ||
|  |     m_pLock->Lock(); | ||
|  |     m_Stop = llTime; | ||
|  |     m_pLock->Unlock(); | ||
|  | 
 | ||
|  |     return ChangeStop(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CSourcePosition::get_PrerollTime(__out REFTIME * pllTime) | ||
|  | { | ||
|  |     CheckPointer(pllTime,E_POINTER); | ||
|  |     ValidateReadWritePtr(pllTime,sizeof(REFTIME)); | ||
|  |     return E_NOTIMPL; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CSourcePosition::put_PrerollTime(REFTIME llTime) | ||
|  | { | ||
|  |     return E_NOTIMPL; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CSourcePosition::get_Rate(__out double * pdRate) | ||
|  | { | ||
|  |     CheckPointer(pdRate,E_POINTER); | ||
|  |     ValidateReadWritePtr(pdRate,sizeof(double)); | ||
|  |     CAutoLock lock(m_pLock); | ||
|  | 
 | ||
|  |     *pdRate = m_Rate; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CSourcePosition::put_Rate(double dRate) | ||
|  | { | ||
|  |     m_pLock->Lock(); | ||
|  |     m_Rate = dRate; | ||
|  |     m_pLock->Unlock(); | ||
|  | 
 | ||
|  |     return ChangeRate(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // By default we can seek forwards
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CSourcePosition::CanSeekForward(__out LONG *pCanSeekForward) | ||
|  | { | ||
|  |     CheckPointer(pCanSeekForward,E_POINTER); | ||
|  |     *pCanSeekForward = OATRUE; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // By default we can seek backwards
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CSourcePosition::CanSeekBackward(__out LONG *pCanSeekBackward) | ||
|  | { | ||
|  |     CheckPointer(pCanSeekBackward,E_POINTER); | ||
|  |     *pCanSeekBackward = OATRUE; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- Implementation of CBasicAudio class ----------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | CBasicAudio::CBasicAudio(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : | ||
|  |     CUnknown(pName, punk) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | // overriden to publicise our interfaces
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBasicAudio::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) | ||
|  | { | ||
|  |     ValidateReadWritePtr(ppv,sizeof(PVOID)); | ||
|  |     if (riid == IID_IBasicAudio) { | ||
|  | 	return GetInterface( (IBasicAudio *) this, ppv); | ||
|  |     } else { | ||
|  | 	return CUnknown::NonDelegatingQueryInterface(riid, ppv); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBasicAudio::GetTypeInfoCount(__out UINT * pctinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfoCount(pctinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBasicAudio::GetTypeInfo( | ||
|  |   UINT itinfo, | ||
|  |   LCID lcid, | ||
|  |   __deref_out ITypeInfo ** pptinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfo( | ||
|  | 		IID_IBasicAudio, | ||
|  | 		itinfo, | ||
|  | 		lcid, | ||
|  | 		pptinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBasicAudio::GetIDsOfNames( | ||
|  |   REFIID riid, | ||
|  |   __in_ecount(cNames) LPOLESTR * rgszNames, | ||
|  |   UINT cNames, | ||
|  |   LCID lcid, | ||
|  |   __out_ecount(cNames) DISPID * rgdispid) | ||
|  | { | ||
|  |     return m_basedisp.GetIDsOfNames( | ||
|  | 			IID_IBasicAudio, | ||
|  | 			rgszNames, | ||
|  | 			cNames, | ||
|  | 			lcid, | ||
|  | 			rgdispid); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBasicAudio::Invoke( | ||
|  |   DISPID dispidMember, | ||
|  |   REFIID riid, | ||
|  |   LCID lcid, | ||
|  |   WORD wFlags, | ||
|  |   __in DISPPARAMS * pdispparams, | ||
|  |   __out_opt VARIANT * pvarResult, | ||
|  |   __out_opt EXCEPINFO * pexcepinfo, | ||
|  |   __out_opt UINT * puArgErr) | ||
|  | { | ||
|  |     // this parameter is a dead leftover from an earlier interface
 | ||
|  |     if (IID_NULL != riid) { | ||
|  | 	return DISP_E_UNKNOWNINTERFACE; | ||
|  |     } | ||
|  | 
 | ||
|  |     ITypeInfo * pti; | ||
|  |     HRESULT hr = GetTypeInfo(0, lcid, &pti); | ||
|  | 
 | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pti->Invoke( | ||
|  | 	    (IBasicAudio *)this, | ||
|  | 	    dispidMember, | ||
|  | 	    wFlags, | ||
|  | 	    pdispparams, | ||
|  | 	    pvarResult, | ||
|  | 	    pexcepinfo, | ||
|  | 	    puArgErr); | ||
|  | 
 | ||
|  |     pti->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- IVideoWindow implementation ----------
 | ||
|  | 
 | ||
|  | CBaseVideoWindow::CBaseVideoWindow(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : | ||
|  |     CUnknown(pName, punk) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // overriden to publicise our interfaces
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) | ||
|  | { | ||
|  |     ValidateReadWritePtr(ppv,sizeof(PVOID)); | ||
|  |     if (riid == IID_IVideoWindow) { | ||
|  | 	return GetInterface( (IVideoWindow *) this, ppv); | ||
|  |     } else { | ||
|  | 	return CUnknown::NonDelegatingQueryInterface(riid, ppv); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseVideoWindow::GetTypeInfoCount(__out UINT * pctinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfoCount(pctinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseVideoWindow::GetTypeInfo( | ||
|  |   UINT itinfo, | ||
|  |   LCID lcid, | ||
|  |   __deref_out ITypeInfo ** pptinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfo( | ||
|  | 		IID_IVideoWindow, | ||
|  | 		itinfo, | ||
|  | 		lcid, | ||
|  | 		pptinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseVideoWindow::GetIDsOfNames( | ||
|  |   REFIID riid, | ||
|  |   __in_ecount(cNames) LPOLESTR * rgszNames, | ||
|  |   UINT cNames, | ||
|  |   LCID lcid, | ||
|  |   __out_ecount(cNames) DISPID * rgdispid) | ||
|  | { | ||
|  |     return m_basedisp.GetIDsOfNames( | ||
|  | 			IID_IVideoWindow, | ||
|  | 			rgszNames, | ||
|  | 			cNames, | ||
|  | 			lcid, | ||
|  | 			rgdispid); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseVideoWindow::Invoke( | ||
|  |   DISPID dispidMember, | ||
|  |   REFIID riid, | ||
|  |   LCID lcid, | ||
|  |   WORD wFlags, | ||
|  |   __in DISPPARAMS * pdispparams, | ||
|  |   __out_opt VARIANT * pvarResult, | ||
|  |   __out_opt EXCEPINFO * pexcepinfo, | ||
|  |   __out_opt UINT * puArgErr) | ||
|  | { | ||
|  |     // this parameter is a dead leftover from an earlier interface
 | ||
|  |     if (IID_NULL != riid) { | ||
|  | 	return DISP_E_UNKNOWNINTERFACE; | ||
|  |     } | ||
|  | 
 | ||
|  |     ITypeInfo * pti; | ||
|  |     HRESULT hr = GetTypeInfo(0, lcid, &pti); | ||
|  | 
 | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pti->Invoke( | ||
|  | 	    (IVideoWindow *)this, | ||
|  | 	    dispidMember, | ||
|  | 	    wFlags, | ||
|  | 	    pdispparams, | ||
|  | 	    pvarResult, | ||
|  | 	    pexcepinfo, | ||
|  | 	    puArgErr); | ||
|  | 
 | ||
|  |     pti->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- IBasicVideo implementation ----------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | CBaseBasicVideo::CBaseBasicVideo(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) : | ||
|  |     CUnknown(pName, punk) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // overriden to publicise our interfaces
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv) | ||
|  | { | ||
|  |     ValidateReadWritePtr(ppv,sizeof(PVOID)); | ||
|  |     if (riid == IID_IBasicVideo || riid == IID_IBasicVideo2) { | ||
|  | 	return GetInterface( static_cast<IBasicVideo2 *>(this), ppv); | ||
|  |     } else { | ||
|  | 	return CUnknown::NonDelegatingQueryInterface(riid, ppv); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseBasicVideo::GetTypeInfoCount(__out UINT * pctinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfoCount(pctinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseBasicVideo::GetTypeInfo( | ||
|  |   UINT itinfo, | ||
|  |   LCID lcid, | ||
|  |   __deref_out ITypeInfo ** pptinfo) | ||
|  | { | ||
|  |     return m_basedisp.GetTypeInfo( | ||
|  | 		IID_IBasicVideo, | ||
|  | 		itinfo, | ||
|  | 		lcid, | ||
|  | 		pptinfo); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseBasicVideo::GetIDsOfNames( | ||
|  |   REFIID riid, | ||
|  |   __in_ecount(cNames) LPOLESTR * rgszNames, | ||
|  |   UINT cNames, | ||
|  |   LCID lcid, | ||
|  |   __out_ecount(cNames) DISPID * rgdispid) | ||
|  | { | ||
|  |     return m_basedisp.GetIDsOfNames( | ||
|  | 			IID_IBasicVideo, | ||
|  | 			rgszNames, | ||
|  | 			cNames, | ||
|  | 			lcid, | ||
|  | 			rgdispid); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CBaseBasicVideo::Invoke( | ||
|  |   DISPID dispidMember, | ||
|  |   REFIID riid, | ||
|  |   LCID lcid, | ||
|  |   WORD wFlags, | ||
|  |   __in DISPPARAMS * pdispparams, | ||
|  |   __out_opt VARIANT * pvarResult, | ||
|  |   __out_opt EXCEPINFO * pexcepinfo, | ||
|  |   __out_opt UINT * puArgErr) | ||
|  | { | ||
|  |     // this parameter is a dead leftover from an earlier interface
 | ||
|  |     if (IID_NULL != riid) { | ||
|  | 	return DISP_E_UNKNOWNINTERFACE; | ||
|  |     } | ||
|  | 
 | ||
|  |     ITypeInfo * pti; | ||
|  |     HRESULT hr = GetTypeInfo(0, lcid, &pti); | ||
|  | 
 | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     hr = pti->Invoke( | ||
|  | 	    (IBasicVideo *)this, | ||
|  | 	    dispidMember, | ||
|  | 	    wFlags, | ||
|  | 	    pdispparams, | ||
|  | 	    pvarResult, | ||
|  | 	    pexcepinfo, | ||
|  | 	    puArgErr); | ||
|  | 
 | ||
|  |     pti->Release(); | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- Implementation of Deferred Commands ----------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | CDispParams::CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr) | ||
|  | { | ||
|  |    cNamedArgs = 0; | ||
|  |    rgdispidNamedArgs = NULL; | ||
|  |    cArgs = nArgs; | ||
|  | 
 | ||
|  |     if (cArgs) { | ||
|  | 	rgvarg = new VARIANT[cArgs]; | ||
|  |         if (NULL == rgvarg) { | ||
|  |             cArgs = 0; | ||
|  |             if (phr) { | ||
|  |                 *phr = E_OUTOFMEMORY; | ||
|  |             } | ||
|  |             return; | ||
|  |         } | ||
|  | 
 | ||
|  | 	for (UINT i = 0; i < cArgs; i++) { | ||
|  | 
 | ||
|  |             //  Why aren't we using VariantCopy?
 | ||
|  | 
 | ||
|  | 	    VARIANT * pDest = &rgvarg[i]; | ||
|  | 	    VARIANT * pSrc = &pArgs[i]; | ||
|  | 
 | ||
|  | 	    pDest->vt = pSrc->vt; | ||
|  | 	    switch(pDest->vt) { | ||
|  | 
 | ||
|  | 	    case VT_I4: | ||
|  | 		pDest->lVal = pSrc->lVal; | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    case VT_UI1: | ||
|  | 		pDest->bVal = pSrc->bVal; | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    case VT_I2: | ||
|  | 		pDest->iVal = pSrc->iVal; | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    case VT_R4: | ||
|  | 		pDest->fltVal = pSrc->fltVal; | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    case VT_R8: | ||
|  | 		pDest->dblVal = pSrc->dblVal; | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    case VT_BOOL: | ||
|  | 		pDest->boolVal = pSrc->boolVal; | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    case VT_ERROR: | ||
|  | 		pDest->scode = pSrc->scode; | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    case VT_CY: | ||
|  | 		pDest->cyVal = pSrc->cyVal; | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    case VT_DATE: | ||
|  | 		pDest->date = pSrc->date; | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    case VT_BSTR: | ||
|  | 		if ((PVOID)pSrc->bstrVal == NULL) { | ||
|  | 		    pDest->bstrVal = NULL; | ||
|  | 		} else { | ||
|  | 
 | ||
|  | 		    // a BSTR is a WORD followed by a UNICODE string.
 | ||
|  | 		    // the pointer points just after the WORD
 | ||
|  | 
 | ||
|  | 		    WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR))); | ||
|  | 		    OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))]; | ||
|  |                     if (pch) { | ||
|  |         		WORD *pui = (WORD*)pch; | ||
|  |         		*pui = len; | ||
|  |          	        pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR)); | ||
|  |          		CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR)); | ||
|  |                     } else { | ||
|  |                         cArgs = i; | ||
|  |                         if (phr) { | ||
|  |                             *phr = E_OUTOFMEMORY; | ||
|  |                         } | ||
|  |                     } | ||
|  | 		} | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    case VT_UNKNOWN: | ||
|  | 		pDest->punkVal = pSrc->punkVal; | ||
|  | 		pDest->punkVal->AddRef(); | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    case VT_DISPATCH: | ||
|  | 		pDest->pdispVal = pSrc->pdispVal; | ||
|  | 		pDest->pdispVal->AddRef(); | ||
|  | 		break; | ||
|  | 
 | ||
|  | 	    default: | ||
|  | 		// a type we haven't got round to adding yet!
 | ||
|  | 		ASSERT(0); | ||
|  | 		break; | ||
|  | 	    } | ||
|  | 	} | ||
|  | 
 | ||
|  |     } else { | ||
|  | 	rgvarg = NULL; | ||
|  |     } | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | CDispParams::~CDispParams() | ||
|  | { | ||
|  |     for (UINT i = 0; i < cArgs; i++) { | ||
|  | 	switch(rgvarg[i].vt) { | ||
|  |         case VT_BSTR: | ||
|  |             //  Explicitly cast BSTR to PVOID to tell code scanning tools we really mean to test the pointer
 | ||
|  | 	    if ((PVOID)rgvarg[i].bstrVal != NULL) { | ||
|  | 		OLECHAR * pch = rgvarg[i].bstrVal - (sizeof(WORD)/sizeof(OLECHAR)); | ||
|  | 		delete pch; | ||
|  | 	    } | ||
|  | 	    break; | ||
|  | 
 | ||
|  | 	case VT_UNKNOWN: | ||
|  | 	    rgvarg[i].punkVal->Release(); | ||
|  | 	    break; | ||
|  | 
 | ||
|  | 	case VT_DISPATCH: | ||
|  | 	    rgvarg[i].pdispVal->Release(); | ||
|  | 	    break; | ||
|  | 	} | ||
|  |     } | ||
|  |     delete[] rgvarg; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // lifetime is controlled by refcounts (see defer.h)
 | ||
|  | 
 | ||
|  | CDeferredCommand::CDeferredCommand( | ||
|  |     __inout CCmdQueue * pQ, | ||
|  |     __in_opt LPUNKNOWN	pUnk, | ||
|  |     __inout HRESULT *	phr, | ||
|  |     __in LPUNKNOWN	pUnkExecutor, | ||
|  |     REFTIME	time, | ||
|  |     __in GUID*	iid, | ||
|  |     long	dispidMethod, | ||
|  |     short	wFlags, | ||
|  |     long	nArgs, | ||
|  |     __in_ecount(nArgs) VARIANT*	pDispParams, | ||
|  |     __out VARIANT*	pvarResult, | ||
|  |     __out short*	puArgErr, | ||
|  |     BOOL	bStream | ||
|  |     ) : | ||
|  | 	CUnknown(NAME("DeferredCommand"), pUnk), | ||
|  | 	m_pQueue(pQ), | ||
|  | 	m_pUnk(pUnkExecutor), | ||
|  | 	m_iid(iid), | ||
|  | 	m_dispidMethod(dispidMethod), | ||
|  | 	m_wFlags(wFlags), | ||
|  | 	m_DispParams(nArgs, pDispParams, phr), | ||
|  | 	m_pvarResult(pvarResult), | ||
|  | 	m_bStream(bStream), | ||
|  | 	m_hrResult(E_ABORT) | ||
|  | 
 | ||
|  | { | ||
|  |     // convert REFTIME to REFERENCE_TIME
 | ||
|  |     COARefTime convertor(time); | ||
|  |     m_time = convertor; | ||
|  | 
 | ||
|  |     // no check of time validity - it's ok to queue a command that's
 | ||
|  |     // already late
 | ||
|  | 
 | ||
|  |     // check iid is supportable on pUnk by QueryInterface for it
 | ||
|  |     IUnknown * pInterface; | ||
|  |     HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	*phr = hr; | ||
|  | 	return; | ||
|  |     } | ||
|  |     pInterface->Release(); | ||
|  | 
 | ||
|  | 
 | ||
|  |     // !!! check dispidMethod and param/return types using typelib
 | ||
|  |     ITypeInfo *pti; | ||
|  |     hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	*phr = hr; | ||
|  | 	return; | ||
|  |     } | ||
|  |     // !!! some sort of ITypeInfo validity check here
 | ||
|  |     pti->Release(); | ||
|  | 
 | ||
|  | 
 | ||
|  |     // Fix up the dispid for put and get
 | ||
|  |     if (wFlags == DISPATCH_PROPERTYPUT) { | ||
|  |         m_DispParams.cNamedArgs = 1; | ||
|  |         m_DispId = DISPID_PROPERTYPUT; | ||
|  |         m_DispParams.rgdispidNamedArgs = &m_DispId; | ||
|  |     } | ||
|  | 
 | ||
|  |     // all checks ok - add to queue
 | ||
|  |     hr = pQ->Insert(this); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	*phr = hr; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // refcounts are held by caller of InvokeAt... and by list. So if
 | ||
|  | // we get here, we can't be on the list
 | ||
|  | 
 | ||
|  | #if 0
 | ||
|  | CDeferredCommand::~CDeferredCommand() | ||
|  | { | ||
|  |     // this assert is invalid since if the queue is deleted while we are
 | ||
|  |     // still on the queue, we will have been removed by the queue and this
 | ||
|  |     // m_pQueue will not have been modified.
 | ||
|  |     // ASSERT(m_pQueue == NULL);
 | ||
|  | 
 | ||
|  |     // we don't hold a ref count on pUnk, which is the object that should
 | ||
|  |     // execute the command.
 | ||
|  |     // This is because there would otherwise be a circular refcount problem
 | ||
|  |     // since pUnk probably owns the CmdQueue object that has a refcount
 | ||
|  |     // on us.
 | ||
|  |     // The lifetime of pUnk is guaranteed by it being part of, or lifetime
 | ||
|  |     // controlled by, our parent object. As long as we are on the list, pUnk
 | ||
|  |     // must be valid. Once we are off the list, we do not use pUnk.
 | ||
|  | 
 | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 
 | ||
|  | // overriden to publicise our interfaces
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, __out void **ppv) | ||
|  | { | ||
|  |     ValidateReadWritePtr(ppv,sizeof(PVOID)); | ||
|  |     if (riid == IID_IDeferredCommand) { | ||
|  | 	return GetInterface( (IDeferredCommand *) this, ppv); | ||
|  |     } else { | ||
|  | 	return CUnknown::NonDelegatingQueryInterface(riid, ppv); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // remove from q. this will reduce the refcount by one (since the q
 | ||
|  | // holds a count) but can't make us go away since he must have a
 | ||
|  | // refcount in order to call this method.
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CDeferredCommand::Cancel() | ||
|  | { | ||
|  |     if (m_pQueue == NULL) { | ||
|  | 	return VFW_E_ALREADY_CANCELLED; | ||
|  |     } | ||
|  | 
 | ||
|  |     HRESULT hr = m_pQueue->Remove(this); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     m_pQueue = NULL; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CDeferredCommand::Confidence(__out LONG* pConfidence) | ||
|  | { | ||
|  |     return E_NOTIMPL; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CDeferredCommand::GetHResult(__out HRESULT * phrResult) | ||
|  | { | ||
|  |     CheckPointer(phrResult,E_POINTER); | ||
|  |     ValidateReadWritePtr(phrResult,sizeof(HRESULT)); | ||
|  | 
 | ||
|  |     if (m_pQueue != NULL) { | ||
|  | 	return E_ABORT; | ||
|  |     } | ||
|  |     *phrResult = m_hrResult; | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // set the time to be a new time (checking that it is valid) and
 | ||
|  | // then requeue
 | ||
|  | 
 | ||
|  | STDMETHODIMP | ||
|  | CDeferredCommand::Postpone(REFTIME newtime) | ||
|  | { | ||
|  | 
 | ||
|  |     // check that this time is not past
 | ||
|  |     // convert REFTIME to REFERENCE_TIME
 | ||
|  |     COARefTime convertor(newtime); | ||
|  | 
 | ||
|  |     // check that the time has not passed
 | ||
|  |     if (m_pQueue->CheckTime(convertor, IsStreamTime())) { | ||
|  | 	return VFW_E_TIME_ALREADY_PASSED; | ||
|  |     } | ||
|  | 
 | ||
|  |     // extract from list
 | ||
|  |     HRESULT hr = m_pQueue->Remove(this); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     // change time
 | ||
|  |     m_time = convertor; | ||
|  | 
 | ||
|  |     // requeue
 | ||
|  |     hr = m_pQueue->Insert(this); | ||
|  | 
 | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CDeferredCommand::Invoke() | ||
|  | { | ||
|  |     // check that we are still outstanding
 | ||
|  |     if (m_pQueue == NULL) { | ||
|  | 	return VFW_E_ALREADY_CANCELLED; | ||
|  |     } | ||
|  | 
 | ||
|  |     // get the type info
 | ||
|  |     ITypeInfo* pti; | ||
|  |     HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     // qi for the expected interface and then invoke it. Note that we have to
 | ||
|  |     // treat the returned interface as IUnknown since we don't know its type.
 | ||
|  |     IUnknown* pInterface; | ||
|  | 
 | ||
|  |     hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface); | ||
|  |     if (FAILED(hr)) { | ||
|  | 	pti->Release(); | ||
|  | 	return hr; | ||
|  |     } | ||
|  | 
 | ||
|  |     EXCEPINFO expinfo; | ||
|  |     UINT uArgErr; | ||
|  |     m_hrResult = pti->Invoke( | ||
|  | 	pInterface, | ||
|  | 	GetMethod(), | ||
|  | 	GetFlags(), | ||
|  | 	GetParams(), | ||
|  | 	GetResult(), | ||
|  | 	&expinfo, | ||
|  | 	&uArgErr); | ||
|  | 
 | ||
|  |     // release the interface we QI'd for
 | ||
|  |     pInterface->Release(); | ||
|  |     pti->Release(); | ||
|  | 
 | ||
|  | 
 | ||
|  |     // remove from list whether or not successful
 | ||
|  |     // or we loop indefinitely
 | ||
|  |     hr = m_pQueue->Remove(this); | ||
|  |     m_pQueue = NULL; | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- CCmdQueue methods ----------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | CCmdQueue::CCmdQueue(__inout_opt HRESULT *phr) : | ||
|  |     m_listPresentation(NAME("Presentation time command list")), | ||
|  |     m_listStream(NAME("Stream time command list")), | ||
|  |     m_evDue(TRUE, phr),    // manual reset
 | ||
|  |     m_dwAdvise(0), | ||
|  |     m_pClock(NULL), | ||
|  |     m_bRunning(FALSE) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | CCmdQueue::~CCmdQueue() | ||
|  | { | ||
|  |     // empty all our lists
 | ||
|  | 
 | ||
|  |     // we hold a refcount on each, so traverse and Release each
 | ||
|  |     // entry then RemoveAll to empty the list
 | ||
|  |     POSITION pos = m_listPresentation.GetHeadPosition(); | ||
|  | 
 | ||
|  |     while(pos) { | ||
|  | 	CDeferredCommand* pCmd = m_listPresentation.GetNext(pos); | ||
|  | 	pCmd->Release(); | ||
|  |     } | ||
|  |     m_listPresentation.RemoveAll(); | ||
|  | 
 | ||
|  |     pos = m_listStream.GetHeadPosition(); | ||
|  | 
 | ||
|  |     while(pos) { | ||
|  | 	CDeferredCommand* pCmd = m_listStream.GetNext(pos); | ||
|  | 	pCmd->Release(); | ||
|  |     } | ||
|  |     m_listStream.RemoveAll(); | ||
|  | 
 | ||
|  |     if (m_pClock) { | ||
|  | 	if (m_dwAdvise) { | ||
|  | 	    m_pClock->Unadvise(m_dwAdvise); | ||
|  | 	    m_dwAdvise = 0; | ||
|  | 	} | ||
|  | 	m_pClock->Release(); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // 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.
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CCmdQueue::New( | ||
|  |     __out CDeferredCommand **ppCmd, | ||
|  |     __in     LPUNKNOWN	pUnk,		// this object will execute command
 | ||
|  |     REFTIME	time, | ||
|  |     __in GUID*	iid, | ||
|  |     long	dispidMethod, | ||
|  |     short	wFlags, | ||
|  |     long	cArgs, | ||
|  |     __in_ecount(cArgs) VARIANT*	pDispParams, | ||
|  |     __out VARIANT*	pvarResult, | ||
|  |     __out short*	puArgErr, | ||
|  |     BOOL	bStream | ||
|  | ) | ||
|  | { | ||
|  |     CAutoLock lock(&m_Lock); | ||
|  | 
 | ||
|  |     HRESULT hr = S_OK; | ||
|  |     *ppCmd = NULL; | ||
|  | 
 | ||
|  |     CDeferredCommand* pCmd; | ||
|  |     pCmd = new CDeferredCommand( | ||
|  | 		    this, | ||
|  | 		    NULL,	    // not aggregated
 | ||
|  | 		    &hr, | ||
|  | 		    pUnk,	    // this guy will execute
 | ||
|  | 		    time, | ||
|  | 		    iid, | ||
|  | 		    dispidMethod, | ||
|  | 		    wFlags, | ||
|  | 		    cArgs, | ||
|  | 		    pDispParams, | ||
|  | 		    pvarResult, | ||
|  | 		    puArgErr, | ||
|  | 		    bStream); | ||
|  | 
 | ||
|  |     if (pCmd == NULL) { | ||
|  | 	hr = E_OUTOFMEMORY; | ||
|  |     } else { | ||
|  | 	*ppCmd = pCmd; | ||
|  |     } | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CCmdQueue::Insert(__in CDeferredCommand* pCmd) | ||
|  | { | ||
|  |     CAutoLock lock(&m_Lock); | ||
|  | 
 | ||
|  |     // addref the item
 | ||
|  |     pCmd->AddRef(); | ||
|  | 
 | ||
|  |     CGenericList<CDeferredCommand> * pList; | ||
|  |     if (pCmd->IsStreamTime()) { | ||
|  | 	pList = &m_listStream; | ||
|  |     } else { | ||
|  | 	pList = &m_listPresentation; | ||
|  |     } | ||
|  |     POSITION pos = pList->GetHeadPosition(); | ||
|  | 
 | ||
|  |     // seek past all items that are before us
 | ||
|  |     while (pos && | ||
|  | 	(pList->GetValid(pos)->GetTime() <= pCmd->GetTime())) { | ||
|  | 
 | ||
|  | 	pList->GetNext(pos); | ||
|  |     } | ||
|  | 
 | ||
|  |     // now at end of list or in front of items that come later
 | ||
|  |     if (!pos) { | ||
|  | 	pList->AddTail(pCmd); | ||
|  |     } else { | ||
|  | 	pList->AddBefore(pos, pCmd); | ||
|  |     } | ||
|  | 
 | ||
|  |     SetTimeAdvise(); | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CCmdQueue::Remove(__in CDeferredCommand* pCmd) | ||
|  | { | ||
|  |     CAutoLock lock(&m_Lock); | ||
|  |     HRESULT hr = S_OK; | ||
|  | 
 | ||
|  |     CGenericList<CDeferredCommand> * pList; | ||
|  |     if (pCmd->IsStreamTime()) { | ||
|  | 	pList = &m_listStream; | ||
|  |     } else { | ||
|  | 	pList = &m_listPresentation; | ||
|  |     } | ||
|  |     POSITION pos = pList->GetHeadPosition(); | ||
|  | 
 | ||
|  |     // traverse the list
 | ||
|  |     while (pos && (pList->GetValid(pos) != pCmd)) { | ||
|  | 	pList->GetNext(pos); | ||
|  |     } | ||
|  | 
 | ||
|  |     // did we drop off the end?
 | ||
|  |     if (!pos) { | ||
|  | 	hr = VFW_E_NOT_FOUND; | ||
|  |     } else { | ||
|  | 
 | ||
|  | 	// found it - now take off list
 | ||
|  | 	pList->Remove(pos); | ||
|  | 
 | ||
|  | 	// Insert did an AddRef, so release it
 | ||
|  | 	pCmd->Release(); | ||
|  | 
 | ||
|  | 	// check that timer request is still for earliest time
 | ||
|  | 	SetTimeAdvise(); | ||
|  |     } | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // set the clock used for timing
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CCmdQueue::SetSyncSource(__in_opt IReferenceClock* pClock) | ||
|  | { | ||
|  |     CAutoLock lock(&m_Lock); | ||
|  | 
 | ||
|  |     // addref the new clock first in case they are the same
 | ||
|  |     if (pClock) { | ||
|  | 	pClock->AddRef(); | ||
|  |     } | ||
|  | 
 | ||
|  |     // kill any advise on the old clock
 | ||
|  |     if (m_pClock) { | ||
|  | 	if (m_dwAdvise) { | ||
|  | 	    m_pClock->Unadvise(m_dwAdvise); | ||
|  | 	    m_dwAdvise = 0; | ||
|  | 	} | ||
|  | 	m_pClock->Release(); | ||
|  |     } | ||
|  |     m_pClock = pClock; | ||
|  | 
 | ||
|  |     // set up a new advise
 | ||
|  |     SetTimeAdvise(); | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // set up a timer event with the reference clock
 | ||
|  | 
 | ||
|  | void | ||
|  | CCmdQueue::SetTimeAdvise(void) | ||
|  | { | ||
|  |     // make sure we have a clock to use
 | ||
|  |     if (!m_pClock) { | ||
|  | 	return; | ||
|  |     } | ||
|  | 
 | ||
|  |     // reset the event whenever we are requesting a new signal
 | ||
|  |     m_evDue.Reset(); | ||
|  | 
 | ||
|  |     // time 0 is earliest
 | ||
|  |     CRefTime current; | ||
|  | 
 | ||
|  |     // find the earliest presentation time
 | ||
|  |     POSITION pos = m_listPresentation.GetHeadPosition(); | ||
|  |     if (pos != NULL) { | ||
|  | 	current = m_listPresentation.GetValid(pos)->GetTime(); | ||
|  |     } | ||
|  | 
 | ||
|  |     // if we're running, check the stream times too
 | ||
|  |     if (m_bRunning) { | ||
|  | 
 | ||
|  | 	CRefTime t; | ||
|  |         pos = m_listStream.GetHeadPosition(); | ||
|  | 	if (NULL != pos) { | ||
|  | 	    t = m_listStream.GetValid(pos)->GetTime(); | ||
|  | 
 | ||
|  | 	    // add on stream time offset to get presentation time
 | ||
|  | 	    t += m_StreamTimeOffset; | ||
|  | 
 | ||
|  | 	    // is this earlier?
 | ||
|  | 	    if ((current == TimeZero) || (t < current)) { | ||
|  | 		current = t; | ||
|  | 	    } | ||
|  | 	} | ||
|  |     } | ||
|  | 
 | ||
|  |     // need to change?
 | ||
|  |     if ((current > TimeZero) && (current != m_tCurrentAdvise)) { | ||
|  | 	if (m_dwAdvise) { | ||
|  | 	    m_pClock->Unadvise(m_dwAdvise); | ||
|  | 	    // reset the event whenever we are requesting a new signal
 | ||
|  | 	    m_evDue.Reset(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// ask for time advice - the first two params are either
 | ||
|  | 	// stream time offset and stream time or
 | ||
|  | 	// presentation time and 0. we always use the latter
 | ||
|  | 	HRESULT hr = m_pClock->AdviseTime( | ||
|  | 		    (REFERENCE_TIME)current, | ||
|  | 		    TimeZero, | ||
|  | 		    (HEVENT) HANDLE(m_evDue), | ||
|  | 		    &m_dwAdvise); | ||
|  | 
 | ||
|  | 	ASSERT(SUCCEEDED(hr)); | ||
|  | 	m_tCurrentAdvise = current; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // switch to run mode. Streamtime to Presentation time mapping known.
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset) | ||
|  | { | ||
|  |     CAutoLock lock(&m_Lock); | ||
|  | 
 | ||
|  |     m_StreamTimeOffset = tStreamTimeOffset; | ||
|  |     m_bRunning = TRUE; | ||
|  | 
 | ||
|  |     // ensure advise is accurate
 | ||
|  |     SetTimeAdvise(); | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // switch to Stopped or Paused mode. Time mapping not known.
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CCmdQueue::EndRun() | ||
|  | { | ||
|  |     CAutoLock lock(&m_Lock); | ||
|  | 
 | ||
|  |     m_bRunning = FALSE; | ||
|  | 
 | ||
|  |     // check timer setting - stream times
 | ||
|  |     SetTimeAdvise(); | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // 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'd object
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CCmdQueue::GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout) | ||
|  | { | ||
|  |     // loop until we timeout or find a due command
 | ||
|  |     for (;;) { | ||
|  | 
 | ||
|  | 	{ | ||
|  | 	    CAutoLock lock(&m_Lock); | ||
|  | 
 | ||
|  | 
 | ||
|  | 	    // find the earliest command
 | ||
|  | 	    CDeferredCommand * pCmd = NULL; | ||
|  | 
 | ||
|  | 	    // check the presentation time and the
 | ||
|  | 	    // stream time list to find the earliest
 | ||
|  | 
 | ||
|  |             POSITION pos = m_listPresentation.GetHeadPosition(); | ||
|  | 
 | ||
|  | 	    if (NULL != pos) { | ||
|  | 		pCmd = m_listPresentation.GetValid(pos); | ||
|  | 	    } | ||
|  | 
 | ||
|  | 	    if (m_bRunning) { | ||
|  | 		pos = m_listStream.GetHeadPosition(); | ||
|  |                 if (NULL != pos) { | ||
|  |                     CDeferredCommand* pStrm = m_listStream.GetValid(pos); | ||
|  | 
 | ||
|  |                     CRefTime t = pStrm->GetTime() + m_StreamTimeOffset; | ||
|  |                     if (!pCmd || (t < pCmd->GetTime())) { | ||
|  |                         pCmd = pStrm; | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  | 	    //	if we have found one, is it due?
 | ||
|  | 	    if (pCmd) { | ||
|  | 		if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) { | ||
|  | 
 | ||
|  | 		    // yes it's due - addref it
 | ||
|  | 		    pCmd->AddRef(); | ||
|  | 		    *ppCmd = pCmd; | ||
|  | 		    return S_OK; | ||
|  | 		} | ||
|  | 	    } | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// block until the advise is signalled
 | ||
|  | 	if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) { | ||
|  | 	    return E_ABORT; | ||
|  | 	} | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // 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 E_ABORT if there are no
 | ||
|  | // commands due yet.
 | ||
|  | //
 | ||
|  | // returns an AddRef'd object
 | ||
|  | 
 | ||
|  | HRESULT | ||
|  | CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, __out CDeferredCommand**ppCmd) | ||
|  | { | ||
|  |     CAutoLock lock(&m_Lock); | ||
|  | 
 | ||
|  |     CRefTime tStream(rtStream); | ||
|  | 
 | ||
|  |     // find the earliest stream and presentation time commands
 | ||
|  |     CDeferredCommand* pStream = NULL; | ||
|  |     POSITION pos = m_listStream.GetHeadPosition(); | ||
|  |     if (NULL != pos) { | ||
|  | 	pStream = m_listStream.GetValid(pos); | ||
|  |     } | ||
|  |     CDeferredCommand* pPresent = NULL; | ||
|  |     pos = m_listPresentation.GetHeadPosition(); | ||
|  |     if (NULL != pos) { | ||
|  | 	pPresent = m_listPresentation.GetValid(pos); | ||
|  |     } | ||
|  | 
 | ||
|  |     // is there a presentation time that has passed already
 | ||
|  |     if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) { | ||
|  | 	pPresent->AddRef(); | ||
|  | 	*ppCmd = pPresent; | ||
|  | 	return S_OK; | ||
|  |     } | ||
|  | 
 | ||
|  |     // is there a stream time command due before this stream time
 | ||
|  |     if (pStream && (pStream->GetTime() <= tStream)) { | ||
|  | 	pStream->AddRef(); | ||
|  | 	*ppCmd = pStream; | ||
|  | 	return S_OK; | ||
|  |     } | ||
|  | 
 | ||
|  |     // if we are running, we can map presentation times to
 | ||
|  |     // stream time. In this case, is there a presentation time command
 | ||
|  |     // that will be due before this stream time is presented?
 | ||
|  |     if (m_bRunning && pPresent) { | ||
|  | 
 | ||
|  | 	// this stream time will appear at...
 | ||
|  | 	tStream += m_StreamTimeOffset; | ||
|  | 
 | ||
|  | 	// due before that?
 | ||
|  | 	if (pPresent->GetTime() <= tStream) { | ||
|  | 	    *ppCmd = pPresent; | ||
|  | 	    return S_OK; | ||
|  | 	} | ||
|  |     } | ||
|  | 
 | ||
|  |     // no commands due yet
 | ||
|  |     return VFW_E_NOT_FOUND; | ||
|  | } | ||
|  | 
 |