BaseMuxer.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:9k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2005 Gabest
  3.  * http://www.gabest.org
  4.  *
  5.  *  This Program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2, or (at your option)
  8.  *  any later version.
  9.  *   
  10.  *  This Program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  *  GNU General Public License for more details.
  14.  *   
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with GNU Make; see the file COPYING.  If not, write to
  17.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  18.  *  http://www.gnu.org/copyleft/gpl.html
  19.  *
  20.  */
  21. #include "StdAfx.h"
  22. #include "BaseMuxer.h"
  23. #include <initguid.h>
  24. #include "........includemoreuuids.h"
  25. //
  26. // CBaseMuxerFilter
  27. //
  28. CBaseMuxerFilter::CBaseMuxerFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid)
  29. : CBaseFilter(NAME("CBaseMuxerFilter"), pUnk, this, clsid)
  30. , m_rtCurrent(0)
  31. {
  32. if(phr) *phr = S_OK;
  33. m_pOutput.Attach(new CBaseMuxerOutputPin(NAME("CBaseMuxerOutputPin"), this, this, phr));
  34. AddInput();
  35. }
  36. CBaseMuxerFilter::~CBaseMuxerFilter()
  37. {
  38. }
  39. STDMETHODIMP CBaseMuxerFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  40. {
  41. CheckPointer(ppv, E_POINTER);
  42. *ppv = NULL;
  43. return 
  44. QI(IMediaSeeking)
  45. QI(IPropertyBag)
  46. QI(IPropertyBag2)
  47. QI(IDSMPropertyBag)
  48. QI(IDSMResourceBag)
  49. QI(IDSMChapterBag)
  50. __super::NonDelegatingQueryInterface(riid, ppv);
  51. }
  52. //
  53. void CBaseMuxerFilter::AddInput()
  54. {
  55. POSITION pos = m_pInputs.GetHeadPosition();
  56. while(pos)
  57. {
  58. CBasePin* pPin = m_pInputs.GetNext(pos);
  59. if(!pPin->IsConnected()) return;
  60. }
  61. CStringW name;
  62. name.Format(L"Input %d", m_pInputs.GetCount()+1);
  63. CBaseMuxerInputPin* pPin = NULL;
  64. if(FAILED(CreateInput(name, &pPin)) || !pPin) {ASSERT(0); return;}
  65. CAutoPtr<CBaseMuxerInputPin> pAutoPtrPin(pPin);
  66. m_pInputs.AddTail(pAutoPtrPin);
  67. }
  68. HRESULT CBaseMuxerFilter::CreateInput(CStringW name, CBaseMuxerInputPin** ppPin)
  69. {
  70. CheckPointer(ppPin, E_POINTER);
  71. HRESULT hr = S_OK;
  72. *ppPin = new CBaseMuxerInputPin(name, this, this, &hr);
  73. return hr;
  74. }
  75. //
  76. DWORD CBaseMuxerFilter::ThreadProc()
  77. {
  78. SetThreadPriority(m_hThread, THREAD_PRIORITY_ABOVE_NORMAL);
  79. POSITION pos;
  80. while(1)
  81. {
  82. DWORD cmd = GetRequest();
  83. switch(cmd)
  84. {
  85. default:
  86. case CMD_EXIT:
  87. CAMThread::m_hThread = NULL;
  88. Reply(S_OK);
  89. return 0;
  90. case CMD_RUN:
  91. m_pActivePins.RemoveAll();
  92. m_pPins.RemoveAll();
  93. pos = m_pInputs.GetHeadPosition();
  94. while(pos)
  95. {
  96. CBaseMuxerInputPin* pPin = m_pInputs.GetNext(pos);
  97. if(pPin->IsConnected())
  98. {
  99. m_pActivePins.AddTail(pPin);
  100. m_pPins.AddTail(pPin);
  101. }
  102. }
  103. CComPtr<IBitStream> pBitStream;
  104. if(m_pOutput)
  105. if(CComQIPtr<IStream> pStream = m_pOutput->GetConnected())
  106. pBitStream = new CBitStream(pStream, true);
  107. m_rtCurrent = 0;
  108. Reply(S_OK);
  109. MuxInit();
  110. try
  111. {
  112. // TRACE(_T("WriteHeadern"));
  113. if(pBitStream) MuxHeader(pBitStream);
  114. MuxHeader();
  115. while(!CheckRequest(NULL) && m_pActivePins.GetCount())
  116. {
  117. if(m_State == State_Paused) {Sleep(10); continue;}
  118. CAutoPtr<MuxerPacket> pPacket = GetPacket();
  119. if(!pPacket) {Sleep(1); continue;}
  120. if(pPacket->IsTimeValid())
  121. m_rtCurrent = pPacket->rtStart;
  122. if(pPacket->IsEOS())
  123. m_pActivePins.RemoveAt(m_pActivePins.Find(pPacket->pPin));
  124. TRACE(_T("WritePacket pPin=%x, size=%d, s%d e%d b%d, rt=(%I64d-%I64d)n"), 
  125. pPacket->pPin->GetID(),
  126. pPacket->pData.GetSize(),
  127. !!(pPacket->flags & MuxerPacket::syncpoint),
  128. !!(pPacket->flags & MuxerPacket::eos), 
  129. !!(pPacket->flags & MuxerPacket::bogus), 
  130. pPacket->rtStart/10000, pPacket->rtStop/10000);
  131. if(pBitStream) MuxPacket(pBitStream, pPacket);
  132. MuxPacket(pPacket);
  133. }
  134. // TRACE(_T("WriteFootern"));
  135. if(pBitStream) MuxFooter(pBitStream);
  136. MuxFooter();
  137. }
  138. catch(HRESULT hr)
  139. {
  140. CComQIPtr<IMediaEventSink>(m_pGraph)->Notify(EC_ERRORABORT, hr, 0);
  141. }
  142. m_pOutput->DeliverEndOfStream();
  143. m_pActivePins.RemoveAll();
  144. m_pPins.RemoveAll();
  145. break;
  146. }
  147. }
  148. ASSERT(0); // we should only exit via CMD_EXIT
  149. CAMThread::m_hThread = NULL;
  150. return 0;
  151. }
  152. CAutoPtr<MuxerPacket> CBaseMuxerFilter::GetPacket()
  153. {
  154. REFERENCE_TIME rtMin = _I64_MAX;
  155. CBaseMuxerInputPin* pPinMin = NULL;
  156. int i = m_pActivePins.GetCount();
  157. POSITION pos = m_pActivePins.GetHeadPosition();
  158. while(pos)
  159. {
  160. CBaseMuxerInputPin* pPin = m_pActivePins.GetNext(pos);
  161. CAutoLock cAutoLock(&pPin->m_csQueue);
  162. if(!pPin->m_queue.GetCount()) continue;
  163. MuxerPacket* p = pPin->m_queue.GetHead();
  164. if(p->IsBogus() || !p->IsTimeValid() || p->IsEOS())
  165. {
  166. pPinMin = pPin;
  167. i = 0;
  168. break;
  169. }
  170. if(p->rtStart < rtMin)
  171. {
  172. rtMin = p->rtStart;
  173. pPinMin = pPin;
  174. }
  175. i--;
  176. }
  177. CAutoPtr<MuxerPacket> pPacket;
  178. if(pPinMin && i == 0)
  179. {
  180. pPacket = pPinMin->PopPacket();
  181. }
  182. else
  183. {
  184. pos = m_pActivePins.GetHeadPosition();
  185. while(pos) m_pActivePins.GetNext(pos)->m_evAcceptPacket.Set();
  186. }
  187. return pPacket;
  188. }
  189. //
  190. int CBaseMuxerFilter::GetPinCount()
  191. {
  192. return m_pInputs.GetCount() + (m_pOutput ? 1 : 0);
  193. }
  194. CBasePin* CBaseMuxerFilter::GetPin(int n)
  195. {
  196.     CAutoLock cAutoLock(this);
  197. if(n >= 0 && n < (int)m_pInputs.GetCount())
  198. {
  199. if(POSITION pos = m_pInputs.FindIndex(n))
  200. return m_pInputs.GetAt(pos);
  201. }
  202. if(n == m_pInputs.GetCount() && m_pOutput)
  203. {
  204. return m_pOutput;
  205. }
  206. return NULL;
  207. }
  208. STDMETHODIMP CBaseMuxerFilter::Stop()
  209. {
  210. CAutoLock cAutoLock(this);
  211. HRESULT hr = __super::Stop();
  212. if(FAILED(hr)) return hr;
  213. CallWorker(CMD_EXIT);
  214. return hr;
  215. }
  216. STDMETHODIMP CBaseMuxerFilter::Pause()
  217. {
  218. CAutoLock cAutoLock(this);
  219. FILTER_STATE fs = m_State;
  220. HRESULT hr = __super::Pause();
  221. if(FAILED(hr)) return hr;
  222. if(fs == State_Stopped && m_pOutput)
  223. {
  224. CAMThread::Create();
  225. CallWorker(CMD_RUN);
  226. }
  227. return hr;
  228. }
  229. STDMETHODIMP CBaseMuxerFilter::Run(REFERENCE_TIME tStart)
  230. {
  231. CAutoLock cAutoLock(this);
  232. HRESULT hr = __super::Run(tStart);
  233. if(FAILED(hr)) return hr;
  234. return hr;
  235. }
  236. // IMediaSeeking
  237. STDMETHODIMP CBaseMuxerFilter::GetCapabilities(DWORD* pCapabilities)
  238. {
  239. return pCapabilities ? *pCapabilities = AM_SEEKING_CanGetDuration|AM_SEEKING_CanGetCurrentPos, S_OK : E_POINTER;
  240. }
  241. STDMETHODIMP CBaseMuxerFilter::CheckCapabilities(DWORD* pCapabilities)
  242. {
  243. CheckPointer(pCapabilities, E_POINTER);
  244. if(*pCapabilities == 0) return S_OK;
  245. DWORD caps;
  246. GetCapabilities(&caps);
  247. caps &= *pCapabilities;
  248. return caps == 0 ? E_FAIL : caps == *pCapabilities ? S_OK : S_FALSE;
  249. }
  250. STDMETHODIMP CBaseMuxerFilter::IsFormatSupported(const GUID* pFormat) {return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;}
  251. STDMETHODIMP CBaseMuxerFilter::QueryPreferredFormat(GUID* pFormat) {return GetTimeFormat(pFormat);}
  252. STDMETHODIMP CBaseMuxerFilter::GetTimeFormat(GUID* pFormat) {return pFormat ? *pFormat = TIME_FORMAT_MEDIA_TIME, S_OK : E_POINTER;}
  253. STDMETHODIMP CBaseMuxerFilter::IsUsingTimeFormat(const GUID* pFormat) {return IsFormatSupported(pFormat);}
  254. STDMETHODIMP CBaseMuxerFilter::SetTimeFormat(const GUID* pFormat) {return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG;}
  255. STDMETHODIMP CBaseMuxerFilter::GetDuration(LONGLONG* pDuration)
  256. {
  257. CheckPointer(pDuration, E_POINTER);
  258. *pDuration = 0;
  259. POSITION pos = m_pInputs.GetHeadPosition();
  260. while(pos) {REFERENCE_TIME rt = m_pInputs.GetNext(pos)->GetDuration(); if(rt > *pDuration) *pDuration = rt;}
  261. return S_OK;
  262. }
  263. STDMETHODIMP CBaseMuxerFilter::GetStopPosition(LONGLONG* pStop) {return E_NOTIMPL;}
  264. STDMETHODIMP CBaseMuxerFilter::GetCurrentPosition(LONGLONG* pCurrent)
  265. {
  266. CheckPointer(pCurrent, E_POINTER);
  267. *pCurrent = m_rtCurrent;
  268. return S_OK;
  269. }
  270. STDMETHODIMP CBaseMuxerFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) {return E_NOTIMPL;}
  271. STDMETHODIMP CBaseMuxerFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
  272. {
  273. FILTER_STATE fs;
  274. if(SUCCEEDED(GetState(0, &fs)) && fs == State_Stopped)
  275. {
  276. POSITION pos = m_pInputs.GetHeadPosition();
  277. while(pos)
  278. {
  279. CBasePin* pPin = m_pInputs.GetNext(pos);
  280. CComQIPtr<IMediaSeeking> pMS = pPin->GetConnected();
  281. if(!pMS) pMS = GetFilterFromPin(pPin->GetConnected());
  282. if(pMS) pMS->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags);
  283. }
  284. return S_OK;
  285. }
  286. return VFW_E_WRONG_STATE;
  287. }
  288. STDMETHODIMP CBaseMuxerFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) {return E_NOTIMPL;}
  289. STDMETHODIMP CBaseMuxerFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) {return E_NOTIMPL;}
  290. STDMETHODIMP CBaseMuxerFilter::SetRate(double dRate) {return E_NOTIMPL;}
  291. STDMETHODIMP CBaseMuxerFilter::GetRate(double* pdRate) {return E_NOTIMPL;}
  292. STDMETHODIMP CBaseMuxerFilter::GetPreroll(LONGLONG* pllPreroll) {return E_NOTIMPL;}