CRefTime类[reftime.h]
CRefTime类维护了REFERENCE_TIME m_time;的成员变量。单位为100ns。
另外,几个跟该类相关的宏:
const LONGLONG MILLISECONDS = (1000); // 10 ^ 3
const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9
const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7
#define MILLISECONDS_TO_100NS_UNITS(lMs) Int32x32To64((lMs), (UNITS / MILLISECONDS))
inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT)
{return (RT / (UNITS / MILLISECONDS));}
IBaseReferenceClock接口
IReferenceClock : public IUnknown
{
public:
// Retrieves the current reference time.
virtual HRESULT STDMETHODCALLTYPE GetTime(
/* [out] */ REFERENCE_TIME *pTime) = 0;
// Creates a one-shot advise request.
virtual HRESULT STDMETHODCALLTYPE AdviseTime(
/* [in] */ REFERENCE_TIME baseTime,
/* [in] */ REFERENCE_TIME streamTime,
/* [in] */ HEVENT hEvent,
/* [out] */ DWORD_PTR *pdwAdviseCookie) = 0;
// Creates a periodic advise request.
virtual HRESULT STDMETHODCALLTYPE AdvisePeriodic(
/* [in] */ REFERENCE_TIME startTime,
/* [in] */ REFERENCE_TIME periodTime,
/* [in] */ HSEMAPHORE hSemaphore,
/* [out] */ DWORD_PTR *pdwAdviseCookie) = 0;
// Removes a pending advise request.
virtual HRESULT STDMETHODCALLTYPE Unadvise(
/* [in] */ DWORD_PTR dwAdviseCookie) = 0;
};
CCritSec和CAutoLock类[wxutil.h/wxutil.cpp]
CCritSec封装了CRITICAL_SECTION m_CritSec;成员变量,通过函数Lock()和Unlock对该变量进行EnterCriticalSection和LeaveCriticalSection,同时,Constructor和Deconstructor分别调用了InitializeCriticalSection和DeleteCriticalSection函数。
CAutoLock是和CCritSec配合使用的Helper类,它在Constructor中接受一个CCritSec的指针,并对其调用Lock函数,而在Deconstructor调用Unlock函数。
CAMSchedule类[dsschedule.h/schedule.cpp]
派生自 CBaseObject
其实此类就是一个List,Node是类型CAdvisePacket。具体解析略。
CBaseReferenceClock类[refclock.h/refclock.cpp]
继承了IReferenceClock接口,同时派生自CUnknown、CCritSec。
成员变量:
REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time
DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime
REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime
REFERENCE_TIME m_rtNextAdvise; // Time of next advise
UINT m_TimerResolution;
BOOL m_bAbort; // Flag used for thread shutdown
HANDLE m_hThread; // Thread handle
CAMSchedule * const m_pSchedule; // 任务列表
// 一个Static函数
static DWORD __stdcall AdviseThreadFunction(LPVOID); // Function used to get there
IReferenceClock接口函数:
STDMETHODIMP GetTime(REFERENCE_TIME *pTime);
{
// 首先调用Lock(),然后rtNow = GetPrivateTime();
// 判断(rtNow > m_rtLastGotTime),是则m_rtLastGotTime = rtNow;否则设置返回值为S_FALSE
// 设置返回值 *pTime = m_rtLastGotTime;
}
/* Ask for an async notification that a time has elapsed */
STDMETHODIMP AdviseTime(
REFERENCE_TIME baseTime, // base reference time
REFERENCE_TIME streamTime, // stream offset time
HEVENT hEvent, // advise via this event
DWORD_PTR *pdwAdviseCookie // where your cookie goes
);
{
// 首先初始化输出变量 *pdwAdviseCookie = 0;
// 判断 ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0));
// 得到当前绝对时间 const REFERENCE_TIME lRefTime = baseTime + streamTime;
// *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( lRefTime, 0, HANDLE(hEvent), FALSE );
}
/* Ask for an asynchronous periodic notification that a time has elapsed */
STDMETHODIMP AdvisePeriodic(
REFERENCE_TIME StartTime, // starting at this time
REFERENCE_TIME PeriodTime, // time between notifications
HSEMAPHORE hSemaphore, // advise via a semaphore
DWORD_PTR *pdwAdviseCookie // where your cookie goes
);
{
// 同样,首先初始化输出变量
// *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( StartTime, PeriodTime, HANDLE(hSemaphore), TRUE );
}
STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie);
{
return m_pSchedule->Unadvise(dwAdviseCookie);
}
新增加的virtual函数:
virtual REFERENCE_TIME GetPrivateTime();
{
CAutoLock cObjectLock(this);
DWORD dwTime = timeGetTime();
m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime));
m_dwPrevSystemTime = dwTime;
return m_rtPrivateTime;
}
普通成员函数:
/* Provide a method for correcting drift */
STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta );
{
CAutoLock cObjectLock(this);
m_rtPrivateTime += TimeDelta;
if ( TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0 ) TriggerThread();
return NOERROR;
}
CAMSchedule * GetSchedule() const { return m_pSchedule; }
void TriggerThread() // Wakes thread up. Need to do this if
{ // time to next advise needs reevaluating.
EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent()));
}
DWORD __stdcall AdviseThreadFunction(LPVOID p)
{
return DWORD(reinterpret_cast<CBaseReferenceClock*>(p)->AdviseThread());
}
// Method in which the advise thread runs
HRESULT AdviseThread()
{
DWORD dwWait = INFINITE;
while ( !m_bAbort )
{
WaitForSingleObject(m_pSchedule->GetEvent(), dwWait);
if (m_bAbort)
break;
const REFERENCE_TIME rtNow = GetPrivateTime();
m_rtNextAdvise = m_pSchedule->Advise( 10000 + rtNow );
LONGLONG llWait = m_rtNextAdvise - rtNow;
llWait = ConvertToMilliseconds(llWait);
// DON'T replace this with a max!! (The type's of these things is VERY important)
dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait);
}
}
Deconstructor:
CBaseReferenceClock::~CBaseReferenceClock()
{
if (m_TimerResolution) timeEndPeriod(m_TimerResolution);
m_pSchedule->DumpLinkedList();
// 如果m_hThread存在,设置m_bAbort为TRUE后调用TriggerThread(),
// 然后等Thread结束:WaitForSingleObject( m_hThread, INFINITE );
// 关闭Thread的handle::EXECUTE_ASSERT( CloseHandle(m_hThread) );
// m_hThread = 0;
// 清除任务列表的Event Handle:EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) );
}
Constructor:
CBaseReferenceClock::CBaseReferenceClock( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pShed )
: CUnknown( pName, pUnk ) , m_rtLastGotTime(0) , m_TimerResolution(0) , m_bAbort( FALSE )
, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) ) , m_hThread(0)
{
// 判断m_pSchedule是否为空,如果为空则直接返回错误
TIMECAPS tc;
m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) ? tc.wPeriodMin: 1;
timeBeginPeriod(m_TimerResolution);
/* Initialise our system times - the derived clock should set the right values */
m_dwPrevSystemTime = timeGetTime();
m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime;
if ( !pShed )
{
DWORD ThreadID;
m_hThread = ::CreateThread(NULL, // Security attributes
(DWORD) 0, // Initial stack size
AdviseThreadFunction, // Thread start address
(LPVOID) this, // Thread parameter
(DWORD) 0, // Creation flags
&ThreadID); // Thread identifier
if (m_hThread) SetThreadPriority( m_hThread, THREAD_PRIORITY_TIME_CRITICAL );
else 返回错误并清除m_pSchedule
}
}
CAMEvent类[wxutil.h/wxutil.cpp]
类似于CCritSec,CAMEvent封装了HANDLE m_hEvent;
Construction:
CAMEvent(BOOL fManualReset = FALSE);
{m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL);}
Deconstructor
~CAMEvent(){if (m_hEvent) EXECUTE_ASSERT(CloseHandle(m_hEvent));}
成员函数很简洁明了
operator HANDLE () const { return m_hEvent; };
void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));};
BOOL Wait(DWORD dwTimeout = INFINITE) {
return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0);
};
void Reset() { ResetEvent(m_hEvent); };
BOOL Check() { return Wait(0); };
CAMThread类[wxutil.h/wxutil.cpp]
CAMThread稍微复杂一点。
成员变量:
CAMEvent m_EventSend;
CAMEvent m_EventComplete;
DWORD m_dwParam;
DWORD m_dwReturnVal;
HANDLE m_hThread;
CCritSec m_AccessLock; // locks access by client threads
CCritSec m_WorkerLock; // locks access to shared objects
其中,m_EventSend默认为TRUE,m_hThread初始化为NULL。
Deconstrutor只调用了Close函数。
新增加的virtual函数:
virtual DWORD ThreadProc() = 0;
成员函数:
// start thread running - error if already running
BOOL Create();
{
CAutoLock lock(&m_AccessLock);
if (ThreadExists()) {return FALSE;}
// 创建Thread,返回创建结果
m_hThread = CreateThread(NULL, 0, CAMThread::InitialThreadProc, this, 0, &threadid);
}
// signal the thread, and block for a response
DWORD CallWorker(DWORD);
{
CAutoLock lock(&m_AccessLock);
// 判断ThreadExists函数
// 设置参数 m_dwParam = dwParam;
// signal the worker thread: m_EventSend.Set();
// 等待该Thread结束 m_EventComplete.Wait();
// 返回结果 return m_dwReturnVal;
}
// accessor thread calls this when done with thread (having told thread to exit)
void Close() {
HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
};
// Return TRUE if the thread exists. FALSE otherwise
BOOL ThreadExists(void) const {return (m_hThread != 0); }
// wait for the next request
DWORD GetRequest();{m_EventSend.Wait();return m_dwParam;}
// is there a request?
BOOL CheckRequest(DWORD * pParam);
{
// if (!m_EventSend.Check())return FALSE;
// 否则设置*pParam = m_dwParam;
}
// reply to the request
void Reply(DWORD);
{
m_dwReturnVal = dw;
m_EventSend.Reset();
m_EventComplete.Set();
}
HANDLE GetRequestHandle() const { return m_EventSend; };
DWORD GetRequestParam() const { return m_dwParam; };
static成员函数:
// thread initially runs this. param is actually 'this'. Function
// just gets this and calls ThreadProc
static DWORD WINAPI InitialThreadProc(LPVOID pv);
{
HRESULT hrCoInit = CAMThread::CoInitializeHelper();
CAMThread * pThread = (CAMThread *) pv;
HRESULT hr = pThread->ThreadProc();
if(SUCCEEDED(hrCoInit)) {CoUninitialize();}
return hr;
}
// call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if available. S_FALSE means it's not available.
static HRESULT CoInitializeHelper();
{
// 通过GetModuleHandle(TEXT("ole32.dll"));来直接调用其中函数CoInitializeEx函数。
}
下几个部分将结合DirectShow中自带的例子分析CSource、CTransform和Render等类的源代码。