StreamSwitcher.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:33k
- // Copyright 2003 Gabest.
- // http://www.gabest.org
- //
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation; either version 2 of the License, or
- // (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program; if not, write to the Free Software
- // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
- // http://www.gnu.org/copyleft/gpl.html
- #include "StdAfx.h"
- #include "StreamSwitcher.h"
- #include "Shlwapi.h"
- #include <atlpath.h>
- #include <mmreg.h>
- #include <ks.h>
- #include <ksmedia.h>
- #include "AudioSwitcher.h"
- #include "Audio.h"
- #include "......DSUtilDSUtil.h"
- #include <initguid.h>
- #include "........includeOggOggDS.h"
- #define BLOCKSTREAM
- //
- // CStreamSwitcherPassThru
- //
- CStreamSwitcherPassThru::CStreamSwitcherPassThru(LPUNKNOWN pUnk, HRESULT* phr, CStreamSwitcherFilter* pFilter)
- : CMediaPosition(NAME("CStreamSwitcherPassThru"), pUnk)
- , m_pFilter(pFilter)
- {
- }
- STDMETHODIMP CStreamSwitcherPassThru::NonDelegatingQueryInterface(REFIID riid, void** ppv)
- {
- CheckPointer(ppv, E_POINTER);
- *ppv = NULL;
- return
- QI(IMediaSeeking)
- CMediaPosition::NonDelegatingQueryInterface(riid, ppv);
- }
- template<class T>
- HRESULT GetPeer(CStreamSwitcherFilter* pFilter, T** ppT)
- {
- *ppT = NULL;
- CBasePin* pPin = pFilter->GetInputPin();
- if(!pPin) return E_NOTIMPL;
- CComPtr<IPin> pConnected;
- if(FAILED(pPin->ConnectedTo(&pConnected)))
- return E_NOTIMPL;
- if(CComQIPtr<T> pT = pConnected)
- {
- *ppT = pT.Detach();
- return S_OK;
- }
- return E_NOTIMPL;
- }
- #define CallPeerSeeking(call)
- CComPtr<IMediaSeeking> pMS;
- if(FAILED(GetPeer(m_pFilter, &pMS))) return E_NOTIMPL;
- return pMS->##call;
- #define CallPeer(call)
- CComPtr<IMediaPosition> pMP;
- if(FAILED(GetPeer(m_pFilter, &pMP))) return E_NOTIMPL;
- return pMP->##call;
- #define CallPeerSeekingAll(call)
- HRESULT hr = E_NOTIMPL;
- POSITION pos = m_pFilter->m_pInputs.GetHeadPosition();
- while(pos)
- {
- CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos);
- CComPtr<IPin> pConnected;
- if(FAILED(pPin->ConnectedTo(&pConnected)))
- continue;
- if(CComQIPtr<IMediaSeeking> pMS = pConnected)
- {
- HRESULT hr2 = pMS->call;
- if(pPin == m_pFilter->GetInputPin())
- hr = hr2;
- }
- }
- return hr;
- #define CallPeerAll(call)
- HRESULT hr = E_NOTIMPL;
- POSITION pos = m_pFilter->m_pInputs.GetHeadPosition();
- while(pos)
- {
- CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos);
- CComPtr<IPin> pConnected;
- if(FAILED(pPin->ConnectedTo(&pConnected)))
- continue;
- if(CComQIPtr<IMediaPosition> pMP = pConnected)
- {
- HRESULT hr2 = pMP->call;
- if(pPin == m_pFilter->GetInputPin())
- hr = hr2;
- }
- }
- return hr;
- // IMediaSeeking
- STDMETHODIMP CStreamSwitcherPassThru::GetCapabilities(DWORD* pCaps)
- {CallPeerSeeking(GetCapabilities(pCaps));}
- STDMETHODIMP CStreamSwitcherPassThru::CheckCapabilities(DWORD* pCaps)
- {CallPeerSeeking(CheckCapabilities(pCaps));}
- STDMETHODIMP CStreamSwitcherPassThru::IsFormatSupported(const GUID* pFormat)
- {CallPeerSeeking(IsFormatSupported(pFormat));}
- STDMETHODIMP CStreamSwitcherPassThru::QueryPreferredFormat(GUID* pFormat)
- {CallPeerSeeking(QueryPreferredFormat(pFormat));}
- STDMETHODIMP CStreamSwitcherPassThru::SetTimeFormat(const GUID* pFormat)
- {CallPeerSeeking(SetTimeFormat(pFormat));}
- STDMETHODIMP CStreamSwitcherPassThru::GetTimeFormat(GUID* pFormat)
- {CallPeerSeeking(GetTimeFormat(pFormat));}
- STDMETHODIMP CStreamSwitcherPassThru::IsUsingTimeFormat(const GUID* pFormat)
- {CallPeerSeeking(IsUsingTimeFormat(pFormat));}
- STDMETHODIMP CStreamSwitcherPassThru::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat)
- {CallPeerSeeking(ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat));}
- STDMETHODIMP CStreamSwitcherPassThru::SetPositions(LONGLONG* pCurrent, DWORD CurrentFlags, LONGLONG* pStop, DWORD StopFlags)
- {CallPeerSeekingAll(SetPositions(pCurrent, CurrentFlags, pStop, StopFlags));}
- STDMETHODIMP CStreamSwitcherPassThru::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop)
- {CallPeerSeeking(GetPositions(pCurrent, pStop));}
- STDMETHODIMP CStreamSwitcherPassThru::GetCurrentPosition(LONGLONG* pCurrent)
- {CallPeerSeeking(GetCurrentPosition(pCurrent));}
- STDMETHODIMP CStreamSwitcherPassThru::GetStopPosition(LONGLONG* pStop)
- {CallPeerSeeking(GetStopPosition(pStop));}
- STDMETHODIMP CStreamSwitcherPassThru::GetDuration(LONGLONG* pDuration)
- {CallPeerSeeking(GetDuration(pDuration));}
- STDMETHODIMP CStreamSwitcherPassThru::GetPreroll(LONGLONG* pllPreroll)
- {CallPeerSeeking(GetPreroll(pllPreroll));}
- STDMETHODIMP CStreamSwitcherPassThru::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest)
- {CallPeerSeeking(GetAvailable(pEarliest, pLatest));}
- STDMETHODIMP CStreamSwitcherPassThru::GetRate(double* pdRate)
- {CallPeerSeeking(GetRate(pdRate));}
- STDMETHODIMP CStreamSwitcherPassThru::SetRate(double dRate)
- {if(0.0 == dRate) return E_INVALIDARG;
- CallPeerSeekingAll(SetRate(dRate));}
- // IMediaPosition
- STDMETHODIMP CStreamSwitcherPassThru::get_Duration(REFTIME* plength)
- {CallPeer(get_Duration(plength));}
- STDMETHODIMP CStreamSwitcherPassThru::get_CurrentPosition(REFTIME* pllTime)
- {CallPeer(get_CurrentPosition(pllTime));}
- STDMETHODIMP CStreamSwitcherPassThru::put_CurrentPosition(REFTIME llTime)
- {CallPeerAll(put_CurrentPosition(llTime));}
- STDMETHODIMP CStreamSwitcherPassThru::get_StopTime(REFTIME* pllTime)
- {CallPeer(get_StopTime(pllTime));}
- STDMETHODIMP CStreamSwitcherPassThru::put_StopTime(REFTIME llTime)
- {CallPeerAll(put_StopTime(llTime));}
- STDMETHODIMP CStreamSwitcherPassThru::get_PrerollTime(REFTIME * pllTime)
- {CallPeer(get_PrerollTime(pllTime));}
- STDMETHODIMP CStreamSwitcherPassThru::put_PrerollTime(REFTIME llTime)
- {CallPeerAll(put_PrerollTime(llTime));}
- STDMETHODIMP CStreamSwitcherPassThru::get_Rate(double* pdRate)
- {CallPeer(get_Rate(pdRate));}
- STDMETHODIMP CStreamSwitcherPassThru::put_Rate(double dRate)
- {if(0.0 == dRate) return E_INVALIDARG;
- CallPeerAll(put_Rate(dRate));}
- STDMETHODIMP CStreamSwitcherPassThru::CanSeekForward(LONG* pCanSeekForward)
- {CallPeer(CanSeekForward(pCanSeekForward));}
- STDMETHODIMP CStreamSwitcherPassThru::CanSeekBackward(LONG* pCanSeekBackward)
- {CallPeer(CanSeekBackward(pCanSeekBackward));}
- //
- // CStreamSwitcherAllocator
- //
- CStreamSwitcherAllocator::CStreamSwitcherAllocator(CStreamSwitcherInputPin* pPin, HRESULT* phr)
- : CMemAllocator(NAME("CStreamSwitcherAllocator"), NULL, phr)
- , m_pPin(pPin)
- , m_fMediaTypeChanged(false)
- {
- ASSERT(phr);
- ASSERT(pPin);
- }
- #ifdef DEBUG
- CStreamSwitcherAllocator::~CStreamSwitcherAllocator()
- {
- ASSERT(m_bCommitted == FALSE);
- }
- #endif
- STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingAddRef()
- {
- return m_pPin->m_pFilter->AddRef();
- }
- STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingRelease()
- {
- return m_pPin->m_pFilter->Release();
- }
- STDMETHODIMP CStreamSwitcherAllocator::GetBuffer(
- IMediaSample** ppBuffer,
- REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime,
- DWORD dwFlags)
- {
- HRESULT hr = VFW_E_NOT_COMMITTED;
- if(!m_bCommitted)
- return hr;
- /*
- TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() + %xn"), this);
- m_pPin->m_evBlock.Wait();
- TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() - %xn"), this);
- */
- if(m_fMediaTypeChanged)
- {
- if(!m_pPin || !m_pPin->m_pFilter)
- return hr;
- CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pPin->m_pFilter)->GetOutputPin();
- if(!pOut || !pOut->CurrentAllocator())
- return hr;
- ALLOCATOR_PROPERTIES Properties, Actual;
- if(FAILED(pOut->CurrentAllocator()->GetProperties(&Actual)))
- return hr;
- if(FAILED(GetProperties(&Properties)))
- return hr;
- if(!m_bCommitted || Properties.cbBuffer < Actual.cbBuffer)
- {
- Properties.cbBuffer = Actual.cbBuffer;
- if(FAILED(Decommit())) return hr;
- if(FAILED(SetProperties(&Properties, &Actual))) return hr;
- if(FAILED(Commit())) return hr;
- ASSERT(Actual.cbBuffer >= Properties.cbBuffer);
- if(Actual.cbBuffer < Properties.cbBuffer) return hr;
- }
- }
- hr = CMemAllocator::GetBuffer(ppBuffer, pStartTime, pEndTime, dwFlags);
- if(m_fMediaTypeChanged && SUCCEEDED(hr))
- {
- (*ppBuffer)->SetMediaType(&m_mt);
- m_fMediaTypeChanged = false;
- }
- return hr;
- }
- void CStreamSwitcherAllocator::NotifyMediaType(const CMediaType& mt)
- {
- CopyMediaType(&m_mt, &mt);
- m_fMediaTypeChanged = true;
- }
- //
- // CStreamSwitcherInputPin
- //
- CStreamSwitcherInputPin::CStreamSwitcherInputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr, LPCWSTR pName)
- : CBaseInputPin(NAME("CStreamSwitcherInputPin"), pFilter, &pFilter->m_csState, phr, pName)
- , m_Allocator(this, phr)
- , m_bSampleSkipped(FALSE)
- , m_bQualityChanged(FALSE)
- , m_bUsingOwnAllocator(FALSE)
- , m_evBlock(TRUE)
- , m_fCanBlock(false)
- , m_hNotifyEvent(NULL)
- {
- m_bCanReconnectWhenActive = TRUE;
- }
- [uuid("138130AF-A79B-45D5-B4AA-87697457BA87")]
- class NeroAudioDecoder {};
- STDMETHODIMP CStreamSwitcherInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
- {
- return
- QI(IStreamSwitcherInputPin)
- IsConnected() && GetCLSID(GetFilterFromPin(GetConnected())) == __uuidof(NeroAudioDecoder) && QI(IPinConnection)
- __super::NonDelegatingQueryInterface(riid, ppv);
- }
- // IPinConnection
- STDMETHODIMP CStreamSwitcherInputPin::DynamicQueryAccept(const AM_MEDIA_TYPE* pmt)
- {
- return QueryAccept(pmt);
- }
- STDMETHODIMP CStreamSwitcherInputPin::NotifyEndOfStream(HANDLE hNotifyEvent)
- {
- if(m_hNotifyEvent) SetEvent(m_hNotifyEvent);
- m_hNotifyEvent = hNotifyEvent;
- return S_OK;
- }
- STDMETHODIMP CStreamSwitcherInputPin::IsEndPin()
- {
- return S_OK;
- }
- STDMETHODIMP CStreamSwitcherInputPin::DynamicDisconnect()
- {
- CAutoLock cAutoLock(&m_csReceive);
- Disconnect();
- return S_OK;
- }
- // IStreamSwitcherInputPin
- STDMETHODIMP_(bool) CStreamSwitcherInputPin::IsActive()
- {
- // TODO: lock onto something here
- return(this == ((CStreamSwitcherFilter*)m_pFilter)->GetInputPin());
- }
- //
- HRESULT CStreamSwitcherInputPin::QueryAcceptDownstream(const AM_MEDIA_TYPE* pmt)
- {
- HRESULT hr = S_OK;
- CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
- if(pOut && pOut->IsConnected())
- {
- if(CComPtr<IPinConnection> pPC = pOut->CurrentPinConnection())
- {
- hr = pPC->DynamicQueryAccept(pmt);
- if(hr == S_OK) return S_OK;
- }
- hr = pOut->GetConnected()->QueryAccept(pmt);
- }
- return hr;
- }
- void CStreamSwitcherInputPin::Block(bool fBlock)
- {
- if(fBlock) m_evBlock.Reset();
- else m_evBlock.Set();
- }
- HRESULT CStreamSwitcherInputPin::InitializeOutputSample(IMediaSample* pInSample, IMediaSample** ppOutSample)
- {
- if(!pInSample || !ppOutSample)
- return E_POINTER;
- CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
- ASSERT(pOut->GetConnected());
- CComPtr<IMediaSample> pOutSample;
- DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0;
- if(!(m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT))
- dwFlags |= AM_GBF_NOTASYNCPOINT;
- HRESULT hr = pOut->GetDeliveryBuffer(&pOutSample
- , m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID ? &m_SampleProps.tStart : NULL
- , m_SampleProps.dwSampleFlags & AM_SAMPLE_STOPVALID ? &m_SampleProps.tStop : NULL
- , dwFlags);
- if(FAILED(hr))
- return hr;
- if(!pOutSample)
- return E_FAIL;
- if(CComQIPtr<IMediaSample2> pOutSample2 = pOutSample)
- {
- AM_SAMPLE2_PROPERTIES OutProps;
- EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps)));
- OutProps.dwTypeSpecificFlags = m_SampleProps.dwTypeSpecificFlags;
- OutProps.dwSampleFlags =
- (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) |
- (m_SampleProps.dwSampleFlags & ~AM_SAMPLE_TYPECHANGED);
- OutProps.tStart = m_SampleProps.tStart;
- OutProps.tStop = m_SampleProps.tStop;
- OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId);
- hr = pOutSample2->SetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), (PBYTE)&OutProps);
- if(m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY)
- m_bSampleSkipped = FALSE;
- }
- else
- {
- if(m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID)
- pOutSample->SetTime(&m_SampleProps.tStart, &m_SampleProps.tStop);
- if(m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT)
- pOutSample->SetSyncPoint(TRUE);
- if(m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY)
- {
- pOutSample->SetDiscontinuity(TRUE);
- m_bSampleSkipped = FALSE;
- }
- LONGLONG MediaStart, MediaEnd;
- if(pInSample->GetMediaTime(&MediaStart, &MediaEnd) == NOERROR)
- pOutSample->SetMediaTime(&MediaStart, &MediaEnd);
- }
- *ppOutSample = pOutSample.Detach();
- return S_OK;
- }
- // pure virtual
- HRESULT CStreamSwitcherInputPin::CheckMediaType(const CMediaType* pmt)
- {
- return ((CStreamSwitcherFilter*)m_pFilter)->CheckMediaType(pmt);
- }
- // virtual
- HRESULT CStreamSwitcherInputPin::CheckConnect(IPin* pPin)
- {
- return (IPin*)((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin() == pPin
- ? E_FAIL
- : __super::CheckConnect(pPin);
- }
- HRESULT CStreamSwitcherInputPin::CompleteConnect(IPin* pReceivePin)
- {
- HRESULT hr = __super::CompleteConnect(pReceivePin);
- if(FAILED(hr)) return hr;
- ((CStreamSwitcherFilter*)m_pFilter)->CompleteConnect(PINDIR_INPUT, this, pReceivePin);
- m_fCanBlock = false;
- bool fForkedSomewhere = false;
- CStringW fileName;
- CStringW pinName;
- IPin* pPin = (IPin*)this;
- IBaseFilter* pBF = (IBaseFilter*)m_pFilter;
- while((pPin = GetUpStreamPin(pBF, pPin)) && (pBF = GetFilterFromPin(pPin)))
- {
- if(IsSplitter(pBF))
- {
- pinName = GetPinName(pPin);
- }
- CLSID clsid = GetCLSID(pBF);
- if(clsid == CLSID_AviSplitter || clsid == CLSID_OggSplitter)
- m_fCanBlock = true;
- int nIn, nOut, nInC, nOutC;
- CountPins(pBF, nIn, nOut, nInC, nOutC);
- fForkedSomewhere = fForkedSomewhere || nIn > 1 || nOut > 1;
- if(CComQIPtr<IFileSourceFilter> pFSF = pBF)
- {
- WCHAR* pszName = NULL;
- AM_MEDIA_TYPE mt;
- if(SUCCEEDED(pFSF->GetCurFile(&pszName, &mt)) && pszName)
- {
- fileName = pszName;
- CoTaskMemFree(pszName);
- fileName.Replace('\', '/');
- CStringW fn = fileName.Mid(fileName.ReverseFind('/')+1);
- if(!fn.IsEmpty()) fileName = fn;
- if(!pinName.IsEmpty()) fileName += L" / " + pinName;
- WCHAR* pName = new WCHAR[fileName.GetLength()+1];
- if(pName)
- {
- wcscpy(pName, fileName);
- if(m_pName) delete [] m_pName;
- m_pName = pName;
- }
- }
- break;
- }
- pPin = GetFirstPin(pBF);
- }
- if(!fForkedSomewhere)
- m_fCanBlock = true;
- m_hNotifyEvent = NULL;
- return S_OK;
- }
- HRESULT CStreamSwitcherInputPin::Active()
- {
- Block(!IsActive());
- return __super::Active();
- }
- HRESULT CStreamSwitcherInputPin::Inactive()
- {
- Block(false);
- return __super::Inactive();
- }
- // IPin
- STDMETHODIMP CStreamSwitcherInputPin::QueryAccept(const AM_MEDIA_TYPE* pmt)
- {
- HRESULT hr = __super::QueryAccept(pmt);
- if(S_OK != hr) return hr;
- return QueryAcceptDownstream(pmt);
- }
- STDMETHODIMP CStreamSwitcherInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt)
- {
- // FIXME: this locked up once
- // CAutoLock cAutoLock(&((CStreamSwitcherFilter*)m_pFilter)->m_csReceive);
- HRESULT hr;
- if(S_OK != (hr = QueryAcceptDownstream(pmt)))
- return VFW_E_TYPE_NOT_ACCEPTED;
- if(m_Connected)
- m_Connected->Release(), m_Connected = NULL;
- return SUCCEEDED(__super::ReceiveConnection(pConnector, pmt)) ? S_OK : E_FAIL;
- }
- STDMETHODIMP CStreamSwitcherInputPin::GetAllocator(IMemAllocator** ppAllocator)
- {
- CheckPointer(ppAllocator, E_POINTER);
- if(m_pAllocator == NULL)
- {
- (m_pAllocator = &m_Allocator)->AddRef();
- }
- (*ppAllocator = m_pAllocator)->AddRef();
- return NOERROR;
- }
- STDMETHODIMP CStreamSwitcherInputPin::NotifyAllocator(IMemAllocator* pAllocator, BOOL bReadOnly)
- {
- HRESULT hr = __super::NotifyAllocator(pAllocator, bReadOnly);
- if(FAILED(hr)) return hr;
- m_bUsingOwnAllocator = (pAllocator == (IMemAllocator*)&m_Allocator);
- return S_OK;
- }
- STDMETHODIMP CStreamSwitcherInputPin::BeginFlush()
- {
- CAutoLock cAutoLock(&((CStreamSwitcherFilter*)m_pFilter)->m_csState);
- CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
- if(!IsConnected() || !pOut || !pOut->IsConnected())
- return VFW_E_NOT_CONNECTED;
- HRESULT hr = __super::BeginFlush();
- if(FAILED(hr))
- return hr;
- return IsActive() ? pOut->DeliverBeginFlush() : Block(false), S_OK;
- }
- STDMETHODIMP CStreamSwitcherInputPin::EndFlush()
- {
- CAutoLock cAutoLock(&((CStreamSwitcherFilter*)m_pFilter)->m_csState);
- CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
- if(!IsConnected() || !pOut || !pOut->IsConnected())
- return VFW_E_NOT_CONNECTED;
- HRESULT hr = __super::EndFlush();
- if(FAILED(hr))
- return hr;
- return IsActive() ? pOut->DeliverEndFlush() : Block(true), S_OK;
- }
- STDMETHODIMP CStreamSwitcherInputPin::EndOfStream()
- {
- CAutoLock cAutoLock(&m_csReceive);
- CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
- if(!IsConnected() || !pOut || !pOut->IsConnected())
- return VFW_E_NOT_CONNECTED;
- if(m_hNotifyEvent)
- {
- SetEvent(m_hNotifyEvent), m_hNotifyEvent = NULL;
- return S_OK;
- }
- return IsActive() ? pOut->DeliverEndOfStream() : S_OK;
- }
- // IMemInputPin
- STDMETHODIMP CStreamSwitcherInputPin::Receive(IMediaSample* pSample)
- {
- AM_MEDIA_TYPE* pmt = NULL;
- if(SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt)
- {
- const CMediaType mt(*pmt);
- DeleteMediaType(pmt), pmt = NULL;
- SetMediaType(&mt);
- }
- // DAMN!!!!!! this doesn't work if the stream we are blocking
- // shares the same thread with another stream, mpeg splitters
- // are usually like that. Our nicely built up multithreaded
- // strategy is useless because of this, ARRRRRRGHHHHHH.
- #ifdef BLOCKSTREAM
- if(m_fCanBlock)
- m_evBlock.Wait();
- #endif
- if(!IsActive())
- {
- #ifdef BLOCKSTREAM
- if(m_fCanBlock)
- return S_FALSE;
- #endif
- TRACE(_T("&^%$#@n"));
- //Sleep(32);
- return E_FAIL; // a stupid fix for this stupid problem
- }
- CAutoLock cAutoLock(&m_csReceive);
- CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
- ASSERT(pOut->GetConnected());
- HRESULT hr = __super::Receive(pSample);
- if(S_OK != hr) return hr;
- if(m_SampleProps.dwStreamId != AM_STREAM_MEDIA)
- {
- return pOut->Deliver(pSample);
- }
- //
- ALLOCATOR_PROPERTIES props, actual;
- hr = m_pAllocator->GetProperties(&props);
- hr = pOut->CurrentAllocator()->GetProperties(&actual);
- REFERENCE_TIME rtStart = 0, rtStop = 0;
- if(S_OK == pSample->GetTime(&rtStart, &rtStop))
- {
- //
- }
- long cbBuffer = pSample->GetActualDataLength();
- CMediaType mtOut = m_mt;
- mtOut = ((CStreamSwitcherFilter*)m_pFilter)->CreateNewOutputMediaType(mtOut, cbBuffer);
- bool fTypeChanged = false;
- if(mtOut != pOut->CurrentMediaType() || cbBuffer > actual.cbBuffer)
- {
- fTypeChanged = true;
- m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED/*|AM_SAMPLE_DATADISCONTINUITY|AM_SAMPLE_TIMEDISCONTINUITY*/;
- /*
- if(CComQIPtr<IPinConnection> pPC = pOut->CurrentPinConnection())
- {
- HANDLE hEOS = CreateEvent(NULL, FALSE, FALSE, NULL);
- hr = pPC->NotifyEndOfStream(hEOS);
- hr = pOut->DeliverEndOfStream();
- WaitForSingleObject(hEOS, 3000);
- CloseHandle(hEOS);
- hr = pOut->DeliverBeginFlush();
- hr = pOut->DeliverEndFlush();
- }
- */
- if(props.cBuffers < 8 && mtOut.majortype == MEDIATYPE_Audio)
- props.cBuffers = 8;
- props.cbBuffer = cbBuffer;
- if(actual.cbAlign != props.cbAlign
- || actual.cbPrefix != props.cbPrefix
- || actual.cBuffers < props.cBuffers
- || actual.cbBuffer < props.cbBuffer)
- {
- hr = pOut->DeliverBeginFlush();
- hr = pOut->DeliverEndFlush();
- hr = pOut->CurrentAllocator()->Decommit();
- hr = pOut->CurrentAllocator()->SetProperties(&props, &actual);
- hr = pOut->CurrentAllocator()->Commit();
- }
- }
- CComPtr<IMediaSample> pOutSample;
- if(FAILED(InitializeOutputSample(pSample, &pOutSample)))
- return E_FAIL;
- pmt = NULL;
- if(SUCCEEDED(pOutSample->GetMediaType(&pmt)) && pmt)
- {
- const CMediaType mt(*pmt);
- DeleteMediaType(pmt), pmt = NULL;
- // TODO
- ASSERT(0);
- }
- if(fTypeChanged)
- {
- pOut->SetMediaType(&mtOut);
- ((CStreamSwitcherFilter*)m_pFilter)->OnNewOutputMediaType(m_mt, mtOut);
- pOutSample->SetMediaType(&mtOut);
- }
- // Transform
- hr = ((CStreamSwitcherFilter*)m_pFilter)->Transform(pSample, pOutSample);
- //
- if(S_OK == hr)
- {
- hr = pOut->Deliver(pOutSample);
- m_bSampleSkipped = FALSE;
- /*
- if(FAILED(hr))
- {
- ASSERT(0);
- }
- */
- }
- else if(S_FALSE == hr)
- {
- hr = S_OK;
- pOutSample = NULL;
- m_bSampleSkipped = TRUE;
-
- if(!m_bQualityChanged)
- {
- m_pFilter->NotifyEvent(EC_QUALITY_CHANGE, 0, 0);
- m_bQualityChanged = TRUE;
- }
- }
- return hr;
- }
- STDMETHODIMP CStreamSwitcherInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
- {
- if(!IsConnected())
- return S_OK;
- CAutoLock cAutoLock(&m_csReceive);
- CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
- if(!pOut || !pOut->IsConnected())
- return VFW_E_NOT_CONNECTED;
- HRESULT hr = pOut->DeliverNewSegment(tStart, tStop, dRate);
- return hr;
- }
- //
- // CStreamSwitcherOutputPin
- //
- CStreamSwitcherOutputPin::CStreamSwitcherOutputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr)
- : CBaseOutputPin(NAME("CStreamSwitcherOutputPin"), pFilter, &pFilter->m_csState, phr, L"Out")
- {
- // m_bCanReconnectWhenActive = TRUE;
- }
- STDMETHODIMP CStreamSwitcherOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
- {
- CheckPointer(ppv,E_POINTER);
- ValidateReadWritePtr(ppv, sizeof(PVOID));
- *ppv = NULL;
- if(riid == IID_IMediaPosition || riid == IID_IMediaSeeking)
- {
- if(m_pStreamSwitcherPassThru == NULL)
- {
- HRESULT hr = S_OK;
- m_pStreamSwitcherPassThru = (IUnknown*)(INonDelegatingUnknown*)
- new CStreamSwitcherPassThru(GetOwner(), &hr, (CStreamSwitcherFilter*)m_pFilter);
- if(!m_pStreamSwitcherPassThru) return E_OUTOFMEMORY;
- if(FAILED(hr)) return hr;
- }
- return m_pStreamSwitcherPassThru->QueryInterface(riid, ppv);
- }
- /*
- else if(riid == IID_IStreamBuilder)
- {
- return GetInterface((IStreamBuilder*)this, ppv);
- }
- */
- return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
- }
- HRESULT CStreamSwitcherOutputPin::QueryAcceptUpstream(const AM_MEDIA_TYPE* pmt)
- {
- HRESULT hr = S_FALSE;
- CStreamSwitcherInputPin* pIn = ((CStreamSwitcherFilter*)m_pFilter)->GetInputPin();
- if(pIn && pIn->IsConnected() && (pIn->IsUsingOwnAllocator() || pIn->CurrentMediaType() == *pmt))
- {
- if(CComQIPtr<IPin> pPinTo = pIn->GetConnected())
- {
- if(S_OK != (hr = pPinTo->QueryAccept(pmt)))
- return VFW_E_TYPE_NOT_ACCEPTED;
- }
- else
- {
- return E_FAIL;
- }
- }
- return hr;
- }
- // pure virtual
- HRESULT CStreamSwitcherOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
- {
- CStreamSwitcherInputPin* pIn = ((CStreamSwitcherFilter*)m_pFilter)->GetInputPin();
- if(!pIn || !pIn->IsConnected()) return E_UNEXPECTED;
- CComPtr<IMemAllocator> pAllocatorIn;
- pIn->GetAllocator(&pAllocatorIn);
- if(!pAllocatorIn) return E_UNEXPECTED;
- HRESULT hr;
- if(FAILED(hr = pAllocatorIn->GetProperties(pProperties)))
- return hr;
- if(pProperties->cBuffers < 8 && pIn->CurrentMediaType().majortype == MEDIATYPE_Audio)
- pProperties->cBuffers = 8;
- ALLOCATOR_PROPERTIES Actual;
- if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual)))
- return hr;
- return(pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
- ? E_FAIL
- : NOERROR);
- }
- // virtual
- [uuid("AEFA5024-215A-4FC7-97A4-1043C86FD0B8")]
- class MatrixMixer {};
- HRESULT CStreamSwitcherOutputPin::CheckConnect(IPin* pPin)
- {
- CComPtr<IBaseFilter> pBF = GetFilterFromPin(pPin);
- return
- IsAudioWaveRenderer(pBF) || GetCLSID(pBF) == __uuidof(MatrixMixer)
- ? __super::CheckConnect(pPin)
- : E_FAIL;
- // return CComQIPtr<IPinConnection>(pPin) ? CBaseOutputPin::CheckConnect(pPin) : E_NOINTERFACE;
- // return CBaseOutputPin::CheckConnect(pPin);
- }
- HRESULT CStreamSwitcherOutputPin::BreakConnect()
- {
- m_pPinConnection = NULL;
- return __super::BreakConnect();
- }
- HRESULT CStreamSwitcherOutputPin::CompleteConnect(IPin* pReceivePin)
- {
- m_pPinConnection = CComQIPtr<IPinConnection>(pReceivePin);
- return __super::CompleteConnect(pReceivePin);
- }
- HRESULT CStreamSwitcherOutputPin::CheckMediaType(const CMediaType* pmt)
- {
- return ((CStreamSwitcherFilter*)m_pFilter)->CheckMediaType(pmt);
- }
- HRESULT CStreamSwitcherOutputPin::GetMediaType(int iPosition, CMediaType* pmt)
- {
- CStreamSwitcherInputPin* pIn = ((CStreamSwitcherFilter*)m_pFilter)->GetInputPin();
- if(!pIn || !pIn->IsConnected()) return E_UNEXPECTED;
- CComPtr<IEnumMediaTypes> pEM;
- if(FAILED(pIn->GetConnected()->EnumMediaTypes(&pEM)))
- return VFW_S_NO_MORE_ITEMS;
- if(iPosition > 0 && FAILED(pEM->Skip(iPosition)))
- return VFW_S_NO_MORE_ITEMS;
- AM_MEDIA_TYPE* tmp = NULL;
- if(S_OK != pEM->Next(1, &tmp, NULL) || !tmp)
- return VFW_S_NO_MORE_ITEMS;
- CopyMediaType(pmt, tmp);
- DeleteMediaType(tmp);
- /*
- if(iPosition < 0) return E_INVALIDARG;
- if(iPosition > 0) return VFW_S_NO_MORE_ITEMS;
- CopyMediaType(pmt, &pIn->CurrentMediaType());
- */
- return S_OK;
- }
- // IPin
- STDMETHODIMP CStreamSwitcherOutputPin::QueryAccept(const AM_MEDIA_TYPE* pmt)
- {
- HRESULT hr = __super::QueryAccept(pmt);
- if(S_OK != hr) return hr;
- return QueryAcceptUpstream(pmt);
- }
- // IQualityControl
- STDMETHODIMP CStreamSwitcherOutputPin::Notify(IBaseFilter* pSender, Quality q)
- {
- CStreamSwitcherInputPin* pIn = ((CStreamSwitcherFilter*)m_pFilter)->GetInputPin();
- if(!pIn || !pIn->IsConnected()) return VFW_E_NOT_CONNECTED;
- return pIn->PassNotify(q);
- }
- // IStreamBuilder
- STDMETHODIMP CStreamSwitcherOutputPin::Render(IPin* ppinOut, IGraphBuilder* pGraph)
- {
- CComPtr<IBaseFilter> pBF;
- pBF.CoCreateInstance(CLSID_DSoundRender);
- if(!pBF || FAILED(pGraph->AddFilter(pBF, L"Default DirectSound Device")))
- {
- return E_FAIL;
- }
- if(FAILED(pGraph->ConnectDirect(ppinOut, GetFirstDisconnectedPin(pBF, PINDIR_INPUT), NULL)))
- {
- pGraph->RemoveFilter(pBF);
- return E_FAIL;
- }
- return S_OK;
- }
- STDMETHODIMP CStreamSwitcherOutputPin::Backout(IPin* ppinOut, IGraphBuilder* pGraph)
- {
- return S_OK;
- }
- //
- // CStreamSwitcherFilter
- //
- CStreamSwitcherFilter::CStreamSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid)
- : CBaseFilter(NAME("CStreamSwitcherFilter"), lpunk, &m_csState, clsid)
- {
- if(phr) *phr = S_OK;
- HRESULT hr = S_OK;
- do
- {
- CAutoPtr<CStreamSwitcherInputPin> pInput;
- CAutoPtr<CStreamSwitcherOutputPin> pOutput;
- hr = S_OK;
- pInput.Attach(new CStreamSwitcherInputPin(this, &hr, L"Channel 1"));
- if(!pInput || FAILED(hr)) break;
- hr = S_OK;
- pOutput.Attach(new CStreamSwitcherOutputPin(this, &hr));
- if(!pOutput || FAILED(hr)) break;
- CAutoLock cAutoLock(&m_csPins);
-
- m_pInputs.AddHead(m_pInput = pInput.Detach());
- m_pOutput = pOutput.Detach();
- return;
- }
- while(false);
- if(phr) *phr = E_FAIL;
- }
- CStreamSwitcherFilter::~CStreamSwitcherFilter()
- {
- CAutoLock cAutoLock(&m_csPins);
- POSITION pos = m_pInputs.GetHeadPosition();
- while(pos) delete m_pInputs.GetNext(pos);
- m_pInputs.RemoveAll();
- m_pInput = NULL;
- delete m_pOutput;
- m_pOutput = NULL;
- }
- STDMETHODIMP CStreamSwitcherFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
- {
- return
- QI(IAMStreamSelect)
- __super::NonDelegatingQueryInterface(riid, ppv);
- }
- //
- int CStreamSwitcherFilter::GetPinCount()
- {
- CAutoLock cAutoLock(&m_csPins);
- return(1 + (int)m_pInputs.GetCount());
- }
- CBasePin* CStreamSwitcherFilter::GetPin(int n)
- {
- CAutoLock cAutoLock(&m_csPins);
- if(n < 0 || n >= GetPinCount()) return NULL;
- else if(n == 0) return m_pOutput;
- else return m_pInputs.GetAt(m_pInputs.FindIndex(n-1));
- }
- int CStreamSwitcherFilter::GetConnectedInputPinCount()
- {
- CAutoLock cAutoLock(&m_csPins);
- int nConnected = 0;
- POSITION pos = m_pInputs.GetHeadPosition();
- while(pos)
- {
- if(m_pInputs.GetNext(pos)->IsConnected())
- nConnected++;
- }
- return(nConnected);
- }
- CStreamSwitcherInputPin* CStreamSwitcherFilter::GetConnectedInputPin(int n)
- {
- if(n >= 0)
- {
- POSITION pos = m_pInputs.GetHeadPosition();
- while(pos)
- {
- CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos);
- if(pPin->IsConnected())
- {
- if(n == 0) return(pPin);
- n--;
- }
- }
- }
- return NULL;
- }
- CStreamSwitcherInputPin* CStreamSwitcherFilter::GetInputPin()
- {
- return m_pInput;
- }
- CStreamSwitcherOutputPin* CStreamSwitcherFilter::GetOutputPin()
- {
- return m_pOutput;
- }
- //
- HRESULT CStreamSwitcherFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin, IPin* pReceivePin)
- {
- if(dir == PINDIR_INPUT)
- {
- CAutoLock cAutoLock(&m_csPins);
- int nConnected = GetConnectedInputPinCount();
- if(nConnected == 1)
- {
- m_pInput = (CStreamSwitcherInputPin*)pPin;
- }
- if(nConnected == m_pInputs.GetCount())
- {
- CStringW name;
- name.Format(L"Channel %d", ++m_PinVersion);
- HRESULT hr = S_OK;
- CStreamSwitcherInputPin* pPin = new CStreamSwitcherInputPin(this, &hr, name);
- if(!pPin || FAILED(hr)) return E_FAIL;
- m_pInputs.AddTail(pPin);
- }
- }
- return S_OK;
- }
- // this should be very thread safe, I hope it is, it must be... :)
- void CStreamSwitcherFilter::SelectInput(CStreamSwitcherInputPin* pInput)
- {
- // make sure no input thinks it is active
- m_pInput = NULL;
- // release blocked GetBuffer in our own allocator & block all Receive
- POSITION pos = m_pInputs.GetHeadPosition();
- while(pos)
- {
- CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos);
- pPin->Block(false);
- // a few Receive calls can arrive here, but since m_pInput == NULL neighter of them gets delivered
- pPin->Block(true);
- }
- // this will let waiting GetBuffer() calls go on inside our Receive()
- if(m_pOutput)
- {
- m_pOutput->DeliverBeginFlush();
- m_pOutput->DeliverEndFlush();
- }
- if(!pInput) return;
- // set new input
- m_pInput = pInput;
- // let it go
- m_pInput->Block(false);
- }
- //
- HRESULT CStreamSwitcherFilter::Transform(IMediaSample* pIn, IMediaSample* pOut)
- {
- BYTE* pDataIn = NULL;
- BYTE* pDataOut = NULL;
- HRESULT hr;
- if(FAILED(hr = pIn->GetPointer(&pDataIn))) return hr;
- if(FAILED(hr = pOut->GetPointer(&pDataOut))) return hr;
- long len = pIn->GetActualDataLength();
- long size = pOut->GetSize();
- if(!pDataIn || !pDataOut /*|| len > size || len <= 0*/) return S_FALSE; // FIXME
- memcpy(pDataOut, pDataIn, min(len, size));
- pOut->SetActualDataLength(min(len, size));
- return S_OK;
- }
- CMediaType CStreamSwitcherFilter::CreateNewOutputMediaType(CMediaType mt, long& cbBuffer)
- {
- return(mt);
- }
- // IAMStreamSelect
- STDMETHODIMP CStreamSwitcherFilter::Count(DWORD* pcStreams)
- {
- if(!pcStreams) return E_POINTER;
- CAutoLock cAutoLock(&m_csPins);
- *pcStreams = GetConnectedInputPinCount();
- return S_OK;
- }
- STDMETHODIMP CStreamSwitcherFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk)
- {
- CAutoLock cAutoLock(&m_csPins);
- CBasePin* pPin = GetConnectedInputPin(lIndex);
- if(!pPin) return E_INVALIDARG;
- if(ppmt)
- *ppmt = CreateMediaType(&m_pOutput->CurrentMediaType());
- if(pdwFlags)
- *pdwFlags = (m_pInput == pPin) ? AMSTREAMSELECTINFO_EXCLUSIVE : 0;
- if(plcid)
- *plcid = 0;
- if(pdwGroup)
- *pdwGroup = 0;
- if(ppszName && (*ppszName = (WCHAR*)CoTaskMemAlloc((wcslen(pPin->Name())+1)*sizeof(WCHAR))))
- wcscpy(*ppszName, pPin->Name());
- if(ppObject)
- *ppObject = NULL;
- if(ppUnk)
- *ppUnk = NULL;
- return S_OK;
- }
- STDMETHODIMP CStreamSwitcherFilter::Enable(long lIndex, DWORD dwFlags)
- {
- if(dwFlags != AMSTREAMSELECTENABLE_ENABLE)
- return E_NOTIMPL;
- PauseGraph;
- CStreamSwitcherInputPin* pNewInput = GetConnectedInputPin(lIndex);
- if(!pNewInput) return E_INVALIDARG;
- SelectInput(pNewInput);
- ResumeGraph;
- return S_OK;
- }
- //////////