129 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//------------------------------------------------------------------------------
 | 
						|
// 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__
 |