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