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