📄 renbase.cpp
字号:
if (m_pInputPin->IsConnected() == FALSE) {
NOTE("Input pin is not connected");
m_State = State_Stopped;
return NOERROR;
}
CBaseFilter::Stop();
// If we are going into a stopped state then we must decommit whatever
// allocator we are using it so that any source filter waiting in the
// GetBuffer can be released and unlock themselves for a state change
if (m_pInputPin->Allocator()) {
m_pInputPin->Allocator()->Decommit();
}
// Cancel any scheduled rendering
SetRepaintStatus(TRUE);
StopStreaming();
SourceThreadCanWait(FALSE);
ResetEndOfStream();
CancelNotification();
// There should be no outstanding clock advise
ASSERT(CancelNotification() == S_FALSE);
ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
ASSERT(m_EndOfStreamTimer == 0);
Ready();
WaitForReceiveToComplete();
m_bAbort = FALSE;
return NOERROR;
}
// When we pause the filter the things we do are:-
// Commit the allocator being used in the connection
// Allow a source filter thread to wait in Receive
// Cancel any clock advise link (we may be running)
// Possibly complete the state change if we have data
// Allow us to be paused when we are not connected
STDMETHODIMP CBaseRenderer::Pause()
{
CAutoLock cRendererLock(&m_InterfaceLock);
FILTER_STATE OldState = m_State;
ASSERT(m_pInputPin->IsFlushing() == FALSE);
// Make sure there really is a state change
if (m_State == State_Paused) {
return CompleteStateChange(State_Paused);
}
// Has our input pin been connected
if (m_pInputPin->IsConnected() == FALSE) {
NOTE("Input pin is not connected");
m_State = State_Paused;
return CompleteStateChange(State_Paused);
}
// Pause the base filter class
HRESULT hr = CBaseFilter::Pause();
if (FAILED(hr)) {
NOTE("Pause failed");
return hr;
}
// Enable EC_REPAINT events again
SetRepaintStatus(TRUE);
StopStreaming();
SourceThreadCanWait(TRUE);
CancelNotification();
ResetEndOfStreamTimer();
// If we are going into a paused state then we must commit whatever
// allocator we are using it so that any source filter can call the
// GetBuffer and expect to get a buffer without returning an error
if (m_pInputPin->Allocator()) {
m_pInputPin->Allocator()->Commit();
}
// There should be no outstanding advise
ASSERT(CancelNotification() == S_FALSE);
ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
ASSERT(m_EndOfStreamTimer == 0);
ASSERT(m_pInputPin->IsFlushing() == FALSE);
// When we come out of a stopped state we must clear any image we were
// holding onto for frame refreshing. Since renderers see state changes
// first we can reset ourselves ready to accept the source thread data
// Paused or running after being stopped causes the current position to
// be reset so we're not interested in passing end of stream signals
if (OldState == State_Stopped) {
m_bAbort = FALSE;
ClearPendingSample();
}
return CompleteStateChange(OldState);
}
// When we run the filter the things we do are:-
// Commit the allocator being used in the connection
// Allow a source filter thread to wait in Receive
// Signal the render event just to get us going
// Start the base class by calling StartStreaming
// Allow us to be run when we are not connected
// Signal EC_COMPLETE if we are not connected
STDMETHODIMP CBaseRenderer::Run(REFERENCE_TIME StartTime)
{
CAutoLock cRendererLock(&m_InterfaceLock);
FILTER_STATE OldState = m_State;
// Make sure there really is a state change
if (m_State == State_Running) {
return NOERROR;
}
// Send EC_COMPLETE if we're not connected
if (m_pInputPin->IsConnected() == FALSE) {
NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this);
m_State = State_Running;
return NOERROR;
}
Ready();
// Pause the base filter class
HRESULT hr = CBaseFilter::Run(StartTime);
if (FAILED(hr)) {
NOTE("Run failed");
return hr;
}
// Allow the source thread to wait
ASSERT(m_pInputPin->IsFlushing() == FALSE);
SourceThreadCanWait(TRUE);
SetRepaintStatus(FALSE);
// There should be no outstanding advise
ASSERT(CancelNotification() == S_FALSE);
ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
ASSERT(m_EndOfStreamTimer == 0);
ASSERT(m_pInputPin->IsFlushing() == FALSE);
// If we are going into a running state then we must commit whatever
// allocator we are using it so that any source filter can call the
// GetBuffer and expect to get a buffer without returning an error
if (m_pInputPin->Allocator()) {
m_pInputPin->Allocator()->Commit();
}
// When we come out of a stopped state we must clear any image we were
// holding onto for frame refreshing. Since renderers see state changes
// first we can reset ourselves ready to accept the source thread data
// Paused or running after being stopped causes the current position to
// be reset so we're not interested in passing end of stream signals
if (OldState == State_Stopped) {
m_bAbort = FALSE;
ClearPendingSample();
}
return StartStreaming();
}
// Return the number of input pins we support
int CBaseRenderer::GetPinCount()
{
return 1;
}
// We only support one input pin and it is numbered zero
CBasePin *CBaseRenderer::GetPin(int n)
{
CAutoLock cObjectCreationLock(&m_ObjectCreationLock);
// Should only ever be called with zero
ASSERT(n == 0);
if (n != 0) {
return NULL;
}
// Create the input pin if not already done so
if (m_pInputPin == NULL) {
// hr must be initialized to NOERROR because
// CRendererInputPin's constructor only changes
// hr's value if an error occurs.
HRESULT hr = NOERROR;
m_pInputPin = new CRendererInputPin(this,&hr,L"In");
if (NULL == m_pInputPin) {
return NULL;
}
if (FAILED(hr)) {
delete m_pInputPin;
m_pInputPin = NULL;
return NULL;
}
}
return m_pInputPin;
}
// If "In" then return the IPin for our input pin, otherwise NULL and error
STDMETHODIMP CBaseRenderer::FindPin(LPCWSTR Id, IPin **ppPin)
{
CheckPointer(ppPin,E_POINTER);
if (0==lstrcmpW(Id,L"In")) {
*ppPin = GetPin(0);
ASSERT(*ppPin);
(*ppPin)->AddRef();
} else {
*ppPin = NULL;
return VFW_E_NOT_FOUND;
}
return NOERROR;
}
// Called when the input pin receives an EndOfStream notification. If we have
// not got a sample, then notify EC_COMPLETE now. If we have samples, then set
// m_bEOS and check for this on completing samples. If we're waiting to pause
// then complete the transition to paused state by setting the state event
HRESULT CBaseRenderer::EndOfStream()
{
// Ignore these calls if we are stopped
if (m_State == State_Stopped) {
return NOERROR;
}
// If we have a sample then wait for it to be rendered
m_bEOS = TRUE;
if (m_pMediaSample) {
return NOERROR;
}
// If we are waiting for pause then we are now ready since we cannot now
// carry on waiting for a sample to arrive since we are being told there
// won't be any. This sets an event that the GetState function picks up
Ready();
// Only signal completion now if we are running otherwise queue it until
// we do run in StartStreaming. This is used when we seek because a seek
// causes a pause where early notification of completion is misleading
if (m_bStreaming) {
SendEndOfStream();
}
return NOERROR;
}
// When we are told to flush we should release the source thread
HRESULT CBaseRenderer::BeginFlush()
{
// If paused then report state intermediate until we get some data
if (m_State == State_Paused) {
NotReady();
}
SourceThreadCanWait(FALSE);
CancelNotification();
ClearPendingSample();
// Wait for Receive to complete
WaitForReceiveToComplete();
return NOERROR;
}
// After flushing the source thread can wait in Receive again
HRESULT CBaseRenderer::EndFlush()
{
// Reset the current sample media time
if (m_pPosition) m_pPosition->ResetMediaTime();
// There should be no outstanding advise
ASSERT(CancelNotification() == S_FALSE);
SourceThreadCanWait(TRUE);
return NOERROR;
}
// We can now send EC_REPAINTs if so required
HRESULT CBaseRenderer::CompleteConnect(IPin *pReceivePin)
{
// The caller should always hold the interface lock because
// the function uses CBaseFilter::m_State.
ASSERT(CritCheckIn(&m_InterfaceLock));
m_bAbort = FALSE;
if (State_Running == GetRealState()) {
HRESULT hr = StartStreaming();
if (FAILED(hr)) {
return hr;
}
SetRepaintStatus(FALSE);
} else {
SetRepaintStatus(TRUE);
}
return NOERROR;
}
// Called when we go paused or running
HRESULT CBaseRenderer::Active()
{
return NOERROR;
}
// Called when we go into a stopped state
HRESULT CBaseRenderer::Inactive()
{
if (m_pPosition) {
m_pPosition->ResetMediaTime();
}
// People who derive from this may want to override this behaviour
// to keep hold of the sample in some circumstances
ClearPendingSample();
return NOERROR;
}
// Tell derived classes about the media type agreed
HRESULT CBaseRenderer::SetMediaType(const CMediaType *pmt)
{
return NOERROR;
}
// When we break the input pin connection we should reset the EOS flags. When
// we are asked for either IMediaPosition or IMediaSeeking we will create a
// CPosPassThru object to handles media time pass through. When we're handed
// samples we store (by calling CPosPassThru::RegisterMediaTime) their media
// times so we can then return a real current position of data being rendered
HRESULT CBaseRenderer::BreakConnect()
{
// Do we have a quality management sink
if (m_pQSink) {
m_pQSink->Release();
m_pQSink = NULL;
}
// Check we have a valid connection
if (m_pInputPin->IsConnected() == FALSE) {
return S_FALSE;
}
// Check we are stopped before disconnecting
if (m_State != State_Stopped && !m_pInputPin->CanReconnectWhenActive()) {
return VFW_E_NOT_STOPPED;
}
SetRepaintStatus(FALSE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -