DirectShow学习(八): CBaseRender类及相应Pin类的源代码分析 1. CRendererInputPin类[renbase.h/renbase.cpp] 派生自CBaseInputPin。
a) 成员变量: CBaseRenderer *m_pRenderer;
b) IPin接口和继承的函数 HRESULT BreakConnect(); { HRESULT hr = m_pRenderer->BreakConnect(); return CBaseInputPin::BreakConnect(); } HRESULT CompleteConnect(IPin *pReceivePin); { HRESULT hr = m_pRenderer->CompleteConnect(pReceivePin); return CBaseInputPin::CompleteConnect(pReceivePin); } HRESULT SetMediaType(const CMediaType *pmt); { HRESULT hr = CBaseInputPin::SetMediaType(pmt); return m_pRenderer->SetMediaType(pmt); } HRESULT CheckMediaType(const CMediaType *pmt); { return m_pRenderer->CheckMediaType(pmt); } HRESULT Active();{ return m_pRenderer->Active();} HRESULT Inactive(); { ASSERT(CritCheckIn(&m_pRenderer->m_InterfaceLock)); m_bRunTimeError = FALSE; return m_pRenderer->Inactive(); } STDMETHODIMP QueryId(LPWSTR *Id); { *Id = (LPWSTR)CoTaskMemAlloc(8); lstrcpyW(*Id, L"In"); } STDMETHODIMP EndOfStream(); { CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); HRESULT hr = CheckStreaming(); hr = m_pRenderer->EndOfStream(); hr = CBaseInputPin::EndOfStream(); } STDMETHODIMP BeginFlush(); { HRESULT hr = m_pRenderer->EndFlush(); hr = CBaseInputPin::EndFlush(); } STDMETHODIMP EndFlush(); { CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); CAutoLock cSampleLock(&m_pRenderer->m_RendererLock); CBaseInputPin::BeginFlush(); m_pRenderer->BeginFlush(); return m_pRenderer->ResetEndOfStream(); } STDMETHODIMP Receive(IMediaSample *pMediaSample); { HRESULT hr = m_pRenderer->Receive(pSample); if (FAILED(hr)) { ASSERT(CritCheckOut(&m_pRenderer->m_RendererLock)); CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock); if (!IsStopped() && !IsFlushing() && !m_pRenderer->m_bAbort && !m_bRunTimeError) { m_pRenderer->NotifyEvent(EC_ERRORABORT,hr,0); CAutoLock alRendererLock(&m_pRenderer->m_RendererLock); if (m_pRenderer->IsStreaming() && !m_pRenderer->IsEndOfStreamDelivered()) { m_pRenderer->NotifyEndOfStream();} m_bRunTimeError = TRUE; } } }
2. CBaseRender类[renbase.h/renbase.cpp] 派生自CBaseFilter。
a) 成员变量 CRendererPosPassThru *m_pPosition; // Media seeking pass by object 类CRendererPosPassThru派生自CPosPassThru,后者继承自接口IMediaSeeking和类CMediaPosition。而类CMediaPosition实现了接口IMediaPosition。具体实现见ctlutil.h CAMEvent m_RenderEvent; // Used to signal timer events CAMEvent m_ThreadSignal; // Signalled to release worker thread CAMEvent m_evComplete; // Signalled when state complete BOOL m_bAbort; // Stop us from rendering more data BOOL m_bStreaming; // Are we currently streaming DWORD_PTR m_dwAdvise; // Timer advise cookie IMediaSample *m_pMediaSample; // Current image media sample BOOL m_bEOS; // Any more samples in the stream BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE CRendererInputPin *m_pInputPin; // Our renderer input pin object CCritSec m_InterfaceLock; // Critical section for interfaces CCritSec m_RendererLock; // Controls access to internals IQualityControl * m_pQSink; // QualityControl sink BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT // Avoid some deadlocks by tracking filter during stop volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive // And actually processing the sample REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE UINT m_EndOfStreamTimer; // Used to signal end of stream CCritSec m_ObjectCreationLock; // This lock protects the creation and // of m_pPosition and m_pInputPin. It ensures that two threads cannot create // either object simultaneously. 构造函数中,对各成员初始化,m_evComplete(TRUE), m_bAbort(FALSE), m_pPosition(NULL), m_ThreadSignal(TRUE), m_bStreaming(FALSE), m_bEOS(FALSE), m_bEOSDelivered(FALSE), m_pMediaSample(NULL), m_dwAdvise(0), m_pQSink(NULL), m_pInputPin(NULL), m_bRepaintStatus(TRUE), m_SignalTime(0), m_bInReceive(FALSE), m_EndOfStreamTimer(0);析构函数中调用StopStreaming和ClearPendingSample;并删除m_pPosition和m_pInputPin。
b) 新增加的virtual函数 // Overriden to say what interfaces we support and where virtual HRESULT GetMediaPositionInterface(REFIID riid,void **ppv); { CAutoLock cObjectCreationLock(&m_ObjectCreationLock); if (m_pPosition) { return m_pPosition->NonDelegatingQueryInterface(riid,ppv); } m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"), CBaseFilter::GetOwner(),(HRESULT *) &hr, GetPin(0)); return GetMediaPositionInterface(riid,ppv); } virtual HRESULT SourceThreadCanWait(BOOL bCanWait); { if (bCanWait == TRUE) m_ThreadSignal.Reset(); else m_ThreadSignal.Set(); } virtual HRESULT WaitForRenderTime(); { HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent }; OnWaitStart(); while (Result == WAIT_TIMEOUT) { Result = WaitForMultipleObjects(2,WaitObjects,FALSE,RENDER_TIMEOUT);} OnWaitEnd(); if (Result == WAIT_OBJECT_0) {return VFW_E_STATE_CHANGED;} SignalTimerFired(); } virtual HRESULT CompleteStateChange(FILTER_STATE OldState); { if (m_pInputPin->IsConnected() == FALSE) {Ready();return S_OK;} if (IsEndOfStream() == TRUE) {Ready();return S_OK;} if (HaveCurrentSample() == TRUE) { if (OldState != State_Stopped) { Ready();return S_OK;} } NotReady(); } virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) {}; virtual void OnRenderStart(IMediaSample *pMediaSample){} virtual void OnRenderEnd(IMediaSample *pMediaSample){} virtual HRESULT OnStartStreaming() { return NOERROR; }; virtual HRESULT OnStopStreaming() { return NOERROR; }; virtual void OnWaitStart() {}; virtual void OnWaitEnd() {}; virtual void PrepareRender() {}; // Quality management implementation for scheduling rendering virtual BOOL ScheduleSample(IMediaSample *pMediaSample); { REFERENCE_TIME StartSample, EndSample; if (pMediaSample == NULL) {return FALSE;} HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample); if (FAILED(hr)) {return FALSE;} if (hr == S_OK) {EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent)); return TRUE;} ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); hr = m_pClock->AdviseTime( (REFERENCE_TIME) m_tStart, // Start run time StartSample, // Stream time (HEVENT)(HANDLE) m_RenderEvent, // Render notification &m_dwAdvise); // Advise cookie if (SUCCEEDED(hr)) {return TRUE;} return FALSE; } virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime); { if (SUCCEEDED(pMediaSample->GetTime(pStartTime, pEndTime))) { if (*pEndTime < *pStartTime) {return VFW_E_START_TIME_AFTER_END;} } else {return S_OK;} if (m_pClock == NULL) {return S_OK;} return ShouldDrawSampleNow(pMediaSample,pStartTime,pEndTime); } virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample, REFERENCE_TIME *ptrStart, REFERENCE_TIME *ptrEnd);{ return S_FALSE;} virtual HRESULT SendEndOfStream(); { ASSERT(CritCheckIn(&m_RendererLock)); if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer) { return NOERROR;} if (m_pClock == NULL) {return NotifyEndOfStream();} REFERENCE_TIME Signal = m_tStart + m_SignalTime; REFERENCE_TIME CurrentTime; m_pClock->GetTime(&CurrentTime); LONG Delay = LONG((Signal - CurrentTime) / 10000); if (Delay < TIMEOUT_DELIVERYWAIT) {return NotifyEndOfStream();} m_EndOfStreamTimer = CompatibleTimeSetEvent((UINT) Delay, // Period of timer TIMEOUT_RESOLUTION, // Timer resolution EndOfStreamTimer, // Callback function DWORD_PTR(this), // Used information TIME_ONESHOT); // Type of callback if (m_EndOfStreamTimer == 0) {return NotifyEndOfStream();} } virtual HRESULT ResetEndOfStream(); { ResetEndOfStreamTimer(); CAutoLock cRendererLock(&m_RendererLock); m_bEOS = FALSE; m_bEOSDelivered = FALSE; m_SignalTime = 0; } virtual HRESULT EndOfStream(); { m_bEOS = TRUE; Ready(); if (m_pMediaSample) { return NOERROR;} if (m_bStreaming) { SendEndOfStream();} } virtual HRESULT CancelNotification(); { ASSERT(m_dwAdvise == 0 || m_pClock); DWORD_PTR dwAdvise = m_dwAdvise; if (m_dwAdvise) { m_pClock->Unadvise(m_dwAdvise); SignalTimerFired();} m_RenderEvent.Reset(); return (dwAdvise ? S_OK : S_FALSE); } virtual HRESULT ClearPendingSample(); { CAutoLock cRendererLock(&m_RendererLock); if (m_pMediaSample) { m_pMediaSample->Release(); m_pMediaSample = NULL;} } virtual HRESULT PrepareReceive(IMediaSample *pMediaSample); { CAutoLock cInterfaceLock(&m_InterfaceLock); m_bInReceive = TRUE; HRESULT hr = m_pInputPin->CBaseInputPin::Receive(pMediaSample); if (hr != NOERROR) {m_bInReceive = FALSE; return E_FAIL;} if (m_pInputPin->SampleProps()->pMediaType) { hr = m_pInputPin->SetMediaType( (CMediaType *)m_pInputPin->SampleProps()->pMediaType); if (FAILED(hr)) { m_bInReceive = FALSE; return hr; } } CAutoLock cSampleLock(&m_RendererLock); if (m_pMediaSample || m_bEOS || m_bAbort) { Ready();m_bInReceive = FALSE; return E_UNEXPECTED;} if (m_pPosition) m_pPosition->RegisterMediaTime(pMediaSample); if ((m_bStreaming == TRUE) && (ScheduleSample(pMediaSample) == FALSE)) { ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); ASSERT(CancelNotification() == S_FALSE); m_bInReceive = FALSE; return VFW_E_SAMPLE_REJECTED; } m_SignalTime = m_pInputPin->SampleProps()->tStop; m_pMediaSample = pMediaSample; m_pMediaSample->AddRef(); if (m_bStreaming == FALSE) {SetRepaintStatus(TRUE);} } virtual BOOL HaveCurrentSample(); { // Checks if there is a sample waiting at the renderer CAutoLock cRendererLock(&m_RendererLock); return (m_pMediaSample == NULL ? FALSE : TRUE); } virtual IMediaSample *GetCurrentSample(); { CAutoLock cRendererLock(&m_RendererLock); if (m_pMediaSample) {m_pMediaSample->AddRef();} return m_pMediaSample; } virtual HRESULT Render(IMediaSample *pMediaSample); { if (pMediaSample == NULL) {return S_FALSE;} if (m_bStreaming == FALSE) {return S_FALSE;} OnRenderStart(pMediaSample); DoRenderSample(pMediaSample); OnRenderEnd(pMediaSample); } virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE;
c) IBaseFilter接口函数以及继承函数 virtual int GetPinCount();{1} virtual CBasePin *GetPin(int n); { CAutoLock cObjectCreationLock(&m_ObjectCreationLock); if (m_pInputPin == NULL) { m_pInputPin = new CRendererInputPin(this,&hr,L"In");} return m_pInputPin; } STDMETHODIMP Stop(); { CAutoLock cRendererLock(&m_InterfaceLock); if (m_State == State_Stopped) { return NOERROR;} if (m_pInputPin->IsConnected() == FALSE) { m_State = State_Stopped; return NOERROR;} CBaseFilter::Stop(); if (m_pInputPin->Allocator()) { m_pInputPin->Allocator()->Decommit();} SetRepaintStatus(TRUE); StopStreaming(); SourceThreadCanWait(FALSE); ResetEndOfStream(); CancelNotification(); Ready(); WaitForReceiveToComplete(); m_bAbort = FALSE; } STDMETHODIMP Pause(); { CAutoLock cRendererLock(&m_InterfaceLock); FILTER_STATE OldState = m_State; if (m_State == State_Paused) { return CompleteStateChange(State_Paused);} if (m_pInputPin->IsConnected() == FALSE) { m_State = State_Paused; return CompleteStateChange(State_Paused); } HRESULT hr = CBaseFilter::Pause(); SetRepaintStatus(TRUE); StopStreaming(); SourceThreadCanWait(TRUE); CancelNotification(); ResetEndOfStreamTimer(); if (m_pInputPin->Allocator()) { m_pInputPin->Allocator()->Commit();} if (OldState == State_Stopped) { m_bAbort = FALSE; ClearPendingSample();} return CompleteStateChange(OldState); } STDMETHODIMP Run(REFERENCE_TIME StartTime); { CAutoLock cRendererLock(&m_InterfaceLock); FILTER_STATE OldState = m_State; if (m_pInputPin->IsConnected() == FALSE) { NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); m_State = State_Running; return NOERROR;} Ready(); HRESULT hr = CBaseFilter::Run(StartTime); SourceThreadCanWait(TRUE); SetRepaintStatus(FALSE); if (m_pInputPin->Allocator()) { m_pInputPin->Allocator()->Commit();} if (OldState == State_Stopped) { m_bAbort = FALSE; ClearPendingSample();} return StartStreaming (); } STDMETHODIMP GetState(DWORD dwMSecs,FILTER_STATE *State); { CheckPointer(State,E_POINTER); if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT) { *State = m_State; return VFW_S_STATE_INTERMEDIATE;} *State = m_State; } STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin); { if (0==lstrcmpW(Id,L"In")) { *ppPin = GetPin(0); (*ppPin)->AddRef();} } virtual HRESULT Active();{return NOERROR;} virtual HRESULT Inactive(); { if (m_pPosition) { m_pPosition->ResetMediaTime();} ClearPendingSample(); } virtual HRESULT StartStreaming(); { CAutoLock cRendererLock(&m_RendererLock); if (m_bStreaming == TRUE) {return NOERROR;} m_bStreaming = TRUE; timeBeginPeriod(1); OnStartStreaming(); ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0)); ASSERT(CancelNotification() == S_FALSE); if (m_pMediaSample == NULL) {return SendEndOfStream();} if (!ScheduleSample(m_pMediaSample)) m_RenderEvent.Set(); } virtual HRESULT StopStreaming(); { CAutoLock cRendererLock(&m_RendererLock); m_bEOSDelivered = FALSE; if (m_bStreaming == TRUE) { m_bStreaming = FALSE; OnStopStreaming(); timeEndPeriod(1);} } virtual HRESULT BeginFlush(); { if (m_State == State_Paused) { NotReady();} SourceThreadCanWait(FALSE); CancelNotification(); ClearPendingSample(); WaitForReceiveToComplete(); } virtual HRESULT EndFlush(); { if (m_pPosition) m_pPosition->ResetMediaTime(); SourceThreadCanWait(TRUE); } virtual HRESULT BreakConnect(); { if (m_pQSink) {m_pQSink->Release();m_pQSink = NULL;} if (m_pInputPin->IsConnected() == FALSE) {return S_FALSE;} if (m_State != State_Stopped && !m_pInputPin->CanReconnectWhenActive()) { return VFW_E_NOT_STOPPED;} SetRepaintStatus(FALSE); ResetEndOfStream(); ClearPendingSample(); m_bAbort = FALSE; if (State_Running == m_State) {StopStreaming();} } virtual HRESULT SetMediaType(const CMediaType *pmt);{ return NOERROR;} virtual HRESULT CompleteConnect(IPin *pReceivePin); { ASSERT(CritCheckIn(&m_InterfaceLock)); m_bAbort = FALSE; if (State_Running == GetRealState()) { HRESULT hr = StartStreaming(); SetRepaintStatus(FALSE); } else { SetRepaintStatus(TRUE);} } virtual HRESULT Receive(IMediaSample *pMediaSample); { HRESULT hr = PrepareReceive(pSample); if (m_State == State_Paused) { PrepareRender(); m_bInReceive = FALSE; { // We must hold both these locks CAutoLock cRendererLock(&m_InterfaceLock); if (m_State == State_Stopped) return NOERROR; m_bInReceive = TRUE; CAutoLock cSampleLock(&m_RendererLock); OnReceiveFirstSample(pSample); } Ready(); } hr = WaitForRenderTime(); if (FAILED(hr)) {m_bInReceive = FALSE; return NOERROR;} PrepareRender(); m_bInReceive = FALSE; CAutoLock cRendererLock(&m_InterfaceLock); if (m_State == State_Stopped) return NOERROR; CAutoLock cSampleLock(&m_RendererLock); Render(m_pMediaSample); ClearPendingSample(); SendEndOfStream(); CancelNotification(); } virtual HRESULT CheckMediaType(const CMediaType *) PURE;
d) 其他函数 BOOL IsEndOfStream() { return m_bEOS; }; BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; }; BOOL IsStreaming() { return m_bStreaming; }; void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; }; CAMEvent *GetRenderEvent() { return &m_RenderEvent; }; // Permit access to the transition state void Ready() { m_evComplete.Set(); }; void NotReady() { m_evComplete.Reset(); }; BOOL CheckReady() { return m_evComplete.Check(); }; FILTER_STATE GetRealState(){ return m_State; }; void SendRepaint(); { CAutoLock cSampleLock(&m_RendererLock); if (m_bAbort == FALSE) { if (m_pInputPin->IsConnected() == TRUE) { if (m_pInputPin->IsFlushing() == FALSE) { if (IsEndOfStream() == FALSE) { if (m_bRepaintStatus == TRUE) { IPin *pPin = (IPin *) m_pInputPin; NotifyEvent(EC_REPAINT,(LONG_PTR) pPin,0); SetRepaintStatus(FALSE); }}}}}} void SendNotifyWindow(IPin *pPin,HWND hwnd); { IMediaEventSink *pSink; HRESULT hr = pPin->QueryInterface(IID_IMediaEventSink,(void **)&pSink); if (SUCCEEDED(hr)) { pSink->Notify(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); pSink->Release();} NotifyEvent(EC_NOTIFY_WINDOW,LONG_PTR(hwnd),0); } BOOL OnDisplayChange(); { CAutoLock cSampleLock(&m_RendererLock); if (m_pInputPin->IsConnected() == FALSE) {return FALSE;} IPin *pPin = (IPin *) m_pInputPin; m_pInputPin->AddRef(); NotifyEvent(EC_DISPLAY_CHANGED,(LONG_PTR) pPin,0); SetAbortSignal(TRUE); ClearPendingSample(); m_pInputPin->Release(); } void SetRepaintStatus(BOOL bRepaint); { CAutoLock cSampleLock(&m_RendererLock); m_bRepaintStatus = bRepaint; } void TimerCallback(); { CAutoLock cRendererLock(&m_RendererLock); if (m_EndOfStreamTimer) { m_EndOfStreamTimer = 0; SendEndOfStream();} } void ResetEndOfStreamTimer(); { ASSERT(CritCheckOut(&m_RendererLock)); if (m_EndOfStreamTimer) { timeKillEvent(m_EndOfStreamTimer); m_EndOfStreamTimer = 0;} } HRESULT NotifyEndOfStream(); { CAutoLock cRendererLock(&m_RendererLock); if (m_bStreaming == FALSE) {return NOERROR;} m_EndOfStreamTimer = 0; if (m_pPosition) m_pPosition->EOS(); m_bEOSDelivered = TRUE; return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this); } void SignalTimerFired();{m_dwAdvise = 0;} void WaitForReceiveToComplete(); { for (;;) { if (!m_bInReceive) {break;} MSG msg; // Receive all interthread sendmessages PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE); Sleep(1); } if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0); } } STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv) { if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { return GetMediaPositionInterface(riid,ppv); } else { return CBaseFilter::NonDelegatingQueryInterface(riid,ppv); } }
e) 友元函数 friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier UINT uMsg, // Not currently used DWORD_PTR dwUser, // User information DWORD_PTR dw1, // Windows reserved DWORD_PTR dw2); // Is also reserved { CBaseRenderer *pRenderer = (CBaseRenderer *) dwUser; pRenderer->TimerCallback(); }
前一篇: (七) CTransInPlaceFilter及相关联Pin类的源代码解析

|