00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "BaseMuxer.h"
00024
00025 #include <initguid.h>
00026 #include "..\..\..\..\include\moreuuids.h"
00027
00028
00029
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
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
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);
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
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;}