//------------------------------------------------------------------------------ | |
// 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__ |