StreamSwitcher.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:33k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. // Copyright 2003 Gabest.
  2. // http://www.gabest.org
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; either version 2 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program; if not, write to the Free Software
  16. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
  17. // http://www.gnu.org/copyleft/gpl.html
  18. #include "StdAfx.h"
  19. #include "StreamSwitcher.h"
  20. #include "Shlwapi.h"
  21. #include <atlpath.h>
  22. #include <mmreg.h>
  23. #include <ks.h>
  24. #include <ksmedia.h>
  25. #include "AudioSwitcher.h"
  26. #include "Audio.h"
  27. #include "......DSUtilDSUtil.h"
  28. #include <initguid.h>
  29. #include "........includeOggOggDS.h"
  30. #define BLOCKSTREAM
  31. //
  32. // CStreamSwitcherPassThru
  33. //
  34. CStreamSwitcherPassThru::CStreamSwitcherPassThru(LPUNKNOWN pUnk, HRESULT* phr, CStreamSwitcherFilter* pFilter)
  35. : CMediaPosition(NAME("CStreamSwitcherPassThru"), pUnk)
  36. , m_pFilter(pFilter)
  37. {
  38. }
  39. STDMETHODIMP CStreamSwitcherPassThru::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  40. {
  41.     CheckPointer(ppv, E_POINTER);
  42.     *ppv = NULL;
  43.     return 
  44. QI(IMediaSeeking)
  45. CMediaPosition::NonDelegatingQueryInterface(riid, ppv);
  46. }
  47. template<class T>
  48. HRESULT GetPeer(CStreamSwitcherFilter* pFilter, T** ppT)
  49. {
  50.     *ppT = NULL;
  51. CBasePin* pPin = pFilter->GetInputPin();
  52. if(!pPin) return E_NOTIMPL;
  53.     CComPtr<IPin> pConnected;
  54.     if(FAILED(pPin->ConnectedTo(&pConnected))) 
  55. return E_NOTIMPL;
  56. if(CComQIPtr<T> pT = pConnected)
  57. {
  58. *ppT = pT.Detach();
  59. return S_OK;
  60. }
  61. return E_NOTIMPL;
  62. }
  63. #define CallPeerSeeking(call) 
  64. CComPtr<IMediaSeeking> pMS; 
  65. if(FAILED(GetPeer(m_pFilter, &pMS))) return E_NOTIMPL; 
  66. return pMS->##call; 
  67. #define CallPeer(call) 
  68. CComPtr<IMediaPosition> pMP; 
  69. if(FAILED(GetPeer(m_pFilter, &pMP))) return E_NOTIMPL; 
  70. return pMP->##call; 
  71. #define CallPeerSeekingAll(call) 
  72. HRESULT hr = E_NOTIMPL; 
  73. POSITION pos = m_pFilter->m_pInputs.GetHeadPosition(); 
  74. while(pos) 
  75. CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos); 
  76. CComPtr<IPin> pConnected; 
  77.     if(FAILED(pPin->ConnectedTo(&pConnected))) 
  78. continue; 
  79. if(CComQIPtr<IMediaSeeking> pMS = pConnected) 
  80. HRESULT hr2 = pMS->call; 
  81. if(pPin == m_pFilter->GetInputPin()) 
  82. hr = hr2; 
  83. return hr; 
  84. #define CallPeerAll(call) 
  85. HRESULT hr = E_NOTIMPL; 
  86. POSITION pos = m_pFilter->m_pInputs.GetHeadPosition(); 
  87. while(pos) 
  88. CBasePin* pPin = m_pFilter->m_pInputs.GetNext(pos); 
  89. CComPtr<IPin> pConnected; 
  90.     if(FAILED(pPin->ConnectedTo(&pConnected))) 
  91. continue; 
  92. if(CComQIPtr<IMediaPosition> pMP = pConnected) 
  93. HRESULT hr2 = pMP->call; 
  94. if(pPin == m_pFilter->GetInputPin()) 
  95. hr = hr2; 
  96. return hr; 
  97. // IMediaSeeking
  98. STDMETHODIMP CStreamSwitcherPassThru::GetCapabilities(DWORD* pCaps)
  99. {CallPeerSeeking(GetCapabilities(pCaps));}
  100. STDMETHODIMP CStreamSwitcherPassThru::CheckCapabilities(DWORD* pCaps)
  101. {CallPeerSeeking(CheckCapabilities(pCaps));}
  102. STDMETHODIMP CStreamSwitcherPassThru::IsFormatSupported(const GUID* pFormat)
  103. {CallPeerSeeking(IsFormatSupported(pFormat));}
  104. STDMETHODIMP CStreamSwitcherPassThru::QueryPreferredFormat(GUID* pFormat)
  105. {CallPeerSeeking(QueryPreferredFormat(pFormat));}
  106. STDMETHODIMP CStreamSwitcherPassThru::SetTimeFormat(const GUID* pFormat)
  107. {CallPeerSeeking(SetTimeFormat(pFormat));}
  108. STDMETHODIMP CStreamSwitcherPassThru::GetTimeFormat(GUID* pFormat)
  109. {CallPeerSeeking(GetTimeFormat(pFormat));}
  110. STDMETHODIMP CStreamSwitcherPassThru::IsUsingTimeFormat(const GUID* pFormat)
  111. {CallPeerSeeking(IsUsingTimeFormat(pFormat));}
  112. STDMETHODIMP CStreamSwitcherPassThru::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat)
  113. {CallPeerSeeking(ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat));}
  114. STDMETHODIMP CStreamSwitcherPassThru::SetPositions(LONGLONG* pCurrent, DWORD CurrentFlags, LONGLONG* pStop, DWORD StopFlags)
  115. {CallPeerSeekingAll(SetPositions(pCurrent, CurrentFlags, pStop, StopFlags));}
  116. STDMETHODIMP CStreamSwitcherPassThru::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop)
  117. {CallPeerSeeking(GetPositions(pCurrent, pStop));}
  118. STDMETHODIMP CStreamSwitcherPassThru::GetCurrentPosition(LONGLONG* pCurrent)
  119. {CallPeerSeeking(GetCurrentPosition(pCurrent));}
  120. STDMETHODIMP CStreamSwitcherPassThru::GetStopPosition(LONGLONG* pStop)
  121. {CallPeerSeeking(GetStopPosition(pStop));}
  122. STDMETHODIMP CStreamSwitcherPassThru::GetDuration(LONGLONG* pDuration)
  123. {CallPeerSeeking(GetDuration(pDuration));}
  124. STDMETHODIMP CStreamSwitcherPassThru::GetPreroll(LONGLONG* pllPreroll)
  125. {CallPeerSeeking(GetPreroll(pllPreroll));}
  126. STDMETHODIMP CStreamSwitcherPassThru::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest)
  127. {CallPeerSeeking(GetAvailable(pEarliest, pLatest));}
  128. STDMETHODIMP CStreamSwitcherPassThru::GetRate(double* pdRate)
  129. {CallPeerSeeking(GetRate(pdRate));}
  130. STDMETHODIMP CStreamSwitcherPassThru::SetRate(double dRate)
  131. {if(0.0 == dRate) return E_INVALIDARG;
  132. CallPeerSeekingAll(SetRate(dRate));}
  133. // IMediaPosition
  134. STDMETHODIMP CStreamSwitcherPassThru::get_Duration(REFTIME* plength)
  135. {CallPeer(get_Duration(plength));}
  136. STDMETHODIMP CStreamSwitcherPassThru::get_CurrentPosition(REFTIME* pllTime)
  137. {CallPeer(get_CurrentPosition(pllTime));}
  138. STDMETHODIMP CStreamSwitcherPassThru::put_CurrentPosition(REFTIME llTime)
  139. {CallPeerAll(put_CurrentPosition(llTime));}
  140. STDMETHODIMP CStreamSwitcherPassThru::get_StopTime(REFTIME* pllTime)
  141. {CallPeer(get_StopTime(pllTime));}
  142. STDMETHODIMP CStreamSwitcherPassThru::put_StopTime(REFTIME llTime)
  143. {CallPeerAll(put_StopTime(llTime));}
  144. STDMETHODIMP CStreamSwitcherPassThru::get_PrerollTime(REFTIME * pllTime)
  145. {CallPeer(get_PrerollTime(pllTime));}
  146. STDMETHODIMP CStreamSwitcherPassThru::put_PrerollTime(REFTIME llTime)
  147. {CallPeerAll(put_PrerollTime(llTime));}
  148. STDMETHODIMP CStreamSwitcherPassThru::get_Rate(double* pdRate)
  149. {CallPeer(get_Rate(pdRate));}
  150. STDMETHODIMP CStreamSwitcherPassThru::put_Rate(double dRate)
  151. {if(0.0 == dRate) return E_INVALIDARG;
  152. CallPeerAll(put_Rate(dRate));}
  153. STDMETHODIMP CStreamSwitcherPassThru::CanSeekForward(LONG* pCanSeekForward)
  154. {CallPeer(CanSeekForward(pCanSeekForward));}
  155. STDMETHODIMP CStreamSwitcherPassThru::CanSeekBackward(LONG* pCanSeekBackward) 
  156. {CallPeer(CanSeekBackward(pCanSeekBackward));}
  157. //
  158. // CStreamSwitcherAllocator
  159. //
  160. CStreamSwitcherAllocator::CStreamSwitcherAllocator(CStreamSwitcherInputPin* pPin, HRESULT* phr)
  161. : CMemAllocator(NAME("CStreamSwitcherAllocator"), NULL, phr)
  162. , m_pPin(pPin)
  163. , m_fMediaTypeChanged(false)
  164. {
  165. ASSERT(phr);
  166. ASSERT(pPin);
  167. }
  168. #ifdef DEBUG
  169. CStreamSwitcherAllocator::~CStreamSwitcherAllocator()
  170. {
  171.     ASSERT(m_bCommitted == FALSE);
  172. }
  173. #endif
  174. STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingAddRef()
  175. {
  176. return m_pPin->m_pFilter->AddRef();
  177. }
  178. STDMETHODIMP_(ULONG) CStreamSwitcherAllocator::NonDelegatingRelease()
  179. {
  180. return m_pPin->m_pFilter->Release();
  181. }
  182. STDMETHODIMP CStreamSwitcherAllocator::GetBuffer(
  183. IMediaSample** ppBuffer, 
  184. REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, 
  185. DWORD dwFlags)
  186. {
  187. HRESULT hr = VFW_E_NOT_COMMITTED;
  188. if(!m_bCommitted)
  189.         return hr;
  190. /*
  191. TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() + %xn"), this);
  192. m_pPin->m_evBlock.Wait();
  193. TRACE(_T("CStreamSwitcherAllocator::GetBuffer m_pPin->m_evBlock.Wait() - %xn"), this);
  194. */
  195. if(m_fMediaTypeChanged)
  196. {
  197. if(!m_pPin || !m_pPin->m_pFilter)
  198. return hr;
  199. CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pPin->m_pFilter)->GetOutputPin();
  200. if(!pOut || !pOut->CurrentAllocator())
  201. return hr;
  202. ALLOCATOR_PROPERTIES Properties, Actual;
  203. if(FAILED(pOut->CurrentAllocator()->GetProperties(&Actual))) 
  204. return hr;
  205. if(FAILED(GetProperties(&Properties))) 
  206. return hr;
  207. if(!m_bCommitted || Properties.cbBuffer < Actual.cbBuffer)
  208. {
  209. Properties.cbBuffer = Actual.cbBuffer;
  210. if(FAILED(Decommit())) return hr;
  211. if(FAILED(SetProperties(&Properties, &Actual))) return hr;
  212. if(FAILED(Commit())) return hr;
  213. ASSERT(Actual.cbBuffer >= Properties.cbBuffer);
  214. if(Actual.cbBuffer < Properties.cbBuffer) return hr;
  215. }
  216. }
  217. hr = CMemAllocator::GetBuffer(ppBuffer, pStartTime, pEndTime, dwFlags);
  218. if(m_fMediaTypeChanged && SUCCEEDED(hr))
  219. {
  220. (*ppBuffer)->SetMediaType(&m_mt);
  221. m_fMediaTypeChanged = false;
  222. }
  223. return hr;
  224. }
  225. void CStreamSwitcherAllocator::NotifyMediaType(const CMediaType& mt)
  226. {
  227. CopyMediaType(&m_mt, &mt);
  228. m_fMediaTypeChanged = true;
  229. }
  230. //
  231. // CStreamSwitcherInputPin
  232. //
  233. CStreamSwitcherInputPin::CStreamSwitcherInputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr, LPCWSTR pName)
  234.     : CBaseInputPin(NAME("CStreamSwitcherInputPin"), pFilter, &pFilter->m_csState, phr, pName)
  235. , m_Allocator(this, phr)
  236. , m_bSampleSkipped(FALSE)
  237. , m_bQualityChanged(FALSE)
  238. , m_bUsingOwnAllocator(FALSE)
  239. , m_evBlock(TRUE)
  240. , m_fCanBlock(false)
  241. , m_hNotifyEvent(NULL)
  242. {
  243. m_bCanReconnectWhenActive = TRUE;
  244. }
  245. [uuid("138130AF-A79B-45D5-B4AA-87697457BA87")]
  246. class NeroAudioDecoder {};
  247. STDMETHODIMP CStreamSwitcherInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  248. {
  249. return
  250. QI(IStreamSwitcherInputPin)
  251. IsConnected() && GetCLSID(GetFilterFromPin(GetConnected())) == __uuidof(NeroAudioDecoder) && QI(IPinConnection)
  252. __super::NonDelegatingQueryInterface(riid, ppv);
  253. }
  254. // IPinConnection
  255. STDMETHODIMP CStreamSwitcherInputPin::DynamicQueryAccept(const AM_MEDIA_TYPE* pmt)
  256. {
  257. return QueryAccept(pmt);
  258. }
  259. STDMETHODIMP CStreamSwitcherInputPin::NotifyEndOfStream(HANDLE hNotifyEvent)
  260. {
  261. if(m_hNotifyEvent) SetEvent(m_hNotifyEvent);
  262. m_hNotifyEvent = hNotifyEvent;
  263. return S_OK;
  264. }
  265. STDMETHODIMP CStreamSwitcherInputPin::IsEndPin()
  266. {
  267. return S_OK;
  268. }
  269. STDMETHODIMP CStreamSwitcherInputPin::DynamicDisconnect()
  270. {
  271. CAutoLock cAutoLock(&m_csReceive);
  272. Disconnect();
  273. return S_OK;
  274. }
  275. // IStreamSwitcherInputPin
  276. STDMETHODIMP_(bool) CStreamSwitcherInputPin::IsActive()
  277. {
  278. // TODO: lock onto something here
  279. return(this == ((CStreamSwitcherFilter*)m_pFilter)->GetInputPin());
  280. }
  281. // 
  282. HRESULT CStreamSwitcherInputPin::QueryAcceptDownstream(const AM_MEDIA_TYPE* pmt)
  283. {
  284. HRESULT hr = S_OK;
  285. CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
  286. if(pOut && pOut->IsConnected())
  287. {
  288. if(CComPtr<IPinConnection> pPC = pOut->CurrentPinConnection())
  289. {
  290. hr = pPC->DynamicQueryAccept(pmt);
  291. if(hr == S_OK) return S_OK;
  292. }
  293. hr = pOut->GetConnected()->QueryAccept(pmt);
  294. }
  295. return hr;
  296. }
  297. void CStreamSwitcherInputPin::Block(bool fBlock)
  298. {
  299. if(fBlock) m_evBlock.Reset();
  300. else m_evBlock.Set();
  301. }
  302. HRESULT CStreamSwitcherInputPin::InitializeOutputSample(IMediaSample* pInSample, IMediaSample** ppOutSample)
  303. {
  304. if(!pInSample || !ppOutSample) 
  305. return E_POINTER;
  306. CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
  307. ASSERT(pOut->GetConnected());
  308.     CComPtr<IMediaSample> pOutSample;
  309. DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0;
  310.     if(!(m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT))
  311. dwFlags |= AM_GBF_NOTASYNCPOINT;
  312. HRESULT hr = pOut->GetDeliveryBuffer(&pOutSample
  313.         , m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID ? &m_SampleProps.tStart : NULL
  314.         , m_SampleProps.dwSampleFlags & AM_SAMPLE_STOPVALID ? &m_SampleProps.tStop : NULL
  315.         , dwFlags);
  316.     if(FAILED(hr))
  317. return hr;
  318. if(!pOutSample) 
  319. return E_FAIL;
  320.     if(CComQIPtr<IMediaSample2> pOutSample2 = pOutSample)
  321. {
  322.         AM_SAMPLE2_PROPERTIES OutProps;
  323. EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps)));
  324.         OutProps.dwTypeSpecificFlags = m_SampleProps.dwTypeSpecificFlags;
  325.         OutProps.dwSampleFlags =
  326.             (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) |
  327.             (m_SampleProps.dwSampleFlags & ~AM_SAMPLE_TYPECHANGED);
  328.         OutProps.tStart = m_SampleProps.tStart;
  329.         OutProps.tStop  = m_SampleProps.tStop;
  330.         OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId);
  331.         hr = pOutSample2->SetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), (PBYTE)&OutProps);
  332.         if(m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY)
  333. m_bSampleSkipped = FALSE;
  334.     }
  335.     else
  336. {
  337.         if(m_SampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID)
  338. pOutSample->SetTime(&m_SampleProps.tStart, &m_SampleProps.tStop);
  339. if(m_SampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT)
  340. pOutSample->SetSyncPoint(TRUE);
  341. if(m_SampleProps.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY)
  342. {
  343. pOutSample->SetDiscontinuity(TRUE);
  344.             m_bSampleSkipped = FALSE;
  345.         }
  346. LONGLONG MediaStart, MediaEnd;
  347.         if(pInSample->GetMediaTime(&MediaStart, &MediaEnd) == NOERROR)
  348. pOutSample->SetMediaTime(&MediaStart, &MediaEnd);
  349.     }
  350. *ppOutSample = pOutSample.Detach();
  351. return S_OK;
  352. }
  353. // pure virtual
  354. HRESULT CStreamSwitcherInputPin::CheckMediaType(const CMediaType* pmt)
  355. {
  356. return ((CStreamSwitcherFilter*)m_pFilter)->CheckMediaType(pmt);
  357. }
  358. // virtual 
  359. HRESULT CStreamSwitcherInputPin::CheckConnect(IPin* pPin)
  360. {
  361. return (IPin*)((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin() == pPin 
  362. ? E_FAIL
  363. : __super::CheckConnect(pPin);
  364. }
  365. HRESULT CStreamSwitcherInputPin::CompleteConnect(IPin* pReceivePin)
  366. {
  367. HRESULT hr = __super::CompleteConnect(pReceivePin);
  368. if(FAILED(hr)) return hr;
  369.     ((CStreamSwitcherFilter*)m_pFilter)->CompleteConnect(PINDIR_INPUT, this, pReceivePin);
  370. m_fCanBlock = false;
  371. bool fForkedSomewhere = false;
  372. CStringW fileName;
  373. CStringW pinName;
  374.     IPin* pPin = (IPin*)this;
  375. IBaseFilter* pBF = (IBaseFilter*)m_pFilter;
  376. while((pPin = GetUpStreamPin(pBF, pPin)) && (pBF = GetFilterFromPin(pPin)))
  377. {
  378. if(IsSplitter(pBF))
  379. {
  380. pinName = GetPinName(pPin);
  381. }
  382. CLSID clsid = GetCLSID(pBF);
  383. if(clsid == CLSID_AviSplitter || clsid == CLSID_OggSplitter)
  384. m_fCanBlock = true;
  385. int nIn, nOut, nInC, nOutC;
  386. CountPins(pBF, nIn, nOut, nInC, nOutC);
  387. fForkedSomewhere = fForkedSomewhere || nIn > 1 || nOut > 1;
  388. if(CComQIPtr<IFileSourceFilter> pFSF = pBF)
  389. {
  390. WCHAR* pszName = NULL;
  391. AM_MEDIA_TYPE mt;
  392. if(SUCCEEDED(pFSF->GetCurFile(&pszName, &mt)) && pszName)
  393. {
  394. fileName = pszName;
  395. CoTaskMemFree(pszName);
  396. fileName.Replace('\', '/');
  397. CStringW fn = fileName.Mid(fileName.ReverseFind('/')+1);
  398. if(!fn.IsEmpty()) fileName = fn;
  399. if(!pinName.IsEmpty()) fileName += L" / " + pinName;
  400. WCHAR* pName = new WCHAR[fileName.GetLength()+1];
  401. if(pName)
  402. {
  403. wcscpy(pName, fileName);
  404. if(m_pName) delete [] m_pName;
  405. m_pName = pName;
  406. }
  407. }
  408. break;
  409. }
  410. pPin = GetFirstPin(pBF);
  411. }
  412. if(!fForkedSomewhere)
  413. m_fCanBlock = true;
  414. m_hNotifyEvent = NULL;
  415. return S_OK;
  416. }
  417. HRESULT CStreamSwitcherInputPin::Active()
  418. {
  419. Block(!IsActive());
  420. return __super::Active();
  421. }
  422. HRESULT CStreamSwitcherInputPin::Inactive()
  423. {
  424. Block(false);
  425. return __super::Inactive();
  426. }
  427. // IPin
  428. STDMETHODIMP CStreamSwitcherInputPin::QueryAccept(const AM_MEDIA_TYPE* pmt)
  429. {
  430. HRESULT hr = __super::QueryAccept(pmt);
  431. if(S_OK != hr) return hr;
  432. return QueryAcceptDownstream(pmt);
  433. }
  434. STDMETHODIMP CStreamSwitcherInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt)
  435. {
  436. // FIXME: this locked up once
  437. //    CAutoLock cAutoLock(&((CStreamSwitcherFilter*)m_pFilter)->m_csReceive);
  438. HRESULT hr;
  439. if(S_OK != (hr = QueryAcceptDownstream(pmt)))
  440. return VFW_E_TYPE_NOT_ACCEPTED;
  441. if(m_Connected) 
  442. m_Connected->Release(), m_Connected = NULL;
  443. return SUCCEEDED(__super::ReceiveConnection(pConnector, pmt)) ? S_OK : E_FAIL;
  444. }
  445. STDMETHODIMP CStreamSwitcherInputPin::GetAllocator(IMemAllocator** ppAllocator)
  446. {
  447.     CheckPointer(ppAllocator, E_POINTER);
  448.     if(m_pAllocator == NULL)
  449. {
  450.         (m_pAllocator = &m_Allocator)->AddRef();
  451.     }
  452.     (*ppAllocator = m_pAllocator)->AddRef();
  453.     return NOERROR;
  454. }
  455. STDMETHODIMP CStreamSwitcherInputPin::NotifyAllocator(IMemAllocator* pAllocator, BOOL bReadOnly)
  456. {
  457. HRESULT hr = __super::NotifyAllocator(pAllocator, bReadOnly);
  458. if(FAILED(hr)) return hr;
  459. m_bUsingOwnAllocator = (pAllocator == (IMemAllocator*)&m_Allocator);
  460. return S_OK;
  461. }
  462. STDMETHODIMP CStreamSwitcherInputPin::BeginFlush()
  463. {
  464.     CAutoLock cAutoLock(&((CStreamSwitcherFilter*)m_pFilter)->m_csState);
  465. CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
  466.     if(!IsConnected() || !pOut || !pOut->IsConnected())
  467. return VFW_E_NOT_CONNECTED;
  468. HRESULT hr = __super::BeginFlush();
  469.     if(FAILED(hr)) 
  470. return hr;
  471. return IsActive() ? pOut->DeliverBeginFlush() : Block(false), S_OK;
  472. }
  473. STDMETHODIMP CStreamSwitcherInputPin::EndFlush()
  474. {
  475. CAutoLock cAutoLock(&((CStreamSwitcherFilter*)m_pFilter)->m_csState);
  476. CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
  477.     if(!IsConnected() || !pOut || !pOut->IsConnected())
  478. return VFW_E_NOT_CONNECTED;
  479. HRESULT hr = __super::EndFlush();
  480.     if(FAILED(hr)) 
  481. return hr;
  482. return IsActive() ? pOut->DeliverEndFlush() : Block(true), S_OK;
  483. }
  484. STDMETHODIMP CStreamSwitcherInputPin::EndOfStream()
  485. {
  486.     CAutoLock cAutoLock(&m_csReceive);
  487. CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
  488. if(!IsConnected() || !pOut || !pOut->IsConnected())
  489. return VFW_E_NOT_CONNECTED;
  490. if(m_hNotifyEvent)
  491. {
  492. SetEvent(m_hNotifyEvent), m_hNotifyEvent = NULL;
  493. return S_OK;
  494. }
  495. return IsActive() ? pOut->DeliverEndOfStream() : S_OK;
  496. }
  497. // IMemInputPin
  498. STDMETHODIMP CStreamSwitcherInputPin::Receive(IMediaSample* pSample)
  499. {
  500. AM_MEDIA_TYPE* pmt = NULL;
  501. if(SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt)
  502. {
  503. const CMediaType mt(*pmt);
  504. DeleteMediaType(pmt), pmt = NULL;
  505. SetMediaType(&mt);
  506. }
  507. // DAMN!!!!!! this doesn't work if the stream we are blocking 
  508. // shares the same thread with another stream, mpeg splitters 
  509. // are usually like that. Our nicely built up multithreaded 
  510. // strategy is useless because of this, ARRRRRRGHHHHHH.
  511. #ifdef BLOCKSTREAM
  512. if(m_fCanBlock)
  513. m_evBlock.Wait();
  514. #endif
  515. if(!IsActive())
  516. {
  517. #ifdef BLOCKSTREAM
  518. if(m_fCanBlock)
  519. return S_FALSE;
  520. #endif
  521. TRACE(_T("&^%$#@n"));
  522. //Sleep(32);
  523. return E_FAIL; // a stupid fix for this stupid problem
  524. }
  525.     CAutoLock cAutoLock(&m_csReceive);
  526. CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
  527. ASSERT(pOut->GetConnected());
  528. HRESULT hr = __super::Receive(pSample);
  529. if(S_OK != hr) return hr;
  530. if(m_SampleProps.dwStreamId != AM_STREAM_MEDIA)
  531. {
  532. return pOut->Deliver(pSample);
  533. }
  534. //
  535. ALLOCATOR_PROPERTIES props, actual;
  536. hr = m_pAllocator->GetProperties(&props);
  537. hr = pOut->CurrentAllocator()->GetProperties(&actual);
  538. REFERENCE_TIME rtStart = 0, rtStop = 0;
  539. if(S_OK == pSample->GetTime(&rtStart, &rtStop))
  540. {
  541. //
  542. }
  543. long cbBuffer = pSample->GetActualDataLength();
  544. CMediaType mtOut = m_mt;
  545. mtOut = ((CStreamSwitcherFilter*)m_pFilter)->CreateNewOutputMediaType(mtOut, cbBuffer);
  546. bool fTypeChanged = false;
  547. if(mtOut != pOut->CurrentMediaType() || cbBuffer > actual.cbBuffer)
  548. {
  549. fTypeChanged = true;
  550. m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED/*|AM_SAMPLE_DATADISCONTINUITY|AM_SAMPLE_TIMEDISCONTINUITY*/;
  551. /*
  552. if(CComQIPtr<IPinConnection> pPC = pOut->CurrentPinConnection())
  553. {
  554. HANDLE hEOS = CreateEvent(NULL, FALSE, FALSE, NULL);
  555. hr = pPC->NotifyEndOfStream(hEOS);
  556. hr = pOut->DeliverEndOfStream();
  557. WaitForSingleObject(hEOS, 3000);
  558. CloseHandle(hEOS);
  559. hr = pOut->DeliverBeginFlush();
  560. hr = pOut->DeliverEndFlush();
  561. }
  562. */
  563. if(props.cBuffers < 8 && mtOut.majortype == MEDIATYPE_Audio)
  564. props.cBuffers = 8;
  565. props.cbBuffer = cbBuffer;
  566. if(actual.cbAlign != props.cbAlign
  567. || actual.cbPrefix != props.cbPrefix
  568. || actual.cBuffers < props.cBuffers
  569. || actual.cbBuffer < props.cbBuffer)
  570. {
  571. hr = pOut->DeliverBeginFlush();
  572. hr = pOut->DeliverEndFlush();
  573. hr = pOut->CurrentAllocator()->Decommit();
  574. hr = pOut->CurrentAllocator()->SetProperties(&props, &actual);
  575. hr = pOut->CurrentAllocator()->Commit();
  576. }
  577. }
  578. CComPtr<IMediaSample> pOutSample;
  579. if(FAILED(InitializeOutputSample(pSample, &pOutSample)))
  580. return E_FAIL;
  581. pmt = NULL;
  582. if(SUCCEEDED(pOutSample->GetMediaType(&pmt)) && pmt)
  583. {
  584. const CMediaType mt(*pmt);
  585. DeleteMediaType(pmt), pmt = NULL;
  586. // TODO
  587. ASSERT(0);
  588. }
  589. if(fTypeChanged)
  590. {
  591. pOut->SetMediaType(&mtOut);
  592. ((CStreamSwitcherFilter*)m_pFilter)->OnNewOutputMediaType(m_mt, mtOut);
  593. pOutSample->SetMediaType(&mtOut);
  594. }
  595. // Transform
  596. hr = ((CStreamSwitcherFilter*)m_pFilter)->Transform(pSample, pOutSample);
  597. //
  598.     if(S_OK == hr)
  599. {
  600. hr = pOut->Deliver(pOutSample);
  601.         m_bSampleSkipped = FALSE;
  602. /*
  603. if(FAILED(hr))
  604. {
  605. ASSERT(0);
  606. }
  607. */
  608. }
  609.     else if(S_FALSE == hr)
  610. {
  611. hr = S_OK;
  612. pOutSample = NULL;
  613. m_bSampleSkipped = TRUE;
  614. if(!m_bQualityChanged)
  615. {
  616. m_pFilter->NotifyEvent(EC_QUALITY_CHANGE, 0, 0);
  617. m_bQualityChanged = TRUE;
  618. }
  619. }
  620. return hr;
  621. }
  622. STDMETHODIMP CStreamSwitcherInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
  623. {
  624. if(!IsConnected())
  625. return S_OK;
  626. CAutoLock cAutoLock(&m_csReceive);
  627. CStreamSwitcherOutputPin* pOut = ((CStreamSwitcherFilter*)m_pFilter)->GetOutputPin();
  628.     if(!pOut || !pOut->IsConnected())
  629. return VFW_E_NOT_CONNECTED;
  630. HRESULT hr = pOut->DeliverNewSegment(tStart, tStop, dRate);
  631. return hr;
  632. }
  633. //
  634. // CStreamSwitcherOutputPin
  635. //
  636. CStreamSwitcherOutputPin::CStreamSwitcherOutputPin(CStreamSwitcherFilter* pFilter, HRESULT* phr)
  637. : CBaseOutputPin(NAME("CStreamSwitcherOutputPin"), pFilter, &pFilter->m_csState, phr, L"Out")
  638. {
  639. // m_bCanReconnectWhenActive = TRUE;
  640. }
  641. STDMETHODIMP CStreamSwitcherOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  642. {
  643.     CheckPointer(ppv,E_POINTER);
  644.     ValidateReadWritePtr(ppv, sizeof(PVOID));
  645.     *ppv = NULL;
  646.     if(riid == IID_IMediaPosition || riid == IID_IMediaSeeking)
  647. {
  648.         if(m_pStreamSwitcherPassThru == NULL)
  649. {
  650. HRESULT hr = S_OK;
  651. m_pStreamSwitcherPassThru = (IUnknown*)(INonDelegatingUnknown*)
  652. new CStreamSwitcherPassThru(GetOwner(), &hr, (CStreamSwitcherFilter*)m_pFilter);
  653. if(!m_pStreamSwitcherPassThru) return E_OUTOFMEMORY;
  654.             if(FAILED(hr)) return hr;
  655.         }
  656.         return m_pStreamSwitcherPassThru->QueryInterface(riid, ppv);
  657.     }
  658. /*
  659. else if(riid == IID_IStreamBuilder)
  660. {
  661. return GetInterface((IStreamBuilder*)this, ppv);
  662. }
  663. */
  664. return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
  665. }
  666. HRESULT CStreamSwitcherOutputPin::QueryAcceptUpstream(const AM_MEDIA_TYPE* pmt)
  667. {
  668. HRESULT hr = S_FALSE;
  669. CStreamSwitcherInputPin* pIn = ((CStreamSwitcherFilter*)m_pFilter)->GetInputPin();
  670. if(pIn && pIn->IsConnected() && (pIn->IsUsingOwnAllocator() || pIn->CurrentMediaType() == *pmt))
  671. {
  672. if(CComQIPtr<IPin> pPinTo = pIn->GetConnected())
  673. {
  674. if(S_OK != (hr = pPinTo->QueryAccept(pmt)))
  675. return VFW_E_TYPE_NOT_ACCEPTED;
  676. }
  677. else
  678. {
  679. return E_FAIL;
  680. }
  681. }
  682. return hr;
  683. }
  684. // pure virtual
  685. HRESULT CStreamSwitcherOutputPin::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
  686. {
  687. CStreamSwitcherInputPin* pIn = ((CStreamSwitcherFilter*)m_pFilter)->GetInputPin();
  688. if(!pIn || !pIn->IsConnected()) return E_UNEXPECTED;
  689. CComPtr<IMemAllocator> pAllocatorIn;
  690. pIn->GetAllocator(&pAllocatorIn);
  691. if(!pAllocatorIn) return E_UNEXPECTED;
  692. HRESULT hr;
  693.     if(FAILED(hr = pAllocatorIn->GetProperties(pProperties))) 
  694. return hr;
  695. if(pProperties->cBuffers < 8 && pIn->CurrentMediaType().majortype == MEDIATYPE_Audio)
  696. pProperties->cBuffers = 8;
  697. ALLOCATOR_PROPERTIES Actual;
  698.     if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) 
  699. return hr;
  700. return(pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
  701. ? E_FAIL
  702. : NOERROR);
  703. }
  704. // virtual
  705. [uuid("AEFA5024-215A-4FC7-97A4-1043C86FD0B8")]
  706. class MatrixMixer {};
  707. HRESULT CStreamSwitcherOutputPin::CheckConnect(IPin* pPin)
  708. {
  709. CComPtr<IBaseFilter> pBF = GetFilterFromPin(pPin);
  710. return 
  711. IsAudioWaveRenderer(pBF) || GetCLSID(pBF) == __uuidof(MatrixMixer)
  712. ? __super::CheckConnect(pPin) 
  713. : E_FAIL;
  714. // return CComQIPtr<IPinConnection>(pPin) ? CBaseOutputPin::CheckConnect(pPin) : E_NOINTERFACE;
  715. // return CBaseOutputPin::CheckConnect(pPin);
  716. }
  717. HRESULT CStreamSwitcherOutputPin::BreakConnect()
  718. {
  719. m_pPinConnection = NULL;
  720. return __super::BreakConnect();
  721. }
  722. HRESULT CStreamSwitcherOutputPin::CompleteConnect(IPin* pReceivePin)
  723. {
  724. m_pPinConnection = CComQIPtr<IPinConnection>(pReceivePin);
  725. return __super::CompleteConnect(pReceivePin);
  726. }
  727. HRESULT CStreamSwitcherOutputPin::CheckMediaType(const CMediaType* pmt)
  728. {
  729. return ((CStreamSwitcherFilter*)m_pFilter)->CheckMediaType(pmt);
  730. }
  731. HRESULT CStreamSwitcherOutputPin::GetMediaType(int iPosition, CMediaType* pmt)
  732. {
  733. CStreamSwitcherInputPin* pIn = ((CStreamSwitcherFilter*)m_pFilter)->GetInputPin();
  734. if(!pIn || !pIn->IsConnected()) return E_UNEXPECTED;
  735. CComPtr<IEnumMediaTypes> pEM;
  736. if(FAILED(pIn->GetConnected()->EnumMediaTypes(&pEM)))
  737. return VFW_S_NO_MORE_ITEMS;
  738. if(iPosition > 0 && FAILED(pEM->Skip(iPosition)))
  739. return VFW_S_NO_MORE_ITEMS;
  740. AM_MEDIA_TYPE* tmp = NULL;
  741. if(S_OK != pEM->Next(1, &tmp, NULL) || !tmp)
  742. return VFW_S_NO_MORE_ITEMS;
  743. CopyMediaType(pmt, tmp);
  744. DeleteMediaType(tmp);
  745. /*
  746. if(iPosition < 0) return E_INVALIDARG;
  747.     if(iPosition > 0) return VFW_S_NO_MORE_ITEMS;
  748. CopyMediaType(pmt, &pIn->CurrentMediaType());
  749. */
  750. return S_OK;
  751. }
  752. // IPin
  753. STDMETHODIMP CStreamSwitcherOutputPin::QueryAccept(const AM_MEDIA_TYPE* pmt)
  754. {
  755. HRESULT hr = __super::QueryAccept(pmt);
  756. if(S_OK != hr) return hr;
  757. return QueryAcceptUpstream(pmt);
  758. }
  759. // IQualityControl
  760. STDMETHODIMP CStreamSwitcherOutputPin::Notify(IBaseFilter* pSender, Quality q)
  761. {
  762. CStreamSwitcherInputPin* pIn = ((CStreamSwitcherFilter*)m_pFilter)->GetInputPin();
  763. if(!pIn || !pIn->IsConnected()) return VFW_E_NOT_CONNECTED;
  764.     return pIn->PassNotify(q);
  765. }
  766. // IStreamBuilder
  767. STDMETHODIMP CStreamSwitcherOutputPin::Render(IPin* ppinOut, IGraphBuilder* pGraph)
  768. {
  769. CComPtr<IBaseFilter> pBF;
  770. pBF.CoCreateInstance(CLSID_DSoundRender);
  771. if(!pBF || FAILED(pGraph->AddFilter(pBF, L"Default DirectSound Device")))
  772. {
  773. return E_FAIL;
  774. }
  775. if(FAILED(pGraph->ConnectDirect(ppinOut, GetFirstDisconnectedPin(pBF, PINDIR_INPUT), NULL)))
  776. {
  777. pGraph->RemoveFilter(pBF);
  778. return E_FAIL;
  779. }
  780. return S_OK;
  781. }
  782. STDMETHODIMP CStreamSwitcherOutputPin::Backout(IPin* ppinOut, IGraphBuilder* pGraph)
  783. {
  784. return S_OK;
  785. }
  786. //
  787. // CStreamSwitcherFilter
  788. //
  789. CStreamSwitcherFilter::CStreamSwitcherFilter(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) 
  790. : CBaseFilter(NAME("CStreamSwitcherFilter"), lpunk, &m_csState, clsid)
  791. {
  792. if(phr) *phr = S_OK;
  793. HRESULT hr = S_OK;
  794. do
  795. {
  796. CAutoPtr<CStreamSwitcherInputPin> pInput;
  797. CAutoPtr<CStreamSwitcherOutputPin> pOutput;
  798. hr = S_OK;
  799.         pInput.Attach(new CStreamSwitcherInputPin(this, &hr, L"Channel 1"));
  800. if(!pInput || FAILED(hr)) break;
  801. hr = S_OK;
  802. pOutput.Attach(new CStreamSwitcherOutputPin(this, &hr));
  803.         if(!pOutput || FAILED(hr)) break;
  804. CAutoLock cAutoLock(&m_csPins);
  805.         
  806. m_pInputs.AddHead(m_pInput = pInput.Detach());
  807. m_pOutput = pOutput.Detach();
  808. return;
  809. }
  810. while(false);
  811. if(phr) *phr = E_FAIL;
  812. }
  813. CStreamSwitcherFilter::~CStreamSwitcherFilter()
  814. {
  815. CAutoLock cAutoLock(&m_csPins);
  816. POSITION pos = m_pInputs.GetHeadPosition();
  817. while(pos) delete m_pInputs.GetNext(pos);
  818. m_pInputs.RemoveAll();
  819. m_pInput = NULL;
  820. delete m_pOutput;
  821. m_pOutput = NULL;
  822. }
  823. STDMETHODIMP CStreamSwitcherFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  824. {
  825. return
  826. QI(IAMStreamSelect)
  827. __super::NonDelegatingQueryInterface(riid, ppv);
  828. }
  829. //
  830. int CStreamSwitcherFilter::GetPinCount()
  831. {
  832. CAutoLock cAutoLock(&m_csPins);
  833. return(1 + (int)m_pInputs.GetCount());
  834. }
  835. CBasePin* CStreamSwitcherFilter::GetPin(int n)
  836. {
  837. CAutoLock cAutoLock(&m_csPins);
  838. if(n < 0 || n >= GetPinCount()) return NULL;
  839. else if(n == 0) return m_pOutput;
  840. else return m_pInputs.GetAt(m_pInputs.FindIndex(n-1));
  841. }
  842. int CStreamSwitcherFilter::GetConnectedInputPinCount()
  843. {
  844. CAutoLock cAutoLock(&m_csPins);
  845. int nConnected = 0;
  846. POSITION pos = m_pInputs.GetHeadPosition();
  847. while(pos)
  848. {
  849. if(m_pInputs.GetNext(pos)->IsConnected()) 
  850. nConnected++;
  851. }
  852. return(nConnected);
  853. }
  854. CStreamSwitcherInputPin* CStreamSwitcherFilter::GetConnectedInputPin(int n)
  855. {
  856. if(n >= 0)
  857. {
  858. POSITION pos = m_pInputs.GetHeadPosition();
  859. while(pos)
  860. {
  861. CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos);
  862. if(pPin->IsConnected())
  863. {
  864. if(n == 0) return(pPin);
  865. n--;
  866. }
  867. }
  868. }
  869. return NULL;
  870. }
  871. CStreamSwitcherInputPin* CStreamSwitcherFilter::GetInputPin()
  872. {
  873. return m_pInput;
  874. }
  875. CStreamSwitcherOutputPin* CStreamSwitcherFilter::GetOutputPin()
  876. {
  877. return m_pOutput;
  878. }
  879. //
  880. HRESULT CStreamSwitcherFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin, IPin* pReceivePin)
  881. {
  882. if(dir == PINDIR_INPUT)
  883. {
  884. CAutoLock cAutoLock(&m_csPins);
  885. int nConnected = GetConnectedInputPinCount();
  886. if(nConnected == 1)
  887. {
  888. m_pInput = (CStreamSwitcherInputPin*)pPin;
  889. }
  890. if(nConnected == m_pInputs.GetCount())
  891. {
  892. CStringW name;
  893. name.Format(L"Channel %d", ++m_PinVersion);
  894. HRESULT hr = S_OK;
  895. CStreamSwitcherInputPin* pPin = new CStreamSwitcherInputPin(this, &hr, name);
  896. if(!pPin || FAILED(hr)) return E_FAIL;
  897. m_pInputs.AddTail(pPin);
  898. }
  899. }
  900. return S_OK;
  901. }
  902. // this should be very thread safe, I hope it is, it must be... :)
  903. void CStreamSwitcherFilter::SelectInput(CStreamSwitcherInputPin* pInput)
  904. {
  905. // make sure no input thinks it is active
  906. m_pInput = NULL;
  907. // release blocked GetBuffer in our own allocator & block all Receive
  908. POSITION pos = m_pInputs.GetHeadPosition();
  909. while(pos)
  910. {
  911. CStreamSwitcherInputPin* pPin = m_pInputs.GetNext(pos);
  912. pPin->Block(false);
  913. // a few Receive calls can arrive here, but since m_pInput == NULL neighter of them gets delivered
  914. pPin->Block(true);
  915. }
  916. // this will let waiting GetBuffer() calls go on inside our Receive()
  917. if(m_pOutput)
  918. {
  919. m_pOutput->DeliverBeginFlush();
  920. m_pOutput->DeliverEndFlush();
  921. }
  922. if(!pInput) return;
  923. // set new input
  924. m_pInput = pInput;
  925. // let it go
  926. m_pInput->Block(false);
  927. }
  928. //
  929. HRESULT CStreamSwitcherFilter::Transform(IMediaSample* pIn, IMediaSample* pOut)
  930. {
  931. BYTE* pDataIn = NULL;
  932. BYTE* pDataOut = NULL;
  933. HRESULT hr;
  934. if(FAILED(hr = pIn->GetPointer(&pDataIn))) return hr;
  935. if(FAILED(hr = pOut->GetPointer(&pDataOut))) return hr;
  936. long len = pIn->GetActualDataLength();
  937. long size = pOut->GetSize();
  938. if(!pDataIn || !pDataOut /*|| len > size || len <= 0*/) return S_FALSE; // FIXME
  939. memcpy(pDataOut, pDataIn, min(len, size));
  940. pOut->SetActualDataLength(min(len, size));
  941. return S_OK;
  942. }
  943. CMediaType CStreamSwitcherFilter::CreateNewOutputMediaType(CMediaType mt, long& cbBuffer)
  944. {
  945. return(mt);
  946. }
  947. // IAMStreamSelect
  948. STDMETHODIMP CStreamSwitcherFilter::Count(DWORD* pcStreams)
  949. {
  950. if(!pcStreams) return E_POINTER;
  951. CAutoLock cAutoLock(&m_csPins);
  952. *pcStreams = GetConnectedInputPinCount();
  953. return S_OK;
  954. }
  955. STDMETHODIMP CStreamSwitcherFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk)
  956. {
  957. CAutoLock cAutoLock(&m_csPins);
  958. CBasePin* pPin = GetConnectedInputPin(lIndex);
  959. if(!pPin) return E_INVALIDARG;
  960. if(ppmt)
  961. *ppmt = CreateMediaType(&m_pOutput->CurrentMediaType());
  962. if(pdwFlags)
  963. *pdwFlags = (m_pInput == pPin) ? AMSTREAMSELECTINFO_EXCLUSIVE : 0;
  964. if(plcid)
  965. *plcid = 0;
  966. if(pdwGroup)
  967. *pdwGroup = 0;
  968. if(ppszName && (*ppszName = (WCHAR*)CoTaskMemAlloc((wcslen(pPin->Name())+1)*sizeof(WCHAR))))
  969. wcscpy(*ppszName, pPin->Name());
  970. if(ppObject)
  971. *ppObject = NULL;
  972. if(ppUnk)
  973. *ppUnk = NULL;
  974. return S_OK;
  975. }
  976. STDMETHODIMP CStreamSwitcherFilter::Enable(long lIndex, DWORD dwFlags)
  977. {
  978. if(dwFlags != AMSTREAMSELECTENABLE_ENABLE)
  979. return E_NOTIMPL;
  980. PauseGraph;
  981. CStreamSwitcherInputPin* pNewInput = GetConnectedInputPin(lIndex);
  982. if(!pNewInput) return E_INVALIDARG;
  983. SelectInput(pNewInput);
  984. ResumeGraph;
  985. return S_OK;
  986. }
  987. //////////