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

📄 renbase.cpp

📁 basic class basic classbasic class
💻 CPP
📖 第 1 页 / 共 5 页
字号:
//
// 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)

//  Helper function for clamping time differences
int inline TimeDiff(REFERENCE_TIME rt)
{
    if (rt < - (50 * UNITS)) {
        return -(50 * UNITS);
    } else
        if (rt > 50 * UNITS) {
            return 50 * UNITS;
        } else return (int)rt;
}

static DWORD s_dwVideoThreadPriority = -1;

// Implements the CBaseRenderer class

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

CBaseFilter(pName,pUnk,&m_InterfaceLock,RenderClass),
m_evComplete(TRUE),
m_bAbort(FALSE),
m_pPosition(NULL),
m_ThreadSignal(TRUE),
m_bStreaming(FALSE),
m_bEOS(FALSE),
m_bEOSDelivered(FALSE),
m_pMediaSample(NULL),
m_dwAdvise(0),
m_pQSink(NULL),
m_pInputPin(NULL),
m_bRepaintStatus(TRUE),
m_SignalTime(0),
m_bInReceive(FALSE),
m_EndOfStreamTimer(0),
m_bFirstFrameRendered(FALSE)
{
    Ready();

    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);
        }
    }
#ifdef PERF
    m_idBaseStamp = MSR_REGISTER("BaseRenderer: sample time stamp");
    m_idBaseRenderTime = MSR_REGISTER("BaseRenderer: draw time (msec)");
    m_idBaseAccuracy = MSR_REGISTER("BaseRenderer: Accuracy (msec)");
#endif
}


// 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

CBaseRenderer::~CBaseRenderer()
{
    ASSERT(m_bStreaming == FALSE);
    ASSERT(m_EndOfStreamTimer == 0);
    StopStreaming();
    ClearPendingSample();
    
    // Delete any IMediaPosition implementation
    
    if (m_pPosition) {
        delete m_pPosition;
        m_pPosition = NULL;
    }
    
    // Delete any input pin created
    
    if (m_pInputPin) {
        delete m_pInputPin;
        m_pInputPin = NULL;
    }
    
    // Release any Quality sink
    
    ASSERT(m_pQSink == NULL);
}


// This returns the IMediaPosition and IMediaSeeking interfaces

HRESULT CBaseRenderer::GetMediaPositionInterface(REFIID riid,void **ppv)
{
    CAutoLock cRendererLock(&m_InterfaceLock);
    if (m_pPosition) {
        return m_pPosition->NonDelegatingQueryInterface(riid,ppv);
    }
    
    HRESULT hr = NOERROR;
    
    // Create implementation of this dynamically since sometimes we may
    // never try and do a seek. The helper object implements a position
    // control interface (IMediaPosition) which in fact simply takes the
    // calls normally from the filter graph and passes them upstream
    
    m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"),
                       CBaseFilter::GetOwner(),
                       (HRESULT *) &hr,
                       GetPin(0));
    if (m_pPosition == NULL) {
        return E_OUTOFMEMORY;
    }
    
    if (FAILED(hr)) {
        delete m_pPosition;
        m_pPosition = NULL;
        return E_NOINTERFACE;
    }
    return GetMediaPositionInterface(riid,ppv);
}


// Overriden to say what interfaces we support and where

STDMETHODIMP CBaseRenderer::NonDelegatingQueryInterface(REFIID riid,void **ppv)
{
    // Do we have this interface
    
    if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) {
        return GetMediaPositionInterface(riid,ppv);
    } else {
        return CBaseFilter::NonDelegatingQueryInterface(riid,ppv);
    }
}


// This is called whenever we change states, we have a manual reset event that
// is signalled whenever we don't won't the source filter thread to wait in us
// (such as in a stopped state) and likewise is not signalled whenever it can
// wait (during paused and running) this function sets or resets the thread
// event. The event is used to stop source filter threads waiting in Receive

