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

多媒体编程

开发平台:

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 "GSCapture.h"
  23. #include "GSCaptureDlg.h"
  24. //
  25. // GSSource
  26. //
  27. #ifdef __INTEL_COMPILER
  28. interface __declspec(uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA")) 
  29. #else
  30. [uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA")] interface
  31. #endif
  32. IGSSource : public IUnknown
  33. {
  34. STDMETHOD(DeliverNewSegment)() PURE;
  35. STDMETHOD(DeliverFrame)(D3DLOCKED_RECT& r) PURE;
  36. STDMETHOD(DeliverEOS)() PURE;
  37. };
  38. #ifdef __INTEL_COMPILER
  39. class __declspec(uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77"))
  40. #else
  41. [uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77")] class 
  42. #endif
  43. GSSource : public CBaseFilter, public IGSSource
  44. {
  45. CCritSec m_csLock;
  46. CAutoPtr<CBaseOutputPin> m_pOutput;
  47. CSize m_size;
  48. REFERENCE_TIME m_rtAvgTimePerFrame, m_rtNow;
  49. STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv)
  50. {
  51. return 
  52. QI(IGSSource)
  53. __super::NonDelegatingQueryInterface(riid, ppv);
  54. }
  55. class GSSourceOutputPin : public CBaseOutputPin
  56. {
  57. CMediaType m_mt;
  58. public:
  59. GSSourceOutputPin(CMediaType& mt, CBaseFilter* pFilter, CCritSec* pLock, HRESULT& hr)
  60. : CBaseOutputPin("GSSourceOutputPin", pFilter, pLock, &hr, L"Output")
  61. , m_mt(mt)
  62. {
  63. }
  64. HRESULT GSSourceOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties)
  65. {
  66. ASSERT(pAlloc && pProperties);
  67. HRESULT hr;
  68. pProperties->cBuffers = 1;
  69. pProperties->cbBuffer = m_mt.lSampleSize;
  70. ALLOCATOR_PROPERTIES Actual;
  71. if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) return hr;
  72. if(Actual.cbBuffer < pProperties->cbBuffer) return E_FAIL;
  73. ASSERT(Actual.cBuffers == pProperties->cBuffers);
  74. return S_OK;
  75. }
  76.     HRESULT CheckMediaType(const CMediaType* pmt)
  77. {
  78. return pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_RGB32 ? S_OK : E_FAIL;
  79. }
  80.     HRESULT GetMediaType(int iPosition, CMediaType* pmt)
  81. {
  82. CheckPointer(pmt, E_POINTER);
  83. if(iPosition < 0) return E_INVALIDARG;
  84. if(iPosition > 0) return VFW_S_NO_MORE_ITEMS;
  85. *pmt = m_mt;
  86. return S_OK;
  87. }
  88. STDMETHODIMP Notify(IBaseFilter* pSender, Quality q)
  89. {
  90. return E_NOTIMPL;
  91. }
  92. };
  93. public:
  94. GSSource(int w, int h, int fps, IUnknown* pUnk, HRESULT& hr)
  95. : CBaseFilter(NAME("GSSource"), pUnk, &m_csLock, __uuidof(this), &hr)
  96. , m_pOutput(NULL)
  97. , m_size(w, h)
  98. , m_rtAvgTimePerFrame(10000000i64/fps)
  99. , m_rtNow(0)
  100. {
  101. CMediaType mt;
  102. mt.majortype = MEDIATYPE_Video;
  103. mt.subtype = MEDIASUBTYPE_RGB32;
  104. mt.formattype = FORMAT_VideoInfo;
  105. mt.lSampleSize = w*h*4;
  106. VIDEOINFOHEADER vih;
  107. memset(&vih, 0, sizeof(vih));
  108. vih.AvgTimePerFrame = m_rtAvgTimePerFrame;
  109. vih.bmiHeader.biSize = sizeof(vih.bmiHeader);
  110. vih.bmiHeader.biCompression = BI_RGB;
  111. vih.bmiHeader.biPlanes = 1;
  112. vih.bmiHeader.biWidth = w;
  113. vih.bmiHeader.biHeight = -h;
  114. vih.bmiHeader.biBitCount = 32;
  115. vih.bmiHeader.biSizeImage = w*h*4;
  116. mt.SetFormat((BYTE*)&vih, sizeof(vih));
  117. m_pOutput.Attach(new GSSourceOutputPin(mt, this, &m_csLock, hr));
  118. }
  119. DECLARE_IUNKNOWN;
  120. int GetPinCount() {return 1;}
  121. CBasePin* GetPin(int n) {return n == 0 ? m_pOutput.m_p : NULL;}
  122. // IGSSource
  123. STDMETHODIMP DeliverNewSegment()
  124. {
  125. return m_pOutput->DeliverNewSegment(m_rtNow = 0, _I64_MAX, 1.0);
  126. }
  127. STDMETHODIMP DeliverFrame(D3DLOCKED_RECT& r)
  128. {
  129. HRESULT hr;
  130. if(!m_pOutput || !m_pOutput->IsConnected()) return E_UNEXPECTED;
  131. CComPtr<IMediaSample> pSample;
  132. if(FAILED(hr = m_pOutput->GetDeliveryBuffer(&pSample, NULL, NULL, 0)))
  133. return hr;
  134. REFERENCE_TIME rtStart = m_rtNow, rtStop = m_rtNow + m_rtAvgTimePerFrame;
  135. pSample->SetTime(&rtStart, &rtStop);
  136. pSample->SetSyncPoint(TRUE);
  137. BYTE* pSrc = (BYTE*)r.pBits;
  138. int srcpitch = r.Pitch;
  139. BYTE* pDst = NULL;
  140. pSample->GetPointer(&pDst);
  141. CMediaType mt;
  142. m_pOutput->GetMediaType(0, &mt);
  143. int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth*4;
  144. int minpitch = min(srcpitch, dstpitch);
  145. for(int y = 0; y < m_size.cy; y++, pDst += dstpitch, pSrc += srcpitch)
  146. memcpy(pDst, pSrc, minpitch);
  147. if(FAILED(hr = m_pOutput->Deliver(pSample)))
  148. return hr;
  149. m_rtNow = rtStop;
  150. return S_OK;
  151. }
  152. STDMETHODIMP DeliverEOS()
  153. {
  154. return m_pOutput->DeliverEndOfStream();
  155. }
  156. };
  157. //
  158. // GSCapture
  159. //
  160. GSCapture::GSCapture()
  161. {
  162. }
  163. bool GSCapture::BeginCapture(IDirect3DDevice9* pD3Dev, int fps)
  164. {
  165. ASSERT(pD3Dev != NULL && fps != 0);
  166. EndCapture();
  167. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  168. GSCaptureDlg dlg;
  169. dlg.DoModal();
  170. //if(IDOK != dlg.DoModal())
  171. // return false;
  172. HRESULT hr;
  173. int w, h;
  174. w = 640, h = 480; // TODO
  175. CComPtr<IDirect3DSurface9> pRTSurf;
  176. if(FAILED(hr = pD3Dev->CreateRenderTarget(w, h, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &pRTSurf, NULL)))
  177. return false;
  178. if(FAILED(hr = pD3Dev->CreateOffscreenPlainSurface(w, h, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &m_pSysMemSurf, NULL)))
  179. return false;
  180. //
  181. m_pGB.CoCreateInstance(CLSID_FilterGraph);
  182. if(!m_pGB) return false;
  183. CComPtr<ICaptureGraphBuilder2> pCGB;
  184. pCGB.CoCreateInstance(CLSID_CaptureGraphBuilder2);
  185. if(!pCGB) return false;
  186. pCGB->SetFiltergraph(m_pGB);
  187. CComPtr<IBaseFilter> pMux;
  188. if(FAILED(hr = pCGB->SetOutputFileName(&MEDIASUBTYPE_Avi, CStringW(dlg.m_filename), &pMux, NULL)))
  189. return false;
  190. m_pSrc = new GSSource(w, h, fps, NULL, hr);
  191. if(FAILED(hr = m_pGB->AddFilter(m_pSrc, L"Source")))
  192. return false;
  193. if(FAILED(hr = m_pGB->AddFilter(dlg.m_pVidEnc, L"Encoder")))
  194. return false;
  195. if(FAILED(hr = pCGB->RenderStream(NULL, NULL, m_pSrc, dlg.m_pVidEnc, pMux)))
  196. return false;
  197. hr = CComQIPtr<IMediaControl>(m_pGB)->Run();
  198. hr = CComQIPtr<IGSSource>(m_pSrc)->DeliverNewSegment();
  199. m_pRTSurf = pRTSurf;
  200. return true;
  201. }
  202. bool GSCapture::BeginFrame(int& w, int& h, IDirect3DSurface9** pRTSurf)
  203. {
  204. if(!m_pRTSurf || !pRTSurf) return false;
  205. // FIXME: remember w, h from BeginCapture
  206. D3DSURFACE_DESC desc;
  207. if(FAILED(m_pRTSurf->GetDesc(&desc))) return false;
  208. w = desc.Width;
  209. h = desc.Height;
  210. (*pRTSurf = m_pRTSurf)->AddRef();
  211. return true;
  212. }
  213. bool GSCapture::EndFrame()
  214. {
  215. if(m_pRTSurf == NULL || m_pSysMemSurf == NULL) {ASSERT(0); return false;}
  216. CComPtr<IDirect3DDevice9> pD3DDev;
  217. D3DLOCKED_RECT r;
  218. if(FAILED(m_pRTSurf->GetDevice(&pD3DDev))
  219. || FAILED(pD3DDev->GetRenderTargetData(m_pRTSurf, m_pSysMemSurf))
  220. || FAILED(m_pSysMemSurf->LockRect(&r, NULL, D3DLOCK_READONLY)))
  221. return false;
  222. CComQIPtr<IGSSource>(m_pSrc)->DeliverFrame(r);
  223. m_pSysMemSurf->UnlockRect();
  224. return true;
  225. }
  226. bool GSCapture::EndCapture()
  227. {
  228. m_pRTSurf = NULL;
  229. m_pSysMemSurf = NULL;
  230. if(m_pSrc) CComQIPtr<IGSSource>(m_pSrc)->DeliverEOS();
  231. if(m_pGB) CComQIPtr<IMediaControl>(m_pGB)->Stop();
  232. m_pSrc = NULL;
  233. m_pGB = NULL;
  234. return true;
  235. }