splitter.cpp
上传用户:sunbaby
上传日期:2013-05-31
资源大小:242k
文件大小:16k
源码类别:

mpeg/mp3

开发平台:

Visual C++

  1. //==========================================================================; // //  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) 1996 - 1997  Microsoft Corporation.  All Rights Reserved. // //--------------------------------------------------------------------------; #include "stdafx.h" #include <streams.h> #include "pullpin.h" #include "alloc.h" #include "splitter.h" /*  Ignore warnings about this pointers being used in member initialization     lists */ #pragma warning(disable:4355) /*  Splitter output pin methds */ /*  -- Constructor -- */ CSplitterOutputPin::CSplitterOutputPin(         CBaseSplitterFilter *pFilter,         HRESULT *phr,         LPCWSTR pName) :     CBaseOutputPin(         NAME("CSplitterOutputPin"),         pFilter,         &pFilter->m_csFilter,         phr,         pName),     m_Notify(this),     m_bDiscontinuity(FALSE),     m_pOutputQueue(NULL),     m_lTypes(NAME("CSplitterFilter::m_lTypes")) { } CSplitterOutputPin::~CSplitterOutputPin() {     while (m_lTypes.GetCount() != 0) {         delete m_lTypes.RemoveHead();     } } /* Override revert to normal ref counting    These pins cannot be finally Release()'d while the input pin is    connected */ STDMETHODIMP_(ULONG) CSplitterOutputPin::NonDelegatingAddRef() {     return CUnknown::NonDelegatingAddRef(); } /* Override to do normal ref counting */ STDMETHODIMP_(ULONG) CSplitterOutputPin::NonDelegatingRelease() {     return CUnknown::NonDelegatingRelease(); } STDMETHODIMP CSplitterOutputPin::Notify(IBaseFilter* pSender, Quality q) {
  2.     return S_OK;
  3. } // override this to set the buffer size and count. Return an error // if the size/count is not to your liking. HRESULT CSplitterOutputPin::DecideBufferSize(     IMemAllocator * pAlloc,     ALLOCATOR_PROPERTIES * pProp ) {     pProp->cBuffers = 100;     pProp->cbBuffer = 65536;            /* Don't care about size */     pProp->cbAlign = 1;     pProp->cbPrefix = 0;     ALLOCATOR_PROPERTIES propActual;     return pAlloc->SetProperties(pProp, &propActual); } // //  Override DecideAllocator because we insist on our own allocator since //  it's 0 cost in terms of bytes // HRESULT CSplitterOutputPin::DecideAllocator(     IMemInputPin *pPin,     IMemAllocator **ppAlloc ) {     HRESULT hr = InitAllocator(ppAlloc);     if (SUCCEEDED(hr)) {         ALLOCATOR_PROPERTIES propRequest;         ZeroMemory(&propRequest, sizeof(propRequest));         hr = DecideBufferSize(*ppAlloc, &propRequest);         if (SUCCEEDED(hr)) {             // tell downstream pins that modification             // in-place is not permitted             hr = pPin->NotifyAllocator(*ppAlloc, TRUE);             if (SUCCEEDED(hr)) {                 return NOERROR;             }         }     }     /* Likewise we may not have an interface to release */     if (*ppAlloc) {         (*ppAlloc)->Release();         *ppAlloc = NULL;     }     return hr; } // override this to control the connection // We use the subsample allocator derived from the input pin's allocator HRESULT CSplitterOutputPin::InitAllocator(IMemAllocator **ppAlloc) {     ASSERT(m_pAllocator == NULL);     HRESULT hr = NOERROR;     *ppAlloc = new CSubAllocator(NULL, &hr, Filter()->Allocator());     if (*ppAlloc == NULL) {         return E_OUTOFMEMORY;     }     if (FAILED(hr)) {         delete *ppAlloc;         *ppAlloc = NULL;         return hr;     }     /* Get a reference counted IID_IMemAllocator interface */     (*ppAlloc)->AddRef();     return NOERROR; } //  Check if we accept a media type - only accept 1 for now HRESULT CSplitterOutputPin::CheckMediaType(const CMediaType *pmt) {     POSITION pos = m_lTypes.GetHeadPosition();     while (pos) {         CMediaType *pmtList = m_lTypes.GetNext(pos);         if (*pmtList == *pmt) {             return S_OK;         }     }     return S_FALSE; } // returns the preferred formats for a pin HRESULT CSplitterOutputPin::GetMediaType(     int iPosition,     CMediaType *pMediaType ) {     POSITION pos = m_lTypes.GetHeadPosition();     while (pos) {         CMediaType *pmtList = m_lTypes.GetNext(pos);         if (iPosition-- == 0) {             *pMediaType = *pmtList;             return S_OK;         }     }     return VFW_S_NO_MORE_ITEMS; } /*  Add a media type that's supported */ HRESULT CSplitterOutputPin::AddMediaType(     CMediaType const *pmt ) {     CMediaType *pmtNew = new CMediaType(*pmt);     if (pmtNew) {         if (m_lTypes.AddTail(pmtNew)) {             return S_OK;         }     }     delete pmtNew;     return E_OUTOFMEMORY; } /*  Output pin - Deliver a sample */ HRESULT CSplitterOutputPin::SendSample(     const BYTE * pbData,     LONG lData,     REFERENCE_TIME rtStart,     BOOL bSync ) {     /*  Get a sample from the allocator */     if (!IsConnected()) {         return S_FALSE;     }     CMediaSample *pSample = Allocator()->GetSample((PBYTE)pbData, lData);     ASSERT(pSample != NULL);     if (bSync) {         REFERENCE_TIME rtStop = rtStart + 1;         pSample->SetTime(&rtStart, &rtStop);         /*  Allow for some decoders that only take not of sync points */         pSample->SetSyncPoint(TRUE);     }     /*  First send newsegment etc if discontinuity */     if (m_bDiscontinuity) {         m_bDiscontinuity = FALSE;         pSample->SetDiscontinuity(TRUE);         /*  HACK - fix this for seeking */         m_pOutputQueue->NewSegment(0, 0x7F00000000000000, 1.0);     }     /*  Output queue will release the sample */     return m_pOutputQueue->Receive(pSample); } /*  Base splitter class methods */ /* -- Constructor -- */ CBaseSplitterFilter::CBaseSplitterFilter(     TCHAR *pName,     LPUNKNOWN pUnk,     REFCLSID rclsid,     HRESULT *phr) :     CBaseFilter(pName, pUnk, &m_csFilter, rclsid, phr),     m_OutputPins(NAME("CBaseSplitterFilter::m_OutputPins")),     m_Notify(this),     m_pInput(NULL),     m_pParser(NULL) { } /* -- Destructor -- */ CBaseSplitterFilter::~CBaseSplitterFilter() {     ASSERT(m_State == State_Stopped);     /* -- Destroy all pins */     DestroyInputPin();     DestroyOutputPins(); } // //  Override Pause() so we can prevent the input pin from starting //  the puller before we're ready (ie have exited stopped state) // //  Starting the puller in Active() caused a hole where the first //  samples could be rejected becase we seemed to be in 'stopped' //  state // STDMETHODIMP CBaseSplitterFilter::Pause() {     CAutoLock lockFilter(&m_csFilter);     if (m_State == State_Stopped) {         // and do the normal inactive processing         POSITION pos = m_OutputPins.GetHeadPosition();         while (pos) {             CSplitterOutputPin *pPin = m_OutputPins.GetNext(pos);             if (pPin->IsConnected()) {                 pPin->Active();             }         }         CAutoLock lockStreaming(&m_csStream);         //  Activate our input pin only if we're connected         if (m_pInput->IsConnected()) {             m_pInput->Active();         }         m_State = State_Paused;         //  Initialize our state         ResetAllocatorAndParser();     } else {         m_State = State_Paused;     }     return S_OK; } /*  Stop the filter     We override this for efficiency and so that we can manage the     locking correctly */ STDMETHODIMP CBaseSplitterFilter::Stop() {     // must get this one first - it serializes state changes     CAutoLock lockFilter(&m_csFilter);     if (m_State == State_Stopped) {         return NOERROR;     }     // decommit the input pin or we can deadlock     if (m_pInput != NULL) {         m_pInput->Inactive();     }     // now hold the Receive critsec to prevent further Receive and EOS calls,     CAutoLock lockStreaming(&m_csStream);     // and do the normal inactive processing     POSITION pos = m_OutputPins.GetHeadPosition();     while (pos) {         CSplitterOutputPin *pPin = m_OutputPins.GetNext(pos);         if (pPin->IsConnected()) {             pPin->Inactive();         }     }     ResetAllocatorAndParser();     m_State = State_Stopped;     return S_OK; } /*  -- Return number of pins */ int CBaseSplitterFilter::GetPinCount() {     CAutoLock lck(&m_csPins);     return (m_pInput != NULL ? 1 : 0) +            m_OutputPins.GetCount(); } /*  -- Return a given pin -- */ CBasePin *CBaseSplitterFilter::GetPin(int iPin) {     CAutoLock lck(&m_csPins);     if (iPin == 0 && m_pInput != NULL) {         return m_pInput;     }     if (m_pInput != NULL) {         iPin--;     }     if (iPin < 0 || iPin >= m_OutputPins.GetCount()) {         return NULL;     }     POSITION pos = m_OutputPins.GetHeadPosition();     while (iPin-- > 0) {         m_OutputPins.GetNext(pos);     }     return m_OutputPins.GetNext(pos); } /*  -- Add an output pin -- */ BOOL CBaseSplitterFilter::AddOutputPin(CSplitterOutputPin *pOutputPin) {     CAutoLock lckFilter(&m_csFilter);     CAutoLock lckPins(&m_csPins);     ASSERT(m_State == State_Stopped);     IncrementPinVersion();     pOutputPin->AddRef();     if (m_OutputPins.AddTail(pOutputPin) == NULL) {         delete pOutputPin;         return FALSE;     }     return TRUE; } /*  -- Destroy the input pin -- */ void CBaseSplitterFilter::DestroyInputPin() {     delete m_pInput;     m_pInput = NULL; } /*  -- Delete the output pins -- */ void CBaseSplitterFilter::DestroyOutputPins() {     CAutoLock lckFilter(&m_csFilter);     CAutoLock lckPins(&m_csPins);     ASSERT(m_State == State_Stopped);     for (;;) {         CSplitterOutputPin *pPin = m_OutputPins.RemoveHead();         if (pPin == NULL) {             break;         }         IncrementPinVersion();         //  Disconnect if necessary         IPin *pPeer = pPin->GetConnected();         if (pPeer != NULL) {             pPeer->Disconnect();             pPin->Disconnect();         }         pPin->Release();     } } /*  Notify to create a new stream     Called back through CParseNotify */ HRESULT CBaseSplitterFilter::CreateStream(     LPCWSTR         pszName,     CStreamNotify **ppStreamNotify ) {     HRESULT hr = S_OK;     CSplitterOutputPin *pPin =         new CSplitterOutputPin(this, &hr, pszName);     if (FAILED(hr)) {         delete pPin;         return hr;     }     if (pPin == NULL) {         return E_OUTOFMEMORY;     }     if (!AddOutputPin(pPin)) {         delete pPin;         return E_OUTOFMEMORY;     }     *ppStreamNotify = pPin->GetNotify();     return S_OK; } HRESULT CBaseSplitterFilter::CompleteConnect(IPin *pReceivePin) {     m_pParser = CreateParser(&m_Notify, InputPin()->MediaType());     if (m_pParser == NULL) {         return E_OUTOFMEMORY;     }     /*  Create a reader to initialize the parser */     CParseReaderFromAsync rdr(InputPin()->Reader());     HRESULT hr = m_pParser->Init(&rdr);     if (SUCCEEDED(hr)) {         ALLOCATOR_PROPERTIES Props, Actual;         /*  Our allocator doesn't accumulate alignment correctly             so use the alignment currently set         */         Allocator()->GetProperties(&Props);         m_pParser->GetSizeAndCount(&Props.cbBuffer, &Props.cBuffers);         ((IMemAllocator *)Allocator())->SetProperties(&Props, &Actual);     }     return hr; } /*  Process some data */ HRESULT CBaseSplitterFilter::Receive(IMediaSample *pSample) {     /*  Notify our allocator about how much data we've got,         Call the parser to eat the data,         eat the data that was parsed     */     Allocator()->AddBuffer((CMediaSample *)pSample);     /*  Now eat the data */     LONG lValid;     PBYTE pbValid = Allocator()->GetValid(&lValid);     LONG lProcessed;     HRESULT hr = m_pParser->Process(pbValid, lValid, &lProcessed);     if (S_OK != hr) {         /*  If something goes wrong do error processing */         return hr;     }     Allocator()->Advance(lProcessed);     /*  Flush the output queues */     POSITION pos = m_OutputPins.GetHeadPosition();     while (pos) {         CSplitterOutputPin *pPin = m_OutputPins.GetNext(pos);         pPin->SendAnyway();     }     return S_OK; } /*  Send EndOfStream */ void CBaseSplitterFilter::EndOfStream() {     ResetAllocatorAndParser();     POSITION pos = m_OutputPins.GetHeadPosition();     while (pos) {         CSplitterOutputPin *pPin = m_OutputPins.GetNext(pos);         if (pPin->IsConnected()) {             pPin->DeliverEndOfStream();         }     } } /*  Send BeginFlush() */ HRESULT CBaseSplitterFilter::BeginFlush() {     POSITION pos = m_OutputPins.GetHeadPosition();     while (pos) {         CSplitterOutputPin *pPin = m_OutputPins.GetNext(pos);         if (pPin->IsConnected()) {             pPin->DeliverBeginFlush();         }     }     return S_OK; } /*  Send EndFlush() */ HRESULT CBaseSplitterFilter::EndFlush() {     ResetAllocatorAndParser();     POSITION pos = m_OutputPins.GetHeadPosition();     while (pos) {         CSplitterOutputPin *pPin = m_OutputPins.GetNext(pos);         if (pPin->IsConnected()) {             pPin->DeliverEndFlush();         }     }     return S_OK; } /*  Break connection on the input pin */ void CBaseSplitterFilter::BreakConnect() {     delete m_pParser;     m_pParser = NULL;     DestroyOutputPins(); } /*  -- Input pin methods -- */ /*  Constructor */ CSplitterInputPin::CSplitterInputPin(     CBaseSplitterFilter *pFilter,     HRESULT *phr ) : CBaseInputPin(NAME("CSplitterInputPin"),              pFilter,              &pFilter->m_csFilter,              phr,              L"Input"),     m_puller(this) { } /*  Connection stuff */ HRESULT CSplitterInputPin::CheckConnect(IPin *pPin) {     HRESULT hr = CBaseInputPin::CheckConnect(pPin);     if (FAILED(hr)) {         return hr;     }     /*  Create our allocator */     ASSERT(m_pAllocator == NULL);     m_pAllocator = new CSequentialAllocator(                            NULL, // No owner - allocators are separate objects                            &hr);     if (m_pAllocator == NULL) {         return E_OUTOFMEMORY;     }     if (FAILED(hr)) {         return hr;     }     /*  The base classes expect the allocator to be AddRef'd */     m_pAllocator->AddRef();     // BUGBUG CPullPin might change the allocator and not tell us!     hr = m_puller.Connect(pPin, m_pAllocator, TRUE);     if (FAILED(hr)) {         return hr;     }     return hr; } /*  Break connection - filter already locked by caller */ HRESULT CSplitterInputPin::BreakConnect() {     Filter()->BreakConnect();     m_puller.Disconnect();     if (m_pAllocator) {         m_pAllocator->Release();         m_pAllocator = NULL;     }     return CBaseInputPin::BreakConnect(); } /*  End of stream */ STDMETHODIMP CSplitterInputPin::EndOfStream() {     CAutoLock lck(&Filter()->m_csStream);     HRESULT hr = CheckStreaming();     if (FAILED(hr)) {         return hr;     }     /*  Forward to the output pins */     Filter()->EndOfStream();     return S_OK; } /*  Forward BeginFlush() and EndFlush() to filter */ STDMETHODIMP CSplitterInputPin::BeginFlush() {     CAutoLock lck(m_pLock);     CBaseInputPin::BeginFlush();     Filter()->BeginFlush();     return S_OK; } STDMETHODIMP CSplitterInputPin::EndFlush() {     CAutoLock lck(&Filter()->m_csStream);     CBaseInputPin::EndFlush();     Filter()->EndFlush();     return S_OK; } /*  Receive - forward to filter */ STDMETHODIMP CSplitterInputPin::Receive(IMediaSample *pSample) {     CAutoLock lck(&Filter()->m_csStream);     HRESULT hr = CheckStreaming();     if (FAILED(hr)) {         return hr;     }     hr = Filter()->Receive(pSample);     if (S_OK != hr) {         NotifyError(hr);     }     return hr; } HRESULT CSplitterInputPin::Active() {     /*  If we're not seekable then just seek to start for now */     REFERENCE_TIME rtDuration;     m_puller.Duration(&rtDuration);     m_puller.Seek(0, rtDuration);     HRESULT hr = m_puller.Active();     if (FAILED(hr)) {         return hr;     }     return CBaseInputPin::Active(); } HRESULT CSplitterInputPin::Inactive() {     m_puller.Inactive();     return CBaseInputPin::Inactive(); } /*  forward connection stuff to filter */ HRESULT CSplitterInputPin::CheckMediaType(const CMediaType *pmt) {     return Filter()->CheckInputType(pmt); } HRESULT CSplitterInputPin::CompleteConnect(IPin *pReceivePin) {     return Filter()->CompleteConnect(pReceivePin); }