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.
- //
- //--------------------------------------------------------------------------;
-
- #include <streams.h>
- #include <initguid.h>
- #include <inftee.h>
- #include <tchar.h>
- #include <stdio.h>
-
-
- //----------------------------------------------------------------------------
- // setup data
- //----------------------------------------------------------------------------
-
- AMOVIESETUP_MEDIATYPE sudPinTypes = { &MEDIATYPE_NULL // clsMajorType
- , &MEDIASUBTYPE_NULL } ; // clsMinorType
-
- AMOVIESETUP_PIN psudPins[] = { { L"Input" // strName
- , FALSE // bRendered
- , FALSE // bOutput
- , FALSE // bZero
- , FALSE // bMany
- , &CLSID_NULL // clsConnectsToFilter
- , L"Output" // strConnectsToPin
- , 1 // nTypes
- , &sudPinTypes } // lpTypes
- , { L"Output" // strName
- , FALSE // bRendered
- , TRUE // bOutput
- , FALSE // bZero
- , FALSE // bMany
- , &CLSID_NULL // clsConnectsToFilter
- , L"Input" // strConnectsToPin
- , 1 // nTypes
- , &sudPinTypes } }; // lpTypes
-
-
- AMOVIESETUP_FILTER sudInfTee = { &CLSID_Tee // clsID
- , L"Infinite Pin Tee" // strName
- , MERIT_DO_NOT_USE // dwMerit
- , 2 // nPins
- , psudPins }; // lpPin
-
- //----------------------------------------------------------------------------
- // Creator function for the class ID
- //----------------------------------------------------------------------------
- CFactoryTemplate g_Templates [1] = { {L"Infinite Pin Tee", &CLSID_Tee, CTee::CreateInstance}} ;
-
- int g_cTemplates = sizeof (g_Templates) / sizeof (g_Templates[0]) ;
-
-
- CUnknown *CTee::CreateInstance (LPUNKNOWN pUnk, HRESULT *phr)
- {
- return new CTee (NAME("Infinite Tee Filter"), pUnk, phr) ;
- }
- //----------------------------------------------------------------------------
- // CTee constructor
- //----------------------------------------------------------------------------
- #pragma warning(disable:4355) // using THIS pointer in constructor for base objects
- CTee::CTee (TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr)
- : m_lCanSeek (TRUE),
- m_pAllocator (NULL),
- m_OutputPinsList (NAME("Tee Output Pins list"), DEFAULTCACHE),
- m_NumOutputPins (0),
- m_NextOutputPinNumber (0),
- m_Input (NAME("Input Pin"), this, phr, L"Input"),
- CBaseFilter (NAME("Infinite Pin Tee Filter"), pUnk, this, CLSID_Tee, phr)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTee constructor")));
-
- ASSERT (phr) ;
-
- // create a single output pin at this time.
- InitOutputPinsList () ;
-
- CTeeOutputPin *pOutputPin = CreateNextOutputPin (this) ;
-
- if (pOutputPin != NULL )
- {
- m_NumOutputPins++ ;
- m_OutputPinsList.AddTail (pOutputPin) ;
- }
-
- }
- #pragma warning(default:4355)
-
- //----------------------------------------------------------------------------
- // CTee destructor
- //----------------------------------------------------------------------------
- CTee::~CTee()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTee destructor")));
- InitOutputPinsList () ;
- }
-
- //----------------------------------------------------------------------------
- // GetSetupData
- //----------------------------------------------------------------------------
- LPAMOVIESETUP_FILTER CTee::GetSetupData()
- {
- return &sudInfTee;
- }
-
- //----------------------------------------------------------------------------
- // CTee::GetPinCount
- //----------------------------------------------------------------------------
- int CTee::GetPinCount ()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTee::GetPinCount")));
- return 1+m_NumOutputPins ;
- }
-
- //----------------------------------------------------------------------------
- // CTee::GetPin
- //----------------------------------------------------------------------------
- CBasePin *CTee::GetPin (int n)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTee::GetPin: PinNumber = %d"), n));
-
- //n == 0 is for input pin. The others are for the output pins
- if (n == 0)
- return &m_Input ;
-
- //output pins
-
- // return the output pin at position (n-1) [zero based]
- return GetPinNFromList (n-1) ;
- }
- //----------------------------------------------------------------------------
- // CTee::InitOutputPinsList () (HELPER FUNCTION)
- //----------------------------------------------------------------------------
- void CTee::InitOutputPinsList ()
- {
- POSITION pos = m_OutputPinsList.GetHeadPosition () ;
- while (pos)
- {
- CTeeOutputPin *pOutputPin = m_OutputPinsList.GetNext (pos) ;
- ASSERT (pOutputPin->m_pOutputQueue == NULL) ;
- pOutputPin->Release() ;
- }
- m_NumOutputPins = 0 ;
- m_OutputPinsList.RemoveAll () ;
- }
- //----------------------------------------------------------------------------
- // CTee::CreateNextOutputPin (HELPER FUNCTION)
- //----------------------------------------------------------------------------
- CTeeOutputPin *CTee::CreateNextOutputPin (CTee *pTee)
- {
- WCHAR szbuf[20] ; // scratch buffer
- m_NextOutputPinNumber++ ; // next number to use for pin
-
- swprintf (szbuf, L"Output%d", m_NextOutputPinNumber) ;
-
- HRESULT hr = NOERROR ;
- CTeeOutputPin *pPin = new CTeeOutputPin (NAME("Tee Output"), pTee,
- &hr, szbuf,
- m_NextOutputPinNumber) ;
- if (pPin)
- pPin->AddRef () ;
-
- if (FAILED (hr) && pPin != NULL)
- {
- pPin->Release () ;
- pPin = NULL ;
- }
- return pPin ;
- }
- //----------------------------------------------------------------------------
- // CTee::DeleteOutputPin -- HELPER FUNCTION
- //----------------------------------------------------------------------------
- void CTee::DeleteOutputPin (CTeeOutputPin *pPin)
- {
- POSITION pos = m_OutputPinsList.GetHeadPosition () ;
- while (pos)
- {
- POSITION posold = pos ; // remember this position
- CTeeOutputPin *pOutputPin = m_OutputPinsList.GetNext (pos) ;
- if (pOutputPin == pPin)
- {
-
- // if this pin holds the seek interface release it.
- if (pPin->m_bHoldsSeek)
- {
- InterlockedExchange (&m_lCanSeek, FALSE) ;
- pPin->m_bHoldsSeek = FALSE ;
- delete pPin->m_pPosition ;
- }
-
- m_OutputPinsList.Remove (posold) ;
- ASSERT (pOutputPin->m_pOutputQueue == NULL) ;
- delete pPin ;
- m_NumOutputPins-- ;
- IncrementPinVersion();
- break ;
- }
- }
- }
- //----------------------------------------------------------------------------
- // CTee::GetNumFreePins -- HELPER FUNCTION
- //----------------------------------------------------------------------------
- int CTee::GetNumFreePins ()
- {
- int n = 0 ;
- POSITION pos = m_OutputPinsList.GetHeadPosition () ;
- while (pos)
- {
- CTeeOutputPin *pOutputPin = m_OutputPinsList.GetNext (pos) ;
- if (pOutputPin->m_Connected == NULL)
- n++ ;
- }
- return n ;
- }
- //----------------------------------------------------------------------------
- // CTee::GetPinNFromList (HELPER FUNCTION)
- //----------------------------------------------------------------------------
- CTeeOutputPin *CTee::GetPinNFromList (int n)
- {
- //validate the position being asked for
- if (n >= m_NumOutputPins)
- return NULL ;
-
- // get the head of the list
- POSITION pos = m_OutputPinsList.GetHeadPosition () ;
-
-
- n++ ; //make the number 1 based
-
- CTeeOutputPin *pOutputPin ;
- while (n)
- {
- pOutputPin = m_OutputPinsList.GetNext (pos) ;
- n-- ;
- }
- return pOutputPin ;
- }
- //----------------------------------------------------------------------------
- // CTee::FindPin (Persistent pinid support)
- //----------------------------------------------------------------------------
- STDMETHODIMP CTee::FindPin(LPCWSTR pwszPinId, IPin **ppPin)
- {
- // There is a plan for pin 1 to pass on quality messages where other pins don't
- // so being the first pin matters.
- *ppPin = GetPin(WstrToInt(pwszPinId));
- if (*ppPin==NULL){
- return VFW_E_NOT_FOUND;
- }
- (*ppPin)->AddRef();
- return NOERROR;
-
- }
- //----------------------------------------------------------------------------
- // CTeeOutputPin::QueryId (Persistent pinid support)
- //----------------------------------------------------------------------------
- STDMETHODIMP CTeeOutputPin::QueryId(LPWSTR * Id)
- {
- POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition () ;
- int nPin = 1; // the first output pin is number 1
-
- // ?? UNUSED -- CTeeOutputPin *pOutputPin ;
- while (pos!=NULL)
- {
- IPin* pip = (IPin*)m_pTee->m_OutputPinsList.GetNext(pos);
- // if this is ME then I have found myself
- if (pip==(IPin*)this) {
- *Id = (LPWSTR)CoTaskMemAlloc(8);
- if (*Id==NULL) {
- return E_OUTOFMEMORY;
- }
- IntToWstr(nPin, *Id);
- return NOERROR;
- }
- ++nPin;
- }
- return VFW_E_NOT_FOUND;
- }
-
- //----------------------------------------------------------------------------
- // CTeeInputPin constructor
- //----------------------------------------------------------------------------
-
- CTeeInputPin::CTeeInputPin (TCHAR *pName, CTee *pTee, HRESULT *phr,
- LPCWSTR pPinName)
- : CBaseInputPin (pName, pTee, pTee, phr, pPinName),
- m_pTee (pTee),
- m_bInsideCheckMediaType (FALSE)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin constructor")));
- ASSERT (pTee) ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeInputPin destructor
- //----------------------------------------------------------------------------
-
- CTeeInputPin::~CTeeInputPin ()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin destructor")));
- ASSERT (m_pTee->m_pAllocator == NULL) ;
- }
-
- //----------------------------------------------------------------------------
- // DisplayMediaType -- DEBUG ONLY HELPER FUNCTION
- //----------------------------------------------------------------------------
-
- void DisplayMediaType(TCHAR *pDescription,const CMediaType *pmt)
- {
- #ifdef DEBUG
-
- // Dump the GUID types and a short description
-
- DbgLog((LOG_TRACE,2,TEXT("")));
- DbgLog((LOG_TRACE,2,TEXT("%s"),pDescription));
- DbgLog((LOG_TRACE,2,TEXT("")));
- DbgLog((LOG_TRACE,2,TEXT("Media Type Description")));
- DbgLog((LOG_TRACE,2,TEXT("Major type %s"),GuidNames[*pmt->Type()]));
- DbgLog((LOG_TRACE,2,TEXT("Subtype %s"),GuidNames[*pmt->Subtype()]));
- DbgLog((LOG_TRACE,2,TEXT("Subtype description %s"),GetSubtypeName(pmt->Subtype())));
- DbgLog((LOG_TRACE,2,TEXT("Format size %d"),pmt->cbFormat));
-
- // Dump the generic media types */
-
- DbgLog((LOG_TRACE,2,TEXT("Fixed size sample %d"),pmt->IsFixedSize()));
- DbgLog((LOG_TRACE,2,TEXT("Temporal compression %d"),pmt->IsTemporalCompressed()));
- DbgLog((LOG_TRACE,2,TEXT("Sample size %d"),pmt->GetSampleSize()));
-
- #endif
- }
-
- //----------------------------------------------------------------------------
- // CTeeInputPin::CheckMediaType
- //----------------------------------------------------------------------------
- HRESULT CTeeInputPin::CheckMediaType (const CMediaType *pmt)
- {
-
- DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::CheckMediaType pmt = %lx"), pmt));
-
- CAutoLock lock_it (m_pLock) ;
-
- // If we are already inside checkmedia type for this pin, return NOERROR
- // It is possble to hookup two of the tee filters and some other filter
- // like the video effects sample to get into this situation. If we
- // do not detect this, we will loop till we blow the stack
- if (m_bInsideCheckMediaType == TRUE)
- return NOERROR ;
- m_bInsideCheckMediaType = TRUE ;
-
- HRESULT hr = NOERROR ;
-
- // display the type of the media for debugging perposes.
- DisplayMediaType (TEXT("Input Pin Checking"), pmt) ;
-
-
- // The media types that we can support are entirely dependent on the
- // downstream connections. If we have downstream connections, we should
- // check with them.
-
- // walk through the list calling each output pin.
-
- int n = m_pTee->m_NumOutputPins ; // number of output pins connected
- POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
-
- while (n)
- {
-
- CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
- if (pOutputPin != NULL)
- {
- if (pOutputPin->m_Connected != NULL)
- {
- // The pin is connected, check its peer
- hr = pOutputPin->m_Connected->QueryAccept (pmt) ;
- if (hr != NOERROR)
- {
- m_bInsideCheckMediaType = FALSE ;
- return VFW_E_TYPE_NOT_ACCEPTED ;
- }
- }
- }
- else
- {
- // This should never happen. We should have as many pins as the
- // count says we have
- ASSERT (FALSE) ;
- }
- n-- ;
- }
-
- // either all the downstream pins have accepted or there are none.
- m_bInsideCheckMediaType = FALSE ;
- return NOERROR ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeInputPin::SetMediaType
- //----------------------------------------------------------------------------
- HRESULT CTeeInputPin::SetMediaType (const CMediaType *pmt)
- {
-
- DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::SetMediaType pmt = %lx"), pmt));
-
- CAutoLock lock_it (m_pLock) ;
-
- HRESULT hr = NOERROR ;
-
- // make sure that the base class likes it
- hr = CBaseInputPin::SetMediaType (pmt) ;
- if (FAILED (hr))
- return hr ;
-
- ASSERT (m_Connected != NULL) ;
-
- return NOERROR ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeInputPin::BreakConnect
- //----------------------------------------------------------------------------
- HRESULT CTeeInputPin::BreakConnect ()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::BreakConnect")));
-
- // release any allocator that we are holding.
- if (m_pTee->m_pAllocator)
- {
- m_pTee->m_pAllocator->Release () ;
- m_pTee->m_pAllocator = NULL ;
- }
-
- return NOERROR ; // this function always succeedes.
- }
-
- //----------------------------------------------------------------------------
- // CTeeInputPin::NotifyAllocator
- //----------------------------------------------------------------------------
- STDMETHODIMP
- CTeeInputPin::NotifyAllocator (IMemAllocator *pAllocator, BOOL bReadOnly)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::NotifyAllocator ptr = %lx"), pAllocator));
-
- CAutoLock lock_it (m_pLock) ;
-
- if (pAllocator == NULL)
- return E_FAIL ;
-
- // free the old allocator if any.
- if (m_pTee->m_pAllocator)
- m_pTee->m_pAllocator->Release () ;
-
- // store away the new allocator
- pAllocator->AddRef () ; // since we are stashing away the ptr
- m_pTee->m_pAllocator = pAllocator ; // save the new allocator
-
- // notify the base class about the allocator.
- return CBaseInputPin::NotifyAllocator (pAllocator,bReadOnly) ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeInputPin::EndOfStream
- //----------------------------------------------------------------------------
- HRESULT CTeeInputPin::EndOfStream ()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::EndOfStream")));
-
- CAutoLock lock_it (m_pLock) ;
-
- ASSERT (m_pTee->m_NumOutputPins) ;
-
- HRESULT hr = NOERROR ;
-
- // walk through the output pins list, sending the message downstream.
-
- int n = m_pTee->m_NumOutputPins ;
- POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
- while (n)
- {
- CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
- if (pOutputPin != NULL)
- {
- // pass call to it.
- hr = pOutputPin->DeliverEndOfStream () ;
- if (FAILED (hr))
- return hr ;
- }
- else
- {
- // This should never happen. We should have as many pins as the
- // count says we have
- ASSERT (FALSE) ;
- }
- n-- ;
- }
- // !!! Why are we NOT passing this on to the base pin when we do it for
- // BeginFlush and EndFlush
- return (NOERROR) ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeInputPin::BeginFlush
- //----------------------------------------------------------------------------
- HRESULT CTeeInputPin::BeginFlush ()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::BeginFlush")));
-
- CAutoLock lock_it (m_pLock) ;
-
- ASSERT (m_pTee->m_NumOutputPins) ;
-
- HRESULT hr = NOERROR ;
-
- // walk through the output pins list, sending the message downstream.
-
- int n = m_pTee->m_NumOutputPins ;
- POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
- while (n)
- {
- CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
- if (pOutputPin != NULL)
- {
- // pass call to it.
- hr = pOutputPin->DeliverBeginFlush () ;
- if (FAILED (hr))
- return hr ;
- }
- else
- {
- // This should never happen. We should have as many pins as the
- // count says we have
- ASSERT (FALSE) ;
- }
- n-- ;
- }
- return CBaseInputPin::BeginFlush () ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeInputPin::EndFlush
- //----------------------------------------------------------------------------
- HRESULT CTeeInputPin::EndFlush ()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::EndFlush")));
-
- CAutoLock lock_it (m_pLock) ;
-
- ASSERT (m_pTee->m_NumOutputPins) ;
-
- HRESULT hr = NOERROR ;
-
- // walk through the output pins list, sending the message downstream.
-
- int n = m_pTee->m_NumOutputPins ;
- POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
- while (n)
- {
- CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
- if (pOutputPin != NULL)
- {
- // pass call to it.
- hr = pOutputPin->DeliverEndFlush () ;
- if (FAILED (hr))
- return hr ;
- }
- else
- {
- // This should never happen. We should have as many pins as the
- // count says we have
- ASSERT (FALSE) ;
- }
- n-- ;
- }
- return CBaseInputPin::EndFlush () ;
- }
- //----------------------------------------------------------------------------
- // CTeeInputPin::Receive
- //----------------------------------------------------------------------------
- HRESULT CTeeInputPin::Receive (IMediaSample *pSample)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeInputPin::pSample ptr = %lx"), pSample));
-
- CAutoLock lock_it (m_pLock) ;
-
- // check that all is well with the base class
- HRESULT hr = NOERROR ;
- hr = CBaseInputPin::Receive (pSample) ;
- if (hr != NOERROR)
- return hr ;
-
- // walk through the output pins list, delivering the buffer to the out pins
-
- int n = m_pTee->m_NumOutputPins ;
- POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
- while (n)
- {
- CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
- if (pOutputPin != NULL)
- {
- // pass call to it.
- hr = pOutputPin->Deliver (pSample) ;
- if (hr != NOERROR)
- return hr ;
- }
- else
- {
- // This should never happen. We should have as many pins as the
- // count says we have
- ASSERT (FALSE) ;
- }
- n-- ;
- }
- return NOERROR ;
- }
-
- //
- // End of connection negotiation. A good time to force all the
- // output pins of differing types to be reconnected.
- HRESULT
- CTeeInputPin::CompleteConnect(IPin *pReceivePin)
- {
-
- HRESULT hr = CBaseInputPin::CompleteConnect(pReceivePin);
- if (FAILED(hr)) {
- return hr;
- }
-
- // now we are definitely connected. Force any output pins to use our
- // type.
-
- int n = m_pTee->m_NumOutputPins ; // number of output pins connected
- POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
-
- while (n)
- {
-
- CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
- if (pOutputPin != NULL)
- {
- // check with downstream pin
- if (pOutputPin->m_Connected != NULL)
- {
- if (m_mt != pOutputPin->m_mt)
- m_pTee->m_pGraph->Reconnect (pOutputPin) ;
- }
- }
- else
- {
- // This should never happen. We should have as many pins as the
- // count says we have
-
- //!!! then why don't we just use List.GetCount() ?
- ASSERT (FALSE) ;
- }
- n-- ;
- }
- return S_OK;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin constructor
- //----------------------------------------------------------------------------
- CTeeOutputPin::CTeeOutputPin (TCHAR *pName, CTee *pTee, HRESULT *phr,
- LPCWSTR pPinName, int PinNumber)
- : CBaseOutputPin (pName, pTee, pTee, phr, pPinName) ,
- m_pOutputQueue (NULL),
- m_bHoldsSeek (FALSE),
- m_pPosition (NULL),
- m_pTee (pTee),
- m_cOurRef (0),
- m_bInsideCheckMediaType (FALSE)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin constructor")));
- ASSERT (pTee) ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin destructor
- //----------------------------------------------------------------------------
- CTeeOutputPin::~CTeeOutputPin ()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin destructor")));
- ASSERT (m_pOutputQueue == NULL) ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::NonDelegatingQueryInterface
- //
- // This function is overwritten to expose IMediaPosition and IMediaSelection
- // Note that only one output stream can be allowed to expose this to avoid
- // conflicts, the other pins will just return E_NOINTERFACE and therefore
- // appear as non seekable streams. We have a LONG value that if exchanged to
- // produce a TRUE means that we have the honor. If it exchanges to FALSE then
- // someone is already in. If we do get it and error occurs then we reset it
- // to TRUE so someone else can get it.
- //----------------------------------------------------------------------------
- STDMETHODIMP CTeeOutputPin::NonDelegatingQueryInterface (REFIID riid, void **ppv)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::NonDelegatingQI" )));
-
- CheckPointer(ppv,E_POINTER);
- ASSERT (ppv) ;
- *ppv = NULL ;
- HRESULT hr = NOERROR ;
-
- // see what interface the caller is interested in.
- if (riid == IID_IMediaPosition || riid == IID_IMediaSelection)
- {
- if (m_pPosition)
- {
- if (m_bHoldsSeek == FALSE)
- return E_NOINTERFACE ;
- return m_pPosition->NonDelegatingQueryInterface (riid, ppv) ;
- }
- }
- else
- return CBaseOutputPin::NonDelegatingQueryInterface (riid, ppv) ;
-
- CAutoLock lock_it (m_pLock) ;
- ASSERT (m_pPosition == NULL) ;
- CPosPassThru *pMediaPosition = NULL ;
-
- // try to create a seeking implementation
- if (InterlockedExchange (&m_pTee->m_lCanSeek, FALSE) == FALSE)
- return E_NOINTERFACE ;
-
- // Create implementation of this dynamically as sometimes we may never
- // try and seek. The helper object implements IMediaPosition and also
- // the IMediaSelection control interface and simply takes the calls
- // normally from the downstream filter and passes them upstream
-
- pMediaPosition = new CPosPassThru (NAME("Tee CPosPassThru"), GetOwner(),
- &hr, (IPin*) &m_pTee->m_Input) ;
- if (pMediaPosition == NULL)
- {
- InterlockedExchange (&m_pTee->m_lCanSeek, TRUE) ;
- return E_OUTOFMEMORY ;
- }
-
- if (FAILED (hr))
- {
- InterlockedExchange (&m_pTee->m_lCanSeek, TRUE) ;
- delete pMediaPosition ;
- return hr ;
- }
-
- m_pPosition = pMediaPosition ;
- m_bHoldsSeek = TRUE ;
- return NonDelegatingQueryInterface (riid, ppv) ;
-
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::NonDelegatingAddRef
- //
- // We need override this method so that we can do proper reference counting
- // on our output pin. The base class CBasePin does not do any reference
- // counting on the pin in RETAIL.
- //
- // Please refer to the comments for the NonDelegatingRelease method for more
- // info on why we need to do this.
- //----------------------------------------------------------------------------
-
- STDMETHODIMP_(ULONG) CTeeOutputPin::NonDelegatingAddRef()
- {
- CAutoLock lock_it (m_pLock) ;
-
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::NonDelegatingAddRef" )));
-
- #ifdef DEBUG
- // update the debug only variable maintained by the base class
- m_cRef++ ;
- ASSERT (m_cRef > 0) ;
- #endif
-
- // now update our reference count
- m_cOurRef++ ;
- ASSERT (m_cOurRef > 0) ;
- return m_cOurRef ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::NonDelegatingRelease
- //
- // CTeeOutputPin overrides this class so that we can take the pin out of our
- // output pins list and delete it when its reference count drops to 1 and there
- // is atleast two free pins.
- //
- // Note that CreateNextOutputPin holds a reference count on the pin so that
- // when the count drops to 1, we know that no one else has the pin.
- //
- // Moreover, the pin that we are about to delete must be a free pin (or else
- // the reference would not have dropped to 1, and we must have atleast one
- // other free pin (as the filter always wants to have one more free pin)
- //
- // Also, since CBasePin::NonDelegatingAddRef passes the call to the owning
- // filter, we will have to call Release on the owning filter as well.
- //
- // Also, note that we maintain our own reference count m_cOurRef as the m_cRef
- // variable maintained by CBasePin is debug only.
- //
- //----------------------------------------------------------------------------
- STDMETHODIMP_(ULONG) CTeeOutputPin::NonDelegatingRelease()
- {
- CAutoLock lock_it (m_pLock) ;
-
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::NonDelegatingRelease" )));
-
- #ifdef DEBUG
- // update the debug only variable in CBasePin
- m_cRef-- ;
- ASSERT(m_cRef >= 0) ;
- #endif
-
- // now update our reference count
- m_cOurRef-- ;
- ASSERT(m_cOurRef >= 0) ;
-
-
- // if the reference count on the object has gone to one, remove
- // the pin from our output pins list and physically delete it
- // provided there are atealst two free pins in the list (including
- // this one)
-
- // Also, when the ref count drops to 0, it really means that our
- // filter that is holding one ref count has released it so we
- // should delete the pin as well.
-
- if (m_cOurRef <= 1)
- {
- int n = 2 ; // default forces pin deletion
- if (m_cOurRef == 1)
- {
- // walk the list of pins, looking for count of free pins
- n = m_pTee->GetNumFreePins () ;
- }
-
- // if there are two free pins, delete this one.
- // NOTE: normall
- if (n >= 2 )
- {
- m_cOurRef = 0 ;
- #ifdef DEBUG
- m_cRef = 0 ;
- #endif
- m_pTee->DeleteOutputPin (this) ;
- return (ULONG) 0 ;
- }
- }
-
-
- return (ULONG) m_cOurRef;
- }
- //----------------------------------------------------------------------------
- // CTeeOutputPin::DecideBufferSize
- //
- // This has to be present to override the PURE virtual class base function.
- //----------------------------------------------------------------------------
- HRESULT CTeeOutputPin::DecideBufferSize (IMemAllocator *pMemAllocator,
- ALLOCATOR_PROPERTIES * ppropInputRequest)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::DecideBufferSize ptr = %lx"), pMemAllocator));
- return NOERROR ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::DecideAllocator
- //----------------------------------------------------------------------------
- HRESULT CTeeOutputPin::DecideAllocator (IMemInputPin *pPin, IMemAllocator **ppAlloc)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::DecideAllocator ptr = %lx"), pPin));
-
- ASSERT (m_pTee->m_pAllocator != NULL) ;
-
- *ppAlloc = NULL ;
-
- // tell the pin about our allocator, set by the input pin.
- HRESULT hr = NOERROR ;
- hr = pPin->NotifyAllocator (m_pTee->m_pAllocator,TRUE) ;
- if (FAILED (hr))
- return hr ;
-
- // return the allocator
- *ppAlloc = m_pTee->m_pAllocator ;
- m_pTee->m_pAllocator->AddRef () ;
- return NOERROR ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::CheckMediaType
- //----------------------------------------------------------------------------
- HRESULT CTeeOutputPin::CheckMediaType (const CMediaType *pmt)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::CheckMediaType ptr = %lx"), pmt));
-
- CAutoLock lock_it (m_pLock) ;
-
- // If we are already inside checkmedia type for this pin, return NOERROR
- // It is possble to hookup two of the tee filters and some other filter
- // like the video effects sample to get into this situation. If we
- // do not detect this, we will loop till we blow the stack
- if (m_bInsideCheckMediaType == TRUE)
- return NOERROR ;
- m_bInsideCheckMediaType = TRUE ;
-
- HRESULT hr = NOERROR ;
-
- // display the type of the media for debugging perposes.
- DisplayMediaType (TEXT("Output Pin Checking"), pmt) ;
-
- // The input needs to have been conneced first.
- if (m_pTee->m_Input.m_Connected == NULL)
- {
- m_bInsideCheckMediaType = FALSE ;
- return VFW_E_NOT_CONNECTED ;
- }
-
- // make sure that our input pin peer is happy with this.
- hr = m_pTee->m_Input.m_Connected->QueryAccept (pmt) ;
- if (hr != NOERROR)
- {
- m_bInsideCheckMediaType = FALSE ;
- return VFW_E_TYPE_NOT_ACCEPTED ;
- }
-
- // check the format with the other outpin pins
-
- int n = m_pTee->m_NumOutputPins ;
- POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
-
- while (n)
- {
- CTeeOutputPin *pOutputPin = m_pTee->m_OutputPinsList.GetNext (pos) ;
- if (pOutputPin != NULL && pOutputPin != this)
- {
- if (pOutputPin->m_Connected != NULL)
- {
- // The pin is connected, check its peer
- hr = pOutputPin->m_Connected->QueryAccept (pmt) ;
- if (hr != NOERROR)
- {
- m_bInsideCheckMediaType = FALSE ;
- return VFW_E_TYPE_NOT_ACCEPTED ;
- }
- }
- }
- n-- ;
- }
- m_bInsideCheckMediaType = FALSE ;
- return NOERROR ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::EnumMediaTypes
- //----------------------------------------------------------------------------
- STDMETHODIMP CTeeOutputPin::EnumMediaTypes (IEnumMediaTypes **ppEnum)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::EnumMediaTypes")));
-
- CAutoLock lock_it (m_pLock) ;
- ASSERT (ppEnum) ;
-
- // make sure that we are connected.
- if (m_pTee->m_Input.m_Connected == NULL)
- return VFW_E_NOT_CONNECTED ;
-
- // we will simply return the enumerator of our input pin's peer.
- return m_pTee->m_Input.m_Connected->EnumMediaTypes (ppEnum) ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::SetMediaType
- //----------------------------------------------------------------------------
- HRESULT CTeeOutputPin::SetMediaType (const CMediaType *pmt)
- {
- CAutoLock lock_it (m_pLock) ;
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::SetMediaType ptr = %lx"), pmt));
-
- // display the format of the media for debugging purposes
- DisplayMediaType (TEXT("Output pin type agreed"), pmt) ;
-
- // make sure that we have an input connected.
- if (m_pTee->m_Input.m_Connected == NULL)
- return VFW_E_NOT_CONNECTED ;
-
- // make sure that the base class likes it.
- HRESULT hr = NOERROR ;
- hr = CBaseOutputPin::SetMediaType (pmt) ;
- if (FAILED (hr))
- return hr ;
-
- return NOERROR ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::CompleteConnect
- //
- //----------------------------------------------------------------------------
- HRESULT CTeeOutputPin::CompleteConnect (IPin *pReceivePin)
- {
- CAutoLock lock_it (m_pLock) ;
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::CompleteConnect ptr = %lx"), pReceivePin));
- ASSERT (m_Connected == pReceivePin) ;
-
- HRESULT hr = NOERROR ;
- hr = CBaseOutputPin::CompleteConnect (pReceivePin) ;
- if (FAILED (hr))
- return hr ;
-
- // if the type is not the same as that stored for the input pin, force the
- // input pins peer to be reconnected
- if (m_mt != m_pTee->m_Input.m_mt)
- m_pTee->m_pGraph->Reconnect (m_pTee->m_Input.m_Connected) ;
-
- // since this pin has been connected up, create another output pin.
- // However, we will do this only if there is no more unconnected
- // pins. Often, CompleteConnect will get called for the same pin
- // during reconnection.
-
- int n = m_pTee->GetNumFreePins () ;
- ASSERT (n <= 1) ;
- if (n == 1)
- return NOERROR ;
-
- // no unconnected pins left, spawn a new one
-
- CTeeOutputPin *pOutputPin = m_pTee->CreateNextOutputPin (m_pTee) ;
- if (pOutputPin != NULL )
- {
- m_pTee->m_NumOutputPins++ ;
- m_pTee->m_OutputPinsList.AddTail (pOutputPin) ;
- m_pTee->IncrementPinVersion();
- }
-
- // !!! At this point we should be able to send some notification that we
- // have sprung a new pin.
-
- return NOERROR ;
- }
- //----------------------------------------------------------------------------
- // CTeeOutputPin::Active
- //
- // This is called when we start running or go paused. We create the output queue
- // object to send data to our associated peer pin.
- //----------------------------------------------------------------------------
- HRESULT CTeeOutputPin::Active ()
- {
- CAutoLock lock_it (m_pLock) ;
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::Active")));
-
- HRESULT hr = NOERROR ;
-
- // make sure that the pin is connected.
- if (m_Connected == NULL)
- return NOERROR ;
-
- // create the output queue if we have to
- if (m_pOutputQueue == NULL)
- {
- m_pOutputQueue = new COutputQueue (m_Connected, &hr, TRUE, FALSE) ;
- if (m_pOutputQueue == NULL)
- return E_OUTOFMEMORY ;
-
- // make sure that the constructor did not return any error.
- if (FAILED (hr))
- {
- delete m_pOutputQueue ;
- m_pOutputQueue = NULL ;
- return hr ;
- }
- }
-
- // pass the call on to the base class
- CBaseOutputPin::Active () ;
- return NOERROR ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::Inactive
- //
- // This is called when we stop streaming. We delete the output queue at this
- // time.
- //----------------------------------------------------------------------------
- HRESULT CTeeOutputPin::Inactive ()
- {
- CAutoLock lock_it (m_pLock) ;
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::Inactive")));
-
- // delete the output queus associated with the pin.
- if (m_pOutputQueue)
- {
- delete m_pOutputQueue ;
- m_pOutputQueue = NULL ;
- }
-
- CBaseOutputPin::Inactive () ;
- return NOERROR ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::Deliver
- //----------------------------------------------------------------------------
- HRESULT CTeeOutputPin::Deliver (IMediaSample *pMediaSample)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::Deliver ptr = %lx"), pMediaSample));
-
- // make sure that we have an output queue
- if (m_pOutputQueue == NULL)
- return NOERROR ;
-
- pMediaSample->AddRef () ;
- return m_pOutputQueue->Receive (pMediaSample) ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::DeliverEndOfStream
- //----------------------------------------------------------------------------
- HRESULT CTeeOutputPin::DeliverEndOfStream ()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::DeliverEndOfStream")));
-
- // make sure that we have an output queue
- if (m_pOutputQueue == NULL)
- return NOERROR ;
-
- m_pOutputQueue->EOS () ;
- return NOERROR ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::DeliverBeginFlush
- //----------------------------------------------------------------------------
- HRESULT CTeeOutputPin::DeliverBeginFlush ()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::DeliverBeginFlush")));
-
- // make sure that we have an output queue
- if (m_pOutputQueue == NULL)
- return NOERROR ;
-
- m_pOutputQueue->BeginFlush () ;
- return NOERROR ;
- }
-
- //----------------------------------------------------------------------------
- // CTeeOutputPin::DeliverEndFlush
- //----------------------------------------------------------------------------
- HRESULT CTeeOutputPin::DeliverEndFlush ()
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::DeliverEndFlush")));
-
- // make sure that we have an output queue
- if (m_pOutputQueue == NULL)
- return NOERROR ;
-
- m_pOutputQueue->EndFlush () ;
- return NOERROR ;
-
- }
- //----------------------------------------------------------------------------
- // CTeeOutputPin::Notify
- //----------------------------------------------------------------------------
-
- STDMETHODIMP CTeeOutputPin::Notify (IFilter *pSender, Quality q)
- {
- DbgLog((LOG_TRACE,2,TEXT("CTeeOutputPin::Notify")));
-
- // We pass the message on, which means that we find the quality sink
- // for our input pin and send it there
-
- POSITION pos = m_pTee->m_OutputPinsList.GetHeadPosition() ;
- CTeeOutputPin *pFirstOutput = m_pTee->m_OutputPinsList.GetNext (pos) ;
-
- if (this == pFirstOutput) {
- DbgLog((LOG_TRACE,2,TEXT("Passing Quality notification through transform")));
- if (m_pTee->m_Input.m_pQSink!=NULL) {
- return m_pTee->m_Input.m_pQSink->Notify(m_pTee, q);
- } else {
-
- // no sink set, so pass it upstream
- HRESULT hr;
- IQualityControl * pIQC;
-
- hr = VFW_E_NOT_FOUND; // default
- if (m_pTee->m_Input.m_Connected) {
- m_pTee->m_Input.m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC);
-
- if (pIQC!=NULL) {
- hr = pIQC->Notify(m_pTee, q);
- pIQC->Release();
- }
- }
- return hr;
- }
- }
-
- // Quality management is too hard to do
- return NOERROR ;
- }
-
- //----------------------------------------------------------------------------
- // exported entry points for registration and
- // unregistration (in this case they only call
- // through to default implmentations).
- //
- //----------------------------------------------------------------------------
- HRESULT
- DllRegisterServer()
- {
- return AMovieDllRegisterServer();
- }
-
- HRESULT
- DllUnregisterServer()
- {
- return AMovieDllUnregisterServer();
- }
-
-
-
-
-
-
-
-