403 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			403 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								// File: StrmCtl.cpp
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Desc: DirectShow base classes.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Copyright (c) 1996-2001 Microsoft Corporation.  All rights reserved.
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <streams.h>
							 | 
						||
| 
								 | 
							
								#include <strmctl.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CBaseStreamControl::CBaseStreamControl(__inout HRESULT *phr)
							 | 
						||
| 
								 | 
							
								: m_StreamState(STREAM_FLOWING)
							 | 
						||
| 
								 | 
							
								, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop
							 | 
						||
| 
								 | 
							
								, m_tStartTime(MAX_TIME)
							 | 
						||
| 
								 | 
							
								, m_tStopTime(MAX_TIME)
							 | 
						||
| 
								 | 
							
								, m_StreamEvent(FALSE, phr)
							 | 
						||
| 
								 | 
							
								, m_dwStartCookie(0)
							 | 
						||
| 
								 | 
							
								, m_dwStopCookie(0)
							 | 
						||
| 
								 | 
							
								, m_pRefClock(NULL)
							 | 
						||
| 
								 | 
							
								, m_FilterState(State_Stopped)
							 | 
						||
| 
								 | 
							
								, m_bIsFlushing(FALSE)
							 | 
						||
| 
								 | 
							
								, m_bStopSendExtra(FALSE)
							 | 
						||
| 
								 | 
							
								{}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CBaseStreamControl::~CBaseStreamControl()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Make sure we release the clock.
							 | 
						||
| 
								 | 
							
								    SetSyncSource(NULL);
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(&m_CritSec);
							 | 
						||
| 
								 | 
							
								    m_bStopSendExtra = FALSE;	// reset
							 | 
						||
| 
								 | 
							
								    m_bStopExtraSent = FALSE;
							 | 
						||
| 
								 | 
							
								    if (ptStop)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (*ptStop == MAX_TIME)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop")));
							 | 
						||
| 
								 | 
							
								            CancelStop();
							 | 
						||
| 
								 | 
							
									    // If there's now a command to start in the future, we assume
							 | 
						||
| 
								 | 
							
									    // they want to be stopped when the graph is first run
							 | 
						||
| 
								 | 
							
									    if (m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) {
							 | 
						||
| 
								 | 
							
									        m_StreamState = STREAM_DISCARDING;
							 | 
						||
| 
								 | 
							
								                DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								            return NOERROR;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"),
							 | 
						||
| 
								 | 
							
												(int)(*ptStop/10000), bSendExtra));
							 | 
						||
| 
								 | 
							
									// if the first command is to stop in the future, then we assume they
							 | 
						||
| 
								 | 
							
								        // want to be started when the graph is first run
							 | 
						||
| 
								 | 
							
									if (m_FilterState == State_Stopped && m_tStartTime > *ptStop) {
							 | 
						||
| 
								 | 
							
									    m_StreamState = STREAM_FLOWING;
							 | 
						||
| 
								 | 
							
								            DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								        m_bStopSendExtra = bSendExtra;
							 | 
						||
| 
								 | 
							
								        m_tStopTime = *ptStop;
							 | 
						||
| 
								 | 
							
								        m_dwStopCookie = dwCookie;
							 | 
						||
| 
								 | 
							
								        m_StreamStateOnStop = STREAM_DISCARDING;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        DbgLog((LOG_TRACE,2,TEXT("StopAt: now")));
							 | 
						||
| 
								 | 
							
									// sending an extra frame when told to stop now would mess people up
							 | 
						||
| 
								 | 
							
								        m_bStopSendExtra = FALSE;
							 | 
						||
| 
								 | 
							
								        m_tStopTime = MAX_TIME;
							 | 
						||
| 
								 | 
							
								        m_dwStopCookie = 0;
							 | 
						||
| 
								 | 
							
								        m_StreamState = STREAM_DISCARDING;
							 | 
						||
| 
								 | 
							
								        m_StreamStateOnStop = STREAM_FLOWING;	// no pending stop
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // we might change our mind what to do with a sample we're blocking
							 | 
						||
| 
								 | 
							
								    m_StreamEvent.Set();
							 | 
						||
| 
								 | 
							
								    return NOERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								STDMETHODIMP CBaseStreamControl::StartAt
							 | 
						||
| 
								 | 
							
								( const REFERENCE_TIME *ptStart, DWORD dwCookie )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(&m_CritSec);
							 | 
						||
| 
								 | 
							
								    if (ptStart)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (*ptStart == MAX_TIME)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start")));
							 | 
						||
| 
								 | 
							
								            CancelStart();
							 | 
						||
| 
								 | 
							
									    // If there's now a command to stop in the future, we assume
							 | 
						||
| 
								 | 
							
									    // they want to be started when the graph is first run
							 | 
						||
| 
								 | 
							
									    if (m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) {
							 | 
						||
| 
								 | 
							
								                DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
							 | 
						||
| 
								 | 
							
									        m_StreamState = STREAM_FLOWING;
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								            return NOERROR;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000)));
							 | 
						||
