JeVois  1.12
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Camera.C
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2016 by Laurent Itti, the University of Southern
4 // California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5 //
6 // This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7 // redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8 // Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10 // License for more details. You should have received a copy of the GNU General Public License along with this program;
11 // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12 //
13 // Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14 // Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 /*! \file */
17 
18 #include <jevois/Core/Camera.H>
19 #include <jevois/Debug/Log.H>
20 #include <jevois/Util/Utils.H>
23 
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 
29 namespace
30 {
31  //! Temporary fix for bug in sunxi-vfe kernel camera driver which returns MBUS format instead or V4L2
32  unsigned int v4l2sunxiFix(unsigned int fcc)
33  {
34  switch (fcc)
35  {
36  case 0x2008: // Handle bug in our sunxi camera driver
37  case V4L2_PIX_FMT_YUYV: return V4L2_PIX_FMT_YUYV;
38 
39  case 0x2001: // Handle bug in our sunxi camera driver
40  case V4L2_PIX_FMT_GREY: return V4L2_PIX_FMT_GREY;
41 
42  case 0x3001: // Handle bug in our sunxi camera driver
43  case V4L2_PIX_FMT_SRGGB8: return V4L2_PIX_FMT_SRGGB8;
44 
45  case 0x1008: // Handle bug in our sunxi camera driver
46  case V4L2_PIX_FMT_RGB565: return V4L2_PIX_FMT_RGB565;
47 
48  case V4L2_PIX_FMT_MJPEG: return V4L2_PIX_FMT_MJPEG;
49 
50  case V4L2_PIX_FMT_BGR24: return V4L2_PIX_FMT_BGR24;
51 
52  default: LFATAL("Unsupported pixel format " << jevois::fccstr(fcc));
53  }
54  }
55 }
56 
57 // ##############################################################################################################
58 jevois::Camera::Camera(std::string const & devname, jevois::CameraSensor s, unsigned int const nbufs) :
59  jevois::VideoInput(devname, nbufs), itsSensor(s), itsFd(-1), itsBuffers(nullptr), itsFormat(),
60  itsStreaming(false), itsFps(0.0F), itsFlags(JEVOIS_SENSOR_COLOR)
61 {
62  JEVOIS_TRACE(1);
63 
64  JEVOIS_TIMED_LOCK(itsMtx);
65 
66  // Get our run() thread going and wait until it is cranking, it will flip itsRunning to true as it starts:
67  itsRunFuture = std::async(std::launch::async, &jevois::Camera::run, this);
68  while (itsRunning.load() == false) std::this_thread::sleep_for(std::chrono::milliseconds(5));
69 
70  // Open the device:
71  itsFd = open(devname.c_str(), O_RDWR | O_NONBLOCK, 0);
72  if (itsFd == -1) PLFATAL("Camera device open failed on " << devname);
73 
74  // See what kinds of inputs we have and select the first one that is a camera:
75  int camidx = -1;
76  struct v4l2_input inp = { };
77  while (true)
78  {
79  try { XIOCTL_QUIET(itsFd, VIDIOC_ENUMINPUT, &inp); } catch (...) { break; }
80  if (inp.type == V4L2_INPUT_TYPE_CAMERA)
81  {
82  if (camidx == -1) camidx = inp.index;
83  LDEBUG("Input " << inp.index << " [" << inp.name << "] is a camera sensor");
84  } else LDEBUG("Input " << inp.index << " [" << inp.name << "] is a NOT camera sensor");
85  ++inp.index;
86  }
87 
88  if (camidx == -1) LFATAL("No valid camera input found on device " << devname);
89 
90  // Select the camera input, this seems to be required by VFE for the camera to power on:
91  XIOCTL(itsFd, VIDIOC_S_INPUT, &camidx);
92 
93  // Find out what camera can do:
94  struct v4l2_capability cap = { };
95  XIOCTL(itsFd, VIDIOC_QUERYCAP, &cap);
96 
97  LINFO('[' << itsFd << "] V4L2 camera " << devname << " card " << cap.card << " bus " << cap.bus_info);
98  if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) LFATAL(devname << " is not a video capture device");
99  if ((cap.capabilities & V4L2_CAP_STREAMING) == 0) LFATAL(devname << " does not support streaming");
100 
101  // List the supported formats:
102  struct v4l2_fmtdesc fmtdesc = { };
103  fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
104  while (true)
105  {
106  try { XIOCTL_QUIET(itsFd, VIDIOC_ENUM_FMT, &fmtdesc); } catch (...) { break; }
107  LDEBUG("Format " << fmtdesc.index << " is [" << fmtdesc.description << "] fcc " << std::showbase <<
108  std::hex << fmtdesc.pixelformat << " [" << jevois::fccstr(fmtdesc.pixelformat) << ']');
109  ++fmtdesc.index;
110  }
111 
112 #ifdef JEVOIS_PLATFORM
113  // Get the sensor flags (if supported):
114  itsFlags = readFlags();
115  LDEBUG("Sensor " << s << (itsFlags & JEVOIS_SENSOR_MONO) ? " Monochrome" : " Color" <<
116  (itsFlags & JEVOIS_SENSOR_ICM20948) ? " with ICM20948 IMU" : " ");
117 #endif
118 }
119 
120 // ##############################################################################################################
122 {
123  JEVOIS_TRACE(2);
124 
125  // We may be streaming, eg, if we were running a mapping with no USB out and then the user starts a video grabber. So
126  // make sure we stream off first:
127  if (itsStreaming.load()) streamOff();
128 
129  JEVOIS_TIMED_LOCK(itsMtx);
130 
131  // Get current format:
132  itsFormat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
133  XIOCTL(itsFd, VIDIOC_G_FMT, &itsFormat);
134 
135  // Set desired format:
136  itsFormat.fmt.pix.width = m.cw;
137  itsFormat.fmt.pix.height = m.ch;
138  itsFormat.fmt.pix.pixelformat = m.cfmt;
139  itsFormat.fmt.pix.field = V4L2_FIELD_NONE;
140  itsFps = m.cfps;
141 
142  LDEBUG("Requesting video format " << itsFormat.fmt.pix.width << 'x' << itsFormat.fmt.pix.height << ' ' <<
143  jevois::fccstr(itsFormat.fmt.pix.pixelformat));
144  try
145  {
146  XIOCTL_QUIET(itsFd, VIDIOC_S_FMT, &itsFormat);
147  }
148  catch (...)
149  {
150  try
151  {
152  // Oops, maybe this sensor only supports raw Bayer:
153  itsFormat.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
154  XIOCTL_QUIET(itsFd, VIDIOC_S_FMT, &itsFormat);
155  }
156  catch (...)
157  {
158  try
159  {
160  // Oops, maybe this sensor only supports monochrome:
161  itsFormat.fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
162  XIOCTL_QUIET(itsFd, VIDIOC_S_FMT, &itsFormat);
163  }
164  catch (...)
165  {
166  LFATAL("Could not set camera format to " << itsFormat.fmt.pix.width << 'x' << itsFormat.fmt.pix.height << ' ' <<
167  jevois::fccstr(m.cfmt) << ". Maybe the sensor does not support requested pixel type or resolution.");
168  }
169  }
170  }
171 
172  // Get the format back as the driver may have adjusted some sizes, etc:
173  XIOCTL(itsFd, VIDIOC_G_FMT, &itsFormat);
174 
175  // The driver returns a different format code, may be the mbus code instead of the v4l2 fcc...
176  itsFormat.fmt.pix.pixelformat = v4l2sunxiFix(itsFormat.fmt.pix.pixelformat);
177 
178  LINFO("Camera set video format to " << itsFormat.fmt.pix.width << 'x' << itsFormat.fmt.pix.height << ' ' <<
179  jevois::fccstr(itsFormat.fmt.pix.pixelformat));
180 
181  // Because modules may rely on the exact format that they request, throw if the camera modified it:
182  if (itsFormat.fmt.pix.width != m.cw ||
183  itsFormat.fmt.pix.height != m.ch ||
184  (itsFormat.fmt.pix.pixelformat != m.cfmt &&
185  (m.cfmt != V4L2_PIX_FMT_YUYV ||
186  (itsFormat.fmt.pix.pixelformat != V4L2_PIX_FMT_SRGGB8 &&
187  itsFormat.fmt.pix.pixelformat != V4L2_PIX_FMT_GREY))))
188  LFATAL("Camera did not accept the requested video format as specified");
189 
190  // Allocate a RawImage for conversion from Bayer or Monochrome to YUYV if needed:
191  if (m.cfmt == V4L2_PIX_FMT_YUYV &&
192  (itsFormat.fmt.pix.pixelformat == V4L2_PIX_FMT_SRGGB8 || itsFormat.fmt.pix.pixelformat == V4L2_PIX_FMT_GREY))
193  {
194  // We will grab raw Bayer/Mono and store that into itsOutputImage, finally converting to YUYV in get():
195  itsConvertedOutputImage.width = itsFormat.fmt.pix.width;
196  itsConvertedOutputImage.height = itsFormat.fmt.pix.height;
197  itsConvertedOutputImage.fmt = V4L2_PIX_FMT_YUYV;
198  itsConvertedOutputImage.fps = itsFps;
199  itsConvertedOutputImage.buf = std::make_shared<jevois::VideoBuf>(-1, itsConvertedOutputImage.bytesize(), 0);
200  }
201  else
202  itsConvertedOutputImage.invalidate();
203 
204  // Reset cropping parameters. NOTE: just open()'ing the device does not reset it, according to the unix toolchain
205  // philosophy. Hence, although here we do not provide support for cropping, we still need to ensure that it is
206  // properly reset. Note that some cameras do not support this so here we swallow that exception:
207  try
208  {
209  struct v4l2_cropcap cropcap = { };
210  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
211  XIOCTL_QUIET(itsFd, VIDIOC_CROPCAP, &cropcap);
212 
213  struct v4l2_crop crop = { };
214  crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; crop.c = cropcap.defrect;
215  XIOCTL_QUIET(itsFd, VIDIOC_S_CROP, &crop);
216 
217  LDEBUG("Set cropping rectangle to " << cropcap.defrect.width << 'x' << cropcap.defrect.height << " @ ("
218  << cropcap.defrect.left << ", " << cropcap.defrect.top << ')');
219  }
220  catch (...) { LDEBUG("Querying/setting crop rectangle not supported"); }
221 
222  // Set frame rate:
223  try
224  {
225  struct v4l2_streamparm parms = { };
226  parms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
227  parms.parm.capture.timeperframe = jevois::VideoMapping::fpsToV4l2(m.cfps);
228  parms.parm.capture.capturemode = 2; // V4L2_MODE_VIDEO not defined in our headers? its value is 2.
229  XIOCTL(itsFd, VIDIOC_S_PARM, &parms);
230 
231  LDEBUG("Set framerate to " << m.cfps << " fps");
232  }
233  catch (...) { LERROR("Setting frame rate to " << m.cfps << " fps failed -- IGNORED"); }
234 }
235 
236 // ##############################################################################################################
238 {
239  JEVOIS_TRACE(1);
240 
241  // Turn off streaming if it was on:
242  try { streamOff(); } catch (...) { jevois::warnAndIgnoreException(); }
243 
244  // Block until the run() thread completes:
245  itsRunning.store(false);
246  if (itsRunFuture.valid()) try { itsRunFuture.get(); } catch (...) { jevois::warnAndIgnoreException(); }
247 
248  if (itsBuffers) delete itsBuffers;
249 
250  if (close(itsFd) == -1) PLERROR("Error closing V4L2 camera");
251 }
252 
253 // ##############################################################################################################
254 void jevois::Camera::run()
255 {
256  JEVOIS_TRACE(1);
257 
258  fd_set rfds; // For new images captured
259  fd_set efds; // For errors
260  struct timeval tv;
261 
262  // Switch to running state:
263  itsRunning.store(true);
264 
265  // We may have to wait until the device is opened:
266  while (itsFd == -1) std::this_thread::sleep_for(std::chrono::milliseconds(1));
267 
268  LDEBUG("run() thread ready");
269 
270  // NOTE: The flow is a little complex here, the goal is to minimize latency between a frame being captured and us
271  // dequeueing it from the driver and making it available to get(). To achieve low latency, we thus need to be polling
272  // the driver most of the time, and we need to prevent other threads from doing various ioctls while we are polling,
273  // as the SUNXI-VFE driver does not like that. Thus, there is high contention on itsMtx which we lock most of the
274  // time. For this reason we do a bit of sleeping with itsMtx unlocked at places where we know it will not increase our
275  // captured image delivery latency.
276  std::vector<size_t> doneidx;
277 
278  // Wait for event from the gadget kernel driver and process them:
279  while (itsRunning.load())
280  try
281  {
282  // Requeue any done buffer. To avoid having to use a double lock on itsOutputMtx (for itsDoneIdx) and itsMtx (for
283  // itsBuffers->qbuf()), we just swap itsDoneIdx into a local variable here, and invalidate it, with itsOutputMtx
284  // locked, then we will do the qbuf() later, if needed, while itsMtx is locked:
285  {
286  std::lock_guard<std::mutex> _(itsOutputMtx);
287  if (itsDoneIdx.empty() == false) itsDoneIdx.swap(doneidx);
288  }
289 
290  std::unique_lock<std::timed_mutex> lck(itsMtx);
291 
292  // Do the actual qbuf of any done buffer, ignoring any exception:
293  for (size_t idx : doneidx) try { itsBuffers->qbuf(idx); } catch (...) { jevois::warnAndIgnoreException(); }
294  doneidx.clear();
295 
296  // SUNXI-VFE does not like to be polled when not streaming; if indeed we are not streaming, unlock and then sleep
297  // a bit to avoid too much contention on itsMtx:
298  if (itsStreaming.load() == false)
299  {
300  lck.unlock();
301  std::this_thread::sleep_for(std::chrono::milliseconds(5));
302  continue;
303  }
304 
305  // Poll the device to wait for any new captured video frame:
306  FD_ZERO(&rfds); FD_ZERO(&efds); FD_SET(itsFd, &rfds); FD_SET(itsFd, &efds);
307  tv.tv_sec = 0; tv.tv_usec = 5000;
308 
309  int ret = select(itsFd + 1, &rfds, nullptr, &efds, &tv);
310  if (ret == -1) { PLERROR("Select error"); if (errno == EINTR) continue; else break; }
311  else if (ret > 0) // NOTE: ret == 0 would mean timeout
312  {
313  if (FD_ISSET(itsFd, &efds)) LFATAL("Camera device error");
314 
315  if (FD_ISSET(itsFd, &rfds))
316  {
317  // A new frame has been captured. Dequeue a buffer from the camera driver:
318  struct v4l2_buffer buf;
319  itsBuffers->dqbuf(buf);
320 
321  // Create a RawImage from that buffer:
322  jevois::RawImage img;
323  img.width = itsFormat.fmt.pix.width;
324  img.height = itsFormat.fmt.pix.height;
325  img.fmt = itsFormat.fmt.pix.pixelformat;
326  img.fps = itsFps;
327  img.buf = itsBuffers->get(buf.index);
328  img.bufindex = buf.index;
329 
330  // Unlock itsMtx:
331  lck.unlock();
332 
333  // We want to never block waiting for people to consume our grabbed frames here, hence we just overwrite our
334  // output image here, it just always contains the latest grabbed image:
335  {
336  std::lock_guard<std::mutex> _(itsOutputMtx);
337  itsOutputImage = img;
338  }
339  LDEBUG("Captured image " << img.bufindex << " ready for processing");
340 
341  // Let anyone trying to get() our image know it's here:
342  itsOutputCondVar.notify_all();
343 
344  // This is also a good time to sleep a bit since it will take a while for the next frame to arrive, this
345  // should allow people who had been trying to get a lock on itsMtx to get it now:
346  std::this_thread::sleep_for(std::chrono::milliseconds(5));
347  }
348  }
349  } catch (...) { jevois::warnAndIgnoreException(); }
350 
351  // Switch out of running state in case we did interrupt the loop here by a break statement:
352  itsRunning.store(false);
353 }
354 
355 // ##############################################################################################################
357 {
358  JEVOIS_TRACE(2);
359 
360  LDEBUG("Turning on camera stream");
361 
362  JEVOIS_TIMED_LOCK(itsMtx);
363 
364  if (itsStreaming.load() || itsBuffers) { LERROR("Stream is already on -- IGNORED"); return; }
365 
366  itsStreaming.store(false); // just in case user forgot to call abortStream()
367 
368  // If number of buffers is zero, adjust it depending on frame size:
369  unsigned int nbuf = itsNbufs;
370  if (nbuf == 0)
371  {
372  unsigned int framesize = jevois::v4l2ImageSize(itsFormat.fmt.pix.pixelformat, itsFormat.fmt.pix.width,
373  itsFormat.fmt.pix.height);
374 
375  // Aim for about 4 mbyte when using small images, and no more than 5 buffers in any case:
376  nbuf = (4U * 1024U * 1024U) / framesize;
377  if (nbuf > 5) nbuf = 5;
378  }
379 
380  // Force number of buffers to a sane value:
381  if (nbuf < 3) nbuf = 3; else if (nbuf > 63) nbuf = 63;
382 
383  // Allocate the buffers for our current video format:
384  itsBuffers = new jevois::VideoBuffers("camera", itsFd, V4L2_BUF_TYPE_VIDEO_CAPTURE, nbuf);
385  LINFO(itsBuffers->size() << " buffers of " << itsBuffers->get(0)->length() << " bytes allocated");
386 
387  // Enqueue all our buffers:
388  itsBuffers->qbufall();
389  LDEBUG("All buffers queued to camera driver");
390 
391  // Start streaming at the device level:
392  int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
393  XIOCTL(itsFd, VIDIOC_STREAMON, &type);
394  LDEBUG("Device stream on");
395 
396  itsStreaming.store(true);
397  LDEBUG("Streaming is on");
398 }
399 
400 // ##############################################################################################################
402 {
403  JEVOIS_TRACE(2);
404 
405  // Set its Streaming to false here while unlocked, which will introduce some sleeping in our run() thread, thereby
406  // helping us acquire our needed double lock:
407  itsStreaming.store(false);
408 
409  // Unblock any get() that is waiting on itsOutputCondVar, it will then throw now that streaming is off:
410  itsOutputCondVar.notify_all();
411 }
412 
413 // ##############################################################################################################
415 {
416  JEVOIS_TRACE(2);
417 
418  // Note: we allow for several streamOff() without complaining, this happens, e.g., when destroying a Camera that is
419  // not currently streaming.
420 
421  LDEBUG("Turning off camera stream");
422 
423  // Abort stream in case it was not already done, which will introduce some sleeping in our run() thread, thereby
424  // helping us acquire our needed double lock:
425  abortStream();
426 
427  // We need a double lock here so that we can both turn off the stream and nuke our output image and done idx:
428  std::unique_lock<std::timed_mutex> lk1(itsMtx, std::defer_lock);
429  std::unique_lock<std::mutex> lk2(itsOutputMtx, std::defer_lock);
430  std::lock(lk1, lk2);
431 
432  // Invalidate our output image:
433  itsOutputImage.invalidate();
434 
435  // User may have called done() but our run() thread has not yet gotten to requeueing this image, if so requeue it here
436  // as it seems to keep the driver happier:
437  if (itsBuffers)
438  for (size_t idx : itsDoneIdx) try { itsBuffers->qbuf(idx); } catch (...) { jevois::warnAndIgnoreException(); }
439  itsDoneIdx.clear();
440 
441  // Stop streaming at the device level:
442  int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
443  try { XIOCTL_QUIET(itsFd, VIDIOC_STREAMOFF, &type); } catch (...) { }
444 
445  // Nuke all the buffers:
446  if (itsBuffers) { delete itsBuffers; itsBuffers = nullptr; }
447 
448  // Unblock any get() that is waiting on itsOutputCondVar, it will then throw now that streaming is off:
449  lk2.unlock();
450  itsOutputCondVar.notify_all();
451 
452  LDEBUG("Camera stream is off");
453 }
454 
455 // ##############################################################################################################
457 {
458  JEVOIS_TRACE(4);
459 
460  if (itsConvertedOutputImage.valid())
461  {
462  // We need to convert from Bayer/Mono to YUYV:
463  std::unique_lock<std::mutex> ulck(itsOutputMtx);
464  itsOutputCondVar.wait(ulck, [&]() { return itsOutputImage.valid() || itsStreaming.load() == false; });
465  if (itsStreaming.load() == false) { LDEBUG("Not streaming"); throw std::runtime_error("Camera not streaming"); }
466 
467  if (itsFlags & JEVOIS_SENSOR_MONO)
468  jevois::rawimage::convertGreyToYUYV(itsOutputImage, itsConvertedOutputImage);
469  else
470  jevois::rawimage::convertBayerToYUYV(itsOutputImage, itsConvertedOutputImage);
471 
472  img = itsConvertedOutputImage;
473  img.bufindex = itsOutputImage.bufindex;
474  itsOutputImage.invalidate();
475  }
476  else
477  {
478  // Regular get() with no conversion:
479  std::unique_lock<std::mutex> ulck(itsOutputMtx);
480  itsOutputCondVar.wait(ulck, [&]() { return itsOutputImage.valid() || itsStreaming.load() == false; });
481  if (itsStreaming.load() == false) { LDEBUG("Not streaming"); throw std::runtime_error("Camera not streaming"); }
482  img = itsOutputImage;
483  itsOutputImage.invalidate();
484  }
485 
486  LDEBUG("Camera image " << img.bufindex << " handed over to processing");
487 }
488 
489 // ##############################################################################################################
491 {
492  JEVOIS_TRACE(4);
493 
494  if (itsStreaming.load() == false)
495  { LDEBUG("Not streaming"); throw std::runtime_error("Camera done() rejected while not streaming"); }
496 
497  // To avoid blocking for a long time here, we do not try to lock itsMtx and to qbuf() the buffer right now, instead we
498  // just make a note that this buffer is available and it will be requeued by our run() thread:
499  std::lock_guard<std::mutex> _(itsOutputMtx);
500  itsDoneIdx.push_back(img.bufindex);
501 
502  LDEBUG("Image " << img.bufindex << " freed by processing");
503 }
504 
505 // ##############################################################################################################
506 void jevois::Camera::queryControl(struct v4l2_queryctrl & qc) const
507 {
508  XIOCTL_QUIET(itsFd, VIDIOC_QUERYCTRL, &qc);
509 }
510 
511 // ##############################################################################################################
512 void jevois::Camera::queryMenu(struct v4l2_querymenu & qm) const
513 {
514  XIOCTL_QUIET(itsFd, VIDIOC_QUERYMENU, &qm);
515 }
516 
517 // ##############################################################################################################
518 void jevois::Camera::getControl(struct v4l2_control & ctrl) const
519 {
520 #ifdef JEVOIS_PLATFORM
521  XIOCTL(itsFd, 0xc00c561b /* should be VIDIOC_G_CTRL, bug in kernel headers? */, &ctrl);
522 #else
523  XIOCTL(itsFd, VIDIOC_G_CTRL, &ctrl);
524 #endif
525 }
526 
527 // ##############################################################################################################
528 void jevois::Camera::setControl(struct v4l2_control const & ctrl)
529 {
530 #ifdef JEVOIS_PLATFORM
531  XIOCTL(itsFd, 0xc00c561c /* should be VIDIOC_S_CTRL, bug in kernel headers? */, &ctrl);
532 #else
533  XIOCTL(itsFd, VIDIOC_S_CTRL, &ctrl);
534 #endif
535 }
536 
537 // ##############################################################################################################
538 void jevois::Camera::writeRegister(unsigned short reg, unsigned short val)
539 {
540  unsigned short data[2] = { reg, val };
541 
542  LDEBUG("Writing 0x" << std::hex << val << " to 0x" << reg);
543  XIOCTL(itsFd, _IOW('V', 192, int), data);
544 }
545 
546 // ##############################################################################################################
547 unsigned short jevois::Camera::readRegister(unsigned short reg)
548 {
549  unsigned short data[2] = { reg, 0 };
550 
551  XIOCTL(itsFd, _IOWR('V', 193, int), data);
552  LDEBUG("Register 0x" << std::hex << reg << " has value 0x" << data[1]);
553  return data[1];
554 }
555 
556 // ##############################################################################################################
557 void jevois::Camera::writeIMUregister(unsigned short reg, unsigned short val)
558 {
559  unsigned short data[2] = { reg, val };
560 
561  LDEBUG("Writing 0x" << std::hex << val << " to 0x" << reg);
562  XIOCTL(itsFd, _IOW('V', 194, int), data);
563 }
564 
565 // ##############################################################################################################
566 unsigned short jevois::Camera::readIMUregister(unsigned short reg)
567 {
568  unsigned short data[2] = { reg, 0 };
569 
570  XIOCTL(itsFd, _IOWR('V', 195, int), data);
571  LDEBUG("Register 0x" << std::hex << reg << " has value 0x" << data[1]);
572  return data[1];
573 }
574 
575 namespace
576 {
577  struct jevois_data
578  {
579  unsigned char addr;
580  unsigned char size;
581  unsigned char data[32];
582  };
583 }
584 
585 // ##############################################################################################################
587 {
588  int data;
589  try { XIOCTL(itsFd, _IOWR('V', 198, int), &data); } catch (...) { return jevois::Camera::JEVOIS_SENSOR_COLOR; }
590  return Flags(data);
591 }
592 
593 // ##############################################################################################################
594 void jevois::Camera::writeIMUregisterArray(unsigned short reg, unsigned char const * vals, size_t num)
595 {
596  if (num > 32) LFATAL("Maximum allowed size is 32 bytes. You must break down larger transfers into 32 byte chunks.");
597 
598  static jevois_data d;
599  d.addr = reg & 0xff;
600  d.size = num;
601  memcpy(d.data, vals, num);
602 
603  LDEBUG("Writing " << num << " values to 0x"<< std::hex << reg);
604  XIOCTL(itsFd, _IOW('V', 196, struct jevois_data), &d);
605 }
606 
607 // ##############################################################################################################
608 void jevois::Camera::readIMUregisterArray(unsigned short reg, unsigned char * vals, size_t num)
609 {
610  if (num > 32) LFATAL("Maximum allowed size is 32 bytes. You must break down larger transfers into 32 byte chunks.");
611 
612  static jevois_data d;
613  d.addr = reg & 0xff;
614  d.size = num;
615 
616  XIOCTL(itsFd, _IOWR('V', 197, struct jevois_data), &d);
617  LDEBUG("Received " << num <<" values from register 0x" << std::hex << reg);
618  memcpy(vals, d.data, num);
619 }
#define LDEBUG(msg)
Convenience macro for users to print out console or syslog messages, DEBUG level. ...
Definition: Log.H:155
std::string warnAndIgnoreException()
Convenience function to catch an exception, issue some LERROR (depending on type), and ignore it.
Definition: Log.C:211
~Camera()
Close the device and free all resources.
Definition: Camera.C:237
void queryControl(struct v4l2_queryctrl &qc) const override
Get information about a control, throw if unsupported by hardware.
Definition: Camera.C:506
Flags readFlags()
Get the sensor flags.
Definition: Camera.C:586
void dqbuf(struct v4l2_buffer &buf)
Dequeue the next captured/displayed buffer, blocks until one is available.
Definition: VideoBuffers.C:133
unsigned int height
Image height in pixels.
Definition: RawImage.H:146
static struct v4l2_fract fpsToV4l2(float fps)
Convert from fps to V4L2 interval.
Definition: VideoMapping.C:65
void writeIMUregisterArray(unsigned short reg, unsigned char const *vals, size_t num) override
Write an array of values to the camera&#39;s IMU registers.
Definition: Camera.C:594
void getControl(struct v4l2_control &ctrl) const
Get a control&#39;s current value, throw if unsupported by hardware.
Definition: Camera.C:518
void streamOff() override
Stop streaming.
Definition: Camera.C:414
void setFormat(VideoMapping const &m) override
Set the video format and frame rate.
Definition: Camera.C:121
unsigned int fmt
Pixel format as a V4L2_PIX_FMT_XXX.
Definition: RawImage.H:147
#define XIOCTL_QUIET(dev, req, mem)
Helper macro to execute an ioctl, ignore interruptions, and, if error throw quietly.
std::shared_ptr< VideoBuf > buf
The pixel data buffer.
Definition: RawImage.H:149
#define JEVOIS_TIMED_LOCK(mtx)
Helper macro to create a timed_lock_guard object.
Definition: Log.H:299
void streamOn() override
Start streaming.
Definition: Camera.C:356
void invalidate()
Invalidate the image by zero&#39;ing out the pointer to pixel buffer and the dims and format...
Definition: RawImage.C:42
void readIMUregisterArray(unsigned short reg, unsigned char *vals, size_t num) override
Read an array of values from the camera&#39;s IMU registers.
Definition: Camera.C:608
void abortStream() override
Abort streaming.
Definition: Camera.C:401
unsigned int const itsNbufs
Our number of buffers.
Definition: VideoInput.H:119
#define JEVOIS_TRACE(level)
Trace object.
Definition: Log.H:267
#define PLFATAL(msg)
Like LDEBUG but appends errno and strerror(errno), to be used when some system call fails...
Definition: Log.H:221
Flags
Sensor flags.
Definition: Camera.H:157
void setControl(struct v4l2_control const &ctrl) override
Set a control, throw if control not supported or the hardware rejects the value.
Definition: Camera.C:528
void done(RawImage &img) override
Indicate that user processing is done with an image previously obtained via get() ...
Definition: Camera.C:490
unsigned short readIMUregister(unsigned short reg) override
Read a value from one of the camera&#39;s IMU registers.
Definition: Camera.C:566
Camera(std::string const &devname, jevois::CameraSensor s=jevois::CameraSensor::any, unsigned int const nbufs=0)
Construct and open the device.
Definition: Camera.C:58
bool valid() const
Check whether the image has a valid pixel buffer.
Definition: RawImage.C:46
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level. ...
Definition: Log.H:193
A raw image as coming from a V4L2 Camera and/or being sent out to a USB Gadget.
Definition: RawImage.H:110
unsigned int ch
camera height
Definition: VideoMapping.H:52
Collection of buffers for V4L2 video frames (Camera or Gadget) with hooks to the MMAP&#39;d areas...
Definition: VideoBuffers.H:41
unsigned short readRegister(unsigned short reg) override
Read a value from one of the camera&#39;s registers.
Definition: Camera.C:547
size_t size() const
Get the number of buffers allocated.
Definition: VideoBuffers.C:80
Simple struct to hold video mapping definitions for the processing Engine.
Definition: VideoMapping.H:43
void queryMenu(struct v4l2_querymenu &qm) const override
Get the available menu entry names for a menu-type control, throw if unsupported by hardware...
Definition: Camera.C:512
#define XIOCTL(dev, req, mem)
Helper macro to execute an ioctl, ignore interruptions, and, if error, issue a fatal message and thro...
std::shared_ptr< VideoBuf > get(size_t const index) const
Get one buffer, by index [0 .. size()[.
Definition: VideoBuffers.C:92
std::string fccstr(unsigned int fcc)
Convert a V4L2 four-cc code (V4L2_PIX_FMT_...) to a 4-char string.
Definition: Utils.C:39
Base class for video input, which will get derived into Camera and MovieInput.
Definition: VideoInput.H:31
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level. ...
Definition: Log.H:212
void convertGreyToYUYV(RawImage const &src, RawImage &dst)
Convert from Grey (monochrome) to YUYV, only used internally by Camera class.
Definition: RawImageOps.C:1597
unsigned int v4l2ImageSize(unsigned int fcc, unsigned int width, unsigned int height)
Return the image size in bytes for a given V4L2_PIX_FMT_..., width, height.
Definition: Utils.C:108
void qbuf(size_t const index)
Queue one buffer to V4L2, by index [0 .. size()[.
Definition: VideoBuffers.C:100
unsigned int cfmt
camera pixel format
Definition: VideoMapping.H:50
unsigned int cw
camera width
Definition: VideoMapping.H:51
float fps
Programmed frames/s as given by current video mapping, may not be actual.
Definition: RawImage.H:148
unsigned int bytesize() const
Helper function to get the total number of bytes in the RawImage, i.e., width * height * bytesperpix(...
Definition: RawImage.C:38
void writeIMUregister(unsigned short reg, unsigned short val) override
Write a value to one of the camera&#39;s IMU registers.
Definition: Camera.C:557
void qbufall()
Queue all buffers, typically used when starting streaming on capture devices.
Definition: VideoBuffers.C:127
#define PLERROR(msg)
Like LERROR but appends errno and strerror(errno), to be used when some system call fails...
Definition: Log.H:201
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
Definition: Log.H:176
size_t bufindex
The index of the data buffer in the kernel driver.
Definition: RawImage.H:150
unsigned int width
Image width in pixels.
Definition: RawImage.H:145
float cfps
camera frame rate in frames/sec
Definition: VideoMapping.H:53
void writeRegister(unsigned short reg, unsigned short val) override
Write a value to one of the camera&#39;s registers.
Definition: Camera.C:538
void get(RawImage &img) override
Get the next captured buffer.
Definition: Camera.C:456
void convertBayerToYUYV(RawImage const &src, RawImage &dst)
Convert from Bayer to YUYV, only used internally by Camera class.
Definition: RawImageOps.C:1577