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

📄 renbaseasync.cpp

📁 basic class basic classbasic class
💻 CPP
📖 第 1 页 / 共 3 页
字号:
                    CeSetThreadPriority(GetCurrentThread(), s_dwVideoThreadPriority);

                events[0] = GetRequestHandle();
                events[1] = m_ThreadSignal;
                events[2] = (HANDLE)m_ScheduleEvent;
                events[3] = (HANDLE)m_RenderEvent;

                DbgLog((LOG_TRACE, 2, TEXT("CBaseRendererAsync::ThreadProc - Start running loop")));

                while (bRunning)
                {
                    DWORD Wait;

                    OnWaitStart();
                    Wait = WaitForMultipleObjects (4, events, FALSE, 200);
                    OnWaitEnd();
                    switch (Wait)
                    {
                        case WAIT_OBJECT_0:            // Received new command
                            DbgLog((LOG_TRACE, 3, TEXT("CBaseRendererAsync::ThreadProc: there's a new cmd request...!\tThread = 0x%x"), m_hThread));
                            bRunning = FALSE;
                            break;

                        case WAIT_OBJECT_0 + 1:        // Received a state change
                            DbgLog((LOG_TRACE, 3, TEXT("CBaseRendererAsync:ThreadProc: there's a state change...!\tThread = 0x%x"), m_hThread));
                            bRunning = FALSE;
                            break;

                        case WAIT_OBJECT_0 + 2:        // m_ScheduleEvent - a new object has been received, schedule it
                            DbgLog((LOG_TRACE, 5, TEXT("CBaseRendererAsync:ThreadProc: trying to schedule new sample\n")));
                            ScheduleQueuedSample();    // Schedule a new sample if there's one
                            break;

                        case WAIT_OBJECT_0 + 3:        // m_RenderEvent - time to render
                            DbgLog((LOG_TRACE, 5, TEXT("CBaseRendererAsync:ThreadProc: Time to render sample\n")));
                            SignalTimerFired();
                            ProcessQueuedSample();
                            ScheduleQueuedSample();    // Schedule a new sample if there's one
                            break;

                        case WAIT_TIMEOUT:
                            DbgLog((LOG_TRACE, 3, TEXT("CBaseRendererAsync:ThreadProc: we timed out waiting for a new object to schedule or dispatch...!\tThread = 0x%x"), m_hThread));
                            ScheduleQueuedSample();    // Schedule a new sample if there's one
                            break;
                    }
                }
                break;
        }
    }

    DbgLog((LOG_TRACE, 2, TEXT("CBaseRendererAsync:ThreadProc exiting... Thread = 0x%x"), m_hThread));

    return S_OK;
}


//
// CBaseVideoRendererAsync functions
//

CBaseVideoRendererAsync::CBaseVideoRendererAsync(
                                       REFCLSID RenderClass, // CLSID for this renderer
                                       TCHAR *pName,         // Debug ONLY description
                                       LPUNKNOWN pUnk,       // Aggregated owner object
                                       HRESULT *phr) :       // General OLE return code

CBaseRendererAsync(RenderClass,pName,pUnk,phr)
{
} // Constructor


// Destructor is just a placeholder

CBaseVideoRendererAsync::~CBaseVideoRendererAsync()
{
    ASSERT(m_dwAdvise == 0);
}


// Overidden to return our IQualProp interface
STDMETHODIMP CBaseVideoRendererAsync::NonDelegatingQueryInterface(REFIID riid,VOID **ppv)
{
    // We return IQualProp and delegate everything else
    
    if (riid == IID_IQualProp) {
        return CVideoRendererQuality::NonDelegatingQueryInterface (riid, ppv);
    } else if (riid == IID_IQualityControl) {
        return GetInterface((IBaseFilter *) this, ppv);
    } else {
        return CBaseRendererAsync::NonDelegatingQueryInterface(riid,ppv);
    }
}


// Override JoinFilterGraph so that, just before leaving
// the graph we can send an EC_WINDOW_DESTROYED event

STDMETHODIMP
CBaseVideoRendererAsync::JoinFilterGraph(IFilterGraph *pGraph,LPCWSTR pName)
{
    // Since we send EC_ACTIVATE, we also need to ensure
    // we send EC_WINDOW_DESTROYED or the resource manager may be
    // holding us as a focus object
    if (!pGraph && m_pGraph) {
        
        // We were in a graph and now we're not
        // Do this properly in case we are aggregated
        IBaseFilter* pFilter;
        QueryInterface(IID_IBaseFilter,(void **) &pFilter);
        NotifyEvent(EC_WINDOW_DESTROYED, (LPARAM) pFilter, 0);
        pFilter->Release();
    }
    return CBaseFilter::JoinFilterGraph(pGraph, pName);
}


