camera_driver.cpp
Go to the documentation of this file.
1 #include <cstdio>
2 #include <linux/videodev2.h>
3 #include <sstream>
4 #include <string>
5 
7 #include "usb_cam/converters.h"
8 #include "usb_cam/types.h"
9 
10 using namespace usb_cam;
11 
12 /* STATIC DATA INITIALIZERS */
13 /* V4L/HARDWARE */
20 
21 /* FFMPEG */
24 unsigned int AbstractV4LUSBCam::buffers_count = 0; // n_buffers_
25 AVFrame* AbstractV4LUSBCam::avframe_camera = nullptr;
26 AVFrame* AbstractV4LUSBCam::avframe_rgb = nullptr;
27 AVPacket* AbstractV4LUSBCam::avpkt = nullptr;
28 AVCodec* AbstractV4LUSBCam::avcodec = nullptr;
29 AVCodecID AbstractV4LUSBCam::codec_id = AV_CODEC_ID_NONE;
30 AVDictionary* AbstractV4LUSBCam::avoptions = nullptr;
31 AVCodecContext* AbstractV4LUSBCam::avcodec_context = nullptr;
34 struct SwsContext* AbstractV4LUSBCam::video_sws = nullptr;
36 bool AbstractV4LUSBCam::capturing = false;
37 std::vector<capture_format_t> AbstractV4LUSBCam::supported_formats = std::vector<capture_format_t>();
38 
39 /* V4L camera parameters */
41 std::string AbstractV4LUSBCam::video_device_name = "/dev/video0";
42 std::string AbstractV4LUSBCam::io_method_name = "mmap";
43 std::string AbstractV4LUSBCam::pixel_format_name = "uyvy";
44 unsigned int AbstractV4LUSBCam::v4l_pixel_format = V4L2_PIX_FMT_UYVY;
45 std::string AbstractV4LUSBCam::color_format_name = "yuv422p";
49 std::vector<camera_control_t> AbstractV4LUSBCam::controls = std::vector<camera_control_t>();
50 std::set<std::string> AbstractV4LUSBCam::ignore_controls = std::set<std::string>();
51 
52 
54 {
55  // Resolving I/O method name tables
58  {
59  printf("Unknown IO method '%s'\n", io_method_name.c_str());
60  return false;
61  }
64  {
65  printf("Unknown pixel format '%s'\n", pixel_format_name.c_str());
66  return false;
67  }
70  {
71  printf("Unknown color format '%s'\n", color_format_name.c_str());
72  return false;
73  }
75  if(v4l_pixel_format == UINT_MAX)
76  {
77  printf("Error in conversion between FFMPEG and Video4Linux pixel format constant '%s'\n", pixel_format_name.c_str());
78  return false;
79  }
80 
81  /* Initializing decoder */
82  if(!init_decoder())
83  {
84  printf("Unable to initialize FFMPEG decoder\n");
85  return false;
86  }
87  return true;
88 }
89 
91 {
92  // V4L initilaization data
93  struct stat st;
94  struct v4l2_capability cap;
95  struct v4l2_cropcap cropcap;
96  struct v4l2_crop crop;
97  struct v4l2_format fmt;
98  unsigned int min;
99  struct v4l2_streamparm stream_params;
100 
101  /* Creating filesystem handler for streaming device */
102  printf("Opening streaming device %s\n", video_device_name.c_str());
103  if(stat(video_device_name.c_str(), &st) < 0)
104  {
105  printf("Cannot identify device by name '%s' (%i)\n", video_device_name.c_str(), errno);
106  return false;
107  }
108  if(!S_ISCHR(st.st_mode))
109  {
110  printf("'%s' is not a proper V4L device (%i)\n", video_device_name.c_str(), errno);
111  return false;
112  }
113  file_dev = open(video_device_name.c_str(),
114  O_RDWR|O_NONBLOCK,
115  0);
116  if(file_dev < 0)
117  {
118  printf("Cannot create a file handler for V4L device '%s' (%i)\n", video_device_name.c_str(), errno);
119  return false;
120  }
121 
122  /* Initializing V4L capture pipeline */
123  if(usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_QUERYCAP), &cap) < 0)
124  {
125  if(errno == EINVAL)
126  printf("File handler created for V4L-incompatible device '%s' (%i)\n", video_device_name.c_str(), errno);
127  else
128  printf("Cannot query capabilities from V4L device '%s' (%i)\n", video_device_name.c_str(), errno);
129  return false;
130  }
131  if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
132  {
133  printf("V4L device '%s' does not support capture mode (%i)\n", video_device_name.c_str(), errno);
134  return false;
135  }
136  switch(io_method)
137  {
138  case IO_METHOD_READ:
139  if(!(cap.capabilities & V4L2_CAP_READWRITE))
140  {
141  printf("Device '%s' does not support '%s' access method (read/write error)\n", video_device_name.c_str(), io_method_name.c_str());
142  return false;
143  }
144  break;
147  if(!(cap.capabilities & V4L2_CAP_STREAMING))
148  {
149  printf("Device '%s' does not support '%s' access method (streaming error)\n", video_device_name.c_str(), io_method_name.c_str());
150  return false;
151  }
152  break;
153  default:
154  printf("Cannot parse access mode for device '%s': '%s', system malfunction expected\n", video_device_name.c_str(), io_method_name.c_str());
155  }
156  /* V4L pipeline tuning */
157  CLEAR(cropcap);
158  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
159  if(usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_CROPCAP), &cropcap) == 0)
160  {
161  crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
162  crop.c = cropcap.defrect; /* reset to default */
163  if(usb_cam::util::xioctl(file_dev, VIDIOC_S_CROP, &crop) < 0)
164  {
165  if(errno == EINVAL)
166  printf("Video4Linux: CROP mode is not supported\n");
167  else
168  printf("Video4Linux: IOCTL is not supported\n");
169  }
170  }
171  else
172  printf("Video4Linux: internal error occurred, hoping for device fallback\n");
173  CLEAR(fmt);
174  fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
175  fmt.fmt.pix.width = image_width;
176  fmt.fmt.pix.height = image_height;
177  fmt.fmt.pix.pixelformat = v4l_pixel_format;
178  fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
179  if(usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_S_FMT), &fmt) < 0)
180  {
181  printf("Cannot set pixel format '%s' (%u)\n", pixel_format_name.c_str(), v4l_pixel_format);
182  return false;
183  }
184  // Buggy driver prevention
185  min = fmt.fmt.pix.width * 2;
186  if(fmt.fmt.pix.bytesperline < min)
187  fmt.fmt.pix.bytesperline = min;
188  min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
189  if(fmt.fmt.pix.sizeimage < min)
190  fmt.fmt.pix.sizeimage = min;
191  image_width = fmt.fmt.pix.width;
192  image_height = fmt.fmt.pix.height;
193  CLEAR(stream_params);
194  stream_params.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
195  if(usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_G_PARM), &stream_params) < 0)
196  {
197  printf("Cannot set stream parameters (%i)\n", errno);
198  return false;
199  }
200  if(!stream_params.parm.capture.capability && V4L2_CAP_TIMEPERFRAME)
201  printf("Video4Linux: V4L2_CAP_TIMEPERFRAME not supported\n");
202  // TODO(lucasw) need to get list of valid numerator/denominator pairs
203  // and match closest to what user put in.
204  stream_params.parm.capture.timeperframe.numerator = 1;
205  stream_params.parm.capture.timeperframe.denominator = framerate;
206  if (usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_S_PARM), &stream_params) < 0)
207  printf("Video4Linux: cannot set desired framerate: %i fps (%i)\n", framerate, errno);
208  /* Final frame grabber setup */
209  run_grabber(fmt.fmt.pix.sizeimage);
210 
211  image = reinterpret_cast<camera_image_t *>(calloc(1, sizeof(camera_image_t)));
212 
215  image->bytes_per_pixel = 3; // corrected 11/10/15 (BYTES not BITS per pixel)
216 
218  image->is_new = 0;
219  image->image = reinterpret_cast<char *>(calloc(image->image_size, sizeof(char)));
220  memset(image->image, 0, image->image_size * sizeof(char));
221 
222  return true;
223 }
224 
226 {
227  suspend();
228  release_device();
229  close_handlers();
230 
231  av_packet_free(&avpkt);
232  if(video_sws)
233  sws_freeContext(video_sws);
234  video_sws = nullptr;
235  if(avcodec_context)
236  {
237  avcodec_close(avcodec_context);
238  av_free(avcodec_context);
239  avcodec_context = nullptr;
240  }
241  if(avframe_camera)
242  av_free(avframe_camera);
243  avframe_camera = nullptr;
244  if(avframe_rgb)
245  av_free(avframe_rgb);
246  avframe_rgb = nullptr;
247  if(image)
248  free(image);
249  image = nullptr;
250 }
251 
253 {
254 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
255  avcodec_register_all();
256 #endif
257  if(v4l_pixel_format == V4L2_PIX_FMT_MJPEG)
258  {
260  printf("Initializing FFMPEG decoder for MJPEG compression\n");
261  }
262  else if(v4l_pixel_format == V4L2_PIX_FMT_H264)
263  {
264  codec_id = AV_CODEC_ID_H264;
265  printf("Initializing FFMPEG decoder for H.264 compression\n");
266  }
267  else
268  return true;
269  avcodec = const_cast<AVCodec*>(avcodec_find_decoder(codec_id));
270  if(!avcodec)
271  {
272  printf("Cannot find FFMPEG decoder for %s\n", pixel_format_name.c_str());
273  return false;
274  }
275  avcodec_context = avcodec_alloc_context3(avcodec);
276  /* Suppress warnings of the following form:
277  * [swscaler @ 0x############] deprecated pixel format used, make sure you did set range correctly
278  * Or set this to AV_LOG_FATAL to additionally suppress occasional frame errors, e.g.:
279  * [mjpeg @ 0x############] overread 4
280  * [mjpeg @ 0x############] No JPEG data found in image
281  * [ERROR] [##########.##########]: Error while decoding frame.
282  */
283  if(!full_ffmpeg_log)
284  av_log_set_level(AV_LOG_ERROR);
285  else
286  av_log_set_level(AV_LOG_INFO);
287 #if LIBAVCODEC_VERSION_MAJOR < 55
288  avframe_camera = avcodec_alloc_frame();
289  avframe_rgb = avcodec_alloc_frame();
290 #else
291  avframe_camera = av_frame_alloc();
292  avframe_rgb = av_frame_alloc();
293 #endif
294 #if LIBAVCODEC_VERSION_MAJOR < 55
295  avpicture_alloc(reinterpret_cast<AVPicture *>(avframe_rgb),
296  AV_PIX_FMT_RGB24,
297  image_width,
298  image_height);
299 #else
300  /*av_image_alloc(reinterpret_cast<uint8_t **>(avframe_rgb),
301  0,
302  image_width,
303  image_height,
304  AV_PIX_FMT_RGB24,
305  1); */
306  avframe_rgb->format = AV_PIX_FMT_RGB24;
307  avframe_rgb->width = image_width;
308  avframe_rgb->height = image_height;
309  av_frame_get_buffer(avframe_rgb, 1);
310 #endif
311  avcodec_context->codec_id = codec_id;
312  avcodec_context->width = image_width;
313  avcodec_context->height = image_height;
314 #if LIBAVCODEC_VERSION_MAJOR > 52
316  avcodec_context->pix_fmt = AV_PIX_FMT_YUV422P;
317  else
318  avcodec_context->pix_fmt = AV_PIX_FMT_YUV420P;
319  avcodec_context->codec_type = AVMEDIA_TYPE_VIDEO;
320 
321  if(avcodec_context->codec_id == AV_CODEC_ID_MJPEG)
322  {
323  switch(avcodec_context->pix_fmt)
324  {
325  case AV_PIX_FMT_YUVJ420P:
326  avcodec_context->pix_fmt = AV_PIX_FMT_YUV420P;
327  avcodec_context->color_range = AVCOL_RANGE_JPEG;
328  break;
329  case AV_PIX_FMT_YUVJ422P:
330  avcodec_context->pix_fmt = AV_PIX_FMT_YUV422P;
331  avcodec_context->color_range = AVCOL_RANGE_JPEG;
332  break;
333  case AV_PIX_FMT_YUVJ444P:
334  avcodec_context->pix_fmt = AV_PIX_FMT_YUV444P;
335  avcodec_context->color_range = AVCOL_RANGE_JPEG;
336  break;
337  default:
338  break;
339  }
340  }
341 #endif
342 #if LIBAVCODEC_VERSION_MAJOR < 55
344  avframe_camera_size = avpicture_get_size(AV_PIX_FMT_YUV422P, image_width, image_height);
345  else
346  avframe_camera_size = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, image_width, image_height);
347  avframe_rgb_size = avpicture_get_size(AV_PIX_FMT_RGB24, image_width, image_height);
348 #else
350  avframe_camera_size = av_image_get_buffer_size(AV_PIX_FMT_YUV422P, image_width, image_height, 1);
351  else
352  avframe_camera_size = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, image_width, image_height, 1);
353  avframe_rgb_size = av_image_get_buffer_size(AV_PIX_FMT_RGB24, image_width, image_height, 1);
354 #endif
355  if(avcodec_open2(avcodec_context, avcodec, &avoptions) < 0)
356  {
357  printf("Cannot open FFMPEG decoder context\n");
358  return false;
359  }
360  if((v4l_pixel_format == V4L2_PIX_FMT_MJPEG) || (v4l_pixel_format == V4L2_PIX_FMT_H264)) // Setting up format converter between YUV and RGB from libswscale
361  video_sws = sws_getContext(image_width,
362  image_height,
363  avcodec_context->pix_fmt,
364  image_width,
365  image_height,
366  AV_PIX_FMT_RGB24,
367  SWS_FAST_BILINEAR,
368  nullptr,
369  nullptr,
370  nullptr);
371  avpkt = av_packet_alloc();
372  return true;
373 }
374 
376 {
377  if(streaming_status)
378  return false;
379 
380  unsigned int i;
381  enum v4l2_buf_type type;
382 
383  switch(io_method)
384  {
385  case IO_METHOD_READ:
386  printf("Capturing from block device, cancelling memory remap\n");
387  break;
388  case IO_METHOD_MMAP:
389  for (i = 0; i < buffers_count; ++i)
390  {
391  struct v4l2_buffer buf;
392  CLEAR(buf);
393  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
394  buf.memory = V4L2_MEMORY_MMAP;
395  buf.index = i;
396  if(usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_QBUF), &buf) < 0)
397  {
398  printf("Video4linux: unable to configure stream (%i)\n", errno);
399  return false;
400  }
401  }
402  break;
403  case IO_METHOD_USERPTR:
404  for (i = 0; i < buffers_count; ++i)
405  {
406  struct v4l2_buffer buf;
407  CLEAR(buf);
408  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
409  buf.memory = V4L2_MEMORY_USERPTR;
410  buf.index = i;
411  buf.m.userptr = reinterpret_cast<uint64_t>(buffers[i].start);
412  buf.length = buffers[i].length;
413  if(usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_QBUF), &buf) < 0)
414  {
415  printf("Video4linux: unable to configure stream (%i)\n", errno);
416  return false;
417  }
418  }
419  break;
420  default:
421  printf("Video4linux: attempt to start stream with unknown I/O method. Dropping request\n");
422  }
423  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
424  if (usb_cam::util::xioctl(file_dev, VIDIOC_STREAMON, &type) < 0)
425  {
426  printf("Video4linux: unable to start stream (%i)\n", errno);
427  return false;
428  }
429  streaming_status = true;
430  return true;
431 }
432 
434 {
435  if(!streaming_status)
436  return false;
437  enum v4l2_buf_type type;
438  streaming_status = false;
439  switch(io_method)
440  {
441  case IO_METHOD_READ:
442  return true;
443  case IO_METHOD_MMAP:
444  case IO_METHOD_USERPTR:
445  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
446  if (usb_cam::util::xioctl(file_dev, VIDIOC_STREAMOFF, &type) < 0)
447  {
448  printf("Video4linux: cannot stop the device properly (%i)\n", errno);
449  return false;
450  }
451  return true;
452  default:
453  printf("Attempt to stop streaming over unknown I/O channel\n");
454  return false;
455  }
456 }
457 
459 {
460  unsigned int i;
461  switch(io_method)
462  {
463  case IO_METHOD_READ:
464  free(buffers[0].start);
465  break;
466  case IO_METHOD_MMAP:
467  for (i = 0; i < buffers_count; ++i)
468  {
469  if (munmap(buffers[i].start, buffers[i].length) < 0)
470  printf("Video4linux: unable to deallocate frame buffers\n");
471  }
472  break;
473  case IO_METHOD_USERPTR:
474  for (i = 0; i < buffers_count; ++i)
475  free(buffers[i].start);
476  break;
477  default:
478  printf("Attempt to free buffer for unknown I/O method\n");
479  }
480  free(buffers);
481 }
482 
484 {
485  int res = close(file_dev);
486  file_dev = -1;
487  if(res < 0)
488  printf("Unable to close device handler properly\n");
489 }
490 
492 {
493 }
494 
496 {
497  if((image->width == 0) || (image->height == 0))
498  return nullptr;
499 
500  fd_set fds;
501  struct timeval tv;
502  int r;
503  FD_ZERO(&fds);
504  FD_SET(file_dev, &fds);
505  // Timeout
506  tv.tv_sec = 5;
507  tv.tv_usec = 0;
508  r = select(file_dev + 1, &fds, nullptr, nullptr, &tv);
509  /* if the v4l2_buffer timestamp isn't available use this time, though
510  * it may be 10s of milliseconds after the frame acquisition.
511  * image->stamp = clock->now(); */
512  timespec_get(&image->stamp, TIME_UTC);
513  if(r < 0)
514  {
515  if(errno == EINTR)
516  return nullptr;
517  printf("Video4linux: frame mapping operation failed (%i)\n", errno);
518  }
519  else if(r == 0)
520  {
521  printf("Video4linux: frame mapping timeout (%i)\n", errno);
522  return nullptr;
523  }
524 
525  // Reading the actual frame
526  struct v4l2_buffer buf;
527  unsigned int i;
528  int len;
529  struct timespec stamp;
530  int64_t buffer_time_s;
531  switch(io_method)
532  {
533  case IO_METHOD_READ:
534  len = read(file_dev, buffers[0].start, buffers[0].length);
535  if(len < 0)
536  {
537  if(errno == EAGAIN)
538  return nullptr;
539  else if(errno == EIO){}
540  else
541  {
542  printf("Block device read failure (%i)\n", errno);
543  return nullptr;
544  }
545  }
546  // Process image
547  break;
548  case IO_METHOD_MMAP:
549  CLEAR(buf);
550  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
551  buf.memory = V4L2_MEMORY_MMAP;
552  if (usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_DQBUF), &buf) < 0)
553  {
554  if(errno == EAGAIN)
555  return nullptr;
556  else if(errno == EIO){}
557  else
558  {
559  printf("Memory mapping failure (%i)\n", errno);
560  return nullptr;
561  }
562  }
563  buffer_time_s = buf.timestamp.tv_sec + static_cast<int64_t>(round(buf.timestamp.tv_usec / 1000000.0));
564  stamp.tv_sec = static_cast<time_t>(round(buffer_time_s)) + epoch_time_shift;
565  stamp.tv_nsec = static_cast<int64_t>(buf.timestamp.tv_usec * 1000.0);
566  assert(buf.index < buffers_count);
567  len = buf.bytesused;
568  // Process image
569  if(usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_QBUF), &buf) < 0)
570  {
571  printf("Unable to exchange buffer with driver (%i)\n", errno);
572  return nullptr;
573  }
574  image->stamp = stamp;
575  break;
576  case IO_METHOD_USERPTR:
577  CLEAR(buf);
578  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
579  buf.memory = V4L2_MEMORY_USERPTR;
580  if (usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_DQBUF), &buf) < 0)
581  {
582  if(errno == EAGAIN)
583  return nullptr;
584  else if(errno == EIO){}
585  else
586  {
587  printf("Unable to exchange poiner with driver (%i)\n", errno);
588  return nullptr;
589  }
590  }
591  buffer_time_s = buf.timestamp.tv_sec + static_cast<int64_t>(round(buf.timestamp.tv_usec / 1000000.0));
592 
593  stamp.tv_sec = static_cast<time_t>(round(buffer_time_s)) + epoch_time_shift;
594  stamp.tv_nsec = static_cast<int64_t>(buf.timestamp.tv_usec / 1000.0);
595 
596  for(i = 0; i < buffers_count; ++i)
597  if(buf.m.userptr == reinterpret_cast<uint64_t>(buffers[i].start) && buf.length == buffers[i].length)
598  break;
599  assert(i < buffers_count);
600  len = buf.bytesused;
601  // Process image
602  if(usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_QBUF), &buf) < 0)
603  {
604  printf("Unable to exchange buffer with driver (%i)\n", errno);
605  return nullptr;
606  }
607  image->stamp = stamp;
608  break;
609  default:
610  printf("Attempt to grab the frame via unknown I/O method (%i)\n", errno);
611  }
612  bool processing_result = false;
614  processing_result = process_image(buffers[0].start, len, image);
615  else if(io_method == IO_METHOD_MMAP)
616  processing_result = process_image(buffers[buf.index].start, len, image);
617  else if(io_method == IO_METHOD_USERPTR)
618  processing_result = process_image(reinterpret_cast<const void *>(buf.m.userptr), len, image);
619  if(!processing_result)
620  {
621  printf("2D processing operation fault\n");
622  return nullptr;
623  }
624 
625  // Setting color table for grayscale image
626  if(monochrome)
627  {
628  image->encoding = "mono8";
629  image->step = image->width;
630  }
631  else
632  {
633  // TODO(lucasw) aren't there other encoding types?
634  image->encoding = "rgb8";
635  image->step = image->width * 3;
636  }
637 
638  image->is_new = 1;
639  return image;
640 }
641 
642 void AbstractV4LUSBCam::run_grabber(unsigned int &buffer_size)
643 {
645  {
646  struct v4l2_requestbuffers req;
647  CLEAR(req);
648  req.count = 4;
649  req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
650  req.memory = V4L2_MEMORY_MMAP;
651  if(usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_REQBUFS), &req) < 0)
652  {
653  if(errno == EINVAL)
654  printf("Video4Linux: device '%s' does not support memory mapping (%i)\n", video_device_name.c_str(), errno);
655  else
656  printf("Video4Linux: unable to start memory mapping (%i)\n", errno);
657  return;
658  }
659  if(req.count < 2)
660  {
661  printf("Video4Linux: insufficient memory buffers number (%i)\n", req.count);
662  return;
663  }
664  buffers = reinterpret_cast<buffer *>(calloc(req.count, sizeof(*buffers)));
665  if(!buffers)
666  {
667  printf("Out of memory\n");
668  return;
669  }
670  for (buffers_count = 0; buffers_count < req.count; ++buffers_count)
671  {
672  struct v4l2_buffer buf;
673 
674  CLEAR(buf);
675 
676  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
677  buf.memory = V4L2_MEMORY_MMAP;
678  buf.index = buffers_count;
679 
680  if (usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_QUERYBUF), &buf) < 0)
681  {
682  printf("Video4Linux: unable to query buffer status (%i)\n", errno);
683  return;
684  }
685  buffers[buffers_count].length = buf.length;
686  buffers[buffers_count].start = mmap(NULL,
687  buf.length,
688  PROT_READ | PROT_WRITE,
689  MAP_SHARED, file_dev,
690  buf.m.offset);
691  if (buffers[buffers_count].start == MAP_FAILED)
692  {
693  printf("Video4Linux: unable to allocate memory (%i)\n", errno);
694  return;
695  }
696  }
697  }
698  else if(io_method == IO_METHOD_READ)
699  {
700  buffers = reinterpret_cast<buffer *>(calloc(1, sizeof(*buffers)));
701  if (!buffers)
702  {
703  printf("Out of memory\n");
704  return;
705  }
706  buffers[0].length = buffer_size;
707  buffers[0].start = malloc(buffer_size);
708  if (!buffers[0].start)
709  {
710  printf("Out of memory\n");
711  return;
712  }
713  }
714  else if(io_method == IO_METHOD_USERPTR)
715  {
716  struct v4l2_requestbuffers req;
717  unsigned int page_size;
718  page_size = getpagesize();
719  buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);
720  CLEAR(req);
721  req.count = 4;
722  req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
723  req.memory = V4L2_MEMORY_USERPTR;
724  if (usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_REQBUFS), &req) < 0)
725  {
726  if (errno == EINVAL)
727  {
728  printf("Video4Linux: device '%s' does not support USERPTR access mode\n", video_device_name.c_str());
729  return;
730  }
731  else
732  {
733  printf("Video4Linux: device '%s' does not support streaming access\n", video_device_name.c_str());
734  return;
735  }
736  }
737  buffers = reinterpret_cast<buffer *>(calloc(4, sizeof(*buffers)));
738  if (!buffers)
739  {
740  printf("Out of memory\n");
741  return;
742  }
743  for (buffers_count = 0; buffers_count < 4; ++buffers_count)
744  {
745  buffers[buffers_count].length = buffer_size;
746  buffers[buffers_count].start = memalign(page_size, buffer_size);
748  {
749  printf("Out of memory\n");
750  return;
751  }
752  }
753  }
754  else
755  {
756  printf("Cannot parse access mode for device '%s': '%s', system malfunction expected\n", video_device_name.c_str(), io_method_name.c_str());
757  return;
758  }
759 }
760 
761 bool AbstractV4LUSBCam::decode_ffmpeg(const void *src, int len, camera_image_t *dest)
762 {
763  char* MJPEG = const_cast<char *>(reinterpret_cast<const char *>(src));
764  char* RGB = dest->image;
765  static int got_picture = 1;
766  // clear the picture
767  memset(RGB, 0, avframe_rgb_size);
768 #if LIBAVCODEC_VERSION_MAJOR > 52
769  av_init_packet(avpkt);
770  av_packet_from_data(avpkt, reinterpret_cast<unsigned char*>(MJPEG), len);
771  if(avcodec_send_packet(avcodec_context, avpkt) < 0)
772  {
773  printf("FFMPEG: error passing frame to decoder context\n");
774  return false;
775  }
776 #else
777  avcodec_decode_video(avcodec_context, avframe_camera, &got_picture, (uint8_t *) MJPEG, len);
778  if (!got_picture)
779  {
780  printf("FFMPEG: buffer empty: expected picture data\n");
781  return;
782  }
783 #endif
784  if (avcodec_receive_frame(avcodec_context, avframe_camera) < 0)
785  {
786  printf("FFMPEG: error decoding frame\n");
787  return false;
788  }
789  if (!got_picture)
790  {
791  printf("FFMPEG: MJPEG frame data expected, but was not received\n");
792  return false;
793  }
794  int xsize = avcodec_context->width;
795  int ysize = avcodec_context->height;
796 
797 #if LIBAVCODEC_VERSION_MAJOR > 52
798  int pic_size = av_image_get_buffer_size(avcodec_context->pix_fmt, xsize, ysize, 1);
799 #else
800  // TODO(lucasw) avpicture_get_size corrupts the pix_fmt
801  int pic_size = avpicture_get_size(avcodec_context->pix_fmt, xsize, ysize);
802 #endif
803  // int pic_size = av_image_get_buffer_size(avcodec_context_->pix_fmt, xsize, ysize);
804  if (pic_size != avframe_camera_size)
805  {
806  printf("FFMPEG: MJPEG output buffer size mismatch: %i (%i expected)\n", avframe_camera_size, pic_size);
807  return false;
808  }
809  // YUV format conversion to RGB
810  sws_scale(video_sws, avframe_camera->data, avframe_camera->linesize, 0, ysize, avframe_rgb->data, avframe_rgb->linesize);
811 
812 #if LIBAVCODEC_VERSION_MAJOR > 52
813  int size = av_image_copy_to_buffer(
814  reinterpret_cast<uint8_t *>(RGB),
816  avframe_rgb->data,
817  avframe_rgb->linesize,
818  AV_PIX_FMT_RGB24,
819  xsize,
820  ysize,
821  1);
822 #else
823  int size = avpicture_layout(
824  reinterpret_cast<AVPicture *>(avframe_rgb), AV_PIX_FMT_RGB24,
825  xsize, ysize, reinterpret_cast<uint8_t *>(RGB), avframe_rgb_size);
826 #endif
827  if (size != avframe_rgb_size)
828  {
829  printf("FFMPEG: image layout mismatch: %i (%i expected)\n", size, avframe_rgb_size);
830  return false;
831  }
832  return true;
833 }
834 
835 std::vector<capture_format_t> &AbstractV4LUSBCam::get_supported_formats()
836 {
837  supported_formats.clear();
838  struct v4l2_fmtdesc current_format;
839  current_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
840  current_format.index = 0;
841  for(current_format.index = 0;
842  usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_ENUM_FMT), &current_format) == 0;
843  current_format.index++)
844  {
845  struct v4l2_frmsizeenum current_size;
846  current_size.index = 0;
847  current_size.pixel_format = current_format.pixelformat;
848 
849  for(current_size.index = 0;
851  file_dev, static_cast<int>(VIDIOC_ENUM_FRAMESIZES), &current_size) == 0;
852  current_size.index++)
853  {
854  struct v4l2_frmivalenum current_interval;
855  current_interval.index = 0;
856  current_interval.pixel_format = current_size.pixel_format;
857  current_interval.width = current_size.discrete.width;
858  current_interval.height = current_size.discrete.height;
859  for(current_interval.index = 0;
861  file_dev, static_cast<int>(VIDIOC_ENUM_FRAMEINTERVALS), &current_interval) == 0;
862  current_interval.index++)
863  {
864  if(current_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
865  capture_format_t capture_format;
866  capture_format.format = current_format;
867  capture_format.size = current_size;
868  capture_format.interval = current_interval;
869  supported_formats.push_back(capture_format);
870  }
871  } // interval loop
872  } // size loop
873  } // fmt loop
874  return supported_formats;
875 }
876 
877 bool AbstractV4LUSBCam::process_image(const void *src, int len, camera_image_t *dest)
878 {
879  bool result = false;
880  if(v4l_pixel_format == V4L2_PIX_FMT_YUYV)
881  {
882  if(monochrome) // actually format V4L2_PIX_FMT_Y16, but usb_cam::utils::xioctl gets unhappy if you don't use the advertised type (yuyv)
883  result = util::converters::MONO102MONO8(const_cast<char *>(reinterpret_cast<const char *>(src)), dest->image, dest->width * dest->height);
884  else
885  result = util::converters::YUYV2RGB(const_cast<char *>(reinterpret_cast<const char *>(src)), dest->image, dest->width * dest->height);
886  }
887  else if(v4l_pixel_format == V4L2_PIX_FMT_UYVY)
888  result = util::converters::UYVY2RGB(const_cast<char *>(reinterpret_cast<const char *>(src)), dest->image, dest->width * dest->height);
889  else if(v4l_pixel_format == V4L2_PIX_FMT_MJPEG || v4l_pixel_format == V4L2_PIX_FMT_H264)
890  result = decode_ffmpeg(src, len, dest); // Internal conversion: condext-dependent
891  else if(v4l_pixel_format == V4L2_PIX_FMT_RGB24 || v4l_pixel_format == V4L2_PIX_FMT_GREY)
892  result = util::converters::COPY2RGB(const_cast<char *>(reinterpret_cast<const char *>(src)), dest->image, dest->width * dest->height);
893  else if(v4l_pixel_format == V4L2_PIX_FMT_YUV420)
894  result = util::converters::YUV4202RGB(const_cast<char *>(reinterpret_cast<const char *>(src)), dest->image, dest->width, dest->height);
895  else if(v4l_pixel_format == V4L2_PIX_FMT_BGR24) // Direct copy for OpenCV
896  {
897  memcpy(dest->image, src, len);
898  result = true;
899  }
900  return result;
901 }
902 
903 bool AbstractV4LUSBCam::set_v4l_parameter(const std::string &param, const std::string &value)
904 {
905  std::stringstream ss;
906  ss << "v4l2-ctl --device=" << video_device_name << " -c " << param << "=" << value << " 2>&1";
907  std::string cmd = ss.str();
908  // printf("%s\n", cmd.c_str());
909  // capture the output
910  std::string output;
911  const int kBufferSize = 256;
912  char buffer[kBufferSize];
913  FILE * stream = popen(cmd.c_str(), "r");
914  if(stream)
915  {
916  while (!feof(stream))
917  {
918  if(fgets(buffer, kBufferSize, stream) != NULL)
919  output.append(buffer);
920  }
921  pclose(stream);
922  // any output should be an error
923  if (output.length() > 0)
924  {
925  printf("Video4linux: error setting camera parameter: '%s'\n", output.c_str());
926  return false;
927  }
928  }
929  else
930  {
931  printf("Video4linux: error running control command: '%s'\n", cmd.c_str());
932  return false;
933  }
934  return true;
935 }
936 
938 {
939  // https://gist.github.com/tugstugi/2627647
940  // https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/extended-controls.html
941  printf("Video4linux: Querying V4L2 driver for available controls (register base 0x%X, 0..99)\n", V4L2_CID_BASE);
942  struct v4l2_queryctrl ctrl;
943  struct v4l2_querymenu menu;
944  memset (&ctrl, 0, sizeof (ctrl));
945  memset (&menu, 0, sizeof (menu));
946  std::vector<std::string> disabled_controls;
947  // std::vector<std::string> ignored_controls;
948  ctrl.id = V4L2_CID_BASE;
949  while(ioctl(file_dev, VIDIOC_QUERYCTRL, &ctrl) == 0)
950  {
951  camera_control_t control;
952  std::stringstream description;
953  if(ctrl.flags & V4L2_CTRL_FLAG_DISABLED)
954  {
955  disabled_controls.push_back(util::converters::v4l_control_name_to_param_name(reinterpret_cast<char*>(ctrl.name)));
956  }
957  else
958  {
959  control.name = util::converters::v4l_control_name_to_param_name(reinterpret_cast<char*>(ctrl.name));
960  control.type = static_cast<v4l2_ctrl_type>(ctrl.type);
961  control.value = std::to_string(ctrl.default_value);
962  description << std::string(reinterpret_cast<char*>(ctrl.name)) << ", min = "
963  << std::to_string(ctrl.minimum) << ", max = "
964  << std::to_string(ctrl.maximum) << ", step = "
965  << std::to_string(ctrl.step) << ", flags = 0x" << std::hex << ctrl.flags << std::dec;
966  if(ctrl.type == V4L2_CTRL_TYPE_MENU)
967  {
968  menu.id = ctrl.id;
969  description << " [ ";
970  for(menu.index = ctrl.minimum; menu.index <= ctrl.maximum; menu.index++)
971  {
972  if(ioctl(file_dev, VIDIOC_QUERYMENU, &menu) == 0)
973  description << menu.index << ": " << std::string(reinterpret_cast<char*>(menu.name)) << " ";
974  }
975  description << "]";
976  }
977  control.description = description.str();
978  controls.push_back(control);
979  }
980  //std::cout << util::converters::v4l_control_name_to_param_name(reinterpret_cast<char*>(ctrl.name)) << std::endl;
981 
982  ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
983  }
984  if(!disabled_controls.empty())
985  {
986  std::cout << "Disabled controls: ";
987  for(auto dc: disabled_controls)
988  std::cout << dc << " ";
989  std::cout << std::endl;
990  }
991  printf("Sorting control names:\n");
992  if(!controls.empty())
993  {
994  for(auto c = controls.begin(); c != controls.end(); c++)
995  {
996  if(c->name.find("auto") != std::string::npos)
997  {
998  camera_control_t tc = (*c);
999  controls.erase(c);
1000  controls.insert(controls.begin(), tc);
1001  }
1002  }
1003  }
1004  for(auto c: controls)
1005  printf("\t%s\n", c.name.c_str());
1006 }
1007 
1009 {
1010  printf("Video4linux: Setting up auxiliary camera parameters\n");
1011  if(controls.empty())
1012  {
1013  printf("Video4linux: camera controls was not queried properly, please call v4l_query_controls() before!\n");
1014  return;
1015  }
1016  for(auto control: controls)
1017  {
1018  if(ignore_controls.find(control.name) == ignore_controls.end())
1019  if(!set_v4l_parameter(control.name, control.value))
1020  printf("Video4linux: cannot set V4L control %s\n", control.name.c_str());
1021  }
1022  /* REPLACED WITH DYNAMICALLY QUERIED PARAMETERS
1023  // Autofocus
1024  if(autofocus)
1025  {
1026  struct v4l2_queryctrl queryctrl;
1027  struct v4l2_ext_control control;
1028 
1029  memset(&queryctrl, 0, sizeof(queryctrl));
1030  queryctrl.id = V4L2_CID_FOCUS_AUTO;
1031 
1032  if (usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_QUERYCTRL), &queryctrl) < 0)
1033  {
1034  if (errno != EINVAL)
1035  printf("Video4linux: cannot query auxiliary control (FOCUS_AUTO, %i)\n", errno);
1036  else
1037  printf("Video4linux: auto focus not supported (%i)\n", errno);
1038  }
1039  else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
1040  printf("Video4linux: auto focus not supported (%i)\n", errno);
1041  else
1042  {
1043  memset(&control, 0, sizeof(control));
1044  control.id = V4L2_CID_FOCUS_AUTO;
1045  control.value = 1;
1046 
1047  if (usb_cam::util::xioctl(file_dev, static_cast<int>(VIDIOC_S_CTRL), &control) < 0)
1048  printf("Video4linux: auxiliary control not supported (%i)\n", errno);
1049  }
1050  set_v4l_parameter("focus_auto", 1);
1051  }
1052  else
1053  {
1054  set_v4l_parameter("focus_auto", 0);
1055  if(focus >= 0)
1056  set_v4l_parameter("focus_absolute", focus);
1057  }
1058  // Autoexposure
1059  if(autoexposure)
1060  set_v4l_parameter("exposure_auto", 1);
1061  else
1062  {
1063  set_v4l_parameter("exposure_auto", 0);
1064  set_v4l_parameter("exposure_absolute", exposure);
1065  }
1066  // Auto white balance
1067  if(auto_white_balance)
1068  set_v4l_parameter("white_balance_temperature_auto", 1);
1069  else
1070  {
1071  set_v4l_parameter("white_balance_temperature_auto", 0);
1072  set_v4l_parameter("white_balance_temperature", white_balance);
1073  }
1074  // Brightness
1075  if(brightness >= 0)
1076  set_v4l_parameter("brightness", brightness);
1077  // Contrast
1078  if(contrast >= 0)
1079  set_v4l_parameter("contrast", contrast);
1080  // Saturation
1081  if(saturation >= 0)
1082  set_v4l_parameter("saturation", saturation);
1083  // Sharpness
1084  if(sharpness >= 0)
1085  set_v4l_parameter("sharpness", sharpness);
1086  // Gain
1087  if(gain >= 0)
1088  set_v4l_parameter("gain", gain);
1089  */
1090 }
static bool process_image(const void *src, int len, camera_image_t *dest)
std::string value
Definition: types.h:137
struct v4l2_frmivalenum interval
Definition: types.h:129
static camera_image_t * read_frame()
static const time_t epoch_time_shift
Definition: camera_driver.h:48
static AVCodecContext * avcodec_context
Definition: camera_driver.h:60
void * start
Definition: types.h:108
static AVPacket * avpkt
Definition: camera_driver.h:56
static color_format_t color_format
Definition: camera_driver.h:45
string cmd
static void run_grabber(unsigned int &buffer_size)
std::string name
Definition: types.h:135
#define AV_CODEC_ID_MJPEG
Definition: camera_driver.h:13
static bool decode_ffmpeg(const void *src, int len, camera_image_t *dest)
static AVFrame * avframe_rgb
Definition: camera_driver.h:55
static AVFrame * avframe_camera
Definition: camera_driver.h:54
bool YUV4202RGB(char *YUV, char *&RGB, const int &width, const int &height)
Definition: converters.cpp:192
#define CLEAR(x)
Definition: util.h:6
static std::string color_format_name
Definition: camera_driver.h:74
static io_method_t io_method
Definition: camera_driver.h:42
color_format_t color_format_from_string(const std::string &str)
Definition: converters.cpp:79
static std::string io_method_name
Definition: camera_driver.h:72
std::string description
Definition: types.h:136
static unsigned int buffers_count
Definition: camera_driver.h:53
static std::vector< camera_control_t > controls
Definition: camera_driver.h:78
static std::vector< capture_format_t > & get_supported_formats()
std::size_t length
Definition: types.h:109
static pixel_format_t pixel_format
Definition: camera_driver.h:43
bool MONO102MONO8(const char *RAW, char *&MONO, const int &NumPixels)
Definition: converters.cpp:151
struct timespec stamp
Definition: types.h:120
struct v4l2_fmtdesc format
Definition: types.h:127
static camera_image_t * image
Definition: camera_driver.h:65
io_method_t io_method_from_string(const std::string &str)
Definition: converters.cpp:15
pixel_format_t
Definition: types.h:83
static unsigned int v4l_pixel_format
Definition: camera_driver.h:44
static AVDictionary * avoptions
Definition: camera_driver.h:59
v4l2_ctrl_type type
Definition: types.h:134
time_t get_epoch_time_shift()
Get epoch time shift.
Definition: util.cpp:52
struct v4l2_frmsizeenum size
Definition: types.h:128
static std::set< std::string > ignore_controls
Definition: camera_driver.h:79
io_method_t
Definition: types.h:74
static AVCodecID codec_id
Definition: camera_driver.h:58
static std::string video_device_name
Definition: camera_driver.h:71
static AVCodec * avcodec
Definition: camera_driver.h:57
std::string v4l_control_name_to_param_name(const char *name)
Definition: converters.cpp:237
bool UYVY2RGB(const char *YUV, char *&RGB, const int &NumPixels)
Definition: converters.cpp:215
static std::string pixel_format_name
Definition: camera_driver.h:73
static struct SwsContext * video_sws
Definition: camera_driver.h:63
static bool set_v4l_parameter(const std::string &param, const std::string &value)
std::string encoding
Definition: types.h:117
static std::vector< capture_format_t > supported_formats
Definition: camera_driver.h:67
color_format_t
Definition: types.h:98
pixel_format_t pixel_format_from_string(const std::string &str)
Definition: converters.cpp:27
int xioctl(int fd, int request, void *arg)
Definition: util.cpp:23
bool COPY2RGB(const char *input, char *&output, const int &NumPixels)
Definition: converters.cpp:186
bool YUYV2RGB(const char *YUV, char *&RGB, const int &NumPixels)
Definition: converters.cpp:162
unsigned int v4l_pixel_format_from_pixel_format(const pixel_format_t &pixelformat, bool &mono)
Definition: converters.cpp:90


usb_cam
Author(s): Benjamin Pitzer
autogenerated on Sat May 27 2023 02:53:04