00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "OggSplitter.h"
00024 #include "..\..\..\DSUtil\DSUtil.h"
00025
00026 #include <initguid.h>
00027 #include "..\..\..\..\include\ogg\OggDS.h"
00028 #include "..\..\..\..\include\moreuuids.h"
00029
00030 #ifdef REGISTER_FILTER
00031
00032 const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
00033 {
00034 {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL},
00035 };
00036
00037 const AMOVIESETUP_PIN sudpPins[] =
00038 {
00039 {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
00040 {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, 0, NULL}
00041 };
00042
00043 const AMOVIESETUP_FILTER sudFilter[] =
00044 {
00045 {&__uuidof(COggSplitterFilter), L"Ogg Splitter", MERIT_NORMAL+1, countof(sudpPins), sudpPins},
00046 {&__uuidof(COggSourceFilter), L"Ogg Source", MERIT_NORMAL+1, 0, NULL},
00047 };
00048
00049 CFactoryTemplate g_Templates[] =
00050 {
00051 {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<COggSplitterFilter>, NULL, &sudFilter[0]},
00052 {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance<COggSourceFilter>, NULL, &sudFilter[1]},
00053 };
00054
00055 int g_cTemplates = countof(g_Templates);
00056
00057 STDAPI DllRegisterServer()
00058 {
00059 RegisterSourceFilter(
00060 CLSID_AsyncReader,
00061 MEDIASUBTYPE_Ogg,
00062 _T("0,4,,4F676753"),
00063 _T(".ogg"), _T(".ogm"), NULL);
00064
00065 return AMovieDllRegisterServer2(TRUE);
00066 }
00067
00068 STDAPI DllUnregisterServer()
00069 {
00070 UnRegisterSourceFilter(MEDIASUBTYPE_Ogg);
00071
00072 return AMovieDllRegisterServer2(FALSE);
00073 }
00074
00075 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
00076
00077 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
00078 {
00079 return DllEntryPoint((HINSTANCE)hModule, dwReason, 0);
00080 }
00081
00082 #endif
00083
00084
00085
00086
00087
00088 class bitstream
00089 {
00090 BYTE* m_p;
00091 int m_len, m_pos;
00092 public:
00093 bitstream(BYTE* p, int len, bool rev = false) : m_p(p), m_len(len*8) {m_pos = !rev ? 0 : len*8;}
00094 bool hasbits(int cnt)
00095 {
00096 int pos = m_pos+cnt;
00097 return(pos >= 0 && pos < m_len);
00098 }
00099 unsigned int showbits(int cnt)
00100 {
00101 if(!hasbits(cnt)) {ASSERT(0); return 0;}
00102 unsigned int ret = 0, off = 0;
00103 BYTE* p = m_p;
00104 if(cnt < 0)
00105 {
00106 p += (m_pos+cnt)>>3;
00107 off = (m_pos+cnt)&7;
00108 cnt = abs(cnt);
00109 ret = (*p++&(~0<<off))>>off; off = 8 - off; cnt -= off;
00110 }
00111 else
00112 {
00113 p += m_pos>>3;
00114 off = m_pos&7;
00115 ret = (*p++>>off)&((1<<min(cnt,8))-1); off = 0; cnt -= 8 - off;
00116 }
00117 while(cnt > 0) {ret |= (*p++&((1<<min(cnt,8))-1)) << off; off += 8; cnt -= 8;}
00118 return ret;
00119 }
00120 unsigned int getbits(int cnt)
00121 {
00122 unsigned int ret = showbits(cnt);
00123 m_pos += cnt;
00124 return ret;
00125 }
00126 };
00127
00128
00129
00130
00131
00132 COggSplitterFilter::COggSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr)
00133 : CBaseSplitterFilter(NAME("COggSplitterFilter"), pUnk, phr, __uuidof(this))
00134 {
00135 }
00136
00137 COggSplitterFilter::~COggSplitterFilter()
00138 {
00139 }
00140
00141 HRESULT COggSplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader)
00142 {
00143 CheckPointer(pAsyncReader, E_POINTER);
00144
00145 HRESULT hr = E_FAIL;
00146
00147 m_pFile.Free();
00148
00149 m_pFile.Attach(new COggFile(pAsyncReader, hr));
00150 if(!m_pFile) return E_OUTOFMEMORY;
00151 if(FAILED(hr)) {m_pFile.Free(); return hr;}
00152
00153 m_rtNewStart = m_rtCurrent = 0;
00154 m_rtNewStop = m_rtStop = 0;
00155
00156 m_rtDuration = 0;
00157
00158 m_pFile->Seek(0);
00159 OggPage page;
00160 for(int i = 0, nWaitForMore = 0; m_pFile->Read(page); i++)
00161 {
00162 BYTE* p = page.GetData();
00163
00164 if(!(page.m_hdr.header_type_flag & OggPageHeader::continued))
00165 {
00166 BYTE type = *p++;
00167 if(!(type&1) && nWaitForMore == 0)
00168 break;
00169
00170 CStringW name;
00171 name.Format(L"Stream %d", i);
00172
00173 HRESULT hr;
00174
00175 if(type == 1 && (page.m_hdr.header_type_flag & OggPageHeader::first))
00176 {
00177 CAutoPtr<CBaseSplitterOutputPin> pPinOut;
00178
00179 if(!memcmp(p, "vorbis", 6))
00180 {
00181 name.Format(L"Vorbis %d", i);
00182 pPinOut.Attach(new COggVorbisOutputPin((OggVorbisIdHeader*)(p+6), name, this, this, &hr));
00183 nWaitForMore++;
00184 }
00185 else if(!memcmp(p, "video", 5))
00186 {
00187 name.Format(L"Video %d", i);
00188 pPinOut.Attach(new COggVideoOutputPin((OggStreamHeader*)p, name, this, this, &hr));
00189 }
00190 else if(!memcmp(p, "audio", 5))
00191 {
00192 name.Format(L"Audio %d", i);
00193 pPinOut.Attach(new COggAudioOutputPin((OggStreamHeader*)p, name, this, this, &hr));
00194 }
00195 else if(!memcmp(p, "text", 4))
00196 {
00197 name.Format(L"Text %d", i);
00198 pPinOut.Attach(new COggTextOutputPin((OggStreamHeader*)p, name, this, this, &hr));
00199 }
00200 else if(!memcmp(p, "Direct Show Samples embedded in Ogg", 35))
00201 {
00202 name.Format(L"DirectShow %d", i);
00203 pPinOut.Attach(new COggDirectShowOutputPin((AM_MEDIA_TYPE*)(p+35+sizeof(GUID)), name, this, this, &hr));
00204 }
00205
00206 AddOutputPin(page.m_hdr.bitstream_serial_number, pPinOut);
00207 }
00208
00209 if(type == 3 && !memcmp(p, "vorbis", 6))
00210 {
00211 if(COggSplitterOutputPin* pOggPin =
00212 dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number)))
00213 {
00214 pOggPin->AddComment(p+6, page.GetSize()-6-1);
00215 }
00216 }
00217 }
00218
00219 if(COggVorbisOutputPin* pOggVorbisPin =
00220 dynamic_cast<COggVorbisOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number)))
00221 {
00222 pOggVorbisPin->UnpackInitPage(page);
00223 if(pOggVorbisPin->IsInitialized()) nWaitForMore--;
00224 }
00225 }
00226
00227 if(m_pOutputs.IsEmpty())
00228 return E_FAIL;
00229
00230 m_pFile->Seek(max(m_pFile->GetLength()-65536, 0));
00231 while(m_pFile->Read(page))
00232 {
00233 COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number));
00234 if(!pOggPin) {ASSERT(0); continue;}
00235 if(page.m_hdr.granule_position == -1) continue;
00236 REFERENCE_TIME rt = pOggPin->GetRefTime(page.m_hdr.granule_position);
00237 m_rtDuration = max(rt, m_rtDuration);
00238 }
00239
00240 m_rtNewStart = m_rtCurrent = 0;
00241 m_rtNewStop = m_rtStop = m_rtDuration;
00242
00243
00244
00245 {
00246 CAtlMap<CStringW, CStringW, CStringElementTraits<CStringW> > tagmap;
00247 tagmap[L"TITLE"] = L"TITL";
00248 tagmap[L"ARTIST"] = L"AUTH";
00249 tagmap[L"COPYRIGHT"] = L"CPYR";
00250 tagmap[L"DESCRIPTION"] = L"DESC";
00251
00252 POSITION pos2 = tagmap.GetStartPosition();
00253 while(pos2)
00254 {
00255 CStringW oggtag, dsmtag;
00256 tagmap.GetNextAssoc(pos2, oggtag, dsmtag);
00257
00258 POSITION pos = m_pOutputs.GetHeadPosition();
00259 while(pos)
00260 {
00261 COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>((CBaseOutputPin*)m_pOutputs.GetNext(pos));
00262 if(!pOggPin) continue;
00263
00264 CStringW value = pOggPin->GetComment(oggtag);
00265 if(!value.IsEmpty())
00266 {
00267 SetProperty(dsmtag, value);
00268 break;
00269 }
00270 }
00271 }
00272
00273 POSITION pos = m_pOutputs.GetHeadPosition();
00274 while(pos && !ChapGetCount())
00275 {
00276 COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>((CBaseOutputPin*)m_pOutputs.GetNext(pos));
00277 if(!pOggPin) continue;
00278
00279 for(int i = 1; pOggPin; i++)
00280 {
00281 CStringW key;
00282 key.Format(L"CHAPTER%02d", i);
00283 CStringW time = pOggPin->GetComment(key);
00284 if(time.IsEmpty()) break;
00285 key.Format(L"CHAPTER%02dNAME", i);
00286 CStringW name = pOggPin->GetComment(key);
00287 if(name.IsEmpty()) name.Format(L"Chapter %d", i);
00288 int h, m, s, ms;
00289 WCHAR c;
00290 if(7 != swscanf(time, L"%d%c%d%c%d%c%d", &h, &c, &m, &c, &s, &c, &ms)) break;
00291 REFERENCE_TIME rt = ((((REFERENCE_TIME)h*60+m)*60+s)*1000+ms)*10000;
00292 ChapAppend(rt, name);
00293 }
00294 }
00295 }
00296
00297 return m_pOutputs.GetCount() > 0 ? S_OK : E_FAIL;
00298 }
00299
00300 bool COggSplitterFilter::DemuxInit()
00301 {
00302 if(!m_pFile) return(false);
00303
00304 return(true);
00305 }
00306
00307 void COggSplitterFilter::DemuxSeek(REFERENCE_TIME rt)
00308 {
00309 if(rt <= 0)
00310 {
00311 m_pFile->Seek(0);
00312 }
00313 else if(m_rtDuration > 0)
00314 {
00315
00316 clock_t t1 = clock();
00317 __int64 len = m_pFile->GetLength();
00318 __int64 startpos = len * rt/m_rtDuration;
00319 __int64 diff = 0;
00320
00321 REFERENCE_TIME rtMinDiff = _I64_MAX;
00322
00323 while(1)
00324 {
00325 __int64 endpos = startpos;
00326 REFERENCE_TIME rtPos = -1;
00327
00328 OggPage page;
00329 m_pFile->Seek(startpos);
00330 while(m_pFile->Read(page, false))
00331 {
00332 if(page.m_hdr.granule_position == -1) continue;
00333
00334 COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number));
00335 if(!pOggPin) {ASSERT(0); continue;}
00336
00337 rtPos = pOggPin->GetRefTime(page.m_hdr.granule_position);
00338 endpos = m_pFile->GetPos();
00339
00340 break;
00341 }
00342
00343 __int64 rtDiff = rtPos - rt;
00344
00345 if(rtDiff < 0)
00346 {
00347 rtDiff = -rtDiff;
00348
00349 if(rtDiff < 1000000 || rtDiff >= rtMinDiff)
00350 {
00351 m_pFile->Seek(startpos);
00352 break;
00353 }
00354
00355 rtMinDiff = rtDiff;
00356 }
00357
00358 __int64 newpos = startpos;
00359
00360 if(rtPos < rt && rtPos < m_rtDuration)
00361 {
00362 newpos = startpos + (__int64)((1.0*(rt - rtPos)/(m_rtDuration - rtPos)) * (len - startpos)) + 1024;
00363 if(newpos < endpos) newpos = endpos + 1024;
00364 }
00365 else if(rtPos > rt && rtPos > 0)
00366 {
00367 newpos = startpos - (__int64)((1.0*(rtPos - rt)/(rtPos - 0)) * (startpos - 0)) - 1024;
00368 if(newpos >= startpos) newpos = startpos - 1024;
00369 }
00370 else if(rtPos == rt)
00371 {
00372 m_pFile->Seek(startpos);
00373 break;
00374 }
00375 else
00376 {
00377 ASSERT(0);
00378 m_pFile->Seek(0);
00379 break;
00380 }
00381
00382 diff = newpos - startpos;
00383
00384 startpos = max(min(newpos, len), 0);
00385 }
00386
00387 TRACE(_T("****** t1: %d\n"), clock() - t1);
00388 t1 = clock();
00389 m_pFile->Seek(startpos);
00390
00391 POSITION pos = m_pOutputs.GetHeadPosition();
00392 while(pos)
00393 {
00394 CBaseSplitterOutputPin* pPin = m_pOutputs.GetNext(pos);
00395 COggVideoOutputPin* pOggVideoPin = dynamic_cast<COggVideoOutputPin*>(pPin);
00396 if(!pOggVideoPin) continue;
00397
00398 bool fKeyFrameFound = false, fSkipKeyFrame = true;
00399 __int64 endpos = _I64_MAX;
00400
00401 while(!(fKeyFrameFound && !fSkipKeyFrame) && startpos > 0)
00402 {
00403 OggPage page;
00404 while(!(fKeyFrameFound && !fSkipKeyFrame) && m_pFile->GetPos() < endpos && m_pFile->Read(page))
00405 {
00406 if(page.m_hdr.granule_position == -1) continue;
00407
00408 COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number));
00409 if(pOggPin != pOggVideoPin) continue;
00410
00411 REFERENCE_TIME rtPos = pOggPin->GetRefTime(page.m_hdr.granule_position);
00412
00413 if(rtPos > rt)
00414 break;
00415
00416 if(!fKeyFrameFound)
00417 {
00418 pOggPin->UnpackPage(page);
00419
00420 CAutoPtr<OggPacket> p;
00421 while(p = pOggPin->GetPacket())
00422 {
00423 if(p->bSyncPoint)
00424 {
00425 fKeyFrameFound = true;
00426 fSkipKeyFrame = p->fSkip;
00427 }
00428 }
00429
00430 if(fKeyFrameFound) break;
00431 }
00432 else
00433 {
00434 pOggPin->UnpackPage(page);
00435
00436 CAutoPtr<OggPacket> p;
00437 while(p = pOggPin->GetPacket())
00438 {
00439 if(!p->fSkip)
00440 {
00441 fSkipKeyFrame = false;
00442 break;
00443 }
00444 }
00445 }
00446 }
00447
00448 if(!(fKeyFrameFound && !fSkipKeyFrame)) {endpos = startpos; startpos = max(startpos - 10*65536, 0);}
00449
00450 m_pFile->Seek(startpos);
00451 }
00452 TRACE(_T("****** t2: %d\n"), clock() - t1);
00453 t1 = clock();
00454
00455 #ifdef DEBUG
00456
00457
00458 {
00459 fKeyFrameFound = false;
00460
00461 OggPage page;
00462 while(!fKeyFrameFound && m_pFile->Read(page))
00463 {
00464 if(page.m_hdr.granule_position == -1) continue;
00465
00466 COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number));
00467 if(pOggPin != pOggVideoPin) continue;
00468
00469 REFERENCE_TIME rtPos = pOggPin->GetRefTime(page.m_hdr.granule_position);
00470 if(rtPos > rt)
00471 break;
00472
00473 pOggPin->UnpackPage(page);
00474
00475 CAutoPtr<OggPacket> p;
00476 while(p = pOggPin->GetPacket())
00477 {
00478 if(p->bSyncPoint)
00479 {
00480 fKeyFrameFound = true;
00481 break;
00482 }
00483 }
00484 }
00485
00486 ASSERT(fKeyFrameFound);
00487
00488 m_pFile->Seek(startpos);
00489 }
00490 TRACE(_T("****** t3: %d\n"), clock() - t1);
00491 t1 = clock();
00492 #endif
00493 break;
00494 }
00495 }
00496 }
00497
00498 bool COggSplitterFilter::DemuxLoop()
00499 {
00500 HRESULT hr = S_OK;
00501
00502 OggPage page;
00503 while(SUCCEEDED(hr) && !CheckRequest(NULL) && m_pFile->Read(page, true, GetRequestHandle()))
00504 {
00505 COggSplitterOutputPin* pOggPin = dynamic_cast<COggSplitterOutputPin*>(GetOutputPin(page.m_hdr.bitstream_serial_number));
00506 if(!pOggPin) {ASSERT(0); continue;}
00507 if(!pOggPin->IsConnected()) continue;
00508 if(FAILED(hr = pOggPin->UnpackPage(page))) {ASSERT(0); break;}
00509 CAutoPtr<OggPacket> p;
00510 while(!CheckRequest(NULL) && SUCCEEDED(hr) && (p = pOggPin->GetPacket()))
00511 {
00512 if(!p->fSkip)
00513 hr = DeliverPacket(p);
00514 }
00515 }
00516
00517 return(true);
00518 }
00519
00520
00521
00522
00523
00524 COggSourceFilter::COggSourceFilter(LPUNKNOWN pUnk, HRESULT* phr)
00525 : COggSplitterFilter(pUnk, phr)
00526 {
00527 m_clsid = __uuidof(this);
00528 m_pInput.Free();
00529 }
00530
00531
00532
00533
00534
00535 COggSplitterOutputPin::COggSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
00536 : CBaseSplitterOutputPin(pName, pFilter, pLock, phr)
00537 {
00538 ResetState(-1);
00539 }
00540
00541 void COggSplitterOutputPin::AddComment(BYTE* p, int len)
00542 {
00543 bitstream bs(p, len);
00544 bs.getbits(bs.getbits(32)*8);
00545 for(int n = bs.getbits(32); n-- > 0; )
00546 {
00547 CStringA str;
00548 for(int len = bs.getbits(32); len-- > 0; )
00549 str += (CHAR)bs.getbits(8);
00550
00551 CList<CStringA> sl;
00552 Explode(str, sl, '=', 2);
00553 if(sl.GetCount() == 2)
00554 {
00555 CAutoPtr<CComment> p(new CComment(UTF8To16(sl.GetHead()), UTF8To16(sl.GetTail())));
00556
00557 if(p->m_key == L"LANGUAGE")
00558 {
00559 CString lang = ISO6392ToLanguage(sl.GetTail()), iso6392 = LanguageToISO6392(CString(p->m_value));
00560
00561 if(p->m_value.GetLength() == 3 && !lang.IsEmpty())
00562 {
00563 SetName(CStringW(lang));
00564 SetProperty(L"LANG", p->m_value);
00565 }
00566 else if(!iso6392.IsEmpty())
00567 {
00568 SetName(p->m_value);
00569 SetProperty(L"LANG", CStringW(iso6392));
00570 }
00571 else
00572 {
00573 SetName(p->m_value);
00574 SetProperty(L"NAME", p->m_value);
00575 }
00576 }
00577
00578 m_pComments.AddTail(p);
00579 }
00580 }
00581 ASSERT(bs.getbits(1) == 1);
00582 }
00583
00584 CStringW COggSplitterOutputPin::GetComment(CStringW key)
00585 {
00586 key.MakeUpper();
00587 CList<CStringW> sl;
00588 POSITION pos = m_pComments.GetHeadPosition();
00589 while(pos)
00590 {
00591 CComment* p = m_pComments.GetNext(pos);
00592 if(key == p->m_key) sl.AddTail(p->m_value);
00593 }
00594 return Implode(sl, ';');
00595 }
00596
00597 void COggSplitterOutputPin::ResetState(DWORD seqnum)
00598 {
00599 CAutoLock csAutoLock(&m_csPackets);
00600 m_packets.RemoveAll();
00601 m_lastpacket.Free();
00602 m_lastseqnum = seqnum;
00603 m_rtLast = 0;
00604 m_fSkip = true;
00605 }
00606
00607 HRESULT COggSplitterOutputPin::UnpackPage(OggPage& page)
00608 {
00609 if(m_lastseqnum != page.m_hdr.page_sequence_number-1)
00610 {
00611 ResetState(page.m_hdr.page_sequence_number);
00612 }
00613 else
00614 {
00615 m_lastseqnum = page.m_hdr.page_sequence_number;
00616 }
00617
00618 POSITION first = page.m_lens.GetHeadPosition();
00619 while(first && page.m_lens.GetAt(first) == 255) page.m_lens.GetNext(first);
00620 if(!first) first = page.m_lens.GetTailPosition();
00621
00622 POSITION last = page.m_lens.GetTailPosition();
00623 while(last && page.m_lens.GetAt(last) == 255) page.m_lens.GetPrev(last);
00624 if(!last) last = page.m_lens.GetTailPosition();
00625
00626 BYTE* pData = page.GetData();
00627
00628 int i = 0, j = 0, len = 0;
00629
00630 for(POSITION pos = page.m_lens.GetHeadPosition(); pos; page.m_lens.GetNext(pos))
00631 {
00632 len = page.m_lens.GetAt(pos);
00633 j += len;
00634
00635 if(len < 255 || pos == page.m_lens.GetTailPosition())
00636 {
00637 if(first == pos && (page.m_hdr.header_type_flag & OggPageHeader::continued))
00638 {
00639
00640
00641 if(m_lastpacket)
00642 {
00643 int size = m_lastpacket->pData.GetSize();
00644 m_lastpacket->pData.SetSize(size + j-i);
00645 memcpy(m_lastpacket->pData.GetData() + size, pData + i, j-i);
00646
00647 CAutoLock csAutoLock(&m_csPackets);
00648
00649 if(len < 255) m_packets.AddTail(m_lastpacket);
00650 }
00651 }
00652 else
00653 {
00654 CAutoPtr<OggPacket> p(new OggPacket());
00655
00656 if(last == pos && page.m_hdr.granule_position != -1)
00657 {
00658 p->bDiscontinuity = m_fSkip;
00659 REFERENCE_TIME rtLast = m_rtLast;
00660 m_rtLast = GetRefTime(page.m_hdr.granule_position);
00661
00662
00663
00664 if(abs(rtLast - m_rtLast) == GetRefTime(1)) m_rtLast = rtLast;
00665 m_fSkip = false;
00666 }
00667
00668 p->TrackNumber = page.m_hdr.bitstream_serial_number;
00669
00670 if(S_OK == UnpackPacket(p, pData + i, j-i))
00671 {
00672
00673 if(p->TrackNumber == 0)
00674 TRACE(_T("[%d]: %d, %I64d -> %I64d (skip=%d, disc=%d, sync=%d)\n"),
00675 (int)p->TrackNumber, p->pData.GetSize(), p->rtStart, p->rtStop,
00676 (int)m_fSkip, (int)p->bDiscontinuity, (int)p->bSyncPoint);
00677
00678 CAutoLock csAutoLock(&m_csPackets);
00679
00680 m_rtLast = p->rtStop;
00681 p->fSkip = m_fSkip;
00682
00683 if(len < 255) m_packets.AddTail(p);
00684 else m_lastpacket = p;
00685 }
00686 }
00687
00688 i = j;
00689 }
00690 }
00691
00692 return S_OK;
00693 }
00694
00695 CAutoPtr<OggPacket> COggSplitterOutputPin::GetPacket()
00696 {
00697 CAutoPtr<OggPacket> p;
00698 CAutoLock csAutoLock(&m_csPackets);
00699 if(m_packets.GetCount()) p = m_packets.RemoveHead();
00700 return p;
00701 }
00702
00703 HRESULT COggSplitterOutputPin::DeliverEndFlush()
00704 {
00705 ResetState();
00706 return __super::DeliverEndFlush();
00707 }
00708
00709 HRESULT COggSplitterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
00710 {
00711 ResetState();
00712 return __super::DeliverNewSegment(tStart, tStop, dRate);
00713 }
00714
00715
00716
00717
00718
00719 COggVorbisOutputPin::COggVorbisOutputPin(OggVorbisIdHeader* h, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
00720 : COggSplitterOutputPin(pName, pFilter, pLock, phr)
00721 {
00722 m_audio_sample_rate = h->audio_sample_rate;
00723 m_blocksize[0] = 1<<h->blocksize_0;
00724 m_blocksize[1] = 1<<h->blocksize_1;
00725 m_lastblocksize = 0;
00726
00727 CMediaType mt;
00728
00729 mt.InitMediaType();
00730 mt.majortype = MEDIATYPE_Audio;
00731 mt.subtype = MEDIASUBTYPE_Vorbis;
00732 mt.formattype = FORMAT_VorbisFormat;
00733 VORBISFORMAT* vf = (VORBISFORMAT*)mt.AllocFormatBuffer(sizeof(VORBISFORMAT));
00734 memset(mt.Format(), 0, mt.FormatLength());
00735 vf->nChannels = h->audio_channels;
00736 vf->nSamplesPerSec = h->audio_sample_rate;
00737 vf->nAvgBitsPerSec = h->bitrate_nominal;
00738 vf->nMinBitsPerSec = h->bitrate_minimum;
00739 vf->nMaxBitsPerSec = h->bitrate_maximum;
00740 vf->fQuality = -1;
00741 mt.SetSampleSize(8192);
00742 m_mts.Add(mt);
00743
00744 mt.InitMediaType();
00745 mt.majortype = MEDIATYPE_Audio;
00746 mt.subtype = MEDIASUBTYPE_Vorbis2;
00747 mt.formattype = FORMAT_VorbisFormat2;
00748 VORBISFORMAT2* vf2 = (VORBISFORMAT2*)mt.AllocFormatBuffer(sizeof(VORBISFORMAT2));
00749 memset(mt.Format(), 0, mt.FormatLength());
00750 vf2->Channels = h->audio_channels;
00751 vf2->SamplesPerSec = h->audio_sample_rate;
00752 mt.SetSampleSize(8192);
00753 m_mts.InsertAt(0, mt);
00754 }
00755
00756 REFERENCE_TIME COggVorbisOutputPin::GetRefTime(__int64 granule_position)
00757 {
00758 REFERENCE_TIME rt = granule_position * 10000000 / m_audio_sample_rate;
00759 return rt;
00760 }
00761
00762 HRESULT COggVorbisOutputPin::UnpackInitPage(OggPage& page)
00763 {
00764 HRESULT hr = __super::UnpackPage(page);
00765
00766 while(m_packets.GetCount())
00767 {
00768 Packet* p = m_packets.GetHead();
00769
00770 if(p->pData.GetCount() >= 6 && p->pData.GetData()[0] == 0x05)
00771 {
00772
00773 bitstream bs(p->pData.GetData(), p->pData.GetCount(), true);
00774 while(bs.hasbits(-1) && bs.getbits(-1) != 1);
00775 for(int cnt = 0; bs.hasbits(-8-16-16-1-6); cnt++)
00776 {
00777 unsigned int modes = bs.showbits(-6)+1;
00778
00779 unsigned int mapping = bs.getbits(-8);
00780 unsigned int transformtype = bs.getbits(-16);
00781 unsigned int windowtype = bs.getbits(-16);
00782 unsigned int blockflag = bs.getbits(-1);
00783
00784 if(transformtype != 0 || windowtype != 0)
00785 {
00786 ASSERT(modes == cnt);
00787 break;
00788 }
00789
00790 m_blockflags.InsertAt(0, !!blockflag);
00791 }
00792 }
00793
00794 int cnt = m_initpackets.GetCount();
00795 if(cnt <= 3)
00796 {
00797 ASSERT(p->pData.GetCount() >= 6 && p->pData.GetData()[0] == 1+cnt*2);
00798 VORBISFORMAT2* vf2 = (VORBISFORMAT2*)m_mts[0].Format();
00799 vf2->HeaderSize[cnt] = p->pData.GetSize();
00800 int len = m_mts[0].FormatLength();
00801 memcpy(
00802 m_mts[0].ReallocFormatBuffer(len + p->pData.GetSize()) + len,
00803 p->pData.GetData(), p->pData.GetSize());
00804 }
00805
00806 m_initpackets.AddTail(m_packets.RemoveHead());
00807 }
00808
00809 return hr;
00810 }
00811
00812 HRESULT COggVorbisOutputPin::UnpackPacket(CAutoPtr<OggPacket>& p, BYTE* pData, int len)
00813 {
00814 if(len > 0 && m_blockflags.GetCount())
00815 {
00816 bitstream bs(pData, len);
00817 if(bs.getbits(1) == 0)
00818 {
00819 int x = m_blockflags.GetCount()-1, n = 0;
00820 while(x) {n++; x >>= 1;}
00821 DWORD blocksize = m_blocksize[m_blockflags[bs.getbits(n)]?1:0];
00822 if(m_lastblocksize) m_rtLast += GetRefTime((m_lastblocksize + blocksize) >> 2);
00823 m_lastblocksize = blocksize;
00824 }
00825 }
00826
00827 p->bSyncPoint = TRUE;
00828 p->rtStart = m_rtLast;
00829 p->rtStop = m_rtLast+1;
00830 p->pData.SetSize(len);
00831 memcpy(p->pData.GetData(), pData, len);
00832
00833 return S_OK;
00834 }
00835
00836 HRESULT COggVorbisOutputPin::DeliverPacket(CAutoPtr<OggPacket> p)
00837 {
00838 if(p->pData.GetSize() > 0 && (p->pData.GetData()[0]&1))
00839 return S_OK;
00840
00841 return __super::DeliverPacket(p);
00842 }
00843
00844 HRESULT COggVorbisOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
00845 {
00846 HRESULT hr = __super::DeliverNewSegment(tStart, tStop, dRate);
00847
00848 m_lastblocksize = 0;
00849
00850 if(m_mt.subtype == MEDIASUBTYPE_Vorbis)
00851 {
00852 POSITION pos = m_initpackets.GetHeadPosition();
00853 while(pos)
00854 {
00855 Packet* pi = m_initpackets.GetNext(pos);
00856 CAutoPtr<OggPacket> p(new OggPacket());
00857 p->TrackNumber = pi->TrackNumber;
00858 p->bDiscontinuity = p->bSyncPoint = TRUE;
00859 p->rtStart = p->rtStop = 0;
00860 p->pData.Copy(pi->pData);
00861 __super::DeliverPacket(p);
00862 }
00863 }
00864
00865 return hr;
00866 }
00867
00868
00869
00870
00871
00872 COggDirectShowOutputPin::COggDirectShowOutputPin(AM_MEDIA_TYPE* pmt, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
00873 : COggSplitterOutputPin(pName, pFilter, pLock, phr)
00874 {
00875 CMediaType mt;
00876 memcpy((AM_MEDIA_TYPE*)&mt, pmt, FIELD_OFFSET(AM_MEDIA_TYPE, pUnk));
00877 mt.SetFormat((BYTE*)(pmt+1), pmt->cbFormat);
00878 mt.SetSampleSize(1);
00879 if(mt.majortype == MEDIATYPE_Video)
00880 m_mts.Add(mt);
00881 }
00882
00883 REFERENCE_TIME COggDirectShowOutputPin::GetRefTime(__int64 granule_position)
00884 {
00885 REFERENCE_TIME rt = 0;
00886
00887 if(m_mt.majortype == MEDIATYPE_Video)
00888 {
00889 rt = granule_position * ((VIDEOINFOHEADER*)m_mt.Format())->AvgTimePerFrame;
00890 }
00891 else if(m_mt.majortype == MEDIATYPE_Audio)
00892 {
00893 rt = granule_position;
00894 }
00895
00896 return rt;
00897 }
00898
00899 HRESULT COggDirectShowOutputPin::UnpackPacket(CAutoPtr<OggPacket>& p, BYTE* pData, int len)
00900 {
00901 int i = 0;
00902
00903 BYTE hdr = pData[i++];
00904
00905 if(!(hdr&1))
00906 {
00907
00908 BYTE nLenBytes = (hdr>>6)|((hdr&2)<<1);
00909 __int64 Length = 0;
00910 for(int j = 0; j < nLenBytes; j++)
00911 Length |= (__int64)pData[i++] << (j << 3);
00912
00913
00914
00915 p->bSyncPoint = !!(hdr&8);
00916 p->rtStart = m_rtLast;
00917 p->rtStop = m_rtLast + (nLenBytes ? GetRefTime(Length) : GetRefTime(1));
00918 p->pData.SetSize(len - i);
00919 memcpy(p->pData.GetData(), &pData[i], len - i);
00920
00921 return S_OK;
00922 }
00923
00924 return S_FALSE;
00925 }
00926
00927
00928
00929
00930
00931 COggStreamOutputPin::COggStreamOutputPin(OggStreamHeader* h, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
00932 : COggSplitterOutputPin(pName, pFilter, pLock, phr)
00933 {
00934 m_time_unit = h->time_unit;
00935 m_samples_per_unit = h->samples_per_unit;
00936 m_default_len = h->default_len;
00937 }
00938
00939 REFERENCE_TIME COggStreamOutputPin::GetRefTime(__int64 granule_position)
00940 {
00941 return granule_position * m_time_unit / m_samples_per_unit;
00942 }
00943
00944 HRESULT COggStreamOutputPin::UnpackPacket(CAutoPtr<OggPacket>& p, BYTE* pData, int len)
00945 {
00946 int i = 0;
00947
00948 BYTE hdr = pData[i++];
00949
00950 if(!(hdr&1))
00951 {
00952 BYTE nLenBytes = (hdr>>6)|((hdr&2)<<1);
00953 __int64 Length = 0;
00954 for(int j = 0; j < nLenBytes; j++)
00955 Length |= (__int64)pData[i++] << (j << 3);
00956
00957
00958
00959 p->bSyncPoint = !!(hdr&8);
00960 p->rtStart = m_rtLast;
00961 p->rtStop = m_rtLast + (nLenBytes ? GetRefTime(Length) : GetRefTime(m_default_len));
00962 p->pData.SetSize(len - i);
00963 memcpy(p->pData.GetData(), &pData[i], len - i);
00964
00965 return S_OK;
00966 }
00967
00968 return S_FALSE;
00969 }
00970
00971
00972
00973
00974
00975 COggVideoOutputPin::COggVideoOutputPin(OggStreamHeader* h, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
00976 : COggStreamOutputPin(h, pName, pFilter, pLock, phr)
00977 {
00978 int extra = (int)h->size - sizeof(OggStreamHeader);
00979 extra = max(extra, 0);
00980
00981 CMediaType mt;
00982 mt.majortype = MEDIATYPE_Video;
00983 mt.subtype = FOURCCMap(MAKEFOURCC(h->subtype[0],h->subtype[1],h->subtype[2],h->subtype[3]));
00984 mt.formattype = FORMAT_VideoInfo;
00985 VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER) + extra);
00986 memset(mt.Format(), 0, mt.FormatLength());
00987 memcpy(mt.Format() + sizeof(VIDEOINFOHEADER), h+1, extra);
00988 pvih->AvgTimePerFrame = h->time_unit / h->samples_per_unit;
00989 pvih->bmiHeader.biWidth = h->v.w;
00990 pvih->bmiHeader.biHeight = h->v.h;
00991 pvih->bmiHeader.biBitCount = (WORD)h->bps;
00992 pvih->bmiHeader.biCompression = mt.subtype.Data1;
00993 switch(pvih->bmiHeader.biCompression)
00994 {
00995 case BI_RGB: case BI_BITFIELDS: mt.subtype =
00996 pvih->bmiHeader.biBitCount == 1 ? MEDIASUBTYPE_RGB1 :
00997 pvih->bmiHeader.biBitCount == 4 ? MEDIASUBTYPE_RGB4 :
00998 pvih->bmiHeader.biBitCount == 8 ? MEDIASUBTYPE_RGB8 :
00999 pvih->bmiHeader.biBitCount == 16 ? MEDIASUBTYPE_RGB565 :
01000 pvih->bmiHeader.biBitCount == 24 ? MEDIASUBTYPE_RGB24 :
01001 pvih->bmiHeader.biBitCount == 32 ? MEDIASUBTYPE_RGB32 :
01002 MEDIASUBTYPE_NULL;
01003 break;
01004 case BI_RLE8: mt.subtype = MEDIASUBTYPE_RGB8; break;
01005 case BI_RLE4: mt.subtype = MEDIASUBTYPE_RGB4; break;
01006 }
01007 mt.SetSampleSize(max(h->buffersize, 1));
01008 m_mts.Add(mt);
01009 }
01010
01011
01012
01013
01014
01015 COggAudioOutputPin::COggAudioOutputPin(OggStreamHeader* h, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
01016 : COggStreamOutputPin(h, pName, pFilter, pLock, phr)
01017 {
01018 int extra = (int)h->size - sizeof(OggStreamHeader);
01019 extra = max(extra, 0);
01020
01021 CMediaType mt;
01022 mt.majortype = MEDIATYPE_Audio;
01023 mt.subtype = FOURCCMap(strtol(CStringA(h->subtype, 4), NULL, 16));
01024 mt.formattype = FORMAT_WaveFormatEx;
01025 WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.AllocFormatBuffer(sizeof(WAVEFORMATEX) + extra);
01026 memset(mt.Format(), 0, mt.FormatLength());
01027 memcpy(mt.Format() + sizeof(WAVEFORMATEX), h+1, extra);
01028 wfe->cbSize = extra;
01029 wfe->wFormatTag = (WORD)mt.subtype.Data1;
01030 wfe->nChannels = h->a.nChannels;
01031 wfe->nSamplesPerSec = (DWORD)(10000000i64 * h->samples_per_unit / h->time_unit);
01032 wfe->wBitsPerSample = (WORD)h->bps;
01033 wfe->nAvgBytesPerSec = h->a.nAvgBytesPerSec;
01034 wfe->nBlockAlign = h->a.nBlockAlign;
01035 mt.SetSampleSize(max(h->buffersize, 1));
01036 m_mts.Add(mt);
01037 }
01038
01039
01040
01041
01042
01043 COggTextOutputPin::COggTextOutputPin(OggStreamHeader* h, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
01044 : COggStreamOutputPin(h, pName, pFilter, pLock, phr)
01045 {
01046 CMediaType mt;
01047 mt.majortype = MEDIATYPE_Text;
01048 mt.subtype = MEDIASUBTYPE_NULL;
01049 mt.formattype = FORMAT_None;
01050 mt.SetSampleSize(1);
01051 m_mts.Add(mt);
01052 }