📄 renbaseasync.cpp
字号:
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 + -