Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
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
43vpDirectShowDevice *vpDirectShowGrabberImpl::deviceList = NULL;
44unsigned int vpDirectShowGrabberImpl::nbDevices;
45
49void 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
66vpDirectShowGrabberImpl::vpDirectShowGrabberImpl()
67{
68 init = false;
69 initCo = false;
70 // COM initialization
71 if (FAILED(hr = CoInitializeEx(NULL, 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 == NULL) {
80 CComPtr<IEnumMoniker> pVideoInputEnum = NULL;
81
82 if (enumerate(pVideoInputEnum)) {
83 createDeviceList(pVideoInputEnum);
84 }
85 // not used anymore, so we release it
86 pVideoInputEnum.Release();
87 }
88}
89
94void vpDirectShowGrabberImpl::open()
95{
96 // create the device list
97 if (deviceList == NULL) {
98 CComPtr<IEnumMoniker> pVideoInputEnum = NULL;
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}
118void vpDirectShowGrabberImpl::open(vpImage<unsigned char> &I) { open(); }
119
124void vpDirectShowGrabberImpl::open(vpImage<vpRGBa> &I) { open(); }
125
131bool 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(NULL);
172 pMediaFilter.Release();
173
174 return true;
175}
176
180vpDirectShowGrabberImpl::~vpDirectShowGrabberImpl() { close(); }
181
187bool vpDirectShowGrabberImpl::enumerate(CComPtr<IEnumMoniker> &ppVideoInputEnum)
188{
189 CComPtr<ICreateDevEnum> pDevEnum = NULL;
190 bool res = false;
191
192 // Enumerate system devices
193 hr = pDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum, NULL, 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
213bool 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
264bool 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 = NULL;
276 if (!enumerate(pVideoInputEnum))
277 return false;
278
279 CComPtr<IMoniker> pMoniker = NULL;
280 bool deviceFound = false;
281
282 // Enumerates the different inputs
283 while (pVideoInputEnum->Next(1, &pMoniker, NULL) == 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
309unsigned 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
332bool 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
358bool vpDirectShowGrabberImpl::createSampleGrabber(CComPtr<IBaseFilter> &ppGrabberFilter)
359{
360 // Creates the sample grabber
361 hr = ppGrabberFilter.CoCreateInstance(CLSID_SampleGrabber, NULL, 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_NULL;
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
405bool 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
479bool 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, NULL, NULL, 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, NULL, NULL, 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(NULL, NULL, _pCapSource, NULL, _pGrabberFilter)))
501 return false;
502
503 // get the Null renderer
504 CComPtr<IBaseFilter> pNull = NULL;
505 if (FAILED(pNull.CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER)))
506 return false;
507
508 if (FAILED(pGraph->AddFilter(pNull, L"NullRenderer")) ||
509 FAILED(pBuild->RenderStream(NULL, NULL, _pGrabberFilter, NULL, 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, NULL, NULL, 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
533bool vpDirectShowGrabberImpl::removeAll()
534{
535 CComPtr<IEnumFilters> pEnum = NULL;
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
561void 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
597void 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
631bool 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
685void vpDirectShowGrabberImpl::displayDevices()
686{
687 if (deviceList == NULL) {
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
701void 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}
717bool vpDirectShowGrabberImpl::setImageSize(unsigned int width, unsigned int height)
718{
719 if (init == false) {
720 close();
722 }
723
724 return setFormat(width, height, NULL);
725}
726
730bool 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}
743bool 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 = NULL;
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 = NULL;
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, NULL, NULL, 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 != NULL)) {
794 VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER *)pmtConfig->pbFormat;
795
796 LONG lWidth = pVih->bmiHeader.biWidth;
797 LONG lHeight = pVih->bmiHeader.biHeight;
798 if (framerate != NULL) {
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 != NULL)
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}
864void 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}
878bool vpDirectShowGrabberImpl::getStreamCapabilities()
879{
880 if (init == false) {
881 close();
883 }
884
885 // gets the stream config interface
886 IAMStreamConfig *pConfig = NULL;
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}
983bool vpDirectShowGrabberImpl::setMediaType(int mediaTypeID)
984{
985 if (init == false) {
986 close();
988 }
989
990 // gets the stream config interface
991 IAMStreamConfig *pConfig = NULL;
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*/
1022int vpDirectShowGrabberImpl::getMediaType()
1023{
1024 if (init == false) {
1025 close();
1027 }
1028
1029 int mediaTypeID = -1;
1030 VIDEOINFOHEADER *pVihConnected = (VIDEOINFOHEADER *)sgCB.connectedMediaType.pbFormat;
1031
1032 // gets the stream config interface
1033 IAMStreamConfig *pConfig = NULL;
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 != NULL)) {
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
1076void vpDirectShowGrabberImpl::MyDeleteMediaType(AM_MEDIA_TYPE *pmt)
1077{
1078 if (pmt != NULL) {
1079 MyFreeMediaType(*pmt); // See FreeMediaType for the implementation.
1080 CoTaskMemFree(pmt);
1081 }
1082}
1083
1087void vpDirectShowGrabberImpl::MyFreeMediaType(AM_MEDIA_TYPE &mt)
1088{
1089 if (mt.cbFormat != 0) {
1090 CoTaskMemFree((PVOID)mt.pbFormat);
1091 mt.cbFormat = 0;
1092 mt.pbFormat = NULL;
1093 }
1094 if (mt.pUnk != NULL) {
1095 // Unecessary because pUnk should not be used, but safest.
1096 mt.pUnk->Release();
1097 mt.pUnk = NULL;
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
1104void 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.
Definition of the vpImage class member functions.
Definition vpImage.h:135
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getHeight() const
Definition vpImage.h:184