Visual Servoing Platform version 3.5.0
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
47vpDirectShowDevice *vpDirectShowGrabberImpl::deviceList = NULL;
48unsigned int vpDirectShowGrabberImpl::nbDevices;
49
53void 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
70vpDirectShowGrabberImpl::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
98void 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}
122void vpDirectShowGrabberImpl::open(vpImage<unsigned char> &I) { open(); }
123
128void vpDirectShowGrabberImpl::open(vpImage<vpRGBa> &I) { open(); }
129
135bool 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
184vpDirectShowGrabberImpl::~vpDirectShowGrabberImpl() { close(); }
185
191bool 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
217bool 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
268bool 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
313unsigned 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
336bool 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
362bool 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
409bool 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
483bool 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
556bool 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
584void 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
620void 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
654bool 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
708void 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
724void 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}
740bool 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
753bool 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}
766bool 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}
897void 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}
911bool 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}
1022bool vpDirectShowGrabberImpl::setMediaType(int mediaTypeID)
1023{
1024 if (init == false) {
1025 close();
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*/
1061int vpDirectShowGrabberImpl::getMediaType()
1062{
1063 if (init == false) {
1064 close();
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
1115void 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
1126void 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
1143void dummy_vpDirectShowGrabberImpl(){};
1144#endif
1145#endif
Error that can be emited by the vpFrameGrabber class and its derivates.
unsigned int getWidth() const
Definition: vpImage.h:246
unsigned int getHeight() const
Definition: vpImage.h:188
void init(unsigned int h, unsigned int w, Type value)
Definition: vpImage.h:631