1017 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			1017 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								// File: Transfrm.cpp
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Desc: DirectShow base classes - implements class for simple transform
							 | 
						||
| 
								 | 
							
								//       filters such as video decompressors.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <streams.h>
							 | 
						||
| 
								 | 
							
								#include <measure.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// =================================================================
							 | 
						||
| 
								 | 
							
								// Implements the CTransformFilter class
							 | 
						||
| 
								 | 
							
								// =================================================================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CTransformFilter::CTransformFilter(__in_opt LPCTSTR pName,
							 | 
						||
| 
								 | 
							
								                                   __inout_opt 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
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef UNICODE
							 | 
						||
| 
								 | 
							
								CTransformFilter::CTransformFilter(__in_opt LPCSTR pName,
							 | 
						||
| 
								 | 
							
								                                   __inout_opt 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
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// destructor
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CTransformFilter::~CTransformFilter()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Delete the pins
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    delete m_pInput;
							 | 
						||
| 
								 | 
							
								    delete m_pOutput;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Transform place holder - should never be called
							 | 
						||
| 
								 | 
							
								HRESULT 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 provide
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int 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, __deref_out 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.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::StartStreaming()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return NOERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::StopStreaming()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return NOERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// override this to grab extra interfaces on connection
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::CheckConnect(PIN_DIRECTION dir, IPin *pPin)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    UNREFERENCED_PARAMETER(dir);
							 | 
						||
| 
								 | 
							
								    UNREFERENCED_PARAMETER(pPin);
							 | 
						||
| 
								 | 
							
								    return NOERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// place holder to allow derived classes to release any extra interfaces
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::BreakConnect(PIN_DIRECTION dir)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    UNREFERENCED_PARAMETER(dir);
							 | 
						||
| 
								 | 
							
								    return NOERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Let derived classes know about connection completion
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    UNREFERENCED_PARAMETER(direction);
							 | 
						||
| 
								 | 
							
								    UNREFERENCED_PARAMETER(pReceivePin);
							 | 
						||
| 
								 | 
							
								    return NOERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// override this to know when the media type is really set
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    UNREFERENCED_PARAMETER(direction);
							 | 
						||
| 
								 | 
							
								    UNREFERENCED_PARAMETER(pmt);
							 | 
						||
| 
								 | 
							
								    return NOERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Set up our output sample
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::InitializeOutputSample(IMediaSample *pSample, __deref_out 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 process
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::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 sent
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::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 thread
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::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 thread
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::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 them
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								STDMETHODIMP
							 | 
						||
| 
								 | 
							
								CTransformFilter::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_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;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								STDMETHODIMP
							 | 
						||
| 
								 | 
							
								CTransformFilter::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_csReceive);
							 | 
						||
| 
								 | 
							
									    hr = StartStreaming();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if (SUCCEEDED(hr)) {
							 | 
						||
| 
								 | 
							
									    hr = CBaseFilter::Pause();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    m_bSampleSkipped = FALSE;
							 | 
						||
| 
								 | 
							
								    m_bQualityChanged = FALSE;
							 | 
						||
| 
								 | 
							
								    return hr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformFilter::NewSegment(
							 | 
						||
| 
								 | 
							
								    REFERENCE_TIME tStart,
							 | 
						||
| 
								 | 
							
								    REFERENCE_TIME tStop,
							 | 
						||
| 
								 | 
							
								    double dRate)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (m_pOutput != NULL) {
							 | 
						||
| 
								 | 
							
								        return m_pOutput->DeliverNewSegment(tStart, tStop, dRate);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return S_OK;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Check streaming status
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformInputPin::CheckStreaming()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    ASSERT(m_pTransformFilter->m_pOutput != NULL);
							 | 
						||
| 
								 | 
							
								    if (!m_pTransformFilter->m_pOutput->IsConnected()) {
							 | 
						||
| 
								 | 
							
								        return VFW_E_NOT_CONNECTED;
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        //  Shouldn't be able to get any data if we're not connected!
							 | 
						||
| 
								 | 
							
								        ASSERT(IsConnected());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        //  we're flushing
							 | 
						||
| 
								 | 
							
								        if (m_bFlushing) {
							 | 
						||
| 
								 | 
							
								            return S_FALSE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        //  Don't process stuff in Stopped state
							 | 
						||
| 
								 | 
							
								        if (IsStopped()) {
							 | 
						||
| 
								 | 
							
								            return VFW_E_WRONG_STATE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (m_bRunTimeError) {
							 | 
						||
| 
								 | 
							
								    	    return VFW_E_RUNTIME_ERROR;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return S_OK;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// =================================================================
							 | 
						||
| 
								 | 
							
								// Implements the CTransformInputPin class
							 | 
						||
| 
								 | 
							
								// =================================================================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// constructor
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CTransformInputPin::CTransformInputPin(
							 | 
						||
| 
								 | 
							
								    __in_opt LPCTSTR pObjectName,
							 | 
						||
| 
								 | 
							
								    __inout CTransformFilter *pTransformFilter,
							 | 
						||
| 
								 | 
							
								    __inout HRESULT * phr,
							 | 
						||
| 
								 | 
							
								    __in_opt LPCWSTR pName)
							 | 
						||
| 
								 | 
							
								    : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin")));
							 | 
						||
| 
								 | 
							
								    m_pTransformFilter = pTransformFilter;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef UNICODE
							 | 
						||
| 
								 | 
							
								CTransformInputPin::CTransformInputPin(
							 | 
						||
| 
								 | 
							
								    __in_opt LPCSTR pObjectName,
							 | 
						||
| 
								 | 
							
								    __inout CTransformFilter *pTransformFilter,
							 | 
						||
| 
								 | 
							
								    __inout HRESULT * phr,
							 | 
						||
| 
								 | 
							
								    __in_opt LPCWSTR pName)
							 | 
						||
| 
								 | 
							
								    : CBaseInputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pName)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    DbgLog((LOG_TRACE,2,TEXT("CTransformInputPin::CTransformInputPin")));
							 | 
						||
| 
								 | 
							
								    m_pTransformFilter = pTransformFilter;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// provides derived filter a chance to grab extra interfaces
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformInputPin::CheckConnect(IPin *pPin)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_INPUT,pPin);
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								    	return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return CBaseInputPin::CheckConnect(pPin);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// provides derived filter a chance to release it's extra interfaces
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformInputPin::BreakConnect()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    //  Can't disconnect unless stopped
							 | 
						||
| 
								 | 
							
								    ASSERT(IsStopped());
							 | 
						||
| 
								 | 
							
								    m_pTransformFilter->BreakConnect(PINDIR_INPUT);
							 | 
						||
| 
								 | 
							
								    return CBaseInputPin::BreakConnect();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Let derived class know when the input pin is connected
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformInputPin::CompleteConnect(IPin *pReceivePin)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_INPUT,pReceivePin);
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								        return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return CBaseInputPin::CompleteConnect(pReceivePin);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// check that we can support a given media type
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformInputPin::CheckMediaType(const CMediaType* pmt)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Check the input type
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    HRESULT hr = m_pTransformFilter->CheckInputType(pmt);
							 | 
						||
| 
								 | 
							
								    if (S_OK != hr) {
							 | 
						||
| 
								 | 
							
								        return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // if the output pin is still connected, then we have
							 | 
						||
| 
								 | 
							
								    // to check the transform not just the input format
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ((m_pTransformFilter->m_pOutput != NULL) &&
							 | 
						||
| 
								 | 
							
								        (m_pTransformFilter->m_pOutput->IsConnected())) {
							 | 
						||
| 
								 | 
							
								            return m_pTransformFilter->CheckTransform(
							 | 
						||
| 
								 | 
							
								                      pmt,
							 | 
						||
| 
								 | 
							
										      &m_pTransformFilter->m_pOutput->CurrentMediaType());
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// set the media type for this connection
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformInputPin::SetMediaType(const CMediaType* mtIn)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Set the base class media type (should always succeed)
							 | 
						||
| 
								 | 
							
								    HRESULT hr = CBasePin::SetMediaType(mtIn);
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								        return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // check the transform can be done (should always succeed)
							 | 
						||
| 
								 | 
							
								    ASSERT(SUCCEEDED(m_pTransformFilter->CheckInputType(mtIn)));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return m_pTransformFilter->SetMediaType(PINDIR_INPUT,mtIn);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// =================================================================
							 | 
						||
| 
								 | 
							
								// Implements IMemInputPin interface
							 | 
						||
| 
								 | 
							
								// =================================================================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// provide EndOfStream that passes straight downstream
							 | 
						||
| 
								 | 
							
								// (there is no queued data)
							 | 
						||
| 
								 | 
							
								STDMETHODIMP
							 | 
						||
| 
								 | 
							
								CTransformInputPin::EndOfStream(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(&m_pTransformFilter->m_csReceive);
							 | 
						||
| 
								 | 
							
								    HRESULT hr = CheckStreaming();
							 | 
						||
| 
								 | 
							
								    if (S_OK == hr) {
							 | 
						||
| 
								 | 
							
								       hr = m_pTransformFilter->EndOfStream();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return hr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// enter flushing state. Call default handler to block Receives, then
							 | 
						||
| 
								 | 
							
								// pass to overridable method in filter
							 | 
						||
| 
								 | 
							
								STDMETHODIMP
							 | 
						||
| 
								 | 
							
								CTransformInputPin::BeginFlush(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(&m_pTransformFilter->m_csFilter);
							 | 
						||
| 
								 | 
							
								    //  Are we actually doing anything?
							 | 
						||
| 
								 | 
							
								    ASSERT(m_pTransformFilter->m_pOutput != NULL);
							 | 
						||
| 
								 | 
							
								    if (!IsConnected() ||
							 | 
						||
| 
								 | 
							
								        !m_pTransformFilter->m_pOutput->IsConnected()) {
							 | 
						||
| 
								 | 
							
								        return VFW_E_NOT_CONNECTED;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    HRESULT hr = CBaseInputPin::BeginFlush();
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								    	return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return m_pTransformFilter->BeginFlush();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// leave flushing state.
							 | 
						||
| 
								 | 
							
								// Pass to overridable method in filter, then call base class
							 | 
						||
| 
								 | 
							
								// to unblock receives (finally)
							 | 
						||
| 
								 | 
							
								STDMETHODIMP
							 | 
						||
| 
								 | 
							
								CTransformInputPin::EndFlush(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(&m_pTransformFilter->m_csFilter);
							 | 
						||
| 
								 | 
							
								    //  Are we actually doing anything?
							 | 
						||
| 
								 | 
							
								    ASSERT(m_pTransformFilter->m_pOutput != NULL);
							 | 
						||
| 
								 | 
							
								    if (!IsConnected() ||
							 | 
						||
| 
								 | 
							
								        !m_pTransformFilter->m_pOutput->IsConnected()) {
							 | 
						||
| 
								 | 
							
								        return VFW_E_NOT_CONNECTED;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    HRESULT hr = m_pTransformFilter->EndFlush();
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								        return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return CBaseInputPin::EndFlush();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// here's the next block of data from the stream.
							 | 
						||
| 
								 | 
							
								// AddRef it yourself if you need to hold it beyond the end
							 | 
						||
| 
								 | 
							
								// of this call.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformInputPin::Receive(IMediaSample * pSample)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HRESULT hr;
							 | 
						||
| 
								 | 
							
								    CAutoLock lck(&m_pTransformFilter->m_csReceive);
							 | 
						||
| 
								 | 
							
								    ASSERT(pSample);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // check all is well with the base class
							 | 
						||
| 
								 | 
							
								    hr = CBaseInputPin::Receive(pSample);
							 | 
						||
| 
								 | 
							
								    if (S_OK == hr) {
							 | 
						||
| 
								 | 
							
								        hr = m_pTransformFilter->Receive(pSample);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return hr;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// override to pass downstream
							 | 
						||
| 
								 | 
							
								STDMETHODIMP
							 | 
						||
| 
								 | 
							
								CTransformInputPin::NewSegment(
							 | 
						||
| 
								 | 
							
								    REFERENCE_TIME tStart,
							 | 
						||
| 
								 | 
							
								    REFERENCE_TIME tStop,
							 | 
						||
| 
								 | 
							
								    double dRate)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    //  Save the values in the pin
							 | 
						||
| 
								 | 
							
								    CBasePin::NewSegment(tStart, tStop, dRate);
							 | 
						||
| 
								 | 
							
								    return m_pTransformFilter->NewSegment(tStart, tStop, dRate);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// =================================================================
							 | 
						||
| 
								 | 
							
								// Implements the CTransformOutputPin class
							 | 
						||
| 
								 | 
							
								// =================================================================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// constructor
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::CTransformOutputPin(
							 | 
						||
| 
								 | 
							
								    __in_opt LPCTSTR pObjectName,
							 | 
						||
| 
								 | 
							
								    __inout CTransformFilter *pTransformFilter,
							 | 
						||
| 
								 | 
							
								    __inout HRESULT * phr,
							 | 
						||
| 
								 | 
							
								    __in_opt LPCWSTR pPinName)
							 | 
						||
| 
								 | 
							
								    : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName),
							 | 
						||
| 
								 | 
							
								      m_pPosition(NULL)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin")));
							 | 
						||
| 
								 | 
							
								    m_pTransformFilter = pTransformFilter;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef UNICODE
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::CTransformOutputPin(
							 | 
						||
| 
								 | 
							
								    __in_opt LPCSTR pObjectName,
							 | 
						||
| 
								 | 
							
								    __inout CTransformFilter *pTransformFilter,
							 | 
						||
| 
								 | 
							
								    __inout HRESULT * phr,
							 | 
						||
| 
								 | 
							
								    __in_opt LPCWSTR pPinName)
							 | 
						||
| 
								 | 
							
								    : CBaseOutputPin(pObjectName, pTransformFilter, &pTransformFilter->m_csFilter, phr, pPinName),
							 | 
						||
| 
								 | 
							
								      m_pPosition(NULL)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::CTransformOutputPin")));
							 | 
						||
| 
								 | 
							
								    m_pTransformFilter = pTransformFilter;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// destructor
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::~CTransformOutputPin()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    DbgLog((LOG_TRACE,2,TEXT("CTransformOutputPin::~CTransformOutputPin")));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (m_pPosition) m_pPosition->Release();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// overriden to expose IMediaPosition and IMediaSeeking control interfaces
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								STDMETHODIMP
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CheckPointer(ppv,E_POINTER);
							 | 
						||
| 
								 | 
							
								    ValidateReadWritePtr(ppv,sizeof(PVOID));
							 | 
						||
| 
								 | 
							
								    *ppv = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // we should have an input pin by now
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ASSERT(m_pTransformFilter->m_pInput != NULL);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (m_pPosition == NULL) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            HRESULT hr = CreatePosPassThru(
							 | 
						||
| 
								 | 
							
								                             GetOwner(),
							 | 
						||
| 
								 | 
							
								                             FALSE,
							 | 
						||
| 
								 | 
							
								                             (IPin *)m_pTransformFilter->m_pInput,
							 | 
						||
| 
								 | 
							
								                             &m_pPosition);
							 | 
						||
| 
								 | 
							
								            if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								                return hr;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return m_pPosition->QueryInterface(riid, ppv);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// provides derived filter a chance to grab extra interfaces
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::CheckConnect(IPin *pPin)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // we should have an input connection first
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ASSERT(m_pTransformFilter->m_pInput != NULL);
							 | 
						||
| 
								 | 
							
								    if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) {
							 | 
						||
| 
								 | 
							
									    return E_UNEXPECTED;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    HRESULT hr = m_pTransformFilter->CheckConnect(PINDIR_OUTPUT,pPin);
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
									    return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return CBaseOutputPin::CheckConnect(pPin);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// provides derived filter a chance to release it's extra interfaces
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::BreakConnect()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    //  Can't disconnect unless stopped
							 | 
						||
| 
								 | 
							
								    ASSERT(IsStopped());
							 | 
						||
| 
								 | 
							
								    m_pTransformFilter->BreakConnect(PINDIR_OUTPUT);
							 | 
						||
| 
								 | 
							
								    return CBaseOutputPin::BreakConnect();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Let derived class know when the output pin is connected
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::CompleteConnect(IPin *pReceivePin)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HRESULT hr = m_pTransformFilter->CompleteConnect(PINDIR_OUTPUT,pReceivePin);
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								        return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return CBaseOutputPin::CompleteConnect(pReceivePin);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// check a given transform - must have selected input type first
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // must have selected input first
							 | 
						||
| 
								 | 
							
								    ASSERT(m_pTransformFilter->m_pInput != NULL);
							 | 
						||
| 
								 | 
							
								    if ((m_pTransformFilter->m_pInput->IsConnected() == FALSE)) {
							 | 
						||
| 
								 | 
							
									        return E_INVALIDARG;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return m_pTransformFilter->CheckTransform(
							 | 
						||
| 
								 | 
							
												    &m_pTransformFilter->m_pInput->CurrentMediaType(),
							 | 
						||
| 
								 | 
							
												    pmtOut);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// called after we have agreed a media type to actually set it in which case
							 | 
						||
| 
								 | 
							
								// we run the CheckTransform function to get the output format type again
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::SetMediaType(const CMediaType* pmtOut)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HRESULT hr = NOERROR;
							 | 
						||
| 
								 | 
							
								    ASSERT(m_pTransformFilter->m_pInput != NULL);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ASSERT(m_pTransformFilter->m_pInput->CurrentMediaType().IsValid());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Set the base class media type (should always succeed)
							 | 
						||
| 
								 | 
							
								    hr = CBasePin::SetMediaType(pmtOut);
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								        return hr;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef DEBUG
							 | 
						||
| 
								 | 
							
								    if (FAILED(m_pTransformFilter->CheckTransform(&m_pTransformFilter->
							 | 
						||
| 
								 | 
							
													m_pInput->CurrentMediaType(),pmtOut))) {
							 | 
						||
| 
								 | 
							
									DbgLog((LOG_ERROR,0,TEXT("*** This filter is accepting an output media type")));
							 | 
						||
| 
								 | 
							
									DbgLog((LOG_ERROR,0,TEXT("    that it can't currently transform to.  I hope")));
							 | 
						||
| 
								 | 
							
									DbgLog((LOG_ERROR,0,TEXT("    it's smart enough to reconnect its input.")));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return m_pTransformFilter->SetMediaType(PINDIR_OUTPUT,pmtOut);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// pass the buffer size decision through to the main transform class
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::DecideBufferSize(
							 | 
						||
| 
								 | 
							
								    IMemAllocator * pAllocator,
							 | 
						||
| 
								 | 
							
								    __inout ALLOCATOR_PROPERTIES* pProp)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    return m_pTransformFilter->DecideBufferSize(pAllocator, pProp);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// return a specific media type indexed by iPosition
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								HRESULT
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::GetMediaType(
							 | 
						||
| 
								 | 
							
								    int iPosition,
							 | 
						||
| 
								 | 
							
								    __inout CMediaType *pMediaType)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    ASSERT(m_pTransformFilter->m_pInput != NULL);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //  We don't have any media types if our input is not connected
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (m_pTransformFilter->m_pInput->IsConnected()) {
							 | 
						||
| 
								 | 
							
								        return m_pTransformFilter->GetMediaType(iPosition,pMediaType);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        return VFW_S_NO_MORE_ITEMS;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Override this if you can do something constructive to act on the
							 | 
						||
| 
								 | 
							
								// quality message.  Consider passing it upstream as well
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Pass the quality mesage on upstream.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								STDMETHODIMP
							 | 
						||
| 
								 | 
							
								CTransformOutputPin::Notify(IBaseFilter * pSender, Quality q)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    UNREFERENCED_PARAMETER(pSender);
							 | 
						||
| 
								 | 
							
								    ValidateReadPtr(pSender,sizeof(IBaseFilter));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // First see if we want to handle this ourselves
							 | 
						||
| 
								 | 
							
								    HRESULT hr = m_pTransformFilter->AlterQuality(q);
							 | 
						||
| 
								 | 
							
								    if (hr!=S_FALSE) {
							 | 
						||
| 
								 | 
							
								        return hr;        // either S_OK or a failure
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // S_FALSE means we pass the message on.
							 | 
						||
| 
								 | 
							
								    // Find the quality sink for our input pin and send it there
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ASSERT(m_pTransformFilter->m_pInput != NULL);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return m_pTransformFilter->m_pInput->PassNotify(q);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								} // Notify
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// the following removes a very large number of level 4 warnings from the microsoft
							 | 
						||
| 
								 | 
							
								// compiler output, which are not useful at all in this case.
							 | 
						||
| 
								 | 
							
								#pragma warning(disable:4514)
							 |