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 "..\..\..\DSUtil\DSUtil.h"
00024 #include <initguid.h>
00025 #include "..\..\..\..\include\moreuuids.h"
00026 #include "..\..\..\..\include\matroska\matroska.h"
00027 #include "..\..\switcher\AudioSwitcher\AudioSwitcher.h"
00028 #include "BaseSplitter.h"
00029
00030 #pragma warning(disable: 4355)
00031
00032 #define MINPACKETS 10
00033 #define MINPACKETSIZE 100*1024
00034 #define MAXPACKETS 10000
00035 #define MAXPACKETSIZE 1024*1024*5
00036
00037
00038
00039
00040
00041 CPacketQueue::CPacketQueue() : m_size(0)
00042 {
00043 }
00044
00045 void CPacketQueue::Add(CAutoPtr<Packet> p)
00046 {
00047 CAutoLock cAutoLock(this);
00048
00049 if(p)
00050 {
00051 m_size += p->GetSize();
00052
00053 if(p->bAppendable && !p->bDiscontinuity && !p->pmt && GetCount() > 0
00054 && p->rtStart == Packet::INVALID_TIME
00055 && GetTail()->rtStart != Packet::INVALID_TIME)
00056 {
00057 Packet* tail = GetTail();
00058 int oldsize = tail->pData.GetSize();
00059 int newsize = tail->pData.GetSize() + p->pData.GetSize();
00060 tail->pData.SetSize(newsize, max(1024, newsize));
00061 memcpy(tail->pData.GetData() + oldsize, p->pData.GetData(), p->pData.GetSize());
00062 return;
00063 }
00064 }
00065
00066 AddTail(p);
00067 }
00068
00069 CAutoPtr<Packet> CPacketQueue::Remove()
00070 {
00071 CAutoLock cAutoLock(this);
00072 ASSERT(__super::GetCount() > 0);
00073 CAutoPtr<Packet> p = RemoveHead();
00074 if(p) m_size -= p->GetSize();
00075 return p;
00076 }
00077
00078 void CPacketQueue::RemoveAll()
00079 {
00080 CAutoLock cAutoLock(this);
00081 m_size = 0;
00082 __super::RemoveAll();
00083 }
00084
00085 int CPacketQueue::GetCount()
00086 {
00087 CAutoLock cAutoLock(this);
00088 return __super::GetCount();
00089 }
00090
00091 int CPacketQueue::GetSize()
00092 {
00093 CAutoLock cAutoLock(this);
00094 return m_size;
00095 }
00096
00097
00098
00099
00100
00101 CBaseSplitterInputPin::CBaseSplitterInputPin(TCHAR* pName, CBaseSplitterFilter* pFilter, CCritSec* pLock, HRESULT* phr)
00102 : CBasePin(pName, pFilter, pLock, phr, L"Input", PINDIR_INPUT)
00103 {
00104 }
00105
00106 CBaseSplitterInputPin::~CBaseSplitterInputPin()
00107 {
00108 }
00109
00110 HRESULT CBaseSplitterInputPin::GetAsyncReader(IAsyncReader** ppAsyncReader)
00111 {
00112 CheckPointer(ppAsyncReader, E_POINTER);
00113 *ppAsyncReader = NULL;
00114 CheckPointer(m_pAsyncReader, VFW_E_NOT_CONNECTED);
00115 (*ppAsyncReader = m_pAsyncReader)->AddRef();
00116 return S_OK;
00117 }
00118
00119 STDMETHODIMP CBaseSplitterInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00120 {
00121 CheckPointer(ppv, E_POINTER);
00122
00123 return
00124 __super::NonDelegatingQueryInterface(riid, ppv);
00125 }
00126
00127 HRESULT CBaseSplitterInputPin::CheckMediaType(const CMediaType* pmt)
00128 {
00129 return S_OK;
00130
00131
00132
00133
00134
00135 }
00136
00137 HRESULT CBaseSplitterInputPin::CheckConnect(IPin* pPin)
00138 {
00139 HRESULT hr;
00140 if(FAILED(hr = __super::CheckConnect(pPin)))
00141 return hr;
00142
00143 return CComQIPtr<IAsyncReader>(pPin) ? S_OK : E_NOINTERFACE;
00144 }
00145
00146 HRESULT CBaseSplitterInputPin::BreakConnect()
00147 {
00148 HRESULT hr;
00149
00150 if(FAILED(hr = __super::BreakConnect()))
00151 return hr;
00152
00153 if(FAILED(hr = ((CBaseSplitterFilter*)m_pFilter)->BreakConnect(PINDIR_INPUT, this)))
00154 return hr;
00155
00156 m_pAsyncReader.Release();
00157
00158 return S_OK;
00159 }
00160
00161 HRESULT CBaseSplitterInputPin::CompleteConnect(IPin* pPin)
00162 {
00163 HRESULT hr;
00164
00165 if(FAILED(hr = __super::CompleteConnect(pPin)))
00166 return hr;
00167
00168 CheckPointer(pPin, E_POINTER);
00169 m_pAsyncReader = pPin;
00170 CheckPointer(m_pAsyncReader, E_NOINTERFACE);
00171
00172 if(FAILED(hr = ((CBaseSplitterFilter*)m_pFilter)->CompleteConnect(PINDIR_INPUT, this)))
00173 return hr;
00174
00175 return S_OK;
00176 }
00177
00178 STDMETHODIMP CBaseSplitterInputPin::BeginFlush()
00179 {
00180 return E_UNEXPECTED;
00181 }
00182
00183 STDMETHODIMP CBaseSplitterInputPin::EndFlush()
00184 {
00185 return E_UNEXPECTED;
00186 }
00187
00188
00189
00190
00191
00192 CBaseSplitterOutputPin::CBaseSplitterOutputPin(CArray<CMediaType>& mts, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers)
00193 : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName)
00194 , m_hrDeliver(S_OK)
00195 , m_fFlushing(false)
00196 , m_eEndFlush(TRUE)
00197 {
00198 m_mts.Copy(mts);
00199 m_nBuffers = max(nBuffers, 1);
00200 memset(&m_brs, 0, sizeof(m_brs));
00201 m_brs.rtLastDeliverTime = Packet::INVALID_TIME;
00202 }
00203
00204 CBaseSplitterOutputPin::CBaseSplitterOutputPin(LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int nBuffers)
00205 : CBaseOutputPin(NAME("CBaseSplitterOutputPin"), pFilter, pLock, phr, pName)
00206 , m_hrDeliver(S_OK)
00207 , m_fFlushing(false)
00208 , m_eEndFlush(TRUE)
00209 {
00210 m_nBuffers = max(nBuffers, 1);
00211 memset(&m_brs, 0, sizeof(m_brs));
00212 m_brs.rtLastDeliverTime = Packet::INVALID_TIME;
00213 }
00214
00215 CBaseSplitterOutputPin::~CBaseSplitterOutputPin()
00216 {
00217 }
00218
00219 STDMETHODIMP CBaseSplitterOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00220 {
00221 CheckPointer(ppv, E_POINTER);
00222
00223 return
00224
00225 QI(IMediaSeeking)
00226 QI(IPropertyBag)
00227 QI(IPropertyBag2)
00228 QI(IDSMPropertyBag)
00229 QI(IBitRateInfo)
00230 __super::NonDelegatingQueryInterface(riid, ppv);
00231 }
00232
00233 HRESULT CBaseSplitterOutputPin::SetName(LPCWSTR pName)
00234 {
00235 CheckPointer(pName, E_POINTER);
00236 if(m_pName) delete [] m_pName;
00237 m_pName = new WCHAR[wcslen(pName)+1];
00238 CheckPointer(m_pName, E_OUTOFMEMORY);
00239 wcscpy(m_pName, pName);
00240 return S_OK;
00241 }
00242
00243 HRESULT CBaseSplitterOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties)
00244 {
00245 ASSERT(pAlloc);
00246 ASSERT(pProperties);
00247
00248 HRESULT hr = NOERROR;
00249
00250 pProperties->cBuffers = m_nBuffers;
00251 pProperties->cbBuffer = max(m_mt.lSampleSize, 1);
00252
00253 ALLOCATOR_PROPERTIES Actual;
00254 if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) return hr;
00255
00256 if(Actual.cbBuffer < pProperties->cbBuffer) return E_FAIL;
00257 ASSERT(Actual.cBuffers == pProperties->cBuffers);
00258
00259 return NOERROR;
00260 }
00261
00262 HRESULT CBaseSplitterOutputPin::CheckMediaType(const CMediaType* pmt)
00263 {
00264 for(int i = 0; i < m_mts.GetCount(); i++)
00265 {
00266 if(*pmt == m_mts[i])
00267 return S_OK;
00268 }
00269
00270 return E_INVALIDARG;
00271 }
00272
00273 HRESULT CBaseSplitterOutputPin::GetMediaType(int iPosition, CMediaType* pmt)
00274 {
00275 CAutoLock cAutoLock(m_pLock);
00276
00277 if(iPosition < 0) return E_INVALIDARG;
00278 if(iPosition >= m_mts.GetCount()) return VFW_S_NO_MORE_ITEMS;
00279
00280 *pmt = m_mts[iPosition];
00281
00282 return S_OK;
00283 }
00284
00285 STDMETHODIMP CBaseSplitterOutputPin::Notify(IBaseFilter* pSender, Quality q)
00286 {
00287 return E_NOTIMPL;
00288 }
00289
00290
00291
00292 HRESULT CBaseSplitterOutputPin::Active()
00293 {
00294 CAutoLock cAutoLock(m_pLock);
00295
00296 if(m_Connected)
00297 Create();
00298
00299 return __super::Active();
00300 }
00301
00302 HRESULT CBaseSplitterOutputPin::Inactive()
00303 {
00304 CAutoLock cAutoLock(m_pLock);
00305
00306 if(ThreadExists())
00307 CallWorker(CMD_EXIT);
00308
00309 return __super::Inactive();
00310 }
00311
00312 HRESULT CBaseSplitterOutputPin::DeliverBeginFlush()
00313 {
00314 m_eEndFlush.Reset();
00315 m_fFlushed = false;
00316 m_fFlushing = true;
00317 m_hrDeliver = S_FALSE;
00318 m_queue.RemoveAll();
00319 HRESULT hr = IsConnected() ? GetConnected()->BeginFlush() : S_OK;
00320 if(S_OK != hr) m_eEndFlush.Set();
00321 return(hr);
00322 }
00323
00324 HRESULT CBaseSplitterOutputPin::DeliverEndFlush()
00325 {
00326 if(!ThreadExists()) return S_FALSE;
00327 HRESULT hr = IsConnected() ? GetConnected()->EndFlush() : S_OK;
00328 m_hrDeliver = S_OK;
00329 m_fFlushing = false;
00330 m_fFlushed = true;
00331 m_eEndFlush.Set();
00332 return hr;
00333 }
00334
00335 HRESULT CBaseSplitterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
00336 {
00337 m_brs.rtLastDeliverTime = Packet::INVALID_TIME;
00338 if(m_fFlushing) return S_FALSE;
00339 m_rtStart = tStart;
00340 if(!ThreadExists()) return S_FALSE;
00341 HRESULT hr = __super::DeliverNewSegment(tStart, tStop, dRate);
00342 if(S_OK != hr) return hr;
00343 MakeISCRHappy();
00344 return hr;
00345 }
00346
00347 int CBaseSplitterOutputPin::QueueCount()
00348 {
00349 return m_queue.GetCount();
00350 }
00351
00352 int CBaseSplitterOutputPin::QueueSize()
00353 {
00354 return m_queue.GetSize();
00355 }
00356
00357 HRESULT CBaseSplitterOutputPin::QueueEndOfStream()
00358 {
00359 return QueuePacket(CAutoPtr<Packet>());
00360 }
00361
00362 HRESULT CBaseSplitterOutputPin::QueuePacket(CAutoPtr<Packet> p)
00363 {
00364 if(!ThreadExists()) return S_FALSE;
00365
00366 while(S_OK == m_hrDeliver
00367 && (!((CBaseSplitterFilter*)m_pFilter)->IsAnyPinDrying()
00368 || m_queue.GetSize() > MAXPACKETSIZE*100))
00369 Sleep(1);
00370
00371 if(S_OK != m_hrDeliver)
00372 return m_hrDeliver;
00373
00374 m_queue.Add(p);
00375
00376 return m_hrDeliver;
00377 }
00378
00379 bool CBaseSplitterOutputPin::IsDiscontinuous()
00380 {
00381 return m_mt.majortype == MEDIATYPE_Text
00382 || m_mt.majortype == MEDIATYPE_ScriptCommand
00383 || m_mt.majortype == MEDIATYPE_Subtitle
00384 || m_mt.subtype == MEDIASUBTYPE_DVD_SUBPICTURE
00385 || m_mt.subtype == MEDIASUBTYPE_CVD_SUBPICTURE
00386 || m_mt.subtype == MEDIASUBTYPE_SVCD_SUBPICTURE;
00387 }
00388
00389 bool CBaseSplitterOutputPin::IsActive()
00390 {
00391 CComPtr<IPin> pPin = this;
00392 do
00393 {
00394 CComPtr<IPin> pPinTo;
00395 CComQIPtr<IStreamSwitcherInputPin> pSSIP;
00396 if(S_OK == pPin->ConnectedTo(&pPinTo) && (pSSIP = pPinTo) && !pSSIP->IsActive())
00397 return(false);
00398 pPin = GetFirstPin(GetFilterFromPin(pPinTo), PINDIR_OUTPUT);
00399 }
00400 while(pPin);
00401
00402 return(true);
00403 }
00404
00405 DWORD CBaseSplitterOutputPin::ThreadProc()
00406 {
00407 m_hrDeliver = S_OK;
00408 m_fFlushing = m_fFlushed = false;
00409 m_eEndFlush.Set();
00410
00411 while(1)
00412 {
00413 Sleep(1);
00414
00415 DWORD cmd;
00416 if(CheckRequest(&cmd))
00417 {
00418 m_hThread = NULL;
00419 cmd = GetRequest();
00420 Reply(S_OK);
00421 ASSERT(cmd == CMD_EXIT);
00422 return 0;
00423 }
00424
00425 int cnt = 0;
00426 do
00427 {
00428 CAutoPtr<Packet> p;
00429
00430 {
00431 CAutoLock cAutoLock(&m_queue);
00432 if((cnt = m_queue.GetCount()) > 0)
00433 p = m_queue.Remove();
00434 }
00435
00436 if(S_OK == m_hrDeliver && cnt > 0)
00437 {
00438 ASSERT(!m_fFlushing);
00439
00440 m_fFlushed = false;
00441
00442
00443
00444 HRESULT hr = p
00445 ? DeliverPacket(p)
00446 : DeliverEndOfStream();
00447
00448 m_eEndFlush.Wait();
00449
00450 if(hr != S_OK && !m_fFlushed)
00451 {
00452
00453 m_hrDeliver = hr;
00454 break;
00455 }
00456 }
00457 }
00458 while(--cnt > 0);
00459 }
00460 }
00461
00462 HRESULT CBaseSplitterOutputPin::DeliverPacket(CAutoPtr<Packet> p)
00463 {
00464 HRESULT hr;
00465
00466 INT_PTR nBytes = p->pData.GetCount();
00467
00468 if(nBytes == 0)
00469 {
00470 return S_OK;
00471 }
00472
00473 m_brs.nBytesSinceLastDeliverTime += nBytes;
00474
00475 if(p->rtStart != Packet::INVALID_TIME)
00476 {
00477 if(m_brs.rtLastDeliverTime == Packet::INVALID_TIME)
00478 {
00479 m_brs.rtLastDeliverTime = p->rtStart;
00480 m_brs.nBytesSinceLastDeliverTime = 0;
00481 }
00482
00483 if(m_brs.rtLastDeliverTime + 10000000 < p->rtStart)
00484 {
00485 REFERENCE_TIME rtDiff = p->rtStart - m_brs.rtLastDeliverTime;
00486
00487 double secs, bits;
00488
00489 secs = (double)rtDiff / 10000000;
00490 bits = 8.0 * m_brs.nBytesSinceLastDeliverTime;
00491 m_brs.nCurrentBitRate = (DWORD)(bits / secs);
00492
00493 m_brs.rtTotalTimeDelivered += rtDiff;
00494 m_brs.nTotalBytesDelivered += m_brs.nBytesSinceLastDeliverTime;
00495
00496 secs = (double)m_brs.rtTotalTimeDelivered / 10000000;
00497 bits = 8.0 * m_brs.nTotalBytesDelivered;
00498 m_brs.nAverageBitRate = (DWORD)(bits / secs);
00499
00500 m_brs.rtLastDeliverTime = p->rtStart;
00501 m_brs.nBytesSinceLastDeliverTime = 0;
00502
00503
00504
00505
00506
00507
00508 }
00509
00510 double dRate = 1.0;
00511 if(SUCCEEDED(((CBaseSplitterFilter*)m_pFilter)->GetRate(&dRate)))
00512 {
00513 p->rtStart = (REFERENCE_TIME)((double)p->rtStart / dRate);
00514 p->rtStop = (REFERENCE_TIME)((double)p->rtStop / dRate);
00515 }
00516 }
00517
00518 do
00519 {
00520 CComPtr<IMediaSample> pSample;
00521 if(S_OK != (hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0))) break;
00522
00523 if(nBytes > pSample->GetSize())
00524 {
00525 pSample.Release();
00526
00527 ALLOCATOR_PROPERTIES props, actual;
00528 if(S_OK != (hr = m_pAllocator->GetProperties(&props))) break;
00529 props.cbBuffer = nBytes*3/2;
00530
00531 if(props.cBuffers > 1)
00532 {
00533 if(S_OK != (hr = __super::DeliverBeginFlush())) break;
00534 if(S_OK != (hr = __super::DeliverEndFlush())) break;
00535 }
00536
00537 if(S_OK != (hr = m_pAllocator->Decommit())) break;
00538 if(S_OK != (hr = m_pAllocator->SetProperties(&props, &actual))) break;
00539 if(S_OK != (hr = m_pAllocator->Commit())) break;
00540 if(S_OK != (hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0))) break;
00541 }
00542
00543 if(p->pmt)
00544 {
00545 pSample->SetMediaType(p->pmt);
00546 p->bDiscontinuity = true;
00547
00548 CAutoLock cAutoLock(m_pLock);
00549 m_mts.RemoveAll();
00550 m_mts.Add(*p->pmt);
00551 }
00552
00553 bool fTimeValid = p->rtStart != Packet::INVALID_TIME;
00554
00555
00556
00557
00558
00559
00560
00561
00562 ASSERT(!p->bSyncPoint || fTimeValid);
00563
00564 BYTE* pData = NULL;
00565 if(S_OK != (hr = pSample->GetPointer(&pData)) || !pData) break;
00566 memcpy(pData, p->pData.GetData(), nBytes);
00567 if(S_OK != (hr = pSample->SetActualDataLength(nBytes))) break;
00568 if(S_OK != (hr = pSample->SetTime(fTimeValid ? &p->rtStart : NULL, fTimeValid ? &p->rtStop : NULL))) break;
00569 if(S_OK != (hr = pSample->SetMediaTime(NULL, NULL))) break;
00570 if(S_OK != (hr = pSample->SetDiscontinuity(p->bDiscontinuity))) break;
00571 if(S_OK != (hr = pSample->SetSyncPoint(p->bSyncPoint))) break;
00572 if(S_OK != (hr = pSample->SetPreroll(fTimeValid && p->rtStart < 0))) break;
00573 if(S_OK != (hr = Deliver(pSample))) break;
00574 }
00575 while(false);
00576
00577 return hr;
00578 }
00579
00580 void CBaseSplitterOutputPin::MakeISCRHappy()
00581 {
00582 CComPtr<IPin> pPinTo = this, pTmp;
00583 while(pPinTo && SUCCEEDED(pPinTo->ConnectedTo(&pTmp)) && (pPinTo = pTmp))
00584 {
00585 pTmp = NULL;
00586
00587 CComPtr<IBaseFilter> pBF = GetFilterFromPin(pPinTo);
00588
00589 if(GetCLSID(pBF) == GUIDFromCString(_T("{48025243-2D39-11CE-875D-00608CB78066}")))
00590 {
00591 CAutoPtr<Packet> p(new Packet());
00592 p->TrackNumber = (DWORD)-1;
00593 p->rtStart = -1; p->rtStop = 0;
00594 p->bSyncPoint = FALSE;
00595 p->pData.SetSize(2);
00596 strcpy((char*)p->pData.GetData(), " ");
00597 QueuePacket(p);
00598 break;
00599 }
00600
00601 pPinTo = GetFirstPin(pBF, PINDIR_OUTPUT);
00602 }
00603 }
00604
00605 HRESULT CBaseSplitterOutputPin::GetDeliveryBuffer(IMediaSample** ppSample, REFERENCE_TIME* pStartTime, REFERENCE_TIME* pEndTime, DWORD dwFlags)
00606 {
00607 return __super::GetDeliveryBuffer(ppSample, pStartTime, pEndTime, dwFlags);
00608 }
00609
00610 HRESULT CBaseSplitterOutputPin::Deliver(IMediaSample* pSample)
00611 {
00612 return __super::Deliver(pSample);
00613 }
00614
00615
00616
00617 STDMETHODIMP CBaseSplitterOutputPin::GetCapabilities(DWORD* pCapabilities)
00618 {
00619 return ((CBaseSplitterFilter*)m_pFilter)->GetCapabilities(pCapabilities);
00620 }
00621 STDMETHODIMP CBaseSplitterOutputPin::CheckCapabilities(DWORD* pCapabilities)
00622 {
00623 return ((CBaseSplitterFilter*)m_pFilter)->CheckCapabilities(pCapabilities);
00624 }
00625 STDMETHODIMP CBaseSplitterOutputPin::IsFormatSupported(const GUID* pFormat)
00626 {
00627 return ((CBaseSplitterFilter*)m_pFilter)->IsFormatSupported(pFormat);
00628 }
00629 STDMETHODIMP CBaseSplitterOutputPin::QueryPreferredFormat(GUID* pFormat)
00630 {
00631 return ((CBaseSplitterFilter*)m_pFilter)->QueryPreferredFormat(pFormat);
00632 }
00633 STDMETHODIMP CBaseSplitterOutputPin::GetTimeFormat(GUID* pFormat)
00634 {
00635 return ((CBaseSplitterFilter*)m_pFilter)->GetTimeFormat(pFormat);
00636 }
00637 STDMETHODIMP CBaseSplitterOutputPin::IsUsingTimeFormat(const GUID* pFormat)
00638 {
00639 return ((CBaseSplitterFilter*)m_pFilter)->IsUsingTimeFormat(pFormat);
00640 }
00641 STDMETHODIMP CBaseSplitterOutputPin::SetTimeFormat(const GUID* pFormat)
00642 {
00643 return ((CBaseSplitterFilter*)m_pFilter)->SetTimeFormat(pFormat);
00644 }
00645 STDMETHODIMP CBaseSplitterOutputPin::GetDuration(LONGLONG* pDuration)
00646 {
00647 return ((CBaseSplitterFilter*)m_pFilter)->GetDuration(pDuration);
00648 }
00649 STDMETHODIMP CBaseSplitterOutputPin::GetStopPosition(LONGLONG* pStop)
00650 {
00651 return ((CBaseSplitterFilter*)m_pFilter)->GetStopPosition(pStop);
00652 }
00653 STDMETHODIMP CBaseSplitterOutputPin::GetCurrentPosition(LONGLONG* pCurrent)
00654 {
00655 return ((CBaseSplitterFilter*)m_pFilter)->GetCurrentPosition(pCurrent);
00656 }
00657 STDMETHODIMP CBaseSplitterOutputPin::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat)
00658 {
00659 return ((CBaseSplitterFilter*)m_pFilter)->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat);
00660 }
00661 STDMETHODIMP CBaseSplitterOutputPin::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
00662 {
00663 return ((CBaseSplitterFilter*)m_pFilter)->SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
00664 }
00665 STDMETHODIMP CBaseSplitterOutputPin::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop)
00666 {
00667 return ((CBaseSplitterFilter*)m_pFilter)->GetPositions(pCurrent, pStop);
00668 }
00669 STDMETHODIMP CBaseSplitterOutputPin::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest)
00670 {
00671 return ((CBaseSplitterFilter*)m_pFilter)->GetAvailable(pEarliest, pLatest);
00672 }
00673 STDMETHODIMP CBaseSplitterOutputPin::SetRate(double dRate)
00674 {
00675 return ((CBaseSplitterFilter*)m_pFilter)->SetRate(dRate);
00676 }
00677 STDMETHODIMP CBaseSplitterOutputPin::GetRate(double* pdRate)
00678 {
00679 return ((CBaseSplitterFilter*)m_pFilter)->GetRate(pdRate);
00680 }
00681 STDMETHODIMP CBaseSplitterOutputPin::GetPreroll(LONGLONG* pllPreroll)
00682 {
00683 return ((CBaseSplitterFilter*)m_pFilter)->GetPreroll(pllPreroll);
00684 }
00685
00686
00687
00688
00689
00690 CBaseSplitterFilter::CBaseSplitterFilter(LPCTSTR pName, LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid)
00691 : CBaseFilter(pName, pUnk, this, clsid)
00692 , m_rtDuration(0), m_rtStart(0), m_rtStop(0), m_rtCurrent(0)
00693 , m_dRate(1.0)
00694 , m_nOpenProgress(100)
00695 , m_fAbort(false)
00696 , m_rtLastStart(_I64_MIN)
00697 , m_rtLastStop(_I64_MIN)
00698 , m_priority(THREAD_PRIORITY_NORMAL)
00699 {
00700 if(phr) *phr = S_OK;
00701
00702 m_pInput.Attach(new CBaseSplitterInputPin(NAME("CBaseSplitterInputPin"), this, this, phr));
00703 }
00704
00705 CBaseSplitterFilter::~CBaseSplitterFilter()
00706 {
00707 CAutoLock cAutoLock(this);
00708
00709 CAMThread::CallWorker(CMD_EXIT);
00710 CAMThread::Close();
00711 }
00712
00713 STDMETHODIMP CBaseSplitterFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00714 {
00715 CheckPointer(ppv, E_POINTER);
00716
00717 *ppv = NULL;
00718
00719 if(m_pInput && riid == __uuidof(IFileSourceFilter))
00720 return E_NOINTERFACE;
00721
00722 return
00723 QI(IFileSourceFilter)
00724 QI(IMediaSeeking)
00725 QI(IAMOpenProgress)
00726 QI2(IAMMediaContent)
00727 QI2(IAMExtendedSeeking)
00728 QI(IKeyFrameInfo)
00729 QI(IBufferInfo)
00730 QI(IPropertyBag)
00731 QI(IPropertyBag2)
00732 QI(IDSMPropertyBag)
00733 QI(IDSMResourceBag)
00734 QI(IDSMChapterBag)
00735 __super::NonDelegatingQueryInterface(riid, ppv);
00736 }
00737
00738 CBaseSplitterOutputPin* CBaseSplitterFilter::GetOutputPin(DWORD TrackNum)
00739 {
00740 CAutoLock cAutoLock(&m_csPinMap);
00741
00742 CBaseSplitterOutputPin* pPin = NULL;
00743 m_pPinMap.Lookup(TrackNum, pPin);
00744 return pPin;
00745 }
00746
00747 DWORD CBaseSplitterFilter::GetOutputTrackNum(CBaseSplitterOutputPin* pPin)
00748 {
00749 CAutoLock cAutoLock(&m_csPinMap);
00750
00751 POSITION pos = m_pPinMap.GetStartPosition();
00752 while(pos)
00753 {
00754 DWORD TrackNum;
00755 CBaseSplitterOutputPin* pPinTmp;
00756 m_pPinMap.GetNextAssoc(pos, TrackNum, pPinTmp);
00757 if(pPinTmp == pPin) return TrackNum;
00758 }
00759
00760 return (DWORD)-1;
00761 }
00762
00763 HRESULT CBaseSplitterFilter::RenameOutputPin(DWORD TrackNumSrc, DWORD TrackNumDst, const AM_MEDIA_TYPE* pmt)
00764 {
00765 CAutoLock cAutoLock(&m_csPinMap);
00766
00767 CBaseSplitterOutputPin* pPin;
00768 if(m_pPinMap.Lookup(TrackNumSrc, pPin))
00769 {
00770 if(CComQIPtr<IPin> pPinTo = pPin->GetConnected())
00771 {
00772 if(pmt && S_OK != pPinTo->QueryAccept(pmt))
00773 return VFW_E_TYPE_NOT_ACCEPTED;
00774 }
00775
00776 m_pPinMap.RemoveKey(TrackNumSrc);
00777 m_pPinMap[TrackNumDst] = pPin;
00778
00779 if(pmt)
00780 {
00781 CAutoLock cAutoLock(&m_csmtnew);
00782 m_mtnew[TrackNumDst] = *pmt;
00783 }
00784
00785 return S_OK;
00786 }
00787
00788 return E_FAIL;
00789 }
00790
00791 HRESULT CBaseSplitterFilter::AddOutputPin(DWORD TrackNum, CAutoPtr<CBaseSplitterOutputPin> pPin)
00792 {
00793 CAutoLock cAutoLock(&m_csPinMap);
00794
00795 if(!pPin) return E_INVALIDARG;
00796 m_pPinMap[TrackNum] = pPin;
00797 m_pOutputs.AddTail(pPin);
00798 return S_OK;
00799 }
00800
00801 HRESULT CBaseSplitterFilter::DeleteOutputs()
00802 {
00803 m_rtDuration = 0;
00804
00805 m_pRetiredOutputs.RemoveAll();
00806
00807 CAutoLock cAutoLockF(this);
00808 if(m_State != State_Stopped) return VFW_E_NOT_STOPPED;
00809
00810 while(m_pOutputs.GetCount())
00811 {
00812 CAutoPtr<CBaseSplitterOutputPin> pPin = m_pOutputs.RemoveHead();
00813 if(IPin* pPinTo = pPin->GetConnected()) pPinTo->Disconnect();
00814 pPin->Disconnect();
00815
00816 m_pRetiredOutputs.AddTail(pPin);
00817 }
00818
00819 CAutoLock cAutoLockPM(&m_csPinMap);
00820 m_pPinMap.RemoveAll();
00821
00822 CAutoLock cAutoLockMT(&m_csmtnew);
00823 m_mtnew.RemoveAll();
00824
00825 RemoveAll();
00826 ResRemoveAll();
00827 ChapRemoveAll();
00828
00829 m_fontinst.UninstallFonts();
00830
00831 m_pSyncReader.Release();
00832
00833 return S_OK;
00834 }
00835
00836 void CBaseSplitterFilter::DeliverBeginFlush()
00837 {
00838 m_fFlushing = true;
00839 POSITION pos = m_pOutputs.GetHeadPosition();
00840 while(pos) m_pOutputs.GetNext(pos)->DeliverBeginFlush();
00841 }
00842
00843 void CBaseSplitterFilter::DeliverEndFlush()
00844 {
00845 POSITION pos = m_pOutputs.GetHeadPosition();
00846 while(pos) m_pOutputs.GetNext(pos)->DeliverEndFlush();
00847 m_fFlushing = false;
00848 m_eEndFlush.Set();
00849 }
00850
00851 DWORD CBaseSplitterFilter::ThreadProc()
00852 {
00853 if(m_pSyncReader)
00854 m_pSyncReader->SetBreakEvent(GetRequestHandle());
00855
00856 if(!DemuxInit())
00857 {
00858 while(1)
00859 {
00860 DWORD cmd = GetRequest();
00861 if(cmd == CMD_EXIT) CAMThread::m_hThread = NULL;
00862 Reply(S_OK);
00863 if(cmd == CMD_EXIT) return 0;
00864 }
00865 }
00866
00867 m_eEndFlush.Set();
00868 m_fFlushing = false;
00869
00870 for(DWORD cmd = -1; ; cmd = GetRequest())
00871 {
00872 if(cmd == CMD_EXIT)
00873 {
00874 m_hThread = NULL;
00875 Reply(S_OK);
00876 return 0;
00877 }
00878
00879 SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL);
00880
00881 m_rtStart = m_rtNewStart;
00882 m_rtStop = m_rtNewStop;
00883
00884 DemuxSeek(m_rtStart);
00885
00886 if(cmd != -1)
00887 Reply(S_OK);
00888
00889 m_eEndFlush.Wait();
00890
00891 m_pActivePins.RemoveAll();
00892
00893 POSITION pos = m_pOutputs.GetHeadPosition();
00894 while(pos && !m_fFlushing)
00895 {
00896 CBaseSplitterOutputPin* pPin = m_pOutputs.GetNext(pos);
00897 if(pPin->IsConnected() && pPin->IsActive())
00898 {
00899 m_pActivePins.AddTail(pPin);
00900 pPin->DeliverNewSegment(m_rtStart, m_rtStop, m_dRate);
00901 }
00902 }
00903
00904 do {m_bDiscontinuitySent.RemoveAll();}
00905 while(!DemuxLoop());
00906
00907 pos = m_pActivePins.GetHeadPosition();
00908 while(pos && !CheckRequest(&cmd))
00909 m_pActivePins.GetNext(pos)->QueueEndOfStream();
00910 }
00911
00912 ASSERT(0);
00913
00914 m_hThread = NULL;
00915 return 0;
00916 }
00917
00918 HRESULT CBaseSplitterFilter::DeliverPacket(CAutoPtr<Packet> p)
00919 {
00920 HRESULT hr = S_FALSE;
00921
00922 CBaseSplitterOutputPin* pPin = GetOutputPin(p->TrackNumber);
00923 if(!pPin || !pPin->IsConnected() || !m_pActivePins.Find(pPin))
00924 return S_FALSE;
00925
00926 if(p->rtStart != Packet::INVALID_TIME)
00927 {
00928 m_rtCurrent = p->rtStart;
00929
00930 p->rtStart -= m_rtStart;
00931 p->rtStop -= m_rtStart;
00932
00933 ASSERT(p->rtStart <= p->rtStop);
00934 }
00935
00936 {
00937 CAutoLock cAutoLock(&m_csmtnew);
00938
00939 CMediaType mt;
00940 if(m_mtnew.Lookup(p->TrackNumber, mt))
00941 {
00942 p->pmt = CreateMediaType(&mt);
00943 m_mtnew.RemoveKey(p->TrackNumber);
00944 }
00945 }
00946
00947 if(!m_bDiscontinuitySent.Find(p->TrackNumber))
00948 p->bDiscontinuity = TRUE;
00949
00950 DWORD TrackNumber = p->TrackNumber;
00951 BOOL bDiscontinuity = p->bDiscontinuity;
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961 hr = pPin->QueuePacket(p);
00962
00963 if(S_OK != hr)
00964 {
00965 if(POSITION pos = m_pActivePins.Find(pPin))
00966 m_pActivePins.RemoveAt(pos);
00967
00968 if(!m_pActivePins.IsEmpty())
00969 hr = S_OK;
00970
00971 return hr;
00972 }
00973
00974 if(bDiscontinuity)
00975 m_bDiscontinuitySent.AddTail(TrackNumber);
00976
00977 return hr;
00978 }
00979
00980 bool CBaseSplitterFilter::IsAnyPinDrying()
00981 {
00982 int totalcount = 0, totalsize = 0;
00983
00984 POSITION pos = m_pActivePins.GetHeadPosition();
00985 while(pos)
00986 {
00987 CBaseSplitterOutputPin* pPin = m_pActivePins.GetNext(pos);
00988 int count = pPin->QueueCount();
00989 int size = pPin->QueueSize();
00990 if(!pPin->IsDiscontinuous() && (count < MINPACKETS || size < MINPACKETSIZE))
00991 {
00992
00993 if(m_priority != THREAD_PRIORITY_BELOW_NORMAL && (count < MINPACKETS/3 || size < MINPACKETSIZE/3))
00994 {
00995
00996 POSITION pos = m_pOutputs.GetHeadPosition();
00997 while(pos) m_pOutputs.GetNext(pos)->SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
00998 m_priority = THREAD_PRIORITY_BELOW_NORMAL;
00999 }
01000 return(true);
01001 }
01002 totalcount += count;
01003 totalsize += size;
01004 }
01005
01006 if(m_priority != THREAD_PRIORITY_NORMAL && (totalcount > MAXPACKETS*2/3 || totalsize > MAXPACKETSIZE*2/3))
01007 {
01008
01009 POSITION pos = m_pOutputs.GetHeadPosition();
01010 while(pos) m_pOutputs.GetNext(pos)->SetThreadPriority(THREAD_PRIORITY_NORMAL);
01011 m_priority = THREAD_PRIORITY_NORMAL;
01012 }
01013
01014 if(totalcount < MAXPACKETS && totalsize < MAXPACKETSIZE)
01015 return(true);
01016
01017 return(false);
01018 }
01019
01020 HRESULT CBaseSplitterFilter::BreakConnect(PIN_DIRECTION dir, CBasePin* pPin)
01021 {
01022 CheckPointer(pPin, E_POINTER);
01023
01024 if(dir == PINDIR_INPUT)
01025 {
01026 DeleteOutputs();
01027 }
01028 else if(dir == PINDIR_OUTPUT)
01029 {
01030 }
01031 else
01032 {
01033 return E_UNEXPECTED;
01034 }
01035
01036 return S_OK;
01037 }
01038
01039 HRESULT CBaseSplitterFilter::CompleteConnect(PIN_DIRECTION dir, CBasePin* pPin)
01040 {
01041 CheckPointer(pPin, E_POINTER);
01042
01043 if(dir == PINDIR_INPUT)
01044 {
01045 CBaseSplitterInputPin* pIn = (CBaseSplitterInputPin*)pPin;
01046
01047 HRESULT hr;
01048
01049 CComPtr<IAsyncReader> pAsyncReader;
01050 if(FAILED(hr = pIn->GetAsyncReader(&pAsyncReader))
01051 || FAILED(hr = DeleteOutputs())
01052 || FAILED(hr = CreateOutputs(pAsyncReader)))
01053 return hr;
01054
01055 ChapSort();
01056
01057 m_pSyncReader = pAsyncReader;
01058 }
01059 else if(dir == PINDIR_OUTPUT)
01060 {
01061 m_pRetiredOutputs.RemoveAll();
01062 }
01063 else
01064 {
01065 return E_UNEXPECTED;
01066 }
01067
01068 return S_OK;
01069 }
01070
01071 int CBaseSplitterFilter::GetPinCount()
01072 {
01073 return (m_pInput ? 1 : 0) + m_pOutputs.GetCount();
01074 }
01075
01076 CBasePin* CBaseSplitterFilter::GetPin(int n)
01077 {
01078 CAutoLock cAutoLock(this);
01079
01080 if(n >= 0 && n < (int)m_pOutputs.GetCount())
01081 {
01082 if(POSITION pos = m_pOutputs.FindIndex(n))
01083 return m_pOutputs.GetAt(pos);
01084 }
01085
01086 if(n == m_pOutputs.GetCount() && m_pInput)
01087 {
01088 return m_pInput;
01089 }
01090
01091 return NULL;
01092 }
01093
01094 STDMETHODIMP CBaseSplitterFilter::Stop()
01095 {
01096 CAutoLock cAutoLock(this);
01097
01098 DeliverBeginFlush();
01099 CallWorker(CMD_EXIT);
01100 DeliverEndFlush();
01101
01102 HRESULT hr;
01103 if(FAILED(hr = __super::Stop()))
01104 return hr;
01105
01106 return S_OK;
01107 }
01108
01109 STDMETHODIMP CBaseSplitterFilter::Pause()
01110 {
01111 CAutoLock cAutoLock(this);
01112
01113 FILTER_STATE fs = m_State;
01114
01115 HRESULT hr;
01116 if(FAILED(hr = __super::Pause()))
01117 return hr;
01118
01119 if(fs == State_Stopped)
01120 {
01121 Create();
01122 }
01123
01124 return S_OK;
01125 }
01126
01127 STDMETHODIMP CBaseSplitterFilter::Run(REFERENCE_TIME tStart)
01128 {
01129 CAutoLock cAutoLock(this);
01130
01131 HRESULT hr;
01132 if(FAILED(hr = __super::Run(tStart)))
01133 return hr;
01134
01135 return S_OK;
01136 }
01137
01138
01139
01140 STDMETHODIMP CBaseSplitterFilter::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt)
01141 {
01142 CheckPointer(pszFileName, E_POINTER);
01143
01144 HRESULT hr = E_FAIL;
01145 CComPtr<IAsyncReader> pAsyncReader = (IAsyncReader*)new CAsyncFileReader(CString(pszFileName), hr);
01146 if(FAILED(hr)
01147 || FAILED(hr = DeleteOutputs())
01148 || FAILED(hr = CreateOutputs(pAsyncReader)))
01149 return hr;
01150
01151 ChapSort();
01152
01153 m_fn = pszFileName;
01154 m_pSyncReader = pAsyncReader;
01155
01156 return S_OK;
01157 }
01158
01159 STDMETHODIMP CBaseSplitterFilter::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt)
01160 {
01161 CheckPointer(ppszFileName, E_POINTER);
01162 if(!(*ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength()+1)*sizeof(WCHAR))))
01163 return E_OUTOFMEMORY;
01164 wcscpy(*ppszFileName, m_fn);
01165 return S_OK;
01166 }
01167
01168
01169
01170 STDMETHODIMP CBaseSplitterFilter::GetCapabilities(DWORD* pCapabilities)
01171 {
01172 return pCapabilities ? *pCapabilities =
01173 AM_SEEKING_CanGetStopPos|
01174 AM_SEEKING_CanGetDuration|
01175 AM_SEEKING_CanSeekAbsolute|
01176 AM_SEEKING_CanSeekForwards|
01177 AM_SEEKING_CanSeekBackwards, S_OK : E_POINTER;
01178 }
01179 STDMETHODIMP CBaseSplitterFilter::CheckCapabilities(DWORD* pCapabilities)
01180 {
01181 CheckPointer(pCapabilities, E_POINTER);
01182 if(*pCapabilities == 0) return S_OK;
01183 DWORD caps;
01184 GetCapabilities(&caps);
01185 if((caps&*pCapabilities) == 0) return E_FAIL;
01186 if(caps == *pCapabilities) return S_OK;
01187 return S_FALSE;
01188 }
01189 STDMETHODIMP CBaseSplitterFilter::IsFormatSupported(const GUID* pFormat) {return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;}
01190 STDMETHODIMP CBaseSplitterFilter::QueryPreferredFormat(GUID* pFormat) {return GetTimeFormat(pFormat);}
01191 STDMETHODIMP CBaseSplitterFilter::GetTimeFormat(GUID* pFormat) {return pFormat ? *pFormat = TIME_FORMAT_MEDIA_TIME, S_OK : E_POINTER;}
01192 STDMETHODIMP CBaseSplitterFilter::IsUsingTimeFormat(const GUID* pFormat) {return IsFormatSupported(pFormat);}
01193 STDMETHODIMP CBaseSplitterFilter::SetTimeFormat(const GUID* pFormat) {return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG;}
01194 STDMETHODIMP CBaseSplitterFilter::GetDuration(LONGLONG* pDuration) {CheckPointer(pDuration, E_POINTER); *pDuration = m_rtDuration; return S_OK;}
01195 STDMETHODIMP CBaseSplitterFilter::GetStopPosition(LONGLONG* pStop) {return GetDuration(pStop);}
01196 STDMETHODIMP CBaseSplitterFilter::GetCurrentPosition(LONGLONG* pCurrent) {return E_NOTIMPL;}
01197 STDMETHODIMP CBaseSplitterFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) {return E_NOTIMPL;}
01198 STDMETHODIMP CBaseSplitterFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
01199 {
01200 return SetPositionsInternal(this, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
01201 }
01202 STDMETHODIMP CBaseSplitterFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop)
01203 {
01204 if(pCurrent) *pCurrent = m_rtCurrent;
01205 if(pStop) *pStop = m_rtStop;
01206 return S_OK;
01207 }
01208 STDMETHODIMP CBaseSplitterFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest)
01209 {
01210 if(pEarliest) *pEarliest = 0;
01211 return GetDuration(pLatest);
01212 }
01213 STDMETHODIMP CBaseSplitterFilter::SetRate(double dRate) {return dRate > 0 ? m_dRate = dRate, S_OK : E_INVALIDARG;}
01214 STDMETHODIMP CBaseSplitterFilter::GetRate(double* pdRate) {return pdRate ? *pdRate = m_dRate, S_OK : E_POINTER;}
01215 STDMETHODIMP CBaseSplitterFilter::GetPreroll(LONGLONG* pllPreroll) {return pllPreroll ? *pllPreroll = 0, S_OK : E_POINTER;}
01216
01217 HRESULT CBaseSplitterFilter::SetPositionsInternal(void* id, LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
01218 {
01219 CAutoLock cAutoLock(this);
01220
01221 if(!pCurrent && !pStop
01222 || (dwCurrentFlags&AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning
01223 && (dwStopFlags&AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning)
01224 return S_OK;
01225
01226 REFERENCE_TIME
01227 rtCurrent = m_rtCurrent,
01228 rtStop = m_rtStop;
01229
01230 if(pCurrent)
01231 switch(dwCurrentFlags&AM_SEEKING_PositioningBitsMask)
01232 {
01233 case AM_SEEKING_NoPositioning: break;
01234 case AM_SEEKING_AbsolutePositioning: rtCurrent = *pCurrent; break;
01235 case AM_SEEKING_RelativePositioning: rtCurrent = rtCurrent + *pCurrent; break;
01236 case AM_SEEKING_IncrementalPositioning: rtCurrent = rtCurrent + *pCurrent; break;
01237 }
01238
01239 if(pStop)
01240 switch(dwStopFlags&AM_SEEKING_PositioningBitsMask)
01241 {
01242 case AM_SEEKING_NoPositioning: break;
01243 case AM_SEEKING_AbsolutePositioning: rtStop = *pStop; break;
01244 case AM_SEEKING_RelativePositioning: rtStop += *pStop; break;
01245 case AM_SEEKING_IncrementalPositioning: rtStop = rtCurrent + *pStop; break;
01246 }
01247
01248 if(m_rtCurrent == rtCurrent && m_rtStop == rtStop)
01249 return S_OK;
01250
01251 if(m_rtLastStart == rtCurrent && m_rtLastStop == rtStop && !m_LastSeekers.Find(id))
01252 {
01253 m_LastSeekers.AddTail(id);
01254 return S_OK;
01255 }
01256
01257 m_rtLastStart = rtCurrent;
01258 m_rtLastStop = rtStop;
01259 m_LastSeekers.RemoveAll();
01260 m_LastSeekers.AddTail(id);
01261
01262 DbgLog((LOG_TRACE, 0, _T("Seek Started %I64d"), rtCurrent));
01263
01264 m_rtNewStart = m_rtCurrent = rtCurrent;
01265 m_rtNewStop = rtStop;
01266
01267 if(ThreadExists())
01268 {
01269 DeliverBeginFlush();
01270 CallWorker(CMD_SEEK);
01271 DeliverEndFlush();
01272 }
01273
01274 DbgLog((LOG_TRACE, 0, _T("Seek Ended")));
01275
01276 return S_OK;
01277 }
01278
01279
01280
01281 STDMETHODIMP CBaseSplitterFilter::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent)
01282 {
01283 CheckPointer(pllTotal, E_POINTER);
01284 CheckPointer(pllCurrent, E_POINTER);
01285
01286 *pllTotal = 100;
01287 *pllCurrent = m_nOpenProgress;
01288
01289 return S_OK;
01290 }
01291
01292 STDMETHODIMP CBaseSplitterFilter::AbortOperation()
01293 {
01294 m_fAbort = true;
01295 return S_OK;
01296 }
01297
01298
01299
01300 STDMETHODIMP CBaseSplitterFilter::get_AuthorName(BSTR* pbstrAuthorName)
01301 {
01302 return GetProperty(L"AUTH", pbstrAuthorName);
01303 }
01304
01305 STDMETHODIMP CBaseSplitterFilter::get_Title(BSTR* pbstrTitle)
01306 {
01307 return GetProperty(L"TITL", pbstrTitle);
01308 }
01309
01310 STDMETHODIMP CBaseSplitterFilter::get_Rating(BSTR* pbstrRating)
01311 {
01312 return GetProperty(L"RTNG", pbstrRating);
01313 }
01314
01315 STDMETHODIMP CBaseSplitterFilter::get_Description(BSTR* pbstrDescription)
01316 {
01317 return GetProperty(L"DESC", pbstrDescription);
01318 }
01319
01320 STDMETHODIMP CBaseSplitterFilter::get_Copyright(BSTR* pbstrCopyright)
01321 {
01322 return GetProperty(L"CPYR", pbstrCopyright);
01323 }
01324
01325
01326
01327 STDMETHODIMP CBaseSplitterFilter::get_ExSeekCapabilities(long* pExCapabilities)
01328 {
01329 CheckPointer(pExCapabilities, E_POINTER);
01330 *pExCapabilities = AM_EXSEEK_CANSEEK;
01331 if(ChapGetCount()) *pExCapabilities |= AM_EXSEEK_MARKERSEEK;
01332 return S_OK;
01333 }
01334
01335 STDMETHODIMP CBaseSplitterFilter::get_MarkerCount(long* pMarkerCount)
01336 {
01337 CheckPointer(pMarkerCount, E_POINTER);
01338 *pMarkerCount = (long)ChapGetCount();
01339 return S_OK;
01340 }
01341
01342 STDMETHODIMP CBaseSplitterFilter::get_CurrentMarker(long* pCurrentMarker)
01343 {
01344 CheckPointer(pCurrentMarker, E_POINTER);
01345 REFERENCE_TIME rt = m_rtCurrent;
01346 long i = ChapLookup(&rt);
01347 if(i < 0) return E_FAIL;
01348 *pCurrentMarker = i+1;
01349 return S_OK;
01350 }
01351
01352 STDMETHODIMP CBaseSplitterFilter::GetMarkerTime(long MarkerNum, double* pMarkerTime)
01353 {
01354 CheckPointer(pMarkerTime, E_POINTER);
01355 REFERENCE_TIME rt;
01356 if(FAILED(ChapGet((int)MarkerNum-1, &rt))) return E_FAIL;
01357 *pMarkerTime = (double)rt / 10000000;
01358 return S_OK;
01359 }
01360
01361 STDMETHODIMP CBaseSplitterFilter::GetMarkerName(long MarkerNum, BSTR* pbstrMarkerName)
01362 {
01363 return ChapGet((int)MarkerNum-1, NULL, pbstrMarkerName);
01364 }
01365
01366
01367
01368 STDMETHODIMP CBaseSplitterFilter::GetKeyFrameCount(UINT& nKFs)
01369 {
01370 return E_NOTIMPL;
01371 }
01372
01373 STDMETHODIMP CBaseSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs)
01374 {
01375 return E_NOTIMPL;
01376 }
01377
01378
01379
01380 STDMETHODIMP_(int) CBaseSplitterFilter::GetCount()
01381 {
01382 CAutoLock cAutoLock(m_pLock);
01383
01384 return m_pOutputs.GetCount();
01385 }
01386
01387 STDMETHODIMP CBaseSplitterFilter::GetStatus(int i, int& samples, int& size)
01388 {
01389 CAutoLock cAutoLock(m_pLock);
01390
01391 if(POSITION pos = m_pOutputs.FindIndex(i))
01392 {
01393 CBaseSplitterOutputPin* pPin = m_pOutputs.GetAt(pos);
01394 samples = pPin->QueueCount();
01395 size = pPin->QueueSize();
01396 return pPin->IsConnected() ? S_OK : S_FALSE;
01397 }
01398
01399 return E_INVALIDARG;
01400 }
01401
01402 STDMETHODIMP_(DWORD) CBaseSplitterFilter::GetPriority()
01403 {
01404 return m_priority;
01405 }