ViSP  2.8.0
vpDirectShowGrabberImpl.cpp
1 /****************************************************************************
2  *
3  * $Id: vpDirectShowGrabberImpl.cpp 4056 2013-01-05 13:04:42Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2013 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * DirectShow framegrabber implementation.
36  *
37  * Authors:
38  * Bruno Renier
39  * Anthony Saunier
40  *
41  *****************************************************************************/
42 
43 #ifndef DOXYGEN_SHOULD_SKIP_THIS
44 
45 #include <visp/vpConfig.h>
46 #if ( defined(VISP_HAVE_DIRECTSHOW) )
47 
48 #include <visp/vpDirectShowGrabberImpl.h>
49 
50 #ifndef DOXYGEN_SHOULD_SKIP_THIS
51 
52 vpDirectShowDevice * vpDirectShowGrabberImpl::deviceList = NULL;
53 unsigned int vpDirectShowGrabberImpl::nbDevices ;
54 
58 void vpDirectShowGrabberImpl::HRtoStr(std::string str)
59 {
60  TCHAR szErr[MAX_ERROR_TEXT_LEN];
61  DWORD res = AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
62 
63  if (res == 0) str = "Unknown Error: 0x%2x";
64 
65  char msg[MAX_ERROR_TEXT_LEN];
66  sprintf(msg,"%s",szErr);
67  str = msg;
68 }
69 
70 
75 vpDirectShowGrabberImpl::vpDirectShowGrabberImpl()
76 {
77  init = false ;
78  initCo = false ;
79  //COM initialization
80  if (FAILED(hr = CoInitializeEx(NULL,COINIT_MULTITHREADED)))
81  {
82  std::string err;
83  HRtoStr(err);
86  "Can't initialize COM\n"+ err));
87  }
88  initCo = true ;
89 
90  //create the device list
91  if(deviceList == NULL) {
92  CComPtr<IEnumMoniker> pVideoInputEnum = NULL;
93 
94  if(enumerate(pVideoInputEnum)) {
95  createDeviceList(pVideoInputEnum);
96  }
97  //not used anymore, so we release it
98  pVideoInputEnum.Release();
99  }
100 }
101 
106 void vpDirectShowGrabberImpl::open()
107 {
108  //create the device list
109  if(deviceList == NULL) {
110  CComPtr<IEnumMoniker> pVideoInputEnum = NULL;
111 
112  if(enumerate(pVideoInputEnum)) {
113  createDeviceList(pVideoInputEnum);
114  }
115  //not used anymore, so we release it
116  pVideoInputEnum.Release();
117  }
118 
119  init = initDirectShow();
120  if(! init )
121  {
122  std::string err;
123  HRtoStr(err);
126  }
127 }
132 void vpDirectShowGrabberImpl::open(vpImage<unsigned char> &I)
133 {
134  open();
135 }
136 
141 void vpDirectShowGrabberImpl::open(vpImage<vpRGBa> &I)
142 {
143  open();
144 }
145 
151 bool vpDirectShowGrabberImpl::initDirectShow()
152 {
153 
154 
155  //get the first working device's filter (unused and getdevice works on it)
156  currentDevice = getFirstUnusedDevice(pCapSource);
157 
158  if(currentDevice == nbDevices)
159  return false;
160 
161  //create the filter graph
162  if(!createGraph())
163  return false;
164 
165  //we add the capture source to the filter graph
166  if(FAILED(hr = pGraph->AddFilter(pCapSource, L"Capture Filter")))
167  return false;
168 
169  //we create a sample grabber
170  if(!createSampleGrabber(pGrabberFilter))
171  return false;
172 
173  //we add the grabber to the filter graph
174  if(FAILED(hr = pGraph->AddFilter(pGrabberFilter, L"SampleGrabber")))
175  return false;
176 
177  //we connect the pins
178  if(!connectSourceToGrabber(pCapSource, pGrabberFilter))
179  return false;
180 
181 
182  //get the current connected media type (needed by the callback)
183  if(FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
184  return false;
185 
186  //Gets the various graph's interfaces
187  CComPtr<IMediaFilter> pMediaFilter;
188 
189  pGraph->QueryInterface(IID_IMediaFilter, (void **)&pMediaFilter);
190  pGraph->QueryInterface(IID_IMediaControl, reinterpret_cast<void**>(&pControl));
191  pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
192 
193  pMediaFilter->SetSyncSource(NULL);
194  pMediaFilter.Release();
195 
196  return true;
197 }
198 
202 vpDirectShowGrabberImpl::~vpDirectShowGrabberImpl()
203 {
204  close();
205 }
206 
212 bool vpDirectShowGrabberImpl::enumerate(CComPtr<IEnumMoniker>& ppVideoInputEnum)
213 {
214  CComPtr<ICreateDevEnum> pDevEnum = NULL;
215  bool res = false;
216 
217  //Enumerate system devices
218  hr = pDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER);
219 
220  //if it is a success
221  if (SUCCEEDED(hr))
222  {
223  //Create a video input device enumerator
224  hr = pDevEnum->CreateClassEnumerator(
225  CLSID_VideoInputDeviceCategory,
226  &ppVideoInputEnum, 0);
227 
228  if(hr == S_OK) res = true;
229  }
230 
231 
232  pDevEnum.Release();
233  return res;
234 }
235 
236 
242 bool vpDirectShowGrabberImpl::createDeviceList(CComPtr<IEnumMoniker>& ppVideoInputEnum)
243 {
244  CComPtr<IMoniker> pMoniker[10]; //const max devices
245  unsigned long nbMoniker;
246 
247  ppVideoInputEnum->Reset();
248 
249  //Enumerates the different inputs
250  ppVideoInputEnum->Next(10, reinterpret_cast<IMoniker **>(&pMoniker), &nbMoniker);
251 
252  //if no input device
253  if(nbMoniker == 0) return false;
254 
255  deviceList = new vpDirectShowDevice[nbMoniker];
256 
257  nbDevices = (unsigned int)nbMoniker;
258 
259  //we try to get the properties of each moniker, if it fails, we skip to the next one and
260  //decrement the number of valid devices
261  unsigned int i=0;
262  unsigned int j=0;
263  while(i<nbDevices)
264  {
265  if(!deviceList[i].init(pMoniker[j]))
266  {
267  //if we can't get the device properties, skip to the next device
268  j++;
269  nbDevices--;
270  }
271  else
272  {
273  i++;
274  j++;
275  }
276  }
277 
278  //if no working input device
279  if(nbDevices == 0) return false;
280 
281  //we release the monikers
282  for(unsigned int i=0 ; i<nbMoniker ;i++)
283  {
284  pMoniker[i].Release();
285  }
286 
287  return true;
288 }
289 
290 
297 bool vpDirectShowGrabberImpl::getDevice(unsigned int n, CComPtr<IBaseFilter>& ppDevice)
298 {
299  //if n is invalid, quit
300  if(n>=nbDevices)
301  return false;
302 
303  //if the device is already in use, quit
304  if(deviceList[n].getState() == true)
305  return false;
306 
307  //if we can't enumerate the devices, quit
308  CComPtr<IEnumMoniker> pVideoInputEnum = NULL;
309  if(!enumerate(pVideoInputEnum))
310  return false;
311 
312  CComPtr<IMoniker> pMoniker = NULL;
313  bool deviceFound = false;
314 
315  //Enumerates the different inputs
316  while (pVideoInputEnum->Next(1, &pMoniker, NULL) == S_OK
317  && !deviceFound)
318  {
319  //implicit conversion should work ...
320  if(deviceList[n] == vpDirectShowDevice(pMoniker))
321  {
322  //we get the filter
323  if(SUCCEEDED(pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&ppDevice)))
324  {
325  //now the device is in use
326  deviceList[n].setInUse();
327  deviceFound = true;
328  }
329  else{ break; } //we can't get the device's filter, quit
330  }
331  pMoniker.Release();
332  }
333 
334  pVideoInputEnum.Release();
335 
336  return deviceFound;
337 }
338 
344 unsigned int vpDirectShowGrabberImpl::getFirstUnusedDevice(CComPtr<IBaseFilter>& ppDevice)
345 {
346  unsigned int n=0;
347  bool found=false;
348 
349  for(n=0;n<nbDevices && !found; n++)
350  {
351  //if the device is not being used
352  if(!deviceList[n].getState())
353  {
354  if(getDevice(n,ppDevice))
355  {
356  found = true;
357  deviceList[n].setInUse();
358  return n;
359  }
360  }
361  }
362 
363  return n;
364 }
365 
370 bool vpDirectShowGrabberImpl::createGraph()
371 {
372 
373  // Create the Capture Graph Builder.
374  hr = pBuild.CoCreateInstance(CLSID_CaptureGraphBuilder2, 0, CLSCTX_INPROC_SERVER);
375 
376  if (SUCCEEDED(hr))
377  {
378  // Create the Filter Graph Manager.
379  hr = pGraph.CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER);
380 
381  if (SUCCEEDED(hr))
382  {
383  // Initialize the Capture Graph Builder.
384  pBuild->SetFiltergraph(pGraph);
385 
386  return true;
387  }
388  }
389 
390  return false;
391 }
392 
398 bool vpDirectShowGrabberImpl::createSampleGrabber(CComPtr<IBaseFilter>& ppGrabberFilter)
399 {
400  //Creates the sample grabber
401  hr = ppGrabberFilter.CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER);
402 
403  if (FAILED(hr))
404  return false;
405 
406  //gets the SampleGrabber interface in order to configure it later
407  hr = ppGrabberFilter->QueryInterface(IID_ISampleGrabber,
408  reinterpret_cast<void**>(&pGrabberI));
409 
410  if (FAILED(hr))
411  return false;
412 
413  //configure the grabber
414  AM_MEDIA_TYPE mt;
415  ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
416 
417  mt.majortype = MEDIATYPE_Video;
418 
419  //ask for a connection
420  mt.subtype = MEDIATYPE_NULL;
421 
422  if(FAILED(hr = pGrabberI->SetMediaType(&mt)))
423  return false;
424 
425  //configure the callback of the grabber
426  pGrabberI->SetCallback(&sgCB,1);
427 
428  //grab only one frame at a time
429  pGrabberI->SetOneShot(TRUE);
430 
431  //no need to bufferize the sample in the grabber
432  pGrabberI->SetBufferSamples(false);
433 
434  return true;
435 }
436 
446 bool vpDirectShowGrabberImpl::checkSourceType(CComPtr<IPin>& pCapSourcePin)
447 {
448  //retrieves the connected media type
449  AM_MEDIA_TYPE mt;
450  if(FAILED (pCapSourcePin->ConnectionMediaType(&mt)))
451  return false;
452 
453  if(mt.majortype != MEDIATYPE_Video)
454  return false;
455 
456  //Known RGB formats
457  if(mt.subtype == MEDIASUBTYPE_ARGB32 ||
458  mt.subtype == MEDIASUBTYPE_RGB32 ||
459  mt.subtype == MEDIASUBTYPE_RGB24 ||
460  mt.subtype == MEDIASUBTYPE_RGB555 ||
461  mt.subtype == MEDIASUBTYPE_RGB565 ||
462  mt.subtype == MEDIASUBTYPE_RGB8 ||
463  mt.subtype == MEDIASUBTYPE_RGB4 ||
464  mt.subtype == MEDIASUBTYPE_RGB1 )
465  {
466  //image orientation will be handled "automatically"
467  sgCB.specialMediaType = false;
468  }
469  //Known YUV formats
470  else if(mt.subtype == MEDIASUBTYPE_AYUV ||
471  mt.subtype == MEDIASUBTYPE_UYVY ||
472  mt.subtype == MEDIASUBTYPE_Y411 ||
473  mt.subtype == MEDIASUBTYPE_Y41P ||
474  mt.subtype == MEDIASUBTYPE_Y211 ||
475  mt.subtype == MEDIASUBTYPE_YUY2 ||
476  mt.subtype == MEDIASUBTYPE_YVYU ||
477  mt.subtype == MEDIASUBTYPE_YUYV ||
478  mt.subtype == MEDIASUBTYPE_IF09 ||
479  mt.subtype == MEDIASUBTYPE_IYUV ||
480  mt.subtype == MEDIASUBTYPE_YV12 ||
481  mt.subtype == MEDIASUBTYPE_YVU9 )
482  {
483  //image orientation will be handled "automatically"
484  sgCB.specialMediaType = false;
485  }
486  //FOURCC formats
487  else
488  {
489  //invertedSource boolean will decide the bitmap orientation
490  sgCB.specialMediaType = true;
491 
492  DWORD format;
493  VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat);
494  BITMAPINFOHEADER bmpInfo = pVih->bmiHeader;
495 
496  //get the fourcc code
497  format = ((bmpInfo.biCompression&0xFF000000)>>24) |
498  ((bmpInfo.biCompression&0x00FF0000)>>8) |
499  ((bmpInfo.biCompression&0x0000FF00)<<8) |
500  (bmpInfo.biCompression&0x000000FF)<<24;
501 
502  std::cout<<"This format is not one of the standard YUV or RGB format supported by DirectShow.\n"
503  <<"FourCC : "
504  <<(char)(bmpInfo.biCompression&0x000000FF)
505  <<(char)((bmpInfo.biCompression&0x0000FF00)>>8)
506  <<(char)((bmpInfo.biCompression&0x00FF0000)>>16)
507  <<(char)((bmpInfo.biCompression&0xFF000000)>>24)<<std::endl;
508 
509  //Y800 is top-down oriented so the image doesn't have to be flipped vertically
510  if(format == 'Y800')
511  {
512  sgCB.invertedSource = false;
513  }
514  //cyuv seems to be the only yuv bottom-up oriented format (image has to be flipped)
515  else if(format == 'cyuv')
516  {
517  sgCB.invertedSource = true;
518  }
519  //insert code for other fourcc formats here
520  //see fourcc.org to know which format is bottom-up oriented and thus needs invertedSource sets to true
521  else
522  {
523  std::cout<<"Unknown FourCC compression type, assuming top-down orientation. Image may be inverted."<<std::endl;
524  sgCB.invertedSource = false; //consider that the image is topdown oriented by default
525  }
526  }
527 
528  return true;
529 }
530 
537 bool vpDirectShowGrabberImpl::connectSourceToGrabber(CComPtr<IBaseFilter>& _pCapSource, CComPtr<IBaseFilter>& _pGrabberFilter)
538 {
539  /*
540  //get the capture source's output pin
541  CComPtr<IPin> pCapSourcePin;
542  if(FAILED(pBuild->FindPin(_pCapSource, PINDIR_OUTPUT, NULL, NULL, false, 0, &pCapSourcePin)))
543  return false;
544 
545  //get the grabber's input pin
546  CComPtr<IPin> pGrabberInputPin;
547  if(FAILED(pBuild->FindPin(_pGrabberFilter, PINDIR_INPUT, NULL, NULL, false, 0, &pGrabberInputPin)))
548  return false;
549 
550  //connect the two of them
551  if(FAILED(pGraph->Connect(pCapSourcePin, pGrabberInputPin)))
552  return false;
553 
554  //not used anymore, we can release it
555  pGrabberInputPin.Release();
556  */
557  if(FAILED(hr = pBuild->RenderStream(NULL,NULL, _pCapSource, NULL, _pGrabberFilter)))
558  return false;
559 
560  /*
561  //get the grabber's output pin
562  CComPtr<IPin> pGrabberOutputPin;
563  if(FAILED(pBuild->FindPin(_pGrabberFilter, PINDIR_OUTPUT, NULL, NULL, false, 0, &pGrabberOutputPin)))
564  return false;
565  */
566  //get the Null renderer
567  CComPtr<IBaseFilter> pNull = NULL;
568  if (FAILED(pNull.CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER)))
569  return false;
570 /*
571  //get the null renderer's input pin
572  CComPtr<IPin> pNullInputPin;
573  if(FAILED(pBuild->FindPin(pNull, PINDIR_INPUT, NULL, NULL, false, 0, &pNullInputPin)))
574  return false;
575 
576  //connect the grabber's output to the null renderer
577  if( FAILED(pGraph->AddFilter(pNull, L"NullRenderer")) ||
578  FAILED(pGraph->Connect(pGrabberOutputPin, pNullInputPin)))
579  return false;
580 */
581 
582  if( FAILED(pGraph->AddFilter(pNull, L"NullRenderer")) ||
583  FAILED(pBuild->RenderStream(NULL,NULL, _pGrabberFilter, NULL, pNull)))
584  return false;
585 
586  //get the capture source's output pin
587  CComPtr<IPin> pCapSourcePin;
588  if(FAILED(pBuild->FindPin(_pCapSource, PINDIR_OUTPUT, NULL, NULL, false, 0, &pCapSourcePin)))
589  return false;
590  //checks the media type of the capture filter
591  //and if the image needs to be inverted
592  if(!checkSourceType(pCapSourcePin))
593  return false;
594 
595  //release the remaining interfaces
596  pCapSourcePin.Release();
597  pNull.Release();
598 // pGrabberOutputPin.Release();
599 // pNullInputPin.Release();
600 
601  return true;
602 }
603 
604 
610 bool vpDirectShowGrabberImpl::removeAll()
611 {
612  CComPtr<IEnumFilters> pEnum = NULL;
613  CComPtr<IBaseFilter> pFilter;
614  ULONG cFetched;
615 
616  if (FAILED(hr = pGraph->EnumFilters(&pEnum)))
617  return false;
618 
619  while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)
620  {
621  if(FAILED(hr = pGraph->RemoveFilter(pFilter))) return false;
622  pFilter.Release();
623  pEnum->Reset();
624  }
625 
626  pEnum.Release();
627  return true;
628 }
629 
630 
639 void vpDirectShowGrabberImpl::acquire(vpImage<vpRGBa> &I)
640 {
641  if (init==false)
642  {
643  close();
645  "Initialization not done") );
646  }
647 
648  //set the rgbaIm pointer on I (will be filled on the next framegrabber callback)
649  sgCB.rgbaIm = &I;
650  //there is an acquire demand (execute copy during callback)
651  sgCB.acqRGBaDemand = true;
652 
653  //Run the graph to grab a frame
654  pControl->Run();
655 
656  // Wait untill it's done
657  long ev;
658  hr = pEvent->WaitForCompletion(MAX_DELAY, &ev);
659 
660  width = I.getWidth();
661  height = I.getHeight();
662 
663  //wait for the end of the next callback (copy)
664  if( WaitForSingleObject(sgCB.copySem,MAX_DELAY) != WAIT_OBJECT_0)
666  "Can't grab the frame, callback timeout") );
667 
668 
669 }
670 
679 void vpDirectShowGrabberImpl::acquire(vpImage<unsigned char> &I)
680 {
681  if (init==false)
682  {
683  close();
685  "Initialization not done") );
686  }
687 
688  //set the grayIm pointer on I (will be filled on the next framegrabber callback)
689  sgCB.grayIm = &I;
690  //there is an acquire demand (execute copy during callback)
691  sgCB.acqGrayDemand = true;
692 
693  //Run the graph to grab a frame
694  pControl->Run();
695 
696  // Wait untill it's done
697  long ev;
698  hr = pEvent->WaitForCompletion(MAX_DELAY, &ev);
699 
700  width = I.getWidth();
701  height = I.getHeight();
702 
703  //wait for the end of the next callback (copy)
704  if( WaitForSingleObject(sgCB.copySem,MAX_DELAY) != WAIT_OBJECT_0)
706  "Can't grab the frame, callback timeout") );
707 }
708 
715 bool vpDirectShowGrabberImpl::setDevice(unsigned int id)
716 {
717  if (init==false)
718  {
719  close();
721  "Initialization not done") );
722  }
723 
724 
725  //if n is invalid, or the device is already in use, quit
726  if(id>=nbDevices || deviceList[id].getState()==true)
727  return false;
728 
729  //we stop the graph
730  pControl->Stop();
731 
732  //then we can safely remove all the filters
733  if(!removeAll()) return false;
734 
735 
736  //we release the previous source's interface
737  pCapSource.Release();
738 
739  //here reset inUse in the old DSDevice
740  deviceList[currentDevice].resetInUse();
741 
742  //we add the grabber back in the graph
743  pGraph->AddFilter(pGrabberFilter,L"SampleGrabber");
744 
745  //get the n-th device's filter
746  if(!getDevice(id, pCapSource))
747  return false;
748 
749  //we add the capture source to the filter graph
750  if(FAILED(hr = pGraph->AddFilter(pCapSource, L"Capture Filter")))
751  return false;
752 
753  //we connect the pins
754  if(!connectSourceToGrabber(pCapSource, pGrabberFilter))
755  return false;
756 
757 
758  //get the current connected media type (needed by the callback)
759  if(FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
760  {
761  return false;
762  }
763 
764  //the device is now in use
765  deviceList[id].setInUse();
766  currentDevice=id;
767 
768  return true;
769 }
770 
774 void vpDirectShowGrabberImpl::displayDevices()
775 {
776  if(deviceList == NULL)
777  {
779  "Initialization not done") );
780  }
781 
782  for(unsigned int i=0 ; i<nbDevices ; i++)
783  std::cout<<i<<" : "<< deviceList[i].getName() <<std::endl;
784 
785  std::cout<<"Current device : "<<currentDevice<<std::endl<<std::endl;
786 }
787 
788 
793 void vpDirectShowGrabberImpl::close()
794 {
795  //the current device isn't being used anymore
796  if (init) {
797  deviceList[currentDevice].resetInUse();
798  init = false ;
799  }
800  if (initCo) {
801  //uninstalls COM
802  CoUninitialize();
803  initCo = false;
804  }
805 }
809 bool vpDirectShowGrabberImpl::setImageSize(unsigned int width,unsigned int height)
810 {
811  if (init==false)
812  {
813  close();
815  "Initialization not done") );
816  }
817 
818  return setFormat(width, height,NULL);
819 
820 }
821 
825 bool vpDirectShowGrabberImpl::setFramerate(double framerate)
826 {
827  if (init==false)
828  {
829  close();
831  "Initialization not done") );
832  }
833 
834  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)sgCB.connectedMediaType.pbFormat;
835  return setFormat(pVih->bmiHeader.biWidth,pVih->bmiHeader.biHeight,framerate);
836 
837 }
841 bool vpDirectShowGrabberImpl::setFormat(unsigned int width,unsigned int height, double framerate)
842 {
843  if (init==false)
844  {
845  close();
847  "Initialization not done") );
848  }
849 
850  bool found=false;
851 
852  //gets the stream config interface
853  IAMStreamConfig *pConfig = NULL;
854 
855  if(FAILED(hr = pBuild->FindInterface(
856  &LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
857  0, // Any media type.
858  pGrabberFilter, // Pointer to the grabber filter.
859  IID_IAMStreamConfig, (void**)&pConfig)))
860  return false;
861 
862  //gets the video control interface
863  IAMVideoControl *pVideoControl = NULL;
864 
865  if(FAILED(hr = pBuild->FindInterface(
866  &LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
867  0, // Any media type.
868  pGrabberFilter, // Pointer to the grabber filter.
869  IID_IAMVideoControl, (void**)&pVideoControl)))
870  return false;
871 
872  //get the grabber's input pin
873  CComPtr<IPin> pCapSourcePin;
874  if(FAILED(pBuild->FindPin(pCapSource, PINDIR_OUTPUT, NULL, NULL, false, 0, &pCapSourcePin)))
875  return false;
876 
877  int iCount = 0, iSize = 0;
878  if(FAILED(hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize)))
879  return false;
880 
881  // Check the size to make sure we pass in the correct structure.
882  if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
883  {
884  // Use the video capabilities structure.
885 
886  for (int iFormat = 0; iFormat < iCount; iFormat++)
887  {
888  VIDEO_STREAM_CONFIG_CAPS scc;
889  AM_MEDIA_TYPE *pmtConfig;
890  hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
891 // VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
892 
893 // pVih->bmiHeader.biWidth;
894 // pVih->bmiHeader.biHeight;
895 // 10000000 /pVih->AvgTimePerFrame;
896 // std::cout<<"available image size : "<<pVih->bmiHeader.biWidth<<" x "<<pVih->bmiHeader.biHeight<<" at "<<10000000 /pVih->AvgTimePerFrame<<std::endl;
897 // std::cout<<"compression : "<<pVih->bmiHeader.biCompression<<std::endl;
898  if (SUCCEEDED(hr)&& found==false)
899  {
900  /* Examine the format, and possibly use it. */
901  if ((pmtConfig->majortype == sgCB.connectedMediaType.majortype) &&
902  (pmtConfig->subtype == sgCB.connectedMediaType.subtype) &&
903  (pmtConfig->formattype == sgCB.connectedMediaType.formattype) &&
904  (pmtConfig->cbFormat >= sizeof (VIDEOINFOHEADER)) &&
905  (pmtConfig->pbFormat != NULL))
906  {
907  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
908 
909  LONG lWidth = pVih->bmiHeader.biWidth;
910  LONG lHeight = pVih->bmiHeader.biHeight;
911  if(framerate != NULL)
912  {
913  if((unsigned int)lWidth == width && (unsigned int)lHeight == height)
914  {
915 
916  pVih->AvgTimePerFrame = (LONGLONG)(10000000 / framerate);
917  //set the capture media type and the grabber media type
918  if(FAILED(hr = pConfig->SetFormat(pmtConfig))||
919  FAILED(hr = pGrabberI->SetMediaType(pmtConfig)))
920  return false;
921  //Run the graph to grab a frame
922  pControl->Run();
923 
924  //get the current connected media type (needed by the callback)
925  if(FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
926  return false;
927  pVih = (VIDEOINFOHEADER*)sgCB.connectedMediaType.pbFormat;
928  LONGLONG ActualFrameDuration;
929  if(FAILED(hr = pVideoControl->GetCurrentActualFrameRate(pCapSourcePin,&ActualFrameDuration)))
930  std::cout<<"Current format (not sure): "<<width <<" x "<< height <<" at "<< 10000000/pVih->AvgTimePerFrame <<" fps"<<std::endl<<std::endl;
931  else {
932  std::cout<<"Current format : "<<width <<" x "<< height <<" at "<< 10000000/ActualFrameDuration <<" fps"<<std::endl<<std::endl;
933  pVih->AvgTimePerFrame = ActualFrameDuration;
934  }
935  found=true;
936  }
937  }
938  else
939  {
940  if((unsigned int)lWidth == width && (unsigned int)lHeight == height)
941  {
942  pVih->AvgTimePerFrame = scc.MinFrameInterval;
943  //set the capture media type and the grabber media type
944  if(FAILED(hr = pConfig->SetFormat(pmtConfig))||
945  FAILED(hr = pGrabberI->SetMediaType(pmtConfig)))
946  return false;
947  //get the current connected media type (needed by the callback)
948  if(FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
949  return false;
950  pVih = (VIDEOINFOHEADER*)sgCB.connectedMediaType.pbFormat;
951  found=true;
952  std::cout<<"Current format : "<<width <<" x "<< height <<" at "<<(10000000 /pVih->AvgTimePerFrame) <<" fps"<<std::endl<<std::endl;
953  }
954 
955  }
956  }
957  }
958  // Delete the media type when you are done.
959  MyDeleteMediaType(pmtConfig);
960  }
961  }
962  if(!found)
963  if(framerate != NULL)
964  std::cout << "The "<<width <<" x "<< height <<" at " <<framerate<<" fps source image format is not available. "<<std::endl<<std::endl;
965  else
966  std::cout << "The "<<width <<" x "<< height <<"source image size is not available. "<<std::endl<<std::endl;
967 
968  return found;
969 }
976 void vpDirectShowGrabberImpl::getFormat(unsigned int &width,unsigned int &height, double &framerate)
977 {
978  if (init==false)
979  {
980  close();
982  "Initialization not done") );
983  }
984  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)sgCB.connectedMediaType.pbFormat;
985  width = (unsigned int)pVih->bmiHeader.biWidth;
986  height = (unsigned int)pVih->bmiHeader.biHeight;
987  framerate = (double)(10000000/pVih->AvgTimePerFrame);
988 
989 }
993 bool vpDirectShowGrabberImpl::getStreamCapabilities()
994 {
995  if (init==false)
996  {
997  close();
999  "Initialization not done") );
1000  }
1001 
1002  //gets the stream config interface
1003  IAMStreamConfig *pConfig = NULL;
1004 
1005  if(FAILED(hr = pBuild->FindInterface(
1006  &LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
1007  0, // Any media type.
1008  pGrabberFilter, // Pointer to the grabber filter.
1009  IID_IAMStreamConfig, (void**)&pConfig)))
1010  return false;
1011 
1012  int iCount = 0, iSize = 0;
1013  if(FAILED(hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize)))
1014  return false;
1015 
1016  // Check the size to make sure we pass in the correct structure.
1017  if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
1018  {
1019  std::cout<<"Available MediaTypes : "<<std::endl<<std::endl;
1020  // Use the video capabilities structure.
1021  for (int iFormat = 0; iFormat < iCount; iFormat++)
1022  {
1023  VIDEO_STREAM_CONFIG_CAPS scc;
1024  AM_MEDIA_TYPE *pmtConfig;
1025  hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
1026 
1027  if (SUCCEEDED(hr))
1028  {
1029  /* Examine the format, and possibly use it. */
1030  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
1031 
1032 // LONG lWidth = pVih->bmiHeader.biWidth;
1033 // LONG lHeight = pVih->bmiHeader.biHeight;
1034 // SIZE dimensions={lWidth,lHeight};
1035 // LONGLONG lAvgTimePerFrame = pVih->AvgTimePerFrame;
1036  std::cout<<"MediaType : "<<iFormat<<std::endl;
1037 
1038  if(pmtConfig->subtype==MEDIASUBTYPE_ARGB32)
1039  std::cout<<"subtype (not supported): MEDIASUBTYPE_ARGB32"<<std::endl;
1040  else if(pmtConfig->subtype==MEDIASUBTYPE_RGB32)
1041  std::cout<<"subtype : MEDIASUBTYPE_RGB32"<<std::endl;
1042  else if(pmtConfig->subtype==MEDIASUBTYPE_RGB24)
1043  std::cout<<"subtype : MEDIASUBTYPE_RGB24"<<std::endl;
1044  else if(pmtConfig->subtype==MEDIASUBTYPE_RGB555)
1045  std::cout<<"subtype (not supported): MEDIASUBTYPE_RGB555"<<std::endl;
1046  else if(pmtConfig->subtype==MEDIASUBTYPE_RGB565)
1047  std::cout<<"subtype (not supported): MEDIASUBTYPE_RGB565"<<std::endl;
1048  else if(pmtConfig->subtype==MEDIASUBTYPE_RGB8)
1049  std::cout<<"subtype (not supported): MEDIASUBTYPE_RGB8"<<std::endl;
1050  else if(pmtConfig->subtype==MEDIASUBTYPE_RGB4)
1051  std::cout<<"subtype (not supported): MEDIASUBTYPE_RGB4"<<std::endl;
1052  else if(pmtConfig->subtype==MEDIASUBTYPE_RGB1)
1053  std::cout<<"subtype (not supported): MEDIASUBTYPE_RGB1"<<std::endl;
1054  else if(pmtConfig->subtype==MEDIASUBTYPE_YV12)
1055  std::cout<<"subtype : MEDIASUBTYPE_YV12"<<std::endl;
1056  else if(pmtConfig->subtype==MEDIASUBTYPE_YVU9)
1057  std::cout<<"subtype : MEDIASUBTYPE_YVU9"<<std::endl;
1058  else if(pmtConfig->subtype==MEDIASUBTYPE_YUY2)
1059  std::cout<<"subtype : MEDIASUBTYPE_YUY2"<<std::endl;
1060  else if(pmtConfig->subtype==MEDIASUBTYPE_YUYV)
1061  std::cout<<"subtype : MEDIASUBTYPE_YUYV"<<std::endl;
1062  else if(pmtConfig->subtype==MEDIASUBTYPE_YVYU)
1063  std::cout<<"subtype : MEDIASUBTYPE_YVYU"<<std::endl;
1064  else if(pmtConfig->subtype==MEDIASUBTYPE_IYUV)
1065  std::cout<<"subtype : MEDIASUBTYPE_IYUV"<<std::endl;
1066  else if(pmtConfig->subtype==MEDIASUBTYPE_UYVY)
1067  std::cout<<"subtype : MEDIASUBTYPE_UYVY"<<std::endl;
1068  else if((((pVih->bmiHeader.biCompression&0xFF000000)>>24) |
1069  ((pVih->bmiHeader.biCompression&0x00FF0000)>>8) |
1070  ((pVih->bmiHeader.biCompression&0x0000FF00)<<8) |
1071  ((pVih->bmiHeader.biCompression&0x000000FF)<<24)) == 'I420')
1072  std::cout<<"subtype : I420"<<std::endl;
1073  else std::cout<<"subtype (not supported) :"
1074  <<(char)(pVih->bmiHeader.biCompression&0x000000FF)
1075  <<(char)((pVih->bmiHeader.biCompression&0x0000FF00)>>8)
1076  <<(char)((pVih->bmiHeader.biCompression&0x00FF0000)>>16)
1077  <<(char)((pVih->bmiHeader.biCompression&0xFF000000)>>24)<<std::endl;
1078 
1079  std::cout<<"image size : "<<pVih->bmiHeader.biWidth<<" x "<<pVih->bmiHeader.biHeight<<std::endl;
1080  std::cout<<"framerate range: ["<< 10000000/scc.MaxFrameInterval<<","<<10000000/scc.MinFrameInterval<<"]"<<std::endl<<std::endl;
1081 
1082 /*
1083  long frameRateNum;
1084  LONGLONG *frameRateList;
1085  if(FAILED(hr = pVideoControl->GetFrameRateList(pCapSourcePin,iFormat,dimensions, //inputs
1086  &frameRateNum, &frameRateList))) //outputs
1087  return false;
1088  for(int i=0; i<(int)frameRateNum ; i++)
1089  {
1090  std::cout<<(float)(10000000/frameRateList[i])<<" fps"<<std::endl;
1091  }
1092  std::cout<<std::endl;
1093 */
1094  }
1095  // Delete the media type when you are done.
1096  MyDeleteMediaType(pmtConfig);
1097  }
1098  }
1099  return true;
1100 }
1104 bool vpDirectShowGrabberImpl::setMediaType(int mediaTypeID)
1105 {
1106  if (init==false)
1107  {
1108  close();
1110  "Initialization not done") );
1111  }
1112 
1113  //gets the stream config interface
1114  IAMStreamConfig *pConfig = NULL;
1115 
1116  if(FAILED(hr = pBuild->FindInterface(
1117  &LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
1118  0, // Any media type.
1119  pGrabberFilter, // Pointer to the grabber filter.
1120  IID_IAMStreamConfig, (void**)&pConfig)))
1121  return false;
1122 
1123  VIDEO_STREAM_CONFIG_CAPS scc;
1124  AM_MEDIA_TYPE *pmtConfig;
1125  hr = pConfig->GetStreamCaps(mediaTypeID, &pmtConfig, (BYTE*)&scc);
1126 
1127 
1128  if (SUCCEEDED(hr))
1129  {
1130  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
1131  pVih->AvgTimePerFrame = scc.MinFrameInterval ;
1132  //set the capture media type and the grabber media type
1133  if(FAILED(hr = pGrabberI->SetMediaType(pmtConfig))||
1134  FAILED(hr = pConfig->SetFormat(pmtConfig)))
1135  return false;
1136  //get the current connected media type (needed by the callback)
1137  if(FAILED(hr = pGrabberI->GetConnectedMediaType(&(sgCB.connectedMediaType))))
1138  return false;
1139  }
1140  // Delete the media type when you are done.
1141  MyDeleteMediaType(pmtConfig);
1142  return true;
1143 }
1144 
1145 /*
1146  Get current capture MediaType
1147  \return mediaTypeID (-1 if failed)
1148 */
1149 int vpDirectShowGrabberImpl::getMediaType()
1150 {
1151  if (init==false)
1152  {
1153  close();
1155  "Initialization not done") );
1156  }
1157 
1158  int mediaTypeID = -1;
1159  VIDEOINFOHEADER *pVihConnected = (VIDEOINFOHEADER*)sgCB.connectedMediaType.pbFormat;
1160 
1161  //gets the stream config interface
1162  IAMStreamConfig *pConfig = NULL;
1163 
1164  if(FAILED(hr = pBuild->FindInterface(
1165  &LOOK_UPSTREAM_ONLY, // Capture pin. / Preview pin
1166  0, // Any media type.
1167  pGrabberFilter, // Pointer to the grabber filter.
1168  IID_IAMStreamConfig, (void**)&pConfig)))
1169  return -1;
1170 
1171  int iCount = 0, iSize = 0;
1172  if(FAILED(hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize)))
1173  return -1;
1174 
1175  // Check the size to make sure we pass in the correct structure.
1176  if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
1177  {
1178  // Use the video capabilities structure.
1179  for (int iFormat = 0; iFormat < iCount; iFormat++)
1180  {
1181  VIDEO_STREAM_CONFIG_CAPS scc;
1182  AM_MEDIA_TYPE *pmtConfig;
1183  hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
1184 
1185  if (SUCCEEDED(hr))
1186  {
1187  /* Examine the format, and possibly use it. */
1188  if ((pmtConfig->majortype == sgCB.connectedMediaType.majortype) &&
1189  (pmtConfig->subtype == sgCB.connectedMediaType.subtype) &&
1190  (pmtConfig->formattype == sgCB.connectedMediaType.formattype) &&
1191  (pmtConfig->cbFormat >= sizeof (VIDEOINFOHEADER)) &&
1192  (pmtConfig->pbFormat != NULL))
1193  {
1194  VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
1195  if(pVih->bmiHeader.biWidth == pVihConnected->bmiHeader.biWidth &&
1196  pVih->bmiHeader.biHeight == pVihConnected->bmiHeader.biHeight)
1197  mediaTypeID = iFormat ;
1198  }
1199  }
1200  // Delete the media type when you are done.
1201  MyDeleteMediaType(pmtConfig);
1202  }
1203  }
1204  return mediaTypeID;
1205 }
1206 
1207 
1211 void vpDirectShowGrabberImpl::MyDeleteMediaType(AM_MEDIA_TYPE *pmt)
1212 {
1213  if (pmt != NULL)
1214  {
1215  MyFreeMediaType(*pmt); // See FreeMediaType for the implementation.
1216  CoTaskMemFree(pmt);
1217  }
1218 }
1219 
1220 
1224 void vpDirectShowGrabberImpl::MyFreeMediaType(AM_MEDIA_TYPE& mt)
1225 {
1226  if (mt.cbFormat != 0)
1227  {
1228  CoTaskMemFree((PVOID)mt.pbFormat);
1229  mt.cbFormat = 0;
1230  mt.pbFormat = NULL;
1231  }
1232  if (mt.pUnk != NULL)
1233  {
1234  // Unecessary because pUnk should not be used, but safest.
1235  mt.pUnk->Release();
1236  mt.pUnk = NULL;
1237  }
1238 }
1239 
1240 #endif
1241 #endif
1242 #endif
unsigned int getWidth() const
Definition: vpImage.h:159
Error that can be emited by the vpFrameGrabber class and its derivates.
unsigned int getHeight() const
Definition: vpImage.h:150