// The timing functions in this class are called by the window object and by
// the renderer's allocator.
// The windows object calls timing functions as it receives media sample
// images for drawing using GDI.
// The allocator calls timing functions when it starts passing DCI/DirectDraw
// surfaces which are not rendered in the same way; The decompressor writes
// directly to the surface with no separate rendering, so those code paths
// call direct into us.  Since we only ever hand out DCI/DirectDraw surfaces
// when we have allocated one and only one image we know there cannot be any
// conflict between the two.
//
// We use timeGetTime to return the timing counts we use (since it's relative
// performance we are interested in rather than absolute compared to a clock)
// The window object sets the accuracy of the system clock (normally 1ms) by
// calling timeBeginPeriod/timeEndPeriod when it changes streaming states


//
// IQualityControl methods
//
STDMETHODIMP CBaseVideoRendererAsync::SetSink( IQualityControl * piqc)
{   
    m_pQSink = piqc;
    
    return NOERROR;
} // SetSink


STDMETHODIMP CBaseVideoRendererAsync::Notify( IBaseFilter * pSelf, Quality q)
{
     return CVideoRendererQuality::NotifyQuality(q);
} // Notify


void CBaseVideoRendererAsync::PrepareRender()
{ 
    if (!m_bFirstFrameRendered)
    {
        NotifyEvent( EC_VIDEOFRAMEREADY, NULL, NULL );
        m_bFirstFrameRendered = TRUE;
    }
}


// Send a message to indicate what our supplier should do about quality.
HRESULT CBaseVideoRendererAsync::SendQuality(REFERENCE_TIME trLate,
                                        REFERENCE_TIME trRealStream)
{
    Quality q;

    CVideoRendererQuality::GetQuality(trLate, trRealStream, &q);
    
    // A specific sink interface may be set through IPin
    
    if (m_pQSink==NULL) {
        // Get our input pin's peer.  We send quality management messages
        // to any nominated receiver of these things (set in the IPin
        // interface), or else to our source filter.
        
        IQualityControl *pQC = NULL;
        IPin *pOutputPin = m_pInputPin->GetConnected();
        ASSERT(pOutputPin != NULL);
        
        // And get an AddRef'd quality control interface
        
        HRESULT hr = pOutputPin->QueryInterface(IID_IQualityControl,(void**) &pQC);
        if (SUCCEEDED(hr)) {
            m_pQSink = pQC;
        }
    }
    if (m_pQSink) {
        return m_pQSink->Notify(this,q);
    }
    
    return S_FALSE;
} // SendQuality


// We are called with a valid IMediaSample image to decide whether this is to
// be drawn or not.  There must be a reference clock in operation.
// Return S_OK if it is to be drawn Now (as soon as possible)
// Return S_FALSE if it is to be drawn when it's due
// Return an error if we want to drop it
// m_nNormal=-1 indicates that we dropped the previous frame and so this
// one should be drawn early.  Respect it and update it.
// Use current stream time plus a number of heuristics (detailed below)
// to make the decision

HRESULT CBaseVideoRendererAsync::ShouldDrawSampleNow(IMediaSample *pMediaSample,
                                                REFERENCE_TIME *ptrStart,
                                                REFERENCE_TIME *ptrEnd)
{
    REFERENCE_TIME trRealStream;     // the real time now expressed as stream time.
    REFERENCE_TIME trLate;

    m_pClock->GetTime(&trRealStream);
    trRealStream -= m_tStart;        // convert to stream time (this is a reftime)

    HRESULT hr = ComputeLateness (*ptrStart, trRealStream, &trLate);
    if (SUCCEEDED(hr))
    {
        hr = SendQuality (trLate, trRealStream);
        BOOL bSupplierHandlingQuality = (hr == S_OK);
        hr = CVideoRendererQuality::ShouldDrawSampleNow(pMediaSample, ptrStart, ptrEnd, trRealStream, bSupplierHandlingQuality);
    }
    return hr;
} // ShouldDrawSampleNow



