Alexandre Lision | 8af73cb | 2013-12-10 14:11:20 -0500 | [diff] [blame] | 1 | //------------------------------------------------------------------------------
|
| 2 | // File: RefClock.h
|
| 3 | //
|
| 4 | // Desc: DirectShow base classes - defines the IReferenceClock interface.
|
| 5 | //
|
| 6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
| 7 | //------------------------------------------------------------------------------
|
| 8 |
|
| 9 |
|
| 10 | #ifndef __BASEREFCLOCK__
|
| 11 | #define __BASEREFCLOCK__
|
| 12 |
|
| 13 | #include <Schedule.h>
|
| 14 |
|
| 15 | const UINT RESOLUTION = 1; /* High resolution timer */
|
| 16 | const INT ADVISE_CACHE = 4; /* Default cache size */
|
| 17 | const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */
|
| 18 |
|
| 19 | inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT)
|
| 20 | {
|
| 21 | /* This converts an arbitrary value representing a reference time
|
| 22 | into a MILLISECONDS value for use in subsequent system calls */
|
| 23 |
|
| 24 | return (RT / (UNITS / MILLISECONDS));
|
| 25 | }
|
| 26 |
|
| 27 | /* This class hierarchy will support an IReferenceClock interface so
|
| 28 | that an audio card (or other externally driven clock) can update the
|
| 29 | system wide clock that everyone uses.
|
| 30 |
|
| 31 | The interface will be pretty thin with probably just one update method
|
| 32 | This interface has not yet been defined.
|
| 33 | */
|
| 34 |
|
| 35 | /* This abstract base class implements the IReferenceClock
|
| 36 | * interface. Classes that actually provide clock signals (from
|
| 37 | * whatever source) have to be derived from this class.
|
| 38 | *
|
| 39 | * The abstract class provides implementations for:
|
| 40 | * CUnknown support
|
| 41 | * locking support (CCritSec)
|
| 42 | * client advise code (creates a thread)
|
| 43 | *
|
| 44 | * Question: what can we do about quality? Change the timer
|
| 45 | * resolution to lower the system load? Up the priority of the
|
| 46 | * timer thread to force more responsive signals?
|
| 47 | *
|
| 48 | * During class construction we create a worker thread that is destroyed during
|
| 49 | * destuction. This thread executes a series of WaitForSingleObject calls,
|
| 50 | * waking up when a command is given to the thread or the next wake up point
|
| 51 | * is reached. The wakeup points are determined by clients making Advise
|
| 52 | * calls.
|
| 53 | *
|
| 54 | * Each advise call defines a point in time when they wish to be notified. A
|
| 55 | * periodic advise is a series of these such events. We maintain a list of
|
| 56 | * advise links and calculate when the nearest event notification is due for.
|
| 57 | * We then call WaitForSingleObject with a timeout equal to this time. The
|
| 58 | * handle we wait on is used by the class to signal that something has changed
|
| 59 | * and that we must reschedule the next event. This typically happens when
|
| 60 | * someone comes in and asks for an advise link while we are waiting for an
|
| 61 | * event to timeout.
|
| 62 | *
|
| 63 | * While we are modifying the list of advise requests we
|
| 64 | * are protected from interference through a critical section. Clients are NOT
|
| 65 | * advised through callbacks. One shot clients have an event set, while
|
| 66 | * periodic clients have a semaphore released for each event notification. A
|
| 67 | * semaphore allows a client to be kept up to date with the number of events
|
| 68 | * actually triggered and be assured that they can't miss multiple events being
|
| 69 | * set.
|
| 70 | *
|
| 71 | * Keeping track of advises is taken care of by the CAMSchedule class.
|
| 72 | */
|
| 73 |
|
| 74 | class CBaseReferenceClock
|
| 75 | : public CUnknown, public IReferenceClock, public CCritSec, public IReferenceClockTimerControl
|
| 76 | {
|
| 77 | protected:
|
| 78 | virtual ~CBaseReferenceClock(); // Don't let me be created on the stack!
|
| 79 | public:
|
| 80 | CBaseReferenceClock(__in_opt LPCTSTR pName,
|
| 81 | __inout_opt LPUNKNOWN pUnk,
|
| 82 | __inout HRESULT *phr,
|
| 83 | __inout_opt CAMSchedule * pSched = 0 );
|
| 84 |
|
| 85 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv);
|
| 86 |
|
| 87 | DECLARE_IUNKNOWN
|
| 88 |
|
| 89 | /* IReferenceClock methods */
|
| 90 | // Derived classes must implement GetPrivateTime(). All our GetTime
|
| 91 | // does is call GetPrivateTime and then check so that time does not
|
| 92 | // go backwards. A return code of S_FALSE implies that the internal
|
| 93 | // clock has gone backwards and GetTime time has halted until internal
|
| 94 | // time has caught up. (Don't know if this will be much use to folk,
|
| 95 | // but it seems odd not to use the return code for something useful.)
|
| 96 | STDMETHODIMP GetTime(__out REFERENCE_TIME *pTime);
|
| 97 | // When this is called, it sets m_rtLastGotTime to the time it returns.
|
| 98 |
|
| 99 | /* Provide standard mechanisms for scheduling events */
|
| 100 |
|
| 101 | /* Ask for an async notification that a time has elapsed */
|
| 102 | STDMETHODIMP AdviseTime(
|
| 103 | REFERENCE_TIME baseTime, // base reference time
|
| 104 | REFERENCE_TIME streamTime, // stream offset time
|
| 105 | HEVENT hEvent, // advise via this event
|
| 106 | __out DWORD_PTR *pdwAdviseCookie// where your cookie goes
|
| 107 | );
|
| 108 |
|
| 109 | /* Ask for an asynchronous periodic notification that a time has elapsed */
|
| 110 | STDMETHODIMP AdvisePeriodic(
|
| 111 | REFERENCE_TIME StartTime, // starting at this time
|
| 112 | REFERENCE_TIME PeriodTime, // time between notifications
|
| 113 | HSEMAPHORE hSemaphore, // advise via a semaphore
|
| 114 | __out DWORD_PTR *pdwAdviseCookie// where your cookie goes
|
| 115 | );
|
| 116 |
|
| 117 | /* Cancel a request for notification(s) - if the notification was
|
| 118 | * a one shot timer then this function doesn't need to be called
|
| 119 | * as the advise is automatically cancelled, however it does no
|
| 120 | * harm to explicitly cancel a one-shot advise. It is REQUIRED that
|
| 121 | * clients call Unadvise to clear a Periodic advise setting.
|
| 122 | */
|
| 123 |
|
| 124 | STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie);
|
| 125 |
|
| 126 | /* Methods for the benefit of derived classes or outer objects */
|
| 127 |
|
| 128 | // GetPrivateTime() is the REAL clock. GetTime is just a cover for
|
| 129 | // it. Derived classes will probably override this method but not
|
| 130 | // GetTime() itself.
|
| 131 | // The important point about GetPrivateTime() is it's allowed to go
|
| 132 | // backwards. Our GetTime() will keep returning the LastGotTime
|
| 133 | // until GetPrivateTime() catches up.
|
| 134 | virtual REFERENCE_TIME GetPrivateTime();
|
| 135 |
|
| 136 | /* Provide a method for correcting drift */
|
| 137 | STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta );
|
| 138 |
|
| 139 | CAMSchedule * GetSchedule() const { return m_pSchedule; }
|
| 140 |
|
| 141 | // IReferenceClockTimerControl methods
|
| 142 | //
|
| 143 | // Setting a default of 0 disables the default of 1ms
|
| 144 | STDMETHODIMP SetDefaultTimerResolution(
|
| 145 | REFERENCE_TIME timerResolution // in 100ns
|
| 146 | );
|
| 147 | STDMETHODIMP GetDefaultTimerResolution(
|
| 148 | __out REFERENCE_TIME* pTimerResolution // in 100ns
|
| 149 | );
|
| 150 |
|
| 151 | private:
|
| 152 | REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time
|
| 153 | DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime
|
| 154 | REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime
|
| 155 | REFERENCE_TIME m_rtNextAdvise; // Time of next advise
|
| 156 | UINT m_TimerResolution;
|
| 157 |
|
| 158 | #ifdef PERF
|
| 159 | int m_idGetSystemTime;
|
| 160 | #endif
|
| 161 |
|
| 162 | // Thread stuff
|
| 163 | public:
|
| 164 | void TriggerThread() // Wakes thread up. Need to do this if
|
| 165 | { // time to next advise needs reevaluating.
|
| 166 | EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent()));
|
| 167 | }
|
| 168 |
|
| 169 |
|
| 170 | private:
|
| 171 | BOOL m_bAbort; // Flag used for thread shutdown
|
| 172 | HANDLE m_hThread; // Thread handle
|
| 173 |
|
| 174 | HRESULT AdviseThread(); // Method in which the advise thread runs
|
| 175 | static DWORD __stdcall AdviseThreadFunction(__in LPVOID); // Function used to get there
|
| 176 |
|
| 177 | protected:
|
| 178 | CAMSchedule * m_pSchedule;
|
| 179 |
|
| 180 | void Restart (IN REFERENCE_TIME rtMinTime = 0I64) ;
|
| 181 | };
|
| 182 |
|
| 183 | #endif
|
| 184 |
|