//------------------------------------------------------------------------------ // File: Schedule.h // // Desc: DirectShow base classes. // // Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ #ifndef __CAMSchedule__ #define __CAMSchedule__ class CAMSchedule : private CBaseObject { public: virtual ~CAMSchedule(); // ev is the event we should fire if the advise time needs re-evaluating CAMSchedule( HANDLE ev ); DWORD GetAdviseCount(); REFERENCE_TIME GetNextAdviseTime(); // We need a method for derived classes to add advise packets, we return the cookie DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic ); // And a way to cancel HRESULT Unadvise(DWORD_PTR dwAdviseCookie); // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event. // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of // whoever is using this helper class (typically a clock). REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime ); // Get the event handle which will be set if advise time requires re-evaluation. HANDLE GetEvent() const { return m_ev; } private: // We define the nodes that will be used in our singly linked list // of advise packets. The list is ordered by time, with the // elements that will expire first at the front. class CAdvisePacket { public: CAdvisePacket() {} CAdvisePacket * m_next; DWORD_PTR m_dwAdviseCookie; REFERENCE_TIME m_rtEventTime; // Time at which event should be set REFERENCE_TIME m_rtPeriod; // Periodic time HANDLE m_hNotify; // Handle to event or semephore BOOL m_bPeriodic; // TRUE => Periodic event CAdvisePacket( __inout_opt CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time) {} void InsertAfter( __inout CAdvisePacket * p ) { p->m_next = m_next; m_next = p; } int IsZ() const // That is, is it the node that represents the end of the list { return m_next == 0; } CAdvisePacket * RemoveNext() { CAdvisePacket *const next = m_next; CAdvisePacket *const new_next = next->m_next; m_next = new_next; return next; } void DeleteNext() { delete RemoveNext(); } CAdvisePacket * Next() const { CAdvisePacket * result = m_next; if (result->IsZ()) result = 0; return result; } DWORD_PTR Cookie() const { return m_dwAdviseCookie; } }; // Structure is: // head -> elmt1 -> elmt2 -> z -> null // So an empty list is: head -> z -> null // Having head & z as links makes insertaion, // deletion and shunting much easier. CAdvisePacket head, z; // z is both a tail and a sentry volatile DWORD_PTR m_dwNextCookie; // Strictly increasing volatile DWORD m_dwAdviseCount; // Number of elements on list CCritSec m_Serialize; // AddAdvisePacket: adds the packet, returns the cookie (0 if failed) DWORD_PTR AddAdvisePacket( __inout CAdvisePacket * pPacket ); // Event that we should set if the packed added above will be the next to fire. const HANDLE m_ev; // A Shunt is where we have changed the first element in the // list and want it re-evaluating (i.e. repositioned) in // the list. void ShuntHead(); // Rather than delete advise packets, we cache them for future use CAdvisePacket * m_pAdviseCache; DWORD m_dwCacheCount; enum { dwCacheMax = 5 }; // Don't bother caching more than five void Delete( __inout CAdvisePacket * pLink );// This "Delete" will cache the Link // Attributes and methods for debugging public: #ifdef DEBUG void DumpLinkedList(); #else void DumpLinkedList() {} #endif }; #endif // __CAMSchedule__