// NOTE we're called by both the window thread and the source filter thread
// so we have to be protected by a critical section (locked before called)
// Also, when the window thread gets signalled to render an image, it always
// does so regardless of how late it is. All the degradation is done when we
// are scheduling the next sample to be drawn. Hence when we start an advise
// link to draw a sample, that sample's time will always become the last one
// drawn - unless of course we stop streaming in which case we cancel links

BOOL CBaseVideoRendererAsync::ScheduleSample(IMediaSample *pMediaSample)
{
    // We override ShouldDrawSampleNow to add quality management
    
    DbgLog((LOG_TRACE, 5, TEXT("CVideoBaseRendererAsync:ThreadProc: ScheduleSample %x\n"), pMediaSample));

    BOOL bDrawImage = CBaseRendererAsync::ScheduleSample(pMediaSample);
    if (bDrawImage == FALSE) {
        CVideoRendererQuality::FrameDropped (pMediaSample);
        DbgLog((LOG_TRACE, 5, TEXT("CVideoBaseRendererAsync:ThreadProc: ScheduleSample DROPPED FRAME\n")));
    }
    return bDrawImage;
}

// Implementation of IQualProp interface needed to support the property page
// This is how the property page gets the data out of the scheduler. We are
// passed into the constructor the owning object in the COM sense, this will
// either be the video renderer or an external IUnknown if we're aggregated.
// We initialise our CUnknown base class with this interface pointer. Then
// all we have to do is to override NonDelegatingQueryInterface to expose
// our IQualProp interface. The AddRef and Release are handled automatically
// by the base class and will be passed on to the appropriate outer object

STDMETHODIMP CBaseVideoRendererAsync::get_FramesDroppedInRenderer(int *pcFramesDropped)
{
    CAutoLock cVideoLock(&m_InterfaceLock);
    return CVideoRendererQuality::get_FramesDroppedInRenderer (pcFramesDropped);
} // get_FramesDroppedInRenderer


// Set *pcFramesDrawn to the number of frames drawn since
// streaming started.

STDMETHODIMP CBaseVideoRendererAsync::get_FramesDrawn( int *pcFramesDrawn)
{
    CAutoLock cVideoLock(&m_InterfaceLock);
    return CVideoRendererQuality::get_FramesDrawn (pcFramesDrawn);
} // get_FramesDrawn


// Set iAvgFrameRate to the frames per hundred secs since
// streaming started.  0 otherwise.

STDMETHODIMP CBaseVideoRendererAsync::get_AvgFrameRate( int *piAvgFrameRate)
{
    CAutoLock cVideoLock(&m_InterfaceLock);
    return CVideoRendererQuality::get_AvgFrameRate (piAvgFrameRate, m_bStreaming);
} // get_AvgFrameRate


// Set *piAvg to the average sync offset since streaming started
// in mSec.  The sync offset is the time in mSec between when the frame
// should have been drawn and when the frame was actually drawn.

STDMETHODIMP CBaseVideoRendererAsync::get_AvgSyncOffset( int *piAvg)
{
    CAutoLock cVideoLock(&m_InterfaceLock);
    return CVideoRendererQuality::get_AvgSyncOffset (piAvg);
} // get_AvgSyncOffset

//
//  Do estimates for standard deviations for per-frame
//  statistics
//
HRESULT CBaseVideoRendererAsync::GetStdDev(
                                      int nSamples,
                                      int *piResult,
                                      LONGLONG llSumSq,
                                      LONGLONG iTot
                                      )
{
    CAutoLock cVideoLock(&m_InterfaceLock);
    return CVideoRendererQuality::GetStdDev (nSamples, piResult, llSumSq, iTot);
}

// Set *piDev to the standard deviation in mSec of the sync offset
// of each frame since streaming started.

STDMETHODIMP CBaseVideoRendererAsync::get_DevSyncOffset( int *piDev)
{
    CAutoLock cVideoLock(&m_InterfaceLock);
    return CVideoRendererQuality::get_DevSyncOffset (piDev);
} // get_DevSyncOffset


// Set *piJitter to the standard deviation in mSec of the inter-frame time
// of frames since streaming started.

STDMETHODIMP CBaseVideoRendererAsync::get_Jitter( int *piJitter)
{
    CAutoLock cVideoLock(&m_InterfaceLock);
    return CVideoRendererQuality::get_Jitter (piJitter);
} // get_Jitter


// This removes a large number of level 4 warnings from the
// Microsoft compiler which in this case are not very useful
#pragma warning(disable: 4514)

⌨️ 快捷键说明

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