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