- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# BaseSplitter.cpp

    00001 /*
    00002  *      Copyright (C) 2003-2005 Gabest
    00003  *      http://www.gabest.org
    00004  *
    00005  *  This Program is free software; you can redistribute it and/or modify
    00006  *  it under the terms of the GNU General Public License as published by
    00007  *  the Free Software Foundation; either version 2, or (at your option)
    00008  *  any later version.
    00009  *
    00010  *  This Program is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    00013  *  GNU General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU General Public License
    00016  *  along with GNU Make; see the file COPYING.  If not, write to
    00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
    00018  *  http://www.gnu.org/copyleft/gpl.html
    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 // CPacketQueue
    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)); // doubles the reserved buffer size
    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 // CBaseSplitterInputPin
    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         return pmt->majortype == MEDIATYPE_Stream
    00132                 ? S_OK
    00133                 : E_INVALIDARG;
    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 // CBaseSplitterOutputPin
    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) // just in case it were asked before the worker thread could be created and reset it
    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) // just in case it were asked before the worker thread could be created and reset it
    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 //              riid == __uuidof(IMediaSeeking) ? m_pFilter->QueryInterface(riid, ppv) :
    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>()); // NULL means EndOfStream
    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                                 // flushing can still start here, to release a blocked deliver call
    00443
    00444                                 HRESULT hr = p
    00445                                         ? DeliverPacket(p)
    00446                                         : DeliverEndOfStream();
    00447
    00448                                 m_eEndFlush.Wait(); // .. so we have to wait until it is done
    00449
    00450                                 if(hr != S_OK && !m_fFlushed) // and only report the error in m_hrDeliver if we didn't flush the stream
    00451                                 {
    00452                                         // CAutoLock cAutoLock(&m_csQueueLock);
    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                         TRACE(_T("[%d] c: %d kbps, a: %d kbps\n"),
    00504                                 p->TrackNumber,
    00505                                 (m_brs.nCurrentBitRate+500)/1000,
    00506                                 (m_brs.nAverageBitRate+500)/1000);
    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 //if(p->TrackNumber == 1)
    00556 //if(p->rtStart != Packet::INVALID_TIME)
    00557 TRACE(_T("[%d]: d%d s%d p%d, b=%d, %I64d-%I64d \n"),
    00558           p->TrackNumber,
    00559           p->bDiscontinuity, p->bSyncPoint, fTimeValid && p->rtStart < 0,
    00560           nBytes, p->rtStart, p->rtStop);
    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}"))) // ISCR
    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 // IMediaSeeking
    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 // CBaseSplitterFilter
    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                 // we can't just let it be deleted now, something might have AddRefed on it (graphedit...)
    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); // we should only exit via CMD_EXIT
    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 //if(p->TrackNumber == 1)
    00954 //if(p->rtStart != Packet::INVALID_TIME)
    00955 TRACE(_T("[%d]: d%d s%d p%d, b=%d, %I64d-%I64d \n"),
    00956           p->TrackNumber,
    00957           p->bDiscontinuity, p->bSyncPoint, p->rtStart != Packet::INVALID_TIME && p->rtStart < 0,
    00958           p->pData.GetCount(), p->rtStart, p->rtStop);
    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()) // only die when all pins are down
    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 //                      if(m_priority != THREAD_PRIORITY_ABOVE_NORMAL && (count < MINPACKETS/3 || size < MINPACKETSIZE/3))
    00993                         if(m_priority != THREAD_PRIORITY_BELOW_NORMAL && (count < MINPACKETS/3 || size < MINPACKETSIZE/3))
    00994                         {
    00995                                 // SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_ABOVE_NORMAL);
    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 //              SetThreadPriority(m_hThread, m_priority = THREAD_PRIORITY_NORMAL);
    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 // IFileSourceFilter
    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 // IMediaSeeking
    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 // IAMOpenProgress
    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 // IAMMediaContent
    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 // IAMExtendedSeeking
    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 // IKeyFrameInfo
    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 // IBufferInfo
    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 }