⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 renbase.cpp

📁 basic class basic classbasic class
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    // We must hold both these locks
    CAutoLock cRendererLock(&m_InterfaceLock);
    
    // since we gave away the filter wide lock, the sate of the filter could
    // have chnaged to Stopped
    if (m_State == State_Stopped)
        return NOERROR;
    
    CAutoLock cSampleLock(&m_RendererLock);
    
    // Deal with this sample
    
    Render(m_pMediaSample);
    ClearPendingSample();
    SendEndOfStream();
    CancelNotification();
    return NOERROR;
}


// This is called when we stop or are inactivated to clear the pending sample
// We release the media sample interface so that they can be allocated to the
// source filter again, unless of course we are changing state to inactive in
// which case GetBuffer will return an error. We must also reset the current
// media sample to NULL so that we know we do not currently have an image

HRESULT CBaseRenderer::ClearPendingSample()
{
    CAutoLock cRendererLock(&m_RendererLock);
    if (m_pMediaSample) {
        m_pMediaSample->Release();
        m_pMediaSample = NULL;
    }
    return NOERROR;
}


// Used to signal end of stream according to the sample end time

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;
    NOTE1("EndOfStreamTimer called (%d)",uID);
    pRenderer->TimerCallback();
}

//  Do the timer callback work
void CBaseRenderer::TimerCallback()
{
    //  Lock for synchronization (but don't hold this lock when calling
    //  timeKillEvent)
    CAutoLock cRendererLock(&m_RendererLock);
    
    // See if we should signal end of stream now
    
    if (m_EndOfStreamTimer) {
        m_EndOfStreamTimer = 0;
        SendEndOfStream();
    }
}


// If we are at the end of the stream signal the filter graph but do not set
// the state flag back to FALSE. Once we drop off the end of the stream we
// leave the flag set (until a subsequent ResetEndOfStream). Each sample we
// get delivered will update m_SignalTime to be the last sample's end time.
// We must wait this long before signalling end of stream to the filtergraph

#define TIMEOUT_DELIVERYWAIT 50
#ifdef UNDER_CE
#define TIMEOUT_RESOLUTION 0 /* Zero indicates to use best available resolution */
#else
#define TIMEOUT_RESOLUTION 10
#endif

HRESULT CBaseRenderer::SendEndOfStream()
{
    ASSERT(CritCheckIn(&m_RendererLock));
    if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer) {
        return NOERROR;
    }
    
    // If there is no clock then signal immediately
    if (m_pClock == NULL) {
        return NotifyEndOfStream();
    }
    
    // How long into the future is the delivery time
    
    REFERENCE_TIME Signal = m_tStart + m_SignalTime;
    REFERENCE_TIME CurrentTime;
    m_pClock->GetTime(&CurrentTime);
    LONG Delay = LONG((Signal - CurrentTime) / 10000);
    
    // Dump the timing information to the debugger
    
    NOTE1("Delay until end of stream delivery %d",Delay);
    NOTE1("Current %s",(LPCTSTR)CDisp((LONGLONG)CurrentTime));
    NOTE1("Signal %s",(LPCTSTR)CDisp((LONGLONG)Signal));
    
    // Wait for the delivery time to arrive
    
    if (Delay < TIMEOUT_DELIVERYWAIT) {
        return NotifyEndOfStream();
    }
    
    // Signal a timer callback on another worker thread

    m_EndOfStreamTimer = timeSetEvent((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();
    }
    return NOERROR;
}


// Signals EC_COMPLETE to the filtergraph manager

HRESULT CBaseRenderer::NotifyEndOfStream()
{
    CAutoLock cRendererLock(&m_RendererLock);
    ASSERT(m_bEOS == TRUE);
    ASSERT(m_bEOSDelivered == FALSE);
    ASSERT(m_EndOfStreamTimer == 0);
    
    // Has the filter changed state
    
    if (m_bStreaming == FALSE) {
        ASSERT(m_EndOfStreamTimer == 0);
        return NOERROR;
    }
    
    // Reset the end of stream timer
    m_EndOfStreamTimer = 0;
    
    // If we've been using the IMediaPosition interface, set it's start
    // and end media "times" to the stop position by hand.  This ensures
    // that we actually get to the end, even if the MPEG guestimate has
    // been bad or if the quality management dropped the last few frames
    
    if (m_pPosition) m_pPosition->EOS();
    m_bEOSDelivered = TRUE;
    NOTE("Sending EC_COMPLETE...");
    return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this);
}


