DirectShow 学习(四):部分Helper Classes类源代码分析

来源:百度文库 编辑:神马文学网 时间:2024/04/30 22:09:11
DirectShow 学习(四):部分Helper Classes类源代码分析

  1. CRefTime[reftime.h]
    CRefTime类维护了REFERENCE_TIME m_time;的成员变量。单位为100ns
    另外,几个跟该类相关的宏:
    const LONGLONG MILLISECONDS = (1000);            // 10 ^ 3
    const LONGLONG NANOSECONDS = (1000000000);       // 10 ^ 9
    const LONGLONG UNITS = (NANOSECONDS / 100);      // 10 ^ 7
    #define MILLISECONDS_TO_100NS_UNITS(lMs) \
        Int32x32To64((lMs), (UNITS / MILLISECONDS))
    inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT)
    {return (RT / (UNITS / MILLISECONDS));}
  2. IBaseReferenceClock接口
    ReferenceClock : public IUnknown
    {
    public:
        // Retrieves the current reference time.
        virtual HRESULT STDMETHODCALLTYPE GetTime(
            /* [out] */ REFERENCE_TIME *pTime) = 0;
        // Creates a one-shot advise request.
        virtual HRESULT STDMETHODCALLTYPE AdviseTime(
            /* [in] */ REFERENCE_TIME baseTime,
            /* [in] */ REFERENCE_TIME streamTime,
            /* [in] */ HEVENT hEvent,
            /* [out] */ DWORD_PTR *pdwAdviseCookie) = 0;
       // Creates a periodic advise request.
       virtual HRESULT STDMETHODCALLTYPE AdvisePeriodic(
            /* [in] */ REFERENCE_TIME startTime,
            /* [in] */ REFERENCE_TIME periodTime,
            /* [in] */ HSEMAPHORE hSemaphore,
            /* [out] */ DWORD_PTR *pdwAdviseCookie) = 0;
       // Removes a pending advise request.
       virtual HRESULT STDMETHODCALLTYPE Unadvise(
            /* [in] */ DWORD_PTR dwAdviseCookie) = 0;
    };
  3. CCritSecCAutoLock[wxutil.h/wxutil.cpp]
    CCritSec封装了CRITICAL_SECTION m_CritSec;成员变量,通过函数Lock()和Unlock对该变量进行EnterCriticalSectionLeaveCriticalSection,同时,Constructor和Deconstructor分别调用了InitializeCriticalSectionDeleteCriticalSection函数。
    CAutoLock是和CCritSec配合使用的Helper类,它在Constructor中接受一个CCritSec的指针,并对其调用Lock函数,而在Deconstructor调用Unlock函数
  4. CAMSchedule[dsschedule.h/schedule.cpp]
    派生自 CBaseObject
    其实此类就是一个List,Node是类型CAdvisePacket。具体解析略。
  5. CBaseReferenceClock[refclock.h/refclock.cpp]
    继承了IReferenceClock接口,同时派生自CUnknown、CCritSec。
    • 成员变量:
      REFERENCE_TIME m_rtPrivateTime;     // Current best estimate of time
      DWORD          m_dwPrevSystemTime;  // Last vaule we got from timeGetTime
      REFERENCE_TIME m_rtLastGotTime;     // Last time returned by GetTime
      REFERENCE_TIME m_rtNextAdvise;      // Time of next advise
      UINT           m_TimerResolution;
      BOOL           m_bAbort;            // Flag used for thread shutdown
      HANDLE         m_hThread;           // Thread handle
      CAMSchedule * const m_pSchedule; // 任务列表
      // 一个Static函数
      static DWORD __stdcall AdviseThreadFunction(LPVOID); // Function used to get there
    • IReferenceClock接口函数:
      STDMETHODIMP GetTime(REFERENCE_TIME *pTime);
      {
              // 首先调用Lock(),然后rtNow = GetPrivateTime();
              // 判断(rtNow > m_rtLastGotTime),是则m_rtLastGotTime = rtNow;否则设置返回值为S_FALSE
              // 设置返回值 *pTime = m_rtLastGotTime;
      }
      /* Ask for an async notification that a time has elapsed */
      STDMETHODIMP AdviseTime(
          REFERENCE_TIME baseTime,        // base reference time
          REFERENCE_TIME streamTime,      // stream offset time
          HEVENT hEvent,                  // advise via this event
          DWORD_PTR *pdwAdviseCookie          // where your cookie goes
      );
      {
                // 首先初始化输出变量 *pdwAdviseCookie = 0;
                // 判断 ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0));
                // 得到当前绝对时间 const REFERENCE_TIME lRefTime = baseTime + streamTime;
                // *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( lRefTime, 0, HANDLE(hEvent), FALSE );
      }
      /* Ask for an asynchronous periodic notification that a time has elapsed */
      STDMETHODIMP AdvisePeriodic(
          REFERENCE_TIME StartTime,       // starting at this time
          REFERENCE_TIME PeriodTime,      // time between notifications
          HSEMAPHORE hSemaphore,          // advise via a semaphore
          DWORD_PTR *pdwAdviseCookie          // where your cookie goes
      );
      {
              // 同样,首先初始化输出变量
              // *pdwAdviseCookie = m_pSchedule->AddAdvisePacket( StartTime, PeriodTime, HANDLE(hSemaphore), TRUE );
      }
      STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie);
      {
              return m_pSchedule->Unadvise(dwAdviseCookie);
      }
    • 新增加的virtual函数:
      virtual REFERENCE_TIME GetPrivateTime();
      {
              CAutoLock cObjectLock(this);
              DWORD dwTime = timeGetTime();
              m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime));
               m_dwPrevSystemTime = dwTime;
               return m_rtPrivateTime;
      }
    • 普通成员函数:
      /* Provide a method for correcting drift */
      STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta );
      {
                CAutoLock cObjectLock(this);
                m_rtPrivateTime += TimeDelta;
                if ( TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0 ) TriggerThread();
                return NOERROR;
      }
      CAMSchedule * GetSchedule() const { return m_pSchedule; }
      void TriggerThread()                 // Wakes thread up.  Need to do this if
      {      // time to next advise needs reevaluating.
              EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent()));
      }
      DWORD __stdcall AdviseThreadFunction(LPVOID p)
      {
                 return DWORD(reinterpret_cast(p)->AdviseThread());
      }
      // Method in which the advise thread runs
      HRESULT AdviseThread()
      {
              DWORD dwWait = INFINITE;
              while ( !m_bAbort )
             {
                       WaitForSingleObject(m_pSchedule->GetEvent(), dwWait);
                       if (m_bAbort) break;
                       const REFERENCE_TIME  rtNow = GetPrivateTime();
                       m_rtNextAdvise = m_pSchedule->Advise( 10000 + rtNow );
                       LONGLONG llWait = m_rtNextAdvise - rtNow;
                       llWait = ConvertToMilliseconds(llWait);
                      // DON'T replace this with a max!! (The type's of these things is VERY important)
                      dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait);
             }
      }
    • Deconstructor:
      CBaseReferenceClock::~CBaseReferenceClock()
      {
               if (m_TimerResolution) timeEndPeriod(m_TimerResolution);
              m_pSchedule->DumpLinkedList();
              // 如果m_hThread存在,设置m_bAbort为TRUE后调用TriggerThread(),
              // 然后等Thread结束:WaitForSingleObject( m_hThread, INFINITE );
              // 关闭Thread的handle::EXECUTE_ASSERT( CloseHandle(m_hThread) );
              // m_hThread = 0;
              // 清除任务列表的Event Handle:EXECUTE_ASSERT( CloseHandle(m_pSchedule->GetEvent()) );
      }
    • Constructor:
      CBaseReferenceClock::CBaseReferenceClock( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pShed )
      : CUnknown( pName, pUnk ) , m_rtLastGotTime(0) , m_TimerResolution(0) , m_bAbort( FALSE )
      , m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) ) , m_hThread(0)
      {
               // 判断m_pSchedule是否为空,如果为空则直接返回错误
               TIMECAPS tc;
               m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc))) ? tc.wPeriodMin: 1;
               timeBeginPeriod(m_TimerResolution);
               /* Initialise our system times - the derived clock should set the right values */
              m_dwPrevSystemTime = timeGetTime();
              m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime;
             if ( !pShed )
            {
                  DWORD ThreadID;
                 m_hThread = ::CreateThread(NULL,                  // Security attributes
                         (DWORD) 0,             // Initial stack size
                        AdviseThreadFunction// Thread start address
                         (LPVOID) this,         // Thread parameter
                         (DWORD) 0,             // Creation flags
                        &ThreadID);            // Thread identifier
                 if (m_hThread) SetThreadPriority( m_hThread, THREAD_PRIORITY_TIME_CRITICAL );
                else 返回错误并清除m_pSchedule
            }
      }
  6. CAMEvent类[wxutil.h/wxutil.cpp]
    类似于CCritSec,CAMEvent封装了HANDLE m_hEvent;
    • Construction:
      CAMEvent(BOOL fManualReset = FALSE);
      {m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL);}
    • Deconstructor
      ~CAMEvent(){if (m_hEvent) EXECUTE_ASSERT(CloseHandle(m_hEvent));}
    • 成员函数很简洁明了
      operator HANDLE () const { return m_hEvent; };
      void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));};
      BOOL Wait(DWORD dwTimeout = INFINITE) {
             return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0);
      };
      void Reset() { ResetEvent(m_hEvent); };
      BOOL Check() { return Wait(0); };
  7. CAMThread类[wxutil.h/wxutil.cpp]
    CAMThread稍微复杂一点。
    • 成员变量:
      CAMEvent m_EventSend;
      CAMEvent m_EventComplete;
      DWORD m_dwParam;
      DWORD m_dwReturnVal;
      HANDLE m_hThread;
      CCritSec m_AccessLock; // locks access by client threads
      CCritSec m_WorkerLock; // locks access to shared objects
      其中,m_EventSend默认为TRUE,m_hThread初始化为NULL。
    • Deconstrutor只调用了Close函数。
    • 新增加的virtual函数:
      virtual DWORD ThreadProc() = 0;
    • 成员函数:
      // start thread running  - error if already running
      BOOL Create();
      {
            CAutoLock lock(&m_AccessLock);
            if (ThreadExists()) {return FALSE;}
            // 创建Thread,返回创建结果
            m_hThread = CreateThread(NULL, 0, CAMThread::InitialThreadProc, this, 0, &threadid);
      }
      // signal the thread, and block for a response
      DWORD CallWorker(DWORD);
      {
             CAutoLock lock(&m_AccessLock);
             // 判断ThreadExists函数
             // 设置参数 m_dwParam = dwParam;
             // signal the worker thread: m_EventSend.Set();
             // 等待该Thread结束 m_EventComplete.Wait();
            // 返回结果 return m_dwReturnVal;
      }
      // accessor thread calls this when done with thread (having told thread to exit)
      void Close() {
          HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0);
          if (hThread) {
              WaitForSingleObject(hThread, INFINITE);
              CloseHandle(hThread);
          }
      };
      // Return TRUE if the thread exists. FALSE otherwise
      BOOL ThreadExists(void) const {return (m_hThread != 0); }
      // wait for the next request
      DWORD GetRequest();{m_EventSend.Wait();return m_dwParam;}
      // is there a request?
      BOOL CheckRequest(DWORD * pParam);
      {
             // if (!m_EventSend.Check())return FALSE;
            // 否则设置*pParam = m_dwParam;
      }
      // reply to the request
      void Reply(DWORD);
      {
            m_dwReturnVal = dw;
            m_EventSend.Reset();
            m_EventComplete.Set();
      }
      HANDLE GetRequestHandle() const { return m_EventSend; };
      DWORD GetRequestParam() const { return m_dwParam; };
    • static成员函数:
      // thread initially runs this. param is actually 'this'. Function
      // just gets this and calls ThreadProc
      static DWORD WINAPI InitialThreadProc(LPVOID pv);
      {
               HRESULT hrCoInit = CAMThread::CoInitializeHelper();
              CAMThread * pThread = (CAMThread *) pv;
              HRESULT hr = pThread->ThreadProc();
              if(SUCCEEDED(hrCoInit)) {CoUninitialize();}
              return hr;
      }
      // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if available. S_FALSE means it's not available.
      static HRESULT CoInitializeHelper();
      {
               // 通过GetModuleHandle(TEXT("ole32.dll"));来直接调用其中函数CoInitializeEx函数。
      }