Visual Servoing Platform  version 3.5.0 under development (2022-02-15)
vpDirectShowGrabberImpl.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * DirectShow framegrabber implementation.
33  *
34  * Authors:
35  * Bruno Renier
36  * Anthony Saunier
37  *
38  *****************************************************************************/
39 
40 #ifndef DOXYGEN_SHOULD_SKIP_THIS
41 
42 #include <visp3/core/vpConfig.h>
43 #if (defined(VISP_HAVE_DIRECTSHOW))
44 
45 #include <visp3/sensor/vpDirectShowGrabberImpl.h>
46 
47 vpDirectShowDevice *vpDirectShowGrabberImpl::deviceList = NULL;
48 unsigned int vpDirectShowGrabberImpl::nbDevices;
49 
53 void vpDirectShowGrabberImpl::HRtoStr(std::string str)
54 {
55  TCHAR szErr[MAX_ERROR_TEXT_LEN];
56  DWORD res = AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
57 
58  if (res == 0)
59  str = "Unknown Error: 0x%2x";
60 
61  char msg[MAX_ERROR_TEXT_LEN];
62  sprintf(msg, "%s", szErr);
63  str = msg;
64 }
65 
70 vpDirectShowGrabberImpl::vpDirectShowGrabberImpl()
71 {
72  init = false;
73  initCo = false;
74  // COM initialization
75  if (FAILED(hr = CoInitializeEx(NULL, COINIT_MULTITHREADED))) {
76  std::string err;
77  HRtoStr(err);
78  throw(vpFrameGrabberException(vpFrameGrabberException::initializationError, "Can't initialize COM\n" + err));
79  }
80  initCo = true;
81 
82  // create the device list
83  if (deviceList == NULL) {
84  CComPtr<IEnumMoniker> pVideoInputEnum = NULL;
85 
86  if (enumerate(pVideoInputEnum)) {
87  createDeviceList(pVideoInputEnum);
88  }
89  // not used anymore, so we release it
90  pVideoInputEnum.Release();
91  }
92 }
93 
98 void vpDirectShowGrabberImpl::open()
99 {
100  // create the device list
101  if (deviceList == NULL) {
102  CComPtr<IEnumMoniker> pVideoInputEnum = NULL;
103 
104  if (enumerate(pVideoInputEnum)) {
105  createDeviceList(pVideoInputEnum);
106  }
107  // not used anymore, so we release it
108  pVideoInputEnum.Release();
109  }
110 
111  init = initDirectShow();
112  if (!init) {
113  std::string err;
114  HRtoStr(err);
116  }
117 }
122 void vpDirectShowGrabberImpl::open(vpImage<unsigned char> &I) { open(); }
123 
128 void vpDirectShowGrabberImpl::open(vpImage<vpRGBa> &I) { open(); }
129 
135 bool vpDirectShowGrabberImpl::initDirectShow()
136 {
137 
138  // get the first working device's filter (unused and getdevice works on it)
139  currentDevice = getFirstUnusedDevice(pCapSource);
140 
141  if (currentDevice == nbDevices)
142  return false;
143 
144  // create the filter graph
145  if (!createGraph())
146  return false;
147 
148  // we add the capture source to the filter graph
149  if (FAILED(hr = pGraph->AddFilter(pCapSource, L"Capture Filter")))
150  return false;
151 
152  // we create a sample grabber
153  if (!createSampleGrabber(pGrabberFilter))
154  return false;
155 
156  // we add the grabber to the filter graph
157  if (FAILED(hr = pGraph->AddFilter(pGrabberFilter, L"SampleGrabber")))
158  return false;
159 
160  // we connect the pins
161  if (!connectSourceToGrabber(pCapSource, pGrabberFilter))
162  return false;
163 
164  // get the current connected media type (needed by the callback)
165  if (FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
166  return false;
167 
168  // Gets the various graph's interfaces
169  CComPtr<IMediaFilter> pMediaFilter;
170 
171  pGraph->QueryInterface(IID_IMediaFilter, (void **)&pMediaFilter);
172  pGraph->QueryInterface(IID_IMediaControl, reinterpret_cast<void **>(&pControl));
173  pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
174 
175  pMediaFilter->SetSyncSource(NULL);
176  pMediaFilter.Release();
177 
178  return true;
179 }
180 
184 vpDirectShowGrabberImpl::~vpDirectShowGrabberImpl() { close(); }
185 
191 bool vpDirectShowGrabberImpl::enumerate(CComPtr<IEnumMoniker> &ppVideoInputEnum)
192 {
193  CComPtr<ICreateDevEnum> pDevEnum = NULL;
194  bool res = false;
195 
196  // Enumerate system devices
197  hr = pDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER);
198 
199  // if it is a success
200  if (SUCCEEDED(hr)) {
201  // Create a video input device enumerator
202  hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &ppVideoInputEnum, 0);
203 
204  if (hr == S_OK)
205  res = true;
206  }
207 
208  pDevEnum.Release();
209  return res;
210 }
211 
217 bool vpDirectShowGrabberImpl::createDeviceList(CComPtr<IEnumMoniker> &ppVideoInputEnum)
218 {
219  CComPtr<IMoniker> pMoniker[10]; // const max devices
220  unsigned long nbMoniker;
221 
222  ppVideoInputEnum->Reset();
223 
224  // Enumerates the different inputs
225  ppVideoInputEnum->Next(10, reinterpret_cast<IMoniker **>(&pMoniker), &nbMoniker);
226 
227  // if no input device
228  if (nbMoniker == 0)
229  return false;
230 
231  deviceList = new vpDirectShowDevice[nbMoniker];
232 
233  nbDevices = (unsigned int)nbMoniker;
234 
235  // we try to get the properties of each moniker, if it fails, we skip to the
236  // next one and decrement the number of valid devices
237  unsigned int i = 0;
238  unsigned int j = 0;
239  while (i < nbDevices) {
240  if (!deviceList[i].init(pMoniker[j])) {
241  // if we can't get the device properties, skip to the next device
242  j++;
243  nbDevices--;
244  } else {
245  i++;
246  j++;
247  }
248  }
249 
250  // if no working input device
251  if (nbDevices == 0)
252  return false;
253 
254  // we release the monikers
255  for (unsigned int i = 0; i < nbMoniker; i++) {
256  pMoniker[i].Release();
257  }
258 
259  return true;
260 }
261 
268 bool vpDirectShowGrabberImpl::getDevice(unsigned int n, CComPtr<IBaseFilter> &ppDevice)
269 {
270  // if n is invalid, quit
271  if (n >= nbDevices)
272  return false;
273 
274  // if the device is already in use, quit
275  if (deviceList[n].getState() == true)
276  return false;
277 
278  // if we can't enumerate the devices, quit
279  CComPtr<IEnumMoniker> pVideoInputEnum = NULL;
280  if (!enumerate(pVideoInputEnum))
281  return false;
282 
283  CComPtr<IMoniker> pMoniker = NULL;
284  bool deviceFound = false;
285 
286  // Enumerates the different inputs
287  while (pVideoInputEnum->Next(1, &pMoniker, NULL) == S_OK && !deviceFound) {
288  // implicit conversion should work ...
289  if (deviceList[n] == vpDirectShowDevice(pMoniker)) {
290  // we get the filter
291  if (SUCCEEDED(pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void **)&ppDevice))) {
292  // now the device is in use
293  deviceList[n].setInUse();
294  deviceFound = true;
295  } else {
296  break;
297  } // we can't get the device's filter, quit
298  }
299  pMoniker.Release();
300  }
301 
302  pVideoInputEnum.Release();
303 
304  return deviceFound;
305 }
306 
313 unsigned int vpDirectShowGrabberImpl::getFirstUnusedDevice(CComPtr<IBaseFilter> &ppDevice)
314 {
315  unsigned int n = 0;
316  bool found = false;
317 
318  for (n = 0; n < nbDevices && !found; n++) {
319  // if the device is not being used
320  if (!deviceList[n].getState()) {
321  if (getDevice(n, ppDevice)) {
322  found = true;
323  deviceList[n].setInUse();
324  return n;
325  }
326  }
327  }
328 
329  return n;
330 }
331 
336 bool vpDirectShowGrabberImpl::createGraph()
337 {
338 
339  // Create the Capture Graph Builder.
340  hr = pBuild.CoCreateInstance(CLSID_CaptureGraphBuilder2, 0, CLSCTX_INPROC_SERVER);
341 
342  if (SUCCEEDED(hr)) {
343  // Create the Filter Graph Manager.
344  hr = pGraph.CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER);
345 
346  if (SUCCEEDED(hr)) {
347  // Initialize the Capture Graph Builder.
348  pBuild->SetFiltergraph(pGraph);
349 
350  return true;
351  }
352  }
353 
354  return false;
355 }
356 
362 bool vpDirectShowGrabberImpl::createSampleGrabber(CComPtr<IBaseFilter> &ppGrabberFilter)
363 {
364  // Creates the sample grabber
365  hr = ppGrabberFilter.CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER);
366 
367  if (FAILED(hr))
368  return false;
369 
370  // gets the SampleGrabber interface in order to configure it later
371  hr = ppGrabberFilter->QueryInterface(IID_ISampleGrabber, reinterpret_cast<void **>(&pGrabberI));
372 
373  if (FAILED(hr))
374  return false;
375 
376  // configure the grabber
377  AM_MEDIA_TYPE mt;
378  ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
379 
380  mt.majortype = MEDIATYPE_Video;
381 
382  // ask for a connection
383  mt.subtype = MEDIATYPE_NULL;
384 
385  if (FAILED(hr = pGrabberI->SetMediaType(&mt)))
386  return false;
387 
388  // configure the callback of the grabber
389  pGrabberI->SetCallback(&sgCB, 1);
390 
391  // grab only one frame at a time
392  pGrabberI->SetOneShot(TRUE);
393 
394  // no need to bufferize the sample in the grabber
395  pGrabberI->SetBufferSamples(false);
396 
397  return true;
398 }
399 
409 bool vpDirectShowGrabberImpl::checkSourceType(CComPtr<IPin> &pCapSourcePin)
410 {
411  // retrieves the connected media type
412  AM_MEDIA_TYPE mt;
413  if (FAILED(pCapSourcePin->ConnectionMediaType(&mt)))
414  return false;
415 
416  if (mt.majortype != MEDIATYPE_Video)
417  return false;
418 
419  // Known RGB formats
420  if (mt.subtype == MEDIASUBTYPE_ARGB32 || mt.subtype == MEDIASUBTYPE_RGB32 || mt.subtype == MEDIASUBTYPE_RGB24 ||
421  mt.subtype == MEDIASUBTYPE_RGB555 || mt.subtype == MEDIASUBTYPE_RGB565 || mt.subtype == MEDIASUBTYPE_RGB8 ||
422  mt.subtype == MEDIASUBTYPE_RGB4 || mt.subtype == MEDIASUBTYPE_RGB1) {
423  // image orientation will be handled "automatically"
424  sgCB.specialMediaType = false;
425  }
426  // Known YUV formats
427  else if (mt.subtype == MEDIASUBTYPE_AYUV || mt.subtype == MEDIASUBTYPE_UYVY || mt.subtype == MEDIASUBTYPE_Y411 ||
428  mt.subtype == MEDIASUBTYPE_Y41P || mt.subtype == MEDIASUBTYPE_Y211 || mt.subtype == MEDIASUBTYPE_YUY2 ||
429  mt.subtype == MEDIASUBTYPE_YVYU || mt.subtype == MEDIASUBTYPE_YUYV || mt.subtype == MEDIASUBTYPE_IF09 ||
430  mt.subtype == MEDIASUBTYPE_IYUV || mt.subtype == MEDIASUBTYPE_YV12 || mt.subtype == MEDIASUBTYPE_YVU9) {
431  // image orientation will be handled "automatically"
432  sgCB.specialMediaType = false;
433  }
434  // FOURCC formats
435  else {
436  // invertedSource boolean will decide the bitmap orientation
437  sgCB.specialMediaType = true;
438 
439  DWORD format;
440  VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER *>(mt.pbFormat);
441  BITMAPINFOHEADER bmpInfo = pVih->bmiHeader;
442 
443  // get the fourcc code
444  format = ((bmpInfo.biCompression & 0xFF000000) >> 24) | ((bmpInfo.biCompression & 0x00FF0000) >> 8) |
445  ((bmpInfo.biCompression & 0x0000FF00) << 8) | (bmpInfo.biCompression & 0x000000FF) << 24;
446 
447  std::cout << "This format is not one of the standard YUV or RGB format "
448  "supported by DirectShow.\n"
449  << "FourCC : " << (char)(bmpInfo.biCompression & 0x000000FF)
450  << (char)((bmpInfo.biCompression & 0x0000FF00) >> 8) << (char)((bmpInfo.biCompression & 0x00FF0000) >> 16)
451  << (char)((bmpInfo.biCompression & 0xFF000000) >> 24) << std::endl;
452 
453  // Y800 is top-down oriented so the image doesn't have to be flipped
454  // vertically
455  if (format == 'Y800') {
456  sgCB.invertedSource = false;
457  }
458  // cyuv seems to be the only yuv bottom-up oriented format (image has to
459  // be flipped)
460  else if (format == 'cyuv') {
461  sgCB.invertedSource = true;
462  }
463  // insert code for other fourcc formats here
464  // see fourcc.org to know which format is bottom-up oriented and thus
465  // needs invertedSource sets to true
466  else {
467  std::cout << "Unknown FourCC compression type, assuming top-down "
468  "orientation. Image may be inverted."
469  << std::endl;
470  sgCB.invertedSource = false; // consider that the image is topdown oriented by default
471  }
472  }
473 
474  return true;
475 }
476 
483 bool vpDirectShowGrabberImpl::connectSourceToGrabber(CComPtr<IBaseFilter> &_pCapSource,
484  CComPtr<IBaseFilter> &_pGrabberFilter)
485 {
486  /*
487  //get the capture source's output pin
488  CComPtr<IPin> pCapSourcePin;
489  if(FAILED(pBuild->FindPin(_pCapSource, PINDIR_OUTPUT, NULL, NULL, false, 0,
490  &pCapSourcePin))) return false;
491 
492  //get the grabber's input pin
493  CComPtr<IPin> pGrabberInputPin;
494  if(FAILED(pBuild->FindPin(_pGrabberFilter, PINDIR_INPUT, NULL, NULL, false,
495  0, &pGrabberInputPin))) return false;
496 
497  //connect the two of them
498  if(FAILED(pGraph->Connect(pCapSourcePin, pGrabberInputPin)))
499  return false;
500 
501  //not used anymore, we can release it
502  pGrabberInputPin.Release();
503  */
504  if (FAILED(hr = pBuild->RenderStream(NULL, NULL, _pCapSource, NULL, _pGrabberFilter)))
505  return false;
506 
507  /*
508  //get the grabber's output pin
509  CComPtr<IPin> pGrabberOutputPin;
510  if(FAILED(pBuild->FindPin(_pGrabberFilter, PINDIR_OUTPUT, NULL, NULL, false,
511  0, &pGrabberOutputPin))) return false;
512  */
513  // get the Null renderer
514  CComPtr<IBaseFilter> pNull = NULL;
515  if (FAILED(pNull.CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER)))
516  return false;
517  /*
518  //get the null renderer's input pin
519  CComPtr<IPin> pNullInputPin;
520  if(FAILED(pBuild->FindPin(pNull, PINDIR_INPUT, NULL, NULL, false, 0,
521  &pNullInputPin))) return false;
522 
523  //connect the grabber's output to the null renderer
524  if( FAILED(pGraph->AddFilter(pNull, L"NullRenderer")) ||
525  FAILED(pGraph->Connect(pGrabberOutputPin, pNullInputPin)))
526  return false;
527  */
528 
529  if (FAILED(pGraph->AddFilter(pNull, L"NullRenderer")) ||
530  FAILED(pBuild->RenderStream(NULL, NULL, _pGrabberFilter, NULL, pNull)))
531  return false;
532 
533  // get the capture source's output pin
534  CComPtr<IPin> pCapSourcePin;
535  if (FAILED(pBuild->FindPin(_pCapSource, PINDIR_OUTPUT, NULL, NULL, false, 0, &pCapSourcePin)))
536  return false;
537  // checks the media type of the capture filter
538  // and if the image needs to be inverted
539  if (!checkSourceType(pCapSourcePin))
540  return false;
541 
542  // release the remaining interfaces
543  pCapSourcePin.Release();
544  pNull.Release();
545  // pGrabberOutputPin.Release();
546  // pNullInputPin.Release();
547 
548  return true;
549 }
550 
556 bool vpDirectShowGrabberImpl::removeAll()
557 {
558  CComPtr<IEnumFilters> pEnum = NULL;
559  CComPtr<IBaseFilter> pFilter;
560  ULONG cFetched;
561 
562  if (FAILED(hr = pGraph->EnumFilters(&pEnum)))
563  return false;
564 
565  while (pEnum->Next(1, &pFilter, &cFetched) == S_OK) {
566  if (FAILED(hr = pGraph->RemoveFilter(pFilter)))
567  return false;
568  pFilter.Release();
569  pEnum->Reset();
570  }
571 
572  pEnum.Release();
573  return true;
574 }
575 
584 void vpDirectShowGrabberImpl::acquire(vpImage<vpRGBa> &I)
585 {
586  if (init == false) {
587  close();
589  }
590 
591  // set the rgbaIm pointer on I (will be filled on the next framegrabber
592  // callback)
593  sgCB.rgbaIm = &I;
594  // there is an acquire demand (execute copy during callback)
595  sgCB.acqRGBaDemand = true;
596 
597  // Run the graph to grab a frame
598  pControl->Run();
599 
600  // Wait untill it's done
601  long ev;
602  hr = pEvent->WaitForCompletion(MAX_DELAY, &ev);
603 
604  width = I.getWidth();
605  height = I.getHeight();
606 
607  // wait for the end of the next callback (copy)
608  if (WaitForSingleObject(sgCB.copySem, MAX_DELAY) != WAIT_OBJECT_0)
609  throw(vpFrameGrabberException(vpFrameGrabberException::otherError, "Can't grab the frame, callback timeout"));
610 }
611 
620 void vpDirectShowGrabberImpl::acquire(vpImage<unsigned char> &I)
621 {
622  if (init == false) {
623  close();
625  }
626 
627  // set the grayIm pointer on I (will be filled on the next framegrabber
628  // callback)
629  sgCB.grayIm = &I;
630  // there is an acquire demand (execute copy during callback)
631  sgCB.acqGrayDemand = true;
632 
633  // Run the graph to grab a frame
634  pControl->Run();
635 
636  // Wait untill it's done
637  long ev;
638  hr = pEvent->WaitForCompletion(MAX_DELAY, &ev);
639 
640  width = I.getWidth();
641  height = I.getHeight();
642 
643  // wait for the end of the next callback (copy)
644  if (WaitForSingleObject(sgCB.copySem, MAX_DELAY) != WAIT_OBJECT_0)
645  throw(vpFrameGrabberException(vpFrameGrabberException::otherError, "Can't grab the frame, callback timeout"));
646 }
647 
654 bool vpDirectShowGrabberImpl::setDevice(unsigned int id)
655 {
656  if (init == false) {
657  close();
659  }
660 
661  // if n is invalid, or the device is already in use, quit
662  if (id >= nbDevices || deviceList[id].getState() == true)
663  return false;
664 
665  // we stop the graph
666  pControl->Stop();
667 
668  // then we can safely remove all the filters
669  if (!removeAll())
670  return false;
671 
672  // we release the previous source's interface
673  pCapSource.Release();
674 
675  // here reset inUse in the old DSDevice
676  deviceList[currentDevice].resetInUse();
677 
678  // we add the grabber back in the graph
679  pGraph->AddFilter(pGrabberFilter, L"SampleGrabber");
680 
681  // get the n-th device's filter
682  if (!getDevice(id, pCapSource))
683  return false;
684 
685  // we add the capture source to the filter graph
686  if (FAILED(hr = pGraph->AddFilter(pCapSource, L"Capture Filter")))
687  return false;
688 
689  // we connect the pins
690  if (!connectSourceToGrabber(pCapSource, pGrabberFilter))
691  return false;
692 
693  // get the current connected media type (needed by the callback)
694  if (FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType)))) {
695  return false;
696  }
697 
698  // the device is now in use
699  deviceList[id].setInUse();
700  currentDevice = id;
701 
702  return true;
703 }
704 
708 void vpDirectShowGrabberImpl::displayDevices()
709 {
710  if (deviceList == NULL) {
712  }
713 
714  for (unsigned int i = 0; i < nbDevices; i++)
715  std::cout << i << " : " << deviceList[i].getName() << std::endl;
716 
717  std::cout << "Current device : " << currentDevice << std::endl << std::endl;
718 }
719 
724 void vpDirectShowGrabberImpl::close()
725 {
726  // the current device isn't being used anymore
727  if (init) {
728  deviceList[currentDevice].resetInUse();
729  init = false;
730  }
731  if (initCo) {
732  // uninstalls COM
733  CoUninitialize();
734  initCo = false;
735  }
736 }
740 bool vpDirectShowGrabberImpl::setImageSize(unsigned int width, unsigned int height)
741 {
742  if (init == false) {
743  close();
745  }
746 
747  return setFormat(width, height, NULL);
748 }
749 
753 bool vpDirectShowGrabberImpl::setFramerate(double framerate)
754 {
755  if (init == false) {
756  close();
758  }
759 
760  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)sgCB.connectedMediaType.pbFormat;
761  return setFormat(pVih->bmiHeader.biWidth, pVih->bmiHeader.biHeight, framerate);
762 }
766 bool vpDirectShowGrabberImpl::setFormat(unsigned int width, unsigned int height, double framerate)
767 {
768  if (init == false) {
769  close();
771  }
772 
773  bool found = false;
774 
775  // gets the stream config interface
776  IAMStreamConfig *pConfig = NULL;
777 
778  if (FAILED(hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
779  0, // Any media type.
780  pGrabberFilter, // Pointer to the grabber filter.
781  IID_IAMStreamConfig, (void **)&pConfig)))
782  return false;
783 
784  // gets the video control interface
785  IAMVideoControl *pVideoControl = NULL;
786 
787  if (FAILED(hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
788  0, // Any media type.
789  pGrabberFilter, // Pointer to the grabber filter.
790  IID_IAMVideoControl, (void **)&pVideoControl)))
791  return false;
792 
793  // get the grabber's input pin
794  CComPtr<IPin> pCapSourcePin;
795  if (FAILED(pBuild->FindPin(pCapSource, PINDIR_OUTPUT, NULL, NULL, false, 0, &pCapSourcePin)))
796  return false;
797 
798  int iCount = 0, iSize = 0;
799  if (FAILED(hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize)))
800  return false;
801 
802  // Check the size to make sure we pass in the correct structure.
803  if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
804  // Use the video capabilities structure.
805 
806  for (int iFormat = 0; iFormat < iCount; iFormat++) {
807  VIDEO_STREAM_CONFIG_CAPS scc;
808  AM_MEDIA_TYPE *pmtConfig;
809  hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE *)&scc);
810  // VIDEOINFOHEADER *pVih =
811  //(VIDEOINFOHEADER*)pmtConfig->pbFormat;
812 
813  // pVih->bmiHeader.biWidth;
814  // pVih->bmiHeader.biHeight;
815  // 10000000 /pVih->AvgTimePerFrame;
816  // std::cout<<"available image size :
817  //"<<pVih->bmiHeader.biWidth<<" x "<<pVih->bmiHeader.biHeight<<" at
818  //"<<10000000 /pVih->AvgTimePerFrame<<std::endl;
819  // std::cout<<"compression :
820  //"<<pVih->bmiHeader.biCompression<<std::endl;
821  if (SUCCEEDED(hr) && found == false) {
822  /* Examine the format, and possibly use it. */
823  if ((pmtConfig->majortype == sgCB.connectedMediaType.majortype) &&
824  (pmtConfig->subtype == sgCB.connectedMediaType.subtype) &&
825  (pmtConfig->formattype == sgCB.connectedMediaType.formattype) &&
826  (pmtConfig->cbFormat >= sizeof(VIDEOINFOHEADER)) && (pmtConfig->pbFormat != NULL)) {
827  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)pmtConfig->pbFormat;
828 
829  LONG lWidth = pVih->bmiHeader.biWidth;
830  LONG lHeight = pVih->bmiHeader.biHeight;
831  if (framerate != NULL) {
832  if ((unsigned int)lWidth == width && (unsigned int)lHeight == height) {
833 
834  pVih->AvgTimePerFrame = (LONGLONG)(10000000 / framerate);
835  // set the capture media type and the grabber media type
836  if (FAILED(hr = pConfig->SetFormat(pmtConfig)) || FAILED(hr = pGrabberI->SetMediaType(pmtConfig)))
837  return false;
838  // Run the graph to grab a frame
839  pControl->Run();
840 
841  // get the current connected media type (needed by the callback)
842  if (FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
843  return false;
844  pVih = (VIDEOINFOHEADER *)sgCB.connectedMediaType.pbFormat;
845  LONGLONG ActualFrameDuration;
846  if (FAILED(hr = pVideoControl->GetCurrentActualFrameRate(pCapSourcePin, &ActualFrameDuration)))
847  std::cout << "Current format (not sure): " << width << " x " << height << " at "
848  << 10000000 / pVih->AvgTimePerFrame << " fps" << std::endl
849  << std::endl;
850  else {
851  std::cout << "Current format : " << width << " x " << height << " at " << 10000000 / ActualFrameDuration
852  << " fps" << std::endl
853  << std::endl;
854  pVih->AvgTimePerFrame = ActualFrameDuration;
855  }
856  found = true;
857  }
858  } else {
859  if ((unsigned int)lWidth == width && (unsigned int)lHeight == height) {
860  pVih->AvgTimePerFrame = scc.MinFrameInterval;
861  // set the capture media type and the grabber media type
862  if (FAILED(hr = pConfig->SetFormat(pmtConfig)) || FAILED(hr = pGrabberI->SetMediaType(pmtConfig)))
863  return false;
864  // get the current connected media type (needed by the callback)
865  if (FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
866  return false;
867  pVih = (VIDEOINFOHEADER *)sgCB.connectedMediaType.pbFormat;
868  found = true;
869  std::cout << "Current format : " << width << " x " << height << " at "
870  << (10000000 / pVih->AvgTimePerFrame) << " fps" << std::endl
871  << std::endl;
872  }
873  }
874  }
875  }
876  // Delete the media type when you are done.
877  MyDeleteMediaType(pmtConfig);
878  }
879  }
880  if (!found)
881  if (framerate != NULL)
882  std::cout << "The " << width << " x " << height << " at " << framerate
883  << " fps source image format is not available. " << std::endl
884  << std::endl;
885  else
886  std::cout << "The " << width << " x " << height << "source image size is not available. " << std::endl
887  << std::endl;
888 
889  return found;
890 }
897 void vpDirectShowGrabberImpl::getFormat(unsigned int &width, unsigned int &height, double &framerate)
898 {
899  if (init == false) {
900  close();
902  }
903  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)sgCB.connectedMediaType.pbFormat;
904  width = (unsigned int)pVih->bmiHeader.biWidth;
905  height = (unsigned int)pVih->bmiHeader.biHeight;
906  framerate = (double)(10000000 / pVih->AvgTimePerFrame);
907 }
911 bool vpDirectShowGrabberImpl::getStreamCapabilities()
912 {
913  if (init == false) {
914  close();
916  }
917 
918  // gets the stream config interface
919  IAMStreamConfig *pConfig = NULL;
920 
921  if (FAILED(hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
922  0, // Any media type.
923  pGrabberFilter, // Pointer to the grabber filter.
924  IID_IAMStreamConfig, (void **)&pConfig)))
925  return false;
926 
927  int iCount = 0, iSize = 0;
928  if (FAILED(hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize)))
929  return false;
930 
931  // Check the size to make sure we pass in the correct structure.
932  if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
933  std::cout << "Available MediaTypes : " << std::endl << std::endl;
934  // Use the video capabilities structure.
935  for (int iFormat = 0; iFormat < iCount; iFormat++) {
936  VIDEO_STREAM_CONFIG_CAPS scc;
937  AM_MEDIA_TYPE *pmtConfig;
938  hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE *)&scc);
939 
940  if (SUCCEEDED(hr)) {
941  /* Examine the format, and possibly use it. */
942  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)pmtConfig->pbFormat;
943 
944  // LONG lWidth = pVih->bmiHeader.biWidth;
945  // LONG lHeight =
946  // pVih->bmiHeader.biHeight; SIZE
947  // dimensions={lWidth,lHeight};
948  // LONGLONG lAvgTimePerFrame =
949  // pVih->AvgTimePerFrame;
950  std::cout << "MediaType : " << iFormat << std::endl;
951 
952  if (pmtConfig->subtype == MEDIASUBTYPE_ARGB32)
953  std::cout << "subtype (not supported): MEDIASUBTYPE_ARGB32" << std::endl;
954  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB32)
955  std::cout << "subtype : MEDIASUBTYPE_RGB32" << std::endl;
956  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB24)
957  std::cout << "subtype : MEDIASUBTYPE_RGB24" << std::endl;
958  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB555)
959  std::cout << "subtype (not supported): MEDIASUBTYPE_RGB555" << std::endl;
960  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB565)
961  std::cout << "subtype (not supported): MEDIASUBTYPE_RGB565" << std::endl;
962  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB8)
963  std::cout << "subtype (not supported): MEDIASUBTYPE_RGB8" << std::endl;
964  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB4)
965  std::cout << "subtype (not supported): MEDIASUBTYPE_RGB4" << std::endl;
966  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB1)
967  std::cout << "subtype (not supported): MEDIASUBTYPE_RGB1" << std::endl;
968  else if (pmtConfig->subtype == MEDIASUBTYPE_YV12)
969  std::cout << "subtype : MEDIASUBTYPE_YV12" << std::endl;
970  else if (pmtConfig->subtype == MEDIASUBTYPE_YVU9)
971  std::cout << "subtype : MEDIASUBTYPE_YVU9" << std::endl;
972  else if (pmtConfig->subtype == MEDIASUBTYPE_YUY2)
973  std::cout << "subtype : MEDIASUBTYPE_YUY2" << std::endl;
974  else if (pmtConfig->subtype == MEDIASUBTYPE_YUYV)
975  std::cout << "subtype : MEDIASUBTYPE_YUYV" << std::endl;
976  else if (pmtConfig->subtype == MEDIASUBTYPE_YVYU)
977  std::cout << "subtype : MEDIASUBTYPE_YVYU" << std::endl;
978  else if (pmtConfig->subtype == MEDIASUBTYPE_IYUV)
979  std::cout << "subtype : MEDIASUBTYPE_IYUV" << std::endl;
980  else if (pmtConfig->subtype == MEDIASUBTYPE_UYVY)
981  std::cout << "subtype : MEDIASUBTYPE_UYVY" << std::endl;
982  else if ((((pVih->bmiHeader.biCompression & 0xFF000000) >> 24) |
983  ((pVih->bmiHeader.biCompression & 0x00FF0000) >> 8) |
984  ((pVih->bmiHeader.biCompression & 0x0000FF00) << 8) |
985  ((pVih->bmiHeader.biCompression & 0x000000FF) << 24)) == 'I420')
986  std::cout << "subtype : I420" << std::endl;
987  else
988  std::cout << "subtype (not supported) :" << (char)(pVih->bmiHeader.biCompression & 0x000000FF)
989  << (char)((pVih->bmiHeader.biCompression & 0x0000FF00) >> 8)
990  << (char)((pVih->bmiHeader.biCompression & 0x00FF0000) >> 16)
991  << (char)((pVih->bmiHeader.biCompression & 0xFF000000) >> 24) << std::endl;
992 
993  std::cout << "image size : " << pVih->bmiHeader.biWidth << " x " << pVih->bmiHeader.biHeight << std::endl;
994  std::cout << "framerate range: [" << 10000000 / scc.MaxFrameInterval << "," << 10000000 / scc.MinFrameInterval
995  << "]" << std::endl
996  << std::endl;
997 
998  /*
999  long frameRateNum;
1000  LONGLONG *frameRateList;
1001  if(FAILED(hr =
1002  pVideoControl->GetFrameRateList(pCapSourcePin,iFormat,dimensions,
1003  //inputs &frameRateNum, &frameRateList))) //outputs return false;
1004  for(int i=0; i<(int)frameRateNum ;
1005  i++)
1006  {
1007  std::cout<<(float)(10000000/frameRateList[i])<<"
1008  fps"<<std::endl;
1009  }
1010  std::cout<<std::endl;
1011  */
1012  }
1013  // Delete the media type when you are done.
1014  MyDeleteMediaType(pmtConfig);
1015  }
1016  }
1017  return true;
1018 }
1022 bool vpDirectShowGrabberImpl::setMediaType(int mediaTypeID)
1023 {
1024  if (init == false) {
1025  close();
1026  throw(vpFrameGrabberException(vpFrameGrabberException::initializationError, "Initialization not done"));
1027  }
1028 
1029  // gets the stream config interface
1030  IAMStreamConfig *pConfig = NULL;
1031 
1032  if (FAILED(hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
1033  0, // Any media type.
1034  pGrabberFilter, // Pointer to the grabber filter.
1035  IID_IAMStreamConfig, (void **)&pConfig)))
1036  return false;
1037 
1038  VIDEO_STREAM_CONFIG_CAPS scc;
1039  AM_MEDIA_TYPE *pmtConfig;
1040  hr = pConfig->GetStreamCaps(mediaTypeID, &pmtConfig, (BYTE *)&scc);
1041 
1042  if (SUCCEEDED(hr)) {
1043  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)pmtConfig->pbFormat;
1044  pVih->AvgTimePerFrame = scc.MinFrameInterval;
1045  // set the capture media type and the grabber media type
1046  if (FAILED(hr = pGrabberI->SetMediaType(pmtConfig)) || FAILED(hr = pConfig->SetFormat(pmtConfig)))
1047  return false;
1048  // get the current connected media type (needed by the callback)
1049  if (FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
1050  return false;
1051  }
1052  // Delete the media type when you are done.
1053  MyDeleteMediaType(pmtConfig);
1054  return true;
1055 }
1056 
1057 /*
1058  Get current capture MediaType
1059  \return mediaTypeID (-1 if failed)
1060 */
1061 int vpDirectShowGrabberImpl::getMediaType()
1062 {
1063  if (init == false) {
1064  close();
1065  throw(vpFrameGrabberException(vpFrameGrabberException::initializationError, "Initialization not done"));
1066  }
1067 
1068  int mediaTypeID = -1;
1069  VIDEOINFOHEADER *pVihConnected = (VIDEOINFOHEADER *)sgCB.connectedMediaType.pbFormat;
1070 
1071  // gets the stream config interface
1072  IAMStreamConfig *pConfig = NULL;
1073 
1074  if (FAILED(hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
1075  0, // Any media type.
1076  pGrabberFilter, // Pointer to the grabber filter.
1077  IID_IAMStreamConfig, (void **)&pConfig)))
1078  return -1;
1079 
1080  int iCount = 0, iSize = 0;
1081  if (FAILED(hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize)))
1082  return -1;
1083 
1084  // Check the size to make sure we pass in the correct structure.
1085  if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
1086  // Use the video capabilities structure.
1087  for (int iFormat = 0; iFormat < iCount; iFormat++) {
1088  VIDEO_STREAM_CONFIG_CAPS scc;
1089  AM_MEDIA_TYPE *pmtConfig;
1090  hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE *)&scc);
1091 
1092  if (SUCCEEDED(hr)) {
1093  /* Examine the format, and possibly use it. */
1094  if ((pmtConfig->majortype == sgCB.connectedMediaType.majortype) &&
1095  (pmtConfig->subtype == sgCB.connectedMediaType.subtype) &&
1096  (pmtConfig->formattype == sgCB.connectedMediaType.formattype) &&
1097  (pmtConfig->cbFormat >= sizeof(VIDEOINFOHEADER)) && (pmtConfig->pbFormat != NULL)) {
1098  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)pmtConfig->pbFormat;
1099  if (pVih->bmiHeader.biWidth == pVihConnected->bmiHeader.biWidth &&
1100  pVih->bmiHeader.biHeight == pVihConnected->bmiHeader.biHeight)
1101  mediaTypeID = iFormat;
1102  }
1103  }
1104  // Delete the media type when you are done.
1105  MyDeleteMediaType(pmtConfig);
1106  }
1107  }
1108  return mediaTypeID;
1109 }
1110 
1115 void vpDirectShowGrabberImpl::MyDeleteMediaType(AM_MEDIA_TYPE *pmt)
1116 {
1117  if (pmt != NULL) {
1118  MyFreeMediaType(*pmt); // See FreeMediaType for the implementation.
1119  CoTaskMemFree(pmt);
1120  }
1121 }
1122 
1126 void vpDirectShowGrabberImpl::MyFreeMediaType(AM_MEDIA_TYPE &mt)
1127 {
1128  if (mt.cbFormat != 0) {
1129  CoTaskMemFree((PVOID)mt.pbFormat);
1130  mt.cbFormat = 0;
1131  mt.pbFormat = NULL;
1132  }
1133  if (mt.pUnk != NULL) {
1134  // Unecessary because pUnk should not be used, but safest.
1135  mt.pUnk->Release();
1136  mt.pUnk = NULL;
1137  }
1138 }
1139 
1140 #elif !defined(VISP_BUILD_SHARED_LIBS)
1141 // Work arround to avoid warning:
1142 // libvisp_sensor.a(vpDirectShowGrabberImpl.cpp.o) has no symbols
1143 void dummy_vpDirectShowGrabberImpl(){};
1144 #endif
1145 #endif
Error that can be emited by the vpFrameGrabber class and its derivates.
unsigned int getHeight() const
Definition: vpImage.h:188
unsigned int getWidth() const
Definition: vpImage.h:246