00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "StdAfx.h"
00032 #include "OggDemuxPacketSourceFilter.h"
00033 #include "OggStreamMapper.h"
00034
00035
00036 CFactoryTemplate g_Templates[] =
00037 {
00038 {
00039 L"OggDemuxFilter",
00040 &CLSID_OggDemuxPacketSourceFilter,
00041 OggDemuxPacketSourceFilter::CreateInstance,
00042 NULL,
00043 NULL
00044 }
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 };
00057
00058
00059 int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
00060
00061
00062 CUnknown* WINAPI OggDemuxPacketSourceFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
00063 {
00064 OggDemuxPacketSourceFilter *pNewObject = new OggDemuxPacketSourceFilter();
00065 if (pNewObject == NULL) {
00066 *pHr = E_OUTOFMEMORY;
00067 }
00068 return pNewObject;
00069 }
00070
00071 STDMETHODIMP OggDemuxPacketSourceFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv)
00072 {
00073 if (riid == IID_IFileSourceFilter) {
00074 *ppv = (IFileSourceFilter*)this;
00075 ((IUnknown*)*ppv)->AddRef();
00076 return NOERROR;
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 } else if (riid == IID_IAMFilterMiscFlags) {
00087 *ppv = (IAMFilterMiscFlags*)this;
00088 ((IUnknown*)*ppv)->AddRef();
00089 return NOERROR;
00090
00091
00092
00093
00094
00095 } else if (riid == IID_IOggBaseTime) {
00096 *ppv = (IOggBaseTime*)this;
00097
00098 return NOERROR;
00099 }
00100
00101
00102
00103
00104 return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
00105 }
00106 OggDemuxPacketSourceFilter::OggDemuxPacketSourceFilter(void)
00107 : CBaseFilter(NAME("OggDemuxPacketSourceFilter"), NULL, m_pLock, CLSID_OggDemuxPacketSourceFilter)
00108 , mDataSource(NULL)
00109 , mSeenAllBOSPages(false)
00110 , mSeenPositiveGranulePos(false)
00111 , mPendingPage(NULL)
00112 , mJustReset(true)
00113 , mSeekTable(NULL)
00114 , mGlobalBaseTime(0)
00115 {
00116
00117 m_pLock = new CCritSec;
00118
00119 mSourceFileLock = new CCritSec;
00120 mDemuxLock = new CCritSec;
00121 mStreamLock = new CCritSec;
00122
00123 mStreamMapper = new OggStreamMapper(this, m_pLock);
00124
00125
00126 }
00127
00128 OggDemuxPacketSourceFilter::~OggDemuxPacketSourceFilter(void)
00129 {
00130 delete mStreamMapper;
00131 delete mSeekTable;
00132
00133
00134 delete mDemuxLock;
00135 delete mStreamLock;
00136 delete mSourceFileLock;
00137
00138 mDataSource->close();
00139 delete mDataSource;
00140 }
00141
00142 STDMETHODIMP OggDemuxPacketSourceFilter::Run(REFERENCE_TIME tStart)
00143 {
00144 CAutoLock locLock(m_pLock);
00145 return CBaseFilter::Run(tStart);
00146
00147
00148
00149 }
00150 STDMETHODIMP OggDemuxPacketSourceFilter::Pause(void)
00151 {
00152 CAutoLock locLock(m_pLock);
00153 if (m_State == State_Stopped) {
00154 if (ThreadExists() == FALSE) {
00155 Create();
00156 }
00157 CallWorker(THREAD_RUN);
00158 }
00159 HRESULT locHR = CBaseFilter::Pause();
00160
00161 return locHR;
00162
00163 }
00164 STDMETHODIMP OggDemuxPacketSourceFilter::Stop(void)
00165 {
00166 CAutoLock locLock(m_pLock);
00167 CallWorker(THREAD_EXIT);
00168 Close();
00169 DeliverBeginFlush();
00170
00171 DeliverEndFlush();
00172
00173 return CBaseFilter::Stop();
00174
00175
00176 }
00177 void OggDemuxPacketSourceFilter::DeliverBeginFlush()
00178 {
00179 CAutoLock locLock(m_pLock);
00180
00181 for (unsigned long i = 0; i < mStreamMapper->numPins(); i++) {
00182 mStreamMapper->getPinByIndex(i)->DeliverBeginFlush();
00183 }
00184
00185
00186
00187
00188 resetStream();
00189 }
00190
00191 void OggDemuxPacketSourceFilter::DeliverEndFlush()
00192 {
00193 CAutoLock locLock(m_pLock);
00194 for (unsigned long i = 0; i < mStreamMapper->numPins(); i++) {
00195
00196 mStreamMapper->getPinByIndex(i)->DeliverEndFlush();
00197 }
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 }
00216 void OggDemuxPacketSourceFilter::DeliverEOS()
00217 {
00218
00219
00220 for (unsigned long i = 0; i < mStreamMapper->numPins(); i++) {
00221
00222 mStreamMapper->getPinByIndex(i)->DeliverEndOfStream();
00223
00224 }
00225
00226 resetStream();
00227 }
00228
00229 void OggDemuxPacketSourceFilter::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
00230 {
00231
00232 for (unsigned long i = 0; i < mStreamMapper->numPins(); i++) {
00233 mStreamMapper->getPinByIndex(i)->DeliverNewSegment(tStart, tStop, dRate);
00234 }
00235 }
00236
00237 void OggDemuxPacketSourceFilter::resetStream() {
00238 {
00239 CAutoLock locDemuxLock(mDemuxLock);
00240 CAutoLock locSourceLock(mSourceFileLock);
00241
00242
00243 mDataSource->clear();
00244
00245 mDataSource->close();
00246 delete mDataSource;
00247 mDataSource = NULL;
00248
00249
00250 mOggBuffer.clearData();
00251
00252
00253 mDataSource = DataSourceFactory::createDataSource(StringHelper::toNarrowStr(mFileName).c_str());
00254
00255 mDataSource->open(StringHelper::toNarrowStr(mFileName).c_str());
00256 mDataSource->seek(0);
00257
00258
00259
00260 mJustReset = true;
00261 }
00262 }
00263 bool OggDemuxPacketSourceFilter::acceptOggPage(OggPage* inOggPage)
00264 {
00265 if (!mSeenAllBOSPages) {
00266 if (!inOggPage->header()->isBOS()) {
00267 mSeenAllBOSPages = true;
00268 mBufferedPages.push_back(inOggPage);
00269 return true;
00270 } else {
00271 return mStreamMapper->acceptOggPage(inOggPage);
00272 }
00273 } else if (!mSeenPositiveGranulePos) {
00274 if (inOggPage->header()->GranulePos() > 0) {
00275 mSeenPositiveGranulePos = true;
00276 }
00277 mBufferedPages.push_back(inOggPage);
00278 return true;
00279 } else {
00280
00281 return mStreamMapper->acceptOggPage(inOggPage);
00282 }
00283 }
00284 HRESULT OggDemuxPacketSourceFilter::SetUpPins()
00285 {
00286 CAutoLock locDemuxLock(mDemuxLock);
00287 CAutoLock locSourceLock(mSourceFileLock);
00288
00289 unsigned short locRetryCount = 0;
00290 const unsigned short RETRY_THRESHOLD = 3;
00291
00292
00293 mDataSource = DataSourceFactory::createDataSource(StringHelper::toNarrowStr(mFileName).c_str());
00294 mDataSource->open(StringHelper::toNarrowStr(mFileName).c_str());
00295
00296
00297
00298
00299 mOggBuffer.registerVirtualCallback(this);
00300
00301 char* locBuff = new char[SETUP_BUFFER_SIZE];
00302 unsigned long locNumRead = 0;
00303
00304
00305 while(!mSeenPositiveGranulePos) {
00306
00307 locNumRead = mDataSource->read(locBuff, SETUP_BUFFER_SIZE);
00308
00309 if (locNumRead > 0) {
00310 mOggBuffer.feed((const unsigned char*)locBuff, locNumRead);
00311 }
00312
00313 if (mDataSource->isEOF() || mDataSource->isError()) {
00314 if (mDataSource->isError() && (mDataSource->shouldRetryAt() != "") && (locRetryCount < RETRY_THRESHOLD)) {
00315 mOggBuffer.clearData();
00316 string locNewLocation = mDataSource->shouldRetryAt();
00317
00318 delete mDataSource;
00319 mDataSource = DataSourceFactory::createDataSource(locNewLocation.c_str());
00320 mDataSource->open(locNewLocation.c_str());
00321 locRetryCount++;
00322 } else {
00323
00324 delete[] locBuff;
00325 return VFW_E_CANNOT_RENDER;
00326 }
00327 }
00328 }
00329
00330
00331
00332 mOggBuffer.clearData();
00333 mDataSource->seek(0);
00334
00335
00336 delete[] locBuff;
00337 return S_OK;
00338
00339
00340 }
00341
00342 vector<OggPage*> OggDemuxPacketSourceFilter::getMatchingBufferedPages(unsigned long inSerialNo)
00343 {
00344 vector<OggPage*> locList;
00345 for (size_t i = 0; i < mBufferedPages.size(); i++) {
00346 if (mBufferedPages[i]->header()->StreamSerialNo() == inSerialNo) {
00347 locList.push_back(mBufferedPages[i]->clone());
00348 }
00349 }
00350 return locList;
00351 }
00352 void OggDemuxPacketSourceFilter::removeMatchingBufferedPages(unsigned long inSerialNo)
00353 {
00354 vector<OggPage*> locNewList;
00355 int locSize = mBufferedPages.size();
00356 for (int i = 0; i < locSize; i++) {
00357 if (mBufferedPages[i]->header()->StreamSerialNo() != inSerialNo) {
00358 locNewList.push_back(mBufferedPages[i]);
00359 } else {
00360 delete mBufferedPages[i];
00361 }
00362 }
00363 mBufferedPages = locNewList;
00364
00365 }
00366
00367
00368
00369 int OggDemuxPacketSourceFilter::GetPinCount()
00370 {
00371
00372 return mStreamMapper->numPins();
00373 }
00374 CBasePin* OggDemuxPacketSourceFilter::GetPin(int inPinNo)
00375 {
00376 if (inPinNo < 0) {
00377 return NULL;
00378 }
00379 return mStreamMapper->getPinByIndex(inPinNo);
00380 }
00381
00382
00383 STDMETHODIMP OggDemuxPacketSourceFilter::GetCurFile(LPOLESTR* outFileName, AM_MEDIA_TYPE* outMediaType)
00384 {
00386 LPOLESTR x = SysAllocString(mFileName.c_str());
00387 *outFileName = x;
00388
00389
00390
00391 return S_OK;
00392 }
00393
00394
00395 STDMETHODIMP OggDemuxPacketSourceFilter::Load(LPCOLESTR inFileName, const AM_MEDIA_TYPE* inMediaType)
00396 {
00398 CAutoLock locLock(m_pLock);
00399
00400
00401
00402 mFileName = inFileName;
00403
00404 if (mFileName.find(L"XsZZfQ__WiiPFD.anx") == mFileName.size() - 18){
00405 mFileName = mFileName.substr(0, mFileName.size() - 18);
00406
00407 }
00408
00409
00410
00411
00412
00413
00414
00415 HRESULT locHR = SetUpPins();
00416
00417 if (locHR == S_OK) {
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 return S_OK;
00430 } else {
00431 return locHR;
00432 }
00433
00434
00435
00436 }
00437
00438
00439 ULONG OggDemuxPacketSourceFilter::GetMiscFlags(void)
00440 {
00441 return AM_FILTER_MISC_FLAGS_IS_SOURCE;
00442 }
00443
00444
00445 DWORD OggDemuxPacketSourceFilter::ThreadProc(void) {
00446
00447 while(true) {
00448 DWORD locThreadCommand = GetRequest();
00449
00450 switch(locThreadCommand) {
00451 case THREAD_EXIT:
00452
00453 Reply(S_OK);
00454 return S_OK;
00455
00456 case THREAD_RUN:
00457
00458 Reply(S_OK);
00459 DataProcessLoop();
00460 break;
00461 }
00462 }
00463 return S_OK;
00464 }
00465
00466 void OggDemuxPacketSourceFilter::notifyPinConnected()
00467 {
00468 if (mStreamMapper->allStreamsReady()) {
00469
00470 if (mSeekTable == NULL) {
00471 mSeekTable = new AutoOggChainGranuleSeekTable(StringHelper::toNarrowStr(mFileName));
00472 int locNumPins = GetPinCount();
00473
00474 OggDemuxPacketSourcePin* locPin = NULL;
00475 for (int i = 0; i < locNumPins; i++) {
00476 locPin = (OggDemuxPacketSourcePin*)GetPin(i);
00477
00478
00479 mSeekTable->addStream(locPin->getSerialNo(), locPin->getDecoderInterface());
00480 }
00481 mSeekTable->buildTable();
00482 }
00483 }
00484 }
00485 HRESULT OggDemuxPacketSourceFilter::DataProcessLoop()
00486 {
00487
00488
00489
00490
00491 DWORD locCommand = 0;
00492 char* locBuff = new char[4096];
00493
00494 bool locKeepGoing = true;
00495 unsigned long locBytesRead = 0;
00496 bool locIsEOF = true;
00497 {
00498 CAutoLock locSourceLock(mSourceFileLock);
00499 locIsEOF = mDataSource->isEOF();
00500 }
00501
00502 while(true) {
00503 if(CheckRequest(&locCommand) == TRUE) {
00504
00505 delete[] locBuff;
00506 return S_OK;
00507 }
00508
00509 {
00510 CAutoLock locSourceLock(mSourceFileLock);
00511
00512
00513 locBytesRead = mDataSource->read(locBuff, 4096);
00514 mJustReset = false;
00515 }
00516
00517 {
00518 CAutoLock locDemuxLock(mDemuxLock);
00519
00520 if (mJustReset) {
00521 continue;
00522 }
00523 locKeepGoing = ((mOggBuffer.feed((const unsigned char*)locBuff, locBytesRead)) == (OggDataBuffer::FEED_OK));;
00524 }
00525 if (!locKeepGoing) {
00526
00527
00528 DeliverEOS();
00529 }
00530 {
00531 CAutoLock locSourceLock(mSourceFileLock);
00532 locIsEOF = mDataSource->isEOF();
00533 }
00534 if (locIsEOF) {
00535
00536
00537 DeliverEOS();
00538 }
00539 }
00540
00541
00542
00543
00544 delete[] locBuff;
00545
00546
00547 return S_OK;
00548 }
00549
00550
00551
00552
00553 STDMETHODIMP OggDemuxPacketSourceFilter::GetCapabilities(DWORD* inCapabilities)
00554 {
00555 if ((mSeekTable != NULL) && (mSeekTable->enabled())) {
00556
00557 *inCapabilities = mSeekingCap;
00558 return S_OK;
00559 } else {
00560
00561 *inCapabilities = 0;
00562 return S_OK;;
00563 }
00564 }
00565 STDMETHODIMP OggDemuxPacketSourceFilter::GetDuration(LONGLONG* outDuration)
00566 {
00567 if ((mSeekTable != NULL) && (mSeekTable->enabled())) {
00568
00569 *outDuration = mSeekTable->fileDuration();
00570 return S_OK;
00571 } else {
00572 return E_NOTIMPL;
00573 }
00574
00575
00576 }
00577
00578 STDMETHODIMP OggDemuxPacketSourceFilter::CheckCapabilities(DWORD *pCapabilities)
00579 {
00580
00581
00582
00583 return E_NOTIMPL;
00584 }
00585 STDMETHODIMP OggDemuxPacketSourceFilter::IsFormatSupported(const GUID *pFormat)
00586 {
00587
00588 if (*pFormat == TIME_FORMAT_MEDIA_TIME) {
00589
00590 return S_OK;
00591 } else {
00592
00593 return S_FALSE;
00594 }
00595
00596
00597
00598 }
00599 STDMETHODIMP OggDemuxPacketSourceFilter::QueryPreferredFormat(GUID *pFormat){
00600
00601 *pFormat = TIME_FORMAT_MEDIA_TIME;
00602 return S_OK;
00603 }
00604 STDMETHODIMP OggDemuxPacketSourceFilter::SetTimeFormat(const GUID *pFormat){
00605
00606 return E_NOTIMPL;
00607 }
00608 STDMETHODIMP OggDemuxPacketSourceFilter::GetTimeFormat( GUID *pFormat){
00609 *pFormat = TIME_FORMAT_MEDIA_TIME;
00610 return S_OK;
00611 }
00612 STDMETHODIMP OggDemuxPacketSourceFilter::GetStopPosition(LONGLONG *pStop){
00613 if ((mSeekTable != NULL) && (mSeekTable->enabled())) {
00614
00615
00616 *pStop = mSeekTable->fileDuration();
00617 return S_OK;
00618 } else {
00619
00620 return E_NOTIMPL;
00621 }
00622
00623
00624
00625 }
00626 STDMETHODIMP OggDemuxPacketSourceFilter::GetCurrentPosition(LONGLONG *pCurrent)
00627 {
00628
00629
00630
00631 return E_NOTIMPL;
00632 }
00633 STDMETHODIMP OggDemuxPacketSourceFilter::ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat){
00634
00635 return E_NOTIMPL;
00636 }
00637 STDMETHODIMP OggDemuxPacketSourceFilter::SetPositions(LONGLONG *pCurrent,DWORD dwCurrentFlags,LONGLONG *pStop,DWORD dwStopFlags){
00638
00639
00640 CAutoLock locLock(m_pLock);
00641
00642 if ((mSeekTable != NULL) && (mSeekTable->enabled())) {
00643
00644 CAutoLock locSourceLock(mSourceFileLock);
00645 DeliverBeginFlush();
00646
00647
00648 if (*pCurrent > mSeekTable->fileDuration()) {
00649 *pCurrent = mSeekTable->fileDuration();
00650 } else if (*pCurrent < 0) {
00651 *pCurrent = 0;
00652 }
00653
00654 OggGranuleSeekTable::tSeekPair locStartPos = mSeekTable->seekPos(*pCurrent);
00655
00656
00657
00658
00659
00660
00661
00662 {
00663
00664 DeliverEndFlush();
00665
00666 DeliverNewSegment(*pCurrent, mSeekTable->fileDuration(), 1.0);
00667 }
00668
00669
00670 mDataSource->seek(locStartPos.second.first);
00671
00672 return S_OK;
00673 } else {
00674
00675 return E_NOTIMPL;
00676 }
00677
00678
00679
00680 }
00681 STDMETHODIMP OggDemuxPacketSourceFilter::GetPositions(LONGLONG *pCurrent, LONGLONG *pStop)
00682 {
00683
00684
00685 return E_NOTIMPL;
00686 }
00687 STDMETHODIMP OggDemuxPacketSourceFilter::GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest){
00688
00689 if ((mSeekTable != NULL) && (mSeekTable->enabled())) {
00690
00691 *pEarliest = 0;
00692
00693 *pLatest = mSeekTable->fileDuration();
00694 return S_OK;
00695 } else {
00696 return E_NOTIMPL;
00697 }
00698
00699
00700 }
00701 STDMETHODIMP OggDemuxPacketSourceFilter::SetRate(double dRate)
00702 {
00703
00704
00705 return E_NOTIMPL;
00706 }
00707 STDMETHODIMP OggDemuxPacketSourceFilter::GetRate(double *dRate)
00708 {
00709
00710 *dRate = 1.0;
00711 return S_OK;;
00712 }
00713 STDMETHODIMP OggDemuxPacketSourceFilter::GetPreroll(LONGLONG *pllPreroll)
00714 {
00715
00716 *pllPreroll = 0;
00717
00718 return S_OK;
00719 }
00720 STDMETHODIMP OggDemuxPacketSourceFilter::IsUsingTimeFormat(const GUID *pFormat) {
00721 if (*pFormat == TIME_FORMAT_MEDIA_TIME) {
00722
00723 return S_OK;
00724 } else {
00725
00726 return S_FALSE;
00727 }
00728
00729
00730 }
00731
00732
00733
00734 bool OggDemuxPacketSourceFilter::notifyStreamBaseTime(__int64 inStreamBaseTime)
00735 {
00736 if (inStreamBaseTime > mGlobalBaseTime) {
00737 mGlobalBaseTime = inStreamBaseTime;
00738 }
00739 return true;
00740 }
00741 __int64 OggDemuxPacketSourceFilter::getGlobalBaseTime()
00742 {
00743 return mGlobalBaseTime;
00744 }
00745
00746