00001
00002
00003
00004
00005
00006 #include <streams.h>
00007 #include <strmctl.h>
00008
00009 CBaseStreamControl::CBaseStreamControl()
00010 : m_StreamState(STREAM_FLOWING)
00011 , m_StreamStateOnStop(STREAM_FLOWING)
00012 , m_tStartTime(MAX_TIME)
00013 , m_tStopTime(MAX_TIME)
00014 , m_dwStartCookie(0)
00015 , m_dwStopCookie(0)
00016 , m_pRefClock(NULL)
00017 , m_FilterState(State_Stopped)
00018 , m_bIsFlushing(FALSE)
00019 , m_bStopSendExtra(FALSE)
00020 {}
00021
00022 CBaseStreamControl::~CBaseStreamControl()
00023 {
00024
00025 SetSyncSource(NULL);
00026 return;
00027 }
00028
00029 STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie)
00030 {
00031 CAutoLock lck(&m_CritSec);
00032 m_bStopSendExtra = FALSE;
00033 m_bStopExtraSent = FALSE;
00034 if (ptStop)
00035 {
00036 if (*ptStop == MAX_TIME)
00037 {
00038 DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop")));
00039 CancelStop();
00040
00041
00042 if (m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) {
00043 m_StreamState = STREAM_DISCARDING;
00044 DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
00045 }
00046 return NOERROR;
00047 }
00048 DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"),
00049 (int)(*ptStop/10000), bSendExtra));
00050
00051
00052 if (m_FilterState == State_Stopped && m_tStartTime > *ptStop) {
00053 m_StreamState = STREAM_FLOWING;
00054 DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
00055 }
00056 m_bStopSendExtra = bSendExtra;
00057 m_tStopTime = *ptStop;
00058 m_dwStopCookie = dwCookie;
00059 m_StreamStateOnStop = STREAM_DISCARDING;
00060 }
00061 else
00062 {
00063 DbgLog((LOG_TRACE,2,TEXT("StopAt: now")));
00064
00065 m_bStopSendExtra = FALSE;
00066 m_tStopTime = MAX_TIME;
00067 m_dwStopCookie = 0;
00068 m_StreamState = STREAM_DISCARDING;
00069 m_StreamStateOnStop = STREAM_FLOWING;
00070 }
00071
00072 m_StreamEvent.Set();
00073 return NOERROR;
00074 }
00075
00076 STDMETHODIMP CBaseStreamControl::StartAt
00077 ( const REFERENCE_TIME *ptStart, DWORD dwCookie )
00078 {
00079 CAutoLock lck(&m_CritSec);
00080 if (ptStart)
00081 {
00082 if (*ptStart == MAX_TIME)
00083 {
00084 DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start")));
00085 CancelStart();
00086
00087
00088 if (m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) {
00089 DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
00090 m_StreamState = STREAM_FLOWING;
00091 }
00092 return NOERROR;
00093 }
00094 DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000)));
00095
00096
00097 if (m_FilterState == State_Stopped && m_tStopTime >= *ptStart) {
00098 DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
00099 m_StreamState = STREAM_DISCARDING;
00100 }
00101 m_tStartTime = *ptStart;
00102 m_dwStartCookie = dwCookie;
00103
00104 }
00105 else
00106 {
00107 DbgLog((LOG_TRACE,2,TEXT("StartAt: now")));
00108 m_tStartTime = MAX_TIME;
00109 m_dwStartCookie = 0;
00110 m_StreamState = STREAM_FLOWING;
00111 }
00112
00113 m_StreamEvent.Set();
00114 return NOERROR;
00115 }
00116
00117 STDMETHODIMP CBaseStreamControl::GetInfo(AM_STREAM_INFO *pInfo)
00118 {
00119 if (pInfo == NULL)
00120 return E_POINTER;
00121
00122 pInfo->tStart = m_tStartTime;
00123 pInfo->tStop = m_tStopTime;
00124 pInfo->dwStartCookie = m_dwStartCookie;
00125 pInfo->dwStopCookie = m_dwStopCookie;
00126 pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0;
00127 pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED;
00128 pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED;
00129 switch (m_StreamState) {
00130 default:
00131 DbgBreak("Invalid stream state");
00132 case STREAM_FLOWING:
00133 break;
00134 case STREAM_DISCARDING:
00135 pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING;
00136 break;
00137 }
00138 return S_OK;
00139 }
00140
00141 void CBaseStreamControl::ExecuteStop()
00142 {
00143 ASSERT(CritCheckIn(&m_CritSec));
00144 m_StreamState = m_StreamStateOnStop;
00145 if (m_dwStopCookie && m_pSink) {
00146 DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"),
00147 m_dwStopCookie));
00148 m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie);
00149 }
00150 CancelStop();
00151 }
00152
00153 void CBaseStreamControl::ExecuteStart()
00154 {
00155 ASSERT(CritCheckIn(&m_CritSec));
00156 m_StreamState = STREAM_FLOWING;
00157 if (m_dwStartCookie) {
00158 DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"),
00159 m_dwStartCookie));
00160 m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie);
00161 }
00162 CancelStart();
00163 }
00164
00165 void CBaseStreamControl::CancelStop()
00166 {
00167 ASSERT(CritCheckIn(&m_CritSec));
00168 m_tStopTime = MAX_TIME;
00169 m_dwStopCookie = 0;
00170 m_StreamStateOnStop = STREAM_FLOWING;
00171 }
00172
00173 void CBaseStreamControl::CancelStart()
00174 {
00175 ASSERT(CritCheckIn(&m_CritSec));
00176 m_tStartTime = MAX_TIME;
00177 m_dwStartCookie = 0;
00178 }
00179
00180 enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes
00181 ( const REFERENCE_TIME * pSampleStart, const REFERENCE_TIME * pSampleStop )
00182 {
00183 CAutoLock lck(&m_CritSec);
00184
00185 ASSERT(!m_bIsFlushing);
00186 ASSERT(pSampleStart && pSampleStop);
00187
00188
00189
00190
00191 if (m_tStopTime >= *pSampleStart)
00192 {
00193 if (m_tStartTime >= *pSampleStop)
00194 return m_StreamState;
00195 if (m_tStopTime < m_tStartTime)
00196 ExecuteStop();
00197 ExecuteStart();
00198 return m_StreamState;
00199 }
00200
00201 if (m_tStartTime >= *pSampleStop)
00202 {
00203 ExecuteStop();
00204 return m_StreamState;
00205 }
00206
00207 if (m_tStartTime <= m_tStopTime)
00208 {
00209 ExecuteStart();
00210 ExecuteStop();
00211 return m_StreamState;
00212 }
00213 else
00214 {
00215 ExecuteStop();
00216 ExecuteStart();
00217 return m_StreamState;
00218 }
00219 }
00220
00221 enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample )
00222 {
00223
00224 REFERENCE_TIME rtBufferStart, rtBufferStop;
00225 const BOOL bNoBufferTimes =
00226 pSample == NULL ||
00227 FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop));
00228
00229 StreamControlState state;
00230 LONG lWait;
00231
00232 do
00233 {
00234
00235 if (m_bIsFlushing || m_FilterState == State_Stopped)
00236 return STREAM_DISCARDING;
00237
00238 if (bNoBufferTimes) {
00239
00240 state = m_StreamState;
00241 break;
00242 } else {
00243 state = CheckSampleTimes( &rtBufferStart, &rtBufferStop );
00244 if (state == STREAM_FLOWING)
00245 break;
00246
00247
00248
00249
00250 if (m_bStopSendExtra && !m_bStopExtraSent &&
00251 m_tStopTime == MAX_TIME &&
00252 m_FilterState != State_Stopped) {
00253 m_bStopExtraSent = TRUE;
00254 DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"),
00255 m_dwStopCookie));
00256 state = STREAM_FLOWING;
00257 break;
00258 }
00259 }
00260
00261
00262
00263
00264 if (!m_pRefClock) {
00265 break;
00266
00267
00268
00269
00270
00271 } else if (m_FilterState == State_Paused) {
00272 lWait = INFINITE;
00273
00274 } else {
00275
00276
00277 REFERENCE_TIME rtNow;
00278 EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow)));
00279 rtNow -= m_tRunStart;
00280 lWait = LONG((rtBufferStart - rtNow)/10000);
00281 if (lWait < 10) break;
00282 }
00283
00284 } while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT);
00285
00286 return state;
00287 }
00288
00289 void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart )
00290 {
00291 CAutoLock lck(&m_CritSec);
00292
00293
00294 if (m_FilterState == new_state)
00295 return;
00296
00297 switch (new_state)
00298 {
00299 case State_Stopped:
00300
00301 DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED")));
00302
00303
00304
00305
00306
00307 if (m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) {
00308 ExecuteStart();
00309 } else if (m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) {
00310 ExecuteStop();
00311 } else if (m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) {
00312 if (m_tStartTime <= m_tStopTime) {
00313 ExecuteStart();
00314 ExecuteStop();
00315 } else {
00316 ExecuteStop();
00317 ExecuteStart();
00318 }
00319 }
00320
00321
00322 m_StreamState = STREAM_FLOWING;
00323 m_FilterState = new_state;
00324 break;
00325
00326 case State_Running:
00327
00328 DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING")));
00329
00330 m_tRunStart = tStart;
00331
00332
00333 default:
00334 m_FilterState = new_state;
00335 }
00336
00337 m_StreamEvent.Set();
00338 }
00339
00340 void CBaseStreamControl::Flushing(BOOL bInProgress)
00341 {
00342 CAutoLock lck(&m_CritSec);
00343 m_bIsFlushing = bInProgress;
00344 m_StreamEvent.Set();
00345 }