BaseMuxer.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 "BaseMuxer.h"
00024 
00025 #include <initguid.h>
00026 #include "..\..\..\..\include\moreuuids.h"
00027 
00028 //
00029 // CBaseMuxerFilter
00030 //
00031 
00032 CBaseMuxerFilter::CBaseMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid)
00033         : CBaseFilter(NAME("CBaseMuxerFilter"), pUnk, this, clsid)
00034         , m_rtCurrent(0)
00035 {
00036         if(phr) *phr = S_OK;
00037         m_pOutput.Attach(new CBaseMuxerOutputPin(NAME("CBaseMuxerOutputPin"), this, this, phr));
00038         AddInput();
00039 }
00040 
00041 CBaseMuxerFilter::~CBaseMuxerFilter()
00042 {
00043 }
00044 
00045 STDMETHODIMP CBaseMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00046 {
00047         CheckPointer(ppv, E_POINTER);
00048 
00049         *ppv = NULL;
00050 
00051         return 
00052                 QI(IMediaSeeking)
00053                 QI(IPropertyBag)
00054                 QI(IPropertyBag2)
00055                 QI(IDSMPropertyBag)
00056                 QI(IDSMResourceBag)
00057                 QI(IDSMChapterBag)
00058                 __super::NonDelegatingQueryInterface(riid, ppv);
00059 }
00060 
00061 //
00062 
00063 void CBaseMuxerFilter::AddInput()
00064 {
00065         POSITION pos = m_pInputs.GetHeadPosition();
00066         while(pos)
00067         {
00068                 CBasePin* pPin = m_pInputs.GetNext(pos);
00069                 if(!pPin->IsConnected()) return;
00070         }
00071 
00072         CStringW name;
00073         name.Format(L"Input %d", m_pInputs.GetCount()+1);
00074         
00075         CBaseMuxerInputPin* pPin = NULL;
00076         if(FAILED(CreateInput(name, &pPin)) || !pPin) {ASSERT(0); return;}
00077 
00078         CAutoPtr<CBaseMuxerInputPin> pAutoPtrPin(pPin);
00079         m_pInputs.AddTail(pAutoPtrPin);
00080 }
00081 
00082 HRESULT CBaseMuxerFilter::CreateInput(CStringW name, CBaseMuxerInputPin** ppPin)
00083 {
00084         CheckPointer(ppPin, E_POINTER);
00085         HRESULT hr = S_OK;
00086         *ppPin = new CBaseMuxerInputPin(name, this, this, &hr);
00087         return hr;
00088 }
00089 
00090 //
00091 
00092 DWORD CBaseMuxerFilter::ThreadProc()
00093 {
00094         SetThreadPriority(m_hThread, THREAD_PRIORITY_ABOVE_NORMAL);
00095 
00096         POSITION pos;
00097 
00098         while(1)
00099         {
00100                 DWORD cmd = GetRequest();
00101 
00102                 switch(cmd)
00103                 {
00104                 default:
00105                 case CMD_EXIT:
00106                         CAMThread::m_hThread = NULL;
00107                         Reply(S_OK);
00108                         return 0;
00109 
00110                 case CMD_RUN:
00111                         m_pActivePins.RemoveAll();
00112                         m_pPins.RemoveAll();
00113 
00114                         pos = m_pInputs.GetHeadPosition();
00115                         while(pos)
00116                         {
00117                                 CBaseMuxerInputPin* pPin = m_pInputs.GetNext(pos);
00118                                 if(pPin->IsConnected())
00119                                 {
00120                                         m_pActivePins.AddTail(pPin);
00121                                         m_pPins.AddTail(pPin);
00122                                 }
00123                         }
00124 
00125                         CComPtr<IBitStream> pBitStream;
00126 
00127                         if(m_pOutput)
00128                         if(CComQIPtr<IStream> pStream = m_pOutput->GetConnected())
00129                                 pBitStream = new CBitStream(pStream, true);
00130 
00131                         m_rtCurrent = 0;
00132 
00133                         Reply(S_OK);
00134 
00135                         MuxInit();
00136 
00137                         try
00138                         {
00139                                 // TRACE(_T("WriteHeader\n"));
00140                                 if(pBitStream) MuxHeader(pBitStream);
00141                                 MuxHeader();
00142 
00143                                 while(!CheckRequest(NULL) && m_pActivePins.GetCount())
00144                                 {
00145                                         if(m_State == State_Paused) {Sleep(10); continue;}
00146 
00147                                         CAutoPtr<MuxerPacket> pPacket = GetPacket();
00148                                         if(!pPacket) {Sleep(1); continue;}
00149 
00150                                         if(pPacket->IsTimeValid())
00151                                                 m_rtCurrent = pPacket->rtStart;
00152 
00153                                         if(pPacket->IsEOS())
00154                                                 m_pActivePins.RemoveAt(m_pActivePins.Find(pPacket->pPin));
00155                                         
00156                                         TRACE(_T("WritePacket pPin=%x, size=%d, s%d e%d b%d, rt=(%I64d-%I64d)\n"), 
00157                                                 pPacket->pPin->GetID(),
00158                                                 pPacket->pData.GetSize(),
00159                                                 !!(pPacket->flags & MuxerPacket::syncpoint),
00160                                                 !!(pPacket->flags & MuxerPacket::eos), 
00161                                                 !!(pPacket->flags & MuxerPacket::bogus), 
00162                                                 pPacket->rtStart/10000, pPacket->rtStop/10000);
00163 
00164                                         if(pBitStream) MuxPacket(pBitStream, pPacket);
00165                                         MuxPacket(pPacket);
00166                                 }
00167 
00168                                 // TRACE(_T("WriteFooter\n"));
00169                                 if(pBitStream) MuxFooter(pBitStream);
00170                                 MuxFooter();
00171                         }
00172                         catch(HRESULT hr)
00173                         {
00174                                 CComQIPtr<IMediaEventSink>(m_pGraph)->Notify(EC_ERRORABORT, hr, 0);
00175                         }
00176 
00177                         m_pOutput->DeliverEndOfStream();
00178 
00179                         m_pActivePins.RemoveAll();
00180                         m_pPins.RemoveAll();
00181 
00182                         break;
00183                 }
00184         }
00185 
00186         ASSERT(0); // we should only exit via CMD_EXIT
00187 
00188         CAMThread::m_hThread = NULL;
00189         return 0;
00190 }
00191 
00192 CAutoPtr<MuxerPacket> CBaseMuxerFilter::GetPacket()
00193 {
00194         REFERENCE_TIME rtMin = _I64_MAX;
00195         CBaseMuxerInputPin* pPinMin = NULL;
00196         int i = m_pActivePins.GetCount();
00197 
00198         POSITION pos = m_pActivePins.GetHeadPosition();
00199         while(pos)
00200         {
00201                 CBaseMuxerInputPin* pPin = m_pActivePins.GetNext(pos);
00202 
00203                 CAutoLock cAutoLock(&pPin->m_csQueue);
00204                 if(!pPin->m_queue.GetCount()) continue;
00205 
00206                 MuxerPacket* p = pPin->m_queue.GetHead();
00207 
00208                 if(p->IsBogus() || !p->IsTimeValid() || p->IsEOS())
00209                 {
00210                         pPinMin = pPin;
00211                         i = 0;
00212                         break;
00213                 }
00214 
00215                 if(p->rtStart < rtMin)
00216                 {
00217                         rtMin = p->rtStart;
00218                         pPinMin = pPin;
00219                 }
00220 
00221                 i--;
00222         }
00223 
00224         CAutoPtr<MuxerPacket> pPacket;
00225 
00226         if(pPinMin && i == 0)
00227         {
00228                 pPacket = pPinMin->PopPacket();
00229         }
00230         else
00231         {
00232                 pos = m_pActivePins.GetHeadPosition();
00233                 while(pos) m_pActivePins.GetNext(pos)->m_evAcceptPacket.Set();
00234         }
00235 
00236         return pPacket;
00237 }
00238 
00239 //
00240 
00241 int CBaseMuxerFilter::GetPinCount()
00242 {
00243         return m_pInputs.GetCount() + (m_pOutput ? 1 : 0);
00244 }
00245 
00246 CBasePin* CBaseMuxerFilter::GetPin(int n)
00247 {
00248     CAutoLock cAutoLock(this);
00249 
00250         if(n >= 0 && n < (int)m_pInputs.GetCount())
00251         {
00252                 if(POSITION pos = m_pInputs.FindIndex(n))
00253                         return m_pInputs.GetAt(pos);
00254         }
00255 
00256         if(n == m_pInputs.GetCount() && m_pOutput)
00257         {
00258                 return m_pOutput;
00259         }
00260 
00261         return NULL;
00262 }
00263 
00264 STDMETHODIMP CBaseMuxerFilter::Stop()
00265 {
00266         CAutoLock cAutoLock(this);
00267 
00268         HRESULT hr = __super::Stop();
00269         if(FAILED(hr)) return hr;
00270 
00271         CallWorker(CMD_EXIT);
00272 
00273         return hr;
00274 }
00275 
00276 STDMETHODIMP CBaseMuxerFilter::Pause()
00277 {
00278         CAutoLock cAutoLock(this);
00279 
00280         FILTER_STATE fs = m_State;
00281 
00282         HRESULT hr = __super::Pause();
00283         if(FAILED(hr)) return hr;
00284 
00285         if(fs == State_Stopped && m_pOutput)
00286         {
00287                 CAMThread::Create();
00288                 CallWorker(CMD_RUN);
00289         }
00290 
00291         return hr;
00292 }
00293 
00294 STDMETHODIMP CBaseMuxerFilter::Run(REFERENCE_TIME tStart)
00295 {
00296         CAutoLock cAutoLock(this);
00297 
00298         HRESULT hr = __super::Run(tStart);
00299         if(FAILED(hr)) return hr;
00300 
00301         return hr;
00302 }
00303 
00304 // IMediaSeeking
00305 
00306 STDMETHODIMP CBaseMuxerFilter::GetCapabilities(DWORD* pCapabilities)
00307 {
00308         return pCapabilities ? *pCapabilities = AM_SEEKING_CanGetDuration|AM_SEEKING_CanGetCurrentPos, S_OK : E_POINTER;
00309 }
00310 STDMETHODIMP CBaseMuxerFilter::CheckCapabilities(DWORD* pCapabilities)
00311 {
00312         CheckPointer(pCapabilities, E_POINTER);
00313         if(*pCapabilities == 0) return S_OK;
00314         DWORD caps;
00315         GetCapabilities(&caps);
00316         caps &= *pCapabilities;
00317         return caps == 0 ? E_FAIL : caps == *pCapabilities ? S_OK : S_FALSE;
00318 }
00319 STDMETHODIMP CBaseMuxerFilter::IsFormatSupported(const GUID* pFormat) {return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;}
00320 STDMETHODIMP CBaseMuxerFilter::QueryPreferredFormat(GUID* pFormat) {return GetTimeFormat(pFormat);}
00321 STDMETHODIMP CBaseMuxerFilter::GetTimeFormat(GUID* pFormat) {return pFormat ? *pFormat = TIME_FORMAT_MEDIA_TIME, S_OK : E_POINTER;}
00322 STDMETHODIMP CBaseMuxerFilter::IsUsingTimeFormat(const GUID* pFormat) {return IsFormatSupported(pFormat);}
00323 STDMETHODIMP CBaseMuxerFilter::SetTimeFormat(const GUID* pFormat) {return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG;}
00324 STDMETHODIMP CBaseMuxerFilter::GetDuration(LONGLONG* pDuration)
00325 {
00326         CheckPointer(pDuration, E_POINTER);
00327         *pDuration = 0;
00328         POSITION pos = m_pInputs.GetHeadPosition();
00329         while(pos) {REFERENCE_TIME rt = m_pInputs.GetNext(pos)->GetDuration(); if(rt > *pDuration) *pDuration = rt;}
00330         return S_OK;
00331 }
00332 STDMETHODIMP CBaseMuxerFilter::GetStopPosition(LONGLONG* pStop) {return E_NOTIMPL;}
00333 STDMETHODIMP CBaseMuxerFilter::GetCurrentPosition(LONGLONG* pCurrent)
00334 {
00335         CheckPointer(pCurrent, E_POINTER);
00336         *pCurrent = m_rtCurrent;
00337         return S_OK;
00338 }
00339 STDMETHODIMP CBaseMuxerFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) {return E_NOTIMPL;}
00340 STDMETHODIMP CBaseMuxerFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
00341 {
00342         FILTER_STATE fs;
00343 
00344         if(SUCCEEDED(GetState(0, &fs)) && fs == State_Stopped)
00345         {
00346                 POSITION pos = m_pInputs.GetHeadPosition();
00347                 while(pos)
00348                 {
00349                         CBasePin* pPin = m_pInputs.GetNext(pos);
00350                         CComQIPtr<IMediaSeeking> pMS = pPin->GetConnected();
00351                         if(!pMS) pMS = GetFilterFromPin(pPin->GetConnected());
00352                         if(pMS) pMS->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags);
00353                 }
00354 
00355                 return S_OK;
00356         }
00357 
00358         return VFW_E_WRONG_STATE;
00359 }
00360 STDMETHODIMP CBaseMuxerFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) {return E_NOTIMPL;}
00361 STDMETHODIMP CBaseMuxerFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) {return E_NOTIMPL;}
00362 STDMETHODIMP CBaseMuxerFilter::SetRate(double dRate) {return E_NOTIMPL;}
00363 STDMETHODIMP CBaseMuxerFilter::GetRate(double* pdRate) {return E_NOTIMPL;}
00364 STDMETHODIMP CBaseMuxerFilter::GetPreroll(LONGLONG* pllPreroll) {return E_NOTIMPL;}

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