Implemented SystemClock (IReferenceClock by dshow).
This commit is contained in:
parent
eed647d0ad
commit
0359eaa80c
|
@ -4,7 +4,7 @@ SRCDIR = @srcdir@
|
|||
VPATH = @srcdir@
|
||||
MODULE = quartz.dll
|
||||
IMPORTS = ole32 oleaut32 advapi32 kernel32 user32
|
||||
EXTRALIBS = -luuid $(LIBUNICODE)
|
||||
EXTRALIBS = -ldxguid -luuid $(LIBUNICODE)
|
||||
|
||||
C_SRCS = \
|
||||
avisplit.c \
|
||||
|
@ -20,7 +20,8 @@ C_SRCS = \
|
|||
main.c \
|
||||
memallocator.c \
|
||||
pin.c \
|
||||
regsvr.c
|
||||
regsvr.c \
|
||||
systemclock.c
|
||||
|
||||
RC_SRCS = version.rc
|
||||
|
||||
|
|
|
@ -66,6 +66,8 @@ static const struct object_creation_info object_creation[] =
|
|||
{ &CLSID_AsyncReader, AsyncReader_create },
|
||||
{ &CLSID_MemoryAllocator, StdMemAllocator_create },
|
||||
{ &CLSID_AviSplitter, AVISplitter_create },
|
||||
|
||||
{ &CLSID_SystemClock, &QUARTZ_CreateSystemClock }
|
||||
};
|
||||
|
||||
static HRESULT WINAPI
|
||||
|
|
|
@ -42,6 +42,7 @@ HRESULT FilterMapper2_create(IUnknown *pUnkOuter, LPVOID *ppObj);
|
|||
HRESULT AsyncReader_create(IUnknown * pUnkOuter, LPVOID * ppv);
|
||||
HRESULT StdMemAllocator_create(IUnknown * pUnkOuter, LPVOID * ppv);
|
||||
HRESULT AVISplitter_create(IUnknown * pUnkOuter, LPVOID * ppv);
|
||||
HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv);
|
||||
|
||||
HRESULT EnumMonikerImpl_Create(IMoniker ** ppMoniker, ULONG nMonikerCount, IEnumMoniker ** ppEnum);
|
||||
|
||||
|
|
|
@ -521,6 +521,12 @@ static struct regsvr_coclass const coclass_list[] = {
|
|||
"quartz.dll",
|
||||
"Both"
|
||||
},
|
||||
{ &CLSID_SystemClock,
|
||||
"System Clock",
|
||||
NULL,
|
||||
"quartz.dll",
|
||||
"Both"
|
||||
},
|
||||
{ NULL } /* list terminator */
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
* Implementation of IReferenceClock
|
||||
*
|
||||
* Copyright 2004 Raphael Junqueira
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define COM_NO_WINDOWS_H
|
||||
#include "quartz_private.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "uuids.h"
|
||||
#include <assert.h>
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
|
||||
|
||||
typedef struct SystemClockAdviseEntry SystemClockAdviseEntry;
|
||||
struct SystemClockAdviseEntry {
|
||||
SystemClockAdviseEntry* next;
|
||||
SystemClockAdviseEntry* prev;
|
||||
|
||||
HANDLE hEvent;
|
||||
REFERENCE_TIME rtBaseTime;
|
||||
REFERENCE_TIME rtIntervalTime;
|
||||
};
|
||||
|
||||
typedef struct SystemClockImpl {
|
||||
ICOM_VFIELD(IReferenceClock);
|
||||
ULONG ref;
|
||||
|
||||
/** IReferenceClock */
|
||||
HANDLE adviseThread;
|
||||
DWORD adviseThreadId;
|
||||
BOOL adviseThreadActive;
|
||||
REFERENCE_TIME lastRefTime;
|
||||
DWORD lastTimeTickCount;
|
||||
CRITICAL_SECTION safe;
|
||||
|
||||
SystemClockAdviseEntry* pSingleShotAdvise;
|
||||
SystemClockAdviseEntry* pPeriodicAdvise;
|
||||
} SystemClockImpl;
|
||||
|
||||
|
||||
static void QUARTZ_RemoveAviseEntryFromQueue(SystemClockImpl* This, SystemClockAdviseEntry* pEntry) {
|
||||
if (pEntry->prev) pEntry->prev->next = pEntry->next;
|
||||
if (pEntry->next) pEntry->next->prev = pEntry->prev;
|
||||
if (This->pSingleShotAdvise == pEntry) This->pSingleShotAdvise = pEntry->next;
|
||||
if (This->pPeriodicAdvise == pEntry) This->pPeriodicAdvise = pEntry->next;
|
||||
}
|
||||
|
||||
static void QUARTZ_InsertAviseEntryFromQueue(SystemClockImpl* This, SystemClockAdviseEntry* pEntry, SystemClockAdviseEntry** pQueue) {
|
||||
SystemClockAdviseEntry* prev_it = NULL;
|
||||
SystemClockAdviseEntry* it = NULL;
|
||||
REFERENCE_TIME bornTime = pEntry->rtBaseTime + pEntry->rtIntervalTime;
|
||||
|
||||
for (it = *pQueue; NULL != it && (it->rtBaseTime + it->rtIntervalTime) < bornTime; it = it->next) {
|
||||
prev_it = it;
|
||||
}
|
||||
if (NULL == prev_it) {
|
||||
pEntry->prev = NULL;
|
||||
if (NULL != (*pQueue)) pEntry->next = (*pQueue)->next;
|
||||
/*assert( NULL == pEntry->next->prev );*/
|
||||
if (NULL != pEntry->next) pEntry->next->prev = pEntry;
|
||||
(*pQueue) = pEntry;
|
||||
} else {
|
||||
pEntry->prev = prev_it;
|
||||
pEntry->next = prev_it->next;
|
||||
prev_it->next = pEntry;
|
||||
if (NULL != pEntry->next) pEntry->next->prev = pEntry;
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_REFTIME (REFERENCE_TIME)(0x7FFFFFFFFFFFFFFF)
|
||||
#define ADVISE_EXIT (WM_APP + 0)
|
||||
#define ADVISE_REMOVE (WM_APP + 2)
|
||||
#define ADVISE_ADD_SINGLESHOT (WM_APP + 4)
|
||||
#define ADVISE_ADD_PERIODIC (WM_APP + 8)
|
||||
|
||||
static DWORD WINAPI SystemClockAdviseThread(LPVOID lpParam) {
|
||||
SystemClockImpl* This = (SystemClockImpl*) lpParam;
|
||||
DWORD timeOut = INFINITE;
|
||||
DWORD tmpTimeOut;
|
||||
MSG msg;
|
||||
HRESULT hr;
|
||||
REFERENCE_TIME curTime;
|
||||
SystemClockAdviseEntry* it = NULL;
|
||||
|
||||
TRACE("(%p): Main Loop\n", This);
|
||||
|
||||
while (TRUE) {
|
||||
if (timeOut > 0) MsgWaitForMultipleObjects(0, NULL, FALSE, timeOut, QS_POSTMESSAGE|QS_SENDMESSAGE|QS_TIMER);
|
||||
|
||||
EnterCriticalSection(&This->safe);
|
||||
/*timeOut = IReferenceClock_OnTimerUpdated(This); */
|
||||
hr = IReferenceClock_GetTime((IReferenceClock*) This, &curTime);
|
||||
if (FAILED(hr)) {
|
||||
timeOut = INFINITE;
|
||||
goto outrefresh;
|
||||
}
|
||||
|
||||
/** First SingleShots Advice: sorted list */
|
||||
for (it = This->pSingleShotAdvise; NULL != it && it->rtBaseTime <= curTime; it = it->next) {
|
||||
/** send event ... */
|
||||
SetEvent((HANDLE) it->hEvent);
|
||||
/** ... and Release it */
|
||||
QUARTZ_RemoveAviseEntryFromQueue(This, it);
|
||||
HeapFree(GetProcessHeap(), 0, it);
|
||||
}
|
||||
if (NULL != it) timeOut = (DWORD) (curTime - (it->rtBaseTime + it->rtIntervalTime));
|
||||
|
||||
/** Now Periodics Advice: semi sorted list (sort cannot be used) */
|
||||
for (it = This->pPeriodicAdvise; NULL != it; it = it->next) {
|
||||
if (it->rtBaseTime <= curTime) {
|
||||
DWORD nPeriods = (DWORD) ((curTime - it->rtBaseTime) / it->rtIntervalTime);
|
||||
/** Release the semaphore ... */
|
||||
ReleaseSemaphore((HANDLE) it->hEvent, nPeriods, NULL);
|
||||
/** ... and refresh time */
|
||||
it->rtBaseTime += it->rtIntervalTime;
|
||||
/*assert( it->rtBaseTime + it->rtIntervalTime < curTime );*/
|
||||
}
|
||||
tmpTimeOut = (DWORD) (curTime - (it->rtBaseTime + it->rtIntervalTime));
|
||||
if (timeOut > tmpTimeOut) timeOut = tmpTimeOut;
|
||||
}
|
||||
|
||||
outrefresh:
|
||||
LeaveCriticalSection(&This->safe);
|
||||
|
||||
while (TRUE == PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
/** if hwnd we suppose that is a windows event ... */
|
||||
if (NULL != msg.hwnd) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
} else {
|
||||
switch (msg.message) {
|
||||
case WM_QUIT:
|
||||
case ADVISE_EXIT:
|
||||
goto outofthread;
|
||||
break;
|
||||
case ADVISE_ADD_SINGLESHOT:
|
||||
case ADVISE_ADD_PERIODIC:
|
||||
/** set timeout to 0 to do a rescan now */
|
||||
timeOut = 0;
|
||||
break;
|
||||
case ADVISE_REMOVE:
|
||||
/** hmmmm what we can do here ... */
|
||||
timeOut = INFINITE;
|
||||
break;
|
||||
default:
|
||||
ERR("Unhandled message %u. Critical Path\n", msg.message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outofthread:
|
||||
TRACE("(%p): Exiting\n", This);
|
||||
return 0;
|
||||
}
|
||||
/*static DWORD WINAPI SystemClockAdviseThread(LPVOID lpParam) { */
|
||||
|
||||
static BOOL SystemClockPostMessageToAdviseThread(SystemClockImpl* This, UINT iMsg) {
|
||||
if (FALSE == This->adviseThreadActive) {
|
||||
This->adviseThread = CreateThread(NULL, 0, SystemClockAdviseThread, This, 0, &This->adviseThreadId);
|
||||
if (NULL == This->adviseThread) return FALSE;
|
||||
SetThreadPriority(This->adviseThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
This->adviseThreadActive = TRUE;
|
||||
}
|
||||
return PostThreadMessageA(This->adviseThreadId, iMsg, 0, 0);
|
||||
}
|
||||
|
||||
ICOM_VTABLE(IReferenceClock) SystemClock_Vtbl;
|
||||
|
||||
static ULONG WINAPI SystemClockImpl_AddRef(IReferenceClock* iface) {
|
||||
ICOM_THIS(SystemClockImpl,iface);
|
||||
TRACE("(%p): AddRef from %ld\n", This, This->ref);
|
||||
return ++(This->ref);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI SystemClockImpl_QueryInterface(IReferenceClock* iface, REFIID riid, void** ppobj) {
|
||||
ICOM_THIS(SystemClockImpl,iface);
|
||||
TRACE("(%p, %s,%p)\n", This, debugstr_guid(riid), ppobj);
|
||||
|
||||
if (IsEqualIID (riid, &IID_IUnknown) ||
|
||||
IsEqualIID (riid, &IID_IReferenceClock)) {
|
||||
SystemClockImpl_AddRef(iface);
|
||||
*ppobj = This;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppobj);
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG WINAPI SystemClockImpl_Release(IReferenceClock* iface) {
|
||||
ICOM_THIS(SystemClockImpl,iface);
|
||||
ULONG ref = --This->ref;
|
||||
TRACE("(%p): ReleaseRef to %ld\n", This, This->ref);
|
||||
if (ref == 0) {
|
||||
if (SystemClockPostMessageToAdviseThread(This, ADVISE_EXIT)) {
|
||||
WaitForSingleObject(This->adviseThread, INFINITE);
|
||||
CloseHandle(This->adviseThread);
|
||||
}
|
||||
DeleteCriticalSection(&This->safe);
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI SystemClockImpl_GetTime(IReferenceClock* iface, REFERENCE_TIME* pTime) {
|
||||
ICOM_THIS(SystemClockImpl,iface);
|
||||
DWORD curTimeTickCount;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
TRACE("(%p, %p)\n", This, pTime);
|
||||
|
||||
if (NULL == pTime) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
curTimeTickCount = GetTickCount();
|
||||
|
||||
EnterCriticalSection(&This->safe);
|
||||
/** TODO: safe this not using * 10000 */
|
||||
This->lastRefTime += (REFERENCE_TIME) (DWORD) (curTimeTickCount - This->lastTimeTickCount) * (REFERENCE_TIME) 10000;
|
||||
This->lastTimeTickCount = curTimeTickCount;
|
||||
LeaveCriticalSection(&This->safe);
|
||||
|
||||
*pTime = This->lastRefTime;
|
||||
if (This->lastTimeTickCount == curTimeTickCount) hr = S_FALSE;
|
||||
This->lastTimeTickCount = curTimeTickCount;
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI SystemClockImpl_AdviseTime(IReferenceClock* iface, REFERENCE_TIME rtBaseTime, REFERENCE_TIME rtStreamTime, HEVENT hEvent, DWORD_PTR* pdwAdviseCookie) {
|
||||
ICOM_THIS(SystemClockImpl,iface);
|
||||
SystemClockAdviseEntry* pEntry = NULL;
|
||||
|
||||
TRACE("(%p, %lld, %lld, %ld, %p)\n", This, rtBaseTime, rtStreamTime, hEvent, pdwAdviseCookie);
|
||||
|
||||
if ((HEVENT) 0 == hEvent) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (0 >= rtBaseTime + rtStreamTime) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (NULL == pdwAdviseCookie) {
|
||||
return E_POINTER;
|
||||
}
|
||||
pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SystemClockAdviseEntry));
|
||||
if (NULL == pEntry) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
pEntry->hEvent = (HANDLE) hEvent;
|
||||
pEntry->rtBaseTime = rtBaseTime + rtStreamTime;
|
||||
pEntry->rtIntervalTime = 0;
|
||||
|
||||
EnterCriticalSection(&This->safe);
|
||||
QUARTZ_InsertAviseEntryFromQueue(This, pEntry, &This->pSingleShotAdvise);
|
||||
LeaveCriticalSection(&This->safe);
|
||||
|
||||
SystemClockPostMessageToAdviseThread(This, ADVISE_ADD_SINGLESHOT);
|
||||
|
||||
*pdwAdviseCookie = (DWORD_PTR) (pEntry);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI SystemClockImpl_AdvisePeriodic(IReferenceClock* iface, REFERENCE_TIME rtStartTime, REFERENCE_TIME rtPeriodTime, HSEMAPHORE hSemaphore, DWORD_PTR* pdwAdviseCookie) {
|
||||
ICOM_THIS(SystemClockImpl,iface);
|
||||
SystemClockAdviseEntry* pEntry = NULL;
|
||||
|
||||
TRACE("(%p, %lld, %lld, %ld, %p)\n", This, rtStartTime, rtPeriodTime, hSemaphore, pdwAdviseCookie);
|
||||
|
||||
if ((HSEMAPHORE) 0 == hSemaphore) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (0 >= rtStartTime || 0 >= rtPeriodTime) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (NULL == pdwAdviseCookie) {
|
||||
return E_POINTER;
|
||||
}
|
||||
pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SystemClockAdviseEntry));
|
||||
if (NULL == pEntry) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
pEntry->hEvent = (HANDLE) hSemaphore;
|
||||
pEntry->rtBaseTime = rtStartTime;
|
||||
pEntry->rtIntervalTime = rtPeriodTime;
|
||||
|
||||
EnterCriticalSection(&This->safe);
|
||||
QUARTZ_InsertAviseEntryFromQueue(This, pEntry, &This->pPeriodicAdvise);
|
||||
LeaveCriticalSection(&This->safe);
|
||||
|
||||
SystemClockPostMessageToAdviseThread(This, ADVISE_ADD_PERIODIC);
|
||||
|
||||
*pdwAdviseCookie = (DWORD_PTR) (pEntry);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI SystemClockImpl_Unadvise(IReferenceClock* iface, DWORD_PTR dwAdviseCookie) {
|
||||
ICOM_THIS(SystemClockImpl,iface);
|
||||
SystemClockAdviseEntry* pEntry = NULL;
|
||||
SystemClockAdviseEntry* it = NULL;
|
||||
HRESULT ret = S_OK;
|
||||
TRACE("(%p, %lu)\n", This, dwAdviseCookie);
|
||||
|
||||
pEntry = (SystemClockAdviseEntry*) dwAdviseCookie;
|
||||
|
||||
EnterCriticalSection(&This->safe);
|
||||
for (it = This->pPeriodicAdvise; NULL != it && it != pEntry; it = it->next) ;
|
||||
if (it != pEntry) {
|
||||
for (it = This->pSingleShotAdvise; NULL != it && it != pEntry; it = it->next) ;
|
||||
if (it != pEntry) {
|
||||
ret = S_FALSE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
QUARTZ_RemoveAviseEntryFromQueue(This, pEntry);
|
||||
HeapFree(GetProcessHeap(), 0, pEntry);
|
||||
|
||||
SystemClockPostMessageToAdviseThread(This, ADVISE_REMOVE);
|
||||
|
||||
out:
|
||||
LeaveCriticalSection(&This->safe);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ICOM_VTABLE(IReferenceClock) SystemClock_Vtbl =
|
||||
{
|
||||
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
||||
SystemClockImpl_QueryInterface,
|
||||
SystemClockImpl_AddRef,
|
||||
SystemClockImpl_Release,
|
||||
SystemClockImpl_GetTime,
|
||||
SystemClockImpl_AdviseTime,
|
||||
SystemClockImpl_AdvisePeriodic,
|
||||
SystemClockImpl_Unadvise
|
||||
};
|
||||
|
||||
HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv) {
|
||||
SystemClockImpl* obj = NULL;
|
||||
|
||||
TRACE("(%p,%p)\n", ppv, pUnkOuter);
|
||||
|
||||
obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IReferenceClock));
|
||||
if (NULL == obj) {
|
||||
*ppv = NULL;
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
obj->lpVtbl = &SystemClock_Vtbl;
|
||||
obj->ref = 0; /* will be inited by QueryInterface */
|
||||
|
||||
obj->lastTimeTickCount = GetTickCount();
|
||||
InitializeCriticalSection(&obj->safe);
|
||||
|
||||
return SystemClockImpl_QueryInterface((IReferenceClock*) obj, &IID_IReferenceClock, ppv);
|
||||
}
|
Loading…
Reference in New Issue