home *** CD-ROM | disk | FTP | other *** search
- //==========================================================================;
- //
- // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
- // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
- // PURPOSE.
- //
- // Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
- //
- //--------------------------------------------------------------------------;
-
- // Base class for simple Transform-In-Place filters such as audio
-
- #include <streams.h>
- #include <measure.h>
- #include <transip.h>
-
-
- // =================================================================
- // Implements the CTransInPlaceFilter class
- // =================================================================
-
- CTransInPlaceFilter::CTransInPlaceFilter
- ( TCHAR *pName,
- LPUNKNOWN pUnk,
- CLSID clsid,
- HRESULT *phr
- )
- : CTransformFilter(pName, pUnk, clsid, phr)
- {
- ASSERT(phr);
- #ifdef PERF
- RegisterPerfId();
- #endif // PERF
- }
-
-
- // 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
-
- // As soon as any pin is needed we create both (this is different from the
- // usual transform filter) because enumerators, allocators etc are passed
- // through from one pin to another and it becomes very painful if the other
- // pin isn't there.
-
- CBasePin *
- CTransInPlaceFilter::GetPin(int n)
- {
- HRESULT hr = S_OK;
-
- // Create an input pin if not already done
-
- if (m_pInput == NULL) {
-
- m_pInput = new CTransInPlaceInputPin( NAME("TransInPlace input pin")
- , this // Owner filter
- , &hr // Result code
- , L"Input" // Pin name
- );
-
- // a failed return code should delete the object
-
- if (FAILED(hr) || m_pInput == NULL) {
- delete m_pInput;
- m_pInput = NULL;
- }
- }
-
- // Create an output pin if not already done
-
- if (m_pOutput == NULL) {
-
- m_pOutput = new CTransInPlaceOutputPin( NAME("TransInPlace output pin")
- , this // Owner filter
- , &hr // Result code
- , L"Output" // Pin name
- );
-
- // a failed return code should delete the object
-
- if (FAILED(hr) || m_pOutput == NULL) {
- delete m_pOutput;
- m_pOutput = NULL;
- }
- }
-
- // Return the appropriate pin
-
- ASSERT (n>=0 && n<=1);
- if (n == 0) {
- return m_pInput;
- } else if (n==1) {
- return m_pOutput;
- } else {
- return NULL;
- }
- }
-
-
-
- HRESULT CTransInPlaceFilter::CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin)
- {
- ASSERT(m_pInput);
- ASSERT(m_pOutput);
-
- // if we are not part of a graph, then don't indirect the pointer
- // this probably prevents use of the filter without a filtergraph
- if (!m_pGraph) {
- return VFW_E_NOT_IN_GRAPH;
- }
-
- // Always reconnect the input to account for buffering changes
-
- if (dir == PINDIR_OUTPUT) {
- if( m_pInput->IsConnected() ) {
- return m_pGraph->Reconnect( m_pInput );
- }
- return NOERROR;
- }
-
- ASSERT(dir == PINDIR_INPUT);
-
- // Reconnect output if necessary
-
- if( m_pOutput->IsConnected() ) {
-
- if ( m_pInput->CurrentMediaType()
- != m_pOutput->CurrentMediaType()
- ) {
- return m_pGraph->Reconnect( m_pOutput );
- }
- }
- return NOERROR;
- }
-
- // override this to customize the transform process
-
- HRESULT
- CTransInPlaceFilter::Receive(IMediaSample *pSample)
- {
- HRESULT hr;
-
- // Start timing the TransInPlace (if PERF is defined)
- MSR_START(m_idTransInPlace);
-
- // have the derived class transform the data
- hr = Transform(pSample);
-
- // Stop the clock and log it (if PERF is defined)
- MSR_STOP(m_idTransInPlace);
-
- if (FAILED(hr)) {
- DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace")));
- return hr;
- }
-
- // 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->Deliver(pSample);
- } else {
- // But it would be an error to return this private hack
- // to the caller ...
- if (S_FALSE == hr) {
- hr = NOERROR;
- }
- }
-
- return hr;
- }
-
-
-
- // =================================================================
- // Implements the CTransInPlaceInputPin class
- // =================================================================
-
-
- // constructor
-
- CTransInPlaceInputPin::CTransInPlaceInputPin
- ( TCHAR *pObjectName
- , CTransInPlaceFilter *pFilter
- , HRESULT *phr
- , LPCWSTR pName
- )
- : CTransformInputPin(pObjectName,
- pFilter,
- phr,
- pName)
- {
- DbgLog((LOG_TRACE, 2
- , TEXT("CTransInPlaceInputPin::CTransInPlaceInputPin")));
- m_pTIPFilter = pFilter;
- }
-
-
- // =================================================================
- // Implements IMemInputPin interface
- // =================================================================
-
-
- STDMETHODIMP CTransInPlaceInputPin::GetAllocator(IMemAllocator ** ppAllocator)
- {
- CheckPointer(ppAllocator,E_POINTER);
- ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
- CAutoLock cObjectLock(m_pLock);
-
- // See if we've already got an allocator
- if (m_pAllocator != NULL) {
- *ppAllocator = m_pAllocator;
- m_pAllocator->AddRef();
- return S_OK;
- }
-
- // We don't actually provide an allocator but the downstream filter's
- // input pin may...
- if( m_pTIPFilter->m_pOutput->IsConnected() ){
- IMemInputPin *pIMemInputPin;
-
- HRESULT hr = m_pTIPFilter->m_pOutput->GetConnected()
- ->QueryInterface( IID_IMemInputPin, (void **) &pIMemInputPin );
-
- if( SUCCEEDED( hr ) ){
-
- hr = pIMemInputPin->GetAllocator( ppAllocator );
- pIMemInputPin->Release();
-
- if( SUCCEEDED( hr ) ){
- // Should be addref'd downstream
- return hr;
- }
- }
- }
-
- return VFW_E_NO_ALLOCATOR;
- }
-
-
-
- /* Get told which allocator the upstream output pin is actually going to use */
-
- STDMETHODIMP
- CTransInPlaceInputPin::NotifyAllocator(
- IMemAllocator * pAllocator,
- BOOL bReadOnly)
- {
- CheckPointer(pAllocator,E_POINTER);
- ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
-
- if (bReadOnly) {
- // we are an in-place transform. We scribble on the buffer.
- // We therefore cannot accept a read only buffer.
- return VFW_E_READ_ONLY;
- }
-
- CAutoLock cObjectLock(m_pLock);
-
- // It's possible that the old and the new are the same thing.
- // AddRef before release ensures that we don't unload the damn thing!
- pAllocator->AddRef();
-
- if( m_pAllocator != NULL )
- m_pAllocator->Release();
-
- m_pAllocator = pAllocator;
-
- // Tell our own output pin as we're all on the same one
- // (That's what Transform In Place means)
- m_pTIPFilter->OutputPin()->NotifyAllocator(pAllocator, bReadOnly);
- return NOERROR;
- }
-
-
- // EnumMediaTypes
- // - pass through to our downstream filter
- STDMETHODIMP CTransInPlaceInputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
- {
- // Can only pass through if connected
- if( !m_pTIPFilter->m_pOutput->IsConnected() )
- return VFW_E_NOT_CONNECTED;
-
- return m_pTIPFilter->m_pOutput->GetConnected()->EnumMediaTypes( ppEnum );
- }
-
-
- // CheckMediaType
- // - agree to anything if not connected,
- // otherwise pass through to the downstream filter.
- // This assumes that the filter does not change the media type.
-
- HRESULT CTransInPlaceInputPin::CheckMediaType(const CMediaType *pmt )
- {
- HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
- if (hr!=S_OK) return hr;
-
- if( m_pTIPFilter->m_pOutput->IsConnected() )
- return m_pTIPFilter->m_pOutput->GetConnected()->QueryAccept( pmt );
- else
- return S_OK;
- }
-
-
- // =================================================================
- // Implements the CTransInPlaceOutputPin class
- // =================================================================
-
-
- // constructor
-
- CTransInPlaceOutputPin::CTransInPlaceOutputPin(
- TCHAR *pObjectName,
- CTransInPlaceFilter *pFilter,
- HRESULT * phr,
- LPCWSTR pPinName)
- : CTransformOutputPin( pObjectName
- , pFilter
- , phr
- , pPinName)
- {
- DbgLog(( LOG_TRACE, 2
- , TEXT("CTransInPlaceOutputPin::CTransInPlaceOutputPin")));
- m_pTIPFilter = pFilter;
-
- }
-
-
- // EnumMediaTypes
- // - pass through to our upstream filter
- STDMETHODIMP CTransInPlaceOutputPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
- {
- // Can only pass through if connected.
- if( ! m_pTIPFilter->m_pInput->IsConnected() )
- return VFW_E_NOT_CONNECTED;
-
- return m_pTIPFilter->m_pInput->GetConnected()->EnumMediaTypes( ppEnum );
- }
-
-
-
- // CheckMediaType
- // - agree to anything if not connected,
- // otherwise pass through to the upstream filter.
-
- HRESULT CTransInPlaceOutputPin::CheckMediaType(const CMediaType *pmt )
- {
-
- // Assumes the type does not change. That's why we're calling
- // CheckINPUTType here on the OUTPUT pin.
- HRESULT hr = m_pTIPFilter->CheckInputType(pmt);
- if (hr!=S_OK) return hr;
-
- if( m_pTIPFilter->m_pInput->IsConnected() )
- return m_pTIPFilter->m_pInput->GetConnected()->QueryAccept( pmt );
- else
- return S_OK;
- }
-
-
- /* Decide on an allocator, override this if you want to use your own allocator
- Override DecideBufferSize to call SetProperties. If the input pin fails
- the GetAllocator call then this will construct a CMemAllocator and call
- DecideBufferSize on that, and if that fails then we are completely hosed.
- If the you succeed the DecideBufferSize call, we will notify the input
- pin of the selected allocator. NOTE this is called during Connect() which
- therefore looks after grabbing and locking the object's critical section */
-
- HRESULT
- CTransInPlaceOutputPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc)
- {
- HRESULT hr = NOERROR;
-
- /* Don't even try any new allocators
- We are using the one we already have from our own input pin */
-
- hr = m_pTIPFilter->m_pInput->GetAllocator( &m_pAllocator );
-
- if(FAILED(hr))
- return hr;
-
- ASSERT( m_pAllocator != NULL );
-
- *ppAlloc = m_pAllocator; // The one our own input pin found
-
- // Tell the downstream input pin
- return pPin->NotifyAllocator(*ppAlloc, FALSE);
- }
-
-
-
- /* Get told which allocator the output pin is actually going to use */
-
- // !!! need to fix up read-only etc.
-
- STDMETHODIMP
- CTransInPlaceOutputPin::NotifyAllocator(
- IMemAllocator * pAllocator,
- BOOL bReadOnly)
- {
- CheckPointer(pAllocator,E_POINTER);
- ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
-
- // It's possible that the old and the new are the same thing.
- // AddRef before release ensures that we don't unload the damn thing!
- pAllocator->AddRef();
-
- if( m_pAllocator != NULL )
- m_pAllocator->Release();
-
- m_pAllocator = pAllocator;
-
- return NOERROR;
- }
-
-