splitter.cpp
资源名称:h264src.zip [点击查看]
上传用户:sunbaby
上传日期:2013-05-31
资源大小:242k
文件大小:16k
源码类别:
mpeg/mp3
开发平台:
Visual C++
- //==========================================================================; // // 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) {
- return S_OK;
- } // 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); }