HRESULT CBaseRenderer::SourceThreadCanWait(BOOL bCanWait)
{
    if (bCanWait == TRUE) {
        m_ThreadSignal.Reset();
    } else {
        m_ThreadSignal.Set();
    }
    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 CBaseRenderer::DisplayRendererState()
{
    DbgLog((LOG_TIMING, 1, TEXT("\nTimed out in WaitForRenderTime")));
    
    // No way should this be signalled at this point
    
    BOOL bSignalled = m_ThreadSignal.Check();
    DbgLog((LOG_TIMING, 1, TEXT("Signal sanity check %d"),bSignalled));
    
    // Now output the current renderer state variables
    
    DbgLog((LOG_TIMING, 1, TEXT("Filter state %d"),m_State));
    
    DbgLog((LOG_TIMING, 1, TEXT("Abort flag %d"),m_bAbort));
    
    DbgLog((LOG_TIMING, 1, TEXT("Streaming flag %d"),m_bStreaming));
    
    DbgLog((LOG_TIMING, 1, TEXT("Clock advise link %d"),m_dwAdvise));
    
    DbgLog((LOG_TIMING, 1, TEXT("Current media sample %x"),m_pMediaSample));
    
    DbgLog((LOG_TIMING, 1, TEXT("EOS signalled %d"),m_bEOS));
    
    DbgLog((LOG_TIMING, 1, TEXT("EOS delivered %d"),m_bEOSDelivered));
    
    DbgLog((LOG_TIMING, 1, TEXT("Repaint status %d"),m_bRepaintStatus));
    
    
    // Output the delayed end of stream timer information
    
    DbgLog((LOG_TIMING, 1, TEXT("End of stream timer %x"),m_EndOfStreamTimer));
    
    DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"),CDisp((LONGLONG)m_SignalTime)));
    
    
    // Should never timeout during a flushing state
    
    BOOL bFlushing = m_pInputPin->IsFlushing();
    DbgLog((LOG_TIMING, 1, TEXT("Flushing sanity check %d"),bFlushing));
    
    // Display the time we were told to start at
    DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"),CDisp((LONGLONG)m_tStart.m_time)));
    
    // Have we got a reference clock
    if (m_pClock == NULL) return;
    
    // Get the current time from the wall clock
    
    CRefTime CurrentTime,StartTime,EndTime;
    m_pClock->GetTime((REFERENCE_TIME*) &CurrentTime);
    CRefTime Offset = CurrentTime - m_tStart;
    
    // Display the current time from the clock
    
    DbgLog((LOG_TIMING, 1, TEXT("Clock time %s"),CDisp((LONGLONG)CurrentTime.m_time)));
    
    DbgLog((LOG_TIMING, 1, TEXT("Time difference %dms"),Offset.Millisecs()));
    
    
    // Do we have a sample ready to render
    if (m_pMediaSample == NULL) return;
    
    m_pMediaSample->GetTime((REFERENCE_TIME*)&StartTime, (REFERENCE_TIME*)&EndTime);
    DbgLog((LOG_TIMING, 1, TEXT("Next sample stream times (Start %d End %d ms)"),
        StartTime.Millisecs(),EndTime.Millisecs()));
    
    // Calculate how long it is until it is due for rendering
    CRefTime Wait = (m_tStart + StartTime) - CurrentTime;
    DbgLog((LOG_TIMING, 1, TEXT("Wait required %d ms"),Wait.Millisecs()));
}
#endif


// Wait until the clock sets the timer event or we're otherwise signalled. We
// set an arbitrary timeout for this wait and if it fires then we display the
// current renderer state on the debugger. It will often fire if the filter's
// left paused in an application however it may also fire during stress tests
// if the synchronisation with application seeks and state changes is faulty

#define RENDER_TIMEOUT 10000

HRESULT CBaseRenderer::WaitForRenderTime()
{
    HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent };
    DWORD Result = WAIT_TIMEOUT;
    
    // Wait for either the time to arrive or for us to be stopped
    
    OnWaitStart();
    while (Result == WAIT_TIMEOUT) {
        Result = WaitForMultipleObjects(2,WaitObjects,FALSE,RENDER_TIMEOUT);
        
#ifdef DEBUG
        if (Result == WAIT_TIMEOUT) DisplayRendererState();
#endif
        
    }
    OnWaitEnd();

    // We may have been awoken without the timer firing
    
    if (Result == WAIT_OBJECT_0) {
        return VFW_E_STATE_CHANGED;
    }
    
    SignalTimerFired();
    return NOERROR;
}


// Poll waiting for Receive to complete.  This really matters when
// Receive may set the palette and cause window messages
// The problem is that if we don't really wait for a renderer to
// stop processing we can deadlock waiting for a transform which
// is calling the renderer's Receive() method because the transform's
// Stop method doesn't know to process window messages to unblock
// the renderer's Receive processing
void CBaseRenderer::WaitForReceiveToComplete()
{
    for (;;) {
        if (!m_bInReceive) {
            break;
        }
        
        MSG msg;
        //  Receive all interthread snedmessages
        PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE);
        
        Sleep(1);
    }
    
#ifndef UNDER_CE
    // If the wakebit for QS_POSTMESSAGE is set, the PeekMessage call
    // above just cleared the changebit which will cause some messaging
    // calls to block (waitMessage, MsgWaitFor...) now.
    // Post a dummy message to set the QS_POSTMESSAGE bit again
    if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) {
        //  Send dummy message
        PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0);
    }
#endif
}

// A filter can have four discrete states, namely Stopped, Running, Paused,
// Intermediate. We are in an intermediate state if we are currently trying
// to pause but haven't yet got the first sample (or if we have been flushed
// in paused state and therefore still have to wait for a sample to arrive)

// This class contains an event called m_evComplete which is signalled when
// the current state is completed and is not signalled when we are waiting to
// complete the last state transition. As mentioned above the only time we
// use this at the moment is when we wait for a media sample in paused state
// If while we are waiting we receive an end of stream notification from the
// source filter then we know no data is imminent so we can reset the event
// This means that when we transition to paused the source filter must call
// end of stream on us or send us an image otherwise we'll hang indefinately


// Simple internal way of getting the real state

FILTER_STATE CBaseRenderer::GetRealState() {
    return m_State;
}


// The renderer doesn't complete the full transition to paused states until
// it has got one media sample to render. If you ask it for its state while
// it's waiting it will return the state along with VFW_S_STATE_INTERMEDIATE

STDMETHODIMP CBaseRenderer::GetState(DWORD dwMSecs,FILTER_STATE *State)
{
    CheckPointer(State,E_POINTER);
    
    if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT) {
        *State = m_State;
        return VFW_S_STATE_INTERMEDIATE;
    }
    *State = m_State;
    return NOERROR;
}


// If we're pausing and we have no samples we don't complete the transition
// to State_Paused and we return S_FALSE. However if the m_bAbort flag has
// been set then all samples are rejected so there is no point waiting for
// one. If we do have a sample then return NOERROR. We will only ever return
// VFW_S_STATE_INTERMEDIATE from GetState after being paused with no sample
// (calling GetState after either being stopped or Run will NOT return this)

HRESULT CBaseRenderer::CompleteStateChange(FILTER_STATE OldState)
{
    // Allow us to be paused when disconnected
    
    if (m_pInputPin->IsConnected() == FALSE) {
        Ready();
        return S_OK;
    }
    
    // Have we run off the end of stream
    

⌨️ 快捷键说明

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