transfrm.cpp.svn-base

来自「ffshow源码」· SVN-BASE 代码 · 共 1,027 行 · 第 1/2 页

SVN-BASE
1,027
字号
//------------------------------------------------------------------------------// File: Transfrm.cpp//// Desc: DirectShow base classes - implements class for simple transform//       filters such as video decompressors.//// Copyright (c) 1992-2002 Microsoft Corporation.  All rights reserved.//------------------------------------------------------------------------------#include "stdafx.h"//#include <measure.h>// =================================================================// Implements the CTransformFilter class// =================================================================CTransformFilter::CTransformFilter(const TCHAR     *pName,                                   LPUNKNOWN pUnk,                                   REFCLSID  clsid) :    CBaseFilter(pName,pUnk,&m_csFilter, clsid),    m_pInput(NULL),    m_pOutput(NULL),    m_bEOSDelivered(FALSE),    m_bQualityChanged(FALSE),    m_bSampleSkipped(FALSE){#ifdef PERF    RegisterPerfId();#endif //  PERF}// destructorCTransformFilter::~CTransformFilter(){    // Delete the pins    delete m_pInput;    delete m_pOutput;}// Transform place holder - should never be calledHRESULT CTransformFilter::Transform(IMediaSample * pIn, IMediaSample *pOut){    UNREFERENCED_PARAMETER(pIn);    UNREFERENCED_PARAMETER(pOut);    DbgBreak("CTransformFilter::Transform() should never be called");    return E_UNEXPECTED;}// return the number of pins we provideint CTransformFilter::GetPinCount(){    return 2;}// return a non-addrefed CBasePin * for the user to addref if he holds onto it// for longer than his pointer to us. We create the pins dynamically when they// are asked for rather than in the constructor. This is because we want to// give the derived class an oppportunity to return different pin objects// We return the objects as and when they are needed. If either of these fails// then we return NULL, the assumption being that the caller will realise the// whole deal is off and destroy us - which in turn will delete everything.CBasePin *CTransformFilter::GetPin(int n){    HRESULT hr = S_OK;    // Create an input pin if necessary    if (m_pInput == NULL) {        m_pInput = new CTransformInputPin(NAME("Transform input pin"),                                          this,              // Owner filter                                          &hr,               // Result code                                          L"XForm In");      // Pin name        //  Can't fail        ASSERT(SUCCEEDED(hr));        if (m_pInput == NULL) {            return NULL;        }        m_pOutput = (CTransformOutputPin *)		   new CTransformOutputPin(NAME("Transform output pin"),                                            this,            // Owner filter                                            &hr,             // Result code                                            L"XForm Out");   // Pin name        // Can't fail        ASSERT(SUCCEEDED(hr));        if (m_pOutput == NULL) {            delete m_pInput;            m_pInput = NULL;        }    }    // Return the appropriate pin    if (n == 0) {        return m_pInput;    } else    if (n == 1) {        return m_pOutput;    } else {        return NULL;    }}//// FindPin//// If Id is In or Out then return the IPin* for that pin// creating the pin if need be.  Otherwise return NULL with an error.STDMETHODIMP CTransformFilter::FindPin(LPCWSTR Id, IPin **ppPin){    CheckPointer(ppPin,E_POINTER);    ValidateReadWritePtr(ppPin,sizeof(IPin *));    if (0==lstrcmpW(Id,L"In")) {        *ppPin = GetPin(0);    } else if (0==lstrcmpW(Id,L"Out")) {        *ppPin = GetPin(1);    } else {        *ppPin = NULL;        return VFW_E_NOT_FOUND;    }    HRESULT hr = NOERROR;    //  AddRef() returned pointer - but GetPin could fail if memory is low.    if (*ppPin) {        (*ppPin)->AddRef();    } else {        hr = E_OUTOFMEMORY;  // probably.  There's no pin anyway.    }    return hr;}// override these two functions if you want to inform something// about entry to or exit from streaming state.HRESULTCTransformFilter::StartStreaming(){    return NOERROR;}HRESULTCTransformFilter::StopStreaming(){    return NOERROR;}// override this to grab extra interfaces on connectionHRESULTCTransformFilter::CheckConnect(PIN_DIRECTION dir,IPin *pPin){    UNREFERENCED_PARAMETER(dir);    UNREFERENCED_PARAMETER(pPin);    return NOERROR;}// place holder to allow derived classes to release any extra interfacesHRESULTCTransformFilter::BreakConnect(PIN_DIRECTION dir){    UNREFERENCED_PARAMETER(dir);    return NOERROR;}// Let derived classes know about connection completionHRESULTCTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin){    UNREFERENCED_PARAMETER(direction);    UNREFERENCED_PARAMETER(pReceivePin);    return NOERROR;}// override this to know when the media type is really setHRESULTCTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt){    UNREFERENCED_PARAMETER(direction);    UNREFERENCED_PARAMETER(pmt);    return NOERROR;}// Set up our output sampleHRESULTCTransformFilter::InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample){    IMediaSample *pOutSample;    // default - times are the same    AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();    DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0;    // This will prevent the image renderer from switching us to DirectDraw    // when we can't do it without skipping frames because we're not on a    // keyframe.  If it really has to switch us, it still will, but then we    // will have to wait for the next keyframe    if (!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) {	dwFlags |= AM_GBF_NOTASYNCPOINT;    }    ASSERT(m_pOutput->m_pAllocator != NULL);    HRESULT hr = m_pOutput->m_pAllocator->GetBuffer(             &pOutSample             , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ?                   &pProps->tStart : NULL             , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ?                   &pProps->tStop : NULL             , dwFlags         );    *ppOutSample = pOutSample;    if (FAILED(hr)) {        return hr;    }    ASSERT(pOutSample);    IMediaSample2 *pOutSample2;    if (SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2,                                             (void **)&pOutSample2))) {        /*  Modify it */        AM_SAMPLE2_PROPERTIES OutProps;        EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties(            FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps)        ));        OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags;        OutProps.dwSampleFlags =            (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) |            (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED);        OutProps.tStart = pProps->tStart;        OutProps.tStop  = pProps->tStop;        OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId);        hr = pOutSample2->SetProperties(            FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId),            (PBYTE)&OutProps        );        if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) {            m_bSampleSkipped = FALSE;        }        pOutSample2->Release();    } else {        if (pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) {            pOutSample->SetTime(&pProps->tStart,                                &pProps->tStop);        }        if (pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) {            pOutSample->SetSyncPoint(TRUE);        }        if (pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) {            pOutSample->SetDiscontinuity(TRUE);            m_bSampleSkipped = FALSE;        }        // Copy the media times        LONGLONG MediaStart, MediaEnd;        if (pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) {            pOutSample->SetMediaTime(&MediaStart,&MediaEnd);        }    }    return S_OK;}// override this to customize the transform processHRESULTCTransformFilter::Receive(IMediaSample *pSample){    /*  Check for other streams and pass them on */    AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();    if (pProps->dwStreamId != AM_STREAM_MEDIA) {        return m_pOutput->m_pInputPin->Receive(pSample);    }    HRESULT hr;    ASSERT(pSample);    IMediaSample * pOutSample;    // If no output to deliver to then no point sending us data    ASSERT (m_pOutput != NULL) ;    // Set up the output sample    hr = InitializeOutputSample(pSample, &pOutSample);    if (FAILED(hr)) {        return hr;    }    // Start timing the transform (if PERF is defined)    //MSR_START(m_idTransform);    // have the derived class transform the data    hr = Transform(pSample, pOutSample);    // Stop the clock and log it (if PERF is defined)    //MSR_STOP(m_idTransform);    if (FAILED(hr)) {	DbgLog((LOG_TRACE,1,TEXT("Error from transform")));    } else {        // the Transform() function can return S_FALSE to indicate that the        // sample should not be delivered; we only deliver the sample if it's        // really S_OK (same as NOERROR, of course.)        if (hr == NOERROR) {    	    hr = m_pOutput->m_pInputPin->Receive(pOutSample);            m_bSampleSkipped = FALSE;	// last thing no longer dropped        } else {            // S_FALSE returned from Transform is a PRIVATE agreement            // We should return NOERROR from Receive() in this cause because returning S_FALSE            // from Receive() means that this is the end of the stream and no more data should            // be sent.            if (S_FALSE == hr) {                //  Release the sample before calling notify to avoid                //  deadlocks if the sample holds a lock on the system                //  such as DirectDraw buffers do                pOutSample->Release();                m_bSampleSkipped = TRUE;                if (!m_bQualityChanged) {                    NotifyEvent(EC_QUALITY_CHANGE,0,0);                    m_bQualityChanged = TRUE;                }                return NOERROR;            }        }    }    // release the output buffer. If the connected pin still needs it,    // it will have addrefed it itself.    pOutSample->Release();    return hr;}// Return S_FALSE to mean "pass the note on upstream"// Return NOERROR (Same as S_OK)// to mean "I've done something about it, don't pass it on"HRESULT CTransformFilter::AlterQuality(Quality q){    UNREFERENCED_PARAMETER(q);    return S_FALSE;}// EndOfStream received. Default behaviour is to deliver straight// downstream, since we have no queued data. If you overrode Receive// and have queue data, then you need to handle this and deliver EOS after// all queued data is sentHRESULTCTransformFilter::EndOfStream(void){    HRESULT hr = NOERROR;    if (m_pOutput != NULL) {        hr = m_pOutput->DeliverEndOfStream();    }    return hr;}// enter flush state. Receives already blocked// must override this if you have queued data or a worker threadHRESULTCTransformFilter::BeginFlush(void){    HRESULT hr = NOERROR;    if (m_pOutput != NULL) {	// block receives -- done by caller (CBaseInputPin::BeginFlush)	// discard queued data -- we have no queued data	// free anyone blocked on receive - not possible in this filter	// call downstream	hr = m_pOutput->DeliverBeginFlush();    }    return hr;}// leave flush state. must override this if you have queued data// or a worker threadHRESULTCTransformFilter::EndFlush(void){    // sync with pushing thread -- we have no worker thread    // ensure no more data to go downstream -- we have no queued data    // call EndFlush on downstream pins    ASSERT (m_pOutput != NULL);    return m_pOutput->DeliverEndFlush();    // caller (the input pin's method) will unblock Receives}// override these so that the derived filter can catch themSTDMETHODIMPCTransformFilter::Stop(){    CAutoLock lck1(&m_csFilter);    if (m_State == State_Stopped) {        return NOERROR;    }    // Succeed the Stop if we are not completely connected    ASSERT(m_pInput == NULL || m_pOutput != NULL);    if (m_pInput == NULL || m_pInput->IsConnected() == FALSE ||        m_pOutput->IsConnected() == FALSE) {                m_State = State_Stopped;                m_bEOSDelivered = FALSE;                return NOERROR;    }    ASSERT(m_pInput);    ASSERT(m_pOutput);    // decommit the input pin before locking or we can deadlock    m_pInput->Inactive();    // synchronize with Receive calls    CAutoLock lck2(&m_csReceiveProtector);    CAutoLock lck3(&m_csReceive);    m_pOutput->Inactive();    // allow a class derived from CTransformFilter    // to know about starting and stopping streaming    HRESULT hr = StopStreaming();    if (SUCCEEDED(hr)) {	// complete the state transition	m_State = State_Stopped;	m_bEOSDelivered = FALSE;    }    return hr;}STDMETHODIMPCTransformFilter::Pause(){    CAutoLock lck(&m_csFilter);    HRESULT hr = NOERROR;    if (m_State == State_Paused) {        // (This space left deliberately blank)    }    // If we have no input pin or it isn't yet connected then when we are    // asked to pause we deliver an end of stream to the downstream filter.    // This makes sure that it doesn't sit there forever waiting for    // samples which we cannot ever deliver without an input connection.    else if (m_pInput == NULL || m_pInput->IsConnected() == FALSE) {        if (m_pOutput && m_bEOSDelivered == FALSE) {            m_pOutput->DeliverEndOfStream();            m_bEOSDelivered = TRUE;        }        m_State = State_Paused;    }    // We may have an input connection but no output connection    // However, if we have an input pin we do have an output pin    else if (m_pOutput->IsConnected() == FALSE) {        m_State = State_Paused;    }    else {	if (m_State == State_Stopped) {	    // allow a class derived from CTransformFilter	    // to know about starting and stopping streaming            CAutoLock lck2(&m_csReceiveProtector);            CAutoLock lck3(&m_csReceive);	    hr = StartStreaming();	}	if (SUCCEEDED(hr)) {	    hr = CBaseFilter::Pause();	}    }    m_bSampleSkipped = FALSE;

⌨️ 快捷键说明

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