PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/release-1.0.4.1/mkvsplit/mkvsplitfilter.cpp

#
C++ | 1306 lines | 752 code | 374 blank | 180 comment | 145 complexity | c3f55df49642db665e17e5568618bda9 MD5 | raw file
  1. #include <strmif.h>
  2. #include <uuids.h>
  3. #include "mkvsplitfilter.hpp"
  4. #include "cenumpins.hpp"
  5. #include "mkvsplitoutpin.hpp"
  6. #include "mkvparser.hpp"
  7. #include "mkvparserstreamvideo.hpp"
  8. #include "mkvparserstreamaudio.hpp"
  9. #include <new>
  10. #include <cassert>
  11. #include <vfwmsgs.h>
  12. #include <process.h>
  13. #include <evcode.h>
  14. #include <limits>
  15. #ifdef _DEBUG
  16. #include "iidstr.hpp"
  17. #include "odbgstream.hpp"
  18. using std::endl;
  19. using std::hex;
  20. using std::dec;
  21. #endif
  22. using std::wstring;
  23. //using std::wistringstream;
  24. namespace MkvSplit
  25. {
  26. // {ADB85B5C-AA6B-4192-85FC-B0E087E9CA37}
  27. extern const CLSID CLSID_MkvSplit =
  28. { 0xadb85b5c, 0xaa6b, 0x4192, { 0x85, 0xfc, 0xb0, 0xe0, 0x87, 0xe9, 0xca, 0x37 } };
  29. // {4CAB9818-1989-4a5f-8474-2D1F66B420F2}
  30. extern const GUID MEDIASUBTYPE_MKV = //TODO: use std value
  31. { 0x4cab9818, 0x1989, 0x4a5f, { 0x84, 0x74, 0x2d, 0x1f, 0x66, 0xb4, 0x20, 0xf2 } };
  32. const LONGLONG Filter::kNoSeek(std::numeric_limits<LONGLONG>::min());
  33. Filter::Lock::Lock() : m_hMutex(0)
  34. {
  35. }
  36. Filter::Lock::~Lock()
  37. {
  38. Release();
  39. }
  40. HRESULT Filter::Lock::Seize(Filter* pFilter, DWORD timeout)
  41. {
  42. assert(m_hMutex == 0);
  43. assert(pFilter);
  44. DWORD index;
  45. const HRESULT hr = CoWaitForMultipleHandles(
  46. 0, //wait flags
  47. timeout,
  48. 1,
  49. &pFilter->m_hMutex,
  50. &index);
  51. //despite the "S" in this name, this is an error
  52. if (hr == RPC_S_CALLPENDING)
  53. return VFW_E_TIMEOUT;
  54. if (FAILED(hr))
  55. return hr;
  56. assert(index == 0);
  57. m_hMutex = pFilter->m_hMutex;
  58. return S_OK;
  59. }
  60. void Filter::Lock::Release()
  61. {
  62. if (m_hMutex)
  63. {
  64. const BOOL b = ReleaseMutex(m_hMutex);
  65. assert(b);
  66. b;
  67. m_hMutex = 0;
  68. }
  69. }
  70. HRESULT CreateInstance(
  71. IClassFactory* pClassFactory,
  72. IUnknown* pOuter,
  73. const IID& iid,
  74. void** ppv)
  75. {
  76. if (ppv == 0)
  77. return E_POINTER;
  78. *ppv = 0;
  79. if ((pOuter != 0) && (iid != __uuidof(IUnknown)))
  80. return E_INVALIDARG;
  81. Filter* p = new (std::nothrow) Filter(pClassFactory, pOuter);
  82. if (p == 0)
  83. return E_OUTOFMEMORY;
  84. assert(p->m_nondelegating.m_cRef == 0);
  85. const HRESULT hr = p->m_nondelegating.QueryInterface(iid, ppv);
  86. if (SUCCEEDED(hr))
  87. {
  88. assert(*ppv);
  89. assert(p->m_nondelegating.m_cRef == 1);
  90. return S_OK;
  91. }
  92. assert(*ppv == 0);
  93. assert(p->m_nondelegating.m_cRef == 0);
  94. delete p;
  95. p = 0;
  96. return hr;
  97. }
  98. #pragma warning(disable:4355) //'this' ptr in member init list
  99. Filter::Filter(IClassFactory* pClassFactory, IUnknown* pOuter)
  100. : m_pClassFactory(pClassFactory),
  101. m_nondelegating(this),
  102. m_pOuter(pOuter ? pOuter : &m_nondelegating),
  103. m_state(State_Stopped),
  104. m_clock(0),
  105. m_hThread(0),
  106. m_pSegment(0),
  107. m_pSeekBase(0),
  108. m_seekTime(kNoSeek),
  109. m_inpin(this),
  110. m_cStarvation(-1) //means "not starving"
  111. {
  112. m_pClassFactory->LockServer(TRUE);
  113. m_hMutex = CreateMutex(0, 0, 0);
  114. assert(m_hMutex); //TODO
  115. //m_hStop = CreateEvent(0, 0, 0, 0);
  116. //assert(m_hStop); //TODO
  117. m_hNewCluster = CreateEvent(0, 0, 0, 0);
  118. assert(m_hNewCluster); //TODO
  119. m_info.pGraph = 0;
  120. m_info.achName[0] = L'\0';
  121. #ifdef _DEBUG
  122. odbgstream os;
  123. os << "mkvsplit::ctor" << endl;
  124. #endif
  125. }
  126. #pragma warning(default:4355)
  127. Filter::~Filter()
  128. {
  129. #ifdef _DEBUG
  130. odbgstream os;
  131. os << "mkvsplit::dtor" << endl;
  132. #endif
  133. assert(m_hThread == 0);
  134. assert(m_outpins.empty());
  135. //while (!m_outpins.empty())
  136. //{
  137. // Outpin* const pPin = m_outpins.back();
  138. // assert(pPin);
  139. // assert(!bool(pPin->m_pPinConnection));
  140. //
  141. // m_outpins.pop_back();
  142. //
  143. // //delete pPin;
  144. // const ULONG n = pPin->Destroy();
  145. // n;
  146. // assert(n == 0);
  147. //}
  148. //while (!m_dormant.empty())
  149. //{
  150. // Outpin* const pPin = m_dormant.back();
  151. // assert(pPin);
  152. // assert(!bool(pPin->m_pPinConnection));
  153. //
  154. // m_dormant.pop_back();
  155. // delete pPin;
  156. //}
  157. //delete m_pSegment;
  158. assert(m_pSegment == 0);
  159. const BOOL b = CloseHandle(m_hMutex);
  160. b;
  161. assert(b);
  162. //b = CloseHandle(m_hStop);
  163. //assert(b);
  164. m_pClassFactory->LockServer(FALSE);
  165. }
  166. void Filter::Init()
  167. {
  168. assert(m_hThread == 0);
  169. if (!bool(m_inpin.m_pReader))
  170. return;
  171. if (m_pSegment->Unparsed() <= 0)
  172. return; //nothing for thread to do
  173. const uintptr_t h = _beginthreadex(
  174. 0, //security
  175. 0, //stack size
  176. &Filter::ThreadProc,
  177. this,
  178. 0, //run immediately
  179. 0); //thread id
  180. m_hThread = reinterpret_cast<HANDLE>(h);
  181. assert(m_hThread);
  182. }
  183. void Filter::Final()
  184. {
  185. if (m_hThread == 0)
  186. return;
  187. IAsyncReader* const pReader = m_inpin.m_pReader;
  188. pReader;
  189. assert(pReader);
  190. //odbgstream os;
  191. //os << "mkvsplit::Filter::Final(begin)" << endl;
  192. //os << "mkvsplit::Filter::Final: calling BeginFlush" << endl;
  193. //TODO: calling BeginFlush has the exact opposite semantics that
  194. //I thought it did: if flush is in effect, then the SyncRead blocks
  195. //indefinitely, until EndFlush is called. In the local file playback
  196. //case this isn't a problem, since SyncRead will never officially block.
  197. //The problem case occurs when this is a slow network download, and
  198. //SyncRead blocks. I thought that BeginFlush could be used to cancel
  199. //the SyncRead in progress, but that doesn't appear to be the case.
  200. //(Apparently it cancels asyncronous reads, not synchronous reads.)
  201. //This only really matters during the transition to stopped. In that
  202. //case we could do something ugly like timeout the wait for signal
  203. //of thread termination, then if timeout occurs then forcibly
  204. //terminate the thread (but I don't know if that will work either).
  205. //The only other alternative is to use proper timed reads, but
  206. //that requires that reads be aligned.
  207. //HRESULT hr = pReader->BeginFlush();
  208. //assert(SUCCEEDED(hr));
  209. //
  210. //os << "mkvsplit::Filter::Final: called BeginFlush; "
  211. // << "waiting for thread termination"
  212. //<< endl;
  213. const DWORD dw = WaitForSingleObject(m_hThread, INFINITE);
  214. dw;
  215. assert(dw == WAIT_OBJECT_0);
  216. //os << "mkvsplit::Filter::Final: thread terminated" << endl;
  217. const BOOL b = CloseHandle(m_hThread);
  218. b;
  219. assert(b);
  220. m_hThread = 0;
  221. //os << "mkvsplit::Filter::Final: calling EndFlush" << endl;
  222. //hr = pReader->EndFlush();
  223. //assert(SUCCEEDED(hr));
  224. //os << "mkvsplit::Filter::Final: called EndFlush" << endl;
  225. //os << "mkvsplit::Filter::Final(end)" << endl;
  226. }
  227. Filter::CNondelegating::CNondelegating(Filter* p)
  228. : m_pFilter(p),
  229. m_cRef(0) //see CreateInstance
  230. {
  231. }
  232. Filter::CNondelegating::~CNondelegating()
  233. {
  234. }
  235. HRESULT Filter::CNondelegating::QueryInterface(
  236. const IID& iid,
  237. void** ppv)
  238. {
  239. if (ppv == 0)
  240. return E_POINTER;
  241. IUnknown*& pUnk = reinterpret_cast<IUnknown*&>(*ppv);
  242. if (iid == __uuidof(IUnknown))
  243. {
  244. pUnk = this; //must be nondelegating
  245. }
  246. else if ((iid == __uuidof(IBaseFilter)) ||
  247. (iid == __uuidof(IMediaFilter)) ||
  248. (iid == __uuidof(IPersist)))
  249. {
  250. pUnk = static_cast<IBaseFilter*>(m_pFilter);
  251. }
  252. else
  253. {
  254. #if 0
  255. wodbgstream os;
  256. os << "mkvsource::filter::QI: iid=" << IIDStr(iid) << std::endl;
  257. #endif
  258. pUnk = 0;
  259. return E_NOINTERFACE;
  260. }
  261. pUnk->AddRef();
  262. return S_OK;
  263. }
  264. ULONG Filter::CNondelegating::AddRef()
  265. {
  266. return InterlockedIncrement(&m_cRef);
  267. }
  268. ULONG Filter::CNondelegating::Release()
  269. {
  270. const LONG n = InterlockedDecrement(&m_cRef);
  271. //odbgstream os;
  272. //os << "Filter::Release: n=" << n << endl;
  273. if (n > 0)
  274. return n;
  275. delete m_pFilter;
  276. return 0;
  277. }
  278. HRESULT Filter::QueryInterface(const IID& iid, void** ppv)
  279. {
  280. return m_pOuter->QueryInterface(iid, ppv);
  281. }
  282. ULONG Filter::AddRef()
  283. {
  284. return m_pOuter->AddRef();
  285. }
  286. ULONG Filter::Release()
  287. {
  288. return m_pOuter->Release();
  289. }
  290. HRESULT Filter::GetClassID(CLSID* p)
  291. {
  292. if (p == 0)
  293. return E_POINTER;
  294. *p = CLSID_MkvSplit;
  295. return S_OK;
  296. }
  297. HRESULT Filter::Stop()
  298. {
  299. //Stop is a synchronous operation: when it completes,
  300. //the filter is stopped.
  301. //odbgstream os;
  302. Lock lock;
  303. HRESULT hr = lock.Seize(this);
  304. if (FAILED(hr))
  305. return hr;
  306. //odbgstream os;
  307. //os << "mkvsplit::Filter::Stop" << endl;
  308. switch (m_state)
  309. {
  310. case State_Paused:
  311. case State_Running:
  312. //Stop is synchronous. When stop completes, all threads
  313. //should be stopped. What does "stopped" mean" In our
  314. //case it probably means "terminated".
  315. //It's a bit tricky here because we hold the filter
  316. //lock. If threads need to acquire filter lock
  317. //then we'll have to release it. Only the FGM can call
  318. //Stop, etc, so there's no problem to release lock
  319. //while Stop is executing, to allow threads to acquire
  320. //filter lock temporarily.
  321. //The streaming thread will receiving an indication
  322. //automatically (assuming it's connected), either via
  323. //GetBuffer or Receive, so there's nothing this filter
  324. //needs to do to tell the streaming thread to stop.
  325. //One implementation strategy is to have build a
  326. //vector of thread handles, and then wait for a signal
  327. //on one of them. When the handle is signalled
  328. //(meaning that the thread has terminated), then
  329. //we remove that handle from the vector, close the
  330. //handle, and the wait again. Repeat until the
  331. //all threads have been terminated.
  332. //We also need to clean up any unused samples,
  333. //and decommit the allocator. (In fact, we could
  334. //decommit the allocator immediately, and then wait
  335. //for the threads to terminated.)
  336. //os << "mkvsplit::filter::stop: calling Release" << endl;
  337. m_state = State_Stopped;
  338. lock.Release();
  339. //os << "mkvsplit::filter::stop: called Release; calling OnStop" << endl;
  340. OnStop();
  341. //os << "mkvsplit::filter::stop: called OnStop; calling Seize" << endl;
  342. hr = lock.Seize(this);
  343. assert(SUCCEEDED(hr)); //TODO
  344. //os << "mkvsplit::filter::stop: Seize called" << endl;
  345. break;
  346. case State_Stopped:
  347. default:
  348. break;
  349. }
  350. return S_OK;
  351. }
  352. HRESULT Filter::Pause()
  353. {
  354. //Unlike Stop(), Pause() can be asynchronous (that's why you have
  355. //GetState()). We could use that here to build the samples index.
  356. Lock lock;
  357. HRESULT hr = lock.Seize(this);
  358. if (FAILED(hr))
  359. return hr;
  360. //odbgstream os;
  361. //os << "mkvsplit::Filter::Pause" << endl;
  362. switch (m_state)
  363. {
  364. case State_Stopped:
  365. OnStart();
  366. break;
  367. case State_Running:
  368. case State_Paused:
  369. default:
  370. break;
  371. }
  372. m_state = State_Paused;
  373. return S_OK;
  374. }
  375. HRESULT Filter::Run(REFERENCE_TIME start)
  376. {
  377. Lock lock;
  378. HRESULT hr = lock.Seize(this);
  379. if (FAILED(hr))
  380. return hr;
  381. //odbgstream os;
  382. //os << "mkvsplit::Filter::Run" << endl;
  383. switch (m_state)
  384. {
  385. case State_Stopped:
  386. OnStart();
  387. break;
  388. case State_Paused:
  389. case State_Running:
  390. default:
  391. break;
  392. }
  393. m_start = start;
  394. m_state = State_Running;
  395. return S_OK;
  396. }
  397. HRESULT Filter::GetState(
  398. DWORD timeout,
  399. FILTER_STATE* p)
  400. {
  401. if (p == 0)
  402. return E_POINTER;
  403. //What the GetState.timeout parameter refers to is not to locking
  404. //the filter, but rather to waiting to determine the current state.
  405. //A request to Stop is always synchronous (hence no timeout parameter),
  406. //but a request to Pause can be asynchronous, so the caller can say
  407. //how long he's willing to wait for the transition (to paused) to
  408. //complete.
  409. //TODO: implement a waiting scheme here. We'll probably have to
  410. //use SignalObjectAndWait atomically release the mutex and then
  411. //wait for the condition variable to change.
  412. //if (hr == VFW_E_TIMEOUT)
  413. // return VFW_S_STATE_INTERMEDIATE;
  414. Lock lock;
  415. HRESULT hrLock = lock.Seize(this);
  416. //The lock is only used for synchronization. If Seize fails,
  417. //it means there's a serious problem with the filter.
  418. if (FAILED(hrLock))
  419. return E_FAIL;
  420. FILTER_STATE& state = *p;
  421. //odbgstream os;
  422. if (m_cStarvation < 0) //not starving
  423. {
  424. //os << "\nmkvsplit::Filter::GetState: NOT STARVING\n" << endl;
  425. state = m_state;
  426. return S_OK;
  427. }
  428. long count = m_pSegment->GetCount();
  429. if (count > m_cStarvation)
  430. {
  431. //os << "\nmkvsplit::Filter::GetState: cStarvation=" << m_cStarvation
  432. // << " clusters.count=" << count
  433. // << "; EXITING STARVATION MODE\n"
  434. // << endl;
  435. m_cStarvation = -1;
  436. state = m_state; //TODO: should be State_Paused?
  437. return S_OK;
  438. }
  439. for (;;)
  440. {
  441. //os << "\nmkvsplit::Filter::GetState: cStarvation=" << m_cStarvation
  442. // << " clusters.count=" << count
  443. // << " timeout=" << timeout
  444. // << "; WAITING FOR SIGNAL\n"
  445. // << endl;
  446. lock.Release();
  447. DWORD index;
  448. //TODO: this timeout isn't quite correct. The parameter refers
  449. //to the total wait time. As used here in the call to WaitForHandles,
  450. //it refers to the wait time for this pass through the loop.
  451. const HRESULT hrWait = CoWaitForMultipleHandles(
  452. 0, //wait flags
  453. timeout,
  454. 1,
  455. &m_hNewCluster,
  456. &index);
  457. if (SUCCEEDED(hrWait))
  458. assert(index == 0);
  459. else if (hrWait != RPC_S_CALLPENDING) //despite the "S" in this name, this is an error
  460. return hrWait;
  461. hrLock = lock.Seize(this);
  462. if (FAILED(hrLock))
  463. return E_FAIL;
  464. count = m_pSegment->GetCount();
  465. if (count > m_cStarvation)
  466. {
  467. //os << "\nmkvsplit::Filter::GetState(cont'd): cStarvation=" << m_cStarvation
  468. // << " clusters.count=" << count
  469. // << "; EXITING STARVATION MODE\n"
  470. // << endl;
  471. m_cStarvation = -1;
  472. state = m_state; //TODO: should be State_Paused?
  473. return S_OK;
  474. }
  475. if (FAILED(hrWait)) //there was a timeout before receiving signal
  476. {
  477. //os << "\nmkvsplit::Filter::GetState(cont'd): cStarvation=" << m_cStarvation
  478. // << " clusters.count=" << count
  479. // << "; INTERMEDIATE FILTER STATE\n"
  480. // << endl;
  481. return VFW_S_STATE_INTERMEDIATE;
  482. }
  483. }
  484. }
  485. HRESULT Filter::SetSyncSource(
  486. IReferenceClock* clock)
  487. {
  488. Lock lock;
  489. HRESULT hr = lock.Seize(this);
  490. if (FAILED(hr))
  491. return hr;
  492. if (m_clock)
  493. m_clock->Release();
  494. m_clock = clock;
  495. if (m_clock)
  496. m_clock->AddRef();
  497. return S_OK;
  498. }
  499. HRESULT Filter::GetSyncSource(
  500. IReferenceClock** pclock)
  501. {
  502. if (pclock == 0)
  503. return E_POINTER;
  504. Lock lock;
  505. HRESULT hr = lock.Seize(this);
  506. if (FAILED(hr))
  507. return hr;
  508. IReferenceClock*& clock = *pclock;
  509. clock = m_clock;
  510. if (clock)
  511. clock->AddRef();
  512. return S_OK;
  513. }
  514. HRESULT Filter::EnumPins(IEnumPins** pp)
  515. {
  516. Lock lock;
  517. HRESULT hr = lock.Seize(this);
  518. if (FAILED(hr))
  519. return hr;
  520. const ULONG outpins_count = static_cast<ULONG>(m_outpins.size());
  521. const ULONG n = 1 + outpins_count;
  522. //odbgstream os;
  523. //os << "mkvsplit::filter::enumpins: n=" << n << endl;
  524. const size_t cb = n * sizeof(IPin*);
  525. IPin** const pins = (IPin**)_alloca(cb);
  526. IPin** pin = pins;
  527. *pin++ = &m_inpin;
  528. typedef outpins_t::iterator iter_t;
  529. iter_t i = m_outpins.begin();
  530. const iter_t j = m_outpins.end();
  531. while (i != j)
  532. *pin++ = *i++;
  533. return CEnumPins::CreateInstance(pins, n, pp);
  534. }
  535. HRESULT Filter::FindPin(
  536. LPCWSTR id1,
  537. IPin** pp)
  538. {
  539. if (pp == 0)
  540. return E_POINTER;
  541. IPin*& p = *pp;
  542. p = 0;
  543. if (id1 == 0)
  544. return E_INVALIDARG;
  545. {
  546. Pin* const pPin = &m_inpin;
  547. const wstring& id2_ = pPin->m_id;
  548. const wchar_t* const id2 = id2_.c_str();
  549. if (wcscmp(id1, id2) == 0) //case-sensitive
  550. {
  551. p = pPin;
  552. p->AddRef();
  553. return S_OK;
  554. }
  555. }
  556. typedef outpins_t::const_iterator iter_t;
  557. iter_t i = m_outpins.begin();
  558. const iter_t j = m_outpins.end();
  559. while (i != j)
  560. {
  561. Pin* const pPin = *i++;
  562. const wstring& id2_ = pPin->m_id;
  563. const wchar_t* const id2 = id2_.c_str();
  564. if (wcscmp(id1, id2) == 0) //case-sensitive
  565. {
  566. p = pPin;
  567. p->AddRef();
  568. return S_OK;
  569. }
  570. }
  571. return VFW_E_NOT_FOUND;
  572. }
  573. HRESULT Filter::QueryFilterInfo(FILTER_INFO* p)
  574. {
  575. if (p == 0)
  576. return E_POINTER;
  577. Lock lock;
  578. HRESULT hr = lock.Seize(this);
  579. if (FAILED(hr))
  580. return hr;
  581. enum { size = sizeof(p->achName)/sizeof(WCHAR) };
  582. const errno_t e = wcscpy_s(p->achName, size, m_info.achName);
  583. e;
  584. assert(e == 0);
  585. p->pGraph = m_info.pGraph;
  586. if (p->pGraph)
  587. p->pGraph->AddRef();
  588. return S_OK;
  589. }
  590. HRESULT Filter::JoinFilterGraph(
  591. IFilterGraph *pGraph,
  592. LPCWSTR name)
  593. {
  594. Lock lock;
  595. HRESULT hr = lock.Seize(this);
  596. if (FAILED(hr))
  597. return hr;
  598. //NOTE:
  599. //No, do not adjust reference counts here!
  600. //Read the docs for the reasons why.
  601. //ENDNOTE.
  602. m_info.pGraph = pGraph;
  603. if (name == 0)
  604. m_info.achName[0] = L'\0';
  605. else
  606. {
  607. enum { size = sizeof(m_info.achName)/sizeof(WCHAR) };
  608. const errno_t e = wcscpy_s(m_info.achName, size, name);
  609. e;
  610. assert(e == 0); //TODO
  611. }
  612. return S_OK;
  613. }
  614. HRESULT Filter::QueryVendorInfo(LPWSTR* pstr)
  615. {
  616. if (pstr == 0)
  617. return E_POINTER;
  618. wchar_t*& str = *pstr;
  619. str = 0;
  620. return E_NOTIMPL;
  621. }
  622. HRESULT Filter::Open(IAsyncReader* pReader)
  623. {
  624. if (m_pSegment)
  625. return VFW_E_WRONG_STATE;
  626. assert(pReader);
  627. assert(m_outpins.empty());
  628. __int64 result, pos;
  629. //TODO: must initialize header to defaults
  630. MkvParser::EBMLHeader h;
  631. result = h.Parse(pReader, pos);
  632. if (result < 0) //error
  633. return static_cast<HRESULT>(result);
  634. if (result > 0) //need more data
  635. return VFW_E_BUFFER_UNDERFLOW; //require full header
  636. if (h.m_version > 1)
  637. return VFW_E_INVALID_FILE_FORMAT;
  638. if (h.m_maxIdLength > 8)
  639. return VFW_E_INVALID_FILE_FORMAT;
  640. if (h.m_maxSizeLength > 8)
  641. return VFW_E_INVALID_FILE_FORMAT;
  642. if (_stricmp(h.m_docType.c_str(), "matroska") != 0)
  643. return VFW_E_INVALID_FILE_FORMAT;
  644. //Just the EBML header has been consumed. pos points
  645. //to start of (first) segment.
  646. MkvParser::Segment* p;
  647. result = MkvParser::Segment::CreateInstance(pReader, pos, p);
  648. if (result < 0)
  649. return static_cast<HRESULT>(result);
  650. if (result > 0)
  651. return VFW_E_BUFFER_UNDERFLOW;
  652. assert(p);
  653. std::auto_ptr<MkvParser::Segment> pSegment(p);
  654. result = pSegment->ParseHeaders();
  655. if (result < 0)
  656. return static_cast<HRESULT>(result);
  657. if (result > 0)
  658. return VFW_E_BUFFER_UNDERFLOW;
  659. const MkvParser::Tracks* const pTracks = pSegment->GetTracks();
  660. if (pTracks == 0)
  661. return VFW_E_INVALID_FILE_FORMAT;
  662. const MkvParser::SegmentInfo* const pInfo = pSegment->GetInfo();
  663. if (pInfo == 0)
  664. return VFW_E_INVALID_FILE_FORMAT; //TODO: liberalize
  665. using MkvParser::VideoTrack;
  666. using MkvParser::VideoStream;
  667. using MkvParser::AudioTrack;
  668. using MkvParser::AudioStream;
  669. using MkvParser::Stream;
  670. typedef Stream::TCreateOutpins<VideoTrack, VideoStream, Filter> EV;
  671. typedef Stream::TCreateOutpins<AudioTrack, AudioStream, Filter> EA;
  672. const EV ev(this, &VideoStream::CreateInstance);
  673. pTracks->EnumerateVideoTracks(ev);
  674. const EA ea(this, &AudioStream::CreateInstance);
  675. pTracks->EnumerateAudioTracks(ea);
  676. if (m_outpins.empty())
  677. return VFW_E_INVALID_FILE_FORMAT; //TODO: better return value here?
  678. //ALLOCATOR_PROPERTIES props;
  679. //props.cbBuffer = GetMaxBufferSize();
  680. //props.cbAlign = 1;
  681. //props.cbPrefix = 0;
  682. //props.cBuffers = 1;
  683. //HRESULT hr = pReader->RequestAllocator(0, &props, &m_pAllocator);
  684. //assert(SUCCEEDED(hr)); //TODO
  685. //assert(bool(m_pAllocator));
  686. m_pSegment = pSegment.release();
  687. m_pSeekBase = 0;
  688. m_seekTime = kNoSeek;
  689. return S_OK;
  690. }
  691. void Filter::CreateOutpin(MkvParser::Stream* s)
  692. {
  693. //Outpin* const p = new (std::nothrow) Outpin(this, s);
  694. Outpin* const p = Outpin::Create(this, s);
  695. m_outpins.push_back(p);
  696. }
  697. void Filter::OnStart()
  698. {
  699. //TODO: init inpin
  700. typedef outpins_t::iterator iter_t;
  701. iter_t i = m_outpins.begin();
  702. const iter_t j = m_outpins.end();
  703. int n = 0;
  704. while (i != j)
  705. {
  706. Outpin* const pPin = *i++;
  707. assert(pPin);
  708. const HRESULT hr = pPin->Start();
  709. assert(SUCCEEDED(hr));
  710. if (hr == S_OK)
  711. ++n;
  712. }
  713. if (n)
  714. m_cStarvation = 0; //temporarily enter starvation mode to force check
  715. Init();
  716. }
  717. void Filter::OnStop()
  718. {
  719. Final();
  720. typedef outpins_t::iterator iter_t;
  721. iter_t i = m_outpins.begin();
  722. const iter_t j = m_outpins.end();
  723. while (i != j)
  724. {
  725. Outpin* const pPin = *i++;
  726. assert(pPin);
  727. pPin->Stop();
  728. }
  729. //TODO: final inpin
  730. }
  731. int Filter::GetConnectionCount() const
  732. {
  733. //filter already locked by caller
  734. int n = 0;
  735. typedef outpins_t::const_iterator iter_t;
  736. iter_t i = m_outpins.begin();
  737. const iter_t j = m_outpins.end();
  738. while (i != j)
  739. {
  740. const Outpin* const pin = *i++;
  741. assert(pin);
  742. if (pin->m_pPinConnection)
  743. ++n;
  744. }
  745. return n;
  746. }
  747. unsigned Filter::ThreadProc(void* pv)
  748. {
  749. Filter* const pFilter = static_cast<Filter*>(pv);
  750. assert(pFilter);
  751. return pFilter->Main();
  752. }
  753. #if 1
  754. unsigned Filter::Main()
  755. {
  756. assert(m_pSegment);
  757. const __int64 stop = m_pSegment->m_start + m_pSegment->m_size;
  758. stop;
  759. //odbgstream os;
  760. //os << "mkvsplit::filter::main: thread running" << endl;
  761. for (;;)
  762. {
  763. Sleep(0);
  764. MkvParser::Cluster* pCluster;
  765. __int64 pos;
  766. HRESULT hr = m_pSegment->ParseCluster(pCluster, pos);
  767. assert(SUCCEEDED(hr)); //TODO
  768. assert((hr != S_OK) || (pCluster != 0));
  769. //os << "mkvsplit::filter::main: cluster=0x" << (void*)pCluster
  770. // << " pos=" << pos
  771. // << "/" << stop
  772. // << " hr=0x" << hex << hr << dec
  773. // << endl;
  774. if (FAILED(hr)) //TODO: how to handle outpin streaming threads?
  775. return 1;
  776. Lock lock;
  777. hr = lock.Seize(this);
  778. assert(SUCCEEDED(hr)); //TODO
  779. if (FAILED(hr))
  780. return 1; //TODO: pCluster != 0 => memory leak
  781. const bool bDone = m_pSegment->AddCluster(pCluster, pos);
  782. //os << "mkvsplit::filter::main: AddCluster; newcount="
  783. // << m_pSegment->GetCount()
  784. // << endl;
  785. OnNewCluster();
  786. if (bDone)
  787. {
  788. //os << "mkvsplit::filter::main: AddCluster returned Done; EXITING" << endl;
  789. return 0;
  790. }
  791. if (m_state == State_Stopped)
  792. {
  793. //os << "mkvsplit::filter::main: state=Stopped; EXITING" << endl;
  794. return 0;
  795. }
  796. }
  797. }
  798. void Filter::OnNewCluster()
  799. {
  800. const BOOL b = SetEvent(m_hNewCluster); //see Filter::GetState
  801. b;
  802. assert(b);
  803. typedef outpins_t::iterator iter_t;
  804. iter_t i = m_outpins.begin();
  805. const iter_t j = m_outpins.end();
  806. while (i != j)
  807. {
  808. Outpin* const outpin = *i++;
  809. assert(outpin);
  810. outpin->OnNewCluster();
  811. }
  812. }
  813. #else
  814. unsigned Filter::Main()
  815. {
  816. std::vector<HANDLE> v;
  817. v.reserve(1 + m_outpins.size());
  818. v.push_back(m_hStop);
  819. typedef outpins_t::iterator iter_t;
  820. iter_t i = m_outpins.begin();
  821. const iter_t j = m_outpins.end();
  822. while (i != j)
  823. {
  824. Outpin* const pPin = *i++;
  825. assert(pPin);
  826. const HANDLE h = pPin->m_hSampleCanBePopulated;
  827. assert(h);
  828. v.push_back(h);
  829. }
  830. const HANDLE* const hh = &v[0];
  831. const DWORD n = static_cast<DWORD>(v.size());
  832. const DWORD dwTimeout = INFINITE;
  833. for (;;)
  834. {
  835. const DWORD dw = WaitForMultipleObjects(n, hh, 0, dwTimeout);
  836. #if 0
  837. if (dw == WAIT_TIMEOUT)
  838. {
  839. Lock lock;
  840. const HRESULT hr = lock.Seize(this);
  841. assert(SUCCEEDED(hr));
  842. const __int64 result = m_pSegment->Parse();
  843. assert(result == 0);
  844. if (m_pSegment->Unparsed() <= 0)
  845. dwTimeout = INFINITE;
  846. continue;
  847. }
  848. #endif
  849. assert(dw >= WAIT_OBJECT_0);
  850. assert(dw < (WAIT_OBJECT_0 + n));
  851. if (dw == WAIT_OBJECT_0) //hStop
  852. return 0;
  853. const DWORD idx = dw - (WAIT_OBJECT_0 + 1);
  854. assert(idx < m_outpins.size());
  855. PopulateSamples(hh + 1, idx);
  856. }
  857. }
  858. void Filter::PopulateSamples(const HANDLE* hh_begin, DWORD idx)
  859. {
  860. //idx represents the pin that just signalled
  861. for (;;)
  862. {
  863. Outpin* const pPin = m_outpins[idx];
  864. assert(pPin);
  865. pPin->PopulateSample();
  866. if (++idx >= m_outpins.size())
  867. return;
  868. const HANDLE* const hh = hh_begin + idx;
  869. const DWORD n = static_cast<DWORD>(m_outpins.size()) - idx;
  870. const DWORD dw = WaitForMultipleObjects(n, hh, 0, 0);
  871. if (dw == WAIT_TIMEOUT)
  872. return;
  873. assert(dw >= WAIT_OBJECT_0);
  874. assert(dw < (WAIT_OBJECT_0 + n));
  875. idx += dw - WAIT_OBJECT_0;
  876. }
  877. }
  878. #endif
  879. HRESULT Filter::OnDisconnectInpin()
  880. {
  881. assert(m_hThread == 0);
  882. //wodbgstream os;
  883. //os << "MkvSplit::Filter::OnDisconnectInpin(begin)" << endl;
  884. while (!m_outpins.empty())
  885. {
  886. Outpin* const pPin = m_outpins.back();
  887. assert(pPin);
  888. if (IPin* pPinConnection = pPin->m_pPinConnection)
  889. {
  890. assert(m_info.pGraph);
  891. HRESULT hr = m_info.pGraph->Disconnect(pPinConnection);
  892. assert(SUCCEEDED(hr));
  893. hr = m_info.pGraph->Disconnect(pPin);
  894. assert(SUCCEEDED(hr));
  895. }
  896. m_outpins.pop_back();
  897. //os << "MkvSplit::Filter::OnDisconnectInpin(cont'd): destroying outpin["
  898. // << pPin->m_id
  899. // << "]"
  900. // << endl;
  901. const ULONG n = pPin->Destroy();
  902. n;
  903. //os << "MkvSplit::Filter::OnDisconnectInpin(cont'd): destroyed outpin"
  904. // << "; n=" << n
  905. // << endl;
  906. }
  907. m_seekTime = kNoSeek;
  908. m_pSeekBase = 0;
  909. delete m_pSegment;
  910. m_pSegment = 0;
  911. //os << "MkvSplit::Filter::OnDisconnectInpin(end)" << endl;
  912. return S_OK;
  913. }
  914. void Filter::OnStarvation(ULONG count)
  915. {
  916. #ifdef _DEBUG
  917. odbgstream os;
  918. os << "mkvsplit::Filter::OnStarvation: count=" << count
  919. << " m_cStarvation=" << m_cStarvation
  920. << endl;
  921. #endif
  922. if (m_cStarvation < 0)
  923. {
  924. const GraphUtil::IMediaEventSinkPtr pSink(m_info.pGraph);
  925. assert(bool(pSink));
  926. const HRESULT hr = pSink->Notify(EC_STARVATION, 0, 0);
  927. hr;
  928. assert(SUCCEEDED(hr));
  929. m_cStarvation = count;
  930. }
  931. }
  932. } //end namespace MkvSplit