📄 renbaseasync.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of your Microsoft Windows CE
// Source Alliance Program license form. If you did not accept the terms of
// such a license, you are not authorized to use this source code.
//
//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
//
//--------------------------------------------------------------------------;
#include <streams.h> // ActiveMovie base class definitions
#include <mmsystem.h> // Needed for definition of timeGetTime
#include <limits.h> // Standard data type limit definitions
#include <measure.h> // Used for time critical log functions
#pragma warning(disable:4355)
static DWORD s_dwVideoThreadPriority = -1;
// Implements the CBaseRendererAsync class
CBaseRendererAsync::CBaseRendererAsync(REFCLSID RenderClass, // CLSID for this renderer
TCHAR *pName, // Debug ONLY description
LPUNKNOWN pUnk, // Aggregated owner object
HRESULT *phr) : // General OLE return code
CBaseRenderer(RenderClass, pName,pUnk,phr),
m_pScheduledSample(NULL)
{
if (-1 == s_dwVideoThreadPriority)
{
s_dwVideoThreadPriority = 248 + THREAD_PRIORITY_NORMAL;
HKEY hKey;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\DirectShow\\ThreadPriority"),
0, 0, &hKey))
{
DWORD dwType, dwSize, dwValue;
// Use default value if the value isn't defined, or is invalidate
dwSize = sizeof (DWORD);
if (ERROR_SUCCESS == RegQueryValueEx (hKey, TEXT("Video"), NULL, &dwType, LPBYTE(&dwValue), &dwSize) &&
REG_DWORD == dwType && dwValue < 256)
{
s_dwVideoThreadPriority = dwValue;
}
RegCloseKey (hKey);
}
}
}
// Delete the dynamically allocated IMediaPosition and IMediaSeeking helper
// object. The object is created when somebody queries us. These are standard
// control interfaces for seeking and setting start/stop positions and rates.
// We will probably also have made an input pin based on CRendererInputPin
// that has to be deleted, it's created when an enumerator calls our GetPin
CBaseRendererAsync::~CBaseRendererAsync()
{
KillThread();
m_RendererQueue.Flush();
}
// Overriden to say what interfaces we support and where
STDMETHODIMP CBaseRendererAsync::NonDelegatingQueryInterface(REFIID riid,void **ppv)
{
return CBaseRenderer::NonDelegatingQueryInterface(riid,ppv);
}
// For the asynchronous renderer case, the source thread never waits.
HRESULT CBaseRendererAsync::SourceThreadCanWait(BOOL bCanWait)
{
return NOERROR;
}
#ifdef DEBUG
// Dump the current renderer state to the debug terminal. The hardest part of
// the renderer is the window where we unlock everything to wait for a clock
// to signal it is time to draw or for the application to cancel everything
// by stopping the filter. If we get things wrong we can leave the thread in
// WaitForRenderTime with no way for it to ever get out and we will deadlock
void CBaseRendererAsync::DisplayRendererState()
{
CBaseRenderer::DisplayRendererState();
DbgLog((LOG_TIMING, 1, TEXT("Sample currently scheduled %d"),m_pScheduledSample));
}
#endif
HRESULT CBaseRendererAsync::WaitForRenderTime()
{
// should not have been called for the asynchronous renderer case
ASSERT(0);
return E_FAIL;
}
void CBaseRendererAsync::WaitForReceiveToComplete()
{
// return immediately for the asynchronous renderer case
}
// When we stop the filter the things we do are:-
// Decommit the allocator being used in the connection
// Release the source filter if it's waiting in Receive
// Cancel any advise link we set up with the clock
// Any end of stream signalled is now obsolete so reset
// Allow us to be stopped when we are not connected
STDMETHODIMP CBaseRendererAsync::Stop()
{
CAutoLock cRendererLock(&m_InterfaceLock);
DbgLog((LOG_TRACE, 2, TEXT("CBaseRendererAsync::Stop")));
// Make sure there really is a state change
if (m_State == State_Stopped) {
// Even though we're "stopped", we may have gotten into
// an indeterminate-state during a Pause() operation, leaving our CAMThread
// running. Let's make sure we use KillThread() to make any of those naughty
// threads exit.
if( KillThread() == NOERROR )
{
DEBUGMSG( 1, ( TEXT( "WMT: Closing CAMThread down properly!\n" ) ) );
}
return NOERROR;
}
// Make the worker thread go to a known state
StopThread();
// Now call the base class
return CBaseRenderer::Stop();
}
// 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 CBaseRendererAsync::Pause()
{
CAutoLock cRendererLock(&m_InterfaceLock);
FILTER_STATE OldState = m_State;
HRESULT hr;
DbgLog((LOG_TRACE, 2, TEXT("CBaseRendererAsync::Pause")));
if (m_State != State_Paused)
{
// if we're going to Pause from Stopped, we're starting.
// Create our worker thread (if needed) and put it in running mode.
if (m_State == State_Stopped)
{
if (!ThreadExists())
{
if (!Create())
{
return E_OUTOFMEMORY;
}
}
RunThread();
}
m_bFirstSample = TRUE; // set after a state change
}
hr = CBaseRenderer::Pause();
return hr;
}
// 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 CBaseRendererAsync::Run(REFERENCE_TIME StartTime)
{
CAutoLock cRendererLock(&m_InterfaceLock);
FILTER_STATE OldState = m_State;
HRESULT hr;
DbgLog((LOG_TRACE, 2, TEXT("CBaseRendererAsync::Run")));
if (m_State == State_Stopped)
{
// if we're going to Run from Stopped, we're starting.
// Create our worker thread (if needed) and put it in running mode.
if (!ThreadExists())
{
if (!Create())
{
return E_OUTOFMEMORY;
}
}
RunThread();
m_bFirstSample = TRUE; // set after a state change
}
hr = CBaseRenderer::Run(StartTime);
return hr;
}
HRESULT CBaseRendererAsync::BeginFlush()
{
CAutoLock cSampleLock(&m_RendererLock);
// If paused then report state intermediate until we get some data
if (m_State == State_Paused) {
NotReady();
}
CancelNotification();
return NOERROR;
}
HRESULT CBaseRendererAsync::EndFlush()
{
// sync with renderer thread -- stop the worker thread from delivering samples...
StopThread();
// now that we know the worker thread is in a stopped state, we can get the RendererLock
CAutoLock cSampleLock(&m_RendererLock);
// Cancel any outstanding advise
CancelNotification();
ClearPendingSample();
m_RendererQueue.Flush();
// Reset the current sample media time
if (m_pPosition) m_pPosition->ResetMediaTime();
// put the worker thread in running mode again
RunThread();
return NOERROR;
}
// Called when we go into a stopped state
HRESULT CBaseRendererAsync::Inactive()
{
HRESULT hr = CBaseRenderer::Inactive();
m_RendererQueue.Flush();
return hr;
}
HRESULT CBaseRendererAsync::BreakConnect()
{
HRESULT hr = CBaseRenderer::BreakConnect();
m_RendererQueue.Flush();
return hr;
}
// We must always reset the current advise time to zero after a timer fires
// because there are several possible ways which lead us not to do any more
// scheduling such as the pending image being cleared after state changes
void CBaseRendererAsync::SignalTimerFired()
{
m_dwAdvise = 0;
if (m_pScheduledSample)
{
m_pScheduledSample->SetScheduled(FALSE);
m_pScheduledSample = NULL;
}
}
//
// Called when the source delivers us a sample. We go through a few checks to
// make sure the sample can be rendered. We queue the sample for further processing
// by the renderer thread. If we are running (streaming) then we set an event to awaken
// the renderer thread.
//
HRESULT CBaseRendererAsync::PrepareReceive(IMediaSample *pMediaSample)
{
CAutoLock cRendererLock(&m_InterfaceLock);
// Check our flushing and filter state
PERFLOG_TRACE_OBJECT(PERFLOG_EV_RENDERER_OBJECT_RECEIVED, PERFLOG_STREAM_VIDEO, -1, pMediaSample, -1, -1, -1, -1, -1);
HRESULT hr = m_pInputPin->CBaseInputPin::Receive(pMediaSample);
if (hr != NOERROR) {
return E_FAIL;
}
// Has the type changed on a media sample. We do all rendering
// synchronously on the source thread, which has a side effect
// that only one buffer is ever outstanding. Therefore when we
// have Receive called we can go ahead and change the format
// Since the format change can cause a SendMessage we just don't
// lock
if (m_pInputPin->SampleProps()->pMediaType) {
m_pInputPin->SetMediaType(
(CMediaType *)m_pInputPin->SampleProps()->pMediaType);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -