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

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2005 Gabest
  3.  * http://www.gabest.org
  4.  *
  5.  *  This Program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2, or (at your option)
  8.  *  any later version.
  9.  *   
  10.  *  This Program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  *  GNU General Public License for more details.
  14.  *   
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with GNU Make; see the file COPYING.  If not, write to
  17.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  18.  *  http://www.gnu.org/copyleft/gpl.html
  19.  *
  20.  */
  21. #include "StdAfx.h"
  22. #include "......DSUtilDSUtil.h"
  23. #include <initguid.h>
  24. #include "........includemoreuuids.h"
  25. #include "........includematroskamatroska.h"
  26. #include "....switcherAudioSwitcherAudioSwitcher.h"
  27. #include "BaseSplitter.h"
  28. #pragma warning(disable: 4355)
  29. #define MINPACKETS 10
  30. #define MINPACKETSIZE 100*1024
  31. #define MAXPACKETS 10000
  32. #define MAXPACKETSIZE 1024*1024*5
  33. //
  34. // CPacketQueue
  35. //
  36. CPacketQueue::CPacketQueue() : m_size(0)
  37. {
  38. }
  39. void CPacketQueue::Add(CAutoPtr<Packet> p)
  40. {
  41. CAutoLock cAutoLock(this);
  42. if(p)
  43. {
  44. m_size += p->GetSize();
  45. if(p->bAppendable && !p->bDiscontinuity && !p->pmt && GetCount() > 0
  46. && p->rtStart == Packet::INVALID_TIME
  47. && GetTail()->rtStart != Packet::INVALID_TIME)
  48. {
  49. Packet* tail = GetTail();
  50. int oldsize = tail->pData.GetSize();
  51. int newsize = tail->pData.GetSize() + p->pData.GetSize();
  52. tail->pData.SetSize(newsize, max(1024, newsize)); // doubles the reserved buffer size
  53. memcpy(tail->pData.GetData() + oldsize, p->pData.GetData(), p->pData.GetSize());
  54. return;
  55. }
  56. }
  57. AddTail(p);
  58. }
  59. CAutoPtr<Packet> CPacketQueue::Remove()
  60. {
  61. CAutoLock cAutoLock(this);
  62. ASSERT(__super::GetCount() > 0);
  63. CAutoPtr<Packet> p = RemoveHead();
  64. if(p) m_size -= p->GetSize();
  65. return p;
  66. }
  67. void CPacketQueue::RemoveAll()
  68. {
  69. CAutoLock cAutoLock(this);
  70. m_size = 0;
  71. __super::RemoveAll();
  72. }
  73. int CPacketQueue::GetCount()
  74. {
  75. CAutoLock cAutoLock(this); 
  76. return __super::GetCount();
  77. }
  78. int CPacketQueue::GetSize()
  79. {
  80. CAutoLock cAutoLock(this); 
  81. return m_size;
  82. }
  83. //
  84. // CBaseSplitterInputPin
  85. //
  86. CBaseSplitterInputPin::CBaseSplitterInputPin(TCHAR* pName, CBaseSplitterFilter* pFilter, CCritSec* pLock, HRESULT* phr)
  87. : CBasePin(pName, pFilter, pLock, phr, L"Input", PINDIR_INPUT)
  88. {
  89. }
  90. CBaseSplitterInputPin::~CBaseSplitterInputPin()
  91. {
  92. }
  93. HRESULT CBaseSplitterInputPin::GetAsyncReader(IAsyncReader** ppAsyncReader)
  94. {
  95. CheckPointer(ppAsyncReader, E_POINTER);
  96. *ppAsyncReader = NULL;
  97. CheckPointer(m_pAsyncReader, VFW_E_NOT_CONNECTED);
  98. (*ppAsyncReader = m_pAsyncReader)->AddRef();
  99. return S_OK;
  100. }
  101. STDMETHODIMP CBaseSplitterInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  102. {
  103. CheckPointer(ppv, E_POINTER);
  104. return 
  105. __super::NonDelegatingQueryInterface(riid, ppv);
  106. }
  107. HRESULT CBaseSplitterInputPin::CheckMediaType(const CMediaType* pmt)
  108. {
  109. return S_OK;
  110. /*
  111. return pmt->majortype == MEDIATYPE_Stream
  112. ? S_OK
  113. : E_INVALIDARG;
  114. */
  115. }
  116. HRESULT CBaseSplitterInputPin::CheckConnect(IPin* pPin)
  117. {
  118. HRESULT hr;
  119. if(FAILED(hr = __super::CheckConnect(pPin)))
  120. return hr;
  121. return CComQIPtr<IAsyncReader>(pPin) ? S_OK : E_NOINTERFACE;
  122. }
  123. HRESULT CBaseSplitterInputPin::BreakConnect()
  124. {
  125. HRESULT hr;
  126. if(FAILED(hr = __super::BreakConnect()))
  127. return hr;
  128. if(FAILED(hr = ((CBaseSplitterFilter*)m_pFilter)->BreakConnect(PINDIR_INPUT, this)))
  129. return hr;
  130. m_pAsyncReader.Release();
  131. return S_OK;
  132. }
  133. HRESULT CBaseSplitterInputPin::CompleteConnect(IPin* pPin)
  134. {
  135. HRESULT hr;
  136. if(FAILED(hr = __super::CompleteConnect(pPin)))
  137. return hr;
  138. CheckPointer(pPin, E_POINTER);
  139. m_pAsyncReader = pPin;
  140. CheckPointer(m_pAsyncReader, E_NOINTERFACE);
  141. if(FAILED(hr = ((CBaseSplitterFilter*)m_pFilter)->CompleteConnect(PINDIR_INPUT, this)))
  142. return hr;
  143. return S_OK;
  144. }
  145. STDMETHODIMP CBaseSplitterInputPin::BeginFlush()
  146. {
  147. return E_UNEXPECTED;
  148. }
  149. STDMETHODIMP CBaseSplitterInputPin::EndFlush()
  150. {
  151. return E_UNEXPECTED;
  152. }
  153. //
  154. // CBaseSplitterOutputPin
  155. //
  156. CBaseSplitterOutputPin::CBaseSplitterOutputPin(CArray<CMediaType>& mts, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers)
  157. : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName)
  158. , m_hrDeliver(S_OK) // just in case it were asked before the worker thread could be created and reset it
  159. , m_fFlushing(false)
  160. , m_eEndFlush(TRUE)
  161. {
  162. m_mts.Copy(mts);
  163. m_nBuffers = max(nBuffers, 1);
  164. memset(&m_brs, 0, sizeof(m_brs));
  165. m_brs.rtLastDeliverTime = Packet::INVALID_TIME;
  166. }
  167. CBaseSplitterOutputPin::CBaseSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers)
  168. : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName)
  169. , m_hrDeliver(S_OK) // just in case it were asked before the worker thread could be created and reset it
  170. , m_fFlushing(false)
  171. , m_eEndFlush(TRUE)
  172. {
  173. m_nBuffers = max(nBuffers, 1);
  174. memset(&m_brs, 0, sizeof(m_brs));
  175. m_brs.rtLastDeliverTime = Packet::INVALID_TIME;
  176. }
  177. CBaseSplitterOutputPin::~CBaseSplitterOutputPin()
  178. {
  179. }
  180. STDMETHODIMP CBaseSplitterOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  181. {
  182. CheckPointer(ppv, E_POINTER);
  183. return 
  184. // riid == __uuidof(IMediaSeeking) ? m_pFilter->QueryInterface(riid, ppv) : 
  185. QI(IMediaSeeking)
  186. QI(IPropertyBag)
  187. QI(IPropertyBag2)
  188. QI(IDSMPropertyBag)
  189. QI(IBitRateInfo)
  190. __super::NonDelegatingQueryInterface(riid, ppv);
  191. }
  192. HRESULT CBaseSplitterOutputPin::SetName(LPCWSTR pName)
  193. {
  194. CheckPointer(pName, E_POINTER);
  195. if(m_pName) delete [] m_pName;
  196. m_pName = new WCHAR[wcslen(pName)+1];
  197. CheckPointer(m_pName, E_OUTOFMEMORY);
  198. wcscpy(m_pName, pName);
  199. return S_OK;
  200. }
  201. HRESULT CBaseSplitterOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties)
  202. {
  203.     ASSERT(pAlloc);
  204.     ASSERT(pProperties);
  205.     HRESULT hr = NOERROR;
  206. pProperties->cBuffers = m_nBuffers;
  207. pProperties->cbBuffer = max(m_mt.lSampleSize, 1);
  208.     ALLOCATOR_PROPERTIES Actual;
  209.     if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) return hr;
  210.     if(Actual.cbBuffer < pProperties->cbBuffer) return E_FAIL;
  211.     ASSERT(Actual.cBuffers == pProperties->cBuffers);
  212.     return NOERROR;
  213. }
  214. HRESULT CBaseSplitterOutputPin::CheckMediaType(const CMediaType* pmt)
  215. {
  216. for(int i = 0; i < m_mts.GetCount(); i++)
  217. {
  218. if(*pmt == m_mts[i])
  219. return S_OK;
  220. }
  221. return E_INVALIDARG;
  222. }
  223. HRESULT CBaseSplitterOutputPin::GetMediaType(int iPosition, CMediaType* pmt)
  224. {
  225.     CAutoLock cAutoLock(m_pLock);
  226. if(iPosition < 0) return E_INVALIDARG;
  227. if(iPosition >= m_mts.GetCount()) return VFW_S_NO_MORE_ITEMS;
  228. *pmt = m_mts[iPosition];
  229. return S_OK;
  230. }
  231. STDMETHODIMP CBaseSplitterOutputPin::Notify(IBaseFilter* pSender, Quality q)
  232. {
  233. return E_NOTIMPL;
  234. }
  235. //
  236. HRESULT CBaseSplitterOutputPin::Active()
  237. {
  238.     CAutoLock cAutoLock(m_pLock);
  239. if(m_Connected) 
  240. Create();
  241. return __super::Active();
  242. }
  243. HRESULT CBaseSplitterOutputPin::Inactive()
  244. {
  245.     CAutoLock cAutoLock(m_pLock);
  246. if(ThreadExists())
  247. CallWorker(CMD_EXIT);
  248. return __super::Inactive();
  249. }
  250. HRESULT CBaseSplitterOutputPin::DeliverBeginFlush()
  251. {
  252. m_eEndFlush.Reset();
  253. m_fFlushed = false;
  254. m_fFlushing = true;
  255. m_hrDeliver = S_FALSE;
  256. m_queue.RemoveAll();
  257. HRESULT hr = IsConnected() ? GetConnected()->BeginFlush() : S_OK;
  258. if(S_OK != hr) m_eEndFlush.Set();
  259. return(hr);
  260. }
  261. HRESULT CBaseSplitterOutputPin::DeliverEndFlush()
  262. {
  263. if(!ThreadExists()) return S_FALSE;
  264. HRESULT hr = IsConnected() ? GetConnected()->EndFlush() : S_OK;
  265. m_hrDeliver = S_OK;
  266. m_fFlushing = false;
  267. m_fFlushed = true;
  268. m_eEndFlush.Set();
  269. return hr;
  270. }
  271. HRESULT CBaseSplitterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
  272. {
  273. m_brs.rtLastDeliverTime = Packet::INVALID_TIME;
  274. if(m_fFlushing) return S_FALSE;
  275. m_rtStart = tStart;
  276. if(!ThreadExists()) return S_FALSE;
  277. HRESULT hr = __super::DeliverNewSegment(tStart, tStop, dRate);
  278. if(S_OK != hr) return hr;
  279. MakeISCRHappy();
  280. return hr;
  281. }
  282. int CBaseSplitterOutputPin::QueueCount()
  283. {
  284. return m_queue.GetCount();
  285. }
  286. int CBaseSplitterOutputPin::QueueSize()
  287. {
  288. return m_queue.GetSize();
  289. }
  290. HRESULT CBaseSplitterOutputPin::QueueEndOfStream()
  291. {
  292. return QueuePacket(CAutoPtr<Packet>()); // NULL means EndOfStream
  293. }
  294. HRESULT CBaseSplitterOutputPin::QueuePacket(CAutoPtr<Packet> p)
  295. {
  296. if(!ThreadExists()) return S_FALSE;
  297. while(S_OK == m_hrDeliver 
  298. && (!((CBaseSplitterFilter*)m_pFilter)->IsAnyPinDrying()
  299. || m_queue.GetSize() > MAXPACKETSIZE*100))
  300. Sleep(1);
  301. if(S_OK != m_hrDeliver)
  302. return m_hrDeliver;
  303. m_queue.Add(p);
  304. return m_hrDeliver;
  305. }
  306. bool CBaseSplitterOutputPin::IsDiscontinuous()
  307. {
  308. return m_mt.majortype == MEDIATYPE_Text
  309. || m_mt.majortype == MEDIATYPE_ScriptCommand
  310. || m_mt.majortype == MEDIATYPE_Subtitle 
  311. || m_mt.subtype == MEDIASUBTYPE_DVD_SUBPICTURE 
  312. || m_mt.subtype == MEDIASUBTYPE_CVD_SUBPICTURE 
  313. || m_mt.subtype == MEDIASUBTYPE_SVCD_SUBPICTURE;
  314. }
  315. bool CBaseSplitterOutputPin::IsActive()
  316. {
  317. CComPtr<IPin> pPin = this;
  318. do
  319. {
  320. CComPtr<IPin> pPinTo;
  321. CComQIPtr<IStreamSwitcherInputPin> pSSIP;
  322. if(S_OK == pPin->ConnectedTo(&pPinTo) && (pSSIP = pPinTo) && !pSSIP->IsActive())
  323. return(false);
  324. pPin = GetFirstPin(GetFilterFromPin(pPinTo), PINDIR_OUTPUT);
  325. }
  326. while(pPin);
  327. return(true);
  328. }
  329. DWORD CBaseSplitterOutputPin::ThreadProc()
  330. {
  331. m_hrDeliver = S_OK;
  332. m_fFlushing = m_fFlushed = false;
  333. m_eEndFlush.Set();
  334. while(1)
  335. {
  336. Sleep(1);
  337. DWORD cmd;
  338. if(CheckRequest(&cmd))
  339. {
  340. m_hThread = NULL;
  341. cmd = GetRequest();
  342. Reply(S_OK);
  343. ASSERT(cmd == CMD_EXIT);
  344. return 0;
  345. }
  346. int cnt = 0;
  347. do
  348. {
  349. CAutoPtr<Packet> p;
  350. {
  351. CAutoLock cAutoLock(&m_queue);
  352. if((cnt = m_queue.GetCount()) > 0)
  353. p = m_queue.Remove();
  354. }
  355. if(S_OK == m_hrDeliver && cnt > 0)
  356. {
  357. ASSERT(!m_fFlushing);
  358. m_fFlushed = false;
  359. // flushing can still start here, to release a blocked deliver call
  360. HRESULT hr = p 
  361. ? DeliverPacket(p) 
  362. : DeliverEndOfStream();
  363. m_eEndFlush.Wait(); // .. so we have to wait until it is done
  364. if(hr != S_OK && !m_fFlushed) // and only report the error in m_hrDeliver if we didn't flush the stream
  365. {
  366. // CAutoLock cAutoLock(&m_csQueueLock);
  367. m_hrDeliver = hr;
  368. break;
  369. }
  370. }
  371. }
  372. while(--cnt > 0);
  373. }
  374. }
  375. HRESULT CBaseSplitterOutputPin::DeliverPacket(CAutoPtr<Packet> p)
  376. {
  377. HRESULT hr;
  378. INT_PTR nBytes = p->pData.GetCount();
  379. if(nBytes == 0)
  380. {
  381. return S_OK;
  382. }
  383. m_brs.nBytesSinceLastDeliverTime += nBytes;
  384. if(p->rtStart != Packet::INVALID_TIME)
  385. {
  386. if(m_brs.rtLastDeliverTime == Packet::INVALID_TIME)
  387. {
  388. m_brs.rtLastDeliverTime = p->rtStart;
  389. m_brs.nBytesSinceLastDeliverTime = 0;
  390. }
  391. if(m_brs.rtLastDeliverTime + 10000000 < p->rtStart)
  392. {
  393. REFERENCE_TIME rtDiff = p->rtStart - m_brs.rtLastDeliverTime;
  394. double secs, bits;
  395. secs = (double)rtDiff / 10000000;
  396. bits = 8.0 * m_brs.nBytesSinceLastDeliverTime;
  397. m_brs.nCurrentBitRate = (DWORD)(bits / secs);
  398. m_brs.rtTotalTimeDelivered += rtDiff;
  399. m_brs.nTotalBytesDelivered += m_brs.nBytesSinceLastDeliverTime;
  400. secs = (double)m_brs.rtTotalTimeDelivered / 10000000;
  401. bits = 8.0 * m_brs.nTotalBytesDelivered;
  402. m_brs.nAverageBitRate = (DWORD)(bits / secs);
  403. m_brs.rtLastDeliverTime = p->rtStart;
  404. m_brs.nBytesSinceLastDeliverTime = 0;
  405. /*
  406. TRACE(_T("[%d] c: %d kbps, a: %d kbpsn"), 
  407. p->TrackNumber,
  408. (m_brs.nCurrentBitRate+500)/1000, 
  409. (m_brs.nAverageBitRate+500)/1000);
  410. */
  411. }
  412. double dRate = 1.0;
  413. if(SUCCEEDED(((CBaseSplitterFilter*)m_pFilter)->GetRate(&dRate)))
  414. {
  415. p->rtStart = (REFERENCE_TIME)((double)p->rtStart / dRate);
  416. p->rtStop = (REFERENCE_TIME)((double)p->rtStop / dRate);
  417. }
  418. }
  419. do
  420. {
  421. CComPtr<IMediaSample> pSample;
  422. if(S_OK != (hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0))) break;
  423. if(nBytes > pSample->GetSize())
  424. {
  425. pSample.Release();
  426. ALLOCATOR_PROPERTIES props, actual;
  427. if(S_OK != (hr = m_pAllocator->GetProperties(&props))) break;
  428. props.cbBuffer = nBytes*3/2;
  429. if(props.cBuffers > 1)
  430. {
  431. if(S_OK != (hr = __super::DeliverBeginFlush())) break;
  432. if(S_OK != (hr = __super::DeliverEndFlush())) break;
  433. }
  434. if(S_OK != (hr = m_pAllocator->Decommit())) break;
  435. if(S_OK != (hr = m_pAllocator->SetProperties(&props, &actual))) break;
  436. if(S_OK != (hr = m_pAllocator->Commit())) break;
  437. if(S_OK != (hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0))) break;
  438. }
  439. if(p->pmt)
  440. {
  441. pSample->SetMediaType(p->pmt);
  442. p->bDiscontinuity = true;
  443.     CAutoLock cAutoLock(m_pLock);
  444. m_mts.RemoveAll();
  445. m_mts.Add(*p->pmt);
  446. }
  447. bool fTimeValid = p->rtStart != Packet::INVALID_TIME;
  448. /*
  449. //if(p->TrackNumber == 1)
  450. //if(p->rtStart != Packet::INVALID_TIME)
  451. TRACE(_T("[%d]: d%d s%d p%d, b=%d, %I64d-%I64d n"), 
  452.   p->TrackNumber,
  453.   p->bDiscontinuity, p->bSyncPoint, fTimeValid && p->rtStart < 0,
  454.   nBytes, p->rtStart, p->rtStop);
  455. */
  456. ASSERT(!p->bSyncPoint || fTimeValid);
  457. BYTE* pData = NULL;
  458. if(S_OK != (hr = pSample->GetPointer(&pData)) || !pData) break;
  459. memcpy(pData, p->pData.GetData(), nBytes);
  460. if(S_OK != (hr = pSample->SetActualDataLength(nBytes))) break;
  461. if(S_OK != (hr = pSample->SetTime(fTimeValid ? &p->rtStart : NULL, fTimeValid ? &p->rtStop : NULL))) break;
  462. if(S_OK != (hr = pSample->SetMediaTime(NULL, NULL))) break;
  463. if(S_OK != (hr = pSample->SetDiscontinuity(p->bDiscontinuity))) break;
  464. if(S_OK != (hr = pSample->SetSyncPoint(p->bSyncPoint))) break;
  465. if(S_OK != (hr = pSample->SetPreroll(fTimeValid && p->rtStart < 0))) break;
  466. if(S_OK != (hr = Deliver(pSample))) break;
  467. }
  468. while(false);
  469. return hr;
  470. }
  471. void CBaseSplitterOutputPin::MakeISCRHappy()
  472. {
  473. CComPtr<IPin> pPinTo = this, pTmp;
  474. while(pPinTo && SUCCEEDED(pPinTo->ConnectedTo(&pTmp)) && (pPinTo = pTmp))
  475. {
  476. pTmp = NULL;
  477. CComPtr<IBaseFilter> pBF = GetFilterFromPin(pPinTo);
  478. if(GetCLSID(pBF) == GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}"))) // ISCR
  479. {
  480. CAutoPtr<Packet> p(new Packet());
  481. p->TrackNumber = (DWORD)-1;
  482. p->rtStart = -1; p->rtStop = 0;
  483. p->bSyncPoint = FALSE;
  484. p->pData.SetSize(2);
  485. strcpy((char*)p->pData.GetData(), " ");
  486. QueuePacket(p);
  487. break;
  488. }
  489. pPinTo = GetFirstPin(pBF, PINDIR_OUTPUT);
  490. }
  491. }
  492. HRESULT CBaseSplitterOutputPin::GetDeliveryBuffer(IMediaSample** ppSample, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags)
  493. {
  494. return __super::GetDeliveryBuffer(ppSample, pStartTime, pEndTime, dwFlags);
  495. }
  496. HRESULT CBaseSplitterOutputPin::Deliver(IMediaSample* pSample)
  497. {
  498. return __super::Deliver(pSample);
  499. }
  500. // IMediaSeeking
  501. STDMETHODIMP CBaseSplitterOutputPin::GetCapabilities(DWORD* pCapabilities)
  502. {
  503. return ((CBaseSplitterFilter*)m_pFilter)->GetCapabilities(pCapabilities);
  504. }
  505. STDMETHODIMP CBaseSplitterOutputPin::CheckCapabilities(DWORD* pCapabilities)
  506. {
  507. return ((CBaseSplitterFilter*)m_pFilter)->CheckCapabilities(pCapabilities);
  508. }
  509. STDMETHODIMP CBaseSplitterOutputPin::IsFormatSupported(const GUID* pFormat)
  510. {
  511. return ((CBaseSplitterFilter*)m_pFilter)->IsFormatSupported(pFormat);
  512. }
  513. STDMETHODIMP CBaseSplitterOutputPin::QueryPreferredFormat(GUID* pFormat)
  514. {
  515. return ((CBaseSplitterFilter*)m_pFilter)->QueryPreferredFormat(pFormat);
  516. }
  517. STDMETHODIMP CBaseSplitterOutputPin::GetTimeFormat(GUID* pFormat)
  518. {
  519. return ((CBaseSplitterFilter*)m_pFilter)->GetTimeFormat(pFormat);
  520. }
  521. STDMETHODIMP CBaseSplitterOutputPin::IsUsingTimeFormat(const GUID* pFormat)
  522. {
  523. return ((CBaseSplitterFilter*)m_pFilter)->IsUsingTimeFormat(pFormat);
  524. }
  525. STDMETHODIMP CBaseSplitterOutputPin::SetTimeFormat(const GUID* pFormat)
  526. {
  527. return ((CBaseSplitterFilter*)m_pFilter)->SetTimeFormat(pFormat);
  528. }
  529. STDMETHODIMP CBaseSplitterOutputPin::GetDuration(LONGLONG* pDuration)
  530. {
  531. return ((CBaseSplitterFilter*)m_pFilter)->GetDuration(pDuration);
  532. }
  533. STDMETHODIMP CBaseSplitterOutputPin::GetStopPosition(LONGLONG* pStop)
  534. {
  535. return ((CBaseSplitterFilter*)m_pFilter)->GetStopPosition(pStop);
  536. }
  537. STDMETHODIMP CBaseSplitterOutputPin::GetCurrentPosition(LONGLONG* pCurrent)
  538. {
  539. return ((CBaseSplitterFilter*)m_pFilter)->GetCurrentPosition(pCurrent);
  540. }
  541. STDMETHODIMP CBaseSplitterOutputPin::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat)
  542. {
  543. return ((CBaseSplitterFilter*)m_pFilter)->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat);
  544. }
  545. STDMETHODIMP CBaseSplitterOutputPin::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
  546. {
  547. return ((CBaseSplitterFilter*)m_pFilter)->SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
  548. }
  549. STDMETHODIMP CBaseSplitterOutputPin::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop)
  550. {
  551. return ((CBaseSplitterFilter*)m_pFilter)->GetPositions(pCurrent, pStop);
  552. }
  553. STDMETHODIMP CBaseSplitterOutputPin::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest)
  554. {
  555. return ((CBaseSplitterFilter*)m_pFilter)->GetAvailable(pEarliest, pLatest);
  556. }
  557. STDMETHODIMP CBaseSplitterOutputPin::SetRate(double dRate)
  558. {
  559. return ((CBaseSplitterFilter*)m_pFilter)->SetRate(dRate);
  560. }
  561. STDMETHODIMP CBaseSplitterOutputPin::GetRate(double* pdRate)
  562. {
  563. return ((CBaseSplitterFilter*)m_pFilter)->GetRate(pdRate);
  564. }
  565. STDMETHODIMP CBaseSplitterOutputPin::GetPreroll(LONGLONG* pllPreroll)
  566. {
  567. return ((CBaseSplitterFilter*)m_pFilter)->GetPreroll(pllPreroll);
  568. }
  569. //
  570. // CBaseSplitterFilter
  571. //
  572. CBaseSplitterFilter::CBaseSplitterFilter(LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid)
  573. : CBaseFilter(pName, pUnk, this, clsid)
  574. , m_rtDuration(0), m_rtStart(0), m_rtStop(0), m_rtCurrent(0)
  575. , m_dRate(1.0)
  576. , m_nOpenProgress(100)
  577. , m_fAbort(false)
  578. , m_rtLastStart(_I64_MIN)
  579. , m_rtLastStop(_I64_MIN)
  580. , m_priority(THREAD_PRIORITY_NORMAL)
  581. {
  582. if(phr) *phr = S_OK;
  583. m_pInput.Attach(new CBaseSplitterInputPin(NAME("CBaseSplitterInputPin"), this, this, phr));
  584. }
  585. CBaseSplitterFilter::~CBaseSplitterFilter()
  586. {
  587. CAutoLock cAutoLock(this);
  588. CAMThread::CallWorker(CMD_EXIT);
  589. CAMThread::Close();
  590. }
  591. STDMETHODIMP CBaseSplitterFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  592. {
  593. CheckPointer(ppv, E_POINTER);
  594. *ppv = NULL;
  595. if(m_pInput && riid == __uuidof(IFileSourceFilter)) 
  596. return E_NOINTERFACE;
  597. return 
  598. QI(IFileSourceFilter)
  599. QI(IMediaSeeking)
  600. QI(IAMOpenProgress)
  601. QI2(IAMMediaContent)
  602. QI2(IAMExtendedSeeking)
  603. QI(IKeyFrameInfo)
  604. QI(IBufferInfo)
  605. QI(IPropertyBag)
  606. QI(IPropertyBag2)
  607. QI(IDSMPropertyBag)
  608. QI(IDSMResourceBag)
  609. QI(IDSMChapterBag)
  610. __super::NonDelegatingQueryInterface(riid, ppv);
  611. }
  612. CBaseSplitterOutputPin* CBaseSplitterFilter::GetOutputPin(DWORD TrackNum)
  613. {
  614. CAutoLock cAutoLock(&m_csPinMap);
  615.     CBaseSplitterOutputPin* pPin = NULL;
  616. m_pPinMap.Lookup(TrackNum, pPin);
  617. return pPin;
  618. }
  619. DWORD CBaseSplitterFilter::GetOutputTrackNum(CBaseSplitterOutputPin* pPin)
  620. {
  621. CAutoLock cAutoLock(&m_csPinMap);
  622. POSITION pos = m_pPinMap.GetStartPosition();
  623. while(pos)
  624. {
  625. DWORD TrackNum;
  626. CBaseSplitterOutputPin* pPinTmp;
  627. m_pPinMap.GetNextAssoc(pos, TrackNum, pPinTmp);
  628. if(pPinTmp == pPin) return TrackNum;
  629. }
  630. return (DWORD)-1;
  631. }
  632. HRESULT CBaseSplitterFilter::RenameOutputPin(DWORD TrackNumSrc, DWORD TrackNumDst, const AM_MEDIA_TYPE* pmt)
  633. {
  634. CAutoLock cAutoLock(&m_csPinMap);
  635. CBaseSplitterOutputPin* pPin;
  636. if(m_pPinMap.Lookup(TrackNumSrc, pPin))
  637. {
  638. if(CComQIPtr<IPin> pPinTo = pPin->GetConnected())
  639. {
  640. if(pmt && S_OK != pPinTo->QueryAccept(pmt))
  641. return VFW_E_TYPE_NOT_ACCEPTED;
  642. }
  643. m_pPinMap.RemoveKey(TrackNumSrc);
  644. m_pPinMap[TrackNumDst] = pPin;
  645. if(pmt)
  646. {
  647. CAutoLock cAutoLock(&m_csmtnew);
  648. m_mtnew[TrackNumDst] = *pmt;
  649. }
  650. return S_OK;
  651. }
  652. return E_FAIL;
  653. }
  654. HRESULT CBaseSplitterFilter::AddOutputPin(DWORD TrackNum, CAutoPtr<CBaseSplitterOutputPin> pPin)
  655. {
  656. CAutoLock cAutoLock(&m_csPinMap);
  657. if(!pPin) return E_INVALIDARG;
  658. m_pPinMap[TrackNum] = pPin;
  659. m_pOutputs.AddTail(pPin);
  660. return S_OK;
  661. }
  662. HRESULT CBaseSplitterFilter::DeleteOutputs()
  663. {
  664. m_rtDuration = 0;
  665. m_pRetiredOutputs.RemoveAll();
  666. CAutoLock cAutoLockF(this);
  667. if(m_State != State_Stopped) return VFW_E_NOT_STOPPED;
  668. while(m_pOutputs.GetCount())
  669. {
  670. CAutoPtr<CBaseSplitterOutputPin> pPin = m_pOutputs.RemoveHead();
  671. if(IPin* pPinTo = pPin->GetConnected()) pPinTo->Disconnect();
  672. pPin->Disconnect();
  673. // we can't just let it be deleted now, something might have AddRefed on it (graphedit...)
  674. m_pRetiredOutputs.AddTail(pPin);
  675. }
  676. CAutoLock cAutoLockPM(&m_csPinMap);
  677. m_pPinMap.RemoveAll();
  678. CAutoLock cAutoLockMT(&m_csmtnew);
  679. m_mtnew.RemoveAll();
  680. RemoveAll();
  681. ResRemoveAll();
  682. ChapRemoveAll();
  683. m_fontinst.UninstallFonts();
  684. m_pSyncReader.Release();
  685. return S_OK;
  686. }
  687. void CBaseSplitterFilter::DeliverBeginFlush()
  688. {
  689. m_fFlushing = true;
  690. POSITION pos = m_pOutputs.GetHeadPosition();
  691. while(pos) m_pOutputs.GetNext(pos)->DeliverBeginFlush();
  692. }
  693. void CBaseSplitterFilter::DeliverEndFlush()
  694. {
  695. POSITION pos = m_pOutputs.GetHeadPosition();
  696. while(pos) m_pOutputs.GetNext(pos)->DeliverEndFlush();
  697. m_fFlushing = false;
  698. m_eEndFlush.Set();
  699. }
  700. DWORD CBaseSplitterFilter::ThreadProc()
  701. {
  702. if(m_pSyncReader) 
  703. m_pSyncReader->SetBreakEvent(GetRequestHandle());
  704. if(!DemuxInit())
  705. {
  706. while(1)
  707. {
  708. DWORD cmd = GetRequest();
  709. if(cmd == CMD_EXIT) CAMThread::m_hThread = NULL;
  710. Reply(S_OK);
  711. if(cmd == CMD_EXIT) return 0;
  712. }
  713. }
  714. m_eEndFlush.Set();
  715. m_fFlushing = false;
  716. for(DWORD cmd = -1; ; cmd = GetRequest())
  717. {
  718. if(cmd == CMD_EXIT)
  719. {
  720. m_hThread = NULL;
  721. Reply(S_OK);
  722. return 0;
  723. }
  724. SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL);
  725. m_rtStart = m_rtNewStart;
  726. m_rtStop = m_rtNewStop;
  727. DemuxSeek(m_rtStart);
  728. if(cmd != -1)
  729. Reply(S_OK);
  730. m_eEndFlush.Wait();
  731. m_pActivePins.RemoveAll();
  732. POSITION pos = m_pOutputs.GetHeadPosition();
  733. while(pos && !m_fFlushing)
  734. {
  735. CBaseSplitterOutputPin* pPin = m_pOutputs.GetNext(pos);
  736. if(pPin->IsConnected() && pPin->IsActive())
  737. {
  738. m_pActivePins.AddTail(pPin);
  739. pPin->DeliverNewSegment(m_rtStart, m_rtStop, m_dRate);
  740. }
  741. }
  742. do {m_bDiscontinuitySent.RemoveAll();}
  743. while(!DemuxLoop());
  744. pos = m_pActivePins.GetHeadPosition();
  745. while(pos && !CheckRequest(&cmd))
  746. m_pActivePins.GetNext(pos)->QueueEndOfStream();
  747. }
  748. ASSERT(0); // we should only exit via CMD_EXIT
  749. m_hThread = NULL;
  750. return 0;
  751. }
  752. HRESULT CBaseSplitterFilter::DeliverPacket(CAutoPtr<Packet> p)
  753. {
  754. HRESULT hr = S_FALSE;
  755. CBaseSplitterOutputPin* pPin = GetOutputPin(p->TrackNumber);
  756. if(!pPin || !pPin->IsConnected() || !m_pActivePins.Find(pPin))
  757. return S_FALSE;
  758. if(p->rtStart != Packet::INVALID_TIME)
  759. {
  760. m_rtCurrent = p->rtStart;
  761. p->rtStart -= m_rtStart;
  762. p->rtStop -= m_rtStart;
  763. ASSERT(p->rtStart <= p->rtStop);
  764. }
  765. {
  766. CAutoLock cAutoLock(&m_csmtnew);
  767. CMediaType mt;
  768. if(m_mtnew.Lookup(p->TrackNumber, mt))
  769. {
  770. p->pmt = CreateMediaType(&mt);
  771. m_mtnew.RemoveKey(p->TrackNumber);
  772. }
  773. }
  774. if(!m_bDiscontinuitySent.Find(p->TrackNumber))
  775. p->bDiscontinuity = TRUE;
  776. DWORD TrackNumber = p->TrackNumber;
  777. BOOL bDiscontinuity = p->bDiscontinuity;
  778. /*
  779. //if(p->TrackNumber == 1)
  780. //if(p->rtStart != Packet::INVALID_TIME)
  781. TRACE(_T("[%d]: d%d s%d p%d, b=%d, %I64d-%I64d n"), 
  782.   p->TrackNumber,
  783.   p->bDiscontinuity, p->bSyncPoint, p->rtStart != Packet::INVALID_TIME && p->rtStart < 0,
  784.   p->pData.GetCount(), p->rtStart, p->rtStop);
  785. */
  786. hr = pPin->QueuePacket(p);
  787. if(S_OK != hr)
  788. {
  789. if(POSITION pos = m_pActivePins.Find(pPin))
  790. m_pActivePins.RemoveAt(pos);
  791. if(!m_pActivePins.IsEmpty()) // only die when all pins are down
  792. hr = S_OK;
  793. return hr;
  794. }
  795. if(bDiscontinuity)
  796. m_bDiscontinuitySent.AddTail(TrackNumber);
  797. return hr;
  798. }
  799. bool CBaseSplitterFilter::IsAnyPinDrying()
  800. {
  801. int totalcount = 0, totalsize = 0;
  802. POSITION pos = m_pActivePins.GetHeadPosition();
  803. while(pos)
  804. {
  805. CBaseSplitterOutputPin* pPin = m_pActivePins.GetNext(pos);
  806. int count = pPin->QueueCount();
  807. int size = pPin->QueueSize();
  808. if(!pPin->IsDiscontinuous() && (count < MINPACKETS || size < MINPACKETSIZE))
  809. {
  810. // if(m_priority != THREAD_PRIORITY_ABOVE_NORMAL && (count < MINPACKETS/3 || size < MINPACKETSIZE/3))
  811. if(m_priority != THREAD_PRIORITY_BELOW_NORMAL && (count < MINPACKETS/3 || size < MINPACKETSIZE/3))
  812. {
  813. // SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_ABOVE_NORMAL);
  814. POSITION pos = m_pOutputs.GetHeadPosition();
  815. while(pos) m_pOutputs.GetNext(pos)->SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
  816. m_priority = THREAD_PRIORITY_BELOW_NORMAL;
  817. }
  818. return(true);
  819. }
  820. totalcount += count;
  821. totalsize += size;
  822. }
  823. if(m_priority != THREAD_PRIORITY_NORMAL && (totalcount > MAXPACKETS*2/3 || totalsize > MAXPACKETSIZE*2/3))
  824. {
  825. // SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL);
  826. POSITION pos = m_pOutputs.GetHeadPosition();
  827. while(pos) m_pOutputs.GetNext(pos)->SetThreadPriority(THREAD_PRIORITY_NORMAL);
  828. m_priority = THREAD_PRIORITY_NORMAL;
  829. }
  830. if(totalcount < MAXPACKETS && totalsize < MAXPACKETSIZE) 
  831. return(true);
  832. return(false);
  833. }
  834. HRESULT CBaseSplitterFilter::BreakConnect(PIN_DIRECTION dir, CBasePin* pPin)
  835. {
  836. CheckPointer(pPin, E_POINTER);
  837. if(dir == PINDIR_INPUT)
  838. {
  839. DeleteOutputs();
  840. }
  841. else if(dir == PINDIR_OUTPUT)
  842. {
  843. }
  844. else
  845. {
  846. return E_UNEXPECTED;
  847. }
  848. return S_OK;
  849. }
  850. HRESULT CBaseSplitterFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin)
  851. {
  852. CheckPointer(pPin, E_POINTER);
  853. if(dir == PINDIR_INPUT)
  854. {
  855. CBaseSplitterInputPin* pIn = (CBaseSplitterInputPin*)pPin;
  856. HRESULT hr;
  857. CComPtr<IAsyncReader> pAsyncReader;
  858. if(FAILED(hr = pIn->GetAsyncReader(&pAsyncReader))
  859. || FAILED(hr = DeleteOutputs())
  860. || FAILED(hr = CreateOutputs(pAsyncReader)))
  861. return hr;
  862. ChapSort();
  863. m_pSyncReader = pAsyncReader;
  864. }
  865. else if(dir == PINDIR_OUTPUT)
  866. {
  867. m_pRetiredOutputs.RemoveAll();
  868. }
  869. else
  870. {
  871. return E_UNEXPECTED;
  872. }
  873. return S_OK;
  874. }
  875. int CBaseSplitterFilter::GetPinCount()
  876. {
  877. return (m_pInput ? 1 : 0) + m_pOutputs.GetCount();
  878. }
  879. CBasePin* CBaseSplitterFilter::GetPin(int n)
  880. {
  881.     CAutoLock cAutoLock(this);
  882. if(n >= 0 && n < (int)m_pOutputs.GetCount())
  883. {
  884. if(POSITION pos = m_pOutputs.FindIndex(n))
  885. return m_pOutputs.GetAt(pos);
  886. }
  887. if(n == m_pOutputs.GetCount() && m_pInput)
  888. {
  889. return m_pInput;
  890. }
  891. return NULL;
  892. }
  893. STDMETHODIMP CBaseSplitterFilter::Stop()
  894. {
  895. CAutoLock cAutoLock(this);
  896. DeliverBeginFlush();
  897. CallWorker(CMD_EXIT);
  898. DeliverEndFlush();
  899. HRESULT hr;
  900. if(FAILED(hr = __super::Stop()))
  901. return hr;
  902. return S_OK;
  903. }
  904. STDMETHODIMP CBaseSplitterFilter::Pause()
  905. {
  906. CAutoLock cAutoLock(this);
  907. FILTER_STATE fs = m_State;
  908. HRESULT hr;
  909. if(FAILED(hr = __super::Pause()))
  910. return hr;
  911. if(fs == State_Stopped)
  912. {
  913. Create();
  914. }
  915. return S_OK;
  916. }
  917. STDMETHODIMP CBaseSplitterFilter::Run(REFERENCE_TIME tStart)
  918. {
  919. CAutoLock cAutoLock(this);
  920. HRESULT hr;
  921. if(FAILED(hr = __super::Run(tStart)))
  922. return hr;
  923. return S_OK;
  924. }
  925. // IFileSourceFilter
  926. STDMETHODIMP CBaseSplitterFilter::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt)
  927. {
  928. CheckPointer(pszFileName, E_POINTER);
  929. HRESULT hr = E_FAIL;
  930. CComPtr<IAsyncReader> pAsyncReader = (IAsyncReader*)new CAsyncFileReader(CString(pszFileName), hr);
  931. if(FAILED(hr)
  932. || FAILED(hr = DeleteOutputs())
  933. || FAILED(hr = CreateOutputs(pAsyncReader)))
  934. return hr;
  935. ChapSort();
  936. m_fn = pszFileName;
  937. m_pSyncReader = pAsyncReader;
  938. return S_OK;
  939. }
  940. STDMETHODIMP CBaseSplitterFilter::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt)
  941. {
  942. CheckPointer(ppszFileName, E_POINTER);
  943. if(!(*ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength()+1)*sizeof(WCHAR))))
  944. return E_OUTOFMEMORY;
  945. wcscpy(*ppszFileName, m_fn);
  946. return S_OK;
  947. }
  948. // IMediaSeeking
  949. STDMETHODIMP CBaseSplitterFilter::GetCapabilities(DWORD* pCapabilities)
  950. {
  951. return pCapabilities ? *pCapabilities = 
  952. AM_SEEKING_CanGetStopPos|
  953. AM_SEEKING_CanGetDuration|
  954. AM_SEEKING_CanSeekAbsolute|
  955. AM_SEEKING_CanSeekForwards|
  956. AM_SEEKING_CanSeekBackwards, S_OK : E_POINTER;
  957. }
  958. STDMETHODIMP CBaseSplitterFilter::CheckCapabilities(DWORD* pCapabilities)
  959. {
  960. CheckPointer(pCapabilities, E_POINTER);
  961. if(*pCapabilities == 0) return S_OK;
  962. DWORD caps;
  963. GetCapabilities(&caps);
  964. if((caps&*pCapabilities) == 0) return E_FAIL;
  965. if(caps == *pCapabilities) return S_OK;
  966. return S_FALSE;
  967. }
  968. STDMETHODIMP CBaseSplitterFilter::IsFormatSupported(const GUID* pFormat) {return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;}
  969. STDMETHODIMP CBaseSplitterFilter::QueryPreferredFormat(GUID* pFormat) {return GetTimeFormat(pFormat);}
  970. STDMETHODIMP CBaseSplitterFilter::GetTimeFormat(GUID* pFormat) {return pFormat ? *pFormat = TIME_FORMAT_MEDIA_TIME, S_OK : E_POINTER;}
  971. STDMETHODIMP CBaseSplitterFilter::IsUsingTimeFormat(const GUID* pFormat) {return IsFormatSupported(pFormat);}
  972. STDMETHODIMP CBaseSplitterFilter::SetTimeFormat(const GUID* pFormat) {return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG;}
  973. STDMETHODIMP CBaseSplitterFilter::GetDuration(LONGLONG* pDuration) {CheckPointer(pDuration, E_POINTER); *pDuration = m_rtDuration; return S_OK;}
  974. STDMETHODIMP CBaseSplitterFilter::GetStopPosition(LONGLONG* pStop) {return GetDuration(pStop);}
  975. STDMETHODIMP CBaseSplitterFilter::GetCurrentPosition(LONGLONG* pCurrent) {return E_NOTIMPL;}
  976. STDMETHODIMP CBaseSplitterFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) {return E_NOTIMPL;}
  977. STDMETHODIMP CBaseSplitterFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
  978. {
  979. return SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
  980. }
  981. STDMETHODIMP CBaseSplitterFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop)
  982. {
  983. if(pCurrent) *pCurrent = m_rtCurrent;
  984. if(pStop) *pStop = m_rtStop;
  985. return S_OK;
  986. }
  987. STDMETHODIMP CBaseSplitterFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest)
  988. {
  989. if(pEarliest) *pEarliest = 0;
  990. return GetDuration(pLatest);
  991. }
  992. STDMETHODIMP CBaseSplitterFilter::SetRate(double dRate) {return dRate > 0 ? m_dRate = dRate, S_OK : E_INVALIDARG;}
  993. STDMETHODIMP CBaseSplitterFilter::GetRate(double* pdRate) {return pdRate ? *pdRate = m_dRate, S_OK : E_POINTER;}
  994. STDMETHODIMP CBaseSplitterFilter::GetPreroll(LONGLONG* pllPreroll) {return pllPreroll ? *pllPreroll = 0, S_OK : E_POINTER;}
  995. HRESULT CBaseSplitterFilter::SetPositionsInternal(void* id, LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
  996. {
  997. CAutoLock cAutoLock(this);
  998. if(!pCurrent && !pStop
  999. || (dwCurrentFlags&AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning 
  1000. && (dwStopFlags&AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning)
  1001. return S_OK;
  1002. REFERENCE_TIME 
  1003. rtCurrent = m_rtCurrent,
  1004. rtStop = m_rtStop;
  1005. if(pCurrent)
  1006. switch(dwCurrentFlags&AM_SEEKING_PositioningBitsMask)
  1007. {
  1008. case AM_SEEKING_NoPositioning: break;
  1009. case AM_SEEKING_AbsolutePositioning: rtCurrent = *pCurrent; break;
  1010. case AM_SEEKING_RelativePositioning: rtCurrent = rtCurrent + *pCurrent; break;
  1011. case AM_SEEKING_IncrementalPositioning: rtCurrent = rtCurrent + *pCurrent; break;
  1012. }
  1013. if(pStop)
  1014. switch(dwStopFlags&AM_SEEKING_PositioningBitsMask)
  1015. {
  1016. case AM_SEEKING_NoPositioning: break;
  1017. case AM_SEEKING_AbsolutePositioning: rtStop = *pStop; break;
  1018. case AM_SEEKING_RelativePositioning: rtStop += *pStop; break;
  1019. case AM_SEEKING_IncrementalPositioning: rtStop = rtCurrent + *pStop; break;
  1020. }
  1021. if(m_rtCurrent == rtCurrent && m_rtStop == rtStop)
  1022. return S_OK;
  1023. if(m_rtLastStart == rtCurrent && m_rtLastStop == rtStop && !m_LastSeekers.Find(id))
  1024. {
  1025. m_LastSeekers.AddTail(id);
  1026. return S_OK;
  1027. }
  1028. m_rtLastStart = rtCurrent;
  1029. m_rtLastStop = rtStop;
  1030. m_LastSeekers.RemoveAll();
  1031. m_LastSeekers.AddTail(id);
  1032. DbgLog((LOG_TRACE, 0, _T("Seek Started %I64d"), rtCurrent));
  1033. m_rtNewStart = m_rtCurrent = rtCurrent;
  1034. m_rtNewStop = rtStop;
  1035. if(ThreadExists())
  1036. {
  1037. DeliverBeginFlush();
  1038. CallWorker(CMD_SEEK);
  1039. DeliverEndFlush();
  1040. }
  1041. DbgLog((LOG_TRACE, 0, _T("Seek Ended")));
  1042. return S_OK;
  1043. }
  1044. // IAMOpenProgress
  1045. STDMETHODIMP CBaseSplitterFilter::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent)
  1046. {
  1047. CheckPointer(pllTotal, E_POINTER);
  1048. CheckPointer(pllCurrent, E_POINTER);
  1049. *pllTotal = 100;
  1050. *pllCurrent = m_nOpenProgress;
  1051. return S_OK;
  1052. }
  1053. STDMETHODIMP CBaseSplitterFilter::AbortOperation()
  1054. {
  1055. m_fAbort = true;
  1056. return S_OK;
  1057. }
  1058. // IAMMediaContent
  1059. STDMETHODIMP CBaseSplitterFilter::get_AuthorName(BSTR* pbstrAuthorName)
  1060. {
  1061. return GetProperty(L"AUTH", pbstrAuthorName);
  1062. }
  1063. STDMETHODIMP CBaseSplitterFilter::get_Title(BSTR* pbstrTitle)
  1064. {
  1065. return GetProperty(L"TITL", pbstrTitle);
  1066. }
  1067. STDMETHODIMP CBaseSplitterFilter::get_Rating(BSTR* pbstrRating)
  1068. {
  1069. return GetProperty(L"RTNG", pbstrRating);
  1070. }
  1071. STDMETHODIMP CBaseSplitterFilter::get_Description(BSTR* pbstrDescription)
  1072. {
  1073. return GetProperty(L"DESC", pbstrDescription);
  1074. }
  1075. STDMETHODIMP CBaseSplitterFilter::get_Copyright(BSTR* pbstrCopyright)
  1076. {
  1077. return GetProperty(L"CPYR", pbstrCopyright);
  1078. }
  1079. // IAMExtendedSeeking
  1080. STDMETHODIMP CBaseSplitterFilter::get_ExSeekCapabilities(long* pExCapabilities)
  1081. {
  1082. CheckPointer(pExCapabilities, E_POINTER);
  1083. *pExCapabilities = AM_EXSEEK_CANSEEK;
  1084. if(ChapGetCount()) *pExCapabilities |= AM_EXSEEK_MARKERSEEK;
  1085. return S_OK;
  1086. }
  1087. STDMETHODIMP CBaseSplitterFilter::get_MarkerCount(long* pMarkerCount)
  1088. {
  1089. CheckPointer(pMarkerCount, E_POINTER);
  1090. *pMarkerCount = (long)ChapGetCount();
  1091. return S_OK;
  1092. }
  1093. STDMETHODIMP CBaseSplitterFilter::get_CurrentMarker(long* pCurrentMarker)
  1094. {
  1095. CheckPointer(pCurrentMarker, E_POINTER);
  1096. REFERENCE_TIME rt = m_rtCurrent;
  1097. long i = ChapLookup(&rt);
  1098. if(i < 0) return E_FAIL;
  1099. *pCurrentMarker = i+1;
  1100. return S_OK;
  1101. }
  1102. STDMETHODIMP CBaseSplitterFilter::GetMarkerTime(long MarkerNum, double* pMarkerTime)
  1103. {
  1104. CheckPointer(pMarkerTime, E_POINTER);
  1105. REFERENCE_TIME rt;
  1106. if(FAILED(ChapGet((int)MarkerNum-1, &rt))) return E_FAIL;
  1107. *pMarkerTime = (double)rt / 10000000;
  1108. return S_OK;
  1109. }
  1110. STDMETHODIMP CBaseSplitterFilter::GetMarkerName(long MarkerNum, BSTR* pbstrMarkerName)
  1111. {
  1112. return ChapGet((int)MarkerNum-1, NULL, pbstrMarkerName);
  1113. }
  1114. // IKeyFrameInfo
  1115. STDMETHODIMP CBaseSplitterFilter::GetKeyFrameCount(UINT& nKFs)
  1116. {
  1117. return E_NOTIMPL;
  1118. }
  1119. STDMETHODIMP CBaseSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs)
  1120. {
  1121. return E_NOTIMPL;
  1122. }
  1123. // IBufferInfo
  1124. STDMETHODIMP_(int) CBaseSplitterFilter::GetCount()
  1125. {
  1126. CAutoLock cAutoLock(m_pLock);
  1127. return m_pOutputs.GetCount();
  1128. }
  1129. STDMETHODIMP CBaseSplitterFilter::GetStatus(int i, int& samples, int& size)
  1130. {
  1131. CAutoLock cAutoLock(m_pLock);
  1132. if(POSITION pos = m_pOutputs.FindIndex(i))
  1133. {
  1134. CBaseSplitterOutputPin* pPin = m_pOutputs.GetAt(pos);
  1135. samples = pPin->QueueCount();
  1136. size = pPin->QueueSize();
  1137. return pPin->IsConnected() ? S_OK : S_FALSE;
  1138. }
  1139. return E_INVALIDARG;
  1140. }
  1141. STDMETHODIMP_(DWORD) CBaseSplitterFilter::GetPriority()
  1142. {
  1143.     return m_priority;
  1144. }