Visual Servoing Platform  version 3.6.1 under development (2024-04-26)
vpDirectShowGrabberImpl.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 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 https://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 *****************************************************************************/
35 
36 #ifndef DOXYGEN_SHOULD_SKIP_THIS
37 
38 #include <visp3/core/vpConfig.h>
39 #if (defined(VISP_HAVE_DIRECTSHOW))
40 
41 #include <visp3/sensor/vpDirectShowGrabberImpl.h>
42 
43 vpDirectShowDevice *vpDirectShowGrabberImpl::deviceList = nullptr;
44 unsigned int vpDirectShowGrabberImpl::nbDevices;
45 
49 void vpDirectShowGrabberImpl::HRtoStr(std::string &str)
50 {
51  TCHAR szErr[MAX_ERROR_TEXT_LEN];
52  DWORD res = AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
53 
54  if (res == 0)
55  str = "Unknown Error: 0x%2x";
56 
57  char msg[MAX_ERROR_TEXT_LEN];
58  snprintf(msg, MAX_ERROR_TEXT_LEN, "%s", szErr);
59  str = msg;
60 }
61 
66 vpDirectShowGrabberImpl::vpDirectShowGrabberImpl()
67 {
68  init = false;
69  initCo = false;
70  // COM initialization
71  if (FAILED(hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED))) {
72  std::string err;
73  HRtoStr(err);
74  throw(vpFrameGrabberException(vpFrameGrabberException::initializationError, "Can't initialize COM\n" + err));
75  }
76  initCo = true;
77 
78  // create the device list
79  if (deviceList == nullptr) {
80  CComPtr<IEnumMoniker> pVideoInputEnum = nullptr;
81 
82  if (enumerate(pVideoInputEnum)) {
83  createDeviceList(pVideoInputEnum);
84  }
85  // not used anymore, so we release it
86  pVideoInputEnum.Release();
87  }
88 }
89 
94 void vpDirectShowGrabberImpl::open()
95 {
96  // create the device list
97  if (deviceList == nullptr) {
98  CComPtr<IEnumMoniker> pVideoInputEnum = nullptr;
99 
100  if (enumerate(pVideoInputEnum)) {
101  createDeviceList(pVideoInputEnum);
102  }
103  // not used anymore, so we release it
104  pVideoInputEnum.Release();
105  }
106 
107  init = initDirectShow();
108  if (!init) {
109  std::string err;
110  HRtoStr(err);
112  }
113 }
118 void vpDirectShowGrabberImpl::open(vpImage<unsigned char> &I) { open(); }
119 
124 void vpDirectShowGrabberImpl::open(vpImage<vpRGBa> &I) { open(); }
125 
131 bool vpDirectShowGrabberImpl::initDirectShow()
132 {
133 
134  // get the first working device's filter (unused and getdevice works on it)
135  currentDevice = getFirstUnusedDevice(pCapSource);
136 
137  if (currentDevice == nbDevices)
138  return false;
139 
140  // create the filter graph
141  if (!createGraph())
142  return false;
143 
144  // we add the capture source to the filter graph
145  if (FAILED(hr = pGraph->AddFilter(pCapSource, L"Capture Filter")))
146  return false;
147 
148  // we create a sample grabber
149  if (!createSampleGrabber(pGrabberFilter))
150  return false;
151 
152  // we add the grabber to the filter graph
153  if (FAILED(hr = pGraph->AddFilter(pGrabberFilter, L"SampleGrabber")))
154  return false;
155 
156  // we connect the pins
157  if (!connectSourceToGrabber(pCapSource, pGrabberFilter))
158  return false;
159 
160  // get the current connected media type (needed by the callback)
161  if (FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
162  return false;
163 
164  // Gets the various graph's interfaces
165  CComPtr<IMediaFilter> pMediaFilter;
166 
167  pGraph->QueryInterface(IID_IMediaFilter, (void **)&pMediaFilter);
168  pGraph->QueryInterface(IID_IMediaControl, reinterpret_cast<void **>(&pControl));
169  pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
170 
171  pMediaFilter->SetSyncSource(nullptr);
172  pMediaFilter.Release();
173 
174  return true;
175 }
176 
180 vpDirectShowGrabberImpl::~vpDirectShowGrabberImpl() { close(); }
181 
187 bool vpDirectShowGrabberImpl::enumerate(CComPtr<IEnumMoniker> &ppVideoInputEnum)
188 {
189  CComPtr<ICreateDevEnum> pDevEnum = nullptr;
190  bool res = false;
191 
192  // Enumerate system devices
193  hr = pDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER);
194 
195  // if it is a success
196  if (SUCCEEDED(hr)) {
197  // Create a video input device enumerator
198  hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &ppVideoInputEnum, 0);
199 
200  if (hr == S_OK)
201  res = true;
202  }
203 
204  pDevEnum.Release();
205  return res;
206 }
207 
213 bool vpDirectShowGrabberImpl::createDeviceList(CComPtr<IEnumMoniker> &ppVideoInputEnum)
214 {
215  CComPtr<IMoniker> pMoniker[10]; // const max devices
216  unsigned long nbMoniker;
217 
218  ppVideoInputEnum->Reset();
219 
220  // Enumerates the different inputs
221  ppVideoInputEnum->Next(10, reinterpret_cast<IMoniker **>(&pMoniker), &nbMoniker);
222 
223  // if no input device
224  if (nbMoniker == 0)
225  return false;
226 
227  deviceList = new vpDirectShowDevice[nbMoniker];
228 
229  nbDevices = (unsigned int)nbMoniker;
230 
231  // we try to get the properties of each moniker, if it fails, we skip to the
232  // next one and decrement the number of valid devices
233  unsigned int i = 0;
234  unsigned int j = 0;
235  while (i < nbDevices) {
236  if (!deviceList[i].init(pMoniker[j])) {
237  // if we can't get the device properties, skip to the next device
238  j++;
239  nbDevices--;
240  } else {
241  i++;
242  j++;
243  }
244  }
245 
246  // if no working input device
247  if (nbDevices == 0)
248  return false;
249 
250  // we release the monikers
251  for (unsigned int i = 0; i < nbMoniker; i++) {
252  pMoniker[i].Release();
253  }
254 
255  return true;
256 }
257 
264 bool vpDirectShowGrabberImpl::getDevice(unsigned int n, CComPtr<IBaseFilter> &ppDevice)
265 {
266  // if n is invalid, quit
267  if (n >= nbDevices)
268  return false;
269 
270  // if the device is already in use, quit
271  if (deviceList[n].getState() == true)
272  return false;
273 
274  // if we can't enumerate the devices, quit
275  CComPtr<IEnumMoniker> pVideoInputEnum = nullptr;
276  if (!enumerate(pVideoInputEnum))
277  return false;
278 
279  CComPtr<IMoniker> pMoniker = nullptr;
280  bool deviceFound = false;
281 
282  // Enumerates the different inputs
283  while (pVideoInputEnum->Next(1, &pMoniker, nullptr) == S_OK && !deviceFound) {
284  // implicit conversion should work ...
285  if (deviceList[n] == vpDirectShowDevice(pMoniker)) {
286  // we get the filter
287  if (SUCCEEDED(pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void **)&ppDevice))) {
288  // now the device is in use
289  deviceList[n].setInUse();
290  deviceFound = true;
291  } else {
292  break;
293  } // we can't get the device's filter, quit
294  }
295  pMoniker.Release();
296  }
297 
298  pVideoInputEnum.Release();
299 
300  return deviceFound;
301 }
302 
309 unsigned int vpDirectShowGrabberImpl::getFirstUnusedDevice(CComPtr<IBaseFilter> &ppDevice)
310 {
311  unsigned int n = 0;
312  bool found = false;
313 
314  for (n = 0; n < nbDevices && !found; n++) {
315  // if the device is not being used
316  if (!deviceList[n].getState()) {
317  if (getDevice(n, ppDevice)) {
318  found = true;
319  deviceList[n].setInUse();
320  return n;
321  }
322  }
323  }
324 
325  return n;
326 }
327 
332 bool vpDirectShowGrabberImpl::createGraph()
333 {
334 
335  // Create the Capture Graph Builder.
336  hr = pBuild.CoCreateInstance(CLSID_CaptureGraphBuilder2, 0, CLSCTX_INPROC_SERVER);
337 
338  if (SUCCEEDED(hr)) {
339  // Create the Filter Graph Manager.
340  hr = pGraph.CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER);
341 
342  if (SUCCEEDED(hr)) {
343  // Initialize the Capture Graph Builder.
344  pBuild->SetFiltergraph(pGraph);
345 
346  return true;
347  }
348  }
349 
350  return false;
351 }
352 
358 bool vpDirectShowGrabberImpl::createSampleGrabber(CComPtr<IBaseFilter> &ppGrabberFilter)
359 {
360  // Creates the sample grabber
361  hr = ppGrabberFilter.CoCreateInstance(CLSID_SampleGrabber, nullptr, CLSCTX_INPROC_SERVER);
362 
363  if (FAILED(hr))
364  return false;
365 
366  // gets the SampleGrabber interface in order to configure it later
367  hr = ppGrabberFilter->QueryInterface(IID_ISampleGrabber, reinterpret_cast<void **>(&pGrabberI));
368 
369  if (FAILED(hr))
370  return false;
371 
372  // configure the grabber
373  AM_MEDIA_TYPE mt;
374  ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
375 
376  mt.majortype = MEDIATYPE_Video;
377 
378  // ask for a connection
379  mt.subtype = MEDIATYPE_nullptr;
380 
381  if (FAILED(hr = pGrabberI->SetMediaType(&mt)))
382  return false;
383 
384  // configure the callback of the grabber
385  pGrabberI->SetCallback(&sgCB, 1);
386 
387  // grab only one frame at a time
388  pGrabberI->SetOneShot(TRUE);
389 
390  // no need to bufferize the sample in the grabber
391  pGrabberI->SetBufferSamples(false);
392 
393  return true;
394 }
395 
405 bool vpDirectShowGrabberImpl::checkSourceType(CComPtr<IPin> &pCapSourcePin)
406 {
407  // retrieves the connected media type
408  AM_MEDIA_TYPE mt;
409  if (FAILED(pCapSourcePin->ConnectionMediaType(&mt)))
410  return false;
411 
412  if (mt.majortype != MEDIATYPE_Video)
413  return false;
414 
415  // Known RGB formats
416  if (mt.subtype == MEDIASUBTYPE_ARGB32 || mt.subtype == MEDIASUBTYPE_RGB32 || mt.subtype == MEDIASUBTYPE_RGB24 ||
417  mt.subtype == MEDIASUBTYPE_RGB555 || mt.subtype == MEDIASUBTYPE_RGB565 || mt.subtype == MEDIASUBTYPE_RGB8 ||
418  mt.subtype == MEDIASUBTYPE_RGB4 || mt.subtype == MEDIASUBTYPE_RGB1) {
419  // image orientation will be handled "automatically"
420  sgCB.specialMediaType = false;
421  }
422  // Known YUV formats
423  else if (mt.subtype == MEDIASUBTYPE_AYUV || mt.subtype == MEDIASUBTYPE_UYVY || mt.subtype == MEDIASUBTYPE_Y411 ||
424  mt.subtype == MEDIASUBTYPE_Y41P || mt.subtype == MEDIASUBTYPE_Y211 || mt.subtype == MEDIASUBTYPE_YUY2 ||
425  mt.subtype == MEDIASUBTYPE_YVYU || mt.subtype == MEDIASUBTYPE_YUYV || mt.subtype == MEDIASUBTYPE_IF09 ||
426  mt.subtype == MEDIASUBTYPE_IYUV || mt.subtype == MEDIASUBTYPE_YV12 || mt.subtype == MEDIASUBTYPE_YVU9) {
427  // image orientation will be handled "automatically"
428  sgCB.specialMediaType = false;
429  }
430  // FOURCC formats
431  else {
432  // invertedSource boolean will decide the bitmap orientation
433  sgCB.specialMediaType = true;
434 
435  DWORD format;
436  VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER *>(mt.pbFormat);
437  BITMAPINFOHEADER bmpInfo = pVih->bmiHeader;
438 
439  // get the fourcc code
440  format = ((bmpInfo.biCompression & 0xFF000000) >> 24) | ((bmpInfo.biCompression & 0x00FF0000) >> 8) |
441  ((bmpInfo.biCompression & 0x0000FF00) << 8) | (bmpInfo.biCompression & 0x000000FF) << 24;
442 
443  std::cout << "This format is not one of the standard YUV or RGB format "
444  "supported by DirectShow.\n"
445  << "FourCC : " << (char)(bmpInfo.biCompression & 0x000000FF)
446  << (char)((bmpInfo.biCompression & 0x0000FF00) >> 8) << (char)((bmpInfo.biCompression & 0x00FF0000) >> 16)
447  << (char)((bmpInfo.biCompression & 0xFF000000) >> 24) << std::endl;
448 
449  // Y800 is top-down oriented so the image doesn't have to be flipped
450  // vertically
451  if (format == 'Y800') {
452  sgCB.invertedSource = false;
453  }
454  // cyuv seems to be the only yuv bottom-up oriented format (image has to
455  // be flipped)
456  else if (format == 'cyuv') {
457  sgCB.invertedSource = true;
458  }
459  // insert code for other fourcc formats here
460  // see fourcc.org to know which format is bottom-up oriented and thus
461  // needs invertedSource sets to true
462  else {
463  std::cout << "Unknown FourCC compression type, assuming top-down "
464  "orientation. Image may be inverted."
465  << std::endl;
466  sgCB.invertedSource = false; // consider that the image is topdown oriented by default
467  }
468  }
469 
470  return true;
471 }
472 
479 bool vpDirectShowGrabberImpl::connectSourceToGrabber(CComPtr<IBaseFilter> &_pCapSource,
480  CComPtr<IBaseFilter> &_pGrabberFilter)
481 {
482  /*
483  //get the capture source's output pin
484  CComPtr<IPin> pCapSourcePin;
485  if(FAILED(pBuild->FindPin(_pCapSource, PINDIR_OUTPUT, nullptr, nullptr, false, 0,
486  &pCapSourcePin))) return false;
487 
488  //get the grabber's input pin
489  CComPtr<IPin> pGrabberInputPin;
490  if(FAILED(pBuild->FindPin(_pGrabberFilter, PINDIR_INPUT, nullptr, nullptr, false,
491  0, &pGrabberInputPin))) return false;
492 
493  //connect the two of them
494  if(FAILED(pGraph->Connect(pCapSourcePin, pGrabberInputPin)))
495  return false;
496 
497  //not used anymore, we can release it
498  pGrabberInputPin.Release();
499  */
500  if (FAILED(hr = pBuild->RenderStream(nullptr, nullptr, _pCapSource, nullptr, _pGrabberFilter)))
501  return false;
502 
503  // get the Null renderer
504  CComPtr<IBaseFilter> pNull = nullptr;
505  if (FAILED(pNull.CoCreateInstance(CLSID_NullRenderer, nullptr, CLSCTX_INPROC_SERVER)))
506  return false;
507 
508  if (FAILED(pGraph->AddFilter(pNull, L"NullRenderer")) ||
509  FAILED(pBuild->RenderStream(nullptr, nullptr, _pGrabberFilter, nullptr, pNull)))
510  return false;
511 
512  // get the capture source's output pin
513  CComPtr<IPin> pCapSourcePin;
514  if (FAILED(pBuild->FindPin(_pCapSource, PINDIR_OUTPUT, nullptr, nullptr, false, 0, &pCapSourcePin)))
515  return false;
516  // checks the media type of the capture filter
517  // and if the image needs to be inverted
518  if (!checkSourceType(pCapSourcePin))
519  return false;
520 
521  // release the remaining interfaces
522  pCapSourcePin.Release();
523  pNull.Release();
524 
525  return true;
526 }
527 
533 bool vpDirectShowGrabberImpl::removeAll()
534 {
535  CComPtr<IEnumFilters> pEnum = nullptr;
536  CComPtr<IBaseFilter> pFilter;
537  ULONG cFetched;
538 
539  if (FAILED(hr = pGraph->EnumFilters(&pEnum)))
540  return false;
541 
542  while (pEnum->Next(1, &pFilter, &cFetched) == S_OK) {
543  if (FAILED(hr = pGraph->RemoveFilter(pFilter)))
544  return false;
545  pFilter.Release();
546  pEnum->Reset();
547  }
548 
549  pEnum.Release();
550  return true;
551 }
552 
561 void vpDirectShowGrabberImpl::acquire(vpImage<vpRGBa> &I)
562 {
563  if (init == false) {
564  close();
566  }
567 
568  // set the rgbaIm pointer on I (will be filled on the next framegrabber
569  // callback)
570  sgCB.rgbaIm = &I;
571  // there is an acquire demand (execute copy during callback)
572  sgCB.acqRGBaDemand = true;
573 
574  // Run the graph to grab a frame
575  pControl->Run();
576 
577  // Wait untill it's done
578  long ev;
579  hr = pEvent->WaitForCompletion(MAX_DELAY, &ev);
580 
581  width = I.getWidth();
582  height = I.getHeight();
583 
584  // wait for the end of the next callback (copy)
585  if (WaitForSingleObject(sgCB.copySem, MAX_DELAY) != WAIT_OBJECT_0)
586  throw(vpFrameGrabberException(vpFrameGrabberException::otherError, "Can't grab the frame, callback timeout"));
587 }
588 
597 void vpDirectShowGrabberImpl::acquire(vpImage<unsigned char> &I)
598 {
599  if (init == false) {
600  close();
602  }
603 
604  // set the grayIm pointer on I (will be filled on the next framegrabber
605  // callback)
606  sgCB.grayIm = &I;
607  // there is an acquire demand (execute copy during callback)
608  sgCB.acqGrayDemand = true;
609 
610  // Run the graph to grab a frame
611  pControl->Run();
612 
613  // Wait untill it's done
614  long ev;
615  hr = pEvent->WaitForCompletion(MAX_DELAY, &ev);
616 
617  width = I.getWidth();
618  height = I.getHeight();
619 
620  // wait for the end of the next callback (copy)
621  if (WaitForSingleObject(sgCB.copySem, MAX_DELAY) != WAIT_OBJECT_0)
622  throw(vpFrameGrabberException(vpFrameGrabberException::otherError, "Can't grab the frame, callback timeout"));
623 }
624 
631 bool vpDirectShowGrabberImpl::setDevice(unsigned int id)
632 {
633  if (init == false) {
634  close();
636  }
637 
638  // if n is invalid, or the device is already in use, quit
639  if (id >= nbDevices || deviceList[id].getState() == true)
640  return false;
641 
642  // we stop the graph
643  pControl->Stop();
644 
645  // then we can safely remove all the filters
646  if (!removeAll())
647  return false;
648 
649  // we release the previous source's interface
650  pCapSource.Release();
651 
652  // here reset inUse in the old DSDevice
653  deviceList[currentDevice].resetInUse();
654 
655  // we add the grabber back in the graph
656  pGraph->AddFilter(pGrabberFilter, L"SampleGrabber");
657 
658  // get the n-th device's filter
659  if (!getDevice(id, pCapSource))
660  return false;
661 
662  // we add the capture source to the filter graph
663  if (FAILED(hr = pGraph->AddFilter(pCapSource, L"Capture Filter")))
664  return false;
665 
666  // we connect the pins
667  if (!connectSourceToGrabber(pCapSource, pGrabberFilter))
668  return false;
669 
670  // get the current connected media type (needed by the callback)
671  if (FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType)))) {
672  return false;
673  }
674 
675  // the device is now in use
676  deviceList[id].setInUse();
677  currentDevice = id;
678 
679  return true;
680 }
681 
685 void vpDirectShowGrabberImpl::displayDevices()
686 {
687  if (deviceList == nullptr) {
689  }
690 
691  for (unsigned int i = 0; i < nbDevices; i++)
692  std::cout << i << " : " << deviceList[i].getName() << std::endl;
693 
694  std::cout << "Current device : " << currentDevice << std::endl << std::endl;
695 }
696 
701 void vpDirectShowGrabberImpl::close()
702 {
703  // the current device isn't being used anymore
704  if (init) {
705  deviceList[currentDevice].resetInUse();
706  init = false;
707  }
708  if (initCo) {
709  // uninstalls COM
710  CoUninitialize();
711  initCo = false;
712  }
713 }
717 bool vpDirectShowGrabberImpl::setImageSize(unsigned int width, unsigned int height)
718 {
719  if (init == false) {
720  close();
722  }
723 
724  return setFormat(width, height, nullptr);
725 }
726 
730 bool vpDirectShowGrabberImpl::setFramerate(double framerate)
731 {
732  if (init == false) {
733  close();
735  }
736 
737  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)sgCB.connectedMediaType.pbFormat;
738  return setFormat(pVih->bmiHeader.biWidth, pVih->bmiHeader.biHeight, framerate);
739 }
743 bool vpDirectShowGrabberImpl::setFormat(unsigned int width, unsigned int height, double framerate)
744 {
745  if (init == false) {
746  close();
748  }
749 
750  bool found = false;
751 
752  // gets the stream config interface
753  IAMStreamConfig *pConfig = nullptr;
754 
755  if (FAILED(hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
756  0, // Any media type.
757  pGrabberFilter, // Pointer to the grabber filter.
758  IID_IAMStreamConfig, (void **)&pConfig)))
759  return false;
760 
761  // gets the video control interface
762  IAMVideoControl *pVideoControl = nullptr;
763 
764  if (FAILED(hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
765  0, // Any media type.
766  pGrabberFilter, // Pointer to the grabber filter.
767  IID_IAMVideoControl, (void **)&pVideoControl)))
768  return false;
769 
770  // get the grabber's input pin
771  CComPtr<IPin> pCapSourcePin;
772  if (FAILED(pBuild->FindPin(pCapSource, PINDIR_OUTPUT, nullptr, nullptr, false, 0, &pCapSourcePin)))
773  return false;
774 
775  int iCount = 0, iSize = 0;
776  if (FAILED(hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize)))
777  return false;
778 
779  // Check the size to make sure we pass in the correct structure.
780  if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
781  // Use the video capabilities structure.
782 
783  for (int iFormat = 0; iFormat < iCount; iFormat++) {
784  VIDEO_STREAM_CONFIG_CAPS scc;
785  AM_MEDIA_TYPE *pmtConfig;
786  hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE *)&scc);
787 
788  if (SUCCEEDED(hr) && found == false) {
789  /* Examine the format, and possibly use it. */
790  if ((pmtConfig->majortype == sgCB.connectedMediaType.majortype) &&
791  (pmtConfig->subtype == sgCB.connectedMediaType.subtype) &&
792  (pmtConfig->formattype == sgCB.connectedMediaType.formattype) &&
793  (pmtConfig->cbFormat >= sizeof(VIDEOINFOHEADER)) && (pmtConfig->pbFormat != nullptr)) {
794  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)pmtConfig->pbFormat;
795 
796  LONG lWidth = pVih->bmiHeader.biWidth;
797  LONG lHeight = pVih->bmiHeader.biHeight;
798  if (framerate != nullptr) {
799  if ((unsigned int)lWidth == width && (unsigned int)lHeight == height) {
800 
801  pVih->AvgTimePerFrame = (LONGLONG)(10000000 / framerate);
802  // set the capture media type and the grabber media type
803  if (FAILED(hr = pConfig->SetFormat(pmtConfig)) || FAILED(hr = pGrabberI->SetMediaType(pmtConfig)))
804  return false;
805  // Run the graph to grab a frame
806  pControl->Run();
807 
808  // get the current connected media type (needed by the callback)
809  if (FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
810  return false;
811  pVih = (VIDEOINFOHEADER *)sgCB.connectedMediaType.pbFormat;
812  LONGLONG ActualFrameDuration;
813  if (FAILED(hr = pVideoControl->GetCurrentActualFrameRate(pCapSourcePin, &ActualFrameDuration)))
814  std::cout << "Current format (not sure): " << width << " x " << height << " at "
815  << 10000000 / pVih->AvgTimePerFrame << " fps" << std::endl
816  << std::endl;
817  else {
818  std::cout << "Current format : " << width << " x " << height << " at " << 10000000 / ActualFrameDuration
819  << " fps" << std::endl
820  << std::endl;
821  pVih->AvgTimePerFrame = ActualFrameDuration;
822  }
823  found = true;
824  }
825  } else {
826  if ((unsigned int)lWidth == width && (unsigned int)lHeight == height) {
827  pVih->AvgTimePerFrame = scc.MinFrameInterval;
828  // set the capture media type and the grabber media type
829  if (FAILED(hr = pConfig->SetFormat(pmtConfig)) || FAILED(hr = pGrabberI->SetMediaType(pmtConfig)))
830  return false;
831  // get the current connected media type (needed by the callback)
832  if (FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
833  return false;
834  pVih = (VIDEOINFOHEADER *)sgCB.connectedMediaType.pbFormat;
835  found = true;
836  std::cout << "Current format : " << width << " x " << height << " at "
837  << (10000000 / pVih->AvgTimePerFrame) << " fps" << std::endl
838  << std::endl;
839  }
840  }
841  }
842  }
843  // Delete the media type when you are done.
844  MyDeleteMediaType(pmtConfig);
845  }
846  }
847  if (!found)
848  if (framerate != nullptr)
849  std::cout << "The " << width << " x " << height << " at " << framerate
850  << " fps source image format is not available. " << std::endl
851  << std::endl;
852  else
853  std::cout << "The " << width << " x " << height << "source image size is not available. " << std::endl
854  << std::endl;
855 
856  return found;
857 }
864 void vpDirectShowGrabberImpl::getFormat(unsigned int &width, unsigned int &height, double &framerate)
865 {
866  if (init == false) {
867  close();
869  }
870  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)sgCB.connectedMediaType.pbFormat;
871  width = (unsigned int)pVih->bmiHeader.biWidth;
872  height = (unsigned int)pVih->bmiHeader.biHeight;
873  framerate = (double)(10000000 / pVih->AvgTimePerFrame);
874 }
878 bool vpDirectShowGrabberImpl::getStreamCapabilities()
879 {
880  if (init == false) {
881  close();
883  }
884 
885  // gets the stream config interface
886  IAMStreamConfig *pConfig = nullptr;
887 
888  if (FAILED(hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
889  0, // Any media type.
890  pGrabberFilter, // Pointer to the grabber filter.
891  IID_IAMStreamConfig, (void **)&pConfig)))
892  return false;
893 
894  int iCount = 0, iSize = 0;
895  if (FAILED(hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize)))
896  return false;
897 
898  // Check the size to make sure we pass in the correct structure.
899  if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
900  std::cout << "Available MediaTypes : " << std::endl << std::endl;
901  // Use the video capabilities structure.
902  for (int iFormat = 0; iFormat < iCount; iFormat++) {
903  VIDEO_STREAM_CONFIG_CAPS scc;
904  AM_MEDIA_TYPE *pmtConfig;
905  hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE *)&scc);
906 
907  if (SUCCEEDED(hr)) {
908  /* Examine the format, and possibly use it. */
909  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)pmtConfig->pbFormat;
910 
911  std::cout << "MediaType : " << iFormat << std::endl;
912 
913  if (pmtConfig->subtype == MEDIASUBTYPE_ARGB32)
914  std::cout << "subtype (not supported): MEDIASUBTYPE_ARGB32" << std::endl;
915  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB32)
916  std::cout << "subtype : MEDIASUBTYPE_RGB32" << std::endl;
917  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB24)
918  std::cout << "subtype : MEDIASUBTYPE_RGB24" << std::endl;
919  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB555)
920  std::cout << "subtype (not supported): MEDIASUBTYPE_RGB555" << std::endl;
921  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB565)
922  std::cout << "subtype (not supported): MEDIASUBTYPE_RGB565" << std::endl;
923  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB8)
924  std::cout << "subtype (not supported): MEDIASUBTYPE_RGB8" << std::endl;
925  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB4)
926  std::cout << "subtype (not supported): MEDIASUBTYPE_RGB4" << std::endl;
927  else if (pmtConfig->subtype == MEDIASUBTYPE_RGB1)
928  std::cout << "subtype (not supported): MEDIASUBTYPE_RGB1" << std::endl;
929  else if (pmtConfig->subtype == MEDIASUBTYPE_YV12)
930  std::cout << "subtype : MEDIASUBTYPE_YV12" << std::endl;
931  else if (pmtConfig->subtype == MEDIASUBTYPE_YVU9)
932  std::cout << "subtype : MEDIASUBTYPE_YVU9" << std::endl;
933  else if (pmtConfig->subtype == MEDIASUBTYPE_YUY2)
934  std::cout << "subtype : MEDIASUBTYPE_YUY2" << std::endl;
935  else if (pmtConfig->subtype == MEDIASUBTYPE_YUYV)
936  std::cout << "subtype : MEDIASUBTYPE_YUYV" << std::endl;
937  else if (pmtConfig->subtype == MEDIASUBTYPE_YVYU)
938  std::cout << "subtype : MEDIASUBTYPE_YVYU" << std::endl;
939  else if (pmtConfig->subtype == MEDIASUBTYPE_IYUV)
940  std::cout << "subtype : MEDIASUBTYPE_IYUV" << std::endl;
941  else if (pmtConfig->subtype == MEDIASUBTYPE_UYVY)
942  std::cout << "subtype : MEDIASUBTYPE_UYVY" << std::endl;
943  else if ((((pVih->bmiHeader.biCompression & 0xFF000000) >> 24) |
944  ((pVih->bmiHeader.biCompression & 0x00FF0000) >> 8) |
945  ((pVih->bmiHeader.biCompression & 0x0000FF00) << 8) |
946  ((pVih->bmiHeader.biCompression & 0x000000FF) << 24)) == 'I420')
947  std::cout << "subtype : I420" << std::endl;
948  else
949  std::cout << "subtype (not supported) :" << (char)(pVih->bmiHeader.biCompression & 0x000000FF)
950  << (char)((pVih->bmiHeader.biCompression & 0x0000FF00) >> 8)
951  << (char)((pVih->bmiHeader.biCompression & 0x00FF0000) >> 16)
952  << (char)((pVih->bmiHeader.biCompression & 0xFF000000) >> 24) << std::endl;
953 
954  std::cout << "image size : " << pVih->bmiHeader.biWidth << " x " << pVih->bmiHeader.biHeight << std::endl;
955  std::cout << "framerate range: [" << 10000000 / scc.MaxFrameInterval << "," << 10000000 / scc.MinFrameInterval
956  << "]" << std::endl
957  << std::endl;
958 
959  /*
960  long frameRateNum;
961  LONGLONG *frameRateList;
962  if(FAILED(hr =
963  pVideoControl->GetFrameRateList(pCapSourcePin,iFormat,dimensions,
964  //inputs &frameRateNum, &frameRateList))) //outputs return false;
965  for(int i=0; i<(int)frameRateNum ;
966  i++)
967  {
968  std::cout<<(float)(10000000/frameRateList[i])<<"
969  fps"<<std::endl;
970  }
971  std::cout<<std::endl;
972  */
973  }
974  // Delete the media type when you are done.
975  MyDeleteMediaType(pmtConfig);
976  }
977  }
978  return true;
979 }
983 bool vpDirectShowGrabberImpl::setMediaType(int mediaTypeID)
984 {
985  if (init == false) {
986  close();
988  }
989 
990  // gets the stream config interface
991  IAMStreamConfig *pConfig = nullptr;
992 
993  if (FAILED(hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
994  0, // Any media type.
995  pGrabberFilter, // Pointer to the grabber filter.
996  IID_IAMStreamConfig, (void **)&pConfig)))
997  return false;
998 
999  VIDEO_STREAM_CONFIG_CAPS scc;
1000  AM_MEDIA_TYPE *pmtConfig;
1001  hr = pConfig->GetStreamCaps(mediaTypeID, &pmtConfig, (BYTE *)&scc);
1002 
1003  if (SUCCEEDED(hr)) {
1004  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)pmtConfig->pbFormat;
1005  pVih->AvgTimePerFrame = scc.MinFrameInterval;
1006  // set the capture media type and the grabber media type
1007  if (FAILED(hr = pGrabberI->SetMediaType(pmtConfig)) || FAILED(hr = pConfig->SetFormat(pmtConfig)))
1008  return false;
1009  // get the current connected media type (needed by the callback)
1010  if (FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
1011  return false;
1012  }
1013  // Delete the media type when you are done.
1014  MyDeleteMediaType(pmtConfig);
1015  return true;
1016 }
1017 
1018 /*
1019  Get current capture MediaType
1020  \return mediaTypeID (-1 if failed)
1021 */
1022 int vpDirectShowGrabberImpl::getMediaType()
1023 {
1024  if (init == false) {
1025  close();
1026  throw(vpFrameGrabberException(vpFrameGrabberException::initializationError, "Initialization not done"));
1027  }
1028 
1029  int mediaTypeID = -1;
1030  VIDEOINFOHEADER *pVihConnected = (VIDEOINFOHEADER *)sgCB.connectedMediaType.pbFormat;
1031 
1032  // gets the stream config interface
1033  IAMStreamConfig *pConfig = nullptr;
1034 
1035  if (FAILED(hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
1036  0, // Any media type.
1037  pGrabberFilter, // Pointer to the grabber filter.
1038  IID_IAMStreamConfig, (void **)&pConfig)))
1039  return -1;
1040 
1041  int iCount = 0, iSize = 0;
1042  if (FAILED(hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize)))
1043  return -1;
1044 
1045  // Check the size to make sure we pass in the correct structure.
1046  if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
1047  // Use the video capabilities structure.
1048  for (int iFormat = 0; iFormat < iCount; iFormat++) {
1049  VIDEO_STREAM_CONFIG_CAPS scc;
1050  AM_MEDIA_TYPE *pmtConfig;
1051  hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE *)&scc);
1052 
1053  if (SUCCEEDED(hr)) {
1054  /* Examine the format, and possibly use it. */
1055  if ((pmtConfig->majortype == sgCB.connectedMediaType.majortype) &&
1056  (pmtConfig->subtype == sgCB.connectedMediaType.subtype) &&
1057  (pmtConfig->formattype == sgCB.connectedMediaType.formattype) &&
1058  (pmtConfig->cbFormat >= sizeof(VIDEOINFOHEADER)) && (pmtConfig->pbFormat != nullptr)) {
1059  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)pmtConfig->pbFormat;
1060  if (pVih->bmiHeader.biWidth == pVihConnected->bmiHeader.biWidth &&
1061  pVih->bmiHeader.biHeight == pVihConnected->bmiHeader.biHeight)
1062  mediaTypeID = iFormat;
1063  }
1064  }
1065  // Delete the media type when you are done.
1066  MyDeleteMediaType(pmtConfig);
1067  }
1068  }
1069  return mediaTypeID;
1070 }
1071 
1076 void vpDirectShowGrabberImpl::MyDeleteMediaType(AM_MEDIA_TYPE *pmt)
1077 {
1078  if (pmt != nullptr) {
1079  MyFreeMediaType(*pmt); // See FreeMediaType for the implementation.
1080  CoTaskMemFree(pmt);
1081  }
1082 }
1083 
1087 void vpDirectShowGrabberImpl::MyFreeMediaType(AM_MEDIA_TYPE &mt)
1088 {
1089  if (mt.cbFormat != 0) {
1090  CoTaskMemFree((PVOID)mt.pbFormat);
1091  mt.cbFormat = 0;
1092  mt.pbFormat = nullptr;
1093  }
1094  if (mt.pUnk != nullptr) {
1095  // Unecessary because pUnk should not be used, but safest.
1096  mt.pUnk->Release();
1097  mt.pUnk = nullptr;
1098  }
1099 }
1100 
1101 #elif !defined(VISP_BUILD_SHARED_LIBS)
1102 // Work around to avoid warning:
1103 // libvisp_sensor.a(vpDirectShowGrabberImpl.cpp.o) has no symbols
1104 void dummy_vpDirectShowGrabberImpl(){};
1105 #endif
1106 #endif
Error that can be emitted by the vpFrameGrabber class and its derivates.
@ initializationError
Grabber initialization error.
@ otherError
Grabber returned an other error.
unsigned int getWidth() const
Definition: vpImage.h:245
unsigned int getHeight() const
Definition: vpImage.h:184
void init(unsigned int h, unsigned int w, Type value)
Definition: vpImage.h:619