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 }

Generated on Tue Dec 13 14:47:11 2005 for guliverkli by  doxygen 1.4.5