//------------------------------------------------------------------------------ | |
// File: StrmCtl.h | |
// | |
// Desc: DirectShow base classes. | |
// | |
// Copyright (c) 1996-2001 Microsoft 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 StreamControlState m_StreamState; // Current stream state | |
enum StreamControlState m_StreamStateOnStop; // State after next stop | |
// (i.e.Blocking or Discarding) | |
REFERENCE_TIME m_tStartTime; // MAX_TIME implies none | |
REFERENCE_TIME m_tStopTime; // MAX_TIME implies none | |
DWORD m_dwStartCookie; // Cookie for notification to app | |
DWORD m_dwStopCookie; // Cookie for notification to app | |
volatile BOOL m_bIsFlushing; // No optimization pls! | |
volatile BOOL m_bStopSendExtra; // bSendExtra was set | |
volatile BOOL m_bStopExtraSent; // the extra one was sent | |
CCritSec m_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. | |
// | |
CAMEvent m_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_STATE m_FilterState; // Just need it! | |
// Filter must tell us via | |
// NotifyFilterState | |
REFERENCE_TIME m_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( __in const REFERENCE_TIME * pSampleStart, | |
__in 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(__inout_opt HRESULT *phr = NULL); | |
~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! | |
// 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( __out 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 |