Reactos
at listview 374 lines 8.6 kB view raw
1/* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy 4 * FILE: dll/directx/ksproxy/clockforward.cpp 5 * PURPOSE: IKsClockForwarder interface 6 * 7 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) 8 */ 9#include "precomp.h" 10 11const GUID IID_IKsClockForwarder = {0x877e4352, 0x6fea, 0x11d0, {0xb8, 0x63, 0x00, 0xaa, 0x00, 0xa2, 0x16, 0xa1}}; 12 13DWORD WINAPI CKsClockForwarder_ThreadStartup(LPVOID lpParameter); 14 15class CKsClockForwarder : public IDistributorNotify, 16 public IKsObject 17{ 18public: 19 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); 20 21 STDMETHODIMP_(ULONG) AddRef() 22 { 23 InterlockedIncrement(&m_Ref); 24 return m_Ref; 25 } 26 STDMETHODIMP_(ULONG) Release() 27 { 28 InterlockedDecrement(&m_Ref); 29 30 if (!m_Ref) 31 { 32 delete this; 33 return 0; 34 } 35 return m_Ref; 36 } 37 38 // IDistributorNotify interface 39 HRESULT STDMETHODCALLTYPE Stop(); 40 HRESULT STDMETHODCALLTYPE Pause(); 41 HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart); 42 HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock); 43 HRESULT STDMETHODCALLTYPE NotifyGraphChange(); 44 45 // IKsObject interface 46 HANDLE STDMETHODCALLTYPE KsGetObjectHandle(); 47 48 CKsClockForwarder(HANDLE handle); 49 virtual ~CKsClockForwarder(){}; 50 HRESULT STDMETHODCALLTYPE SetClockState(KSSTATE State); 51protected: 52 LONG m_Ref; 53 HANDLE m_Handle; 54 IReferenceClock * m_Clock; 55 HANDLE m_hEvent; 56 HANDLE m_hThread; 57 BOOL m_ThreadStarted; 58 BOOL m_PendingStop; 59 BOOL m_ForceStart; 60 KSSTATE m_State; 61 REFERENCE_TIME m_Time; 62 63 friend DWORD WINAPI CKsClockForwarder_ThreadStartup(LPVOID lpParameter); 64}; 65 66CKsClockForwarder::CKsClockForwarder( 67 HANDLE handle) : m_Ref(0), 68 m_Handle(handle), 69 m_Clock(0), 70 m_hEvent(NULL), 71 m_hThread(NULL), 72 m_ThreadStarted(FALSE), 73 m_PendingStop(FALSE), 74 m_ForceStart(FALSE), 75 m_State(KSSTATE_STOP), 76 m_Time(0) 77{ 78} 79 80HRESULT 81STDMETHODCALLTYPE 82CKsClockForwarder::QueryInterface( 83 IN REFIID refiid, 84 OUT PVOID* Output) 85{ 86 if (IsEqualGUID(refiid, IID_IUnknown)) 87 { 88 *Output = PVOID(this); 89 reinterpret_cast<IUnknown*>(*Output)->AddRef(); 90 return NOERROR; 91 } 92 if (IsEqualGUID(refiid, IID_IKsObject) || 93 IsEqualGUID(refiid, IID_IKsClockForwarder)) 94 { 95 *Output = (IKsObject*)(this); 96 reinterpret_cast<IKsObject*>(*Output)->AddRef(); 97 return NOERROR; 98 } 99 100 if (IsEqualGUID(refiid, IID_IDistributorNotify)) 101 { 102 *Output = (IDistributorNotify*)(this); 103 reinterpret_cast<IDistributorNotify*>(*Output)->AddRef(); 104 return NOERROR; 105 } 106 107 return E_NOINTERFACE; 108} 109 110//------------------------------------------------------------------- 111// IDistributorNotify interface 112// 113 114 115HRESULT 116STDMETHODCALLTYPE 117CKsClockForwarder::Stop() 118{ 119#ifdef KSPROXY_TRACE 120 WCHAR Buffer[200]; 121 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); 122 OutputDebugStringW(Buffer); 123#endif 124 125 m_Time = 0; 126 if (m_ThreadStarted) 127 { 128 // signal pending stop 129 m_PendingStop = true; 130 131 assert(m_hThread); 132 assert(m_hEvent); 133 134 // set stop event 135 SetEvent(m_hEvent); 136 137 // wait untill the thread has finished 138 WaitForSingleObject(m_hThread, INFINITE); 139 140 // close thread handle 141 CloseHandle(m_hThread); 142 143 // zero handle 144 m_hThread = NULL; 145 } 146 147 if (m_hEvent) 148 { 149 // close stop event 150 CloseHandle(m_hEvent); 151 m_hEvent = NULL; 152 } 153 154 m_PendingStop = false; 155 156 SetClockState(KSSTATE_STOP); 157 return NOERROR; 158} 159 160HRESULT 161STDMETHODCALLTYPE 162CKsClockForwarder::Pause() 163{ 164#ifdef KSPROXY_TRACE 165 OutputDebugString("CKsClockForwarder::Pause\n"); 166#endif 167 168 if (!m_hEvent) 169 { 170 m_hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); 171 if (!m_hEvent) 172 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); 173 } 174 175 if (m_State <= KSSTATE_PAUSE) 176 { 177 if (m_State == KSSTATE_STOP) 178 SetClockState(KSSTATE_ACQUIRE); 179 180 if (m_State == KSSTATE_ACQUIRE) 181 SetClockState(KSSTATE_PAUSE); 182 } 183 else 184 { 185 if (!m_ForceStart) 186 { 187 SetClockState(KSSTATE_PAUSE); 188 } 189 } 190 191 if (!m_hThread) 192 { 193 m_hThread = CreateThread(NULL, 0, CKsClockForwarder_ThreadStartup, (LPVOID)this, 0, NULL); 194 if (!m_hThread) 195 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError()); 196 } 197 198 return NOERROR; 199} 200 201HRESULT 202STDMETHODCALLTYPE 203CKsClockForwarder::Run( 204 REFERENCE_TIME tStart) 205{ 206#ifdef KSPROXY_TRACE 207 OutputDebugString("CKsClockForwarder::Run\n"); 208#endif 209 210 m_Time = tStart; 211 212 if (!m_hEvent || !m_hThread) 213 { 214 m_ForceStart = TRUE; 215 HRESULT hr = Pause(); 216 m_ForceStart = FALSE; 217 218 if (FAILED(hr)) 219 return hr; 220 } 221 222 assert(m_hThread); 223 224 SetClockState(KSSTATE_RUN); 225 SetEvent(m_hEvent); 226 227 return NOERROR; 228} 229 230HRESULT 231STDMETHODCALLTYPE 232CKsClockForwarder::SetSyncSource( 233 IReferenceClock *pClock) 234{ 235#ifdef KSPROXY_TRACE 236 OutputDebugString("CKsClockForwarder::SetSyncSource\n"); 237#endif 238 239 if (pClock) 240 pClock->AddRef(); 241 242 if (m_Clock) 243 m_Clock->Release(); 244 245 246 m_Clock = pClock; 247 return NOERROR; 248} 249 250HRESULT 251STDMETHODCALLTYPE 252CKsClockForwarder::NotifyGraphChange() 253{ 254#ifdef KSPROXY_TRACE 255 OutputDebugString("CKsClockForwarder::NotifyGraphChange\n"); 256#endif 257 258 return NOERROR; 259} 260 261//------------------------------------------------------------------- 262// IKsObject interface 263// 264 265HANDLE 266STDMETHODCALLTYPE 267CKsClockForwarder::KsGetObjectHandle() 268{ 269 return m_Handle; 270} 271 272//------------------------------------------------------------------- 273HRESULT 274STDMETHODCALLTYPE 275CKsClockForwarder::SetClockState(KSSTATE State) 276{ 277 KSPROPERTY Property; 278 ULONG BytesReturned; 279 280 Property.Set = KSPROPSETID_Clock; 281 Property.Id = KSPROPERTY_CLOCK_STATE; 282 Property.Flags = KSPROPERTY_TYPE_SET; 283 284 HRESULT hr = KsSynchronousDeviceControl(m_Handle, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), &State, sizeof(KSSTATE), &BytesReturned); 285 if (SUCCEEDED(hr)) 286 m_State = State; 287 288#ifdef KSPROXY_TRACE 289 WCHAR Buffer[100]; 290 swprintf(Buffer, L"CKsClockForwarder::SetClockState m_State %u State %u hr %lx\n", m_State, State, hr); 291 OutputDebugStringW(Buffer); 292#endif 293 294 return hr; 295} 296 297DWORD 298WINAPI 299CKsClockForwarder_ThreadStartup(LPVOID lpParameter) 300{ 301 REFERENCE_TIME Time; 302 ULONG BytesReturned; 303 304 CKsClockForwarder * Fwd = (CKsClockForwarder*)lpParameter; 305 306 Fwd->m_ThreadStarted = TRUE; 307 308 do 309 { 310 if (Fwd->m_PendingStop) 311 break; 312 313 if (Fwd->m_State != KSSTATE_RUN) 314 WaitForSingleObject(Fwd->m_hEvent, INFINITE); 315 316 KSPROPERTY Property; 317 Property.Set = KSPROPSETID_Clock; 318 Property.Id = KSPROPERTY_CLOCK_TIME; 319 Property.Flags = KSPROPERTY_TYPE_SET; 320 321 Fwd->m_Clock->GetTime(&Time); 322 Time -= Fwd->m_Time; 323 324 KsSynchronousDeviceControl(Fwd->m_Handle, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), &Time, sizeof(REFERENCE_TIME), &BytesReturned); 325 } 326 while(TRUE); 327 328 Fwd->m_ThreadStarted = FALSE; 329 return NOERROR; 330} 331 332HRESULT 333WINAPI 334CKsClockForwarder_Constructor( 335 IUnknown * pUnkOuter, 336 REFIID riid, 337 LPVOID * ppv) 338{ 339 HRESULT hr; 340 HANDLE handle; 341 342#ifdef KSPROXY_TRACE 343 OutputDebugStringW(L"CKsClockForwarder_Constructor\n"); 344#endif 345 346 // open default clock 347 hr = KsOpenDefaultDevice(KSCATEGORY_CLOCK, GENERIC_READ | GENERIC_WRITE, &handle); 348 349 if (hr != NOERROR) 350 { 351#ifdef KSPROXY_TRACE 352 OutputDebugString("CKsClockForwarder_Constructor failed to open device\n"); 353#endif 354 return hr; 355 } 356 357 CKsClockForwarder * clock = new CKsClockForwarder(handle); 358 359 if (!clock) 360 { 361 // free clock handle 362 CloseHandle(handle); 363 return E_OUTOFMEMORY; 364 } 365 366 if (FAILED(clock->QueryInterface(riid, ppv))) 367 { 368 /* not supported */ 369 delete clock; 370 return E_NOINTERFACE; 371 } 372 373 return NOERROR; 374}