reactos/dll/directx/ksproxy/clockforward.cpp

375 lines
8.4 KiB
C++

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS WDM Streaming ActiveMovie Proxy
* FILE: dll/directx/ksproxy/clockforward.cpp
* PURPOSE: IKsClockForwarder interface
*
* PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#include "precomp.h"
const GUID IID_IKsClockForwarder = {0x877e4352, 0x6fea, 0x11d0, {0xb8, 0x63, 0x00, 0xaa, 0x00, 0xa2, 0x16, 0xa1}};
DWORD WINAPI CKsClockForwarder_ThreadStartup(LPVOID lpParameter);
class CKsClockForwarder : public IDistributorNotify,
public IKsObject
{
public:
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
STDMETHODIMP_(ULONG) AddRef()
{
InterlockedIncrement(&m_Ref);
return m_Ref;
}
STDMETHODIMP_(ULONG) Release()
{
InterlockedDecrement(&m_Ref);
if (!m_Ref)
{
delete this;
return 0;
}
return m_Ref;
}
// IDistributorNotify interface
HRESULT STDMETHODCALLTYPE Stop();
HRESULT STDMETHODCALLTYPE Pause();
HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
HRESULT STDMETHODCALLTYPE NotifyGraphChange();
// IKsObject interface
HANDLE STDMETHODCALLTYPE KsGetObjectHandle();
CKsClockForwarder(HANDLE handle);
virtual ~CKsClockForwarder(){};
HRESULT STDMETHODCALLTYPE SetClockState(KSSTATE State);
protected:
LONG m_Ref;
HANDLE m_Handle;
IReferenceClock * m_Clock;
HANDLE m_hEvent;
HANDLE m_hThread;
BOOL m_ThreadStarted;
BOOL m_PendingStop;
BOOL m_ForceStart;
KSSTATE m_State;
REFERENCE_TIME m_Time;
friend DWORD WINAPI CKsClockForwarder_ThreadStartup(LPVOID lpParameter);
};
CKsClockForwarder::CKsClockForwarder(
HANDLE handle) : m_Ref(0),
m_Handle(handle),
m_Clock(0),
m_hEvent(NULL),
m_hThread(NULL),
m_ThreadStarted(FALSE),
m_PendingStop(FALSE),
m_ForceStart(FALSE),
m_State(KSSTATE_STOP),
m_Time(0)
{
}
HRESULT
STDMETHODCALLTYPE
CKsClockForwarder::QueryInterface(
IN REFIID refiid,
OUT PVOID* Output)
{
if (IsEqualGUID(refiid, IID_IUnknown))
{
*Output = PVOID(this);
reinterpret_cast<IUnknown*>(*Output)->AddRef();
return NOERROR;
}
if (IsEqualGUID(refiid, IID_IKsObject) ||
IsEqualGUID(refiid, IID_IKsClockForwarder))
{
*Output = (IKsObject*)(this);
reinterpret_cast<IKsObject*>(*Output)->AddRef();
return NOERROR;
}
if (IsEqualGUID(refiid, IID_IDistributorNotify))
{
*Output = (IDistributorNotify*)(this);
reinterpret_cast<IDistributorNotify*>(*Output)->AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
//-------------------------------------------------------------------
// IDistributorNotify interface
//
HRESULT
STDMETHODCALLTYPE
CKsClockForwarder::Stop()
{
#ifdef KSPROXY_TRACE
WCHAR Buffer[200];
swprintf(Buffer, L"CKsClockForwarder::Stop m_ThreadStarted %u m_PendingStop %u m_hThread %p m_hEvent %p m_Handle %p\n", m_ThreadStarted, m_PendingStop, m_hThread, m_hEvent, m_Handle);
OutputDebugStringW(Buffer);
#endif
m_Time = 0;
if (m_ThreadStarted)
{
// signal pending stop
m_PendingStop = true;
assert(m_hThread);
assert(m_hEvent);
// set stop event
SetEvent(m_hEvent);
// wait untill the thread has finished
WaitForSingleObject(m_hThread, INFINITE);
// close thread handle
CloseHandle(m_hThread);
// zero handle
m_hThread = NULL;
}
if (m_hEvent)
{
// close stop event
CloseHandle(m_hEvent);
m_hEvent = NULL;
}
m_PendingStop = false;
SetClockState(KSSTATE_STOP);
return NOERROR;
}
HRESULT
STDMETHODCALLTYPE
CKsClockForwarder::Pause()
{
#ifdef KSPROXY_TRACE
OutputDebugString("CKsClockForwarder::Pause\n");
#endif
if (!m_hEvent)
{
m_hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!m_hEvent)
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
}
if (m_State <= KSSTATE_PAUSE)
{
if (m_State == KSSTATE_STOP)
SetClockState(KSSTATE_ACQUIRE);
if (m_State == KSSTATE_ACQUIRE)
SetClockState(KSSTATE_PAUSE);
}
else
{
if (!m_ForceStart)
{
SetClockState(KSSTATE_PAUSE);
}
}
if (!m_hThread)
{
m_hThread = CreateThread(NULL, 0, CKsClockForwarder_ThreadStartup, (LPVOID)this, 0, NULL);
if (!m_hThread)
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
}
return NOERROR;
}
HRESULT
STDMETHODCALLTYPE
CKsClockForwarder::Run(
REFERENCE_TIME tStart)
{
#ifdef KSPROXY_TRACE
OutputDebugString("CKsClockForwarder::Run\n");
#endif
m_Time = tStart;
if (!m_hEvent || !m_hThread)
{
m_ForceStart = TRUE;
HRESULT hr = Pause();
m_ForceStart = FALSE;
if (FAILED(hr))
return hr;
}
assert(m_hThread);
SetClockState(KSSTATE_RUN);
SetEvent(m_hEvent);
return NOERROR;
}
HRESULT
STDMETHODCALLTYPE
CKsClockForwarder::SetSyncSource(
IReferenceClock *pClock)
{
#ifdef KSPROXY_TRACE
OutputDebugString("CKsClockForwarder::SetSyncSource\n");
#endif
if (pClock)
pClock->AddRef();
if (m_Clock)
m_Clock->Release();
m_Clock = pClock;
return NOERROR;
}
HRESULT
STDMETHODCALLTYPE
CKsClockForwarder::NotifyGraphChange()
{
#ifdef KSPROXY_TRACE
OutputDebugString("CKsClockForwarder::NotifyGraphChange\n");
#endif
return NOERROR;
}
//-------------------------------------------------------------------
// IKsObject interface
//
HANDLE
STDMETHODCALLTYPE
CKsClockForwarder::KsGetObjectHandle()
{
return m_Handle;
}
//-------------------------------------------------------------------
HRESULT
STDMETHODCALLTYPE
CKsClockForwarder::SetClockState(KSSTATE State)
{
KSPROPERTY Property;
ULONG BytesReturned;
Property.Set = KSPROPSETID_Clock;
Property.Id = KSPROPERTY_CLOCK_STATE;
Property.Flags = KSPROPERTY_TYPE_SET;
HRESULT hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), &State, sizeof(KSSTATE), &BytesReturned);
if (SUCCEEDED(hr))
m_State = State;
#ifdef KSPROXY_TRACE
WCHAR Buffer[100];
swprintf(Buffer, L"CKsClockForwarder::SetClockState m_State %u State %u hr %lx\n", m_State, State, hr);
OutputDebugStringW(Buffer);
#endif
return hr;
}
DWORD
WINAPI
CKsClockForwarder_ThreadStartup(LPVOID lpParameter)
{
REFERENCE_TIME Time;
ULONG BytesReturned;
CKsClockForwarder * Fwd = (CKsClockForwarder*)lpParameter;
Fwd->m_ThreadStarted = TRUE;
do
{
if (Fwd->m_PendingStop)
break;
if (Fwd->m_State != KSSTATE_RUN)
WaitForSingleObject(Fwd->m_hEvent, INFINITE);
KSPROPERTY Property;
Property.Set = KSPROPSETID_Clock;
Property.Id = KSPROPERTY_CLOCK_TIME;
Property.Flags = KSPROPERTY_TYPE_SET;
Fwd->m_Clock->GetTime(&Time);
Time -= Fwd->m_Time;
KsSynchronousDeviceControl(Fwd->m_Handle, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), &Time, sizeof(REFERENCE_TIME), &BytesReturned);
}
while(TRUE);
Fwd->m_ThreadStarted = FALSE;
return NOERROR;
}
HRESULT
WINAPI
CKsClockForwarder_Constructor(
IUnknown * pUnkOuter,
REFIID riid,
LPVOID * ppv)
{
HRESULT hr;
HANDLE handle;
#ifdef KSPROXY_TRACE
OutputDebugStringW(L"CKsClockForwarder_Constructor\n");
#endif
// open default clock
hr = KsOpenDefaultDevice(KSCATEGORY_CLOCK, GENERIC_READ | GENERIC_WRITE, &handle);
if (hr != NOERROR)
{
#ifdef KSPROXY_TRACE
OutputDebugString("CKsClockForwarder_Constructor failed to open device\n");
#endif
return hr;
}
CKsClockForwarder * clock = new CKsClockForwarder(handle);
if (!clock)
{
// free clock handle
CloseHandle(handle);
return E_OUTOFMEMORY;
}
if (FAILED(clock->QueryInterface(riid, ppv)))
{
/* not supported */
delete clock;
return E_NOINTERFACE;
}
return NOERROR;
}