mirror of
https://github.com/reactos/reactos.git
synced 2024-08-27 13:48:42 +00:00
375 lines
8.4 KiB
C++
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;
|
|
}
|