| 
								 | 
							
									// if the first command is to start in the future, then we assume they
							 | 
						||
| 
								 | 
							
								        // want to be stopped when the graph is first run
							 | 
						||
| 
								 | 
							
									if (m_FilterState == State_Stopped && m_tStopTime >= *ptStart) {
							 | 
						||
| 
								 | 
							
								            DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
							 | 
						||
| 
								 | 
							
									    m_StreamState = STREAM_DISCARDING;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								        m_tStartTime = *ptStart;
							 | 
						||
| 
								 | 
							
								        m_dwStartCookie = dwCookie;
							 | 
						||
| 
								 | 
							
								        // if (m_tStopTime == m_tStartTime) CancelStop();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        DbgLog((LOG_TRACE,2,TEXT("StartAt: now")));
							 | 
						||
| 
								 | 
							
								        m_tStartTime = MAX_TIME;
							 | 
						||
| 
								 | 
							
								        m_dwStartCookie = 0;
							 | 
						||
| 
								 | 
							
								        m_StreamState = STREAM_FLOWING;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // we might change our mind what to do with a sample we're blocking
							 | 
						||
| 
								 | 
							
								    m_StreamEvent.Set();
							 | 
						||
| 
								 | 
							
								    return NOERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//  Retrieve information about current settings
							 | 
						||
| 
								 | 
							
								STDMETHODIMP CBaseStreamControl::GetInfo(__out AM_STREAM_INFO *pInfo)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (pInfo == NULL)
							 | 
						||
| 
								 | 
							
									return E_POINTER;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    pInfo->tStart = m_tStartTime;
							 | 
						||
| 
								 | 
							
								    pInfo->tStop  = m_tStopTime;
							 | 
						||
| 
								 | 
							
								    pInfo->dwStartCookie = m_dwStartCookie;
							 | 
						||
| 
								 | 
							
								    pInfo->dwStopCookie  = m_dwStopCookie;
							 | 
						||
| 
								 | 
							
								    pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0;
							 | 
						||
| 
								 | 
							
								    pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED;
							 | 
						||
| 
								 | 
							
								    pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED;
							 | 
						||
| 
								 | 
							
								    switch (m_StreamState) {
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        DbgBreak("Invalid stream state");
							 | 
						||
| 
								 | 
							
								    case STREAM_FLOWING:
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case STREAM_DISCARDING:
							 | 
						||
| 
								 | 
							
								        pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING;
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return S_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void CBaseStreamControl::ExecuteStop()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    ASSERT(CritCheckIn(&m_CritSec));
							 | 
						||
| 
								 | 
							
								    m_StreamState = m_StreamStateOnStop;
							 | 
						||
| 
								 | 
							
								    if (m_dwStopCookie && m_pSink) {
							 | 
						||
| 
								 | 
							
									DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"),
							 | 
						||
| 
								 | 
							
															m_dwStopCookie));
							 | 
						||
| 
								 | 
							
								        m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    CancelStop(); // This will do the tidy up
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void CBaseStreamControl::ExecuteStart()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    ASSERT(CritCheckIn(&m_CritSec));
							 | 
						||
| 
								 | 
							
								    m_StreamState = STREAM_FLOWING;
							 | 
						||
| 
								 | 
							
								    if (m_dwStartCookie) {
							 | 
						||
| 
								 | 
							
									DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"),
							 | 
						||
| 
								 | 
							
															m_dwStartCookie));
							 | 
						||
| 
								 | 
							
								        m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    CancelStart(); // This will do the tidy up
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void CBaseStreamControl::CancelStop()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    ASSERT(CritCheckIn(&m_CritSec));
							 | 
						||
| 
								 | 
							
								    m_tStopTime = MAX_TIME;
							 | 
						||
| 
								 | 
							
								    m_dwStopCookie = 0;
							 | 
						||
| 
								 | 
							
								    m_StreamStateOnStop = STREAM_FLOWING;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void CBaseStreamControl::CancelStart()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    ASSERT(CritCheckIn(&m_CritSec));
							 | 
						||
| 
								 | 
							
								    m_tStartTime = MAX_TIME;
							 | 
						||
| 
								 | 
							
								    m_dwStartCookie = 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 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 *pSampleStart 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.
							 | 
						||
| 
								 | 
							
								//			I use pSampleStart (not Stop) so that live sources don't
							 | 
						||
| 
								 | 
							
								// 			block for the duration of their samples, since the clock
							 | 
						||
| 
								 | 
							
								//			will always read approximately pSampleStart when called
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// All through this code, you'll notice the following rules:
							 | 
						||
