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.
33  *
34  * Authors:
35  * Bruno Renier
36  * Anthony Saunier
37  *
38  *****************************************************************************/
39 #ifndef DOXYGEN_SHOULD_SKIP_THIS
40 
41 #include <visp3/core/vpImageConvert.h>
42 #include <visp3/sensor/vpDirectShowSampleGrabberI.h>
43 
44 #include <visp3/core/vpConfig.h>
45 #if (defined(VISP_HAVE_DIRECTSHOW))
46 
47 /*!
48         Constructor - creates the semaphore
49 */
vpDirectShowSampleGrabberI()50 vpDirectShowSampleGrabberI::vpDirectShowSampleGrabberI()
51   : acqGrayDemand(false), acqRGBaDemand(false), specialMediaType(false), invertedSource(false)
52 {
53   // semaphore(0), max value = 1
54   copySem = CreateSemaphore(NULL, 0, 1, NULL);
55 }
56 
57 /*!
58         Destructor - destroys the semaphore
59 */
~vpDirectShowSampleGrabberI()60 vpDirectShowSampleGrabberI::~vpDirectShowSampleGrabberI()
61 {
62   // destroys the semaphore
63   CloseHandle(copySem);
64 }
65 
QueryInterface(REFIID riid,void ** ppvObject)66 STDMETHODIMP vpDirectShowSampleGrabberI::QueryInterface(REFIID riid, void **ppvObject)
67 {
68   if (NULL == ppvObject)
69     return E_POINTER;
70   if (riid == __uuidof(IUnknown)) {
71     *ppvObject = static_cast<IUnknown *>(this);
72     return S_OK;
73   }
74   if (riid == __uuidof(ISampleGrabberCB)) {
75     *ppvObject = static_cast<ISampleGrabberCB *>(this);
76     return S_OK;
77   }
78   return E_NOTIMPL;
79 }
80 
81 /*!
82         The frame grabber callback -
83         Called when the input buffer is full.
84         Rq : BufferLen == bmpInfo.biWidth*bmpInfo.biHeight*sizeof(vpRGBa)
85 */
BufferCB(double Time,BYTE * pBuffer,long BufferLen)86 STDMETHODIMP vpDirectShowSampleGrabberI::BufferCB(double Time, BYTE *pBuffer, long BufferLen)
87 {
88   // if there has been a frame demand
89   if (acqGrayDemand || acqRGBaDemand) {
90     // check if the connected media is compatible
91     if (connectedMediaType.formattype == FORMAT_VideoInfo) {
92       // retrieve the image information
93       VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER *>(connectedMediaType.pbFormat);
94       BITMAPINFOHEADER bmpInfo = pVih->bmiHeader;
95 
96       // if biHeight > 0 and the source is not special
97       // then  the image needs to be verticaly flipped
98       bool flip;
99       if (!specialMediaType)
100         flip = bmpInfo.biHeight >= 0;
101       // the source is fourcc and the image is inverted with this compression
102       else if (invertedSource)
103         flip = true;
104       // fourcc and the image doesn't need to be flipped
105       else
106         flip = false;
107 
108       // if the buffer contains a RGB24 image (DS RGB24 <=> BGR)
109       if (connectedMediaType.subtype == MEDIASUBTYPE_RGB24) {
110         // if it was an RGBa image demand
111         if (acqRGBaDemand) {
112           // first, resizes the image as needed
113           rgbaIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
114           // copy and convert the image
115           vpImageConvert::BGRToRGBa(pBuffer, (unsigned char *)rgbaIm->bitmap, rgbaIm->getWidth(), rgbaIm->getHeight(),
116                                     flip);
117           // reset the demand boolean
118           acqRGBaDemand = false;
119         } else // if it was a grayscale image demand
120         {
121           // first, resizes the image as needed
122           grayIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
123           // copy and convert the image
124           vpImageConvert::BGRToGrey(pBuffer, grayIm->bitmap, grayIm->getWidth(), grayIm->getHeight(), flip);
125           // reset the demand boolean
126           acqGrayDemand = false;
127         }
128       } else {
129         unsigned long FourCC;
130         FourCC = ((bmpInfo.biCompression & 0xFF000000) >> 24) | ((bmpInfo.biCompression & 0x00FF0000) >> 8) |
131                  ((bmpInfo.biCompression & 0x0000FF00) << 8) | (bmpInfo.biCompression & 0x000000FF) << 24;
132         // if the buffer contains a like YUV420 image
133         if (connectedMediaType.subtype == MEDIASUBTYPE_IYUV || FourCC == 'I420') {
134           // if it was an RGBa image demand
135           if (acqRGBaDemand) {
136             // first, resizes the image as needed
137             rgbaIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
138             // copy and convert the image
139             vpImageConvert::YUV420ToRGBa(pBuffer, (unsigned char *)rgbaIm->bitmap, rgbaIm->getWidth(),
140                                          rgbaIm->getHeight());
141             // reset the demand boolean
142             acqRGBaDemand = false;
143           } else // if it was a grayscale image demand
144           {
145             // first, resizes the image as needed
146             grayIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
147             // copy and convert the image
148             vpImageConvert::YUV420ToGrey(pBuffer, grayIm->bitmap, grayIm->getWidth() * grayIm->getHeight());
149             // reset the demand boolean
150             acqGrayDemand = false;
151           }
152 
153         } else if (connectedMediaType.subtype == MEDIASUBTYPE_YV12) {
154           // if it was an RGBa image demand
155           if (acqRGBaDemand) {
156             // first, resizes the image as needed
157             rgbaIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
158             // copy and convert the image
159             vpImageConvert::YV12ToRGBa(pBuffer, (unsigned char *)rgbaIm->bitmap, rgbaIm->getWidth(),
160                                        rgbaIm->getHeight());
161             // reset the demand boolean
162             acqRGBaDemand = false;
163           } else // if it was a grayscale image demand
164           {
165             // first, resizes the image as needed
166             grayIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
167             // copy and convert the image
168             vpImageConvert::YUV420ToGrey(pBuffer, grayIm->bitmap, grayIm->getWidth() * grayIm->getHeight());
169             // reset the demand boolean
170             acqGrayDemand = false;
171           }
172         } else if (connectedMediaType.subtype == MEDIASUBTYPE_YVU9) {
173           // if it was an RGBa image demand
174           if (acqRGBaDemand) {
175             // first, resizes the image as needed
176             rgbaIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
177             // copy and convert the image
178             vpImageConvert::YVU9ToRGBa(pBuffer, (unsigned char *)rgbaIm->bitmap, rgbaIm->getWidth(),
179                                        rgbaIm->getHeight());
180             // reset the demand boolean
181             acqRGBaDemand = false;
182           } else // if it was a grayscale image demand
183           {
184             // first, resizes the image as needed
185             grayIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
186             // copy and convert the image
187             vpImageConvert::YUV420ToGrey(pBuffer, grayIm->bitmap, grayIm->getWidth() * grayIm->getHeight());
188             // reset the demand boolean
189             acqGrayDemand = false;
190           }
191         } else if (connectedMediaType.subtype == MEDIASUBTYPE_YUY2 || connectedMediaType.subtype == MEDIASUBTYPE_YUYV) {
192           // if it was an RGBa image demand
193           if (acqRGBaDemand) {
194             // first, resizes the image as needed
195             rgbaIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
196             // copy and convert the image
197             vpImageConvert::YCbCrToRGBa(pBuffer, (unsigned char *)rgbaIm->bitmap,
198                                         rgbaIm->getWidth() * rgbaIm->getHeight());
199             // reset the demand boolean
200             acqRGBaDemand = false;
201           } else // if it was a grayscale image demand
202           {
203             // first, resizes the image as needed
204             grayIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
205             // copy and convert the image
206             vpImageConvert::YCbCrToGrey(pBuffer, grayIm->bitmap, grayIm->getWidth() * grayIm->getHeight());
207             // reset the demand boolean
208             acqGrayDemand = false;
209           }
210         } else if (connectedMediaType.subtype == MEDIASUBTYPE_YVYU) {
211           // if it was an RGBa image demand
212           if (acqRGBaDemand) {
213             // first, resizes the image as needed
214             rgbaIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
215             // copy and convert the image
216             vpImageConvert::YCrCbToRGBa(pBuffer, (unsigned char *)rgbaIm->bitmap,
217                                         rgbaIm->getWidth() * rgbaIm->getHeight());
218             // reset the demand boolean
219             acqRGBaDemand = false;
220           } else // if it was a grayscale image demand
221           {
222             // first, resizes the image as needed
223             grayIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
224             // copy and convert the image
225             vpImageConvert::YCbCrToGrey(pBuffer, grayIm->bitmap, grayIm->getWidth() * grayIm->getHeight());
226             // reset the demand boolean
227             acqGrayDemand = false;
228           }
229         } else if (connectedMediaType.subtype == MEDIASUBTYPE_UYVY) {
230           // if it was an RGBa image demand
231           if (acqRGBaDemand) {
232             // first, resizes the image as needed
233             rgbaIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
234             // copy and convert the image
235             vpImageConvert::YUV422ToRGBa(pBuffer, (unsigned char *)rgbaIm->bitmap,
236                                          rgbaIm->getWidth() * rgbaIm->getHeight());
237             // reset the demand boolean
238             acqRGBaDemand = false;
239           } else // if it was a grayscale image demand
240           {
241             // first, resizes the image as needed
242             grayIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
243             // copy and convert the image
244             vpImageConvert::YUV422ToGrey(pBuffer, grayIm->bitmap, grayIm->getWidth() * grayIm->getHeight());
245             // reset the demand boolean
246             acqGrayDemand = false;
247           }
248         } else if (connectedMediaType.subtype == MEDIASUBTYPE_RGB32) {
249           // if it was an RGBa image demand
250           if (acqRGBaDemand) {
251             // first, resizes the image as needed
252             rgbaIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
253             // copy and convert the image
254             // copy(pBuffer ,pBuffer +
255             // 4*rgbaIm->getWidth()*rgbaIm->getHeight(),rgbaIm->bitmap);
256             memcpy(rgbaIm->bitmap, pBuffer, 4 * rgbaIm->getWidth() * rgbaIm->getHeight());
257             // reset the demand boolean
258             acqRGBaDemand = false;
259           } else // if it was a grayscale image demand
260           {
261             // first, resizes the image as needed
262             grayIm->resize(abs(bmpInfo.biHeight), bmpInfo.biWidth);
263             // copy and convert the image
264             vpImageConvert::RGBaToGrey(pBuffer, grayIm->bitmap, grayIm->getWidth() * grayIm->getHeight());
265             // reset the demand boolean
266             acqGrayDemand = false;
267           }
268         }
269       }
270     }
271 
272     // increment the semaphore - allows acquire to continue execution
273     ReleaseSemaphore(copySem, 1, NULL);
274   }
275   return S_OK;
276 }
277 
278 #elif !defined(VISP_BUILD_SHARED_LIBS)
279 // Work arround to avoid warning:
280 // libvisp_sensor.a(vpDirectShowSampleGrabberI.cpp.o) has no symbols
dummy_vpDirectShowSampleGrabberI()281 void dummy_vpDirectShowSampleGrabberI(){};
282 #endif
283 
284 #endif
285