PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

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

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