| 
								 | 
							
								// - When start and stop time are the same, it's as if start was first
							 | 
						||
| 
								 | 
							
								// - An event is considered inside the sample when it's >= sample start time
							 | 
						||
| 
								 | 
							
								//   but < sample stop time
							 | 
						||
| 
								 | 
							
								// - if any part of the sample is supposed to be sent, we'll send the whole
							 | 
						||
| 
								 | 
							
								//   thing since we don't break it into smaller pieces
							 | 
						||
| 
								 | 
							
								// - If we skip over a start or stop without doing it, we still signal the event
							 | 
						||
| 
								 | 
							
								//   and reset ourselves in case somebody's waiting for the event, and to make
							 | 
						||
| 
								 | 
							
								//   sure we notice that the event is past and should be forgotten
							 | 
						||
| 
								 | 
							
								// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample):
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// 1.	xo<-->		start then stop
							 | 
						||
| 
								 | 
							
								// 2.	ox<-->		stop then start
							 | 
						||
| 
								 | 
							
								// 3.	 x<o->		start
							 | 
						||
| 
								 | 
							
								// 4.	 o<x->		stop then start
							 | 
						||
| 
								 | 
							
								// 5.	 x<-->o		start
							 | 
						||
| 
								 | 
							
								// 6.	 o<-->x		stop
							 | 
						||
| 
								 | 
							
								// 7.	  <x->o		start
							 | 
						||
| 
								 | 
							
								// 8.	  <o->x		no change
							 | 
						||
| 
								 | 
							
								// 9.	  <xo>		start
							 | 
						||
| 
								 | 
							
								// 10.	  <ox>		stop then start
							 | 
						||
| 
								 | 
							
								// 11.	  <-->xo	no change
							 | 
						||
| 
								 | 
							
								// 12.	  <-->ox	no change
							 | 
						||
| 
								 | 
							
								// 13.	 x<-->		start
							 | 
						||
| 
								 | 
							
								// 14.    <x->		start
							 | 
						||
| 
								 | 
							
								// 15.    <-->x		no change
							 | 
						||
| 
								 | 
							
								// 16.   o<-->		stop
							 | 
						||
| 
								 | 
							
								// 17.	  <o->		no change
							 | 
						||
| 
								 | 
							
								// 18.	  <-->o		no change
							 | 
						||
| 
								 | 
							
								// 19.    <-->		no change
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes
							 | 
						||
| 
								 | 
							
								( __in const REFERENCE_TIME * pSampleStart, __in const REFERENCE_TIME * pSampleStop )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(&m_CritSec);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ASSERT(!m_bIsFlushing);
							 | 
						||
| 
								 | 
							
								    ASSERT(pSampleStart && pSampleStop);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Don't ask me how I came up with the code below to handle all 19 cases
							 | 
						||
| 
								 | 
							
								    // - DannyMi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (m_tStopTime >= *pSampleStart)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        if (m_tStartTime >= *pSampleStop)
							 | 
						||
| 
								 | 
							
									    return m_StreamState;		// cases  8 11 12 15 17 18 19
							 | 
						||
| 
								 | 
							
									if (m_tStopTime < m_tStartTime)
							 | 
						||
| 
								 | 
							
									    ExecuteStop();			// case 10
							 | 
						||
| 
								 | 
							
									ExecuteStart();                         // cases 3 5 7 9 13 14
							 | 
						||
| 
								 | 
							
									return m_StreamState;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (m_tStartTime >= *pSampleStop)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        ExecuteStop();                          // cases 6 16
							 | 
						||
| 
								 | 
							
								        return m_StreamState;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (m_tStartTime <= m_tStopTime)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
									ExecuteStart();
							 | 
						||
| 
								 | 
							
									ExecuteStop();
							 | 
						||
| 
								 | 
							
								        return m_StreamState;		// case 1
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
									ExecuteStop();
							 | 
						||
| 
								 | 
							
									ExecuteStart();
							 | 
						||
| 
								 | 
							
								        return m_StreamState;		// cases 2 4
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    REFERENCE_TIME rtBufferStart, rtBufferStop;
							 | 
						||
| 
								 | 
							
								    const BOOL bNoBufferTimes =
							 | 
						||
| 
								 | 
							
								              pSample == NULL ||
							 | 
						||
| 
								 | 
							
								              FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    StreamControlState state;
							 | 
						||
| 
								 | 
							
								    LONG lWait;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    do
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								 	    // something has to break out of the blocking
							 | 
						||
| 
								 | 
							
								            if (m_bIsFlushing || m_FilterState == State_Stopped)
							 | 
						||
