- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# 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;}