STRMCTL.H
//==========================================================================; 
// 
//  Copyright (c) 1997Microsoft Corporation.All Rights Reserved. 
// 
//--------------------------------------------------------------------------; 
 
#ifndef __strmctl_h__ 
#define __strmctl_h__ 
 
class CBaseStreamControl : public IAMStreamControl 
{ 
public: 
    // Used by the implementation 
    enum StreamControlState 
    { STREAM_FLOWING = 0x1000, 
      STREAM_DISCARDING 
    }; 
 
private: 
    enum StreamControlStatem_StreamState;// Current stream state 
    enum StreamControlStatem_StreamStateOnStop;// State after next stop 
// (i.e.Blocking or Discarding) 
 
    REFERENCE_TIMEm_tStartTime;    // MAX_TIME implies none 
    REFERENCE_TIMEm_tStopTime;    // MAX_TIME implies none 
    DWORDm_dwStartCookie;    // Cookie for notification to app 
    DWORDm_dwStopCookie;    // Cookie for notification to app 
    volatile BOOL       m_bIsFlushing;        // No optimization pls! 
    volatile BOOLm_bStopSendExtra;   // bSendExtra was set 
    volatile BOOLm_bStopExtraSent;   // the extra one was sent 
 
    CCritSecm_CritSec;    // CritSec to guard above attributes 
 
    // Event to fire when we can come 
    // out of blocking, or to come out of waiting 
    // to discard if we change our minds. 
    // 
    CAMEventm_StreamEvent; 
 
    // All of these methods execute immediately.  Helpers for others. 
    // 
    void ExecuteStop(); 
    void ExecuteStart(); 
    void CancelStop(); 
    void CancelStart(); 
 
    // Some things we need to be told by our owning filter 
    // Your pin must also expose IAMStreamControl when QI'd for it! 
    // 
    IReferenceClock *m_pRefClock;    // Need it to set advises 
    // Filter must tell us via 
    // SetSyncSource 
    IMediaEventSink *   m_pSink;            // Event sink 
    // Filter must tell us after it 
    // creates it in JoinFilterGraph() 
    FILTER_STATEm_FilterState;    // Just need it! 
    // Filter must tell us via 
    // NotifyFilterState 
    REFERENCE_TIMEm_tRunStart;    // Per the Run call to the filter 
 
    // This guy will return one of the three StreamControlState's.  Here's what 
    // the caller should do for each one: 
    // 
    // STREAM_FLOWING:Proceed as usual (render or pass the sample on) 
    // STREAM_DISCARDING:Calculate the time 'til *pSampleStop and wait 
    //that long for the event handle 
    //(GetStreamEventHandle()).  If the wait 
    //expires, throw the sample away.  If the event 
    //fires, call me back - I've changed my mind. 
    // 
    enum StreamControlState CheckSampleTimes( const REFERENCE_TIME * pSampleStart, 
      const REFERENCE_TIME * pSampleStop ); 
 
public: 
    // You don't have to tell us much when we're created, but there are other 
    // obligations that must be met.  See SetSyncSource & NotifyFilterState 
    // below. 
    // 
    CBaseStreamControl(); 
    ~CBaseStreamControl(); 
 
    // If you want this class to work properly, there are thing you need to 
    // (keep) telling it.  Filters with pins that use this class 
    // should ensure that they pass through to this method any calls they 
    // receive on their SetSyncSource. 
 
    // We need a clock to see what time it is.  This is for the 
    // "discard in a timely fashion" logic.  If we discard everything as 
    // quick as possible, a whole 60 minute file could get discarded in the 
    // first 10 seconds, and if somebody wants to turn streaming on at 30  
    // minutes into the file, and they make the call more than a few seconds 
    // after the graph is run, it may be too late!  That would be silly. 
    // So we hold every sample until it's time has gone, then we discard it. 
    // The filter should call this when it gets a SetSyncSource 
    // 
    void SetSyncSource( IReferenceClock * pRefClock ) 
    { 
CAutoLock lck(&m_CritSec); 
if (m_pRefClock) m_pRefClock->Release(); 
m_pRefClock = pRefClock; 
if (m_pRefClock) m_pRefClock->AddRef(); 
    } 
 
    // Set event sink for notifications 
    // The filter should call this in its JoinFilterGraph after it creates the 
    // IMediaEventSink 
    // 
    void SetFilterGraph( IMediaEventSink *pSink ) { 
        m_pSink = pSink; 
    } 
 
    // Since we schedule in stream time, we need the tStart and must track the 
    // state of our owning filter. 
    // The app should call this ever state change 
    // 
    void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 ); 
 
    // Filter should call Flushing(TRUE) in BeginFlush, 
    // and Flushing(FALSE) in EndFlush. 
    // 
    void Flushing( BOOL bInProgress ); 
 
 
    // The two main methods of IAMStreamControl 
 
    // Class adds default values suitable for immediate 
    // muting and unmuting of the stream. 
 
    STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL, 
 BOOL bSendExtra = FALSE, 
 DWORD dwCookie = 0 ); 
    STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL, 
      DWORD dwCookie = 0 ); 
    STDMETHODIMP GetInfo( AM_STREAM_INFO *pInfo); 
 
    // Helper function for pin's receive method.  Call this with 
    // the sample and we'll tell you what to do with it.  We'll do a 
    // WaitForSingleObject within this call if one is required.  This is 
    // a "What should I do with this sample?" kind of call. We'll tell the 
    // caller to either flow it or discard it. 
    // If pSample is NULL we evaluate based on the current state 
    // settings 
    enum StreamControlState CheckStreamState( IMediaSample * pSample ); 
 
private: 
    // These don't require locking, but we are relying on the fact that 
    // m_StreamState can be retrieved with integrity, and is a snap shot that 
    // may have just been, or may be just about to be, changed. 
    HANDLE GetStreamEventHandle() const { return m_StreamEvent; } 
    enum StreamControlState GetStreamState() const { return m_StreamState; } 
    BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; } 
}; 
 
#endif