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

多媒体编程

开发平台:

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 "OggSplitter.h"
  23. #include "......DSUtilDSUtil.h"
  24. #include <initguid.h>
  25. #include "........includeoggOggDS.h"
  26. #include "........includemoreuuids.h"
  27. #ifdef REGISTER_FILTER
  28. const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
  29. {
  30. {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL},
  31. };
  32. const AMOVIESETUP_PIN sudpPins[] =
  33. {
  34.     {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
  35.     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, 0, NULL}
  36. };
  37. const AMOVIESETUP_FILTER sudFilter[] =
  38. {
  39. {&__uuidof(COggSplitterFilter), L"Ogg Splitter", MERIT_NORMAL+1, countof(sudpPins), sudpPins},
  40. {&__uuidof(COggSourceFilter), L"Ogg Source", MERIT_NORMAL+1, 0, NULL},
  41. };
  42. CFactoryTemplate g_Templates[] =
  43. {
  44. {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<COggSplitterFilter>, NULL, &sudFilter[0]},
  45. {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance<COggSourceFilter>, NULL, &sudFilter[1]},
  46. };
  47. int g_cTemplates = countof(g_Templates);
  48. STDAPI DllRegisterServer()
  49. {
  50. RegisterSourceFilter(
  51. CLSID_AsyncReader, 
  52. MEDIASUBTYPE_Ogg, 
  53. _T("0,4,,4F676753"), // OggS
  54. _T(".ogg"), _T(".ogm"), NULL);
  55. return AMovieDllRegisterServer2(TRUE);
  56. }
  57. STDAPI DllUnregisterServer()
  58. {
  59. UnRegisterSourceFilter(MEDIASUBTYPE_Ogg);
  60. return AMovieDllRegisterServer2(FALSE);
  61. }
  62. extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
  63. BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
  64. {
  65.     return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
  66. }
  67. #endif
  68. //
  69. // bitstream
  70. //
  71. class bitstream
  72. {
  73. BYTE* m_p;
  74. int m_len, m_pos;
  75. public:
  76. bitstream(BYTE* p, int len, bool rev = false) : m_p(p), m_len(len*8) {m_pos = !rev ? 0 : len*8;}
  77. bool hasbits(int cnt)
  78. {
  79. int pos = m_pos+cnt;
  80. return(pos >= 0 && pos < m_len);
  81. }
  82. unsigned int showbits(int cnt) // a bit unclean, but works and can read backwards too! :P
  83. {
  84. if(!hasbits(cnt)) {ASSERT(0); return 0;}
  85. unsigned int ret = 0, off = 0;
  86. BYTE* p = m_p;
  87. if(cnt < 0)
  88. {
  89. p += (m_pos+cnt)>>3;
  90. off = (m_pos+cnt)&7;
  91. cnt = abs(cnt);
  92. ret = (*p++&(~0<<off))>>off; off = 8 - off; cnt -= off;
  93. }
  94. else
  95. {
  96. p += m_pos>>3;
  97. off = m_pos&7;
  98. ret = (*p++>>off)&((1<<min(cnt,8))-1); off = 0; cnt -= 8 - off;
  99. }
  100. while(cnt > 0) {ret |= (*p++&((1<<min(cnt,8))-1)) << off; off += 8; cnt -= 8;}
  101. return ret;
  102. }
  103. unsigned int getbits(int cnt)
  104. {
  105. unsigned int ret = showbits(cnt);
  106. m_pos += cnt;
  107. return ret;
  108. }
  109. };
  110. //
  111. // COggSplitterFilter
  112. //
  113. COggSplitterFilter::COggSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr)
  114. : CBaseSplitterFilter(NAME("COggSplitterFilter"), pUnk, phr, __uuidof(this))
  115. {
  116. }
  117. COggSplitterFilter::~COggSplitterFilter()
  118. {
  119. }
  120. HRESULT COggSplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader)
  121. {
  122. CheckPointer(pAsyncReader, E_POINTER);
  123. HRESULT hr = E_FAIL;
  124. m_pFile.Free();
  125. m_pFile.Attach(new COggFile(pAsyncReader, hr));
  126. if(!m_pFile) return E_OUTOFMEMORY;
  127. if(FAILED(hr)) {m_pFile.Free(); return hr;}
  128. m_rtNewStart = m_rtCurrent = 0;
  129. m_rtNewStop = m_rtStop = 0;
  130. m_rtDuration = 0;
  131. m_pFile->Seek(0);
  132. OggPage page;
  133. for(int i = 0, nWaitForMore = 0; m_pFile->Read(page); i++)
  134. {
  135. BYTE* p = page.GetData();
  136. if(!(page.m_hdr.header_type_flag & OggPageHeader::continued))
  137. {
  138. BYTE type = *p++;
  139. if(!(type&1) && nWaitForMore == 0)
  140. break;
  141. CStringW name;
  142. name.Format(L"Stream %d", i);
  143. HRESULT hr;
  144. if(type == 1 && (page.m_hdr.header_type_flag & OggPageHeader::first))
  145. {
  146. CAutoPtr<CBaseSplitterOutputPin> pPinOut;
  147. if(!memcmp(p, "vorbis", 6))
  148. {
  149. name.Format(L"Vorbis %d", i);
  150. pPinOut.Attach(new COggVorbisOutputPin((OggVorbisIdHeader*)(p+6), name, this, this, &hr));
  151. nWaitForMore++;
  152. }
  153. else if(!memcmp(p, "video", 5))
  154. {
  155. name.Format(L"Video %d", i);
  156. pPinOut.Attach(new COggVideoOutputPin((OggStreamHeader*)p, name, this, this, &hr));
  157. }
  158. else if(!memcmp(p, "audio", 5))
  159. {
  160. name.Format(L"Audio %d", i);
  161. pPinOut.Attach(new COggAudioOutputPin((OggStreamHeader*)p, name, this, this, &hr));
  162. }
  163. else if(!memcmp(p, "text", 4))
  164. {
  165. name.Format(L"Text %d", i);
  166. pPinOut.Attach(new COggTextOutputPin((OggStreamHeader*)p, name, this, this, &hr));
  167. }
  168. else if(!memcmp(p, "Direct Show Samples embedded in Ogg", 35))
  169. {
  170. name.Format(L"DirectShow %d", i);
  171. pPinOut.Attach(new COggDirectShowOutputPin((AM_MEDIA_TYPE*)(p+35+sizeof(GUID)), name, this, this, &hr));
  172. }
  173. AddOutputPin(page.m_hdr.bitstream_serial_number, pPinOut);
  174. }
  175. if(type == 3 && !memcmp(p, "vorbis", 6))
  176. {
  177. if(COggSplitterOutputPin* pOggPin = 
  178. dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number)))
  179. {
  180. pOggPin->AddComment(p+6, page.GetSize()-6-1);
  181. }
  182. }
  183. }
  184. if(COggVorbisOutputPin* pOggVorbisPin = 
  185. dynamic_cast<COggVorbisOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number)))
  186. {
  187. pOggVorbisPin->UnpackInitPage(page);
  188. if(pOggVorbisPin->IsInitialized()) nWaitForMore--;
  189. }
  190. }
  191. if(m_pOutputs.IsEmpty())
  192. return E_FAIL;
  193. m_pFile->Seek(max(m_pFile->GetLength()-65536, 0));
  194. while(m_pFile->Read(page))
  195. {
  196. COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number));
  197. if(!pOggPin) {ASSERT(0); continue;}
  198. if(page.m_hdr.granule_position == -1) continue;
  199. REFERENCE_TIME rt = pOggPin->GetRefTime(page.m_hdr.granule_position);
  200. m_rtDuration = max(rt, m_rtDuration);
  201. }
  202. m_rtNewStart = m_rtCurrent = 0;
  203. m_rtNewStop = m_rtStop = m_rtDuration;
  204. // comments
  205. {
  206. CAtlMap<CStringW, CStringW, CStringElementTraits<CStringW> > tagmap;
  207. tagmap[L"TITLE"] = L"TITL";
  208. tagmap[L"ARTIST"] = L"AUTH"; // not quite
  209. tagmap[L"COPYRIGHT"] = L"CPYR";
  210. tagmap[L"DESCRIPTION"] = L"DESC";
  211. POSITION pos2 = tagmap.GetStartPosition();
  212. while(pos2)
  213. {
  214. CStringW oggtag, dsmtag;
  215. tagmap.GetNextAssoc(pos2, oggtag, dsmtag);
  216. POSITION pos = m_pOutputs.GetHeadPosition();
  217. while(pos)
  218. {
  219. COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>((CBaseOutputPin*)m_pOutputs.GetNext(pos));
  220. if(!pOggPin) continue;
  221. CStringW value = pOggPin->GetComment(oggtag);
  222. if(!value.IsEmpty())
  223. {
  224. SetProperty(dsmtag, value);
  225. break;
  226. }
  227. }
  228. }
  229. POSITION pos = m_pOutputs.GetHeadPosition();
  230. while(pos && !ChapGetCount())
  231. {
  232. COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>((CBaseOutputPin*)m_pOutputs.GetNext(pos));
  233. if(!pOggPin) continue;
  234. for(int i = 1; pOggPin; i++)
  235. {
  236. CStringW key; 
  237. key.Format(L"CHAPTER%02d", i);
  238. CStringW time = pOggPin->GetComment(key);
  239. if(time.IsEmpty()) break;
  240. key.Format(L"CHAPTER%02dNAME", i);
  241. CStringW name = pOggPin->GetComment(key);
  242. if(name.IsEmpty()) name.Format(L"Chapter %d", i);
  243. int h, m, s, ms;
  244. WCHAR c;
  245. if(7 != swscanf(time, L"%d%c%d%c%d%c%d", &h, &c, &m, &c, &s, &c, &ms)) break;
  246. REFERENCE_TIME rt = ((((REFERENCE_TIME)h*60+m)*60+s)*1000+ms)*10000;
  247. ChapAppend(rt, name);
  248. }
  249. }
  250. }
  251. return m_pOutputs.GetCount() > 0 ? S_OK : E_FAIL;
  252. }
  253. bool COggSplitterFilter::DemuxInit()
  254. {
  255. if(!m_pFile) return(false);
  256. return(true);
  257. }
  258. void COggSplitterFilter::DemuxSeek(REFERENCE_TIME rt)
  259. {
  260. if(rt <= 0)
  261. {
  262. m_pFile->Seek(0);
  263. }
  264. else if(m_rtDuration > 0)
  265. {
  266. // oh, the horror...
  267. clock_t t1 = clock();
  268. __int64 len = m_pFile->GetLength();
  269. __int64 startpos = len * rt/m_rtDuration;
  270. __int64 diff = 0;
  271. REFERENCE_TIME rtMinDiff = _I64_MAX;
  272. while(1)
  273. {
  274. __int64 endpos = startpos;
  275. REFERENCE_TIME rtPos = -1;
  276. OggPage page;
  277. m_pFile->Seek(startpos);
  278. while(m_pFile->Read(page, false))
  279. {
  280. if(page.m_hdr.granule_position == -1) continue;
  281. COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number));
  282. if(!pOggPin) {ASSERT(0); continue;}
  283. rtPos = pOggPin->GetRefTime(page.m_hdr.granule_position);
  284. endpos = m_pFile->GetPos();
  285. break;
  286. }
  287. __int64 rtDiff = rtPos - rt;
  288. if(rtDiff < 0)
  289. {
  290. rtDiff = -rtDiff;
  291. if(rtDiff < 1000000 || rtDiff >= rtMinDiff)
  292. {
  293. m_pFile->Seek(startpos);
  294. break;
  295. }
  296. rtMinDiff = rtDiff;
  297. }
  298. __int64 newpos = startpos;
  299. if(rtPos < rt && rtPos < m_rtDuration)
  300. {
  301. newpos = startpos + (__int64)((1.0*(rt - rtPos)/(m_rtDuration - rtPos)) * (len - startpos)) + 1024;
  302.             if(newpos < endpos) newpos = endpos + 1024;
  303. }
  304. else if(rtPos > rt && rtPos > 0)
  305. {
  306. newpos = startpos - (__int64)((1.0*(rtPos - rt)/(rtPos - 0)) * (startpos - 0)) - 1024;
  307.             if(newpos >= startpos) newpos = startpos - 1024;
  308. }
  309. else if(rtPos == rt)
  310. {
  311. m_pFile->Seek(startpos);
  312. break;
  313. }
  314. else
  315. {
  316. ASSERT(0);
  317. m_pFile->Seek(0);
  318. break;
  319. }
  320. diff = newpos - startpos;
  321. startpos = max(min(newpos, len), 0);
  322. }
  323. TRACE(_T("****** t1: %dn"), clock() - t1);
  324. t1 = clock();
  325. m_pFile->Seek(startpos);
  326. POSITION pos = m_pOutputs.GetHeadPosition();
  327. while(pos)
  328. {
  329. CBaseSplitterOutputPin* pPin = m_pOutputs.GetNext(pos);
  330. COggVideoOutputPin* pOggVideoPin = dynamic_cast<COggVideoOutputPin*>(pPin);
  331. if(!pOggVideoPin) continue;
  332. bool fKeyFrameFound = false, fSkipKeyFrame = true;
  333. __int64 endpos = _I64_MAX;
  334. while(!(fKeyFrameFound && !fSkipKeyFrame) && startpos > 0)
  335. {
  336. OggPage page;
  337. while(!(fKeyFrameFound && !fSkipKeyFrame) && m_pFile->GetPos() < endpos && m_pFile->Read(page))
  338. {
  339. if(page.m_hdr.granule_position == -1) continue;
  340. COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number));
  341. if(pOggPin != pOggVideoPin) continue;
  342. REFERENCE_TIME rtPos = pOggPin->GetRefTime(page.m_hdr.granule_position);
  343. if(rtPos > rt)
  344. break;
  345. if(!fKeyFrameFound)
  346. {
  347. pOggPin->UnpackPage(page);
  348. CAutoPtr<OggPacket> p;
  349. while(p = pOggPin->GetPacket())
  350. {
  351. if(p->bSyncPoint)
  352. {
  353. fKeyFrameFound = true;
  354. fSkipKeyFrame = p->fSkip;
  355. }
  356. }
  357. if(fKeyFrameFound) break;
  358. }
  359. else
  360. {
  361. pOggPin->UnpackPage(page);
  362. CAutoPtr<OggPacket> p;
  363. while(p = pOggPin->GetPacket())
  364. {
  365. if(!p->fSkip)
  366. {
  367. fSkipKeyFrame = false;
  368. break;
  369. }
  370. }
  371. }
  372. }
  373. if(!(fKeyFrameFound && !fSkipKeyFrame)) {endpos = startpos; startpos = max(startpos - 10*65536, 0);}
  374. m_pFile->Seek(startpos);
  375. }
  376. TRACE(_T("****** t2: %dn"), clock() - t1);
  377. t1 = clock();
  378. #ifdef DEBUG
  379. // verify kf
  380. {
  381. fKeyFrameFound = false;
  382. OggPage page;
  383. while(!fKeyFrameFound && m_pFile->Read(page))
  384. {
  385. if(page.m_hdr.granule_position == -1) continue;
  386. COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number));
  387. if(pOggPin != pOggVideoPin) continue;
  388. REFERENCE_TIME rtPos = pOggPin->GetRefTime(page.m_hdr.granule_position);
  389. if(rtPos > rt)
  390. break;
  391. pOggPin->UnpackPage(page);
  392. CAutoPtr<OggPacket> p;
  393. while(p = pOggPin->GetPacket())
  394. {
  395. if(p->bSyncPoint)
  396. {
  397. fKeyFrameFound = true;
  398. break;
  399. }
  400. }
  401. }
  402. ASSERT(fKeyFrameFound);
  403. m_pFile->Seek(startpos);
  404. }
  405. TRACE(_T("****** t3: %dn"), clock() - t1);
  406. t1 = clock();
  407. #endif
  408. break;
  409. }
  410. }
  411. }
  412. bool COggSplitterFilter::DemuxLoop()
  413. {
  414. HRESULT hr = S_OK;
  415. OggPage page;
  416. while(SUCCEEDED(hr) && !CheckRequest(NULL) && m_pFile->Read(page, true, GetRequestHandle()))
  417. {
  418. COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number));
  419. if(!pOggPin) {ASSERT(0); continue;}
  420. if(!pOggPin->IsConnected()) continue;
  421. if(FAILED(hr = pOggPin->UnpackPage(page))) {ASSERT(0); break;}
  422. CAutoPtr<OggPacket> p;
  423. while(!CheckRequest(NULL) && SUCCEEDED(hr) && (p = pOggPin->GetPacket()))
  424. {
  425. if(!p->fSkip)
  426. hr = DeliverPacket(p);
  427. }
  428. }
  429. return(true);
  430. }
  431. //
  432. // COggSourceFilter
  433. //
  434. COggSourceFilter::COggSourceFilter(LPUNKNOWN pUnk, HRESULT* phr)
  435. : COggSplitterFilter(pUnk, phr)
  436. {
  437. m_clsid = __uuidof(this);
  438. m_pInput.Free();
  439. }
  440. //
  441. // COggSplitterOutputPin
  442. //
  443. COggSplitterOutputPin::COggSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
  444. : CBaseSplitterOutputPin(pName, pFilter, pLock, phr)
  445. {
  446. ResetState(-1);
  447. }
  448. void COggSplitterOutputPin::AddComment(BYTE* p, int len)
  449. {
  450. bitstream bs(p, len);
  451. bs.getbits(bs.getbits(32)*8);
  452. for(int n = bs.getbits(32); n-- > 0; )
  453. {
  454. CStringA str;
  455. for(int len = bs.getbits(32); len-- > 0; )
  456. str += (CHAR)bs.getbits(8);
  457. CList<CStringA> sl;
  458. Explode(str, sl, '=', 2);
  459. if(sl.GetCount() == 2)
  460. {
  461. CAutoPtr<CComment> p(new CComment(UTF8To16(sl.GetHead()), UTF8To16(sl.GetTail())));
  462. if(p->m_key == L"LANGUAGE")
  463. {
  464. CString lang = ISO6392ToLanguage(sl.GetTail()), iso6392 = LanguageToISO6392(CString(p->m_value));
  465. if(p->m_value.GetLength() == 3 && !lang.IsEmpty())
  466. {
  467. SetName(CStringW(lang));
  468. SetProperty(L"LANG", p->m_value);
  469. }
  470. else if(!iso6392.IsEmpty())
  471. {
  472. SetName(p->m_value);
  473. SetProperty(L"LANG", CStringW(iso6392));
  474. }
  475. else
  476. {
  477. SetName(p->m_value);
  478. SetProperty(L"NAME", p->m_value);
  479. }
  480. }
  481. m_pComments.AddTail(p);
  482. }
  483. }
  484. ASSERT(bs.getbits(1) == 1);
  485. }
  486. CStringW COggSplitterOutputPin::GetComment(CStringW key)
  487. {
  488. key.MakeUpper();
  489. CList<CStringW> sl;
  490. POSITION pos = m_pComments.GetHeadPosition();
  491. while(pos)
  492. {
  493. CComment* p = m_pComments.GetNext(pos);
  494. if(key == p->m_key) sl.AddTail(p->m_value);
  495. }
  496. return Implode(sl, ';');
  497. }
  498. void COggSplitterOutputPin::ResetState(DWORD seqnum)
  499. {
  500. CAutoLock csAutoLock(&m_csPackets);
  501. m_packets.RemoveAll();
  502. m_lastpacket.Free();
  503. m_lastseqnum = seqnum;
  504. m_rtLast = 0;
  505. m_fSkip = true;
  506. }
  507. HRESULT COggSplitterOutputPin::UnpackPage(OggPage& page)
  508. {
  509. if(m_lastseqnum != page.m_hdr.page_sequence_number-1)
  510. {
  511. ResetState(page.m_hdr.page_sequence_number);
  512. }
  513. else
  514. {
  515. m_lastseqnum = page.m_hdr.page_sequence_number;
  516. }
  517. POSITION first = page.m_lens.GetHeadPosition();
  518. while(first && page.m_lens.GetAt(first) == 255) page.m_lens.GetNext(first);
  519. if(!first) first = page.m_lens.GetTailPosition();
  520. POSITION last = page.m_lens.GetTailPosition();
  521. while(last && page.m_lens.GetAt(last) == 255) page.m_lens.GetPrev(last);
  522. if(!last) last = page.m_lens.GetTailPosition();
  523. BYTE* pData = page.GetData();
  524. int i = 0, j = 0, len = 0;
  525.     for(POSITION pos = page.m_lens.GetHeadPosition(); pos; page.m_lens.GetNext(pos))
  526. {
  527. len = page.m_lens.GetAt(pos);
  528. j += len;
  529. if(len < 255 || pos == page.m_lens.GetTailPosition())
  530. {
  531. if(first == pos && (page.m_hdr.header_type_flag & OggPageHeader::continued))
  532. {
  533. // ASSERT(m_lastpacket);
  534. if(m_lastpacket)
  535. {
  536. int size = m_lastpacket->pData.GetSize();
  537. m_lastpacket->pData.SetSize(size + j-i);
  538. memcpy(m_lastpacket->pData.GetData() + size, pData + i, j-i);
  539. CAutoLock csAutoLock(&m_csPackets);
  540. if(len < 255) m_packets.AddTail(m_lastpacket);
  541. }
  542. }
  543. else
  544. {
  545. CAutoPtr<OggPacket> p(new OggPacket());
  546. if(last == pos && page.m_hdr.granule_position != -1)
  547. {
  548. p->bDiscontinuity = m_fSkip;
  549. REFERENCE_TIME rtLast = m_rtLast;
  550. m_rtLast = GetRefTime(page.m_hdr.granule_position);
  551. // some bad encodings have a +/-1 frame difference from the normal timeline, 
  552. // but these seem to cancel eachother out nicely so we can just ignore them 
  553. // to make it play a bit more smooth.
  554. if(abs(rtLast - m_rtLast) == GetRefTime(1)) m_rtLast = rtLast; // FIXME
  555. m_fSkip = false;
  556. }
  557. p->TrackNumber = page.m_hdr.bitstream_serial_number;
  558. if(S_OK == UnpackPacket(p, pData + i, j-i))
  559. {
  560. if(p->TrackNumber == 0)
  561. TRACE(_T("[%d]: %d, %I64d -> %I64d (skip=%d, disc=%d, sync=%d)n"), 
  562. (int)p->TrackNumber, p->pData.GetSize(), p->rtStart, p->rtStop,
  563. (int)m_fSkip, (int)p->bDiscontinuity, (int)p->bSyncPoint);
  564. CAutoLock csAutoLock(&m_csPackets);
  565. m_rtLast = p->rtStop;
  566. p->fSkip = m_fSkip;
  567. if(len < 255) m_packets.AddTail(p);
  568. else m_lastpacket = p;
  569. }
  570. }
  571. i = j;
  572. }
  573. }
  574. return S_OK;
  575. }
  576. CAutoPtr<OggPacket> COggSplitterOutputPin::GetPacket()
  577. {
  578. CAutoPtr<OggPacket> p;
  579. CAutoLock csAutoLock(&m_csPackets);
  580. if(m_packets.GetCount()) p = m_packets.RemoveHead();
  581. return p;
  582. }
  583. HRESULT COggSplitterOutputPin::DeliverEndFlush()
  584. {
  585. ResetState();
  586. return __super::DeliverEndFlush();
  587. }
  588. HRESULT COggSplitterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
  589. {
  590. ResetState();
  591. return __super::DeliverNewSegment(tStart, tStop, dRate);
  592. }
  593. //
  594. // COggVorbisOutputPin
  595. //
  596. COggVorbisOutputPin::COggVorbisOutputPin(OggVorbisIdHeader* h, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
  597. : COggSplitterOutputPin(pName, pFilter, pLock, phr)
  598. {
  599. m_audio_sample_rate = h->audio_sample_rate;
  600. m_blocksize[0] = 1<<h->blocksize_0;
  601. m_blocksize[1] = 1<<h->blocksize_1;
  602. m_lastblocksize = 0;
  603. CMediaType mt;
  604. mt.InitMediaType();
  605. mt.majortype = MEDIATYPE_Audio;
  606. mt.subtype = MEDIASUBTYPE_Vorbis;
  607. mt.formattype = FORMAT_VorbisFormat;
  608. VORBISFORMAT* vf = (VORBISFORMAT*)mt.AllocFormatBuffer(sizeof(VORBISFORMAT));
  609. memset(mt.Format(), 0, mt.FormatLength());
  610. vf->nChannels = h->audio_channels;
  611. vf->nSamplesPerSec = h->audio_sample_rate;
  612. vf->nAvgBitsPerSec = h->bitrate_nominal;
  613. vf->nMinBitsPerSec = h->bitrate_minimum;
  614. vf->nMaxBitsPerSec = h->bitrate_maximum;
  615. vf->fQuality = -1;
  616. mt.SetSampleSize(8192);
  617. m_mts.Add(mt);
  618. mt.InitMediaType();
  619. mt.majortype = MEDIATYPE_Audio;
  620. mt.subtype = MEDIASUBTYPE_Vorbis2;
  621. mt.formattype = FORMAT_VorbisFormat2;
  622. VORBISFORMAT2* vf2 = (VORBISFORMAT2*)mt.AllocFormatBuffer(sizeof(VORBISFORMAT2));
  623. memset(mt.Format(), 0, mt.FormatLength());
  624. vf2->Channels = h->audio_channels;
  625. vf2->SamplesPerSec = h->audio_sample_rate;
  626. mt.SetSampleSize(8192);
  627. m_mts.InsertAt(0, mt);
  628. }
  629. REFERENCE_TIME COggVorbisOutputPin::GetRefTime(__int64 granule_position)
  630. {
  631. REFERENCE_TIME rt = granule_position * 10000000 / m_audio_sample_rate;
  632. return rt;
  633. }
  634. HRESULT COggVorbisOutputPin::UnpackInitPage(OggPage& page)
  635. {
  636. HRESULT hr = __super::UnpackPage(page);
  637. while(m_packets.GetCount())
  638. {
  639. Packet* p = m_packets.GetHead();
  640. if(p->pData.GetCount() >= 6 && p->pData.GetData()[0] == 0x05)
  641. {
  642. // yeah, right, we are going to be parsing this backwards! :P
  643. bitstream bs(p->pData.GetData(), p->pData.GetCount(), true);
  644. while(bs.hasbits(-1) && bs.getbits(-1) != 1);
  645. for(int cnt = 0; bs.hasbits(-8-16-16-1-6); cnt++)
  646. {
  647. unsigned int modes = bs.showbits(-6)+1;
  648. unsigned int mapping = bs.getbits(-8);
  649. unsigned int transformtype = bs.getbits(-16);
  650. unsigned int windowtype = bs.getbits(-16);
  651. unsigned int blockflag = bs.getbits(-1);
  652. if(transformtype != 0 || windowtype != 0)
  653. {
  654. ASSERT(modes == cnt);
  655. break;
  656. }
  657. m_blockflags.InsertAt(0, !!blockflag);
  658. }
  659. }
  660. int cnt = m_initpackets.GetCount();
  661. if(cnt <= 3)
  662. {
  663. ASSERT(p->pData.GetCount() >= 6 && p->pData.GetData()[0] == 1+cnt*2);
  664. VORBISFORMAT2* vf2 = (VORBISFORMAT2*)m_mts[0].Format();
  665. vf2->HeaderSize[cnt] = p->pData.GetSize();
  666. int len = m_mts[0].FormatLength();
  667. memcpy(
  668. m_mts[0].ReallocFormatBuffer(len + p->pData.GetSize()) + len, 
  669. p->pData.GetData(), p->pData.GetSize());
  670. }
  671. m_initpackets.AddTail(m_packets.RemoveHead());
  672. }
  673. return hr;
  674. }
  675. HRESULT COggVorbisOutputPin::UnpackPacket(CAutoPtr<OggPacket>& p, BYTE* pData, int len)
  676. {
  677. if(len > 0 && m_blockflags.GetCount())
  678. {
  679. bitstream bs(pData, len);
  680. if(bs.getbits(1) == 0)
  681. {
  682. int x = m_blockflags.GetCount()-1, n = 0;
  683. while(x) {n++; x >>= 1;}
  684. DWORD blocksize = m_blocksize[m_blockflags[bs.getbits(n)]?1:0];
  685. if(m_lastblocksize) m_rtLast += GetRefTime((m_lastblocksize + blocksize) >> 2);
  686. m_lastblocksize = blocksize;
  687. }
  688. }
  689. p->bSyncPoint = TRUE;
  690. p->rtStart = m_rtLast;
  691. p->rtStop = m_rtLast+1;
  692. p->pData.SetSize(len);
  693. memcpy(p->pData.GetData(), pData, len);
  694. return S_OK;
  695. }
  696. HRESULT COggVorbisOutputPin::DeliverPacket(CAutoPtr<OggPacket> p)
  697. {
  698. if(p->pData.GetSize() > 0 && (p->pData.GetData()[0]&1))
  699. return S_OK;
  700. return __super::DeliverPacket(p);
  701. }
  702. HRESULT COggVorbisOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
  703. {
  704. HRESULT hr = __super::DeliverNewSegment(tStart, tStop, dRate);
  705. m_lastblocksize = 0;
  706. if(m_mt.subtype == MEDIASUBTYPE_Vorbis)
  707. {
  708. POSITION pos = m_initpackets.GetHeadPosition();
  709. while(pos)
  710. {
  711. Packet* pi = m_initpackets.GetNext(pos);
  712. CAutoPtr<OggPacket> p(new OggPacket());
  713. p->TrackNumber = pi->TrackNumber;
  714. p->bDiscontinuity = p->bSyncPoint = TRUE;
  715. p->rtStart = p->rtStop = 0;
  716. p->pData.Copy(pi->pData);
  717. __super::DeliverPacket(p);
  718. }
  719. }
  720. return hr;
  721. }
  722. //
  723. // COggDirectShowOutputPin
  724. //
  725. COggDirectShowOutputPin::COggDirectShowOutputPin(AM_MEDIA_TYPE* pmt, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
  726. : COggSplitterOutputPin(pName, pFilter, pLock, phr)
  727. {
  728. CMediaType mt;
  729. memcpy((AM_MEDIA_TYPE*)&mt, pmt, FIELD_OFFSET(AM_MEDIA_TYPE, pUnk));
  730. mt.SetFormat((BYTE*)(pmt+1), pmt->cbFormat);
  731. mt.SetSampleSize(1);
  732. if(mt.majortype == MEDIATYPE_Video) // TODO: find samples for audio and find out what to return in GetRefTime...
  733. m_mts.Add(mt);
  734. }
  735. REFERENCE_TIME COggDirectShowOutputPin::GetRefTime(__int64 granule_position)
  736. {
  737. REFERENCE_TIME rt = 0;
  738. if(m_mt.majortype == MEDIATYPE_Video)
  739. {
  740. rt = granule_position * ((VIDEOINFOHEADER*)m_mt.Format())->AvgTimePerFrame;
  741. }
  742. else if(m_mt.majortype == MEDIATYPE_Audio)
  743. {
  744. rt = granule_position; // ((WAVEFORMATEX*)m_mt.Format())-> // TODO
  745. }
  746. return rt;
  747. }
  748. HRESULT COggDirectShowOutputPin::UnpackPacket(CAutoPtr<OggPacket>& p, BYTE* pData, int len)
  749. {
  750. int i = 0;
  751. BYTE hdr = pData[i++];
  752. if(!(hdr&1))
  753. {
  754. // TODO: verify if this was still present in the old format (haven't found one sample yet)
  755. BYTE nLenBytes = (hdr>>6)|((hdr&2)<<1);
  756. __int64 Length = 0;
  757. for(int j = 0; j < nLenBytes; j++)
  758. Length |= (__int64)pData[i++] << (j << 3);
  759. // TODO: if(len < i) {ASSERT(0); return E_FAIL;}
  760. p->bSyncPoint = !!(hdr&8);
  761. p->rtStart = m_rtLast;
  762. p->rtStop = m_rtLast + (nLenBytes ? GetRefTime(Length) : GetRefTime(1));
  763. p->pData.SetSize(len - i);
  764. memcpy(p->pData.GetData(), &pData[i], len - i);
  765. return S_OK;
  766. }
  767. return S_FALSE;
  768. }
  769. //
  770. // COggStreamOutputPin
  771. //
  772. COggStreamOutputPin::COggStreamOutputPin(OggStreamHeader* h, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
  773. : COggSplitterOutputPin(pName, pFilter, pLock, phr)
  774. {
  775. m_time_unit = h->time_unit;
  776. m_samples_per_unit = h->samples_per_unit;
  777. m_default_len = h->default_len;
  778. }
  779. REFERENCE_TIME COggStreamOutputPin::GetRefTime(__int64 granule_position)
  780. {
  781. return granule_position * m_time_unit / m_samples_per_unit;
  782. }
  783. HRESULT COggStreamOutputPin::UnpackPacket(CAutoPtr<OggPacket>& p, BYTE* pData, int len)
  784. {
  785. int i = 0;
  786. BYTE hdr = pData[i++];
  787. if(!(hdr&1))
  788. {
  789. BYTE nLenBytes = (hdr>>6)|((hdr&2)<<1);
  790. __int64 Length = 0;
  791. for(int j = 0; j < nLenBytes; j++)
  792. Length |= (__int64)pData[i++] << (j << 3);
  793. // TODO: if(len < i) {ASSERT(0); return E_FAIL;}
  794. p->bSyncPoint = !!(hdr&8);
  795. p->rtStart = m_rtLast;
  796. p->rtStop = m_rtLast + (nLenBytes ? GetRefTime(Length) : GetRefTime(m_default_len));
  797. p->pData.SetSize(len - i);
  798. memcpy(p->pData.GetData(), &pData[i], len - i);
  799. return S_OK;
  800. }
  801. return S_FALSE;
  802. }
  803. //
  804. // COggVideoOutputPin
  805. //
  806. COggVideoOutputPin::COggVideoOutputPin(OggStreamHeader* h, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
  807. : COggStreamOutputPin(h, pName, pFilter, pLock, phr)
  808. {
  809. int extra = (int)h->size - sizeof(OggStreamHeader);
  810. extra = max(extra, 0);
  811. CMediaType mt;
  812. mt.majortype = MEDIATYPE_Video;
  813. mt.subtype = FOURCCMap(MAKEFOURCC(h->subtype[0],h->subtype[1],h->subtype[2],h->subtype[3]));
  814. mt.formattype = FORMAT_VideoInfo;
  815. VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER) + extra);
  816. memset(mt.Format(), 0, mt.FormatLength());
  817. memcpy(mt.Format() + sizeof(VIDEOINFOHEADER), h+1, extra);
  818. pvih->AvgTimePerFrame = h->time_unit / h->samples_per_unit;
  819. pvih->bmiHeader.biWidth = h->v.w;
  820. pvih->bmiHeader.biHeight = h->v.h;
  821. pvih->bmiHeader.biBitCount = (WORD)h->bps;
  822. pvih->bmiHeader.biCompression = mt.subtype.Data1;
  823. switch(pvih->bmiHeader.biCompression)
  824. {
  825. case BI_RGB: case BI_BITFIELDS: mt.subtype = 
  826. pvih->bmiHeader.biBitCount == 1 ? MEDIASUBTYPE_RGB1 :
  827. pvih->bmiHeader.biBitCount == 4 ? MEDIASUBTYPE_RGB4 :
  828. pvih->bmiHeader.biBitCount == 8 ? MEDIASUBTYPE_RGB8 :
  829. pvih->bmiHeader.biBitCount == 16 ? MEDIASUBTYPE_RGB565 :
  830. pvih->bmiHeader.biBitCount == 24 ? MEDIASUBTYPE_RGB24 :
  831. pvih->bmiHeader.biBitCount == 32 ? MEDIASUBTYPE_RGB32 :
  832. MEDIASUBTYPE_NULL;
  833. break;
  834. case BI_RLE8: mt.subtype = MEDIASUBTYPE_RGB8; break;
  835. case BI_RLE4: mt.subtype = MEDIASUBTYPE_RGB4; break;
  836. }
  837. mt.SetSampleSize(max(h->buffersize, 1));
  838. m_mts.Add(mt);
  839. }
  840. //
  841. // COggAudioOutputPin
  842. //
  843. COggAudioOutputPin::COggAudioOutputPin(OggStreamHeader* h, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
  844. : COggStreamOutputPin(h, pName, pFilter, pLock, phr)
  845. {
  846. int extra = (int)h->size - sizeof(OggStreamHeader);
  847. extra = max(extra, 0);
  848. CMediaType mt;
  849. mt.majortype = MEDIATYPE_Audio;
  850. mt.subtype = FOURCCMap(strtol(CStringA(h->subtype, 4), NULL, 16));
  851. mt.formattype = FORMAT_WaveFormatEx;
  852. WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.AllocFormatBuffer(sizeof(WAVEFORMATEX) + extra);
  853. memset(mt.Format(), 0, mt.FormatLength());
  854. memcpy(mt.Format() + sizeof(WAVEFORMATEX), h+1, extra);
  855. wfe->cbSize = extra;
  856. wfe->wFormatTag = (WORD)mt.subtype.Data1;
  857. wfe->nChannels = h->a.nChannels;
  858. wfe->nSamplesPerSec = (DWORD)(10000000i64 * h->samples_per_unit / h->time_unit);
  859. wfe->wBitsPerSample = (WORD)h->bps;
  860. wfe->nAvgBytesPerSec = h->a.nAvgBytesPerSec; // TODO: verify for PCM
  861. wfe->nBlockAlign = h->a.nBlockAlign; // TODO: verify for PCM
  862. mt.SetSampleSize(max(h->buffersize, 1));
  863. m_mts.Add(mt);
  864. }
  865. //
  866. // COggTextOutputPin
  867. //
  868. COggTextOutputPin::COggTextOutputPin(OggStreamHeader* h, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
  869. : COggStreamOutputPin(h, pName, pFilter, pLock, phr)
  870. {
  871. CMediaType mt;
  872. mt.majortype = MEDIATYPE_Text;
  873. mt.subtype = MEDIASUBTYPE_NULL;
  874. mt.formattype = FORMAT_None;
  875. mt.SetSampleSize(1);
  876. m_mts.Add(mt);
  877. }