// Reset the end of stream flag, this is typically called when we transfer to
// stopped states since that resets the current position back to the start so
// we will receive more samples or another EndOfStream if there aren't any. We
// keep two separate flags one to say we have run off the end of the stream
// (this is the m_bEOS flag) and another to say we have delivered EC_COMPLETE
// to the filter graph. We need the latter otherwise we can end up sending an
// EC_COMPLETE every time the source changes state and calls our EndOfStream

HRESULT CBaseRenderer::ResetEndOfStream()
{
    ResetEndOfStreamTimer();
    CAutoLock cRendererLock(&m_RendererLock);
    
    m_bEOS = FALSE;
    m_bEOSDelivered = FALSE;
    m_SignalTime = 0;
    
    return NOERROR;
}


// Kills any outstanding end of stream timer

void CBaseRenderer::ResetEndOfStreamTimer()
{
    ASSERT(CritCheckOut(&m_RendererLock));
    if (m_EndOfStreamTimer) {
        MMRESULT mmres;
        if( ( mmres = timeKillEvent( m_EndOfStreamTimer ) ) != TIMERR_NOERROR )
        {
            DbgLog((LOG_ERROR, 0, TEXT( "CAMSyncObj::ResetEndOfStreamTimer() - timeKillEvent( 0x%x ) returned %d\n" ), m_EndOfStreamTimer, mmres));
        }
        m_EndOfStreamTimer = NULL;
    }
}


// This is called when we start running so that we can schedule any pending
// image we have with the clock and display any timing information. If we
// don't have any sample but we have queued an EOS flag then we send it. If
// we do have a sample then we wait until that has been rendered before we
// signal the filter graph otherwise we may change state before it's done

HRESULT CBaseRenderer::StartStreaming()
{
    CAutoLock cRendererLock(&m_RendererLock);
    if (m_bStreaming == TRUE) {
        return NOERROR;
    }
    
    // Reset the streaming times ready for running
    
    m_bStreaming = TRUE;
    timeBeginPeriod(1);
    OnStartStreaming();
    
    // There should be no outstanding advise
    ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent,0));
    ASSERT(CancelNotification() == S_FALSE);
    
    // If we have an EOS and no data then deliver it now
    
    if (m_pMediaSample == NULL) {
        return SendEndOfStream();
    }
    
    // Have the data rendered
    
    ASSERT(m_pMediaSample);
    if (!ScheduleSample(m_pMediaSample))
        m_RenderEvent.Set();
    
    return NOERROR;
}


// This is called when we stop streaming so that we can set our internal flag
// indicating we are not now to schedule any more samples arriving. The state
// change methods in the filter implementation take care of cancelling any
// clock advise link we have set up and clearing any pending sample we have

HRESULT CBaseRenderer::StopStreaming()
{
    CAutoLock cRendererLock(&m_RendererLock);
    m_bEOSDelivered = FALSE;
    
    if (m_bStreaming == TRUE) {
        m_bStreaming = FALSE;
        OnStopStreaming();
        timeEndPeriod(1);
    }
    return NOERROR;
}


// We have a boolean flag that is reset when we have signalled EC_REPAINT to
// the filter graph. We set this when we receive an image so that should any
// conditions arise again we can send another one. By having a flag we ensure
// we don't flood the filter graph with redundant calls. We do not set the
// event when we receive an EndOfStream call since there is no point in us
// sending further EC_REPAINTs. In particular the AutoShowWindow method and
// the DirectDraw object use this method to control the window repainting

