Visual Servoing Platform  version 3.6.1 under development (2024-02-13)
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 
50 vpDirectShowSampleGrabberI::vpDirectShowSampleGrabberI()
51  : acqGrayDemand(false), acqRGBaDemand(false), specialMediaType(false), invertedSource(false)
52 {
53  // semaphore(0), max value = 1
54  copySem = CreateSemaphore(nullptr, 0, 1, nullptr);
55 }
56 
60 vpDirectShowSampleGrabberI::~vpDirectShowSampleGrabberI()
61 {
62  // destroys the semaphore
63  CloseHandle(copySem);
64 }
65 
66 STDMETHODIMP vpDirectShowSampleGrabberI::QueryInterface(REFIID riid, void **ppvObject)
67 {
68  if (nullptr == 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 
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 vertically 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, nullptr);
274  }
275  return S_OK;
276 }
277 
278 #elif !defined(VISP_BUILD_SHARED_LIBS)
279 // Work around to avoid warning:
280 // libvisp_sensor.a(vpDirectShowSampleGrabberI.cpp.o) has no symbols
281 void dummy_vpDirectShowSampleGrabberI(){};
282 #endif
283 
284 #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)