strmctl.cpp
上传用户:liguizhu
上传日期:2015-11-01
资源大小:2422k
文件大小:13k
源码类别:

P2P编程

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // File: StrmCtl.cpp
  3. //
  4. // Desc: DirectShow base classes.
  5. //
  6. // Copyright (c) Microsoft Corporation.  All rights reserved.
  7. //------------------------------------------------------------------------------
  8. #include <streams.h>
  9. #include <strmctl.h>
  10. CBaseStreamControl::CBaseStreamControl()
  11. : m_StreamState(STREAM_FLOWING)
  12. , m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop
  13. , m_tStartTime(MAX_TIME)
  14. , m_tStopTime(MAX_TIME)
  15. , m_dwStartCookie(0)
  16. , m_dwStopCookie(0)
  17. , m_pRefClock(NULL)
  18. , m_FilterState(State_Stopped)
  19. , m_bIsFlushing(FALSE)
  20. , m_bStopSendExtra(FALSE)
  21. {}
  22. CBaseStreamControl::~CBaseStreamControl()
  23. {
  24.     // Make sure we release the clock.
  25.     SetSyncSource(NULL);
  26.     return;
  27. }
  28. STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie)
  29. {
  30.     CAutoLock lck(&m_CritSec);
  31.     m_bStopSendExtra = FALSE; // reset
  32.     m_bStopExtraSent = FALSE;
  33.     if (ptStop)
  34.     {
  35.         if (*ptStop == MAX_TIME)
  36.         {
  37.             DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop")));
  38.             CancelStop();
  39.     // If there's now a command to start in the future, we assume
  40.     // they want to be stopped when the graph is first run
  41.     if (m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) {
  42.         m_StreamState = STREAM_DISCARDING;
  43.                 DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
  44.     }
  45.             return NOERROR;
  46.         }
  47.         DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"),
  48. (int)(*ptStop/10000), bSendExtra));
  49. // if the first command is to stop in the future, then we assume they
  50.         // want to be started when the graph is first run
  51. if (m_FilterState == State_Stopped && m_tStartTime > *ptStop) {
  52.     m_StreamState = STREAM_FLOWING;
  53.             DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
  54. }
  55.         m_bStopSendExtra = bSendExtra;
  56.         m_tStopTime = *ptStop;
  57.         m_dwStopCookie = dwCookie;
  58.         m_StreamStateOnStop = STREAM_DISCARDING;
  59.     }
  60.     else
  61.     {
  62.         DbgLog((LOG_TRACE,2,TEXT("StopAt: now")));
  63. // sending an extra frame when told to stop now would mess people up
  64.         m_bStopSendExtra = FALSE;
  65.         m_tStopTime = MAX_TIME;
  66.         m_dwStopCookie = 0;
  67.         m_StreamState = STREAM_DISCARDING;
  68.         m_StreamStateOnStop = STREAM_FLOWING; // no pending stop
  69.     }
  70.     // we might change our mind what to do with a sample we're blocking
  71.     m_StreamEvent.Set();
  72.     return NOERROR;
  73. }
  74. STDMETHODIMP CBaseStreamControl::StartAt
  75. ( const REFERENCE_TIME *ptStart, DWORD dwCookie )
  76. {
  77.     CAutoLock lck(&m_CritSec);
  78.     if (ptStart)
  79.     {
  80.         if (*ptStart == MAX_TIME)
  81.         {
  82.             DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start")));
  83.             CancelStart();
  84.     // If there's now a command to stop in the future, we assume
  85.     // they want to be started when the graph is first run
  86.     if (m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) {
  87.                 DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
  88.         m_StreamState = STREAM_FLOWING;
  89.     }
  90.             return NOERROR;
  91.         }
  92.         DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000)));
  93. // if the first command is to start in the future, then we assume they
  94.         // want to be stopped when the graph is first run
  95. if (m_FilterState == State_Stopped && m_tStopTime >= *ptStart) {
  96.             DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
  97.     m_StreamState = STREAM_DISCARDING;
  98. }
  99.         m_tStartTime = *ptStart;
  100.         m_dwStartCookie = dwCookie;
  101.         // if (m_tStopTime == m_tStartTime) CancelStop();
  102.     }
  103.     else
  104.     {
  105.         DbgLog((LOG_TRACE,2,TEXT("StartAt: now")));
  106.         m_tStartTime = MAX_TIME;
  107.         m_dwStartCookie = 0;
  108.         m_StreamState = STREAM_FLOWING;
  109.     }
  110.     // we might change our mind what to do with a sample we're blocking
  111.     m_StreamEvent.Set();
  112.     return NOERROR;
  113. }
  114. //  Retrieve information about current settings
  115. STDMETHODIMP CBaseStreamControl::GetInfo(AM_STREAM_INFO *pInfo)
  116. {
  117.     if (pInfo == NULL)
  118. return E_POINTER;
  119.     pInfo->tStart = m_tStartTime;
  120.     pInfo->tStop  = m_tStopTime;
  121.     pInfo->dwStartCookie = m_dwStartCookie;
  122.     pInfo->dwStopCookie  = m_dwStopCookie;
  123.     pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0;
  124.     pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED;
  125.     pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED;
  126.     switch (m_StreamState) {
  127.     default:
  128.         DbgBreak("Invalid stream state");
  129.     case STREAM_FLOWING:
  130.         break;
  131.     case STREAM_DISCARDING:
  132.         pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING;
  133.         break;
  134.     }
  135.     return S_OK;
  136. }
  137. void CBaseStreamControl::ExecuteStop()
  138. {
  139.     ASSERT(CritCheckIn(&m_CritSec));
  140.     m_StreamState = m_StreamStateOnStop;
  141.     if (m_dwStopCookie && m_pSink) {
  142. DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"),
  143. m_dwStopCookie));
  144.         m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie);
  145.     }
  146.     CancelStop(); // This will do the tidy up
  147. }
  148. void CBaseStreamControl::ExecuteStart()
  149. {
  150.     ASSERT(CritCheckIn(&m_CritSec));
  151.     m_StreamState = STREAM_FLOWING;
  152.     if (m_dwStartCookie) {
  153. DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"),
  154. m_dwStartCookie));
  155.         m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie);
  156.     }
  157.     CancelStart(); // This will do the tidy up
  158. }
  159. void CBaseStreamControl::CancelStop()
  160. {
  161.     ASSERT(CritCheckIn(&m_CritSec));
  162.     m_tStopTime = MAX_TIME;
  163.     m_dwStopCookie = 0;
  164.     m_StreamStateOnStop = STREAM_FLOWING;
  165. }
  166. void CBaseStreamControl::CancelStart()
  167. {
  168.     ASSERT(CritCheckIn(&m_CritSec));
  169.     m_tStartTime = MAX_TIME;
  170.     m_dwStartCookie = 0;
  171. }
  172. // This guy will return one of the three StreamControlState's.  Here's what the caller
  173. // should do for each one:
  174. //
  175. // STREAM_FLOWING:      Proceed as usual (render or pass the sample on)
  176. // STREAM_DISCARDING:   Calculate the time 'til *pSampleStart and wait that long
  177. //                      for the event handle (GetStreamEventHandle()).  If the
  178. //                      wait expires, throw the sample away.  If the event
  179. // fires, call me back, I've changed my mind.
  180. // I use pSampleStart (not Stop) so that live sources don't
  181. //  block for the duration of their samples, since the clock
  182. // will always read approximately pSampleStart when called
  183. // All through this code, you'll notice the following rules:
  184. // - When start and stop time are the same, it's as if start was first
  185. // - An event is considered inside the sample when it's >= sample start time
  186. //   but < sample stop time
  187. // - if any part of the sample is supposed to be sent, we'll send the whole
  188. //   thing since we don't break it into smaller pieces
  189. // - If we skip over a start or stop without doing it, we still signal the event
  190. //   and reset ourselves in case somebody's waiting for the event, and to make
  191. //   sure we notice that the event is past and should be forgotten
  192. // Here are the 19 cases that have to be handled (x=start o=stop <-->=sample):
  193. //
  194. // 1. xo<--> start then stop
  195. // 2. ox<--> stop then start
  196. // 3.  x<o-> start
  197. // 4.  o<x-> stop then start
  198. // 5.  x<-->o start
  199. // 6.  o<-->x stop
  200. // 7.   <x->o start
  201. // 8.   <o->x no change
  202. // 9.   <xo> start
  203. // 10.   <ox> stop then start
  204. // 11.   <-->xo no change
  205. // 12.   <-->ox no change
  206. // 13.  x<--> start
  207. // 14.    <x-> start
  208. // 15.    <-->x no change
  209. // 16.   o<--> stop
  210. // 17.   <o-> no change
  211. // 18.   <-->o no change
  212. // 19.    <--> no change
  213. enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes
  214. ( const REFERENCE_TIME * pSampleStart, const REFERENCE_TIME * pSampleStop )
  215. {
  216.     CAutoLock lck(&m_CritSec);
  217.     ASSERT(!m_bIsFlushing);
  218.     ASSERT(pSampleStart && pSampleStop);
  219.     // Don't ask me how I came up with the code below to handle all 19 cases
  220.     // - DannyMi
  221.     if (m_tStopTime >= *pSampleStart)
  222.     {
  223.         if (m_tStartTime >= *pSampleStop)
  224.     return m_StreamState; // cases  8 11 12 15 17 18 19
  225. if (m_tStopTime < m_tStartTime)
  226.     ExecuteStop(); // case 10
  227. ExecuteStart();                         // cases 3 5 7 9 13 14
  228. return m_StreamState;
  229.     }
  230.     if (m_tStartTime >= *pSampleStop)
  231.     {
  232.         ExecuteStop();                          // cases 6 16
  233.         return m_StreamState;
  234.     }
  235.     if (m_tStartTime <= m_tStopTime)
  236.     {
  237. ExecuteStart();
  238. ExecuteStop();
  239.         return m_StreamState; // case 1
  240.     }
  241.     else
  242.     {
  243. ExecuteStop();
  244. ExecuteStart();
  245.         return m_StreamState; // cases 2 4
  246.     }
  247. }
  248. enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample )
  249. {
  250.     REFERENCE_TIME rtBufferStart, rtBufferStop;
  251.     const BOOL bNoBufferTimes =
  252.               pSample == NULL ||
  253.               FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop));
  254.     StreamControlState state;
  255.     LONG lWait;
  256.     do
  257.         {
  258.       // something has to break out of the blocking
  259.             if (m_bIsFlushing || m_FilterState == State_Stopped)
  260. return STREAM_DISCARDING;
  261.             if (bNoBufferTimes) {
  262.                 //  Can't do anything until we get a time stamp
  263.                 state = m_StreamState;
  264.                 break;
  265.             } else {
  266.                 state = CheckSampleTimes( &rtBufferStart, &rtBufferStop );
  267.                 if (state == STREAM_FLOWING)
  268.     break;
  269. // we aren't supposed to send this, but we've been
  270. // told to send one more than we were supposed to
  271. // (and the stop isn't still pending and we're streaming)
  272. if (m_bStopSendExtra && !m_bStopExtraSent &&
  273. m_tStopTime == MAX_TIME &&
  274. m_FilterState != State_Stopped) {
  275.     m_bStopExtraSent = TRUE;
  276.     DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"),
  277.     m_dwStopCookie));
  278.     state = STREAM_FLOWING;
  279.     break;
  280. }
  281.             }
  282.             // We're in discarding mode
  283.             // If we've no clock, discard as fast as we can
  284.             if (!m_pRefClock) {
  285. break;
  286.     // If we're paused, we can't discard in a timely manner because
  287.     // there's no such thing as stream times.  We must block until
  288.     // we run or stop, or we'll end up throwing the whole stream away
  289.     // as quickly as possible
  290.     } else if (m_FilterState == State_Paused) {
  291. lWait = INFINITE;
  292.     } else {
  293.         // wait until it's time for the sample until we say "discard"
  294.         // ("discard in a timely fashion")
  295.         REFERENCE_TIME rtNow;
  296.                 EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow)));
  297.                 rtNow -= m_tRunStart;   // Into relative ref-time
  298.                 lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms
  299.                 if (lWait < 10) break; // Not worth waiting - discard early
  300.     }
  301.     } while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT);
  302.     return state;
  303. }
  304. void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart )
  305. {
  306.     CAutoLock lck(&m_CritSec);
  307.     // or we will get confused
  308.     if (m_FilterState == new_state)
  309. return;
  310.     switch (new_state)
  311.     {
  312.         case State_Stopped:
  313.             DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED")));
  314.     // execute any pending starts and stops in the right order,
  315.     // to make sure all notifications get sent, and we end up
  316.     // in the right state to begin next time (??? why not?)
  317.     if (m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) {
  318. ExecuteStart();
  319.     } else if (m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) {
  320. ExecuteStop();
  321.     } else if (m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) {
  322. if (m_tStartTime <= m_tStopTime) {
  323.     ExecuteStart();
  324.     ExecuteStop();
  325. } else {
  326.     ExecuteStop();
  327.     ExecuteStart();
  328. }
  329.     }
  330.     // always start off flowing when the graph starts streaming
  331.     // unless told otherwise
  332.     m_StreamState = STREAM_FLOWING;
  333.             m_FilterState = new_state;
  334.             break;
  335.         case State_Running:
  336.             DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING")));
  337.             m_tRunStart = tStart;
  338.             // fall-through
  339.         default: // case State_Paused:
  340.             m_FilterState = new_state;
  341.     }
  342.     // unblock!
  343.     m_StreamEvent.Set();
  344. }
  345. void CBaseStreamControl::Flushing(BOOL bInProgress)
  346. {
  347.     CAutoLock lck(&m_CritSec);
  348.     m_bIsFlushing = bInProgress;
  349.     m_StreamEvent.Set();
  350. }