void CBaseRenderer::SetRepaintStatus(BOOL bRepaint)
{
    CAutoLock cSampleLock(&m_RendererLock);
    m_bRepaintStatus = bRepaint;
}


// Pass the window handle to the upstream filter

void CBaseRenderer::SendNotifyWindow(IPin *pPin,HWND hwnd)
{
    IMediaEventSink *pSink;
    
    // Does the pin support IMediaEventSink
    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);
}


// Signal an EC_REPAINT to the filter graph. This can be used to have data
// sent to us. For example when a video window is first displayed it may
// not have an image to display, at which point it signals EC_REPAINT. The
// filtergraph will either pause the graph if stopped or if already paused
// it will call put_CurrentPosition of the current position. Setting the
// current position to itself has the stream flushed and the image resent

#define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_)));

void CBaseRenderer::SendRepaint()
{
    CAutoLock cSampleLock(&m_RendererLock);
    ASSERT(m_pInputPin);
    
    // We should not send repaint notifications when...
    //    - An end of stream has been notified
    //    - Our input pin is being flushed
    //    - The input pin is not connected
    //    - We have aborted a video playback
    //    - There is a repaint already sent
    
    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);
                        RLOG("Sending repaint");
                    }
                }
            }
        }
    }
}


// When a video window detects a display change (WM_DISPLAYCHANGE message) it
// can send an EC_DISPLAY_CHANGED event code along with the renderer pin. The
// filtergraph will stop everyone and reconnect our input pin. As we're then
// reconnected we can accept the media type that matches the new display mode
// since we may no longer be able to draw the current image type efficiently

BOOL CBaseRenderer::OnDisplayChange()
{
    // Ignore if we are not connected yet
    
    CAutoLock cSampleLock(&m_RendererLock);
    if (m_pInputPin->IsConnected() == FALSE) {
        return FALSE;
    }
    
    RLOG("Notification of EC_DISPLAY_CHANGE");
    
    // Pass our input pin as parameter on the event
    
    IPin *pPin = (IPin *) m_pInputPin;
    m_pInputPin->AddRef();
    NotifyEvent(EC_DISPLAY_CHANGED,(LONG_PTR) pPin,0);
    SetAbortSignal(TRUE);
    ClearPendingSample();
    m_pInputPin->Release();
    
    return TRUE;
}


void CBaseRenderer::OnNewSegment(REFERENCE_TIME tStart,
                                 REFERENCE_TIME tStop,
                                 double dRate)
{
    m_bFirstFrameRendered = FALSE;
}



// Called just before we start drawing.
// Store the current time in m_trRenderStart to allow the rendering time to be
// logged.  Log the time stamp of the sample and how late it is (neg is early)

void CBaseRenderer::OnRenderStart(IMediaSample *pMediaSample)
{
#ifdef PERF
    REFERENCE_TIME trStart, trEnd;
    pMediaSample->GetTime(&trStart, &trEnd);
    
    MSR_INTEGER(m_idBaseStamp, (int)trStart);     // dump low order 32 bits
    
    m_pClock->GetTime(&m_trRenderStart);
    MSR_INTEGER(0, (int)m_trRenderStart);
    REFERENCE_TIME trStream;
    trStream = m_trRenderStart-m_tStart;     // convert reftime to stream time
    MSR_INTEGER(0,(int)trStream);
    
    const int trLate = (int)(trStream - trStart);
    MSR_INTEGER(m_idBaseAccuracy, trLate/10000);  // dump in mSec
#endif
    
} // OnRenderStart


// Called directly after drawing an image.
// calculate the time spent drawing and log it.

void CBaseRenderer::OnRenderEnd(IMediaSample *pMediaSample)
{
#ifdef PERF
    REFERENCE_TIME trNow;
    m_pClock->GetTime(&trNow);
    MSR_INTEGER(0,(int)trNow);
    int t = (int)((trNow - m_trRenderStart)/10000);   // convert UNITS->msec
    MSR_INTEGER(m_idBaseRenderTime, t);
#endif
} // OnRenderEnd




⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -