DDGrab.cpp
上传用户:limilano
上传日期:2013-07-02
资源大小:19k
文件大小:15k
源码类别:

视频捕捉/采集

开发平台:

Matlab

  1. /***************************************************
  2. This is the main Grabber code.  It builds the Direct Show graphs 
  3. and then inserts SampleGrabbers right before the renderers.  It 
  4. then changes all of the renderers to NullRenderers.  This code 
  5. supports any number of audio or video streams.  Raw midi streams
  6. are not supported -- I didn't think I should bother.
  7. This code was intended to be used inside of a matlab interface,
  8. but can be used as a generic grabber class for anyone who needs 
  9. one.
  10. Written by Micah Richert.
  11. 07/14/2005
  12. **************************************************/
  13. #include "DDGrab.h"
  14. GUID NULLGUID = {0};
  15. CSampleGrabberCB::CSampleGrabberCB()
  16. {
  17. pbFormat = NULL;
  18. frameNr = 0;
  19. disabled = FALSE;
  20. }
  21. CSampleGrabberCB::~CSampleGrabberCB()
  22. {
  23. if (pbFormat) free(pbFormat);
  24. for (int f=0;f<frames.size();f++) if (frames[f]) free(frames[f]);
  25. }
  26. // Fake out any COM QI'ing
  27. //
  28. STDMETHODIMP CSampleGrabberCB::QueryInterface(REFIID riid, void ** ppv)
  29. {
  30. if (!ppv) return E_POINTER;
  31. if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown ) 
  32. {
  33. *ppv = (void *) static_cast<ISampleGrabberCB*> ( this );
  34. return NOERROR;
  35. }
  36. return E_NOINTERFACE;
  37. }
  38. // The sample grabber is calling us back on its deliver thread.
  39. // This is NOT the main app thread!
  40. //
  41. STDMETHODIMP CSampleGrabberCB::BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize )
  42. {
  43. if (disabled) return 0;
  44. if (!pBuffer) return E_POINTER;
  45. frameNr++;
  46. bool foundNr = false;
  47. for (int i=0;i<frameNrs.size();i++) if (frameNrs[i] == frameNr) foundNr = true;
  48. if (frameNrs.size() == 0 || foundNr)
  49. {
  50. BYTE* tmp = new BYTE[lBufferSize];
  51. if (!tmp) return E_OUTOFMEMORY;
  52. memcpy(tmp,pBuffer,lBufferSize);
  53. frames.push_back(tmp);
  54. frameBytes.push_back(lBufferSize);
  55. }
  56. return 0;
  57. }
  58. void DDGrabber::cleanUp()
  59. {
  60. IEnumFilters* filterList;
  61. IBaseFilter* filt;
  62. ULONG tmp;
  63. int i;
  64. for (i=0; i<VideoCBs.size(); i++) delete VideoCBs[i];
  65. for (i=0; i<AudioCBs.size(); i++) delete AudioCBs[i];
  66. VideoCBs.clear();
  67. AudioCBs.clear();
  68. if (!FAILED(pGraphBuilder->EnumFilters(&filterList)))
  69. {
  70. filterList->Reset();
  71. while (filterList->Next(1, &filt, &tmp) == S_OK)
  72. {
  73. filt->Release();
  74. }
  75. filterList->Release();
  76. }
  77. pGraphBuilder = NULL;
  78. }
  79. void DDGrabber::MyFreeMediaType(AM_MEDIA_TYPE& mt)
  80. {
  81. if (mt.cbFormat != 0)
  82. {
  83. CoTaskMemFree((PVOID)mt.pbFormat);
  84. mt.cbFormat = 0;
  85. mt.pbFormat = NULL;
  86. }
  87. if (mt.pUnk != NULL)
  88. {
  89. // Unecessary because pUnk should not be used, but safest.
  90. mt.pUnk->Release();
  91. mt.pUnk = NULL;
  92. }
  93. }
  94. PIN_INFO DDGrabber::getPinInfo(IPin* pin)
  95. {
  96. PIN_INFO info = {0};
  97. if (pin)
  98. {
  99. if (!FAILED(pin->QueryPinInfo(&info)))
  100. {
  101. info.pFilter->Release();
  102. }
  103. }
  104. return info;
  105. }
  106. IPin* DDGrabber::getInputPin(IBaseFilter* filt)
  107. {
  108. IPin* pin = NULL;
  109. IEnumPins* pinList;
  110. ULONG tmp;
  111. if (!filt) return NULL;
  112. //get the input
  113. if (!FAILED(filt->EnumPins(&pinList)))
  114. {
  115. pinList->Reset();
  116. while (pinList->Next(1, &pin, &tmp) == S_OK && getPinInfo(pin).dir != PINDIR_INPUT);
  117. pinList->Release();
  118. if (getPinInfo(pin).dir != PINDIR_INPUT) return NULL;
  119. }
  120. return pin;
  121. }
  122. IPin* DDGrabber::getOutputPin(IBaseFilter* filt)
  123. {
  124. IPin* pin = NULL;
  125. IEnumPins* pinList;
  126. ULONG tmp;
  127. if (!filt) return NULL;
  128. //get the output
  129. if (!FAILED(filt->EnumPins(&pinList)))
  130. {
  131. pinList->Reset();
  132. while (pinList->Next(1, &pin, &tmp) == S_OK && getPinInfo(pin).dir != PINDIR_OUTPUT);
  133. pinList->Release();
  134. if (getPinInfo(pin).dir != PINDIR_OUTPUT) return NULL;
  135. }
  136. return pin;
  137. }
  138. bool DDGrabber::isRenderer(IBaseFilter* filt)
  139. {
  140. if (!filt) return false;
  141. IEnumPins* pinList;
  142. int nrOutput = 0;
  143. int nrInput = 0;
  144. IPin* pin = NULL;
  145. ULONG tmp;
  146. if (FAILED(filt->EnumPins(&pinList))) return false;
  147. pinList->Reset();
  148. while (pinList->Next(1, &pin, &tmp) == S_OK)
  149. {
  150. if (getPinInfo(pin).dir == PINDIR_OUTPUT) nrOutput++;
  151. else nrInput++;
  152. }
  153. pinList->Release();
  154. #ifdef _DEBUG
  155. FILTER_INFO info;
  156. filt->QueryFilterInfo(&info);
  157. char str[100];
  158. WideCharToMultiByte( CP_ACP, 0, info.achName, -1, str, 100, NULL, NULL );
  159. _RPT0(_CRT_WARN,str);
  160. _RPT2(_CRT_WARN," %d %dn", nrOutput, nrInput);
  161. #endif
  162. return nrOutput == 0 && nrInput == 1;  // the only filters that have no outputs are renderers
  163. }
  164. IPin* DDGrabber::connectedToInput(IBaseFilter* filt)
  165. {
  166. if (!filt) return NULL;
  167. IPin* inPin;
  168. IPin* outPin;
  169. inPin = getInputPin(filt);
  170. if (!inPin) return NULL;
  171. if (FAILED(inPin->ConnectedTo(&outPin))) return NULL;
  172. return outPin;
  173. }
  174. GUID DDGrabber::getMajorType(IBaseFilter* filt)
  175. {
  176. if (!filt) return NULLGUID;
  177. IPin* inPin;
  178. inPin = getInputPin(filt);
  179. if (!inPin) return NULLGUID;
  180. AM_MEDIA_TYPE mt = {0};
  181. // ZeroMemory(&MediaType,sizeof(MediaType));
  182. if (FAILED(inPin->ConnectionMediaType(&mt))) return NULLGUID;
  183. GUID ret = mt.majortype;
  184. MyFreeMediaType(mt);
  185. return ret;
  186. }
  187. HRESULT DDGrabber::getVideoInfo(unsigned int id, int* width, int* height, int* nrFramesCaptured, int* nrFramesTotal)
  188. {
  189. if (!width || !height || !nrFramesCaptured || !nrFramesTotal) return E_POINTER;
  190. if (id >= VideoCBs.size()) return E_NOINTERFACE;
  191. CSampleGrabberCB* CB = VideoCBs[id];
  192. if (!CB) return E_POINTER;
  193. if (CB->frameNr == 0)
  194. {
  195. *width = 0;
  196. *height = 0;
  197. } else {
  198. VIDEOINFOHEADER * h = (VIDEOINFOHEADER*) CB->pbFormat;
  199. if (!h) return E_POINTER;
  200. *width  = h->bmiHeader.biWidth;
  201. *height = h->bmiHeader.biHeight;
  202. }
  203. *nrFramesCaptured = CB->frames.size();
  204. *nrFramesTotal = CB->frameNr;
  205. return S_OK;
  206. }
  207. HRESULT DDGrabber::getAudioInfo(unsigned int id, int* nrChannels, int* rate, int* bits, int* nrFramesCaptured, int* nrFramesTotal)
  208. {
  209. if (!nrChannels || !rate || !bits || !nrFramesCaptured || !nrFramesTotal) return E_POINTER;
  210. if (id >= AudioCBs.size()) return E_NOINTERFACE;
  211. CSampleGrabberCB* CB = AudioCBs[id];
  212. if (!CB) return E_POINTER;
  213. if (CB->frameNr == 0)
  214. {
  215. *nrChannels = 0;
  216. *rate = 0;
  217. *bits = 0;
  218. } else {
  219. WAVEFORMATEX * h = (WAVEFORMATEX*) CB->pbFormat;
  220. if (!h) return E_POINTER;
  221. *nrChannels = h->nChannels;
  222. *rate = h->nSamplesPerSec;
  223. *bits = h->wBitsPerSample;
  224. }
  225. *nrFramesCaptured = CB->frames.size();
  226. *nrFramesTotal = CB->frameNr;
  227. return S_OK;
  228. }
  229. void DDGrabber::getCaptureInfo(int* nrVideo, int* nrAudio)
  230. {
  231. if (!nrVideo || !nrAudio) return;
  232. *nrVideo = (VideoCBs.size()>0&&VideoCBs[0]&&VideoCBs[0]->disabled)?0:VideoCBs.size();
  233. *nrAudio = (AudioCBs.size()>0&&AudioCBs[0]&&AudioCBs[0]->disabled)?0:AudioCBs.size();
  234. }
  235. // data must be freed by caller
  236. HRESULT DDGrabber::getVideoFrame(unsigned int id, int frameNr, char** data, int* nrBytes)
  237. {
  238. if (!data || !nrBytes) return E_POINTER;
  239. if (id >= VideoCBs.size()) return E_NOINTERFACE;
  240. CSampleGrabberCB* CB = VideoCBs[id];
  241. if (!CB) return E_POINTER;
  242. if (CB->frameNr == 0) return E_NOINTERFACE;
  243. if (frameNr < 0 || frameNr >= CB->frames.size()) return E_NOINTERFACE;
  244. BYTE* tmp = CB->frames[frameNr];
  245. if (!tmp) return E_NOINTERFACE;
  246. *nrBytes = CB->frameBytes[frameNr];
  247. *data = new char[*nrBytes];
  248. if (!*data) return E_OUTOFMEMORY;
  249. memcpy(*data,tmp,*nrBytes);
  250. free(tmp);
  251. CB->frames[frameNr] = NULL;
  252. return S_OK;
  253. }
  254. // data must be freed by caller
  255. HRESULT DDGrabber::getAudioFrame(unsigned int id, int frameNr, char** data, int* nrBytes)
  256. {
  257. if (!data || !nrBytes) return E_POINTER;
  258. if (id >= AudioCBs.size()) return E_NOINTERFACE;
  259. CSampleGrabberCB* CB = AudioCBs[id];
  260. if (!CB) return E_POINTER;
  261. if (CB->frameNr == 0) return E_NOINTERFACE;
  262. if (frameNr < 0 || frameNr >= CB->frames.size()) return E_NOINTERFACE;
  263. BYTE* tmp = CB->frames[frameNr];
  264. if (!tmp) return E_NOINTERFACE;
  265. *nrBytes = CB->frameBytes[frameNr];
  266. *data = new char[*nrBytes];
  267. if (!*data) return E_OUTOFMEMORY;
  268. memcpy(*data,tmp,*nrBytes);
  269. free(tmp);
  270. CB->frames[frameNr] = NULL;
  271. return S_OK;
  272. }
  273. void DDGrabber::setFrames(int* frameNrs, int nrFrames)
  274. {
  275. if (!frameNrs) return;
  276. for (int i=0; i < VideoCBs.size(); i++)
  277. {
  278. CSampleGrabberCB* CB = VideoCBs[i];
  279. if (CB)
  280. {
  281. CB->frames.clear();
  282. CB->frameNr = 0;
  283. CB->frameNrs.clear();
  284. for (int i=0; i<nrFrames; i++) CB->frameNrs.push_back(frameNrs[i]);
  285. }
  286. }
  287. // the meaning of frames doesn't make much sense for audio...
  288. }
  289. void DDGrabber::disableVideo()
  290. {
  291. for (int i=0; i < VideoCBs.size(); i++)
  292. {
  293. if (VideoCBs[i]) VideoCBs[i]->disabled = true;
  294. }
  295. }
  296. void DDGrabber::disableAudio()
  297. {
  298. for (int i=0; i < AudioCBs.size(); i++)
  299. {
  300. if (AudioCBs[i]) AudioCBs[i]->disabled = true;
  301. }
  302. }
  303. HRESULT DDGrabber::changeToNull(IGraphBuilder* pGraphBuilder, IBaseFilter* pRenderer)
  304. {
  305. HRESULT hr;
  306. if (!pGraphBuilder || !pRenderer) return E_POINTER;
  307. IPin* outPin = connectedToInput(pRenderer);
  308. if (!outPin) return E_NOINTERFACE;
  309. // Add the Null Renderer filter to the graph.
  310. IBaseFilter *pNull;
  311. if (FAILED(hr = ::CoCreateInstance(CLSID_NullRenderer,NULL,CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)&pNull))) return hr;
  312. if (FAILED(hr = pGraphBuilder->AddFilter(pNull, L"NullRender"))) return hr;
  313. if (FAILED(hr = outPin->Disconnect())) return hr;
  314. IPin* inPin = getInputPin(pNull);
  315. if (!inPin) return E_NOINTERFACE;
  316. #ifdef _DEBUG
  317. FILTER_INFO info;
  318. pRenderer->QueryFilterInfo(&info);
  319. char str[100];
  320. WideCharToMultiByte( CP_ACP, 0, info.achName, -1, str, 100, NULL, NULL );
  321. _RPT0(_CRT_WARN,str);
  322. _RPT0(_CRT_WARN," Removedn");
  323. #endif
  324. if (FAILED(hr = pGraphBuilder->RemoveFilter(pRenderer))) return hr;
  325. hr = pGraphBuilder->Connect(outPin,inPin);
  326. return hr;
  327. }
  328. HRESULT DDGrabber::insertCapture(IGraphBuilder* pGraphBuilder, IBaseFilter* pRenderer, AM_MEDIA_TYPE* mt, CSampleGrabberCB** grabberCB)
  329. {
  330. HRESULT hr;
  331. if (!pGraphBuilder || !pRenderer || !mt || !grabberCB) return E_POINTER;
  332. IPin* rendererPin = getInputPin(pRenderer);
  333. IPin* upStreamPin = connectedToInput(pRenderer);
  334. if (!upStreamPin || !rendererPin) return E_NOINTERFACE;
  335.   // Create the "Grabber filter"
  336. CComPtr<IBaseFilter> pGrabberBaseFilter;
  337. CComPtr<ISampleGrabber> pSampleGrabber;
  338. if (FAILED(hr = ::CoCreateInstance(CLSID_SampleGrabber,NULL,CLSCTX_INPROC_SERVER,IID_IBaseFilter, (LPVOID *)&pGrabberBaseFilter))) return hr;
  339. pGrabberBaseFilter->QueryInterface(IID_ISampleGrabber, (void**)&pSampleGrabber);
  340. if (pSampleGrabber == NULL) return E_NOINTERFACE;
  341. if (FAILED(hr = pGraphBuilder->AddFilter(pGrabberBaseFilter,L"Grabber"))) return hr;
  342. if (FAILED(hr = pSampleGrabber->SetMediaType(mt))) return hr;
  343. IPin* grabberInPin = getInputPin(pGrabberBaseFilter);
  344. if (!grabberInPin) return E_NOINTERFACE;
  345. if (FAILED(hr = upStreamPin->Disconnect())) return hr;
  346. if (FAILED(hr = rendererPin->Disconnect())) return hr;
  347. if (FAILED(hr = pGraphBuilder->Connect(upStreamPin,grabberInPin))) return hr;
  348. IPin* grabberOutPin = getOutputPin(pGrabberBaseFilter);
  349. if (!grabberOutPin) return E_NOINTERFACE;
  350. if (FAILED(hr = pGraphBuilder->Connect(grabberOutPin,rendererPin))) return hr;
  351. if (FAILED(hr = pSampleGrabber->SetBufferSamples(FALSE))) return hr;
  352. *grabberCB = new CSampleGrabberCB();
  353. if (!*grabberCB) return E_OUTOFMEMORY;
  354. CComQIPtr< ISampleGrabberCB, &IID_ISampleGrabberCB> CB(*grabberCB);
  355. if (FAILED(hr = pSampleGrabber->SetCallback( CB, 1 ))) return hr;
  356. if (FAILED(hr = pSampleGrabber->GetConnectedMediaType(mt))) return hr;
  357. // I don't know how long this pointer will stay valid... so copy it
  358. if ((*grabberCB)->pbFormat) free((*grabberCB)->pbFormat);
  359. (*grabberCB)->pbFormat = new BYTE[mt->cbFormat];
  360. if (!(*grabberCB)->pbFormat) return E_OUTOFMEMORY;
  361. memcpy((*grabberCB)->pbFormat,mt->pbFormat,mt->cbFormat);
  362. return hr;
  363. }
  364. HRESULT DDGrabber::insertVideoCapture(IGraphBuilder* pGraphBuilder, IBaseFilter* pRenderer)
  365. {
  366. AM_MEDIA_TYPE mt = {0};
  367. CSampleGrabberCB* grabberCB;
  368. if (!pGraphBuilder || !pRenderer) return E_POINTER;
  369. // ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
  370. mt.majortype = MEDIATYPE_Video;
  371. mt.subtype = MEDIASUBTYPE_RGB24;
  372. mt.formattype = FORMAT_VideoInfo; 
  373. HRESULT hr = insertCapture(pGraphBuilder, pRenderer, &mt, &grabberCB);
  374. if (!FAILED(hr))
  375. {
  376. VideoCBs.push_back(grabberCB);
  377. MyFreeMediaType(mt);
  378. }
  379. return hr;
  380. }
  381. HRESULT DDGrabber::insertAudioCapture(IGraphBuilder* pGraphBuilder, IBaseFilter* pRenderer)
  382. {
  383. AM_MEDIA_TYPE mt = {0};
  384. CSampleGrabberCB* grabberCB;
  385. if (!pGraphBuilder || !pRenderer) return E_POINTER;
  386. // ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
  387. mt.majortype = MEDIATYPE_Audio;
  388. mt.subtype = MEDIASUBTYPE_PCM;
  389. mt.formattype = FORMAT_WaveFormatEx;
  390. HRESULT hr = insertCapture(pGraphBuilder, pRenderer, &mt, &grabberCB);
  391. if (!FAILED(hr))
  392. {
  393. AudioCBs.push_back(grabberCB);
  394. MyFreeMediaType(mt);
  395. }
  396. return hr;
  397. }
  398. HRESULT DDGrabber::mangleGraph(IGraphBuilder* pGraphBuilder)
  399. {
  400. if (!pGraphBuilder) return E_POINTER;
  401. IEnumFilters* filterList;
  402. IBaseFilter* filt;
  403. vector<IBaseFilter*> renderers; // if there is an audio and a video stream then we could have two renderers
  404. ULONG tmp;
  405. HRESULT hr;
  406. if (FAILED(hr = pGraphBuilder->EnumFilters(&filterList))) return hr;
  407. filterList->Reset();
  408. while (filterList->Next(1, &filt, &tmp) == S_OK)
  409. {
  410. if (isRenderer(filt)) renderers.push_back(filt);
  411. }
  412. filterList->Release();
  413. for (int i=0; i<renderers.size(); i++)
  414. {
  415. if (MEDIATYPE_Video == getMajorType(renderers[i]))
  416. {
  417. if (FAILED(hr = insertVideoCapture(pGraphBuilder,renderers[i]))) return hr;
  418. } else if (MEDIATYPE_Audio == getMajorType(renderers[i])) {
  419. if (FAILED(hr = insertAudioCapture(pGraphBuilder,renderers[i]))) return hr;
  420. } else {
  421. _RPT0(_CRT_WARN,"Renderer type not recognized.n");
  422. }
  423. if (FAILED(hr = changeToNull(pGraphBuilder,renderers[i]))) return hr;
  424. }
  425. return S_OK;
  426. }
  427. HRESULT DDGrabber::buildGraph(char* filename)
  428. {
  429. if (!filename) return E_POINTER;
  430. WCHAR uniFilename[MAX_PATH];
  431. HRESULT hr;
  432. MultiByteToWideChar(CP_ACP, 0, filename, -1, uniFilename, MAX_PATH);
  433. // Create the graph builder
  434. pGraphBuilder = NULL;
  435. if (FAILED(hr = ::CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraphBuilder))) return hr;
  436. if (FAILED(hr = pGraphBuilder->RenderFile(uniFilename,NULL))) return hr;
  437. // insert the Capture CBs, and change the Renderers to Null
  438. if (FAILED(hr = mangleGraph(pGraphBuilder))) return hr;
  439. return hr;
  440. }
  441. HRESULT DDGrabber::doCapture()
  442. {
  443. HRESULT hr;
  444. CComPtr<IMediaControl> pMediaControl;
  445. CComPtr<IMediaEvent> pMediaEventEx;
  446. CComPtr<IMediaFilter> pMediaFilter;
  447. long evCode;
  448. pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&pMediaControl);
  449. pGraphBuilder->QueryInterface(IID_IMediaEvent, (void **)&pMediaEventEx);
  450. pGraphBuilder->QueryInterface(IID_IMediaFilter, (void **)&pMediaFilter);
  451. if (pMediaControl == NULL || pMediaEventEx == NULL || pMediaFilter == NULL) return E_NOINTERFACE;
  452. //turn off the clock, so that it will run as fast as possible
  453. pMediaFilter->SetSyncSource(NULL);
  454. // Run the graph and wait for completion.
  455. if (FAILED(hr = pMediaControl->Run())) return hr;
  456. if (FAILED(hr = pMediaEventEx->WaitForCompletion(INFINITE, &evCode))) return hr;
  457. return S_OK;
  458. }