| 
								 | 
							
										return STREAM_DISCARDING;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (bNoBufferTimes) {
							 | 
						||
| 
								 | 
							
								                //  Can't do anything until we get a time stamp
							 | 
						||
| 
								 | 
							
								                state = m_StreamState;
							 | 
						||
| 
								 | 
							
								                break;
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                state = CheckSampleTimes( &rtBufferStart, &rtBufferStop );
							 | 
						||
| 
								 | 
							
								                if (state == STREAM_FLOWING)
							 | 
						||
| 
								 | 
							
										    break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// we aren't supposed to send this, but we've been
							 | 
						||
| 
								 | 
							
										// told to send one more than we were supposed to
							 | 
						||
| 
								 | 
							
										// (and the stop isn't still pending and we're streaming)
							 | 
						||
| 
								 | 
							
										if (m_bStopSendExtra && !m_bStopExtraSent &&
							 | 
						||
| 
								 | 
							
													m_tStopTime == MAX_TIME &&
							 | 
						||
| 
								 | 
							
													m_FilterState != State_Stopped) {
							 | 
						||
| 
								 | 
							
										    m_bStopExtraSent = TRUE;
							 | 
						||
| 
								 | 
							
										    DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"),
							 | 
						||
| 
								 | 
							
															    m_dwStopCookie));
							 | 
						||
| 
								 | 
							
										    state = STREAM_FLOWING;
							 | 
						||
| 
								 | 
							
										    break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // We're in discarding mode
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // If we've no clock, discard as fast as we can
							 | 
						||
| 
								 | 
							
								            if (!m_pRefClock) {
							 | 
						||
| 
								 | 
							
										break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    // If we're paused, we can't discard in a timely manner because
							 | 
						||
| 
								 | 
							
									    // there's no such thing as stream times.  We must block until
							 | 
						||
| 
								 | 
							
									    // we run or stop, or we'll end up throwing the whole stream away
							 | 
						||
| 
								 | 
							
									    // as quickly as possible
							 | 
						||
| 
								 | 
							
									    } else if (m_FilterState == State_Paused) {
							 | 
						||
| 
								 | 
							
										lWait = INFINITE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    } else {
							 | 
						||
| 
								 | 
							
									        // wait until it's time for the sample until we say "discard"
							 | 
						||
| 
								 | 
							
									        // ("discard in a timely fashion")
							 | 
						||
| 
								 | 
							
									        REFERENCE_TIME rtNow;
							 | 
						||
| 
								 | 
							
								                EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow)));
							 | 
						||
| 
								 | 
							
								                rtNow -= m_tRunStart;   // Into relative ref-time
							 | 
						||
| 
								 | 
							
								                lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms
							 | 
						||
| 
								 | 
							
								                if (lWait < 10) break; // Not worth waiting - discard early
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    } while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return state;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart )
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(&m_CritSec);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // or we will get confused
							 | 
						||
| 
								 | 
							
								    if (m_FilterState == new_state)
							 | 
						||
| 
								 | 
							
									return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switch (new_state)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        case State_Stopped:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED")));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    // execute any pending starts and stops in the right order,
							 | 
						||
| 
								 | 
							
									    // to make sure all notifications get sent, and we end up
							 | 
						||
| 
								 | 
							
									    // in the right state to begin next time (??? why not?)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    if (m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) {
							 | 
						||
| 
								 | 
							
										ExecuteStart();
							 | 
						||
| 
								 | 
							
									    } else if (m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) {
							 | 
						||
| 
								 | 
							
										ExecuteStop();
							 | 
						||
| 
								 | 
							
									    } else if (m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) {
							 | 
						||
| 
								 | 
							
										if (m_tStartTime <= m_tStopTime) {
							 | 
						||
| 
								 | 
							
										    ExecuteStart();
							 | 
						||
| 
								 | 
							
										    ExecuteStop();
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
										    ExecuteStop();
							 | 
						||
| 
								 | 
							
										    ExecuteStart();
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
									    // always start off flowing when the graph starts streaming
							 | 
						||
| 
								 | 
							
									    // unless told otherwise
							 | 
						||
| 
								 | 
							
									    m_StreamState = STREAM_FLOWING;
							 | 
						||
| 
								 | 
							
								            m_FilterState = new_state;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        case State_Running:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING")));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            m_tRunStart = tStart;
							 | 
						||
| 
								 | 
							
								            // fall-through
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        default: // case State_Paused:
							 | 
						||
| 
								 | 
							
								            m_FilterState = new_state;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // unblock!
							 | 
						||
| 
								 | 
							
								    m_StreamEvent.Set();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void CBaseStreamControl::Flushing(BOOL bInProgress)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(&m_CritSec);
							 | 
						||
| 
								 | 
							
								    m_bIsFlushing = bInProgress;
							 | 
						||
| 
								 | 
							
								    m_StreamEvent.Set();
							 | 
						||
| 
								 | 
							
								}
							 |