1/* This is the contributed code:
2
3File:             cvcap_v4l.cpp
4Current Location: ../opencv-0.9.6/otherlibs/videoio
5
6Original Version: 2003-03-12  Magnus Lundin lundin@mlu.mine.nu
7Original Comments:
8
9ML:This set of files adds support for firevre and usb cameras.
10First it tries to install a firewire camera,
11if that fails it tries a v4l/USB camera
12It has been tested with the motempl sample program
13
14First Patch:  August 24, 2004 Travis Wood   TravisOCV@tkwood.com
15For Release:  OpenCV-Linux Beta4  opencv-0.9.6
16Tested On:    LMLBT44 with 8 video inputs
17Problems?     Post your questions at answers.opencv.org,
18              Report bugs at code.opencv.org,
19              Submit your fixes at https://github.com/Itseez/opencv/
20Patched Comments:
21
22TW: The cv cam utils that came with the initial release of OpenCV for LINUX Beta4
23were not working.  I have rewritten them so they work for me. At the same time, trying
24to keep the original code as ML wrote it as unchanged as possible.  No one likes to debug
25someone elses code, so I resisted changes as much as possible.  I have tried to keep the
26same "ideas" where applicable, that is, where I could figure out what the previous author
27intended. Some areas I just could not help myself and had to "spiffy-it-up" my way.
28
29These drivers should work with other V4L frame capture cards other then my bttv
30driven frame capture card.
31
32Re Written driver for standard V4L mode. Tested using LMLBT44 video capture card.
33Standard bttv drivers are on the LMLBT44 with up to 8 Inputs.
34
35This utility was written with the help of the document:
36http://pages.cpsc.ucalgary.ca/~sayles/VFL_HowTo
37as a general guide for interfacing into the V4l standard.
38
39Made the index value passed for icvOpenCAM_V4L(index) be the number of the
40video device source in the /dev tree. The -1 uses original /dev/video.
41
42Index  Device
43  0    /dev/video0
44  1    /dev/video1
45  2    /dev/video2
46  3    /dev/video3
47  ...
48  7    /dev/video7
49with
50  -1   /dev/video
51
52TW: You can select any video source, but this package was limited from the start to only
53ONE camera opened at any ONE time.
54This is an original program limitation.
55If you are interested, I will make my version available to other OpenCV users.  The big
56difference in mine is you may pass the camera number as part of the cv argument, but this
57convention is non standard for current OpenCV calls and the camera number is not currently
58passed into the called routine.
59
60Second Patch:   August 28, 2004 Sfuncia Fabio fiblan@yahoo.it
61For Release:  OpenCV-Linux Beta4 Opencv-0.9.6
62
63FS: this patch fix not sequential index of device (unplugged device), and real numCameras.
64    for -1 index (icvOpenCAM_V4L) i dont use /dev/video but real device available, because
65    if /dev/video is a link to /dev/video0 and i unplugged device on /dev/video0, /dev/video
66    is a bad link. I search the first available device with indexList.
67
68Third Patch:   December 9, 2004 Frederic Devernay Frederic.Devernay@inria.fr
69For Release:  OpenCV-Linux Beta4 Opencv-0.9.6
70
71[FD] I modified the following:
72 - handle YUV420P, YUV420, and YUV411P palettes (for many webcams) without using floating-point
73 - cvGrabFrame should not wait for the end of the first frame, and should return quickly
74   (see videoio doc)
75 - cvRetrieveFrame should in turn wait for the end of frame capture, and should not
76   trigger the capture of the next frame (the user choses when to do it using GrabFrame)
77   To get the old behavior, re-call cvRetrieveFrame just after cvGrabFrame.
78 - having global bufferIndex and FirstCapture variables makes the code non-reentrant
79 (e.g. when using several cameras), put these in the CvCapture struct.
80 - according to V4L HowTo, incrementing the buffer index must be done before VIDIOCMCAPTURE.
81 - the VID_TYPE_SCALES stuff from V4L HowTo is wrong: image size can be changed
82   even if the hardware does not support scaling (e.g. webcams can have several
83   resolutions available). Just don't try to set the size at 640x480 if the hardware supports
84   scaling: open with the default (probably best) image size, and let the user scale it
85   using SetProperty.
86 - image size can be changed by two subsequent calls to SetProperty (for width and height)
87 - bug fix: if the image size changes, realloc the new image only when it is grabbed
88 - issue errors only when necessary, fix error message formatting.
89
90Fourth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu
91For Release:  OpenCV-Linux Beta5 OpenCV-0.9.7
92
93I modified the following:
94  - Additional Video4Linux2 support :)
95  - Use mmap functions (v4l2)
96  - New methods are internal:
97    try_palette_v4l2 -> rewrite try_palette for v4l2
98    mainloop_v4l2, read_image_v4l2 -> this methods are moved from official v4l2 capture.c example
99    try_init_v4l -> device v4l initialisation
100    try_init_v4l2 -> device v4l2 initialisation
101    autosetup_capture_mode_v4l -> autodetect capture modes for v4l
102    autosetup_capture_mode_v4l2 -> autodetect capture modes for v4l2
103  - Modifications are according with Video4Linux old codes
104  - Video4Linux handling is automatically if it does not recognize a Video4Linux2 device
105  - Tested successfully with Logitech Quickcam Express (V4L), Creative Vista (V4L) and Genius VideoCam Notebook (V4L2)
106  - Correct source lines with compiler warning messages
107  - Information message from v4l/v4l2 detection
108
109Fifth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu
110For Release:  OpenCV-Linux Beta5 OpenCV-0.9.7
111
112I modified the following:
113  - SN9C10x chip based webcams support
114  - New methods are internal:
115    bayer2rgb24, sonix_decompress -> decoder routines for SN9C10x decoding from Takafumi Mizuno <taka-qce@ls-a.jp> with his pleasure :)
116  - Tested successfully with Genius VideoCam Notebook (V4L2)
117
118Sixth Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu
119For Release:  OpenCV-Linux Beta5 OpenCV-0.9.7
120
121I added the following:
122  - Add capture control support (hue, saturation, brightness, contrast, gain)
123  - Get and change V4L capture controls (hue, saturation, brightness, contrast)
124  - New method is internal:
125    icvSetControl -> set capture controls
126  - Tested successfully with Creative Vista (V4L)
127
128Seventh Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu
129For Release:  OpenCV-Linux Beta5 OpenCV-0.9.7
130
131I added the following:
132  - Detect, get and change V4L2 capture controls (hue, saturation, brightness, contrast, gain)
133  - New methods are internal:
134    v4l2_scan_controls_enumerate_menu, v4l2_scan_controls -> detect capture control intervals
135  - Tested successfully with Genius VideoCam Notebook (V4L2)
136
1378th patch: Jan 5, 2006, Olivier.Bornet@idiap.ch
138Add support of V4L2_PIX_FMT_YUYV and V4L2_PIX_FMT_MJPEG.
139With this patch, new webcams of Logitech, like QuickCam Fusion works.
140Note: For use these webcams, look at the UVC driver at
141http://linux-uvc.berlios.de/
142
1439th patch: Mar 4, 2006, Olivier.Bornet@idiap.ch
144- try V4L2 before V4L, because some devices are V4L2 by default,
145  but they try to implement the V4L compatibility layer.
146  So, I think this is better to support V4L2 before V4L.
147- better separation between V4L2 and V4L initialization. (this was needed to support
148  some drivers working, but not fully with V4L2. (so, we do not know when we
149  need to switch from V4L2 to V4L.
150
15110th patch: July 02, 2008, Mikhail Afanasyev fopencv@theamk.com
152Fix reliability problems with high-resolution UVC cameras on linux
153the symptoms were damaged image and 'Corrupt JPEG data: premature end of data segment' on stderr
154- V4L_ABORT_BADJPEG detects JPEG warnings and turns them into errors, so bad images
155  could be filtered out
156- USE_TEMP_BUFFER fixes the main problem (improper buffer management) and
157  prevents bad images in the first place
158
15911th patch: Apr 13, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
160- Tries to setup all properties first through v4l2_ioctl call.
161- Allows setting up all Video4Linux properties through cvSetCaptureProperty instead of only CV_CAP_PROP_BRIGHTNESS, CV_CAP_PROP_CONTRAST, CV_CAP_PROP_SATURATION, CV_CAP_PROP_HUE, CV_CAP_PROP_GAIN and CV_CAP_PROP_EXPOSURE.
162
16312th patch: Apr 16, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
164- CvCaptureCAM_V4L structure cleanup (no longer needs <PROPERTY>_{min,max,} variables)
165- Introduction of v4l2_ctrl_range - minimum and maximum allowed values for v4l controls
166- Allows setting up all Video4Linux properties through cvSetCaptureProperty using input values between 0.0 and 1.0
167- Gets v4l properties first through v4l2_ioctl call (ignores capture->is_v4l2_device)
168- cvGetCaptureProperty adjusted to support the changes
169- Returns device properties to initial values after device closes
170
17113th patch: Apr 27, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
172- Solved problem mmaping the device using uvcvideo driver (use o v4l2_mmap instead of mmap)
173make & enjoy!
174
17514th patch: May 10, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
176- Bug #142: Solved/Workaround "setting frame width and height does not work"
177  There was a problem setting up the size when the input is a v4l2 device
178  The workaround closes the camera and reopens it with the new definition
179  Planning for future rewrite of this whole library (July/August 2010)
180
18115th patch: May 12, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
182- Broken compile of library (include "_videoio.h")
183
18416th patch: Dec 16, 2014, Joseph Howse josephhowse@nummist.com
185- Allow getting/setting CV_CAP_PROP_MODE. These values are supported:
186    - CV_CAP_MODE_BGR  : BGR24 (default)
187    - CV_CAP_MODE_RGB  : RGB24
188    - CV_CAP_MODE_GRAY : Y8, extracted from YUV420
189- Tested successfully on these cameras:
190    - PlayStation 3 Eye
191    - Logitech C920
192    - Odroid USB-CAM 720P
193
19417th patch: May 9, 2015, Matt Sandler
195 added supported for CV_CAP_PROP_POS_MSEC, CV_CAP_PROP_POS_FRAMES, CV_CAP_PROP_FPS
196
197*/
198
199/*M///////////////////////////////////////////////////////////////////////////////////////
200//
201//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
202//
203//  By downloading, copying, installing or using the software you agree to this license.
204//  If you do not agree to this license, do not download, install,
205//  copy or use the software.
206//
207//
208//                        Intel License Agreement
209//                For Open Source Computer Vision Library
210//
211// Copyright (C) 2000, Intel Corporation, all rights reserved.
212// Third party copyrights are property of their respective owners.
213//
214// Redistribution and use in source and binary forms, with or without modification,
215// are permitted provided that the following conditions are met:
216//
217//   * Redistribution's of source code must retain the above copyright notice,
218//     this list of conditions and the following disclaimer.
219//
220//   * Redistribution's in binary form must reproduce the above copyright notice,
221//     this list of conditions and the following disclaimer in the documentation
222//     and/or other materials provided with the distribution.
223//
224//   * The name of Intel Corporation may not be used to endorse or promote products
225//     derived from this software without specific prior written permission.
226//
227// This software is provided by the copyright holders and contributors "as is" and
228// any express or implied warranties, including, but not limited to, the implied
229// warranties of merchantability and fitness for a particular purpose are disclaimed.
230// In no event shall the Intel Corporation or contributors be liable for any direct,
231// indirect, incidental, special, exemplary, or consequential damages
232// (including, but not limited to, procurement of substitute goods or services;
233// loss of use, data, or profits; or business interruption) however caused
234// and on any theory of liability, whether in contract, strict liability,
235// or tort (including negligence or otherwise) arising in any way out of
236// the use of this software, even if advised of the possibility of such damage.
237//
238//M*/
239
240#include "precomp.hpp"
241
242#if !defined WIN32 && defined HAVE_LIBV4L
243
244#define CLEAR(x) memset (&(x), 0, sizeof (x))
245
246#include <stdio.h>
247#include <unistd.h>
248#include <fcntl.h>
249#include <errno.h>
250#include <sys/types.h>
251#include <sys/mman.h>
252#include <string.h>
253#include <stdlib.h>
254#include <asm/types.h>          /* for videodev2.h */
255#include <assert.h>
256#include <sys/stat.h>
257#include <sys/ioctl.h>
258
259#ifdef HAVE_CAMV4L
260#include <linux/videodev.h>
261#endif
262#ifdef HAVE_CAMV4L2
263#include <linux/videodev2.h>
264#endif
265
266#include <libv4l1.h>
267#include <libv4l2.h>
268
269/* Defaults - If your board can do better, set it here.  Set for the most common type inputs. */
270#define DEFAULT_V4L_WIDTH  640
271#define DEFAULT_V4L_HEIGHT 480
272
273#define CHANNEL_NUMBER 1
274#define MAX_CAMERAS 8
275
276
277// default and maximum number of V4L buffers, not including last, 'special' buffer
278#define MAX_V4L_BUFFERS 10
279#define DEFAULT_V4L_BUFFERS 4
280
281// if enabled, copies data from the buffer. this uses a bit more memory,
282//  but much more reliable for some UVC cameras
283#define USE_TEMP_BUFFER
284
285#define MAX_DEVICE_DRIVER_NAME 80
286
287/* Device Capture Objects */
288/* V4L2 structure */
289struct buffer
290{
291  void *  start;
292  size_t  length;
293};
294static unsigned int n_buffers = 0;
295
296/* TODO: Dilemas: */
297/* TODO: Consider drop the use of this data structure and perform ioctl to obtain needed values */
298/* TODO: Consider at program exit return controls to the initial values - See v4l2_free_ranges function */
299/* TODO: Consider at program exit reset the device to default values - See v4l2_free_ranges function */
300typedef struct v4l2_ctrl_range {
301  __u32 ctrl_id;
302  __s32 initial_value;
303  __s32 current_value;
304  __s32 minimum;
305  __s32 maximum;
306  __s32 default_value;
307} v4l2_ctrl_range;
308
309typedef struct CvCaptureCAM_V4L
310{
311    char* deviceName;
312    int deviceHandle;
313    int bufferIndex;
314    int FirstCapture;
315
316    int width; int height;
317    int mode;
318
319    struct video_capability capability;
320    struct video_window     captureWindow;
321    struct video_picture    imageProperties;
322    struct video_mbuf       memoryBuffer;
323    struct video_mmap       *mmaps;
324    char *memoryMap;
325    IplImage frame;
326
327   /* V4L2 variables */
328   buffer buffers[MAX_V4L_BUFFERS + 1];
329   struct v4l2_capability cap;
330   struct v4l2_input inp;
331   struct v4l2_format form;
332   struct v4l2_crop crop;
333   struct v4l2_cropcap cropcap;
334   struct v4l2_requestbuffers req;
335   struct v4l2_jpegcompression compr;
336   struct v4l2_control control;
337   enum v4l2_buf_type type;
338   struct v4l2_queryctrl queryctrl;
339
340   struct timeval timestamp;
341
342   /** value set the buffer of V4L*/
343   int sequence;
344
345   /* V4L2 control variables */
346   v4l2_ctrl_range** v4l2_ctrl_ranges;
347   int v4l2_ctrl_count;
348
349   int is_v4l2_device;
350}
351CvCaptureCAM_V4L;
352
353static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture );
354
355static int icvGrabFrameCAM_V4L( CvCaptureCAM_V4L* capture );
356static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int );
357CvCapture* cvCreateCameraCapture_V4L( int index );
358
359static double icvGetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id );
360static int    icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id, double value );
361
362static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h);
363
364/***********************   Implementations  ***************************************/
365
366static int numCameras = 0;
367static int indexList = 0;
368
369// IOCTL handling for V4L2
370#ifdef HAVE_IOCTL_ULONG
371static int xioctl( int fd, unsigned long request, void *arg)
372#else
373static int xioctl( int fd, int request, void *arg)
374#endif
375{
376
377  int r;
378
379
380  do r = v4l2_ioctl (fd, request, arg);
381  while (-1 == r && EINTR == errno);
382
383  return r;
384
385}
386
387
388/* Simple test program: Find number of Video Sources available.
389   Start from 0 and go to MAX_CAMERAS while checking for the device with that name.
390   If it fails on the first attempt of /dev/video0, then check if /dev/video is valid.
391   Returns the global numCameras with the correct value (we hope) */
392
393static void icvInitCapture_V4L() {
394   int deviceHandle;
395   int CameraNumber;
396   char deviceName[MAX_DEVICE_DRIVER_NAME];
397
398   CameraNumber = 0;
399   while(CameraNumber < MAX_CAMERAS) {
400      /* Print the CameraNumber at the end of the string with a width of one character */
401      sprintf(deviceName, "/dev/video%1d", CameraNumber);
402      /* Test using an open to see if this new device name really does exists. */
403      deviceHandle = open(deviceName, O_RDONLY);
404      if (deviceHandle != -1) {
405         /* This device does indeed exist - add it to the total so far */
406    // add indexList
407    indexList|=(1 << CameraNumber);
408        numCameras++;
409    }
410    if (deviceHandle != -1)
411      close(deviceHandle);
412      /* Set up to test the next /dev/video source in line */
413      CameraNumber++;
414   } /* End while */
415
416}; /* End icvInitCapture_V4L */
417
418
419static int try_init_v4l(CvCaptureCAM_V4L* capture, char *deviceName)
420
421{
422
423  // if detect = -1 then unable to open device
424  // if detect = 0 then detected nothing
425  // if detect = 1 then V4L device
426  int detect = 0;
427
428
429  // Test device for V4L compability
430
431  /* Test using an open to see if this new device name really does exists. */
432  /* No matter what the name - it still must be opened! */
433  capture->deviceHandle = v4l1_open(deviceName, O_RDWR);
434
435
436  if (capture->deviceHandle == 0)
437  {
438    detect = -1;
439
440    icvCloseCAM_V4L(capture);
441  }
442
443  if (detect == 0)
444  {
445    /* Query the newly opened device for its capabilities */
446    if (v4l1_ioctl(capture->deviceHandle, VIDIOCGCAP, &capture->capability) < 0)
447    {
448      detect = 0;
449
450      icvCloseCAM_V4L(capture);
451    }
452      else
453    {
454      detect = 1;
455    }
456  }
457
458  return detect;
459
460}
461
462
463static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName)
464{
465
466  // if detect = -1 then unable to open device
467  // if detect = 0 then detected nothing
468  // if detect = 1 then V4L2 device
469  int detect = 0;
470
471
472  // Test device for V4L2 compability
473
474  /* Open and test V4L2 device */
475  capture->deviceHandle = v4l2_open (deviceName, O_RDWR /* required */ | O_NONBLOCK, 0);
476
477
478
479  if (capture->deviceHandle == 0)
480  {
481    detect = -1;
482
483    icvCloseCAM_V4L(capture);
484  }
485
486  if (detect == 0)
487  {
488    CLEAR (capture->cap);
489    if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYCAP, &capture->cap))
490    {
491      detect = 0;
492
493      icvCloseCAM_V4L(capture);
494    }
495      else
496    {
497      CLEAR (capture->capability);
498      capture->capability.type = capture->cap.capabilities;
499
500      /* Query channels number */
501      if (-1 != xioctl (capture->deviceHandle, VIDIOC_G_INPUT, &capture->capability.channels))
502      {
503        detect = 1;
504      }
505    }
506  }
507
508  return detect;
509
510}
511
512
513static void v4l2_free_ranges(CvCaptureCAM_V4L* capture) {
514  int i;
515  if (capture->v4l2_ctrl_ranges != NULL) {
516    for (i = 0; i < capture->v4l2_ctrl_count; i++) {
517      /* Return device to initial values: */
518      /* double value = (capture->v4l2_ctrl_ranges[i]->initial_value == 0)?0.0:((float)capture->v4l2_ctrl_ranges[i]->initial_value - capture->v4l2_ctrl_ranges[i]->minimum) / (capture->v4l2_ctrl_ranges[i]->maximum - capture->v4l2_ctrl_ranges[i]->minimum); */
519      /* Return device to default values: */
520      /* double value = (capture->v4l2_ctrl_ranges[i]->default_value == 0)?0.0:((float)capture->v4l2_ctrl_ranges[i]->default_value - capture->v4l2_ctrl_ranges[i]->minimum + 1) / (capture->v4l2_ctrl_ranges[i]->maximum - capture->v4l2_ctrl_ranges[i]->minimum); */
521
522      /* icvSetPropertyCAM_V4L(capture, capture->v4l2_ctrl_ranges[i]->ctrl_id, value); */
523      free(capture->v4l2_ctrl_ranges[i]);
524    }
525  }
526  free(capture->v4l2_ctrl_ranges);
527  capture->v4l2_ctrl_count  = 0;
528  capture->v4l2_ctrl_ranges = NULL;
529}
530
531static void v4l2_add_ctrl_range(CvCaptureCAM_V4L* capture, v4l2_control* ctrl) {
532  v4l2_ctrl_range* range    = (v4l2_ctrl_range*)malloc(sizeof(v4l2_ctrl_range));
533  range->ctrl_id            = ctrl->id;
534  range->initial_value      = ctrl->value;
535  range->current_value      = ctrl->value;
536  range->minimum            = capture->queryctrl.minimum;
537  range->maximum            = capture->queryctrl.maximum;
538  range->default_value      = capture->queryctrl.default_value;
539  capture->v4l2_ctrl_ranges[capture->v4l2_ctrl_count] = range;
540  capture->v4l2_ctrl_count += 1;
541  capture->v4l2_ctrl_ranges = (v4l2_ctrl_range**)realloc((v4l2_ctrl_range**)capture->v4l2_ctrl_ranges, (capture->v4l2_ctrl_count + 1) * sizeof(v4l2_ctrl_range*));
542}
543
544static int v4l2_get_ctrl_default(CvCaptureCAM_V4L* capture, __u32 id) {
545  int i;
546  for (i = 0; i < capture->v4l2_ctrl_count; i++) {
547    if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) {
548      return capture->v4l2_ctrl_ranges[i]->default_value;
549    }
550  }
551  return -1;
552}
553
554static int v4l2_get_ctrl_min(CvCaptureCAM_V4L* capture, __u32 id) {
555  int i;
556  for (i = 0; i < capture->v4l2_ctrl_count; i++) {
557    if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) {
558      return capture->v4l2_ctrl_ranges[i]->minimum;
559    }
560  }
561  return -1;
562}
563
564static int v4l2_get_ctrl_max(CvCaptureCAM_V4L* capture, __u32 id) {
565  int i;
566  for (i = 0; i < capture->v4l2_ctrl_count; i++) {
567    if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) {
568      return capture->v4l2_ctrl_ranges[i]->maximum;
569    }
570  }
571  return -1;
572}
573
574
575static void v4l2_scan_controls(CvCaptureCAM_V4L* capture) {
576
577  __u32 ctrl_id;
578  struct v4l2_control c;
579  if (capture->v4l2_ctrl_ranges != NULL) {
580    v4l2_free_ranges(capture);
581  }
582  capture->v4l2_ctrl_ranges = (v4l2_ctrl_range**)malloc(sizeof(v4l2_ctrl_range*));
583#ifdef V4L2_CTRL_FLAG_NEXT_CTRL
584  /* Try the extended control API first */
585  capture->queryctrl.id      = V4L2_CTRL_FLAG_NEXT_CTRL;
586  if(0 == v4l2_ioctl (capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl)) {
587    do {
588      c.id = capture->queryctrl.id;
589      capture->queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
590      if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
591        continue;
592      }
593      if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
594         capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
595         capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
596        continue;
597      }
598      if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
599        v4l2_add_ctrl_range(capture, &c);
600      }
601
602    } while(0 == v4l2_ioctl (capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl));
603  } else
604#endif
605  {
606    /* Check all the standard controls */
607    for(ctrl_id=V4L2_CID_BASE; ctrl_id<V4L2_CID_LASTP1; ctrl_id++) {
608      capture->queryctrl.id = ctrl_id;
609      if(v4l2_ioctl(capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl) == 0) {
610        if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
611          continue;
612        }
613        if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
614           capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
615           capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
616          continue;
617        }
618        c.id = ctrl_id;
619
620        if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
621          v4l2_add_ctrl_range(capture, &c);
622        }
623      }
624    }
625
626    /* Check any custom controls */
627    for(ctrl_id=V4L2_CID_PRIVATE_BASE; ; ctrl_id++) {
628      capture->queryctrl.id = ctrl_id;
629      if(v4l2_ioctl(capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl) == 0) {
630        if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
631          continue;
632        }
633
634
635        if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
636           capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
637           capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
638           continue;
639        }
640
641        c.id = ctrl_id;
642
643        if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
644          v4l2_add_ctrl_range(capture, &c);
645        }
646      } else {
647        break;
648      }
649    }
650  }
651}
652
653static inline int channels_for_mode(int mode)
654{
655    switch(mode) {
656    case CV_CAP_MODE_GRAY:
657        return 1;
658    case CV_CAP_MODE_YUYV:
659        return 2;
660    default:
661        return 3;
662    }
663}
664
665static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName)
666{
667   int detect_v4l2 = 0;
668
669   capture->deviceName = strdup(deviceName);
670
671   detect_v4l2 = try_init_v4l2(capture, deviceName);
672
673   if (detect_v4l2 != 1) {
674       /* init of the v4l2 device is not OK */
675       return -1;
676   }
677
678   /* starting from here, we assume we are in V4L2 mode */
679   capture->is_v4l2_device = 1;
680
681   capture->v4l2_ctrl_ranges = NULL;
682   capture->v4l2_ctrl_count = 0;
683
684   /* Scan V4L2 controls */
685   v4l2_scan_controls(capture);
686
687   if ((capture->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
688      /* Nope. */
689      fprintf( stderr, "VIDEOIO ERROR: V4L2: device %s is unable to capture video memory.\n",deviceName);
690      icvCloseCAM_V4L(capture);
691      return -1;
692   }
693
694   /* The following code sets the CHANNEL_NUMBER of the video input.  Some video sources
695   have sub "Channel Numbers".  For a typical V4L TV capture card, this is usually 1.
696   I myself am using a simple NTSC video input capture card that uses the value of 1.
697   If you are not in North America or have a different video standard, you WILL have to change
698   the following settings and recompile/reinstall.  This set of settings is based on
699   the most commonly encountered input video source types (like my bttv card) */
700
701   if(capture->inp.index > 0) {
702       CLEAR (capture->inp);
703       capture->inp.index = CHANNEL_NUMBER;
704       /* Set only channel number to CHANNEL_NUMBER */
705       /* V4L2 have a status field from selected video mode */
706       if (-1 == xioctl (capture->deviceHandle, VIDIOC_ENUMINPUT, &capture->inp))
707       {
708         fprintf (stderr, "VIDEOIO ERROR: V4L2: Aren't able to set channel number\n");
709         icvCloseCAM_V4L (capture);
710         return -1;
711       }
712   } /* End if */
713
714   /* Find Window info */
715   CLEAR (capture->form);
716   capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
717
718   if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
719       fprintf( stderr, "VIDEOIO ERROR: V4L2: Could not obtain specifics of capture window.\n\n");
720       icvCloseCAM_V4L(capture);
721       return -1;
722   }
723
724  /* libv4l will convert from any format to V4L2_PIX_FMT_BGR24,
725     V4L2_PIX_FMT_RGV24, or V4L2_PIX_FMT_YUV420 */
726  unsigned int requestedPixelFormat;
727  switch (capture->mode) {
728  case CV_CAP_MODE_RGB:
729    requestedPixelFormat = V4L2_PIX_FMT_RGB24;
730    break;
731  case CV_CAP_MODE_GRAY:
732    requestedPixelFormat = V4L2_PIX_FMT_YUV420;
733    break;
734  case CV_CAP_MODE_YUYV:
735    requestedPixelFormat = V4L2_PIX_FMT_YUYV;
736    break;
737  default:
738    requestedPixelFormat = V4L2_PIX_FMT_BGR24;
739    break;
740  }
741  CLEAR (capture->form);
742  capture->form.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
743  capture->form.fmt.pix.pixelformat = requestedPixelFormat;
744  capture->form.fmt.pix.field       = V4L2_FIELD_ANY;
745  capture->form.fmt.pix.width       = capture->width;
746  capture->form.fmt.pix.height      = capture->height;
747
748  if (-1 == xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form)) {
749      fprintf(stderr, "VIDEOIO ERROR: libv4l unable to ioctl S_FMT\n");
750      return -1;
751  }
752
753  if (requestedPixelFormat != capture->form.fmt.pix.pixelformat) {
754      fprintf( stderr, "VIDEOIO ERROR: libv4l unable convert to requested pixfmt\n");
755      return -1;
756  }
757
758   /* icvSetVideoSize(capture, DEFAULT_V4L_WIDTH, DEFAULT_V4L_HEIGHT); */
759
760   unsigned int min;
761
762   /* Buggy driver paranoia. */
763   min = capture->form.fmt.pix.width * 2;
764
765   if (capture->form.fmt.pix.bytesperline < min)
766       capture->form.fmt.pix.bytesperline = min;
767
768   min = capture->form.fmt.pix.bytesperline * capture->form.fmt.pix.height;
769
770   if (capture->form.fmt.pix.sizeimage < min)
771       capture->form.fmt.pix.sizeimage = min;
772
773   CLEAR (capture->req);
774
775   unsigned int buffer_number = DEFAULT_V4L_BUFFERS;
776
777   try_again:
778
779   capture->req.count = buffer_number;
780   capture->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
781   capture->req.memory = V4L2_MEMORY_MMAP;
782
783   if (-1 == xioctl (capture->deviceHandle, VIDIOC_REQBUFS, &capture->req))
784   {
785       if (EINVAL == errno)
786       {
787         fprintf (stderr, "%s does not support memory mapping\n", deviceName);
788       } else {
789         perror ("VIDIOC_REQBUFS");
790       }
791       /* free capture, and returns an error code */
792       icvCloseCAM_V4L (capture);
793       return -1;
794   }
795
796   if (capture->req.count < buffer_number)
797   {
798       if (buffer_number == 1)
799       {
800           fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName);
801
802           /* free capture, and returns an error code */
803           icvCloseCAM_V4L (capture);
804           return -1;
805       } else {
806         buffer_number--;
807   fprintf (stderr, "Insufficient buffer memory on %s -- decreaseing buffers\n", deviceName);
808
809   goto try_again;
810       }
811   }
812
813   for (n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
814   {
815       struct v4l2_buffer buf;
816
817       CLEAR (buf);
818
819       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
820       buf.memory = V4L2_MEMORY_MMAP;
821       buf.index = n_buffers;
822
823       if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYBUF, &buf)) {
824           perror ("VIDIOC_QUERYBUF");
825
826           /* free capture, and returns an error code */
827           icvCloseCAM_V4L (capture);
828           return -1;
829       }
830
831       capture->buffers[n_buffers].length = buf.length;
832       capture->buffers[n_buffers].start =
833         v4l2_mmap (NULL /* start anywhere */,
834                    buf.length,
835                    PROT_READ | PROT_WRITE /* required */,
836                    MAP_SHARED /* recommended */,
837                    capture->deviceHandle, buf.m.offset);
838
839       if (MAP_FAILED == capture->buffers[n_buffers].start) {
840           perror ("mmap");
841
842           /* free capture, and returns an error code */
843           icvCloseCAM_V4L (capture);
844           return -1;
845       }
846
847#ifdef USE_TEMP_BUFFER
848       if (n_buffers == 0) {
849           if (capture->buffers[MAX_V4L_BUFFERS].start) {
850               free(capture->buffers[MAX_V4L_BUFFERS].start);
851               capture->buffers[MAX_V4L_BUFFERS].start = NULL;
852       }
853
854           capture->buffers[MAX_V4L_BUFFERS].start = malloc(buf.length);
855           capture->buffers[MAX_V4L_BUFFERS].length = buf.length;
856       };
857#endif
858   }
859
860   /* Set up Image data */
861   cvInitImageHeader( &capture->frame,
862                      cvSize( capture->captureWindow.width,
863                              capture->captureWindow.height ),
864                      IPL_DEPTH_8U, channels_for_mode(capture->mode),
865                      IPL_ORIGIN_TL, 4 );
866   /* Allocate space for RGBA data */
867   capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
868
869   return 1;
870}; /* End _capture_V4L2 */
871
872
873static int _capture_V4L (CvCaptureCAM_V4L *capture, char *deviceName)
874{
875   int detect_v4l = 0;
876
877   detect_v4l = try_init_v4l(capture, deviceName);
878
879   if (detect_v4l == -1)
880   {
881     fprintf (stderr, "VIDEOIO ERROR: V4L"
882              ": device %s: Unable to open for READ ONLY\n", deviceName);
883
884     return -1;
885   }
886
887   if (detect_v4l <= 0)
888   {
889     fprintf (stderr, "VIDEOIO ERROR: V4L"
890              ": device %s: Unable to query number of channels\n", deviceName);
891
892     return -1;
893   }
894
895   {
896     if ((capture->capability.type & VID_TYPE_CAPTURE) == 0) {
897       /* Nope. */
898       fprintf( stderr, "VIDEOIO ERROR: V4L: "
899                "device %s is unable to capture video memory.\n",deviceName);
900       icvCloseCAM_V4L(capture);
901       return -1;
902     }
903
904   }
905
906
907   /* The following code sets the CHANNEL_NUMBER of the video input.  Some video sources
908   have sub "Channel Numbers".  For a typical V4L TV capture card, this is usually 1.
909   I myself am using a simple NTSC video input capture card that uses the value of 1.
910   If you are not in North America or have a different video standard, you WILL have to change
911   the following settings and recompile/reinstall.  This set of settings is based on
912   the most commonly encountered input video source types (like my bttv card) */
913
914   {
915
916     if(capture->capability.channels>0) {
917
918       struct video_channel selectedChannel;
919
920       selectedChannel.channel=CHANNEL_NUMBER;
921       if (v4l1_ioctl(capture->deviceHandle, VIDIOCGCHAN , &selectedChannel) != -1) {
922          /* set the video mode to ( VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM) */
923//           selectedChannel.norm = VIDEO_MODE_NTSC;
924          if (v4l1_ioctl(capture->deviceHandle, VIDIOCSCHAN , &selectedChannel) == -1) {
925             /* Could not set selected channel - Oh well */
926             //printf("\n%d, %s not NTSC capable.\n",selectedChannel.channel, selectedChannel.name);
927          } /* End if */
928       } /* End if */
929     } /* End if */
930
931   }
932
933   {
934
935     if(v4l1_ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) == -1) {
936       fprintf( stderr, "VIDEOIO ERROR: V4L: "
937                "Could not obtain specifics of capture window.\n\n");
938       icvCloseCAM_V4L(capture);
939       return -1;
940     }
941
942   }
943
944   {
945      if(v4l1_ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) {
946         fprintf( stderr, "VIDEOIO ERROR: V4L: Unable to determine size of incoming image\n");
947         icvCloseCAM_V4L(capture);
948         return -1;
949      }
950
951      int requestedVideoPalette;
952      int depth;
953      switch (capture->mode) {
954      case CV_CAP_MODE_GRAY:
955        requestedVideoPalette = VIDEO_PALETTE_YUV420;
956        depth = 8;
957        break;
958      case CV_CAP_MODE_YUYV:
959        requestedVideoPalette = VIDEO_PALETTE_YUYV;
960        depth = 16;
961        break;
962      default:
963        requestedVideoPalette = VIDEO_PALETTE_RGB24;
964        depth = 24;
965        break;
966      }
967      capture->imageProperties.depth = depth;
968      capture->imageProperties.palette = requestedVideoPalette;
969      if (v4l1_ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties) < 0) {
970        fprintf( stderr, "VIDEOIO ERROR: libv4l unable to ioctl VIDIOCSPICT\n\n");
971        icvCloseCAM_V4L(capture);
972        return -1;
973      }
974      if (v4l1_ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) {
975        fprintf( stderr, "VIDEOIO ERROR: libv4l unable to ioctl VIDIOCGPICT\n\n");
976        icvCloseCAM_V4L(capture);
977        return -1;
978      }
979      if (capture->imageProperties.palette != requestedVideoPalette) {
980        fprintf( stderr, "VIDEOIO ERROR: libv4l unable convert to requested pixfmt\n\n");
981        icvCloseCAM_V4L(capture);
982        return -1;
983      }
984
985   }
986
987   {
988
989     v4l1_ioctl(capture->deviceHandle, VIDIOCGMBUF, &capture->memoryBuffer);
990     capture->memoryMap  = (char *)v4l1_mmap(0,
991                                   capture->memoryBuffer.size,
992                                   PROT_READ | PROT_WRITE,
993                                   MAP_SHARED,
994                                   capture->deviceHandle,
995                                   0);
996     if (capture->memoryMap == MAP_FAILED) {
997        fprintf( stderr, "VIDEOIO ERROR: V4L: Mapping Memmory from video source error: %s\n", strerror(errno));
998        icvCloseCAM_V4L(capture);
999        return -1;
1000     }
1001
1002     /* Set up video_mmap structure pointing to this memory mapped area so each image may be
1003        retrieved from an index value */
1004     capture->mmaps = (struct video_mmap *)
1005                 (malloc(capture->memoryBuffer.frames * sizeof(struct video_mmap)));
1006     if (!capture->mmaps) {
1007        fprintf( stderr, "VIDEOIO ERROR: V4L: Could not memory map video frames.\n");
1008        icvCloseCAM_V4L(capture);
1009        return -1;
1010     }
1011
1012   }
1013
1014   /* Set up Image data */
1015   cvInitImageHeader( &capture->frame,
1016                      cvSize( capture->captureWindow.width,
1017                              capture->captureWindow.height ),
1018                      IPL_DEPTH_8U, channels_for_mode(capture->mode),
1019                      IPL_ORIGIN_TL, 4 );
1020   /* Allocate space for RGBA data */
1021   capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1022
1023   return 1;
1024}; /* End _capture_V4L */
1025
1026static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index)
1027{
1028   static int autoindex;
1029   autoindex = 0;
1030
1031   char deviceName[MAX_DEVICE_DRIVER_NAME];
1032
1033   if (!numCameras)
1034      icvInitCapture_V4L(); /* Havent called icvInitCapture yet - do it now! */
1035   if (!numCameras)
1036     return NULL; /* Are there any /dev/video input sources? */
1037
1038   //search index in indexList
1039   if ( (index>-1) && ! ((1 << index) & indexList) )
1040   {
1041     fprintf( stderr, "VIDEOIO ERROR: V4L: index %d is not correct!\n",index);
1042     return NULL; /* Did someone ask for not correct video source number? */
1043   }
1044   /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL
1045      the handles for V4L processing */
1046   CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L));
1047   if (!capture) {
1048      fprintf( stderr, "VIDEOIO ERROR: V4L: Could not allocate memory for capture process.\n");
1049      return NULL;
1050   }
1051
1052#ifdef USE_TEMP_BUFFER
1053   capture->buffers[MAX_V4L_BUFFERS].start = NULL;
1054#endif
1055
1056   /* Select camera, or rather, V4L video source */
1057   if (index<0) { // Asking for the first device available
1058     for (; autoindex<MAX_CAMERAS;autoindex++)
1059    if (indexList & (1<<autoindex))
1060        break;
1061     if (autoindex==MAX_CAMERAS)
1062    return NULL;
1063     index=autoindex;
1064     autoindex++;// i can recall icvOpenCAM_V4l with index=-1 for next camera
1065   }
1066   /* Print the CameraNumber at the end of the string with a width of one character */
1067   sprintf(deviceName, "/dev/video%1d", index);
1068
1069   /* w/o memset some parts  arent initialized - AKA: Fill it with zeros so it is clean */
1070   memset(capture,0,sizeof(CvCaptureCAM_V4L));
1071   /* Present the routines needed for V4L funtionality.  They are inserted as part of
1072      the standard set of cv calls promoting transparency.  "Vector Table" insertion. */
1073   capture->FirstCapture = 1;
1074
1075   /* set the default size */
1076   capture->width  = DEFAULT_V4L_WIDTH;
1077   capture->height = DEFAULT_V4L_HEIGHT;
1078
1079   if (_capture_V4L2 (capture, deviceName) == -1) {
1080       icvCloseCAM_V4L(capture);
1081       capture->is_v4l2_device = 0;
1082       if (_capture_V4L (capture, deviceName) == -1) {
1083           icvCloseCAM_V4L(capture);
1084           return NULL;
1085       }
1086   } else {
1087       capture->is_v4l2_device = 1;
1088   }
1089
1090   return capture;
1091}; /* End icvOpenCAM_V4L */
1092
1093#ifdef HAVE_CAMV4L2
1094
1095static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
1096    struct v4l2_buffer buf;
1097
1098    CLEAR (buf);
1099
1100    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1101    buf.memory = V4L2_MEMORY_MMAP;
1102
1103    if (-1 == xioctl (capture->deviceHandle, VIDIOC_DQBUF, &buf)) {
1104        switch (errno) {
1105        case EAGAIN:
1106            return 0;
1107
1108        case EIO:
1109            /* Could ignore EIO, see spec. */
1110
1111            /* fall through */
1112
1113        default:
1114            /* display the error and stop processing */
1115            perror ("VIDIOC_DQBUF");
1116            return 1;
1117        }
1118   }
1119
1120   assert(buf.index < capture->req.count);
1121
1122#ifdef USE_TEMP_BUFFER
1123   memcpy(capture->buffers[MAX_V4L_BUFFERS].start,
1124    capture->buffers[buf.index].start,
1125    capture->buffers[MAX_V4L_BUFFERS].length );
1126   capture->bufferIndex = MAX_V4L_BUFFERS;
1127   //printf("got data in buff %d, len=%d, flags=0x%X, seq=%d, used=%d)\n",
1128   //   buf.index, buf.length, buf.flags, buf.sequence, buf.bytesused);
1129#else
1130   capture->bufferIndex = buf.index;
1131#endif
1132
1133   if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf))
1134       perror ("VIDIOC_QBUF");
1135
1136   //set timestamp in capture struct to be timestamp of most recent frame
1137   /** where timestamps refer to the instant the field or frame was received by the driver, not the capture time*/
1138   capture->timestamp = buf.timestamp;   //printf( "timestamp update done \n");
1139   capture->sequence = buf.sequence;
1140
1141   return 1;
1142}
1143
1144static void mainloop_v4l2(CvCaptureCAM_V4L* capture) {
1145    unsigned int count;
1146
1147    count = 1;
1148
1149    while (count-- > 0) {
1150        for (;;) {
1151            fd_set fds;
1152            struct timeval tv;
1153            int r;
1154
1155            FD_ZERO (&fds);
1156            FD_SET (capture->deviceHandle, &fds);
1157
1158            /* Timeout. */
1159            tv.tv_sec = 10;
1160            tv.tv_usec = 0;
1161
1162            r = select (capture->deviceHandle+1, &fds, NULL, NULL, &tv);
1163
1164            if (-1 == r) {
1165                if (EINTR == errno)
1166                    continue;
1167
1168                perror ("select");
1169            }
1170
1171            if (0 == r) {
1172                fprintf (stderr, "select timeout\n");
1173
1174                /* end the infinite loop */
1175                break;
1176            }
1177
1178            if (read_frame_v4l2 (capture))
1179                break;
1180        }
1181    }
1182}
1183
1184static int icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) {
1185
1186   if (capture->FirstCapture) {
1187      /* Some general initialization must take place the first time through */
1188
1189      /* This is just a technicality, but all buffers must be filled up before any
1190         staggered SYNC is applied.  SO, filler up. (see V4L HowTo) */
1191
1192      if (capture->is_v4l2_device == 1)
1193      {
1194
1195        for (capture->bufferIndex = 0;
1196             capture->bufferIndex < ((int)capture->req.count);
1197             ++capture->bufferIndex)
1198        {
1199
1200          struct v4l2_buffer buf;
1201
1202          CLEAR (buf);
1203
1204          buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1205          buf.memory      = V4L2_MEMORY_MMAP;
1206          buf.index       = (unsigned long)capture->bufferIndex;
1207
1208          if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) {
1209              perror ("VIDIOC_QBUF");
1210              return 0;
1211          }
1212        }
1213
1214        /* enable the streaming */
1215        capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1216        if (-1 == xioctl (capture->deviceHandle, VIDIOC_STREAMON,
1217                          &capture->type)) {
1218            /* error enabling the stream */
1219            perror ("VIDIOC_STREAMON");
1220            return 0;
1221        }
1222      } else
1223      {
1224
1225        for (capture->bufferIndex = 0;
1226         capture->bufferIndex < (capture->memoryBuffer.frames-1);
1227         ++capture->bufferIndex) {
1228
1229          capture->mmaps[capture->bufferIndex].frame  = capture->bufferIndex;
1230          capture->mmaps[capture->bufferIndex].width  = capture->captureWindow.width;
1231          capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1232          capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1233
1234          if (v4l1_ioctl(capture->deviceHandle, VIDIOCMCAPTURE, &capture->mmaps[capture->bufferIndex]) == -1) {
1235            fprintf( stderr, "VIDEOIO ERROR: V4L: Initial Capture Error: Unable to load initial memory buffers.\n");
1236            return 0;
1237          }
1238        }
1239
1240      }
1241
1242      /* preparation is ok */
1243      capture->FirstCapture = 0;
1244   }
1245
1246   if (capture->is_v4l2_device == 1)
1247   {
1248
1249     mainloop_v4l2(capture);
1250
1251   } else
1252   {
1253
1254   capture->mmaps[capture->bufferIndex].frame  = capture->bufferIndex;
1255   capture->mmaps[capture->bufferIndex].width  = capture->captureWindow.width;
1256   capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1257   capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1258
1259   if (v4l1_ioctl (capture->deviceHandle, VIDIOCMCAPTURE,
1260           &capture->mmaps[capture->bufferIndex]) == -1) {
1261      /* capture is on the way, so just exit */
1262      return 1;
1263   }
1264
1265     ++capture->bufferIndex;
1266     if (capture->bufferIndex == capture->memoryBuffer.frames) {
1267        capture->bufferIndex = 0;
1268     }
1269
1270   }
1271
1272   return(1);
1273}
1274
1275static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int) {
1276
1277  if (capture->is_v4l2_device == 0)
1278  {
1279
1280    /* [FD] this really belongs here */
1281    if (v4l1_ioctl(capture->deviceHandle, VIDIOCSYNC, &capture->mmaps[capture->bufferIndex].frame) == -1) {
1282      fprintf( stderr, "VIDEOIO ERROR: V4L: Could not SYNC to video stream. %s\n", strerror(errno));
1283    }
1284
1285  }
1286
1287   /* Now get what has already been captured as a IplImage return */
1288
1289   /* First, reallocate imageData if the frame size changed */
1290
1291  if (capture->is_v4l2_device == 1)
1292  {
1293
1294    if(((unsigned long)capture->frame.width != capture->form.fmt.pix.width)
1295       || ((unsigned long)capture->frame.height != capture->form.fmt.pix.height)) {
1296        cvFree(&capture->frame.imageData);
1297        cvInitImageHeader( &capture->frame,
1298                           cvSize( capture->form.fmt.pix.width,
1299                                   capture->form.fmt.pix.height ),
1300                           IPL_DEPTH_8U, channels_for_mode(capture->mode),
1301                           IPL_ORIGIN_TL, 4 );
1302       capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1303    }
1304
1305  } else
1306  {
1307
1308    if((capture->frame.width != capture->mmaps[capture->bufferIndex].width)
1309      || (capture->frame.height != capture->mmaps[capture->bufferIndex].height)) {
1310       cvFree(&capture->frame.imageData);
1311       cvInitImageHeader( &capture->frame,
1312                          cvSize( capture->captureWindow.width,
1313                                  capture->captureWindow.height ),
1314                          IPL_DEPTH_8U, channels_for_mode(capture->mode),
1315                          IPL_ORIGIN_TL, 4 );
1316       capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1317    }
1318
1319  }
1320
1321  if (capture->is_v4l2_device == 1)
1322  {
1323
1324    if(capture->buffers[capture->bufferIndex].start){
1325      memcpy((char *)capture->frame.imageData,
1326         (char *)capture->buffers[capture->bufferIndex].start,
1327         capture->frame.imageSize);
1328    }
1329
1330  } else
1331#endif /* HAVE_CAMV4L2 */
1332  {
1333
1334    switch(capture->imageProperties.palette) {
1335      case VIDEO_PALETTE_RGB24:
1336      case VIDEO_PALETTE_YUV420:
1337      case VIDEO_PALETTE_YUYV:
1338        memcpy((char *)capture->frame.imageData,
1339           (char *)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
1340           capture->frame.imageSize);
1341        break;
1342      default:
1343        fprintf( stderr,
1344                 "VIDEOIO ERROR: V4L: Cannot convert from palette %d to mode %d\n",
1345                 capture->imageProperties.palette,
1346                 capture->mode);
1347        return 0;
1348    }
1349
1350  }
1351
1352   return(&capture->frame);
1353}
1354
1355/* TODO: review this adaptation */
1356static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture,
1357                                     int property_id ) {
1358  char name[32];
1359  int is_v4l2_device = 0;
1360      /* initialize the control structure */
1361  switch (property_id) {
1362    case CV_CAP_PROP_FRAME_WIDTH:
1363    case CV_CAP_PROP_FRAME_HEIGHT:
1364      CLEAR (capture->form);
1365      capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1366      if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
1367          /* display an error message, and return an error code */
1368          perror ("VIDIOC_G_FMT");
1369        if (v4l1_ioctl (capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
1370          fprintf (stderr, " ERROR: V4L: Unable to determine size of incoming image\n");
1371          icvCloseCAM_V4L(capture);
1372          return -1;
1373        } else {
1374          int retval = (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->captureWindow.width:capture->captureWindow.height;
1375          return retval / 0xFFFF;
1376        }
1377      }
1378      return (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->form.fmt.pix.width:capture->form.fmt.pix.height;
1379
1380    case CV_CAP_PROP_POS_MSEC:
1381        if (capture->FirstCapture) {
1382            return 0;
1383        } else {
1384            //would be maximally numerically stable to cast to convert as bits, but would also be counterintuitive to decode
1385            return 1000 * capture->timestamp.tv_sec + ((double) capture->timestamp.tv_usec) / 1000;
1386        }
1387        break;
1388
1389    case CV_CAP_PROP_POS_FRAMES:
1390        return capture->sequence;
1391        break;
1392
1393    case CV_CAP_PROP_FPS: {
1394        struct v4l2_streamparm sp;
1395        memset (&sp, 0, sizeof(struct v4l2_streamparm));
1396        sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1397        if (xioctl (capture->deviceHandle, VIDIOC_G_PARM, &sp) < 0){
1398            fprintf(stderr, "VIDEOIO ERROR: V4L: Unable to get camera FPS\n");
1399            return (double) -1;
1400        }
1401
1402        // this is the captureable, not per say what you'll get..
1403        double framesPerSec = sp.parm.capture.timeperframe.denominator / (double)  sp.parm.capture.timeperframe.numerator ;
1404        return framesPerSec;
1405    }
1406    break;
1407
1408
1409    case CV_CAP_PROP_MODE:
1410      return capture->mode;
1411      break;
1412    case CV_CAP_PROP_BRIGHTNESS:
1413      sprintf(name, "Brightness");
1414      capture->control.id = V4L2_CID_BRIGHTNESS;
1415      break;
1416    case CV_CAP_PROP_CONTRAST:
1417      sprintf(name, "Contrast");
1418      capture->control.id = V4L2_CID_CONTRAST;
1419      break;
1420    case CV_CAP_PROP_SATURATION:
1421      sprintf(name, "Saturation");
1422      capture->control.id = V4L2_CID_SATURATION;
1423      break;
1424    case CV_CAP_PROP_HUE:
1425      sprintf(name, "Hue");
1426      capture->control.id = V4L2_CID_HUE;
1427      break;
1428    case CV_CAP_PROP_GAIN:
1429      sprintf(name, "Gain");
1430      capture->control.id = V4L2_CID_GAIN;
1431      break;
1432    case CV_CAP_PROP_EXPOSURE:
1433      sprintf(name, "Exposure");
1434      capture->control.id = V4L2_CID_EXPOSURE;
1435      break;
1436    default:
1437      sprintf(name, "<unknown property string>");
1438      capture->control.id = property_id;
1439  }
1440
1441  if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &capture->control) == 0) {
1442    /* all went well */
1443    is_v4l2_device = 1;
1444  } else {
1445    fprintf(stderr, "VIDEOIO ERROR: V4L2: Unable to get property %s(%u) - %s\n", name, capture->control.id, strerror(errno));
1446  }
1447
1448  if (is_v4l2_device == 1) {
1449      /* get the min/max values */
1450      int v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
1451      int v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);
1452
1453      if ((v4l2_min == -1) && (v4l2_max == -1)) {
1454        fprintf(stderr, "VIDEOIO ERROR: V4L2: Property %s(%u) not supported by device\n", name, property_id);
1455        return -1;
1456      }
1457
1458      /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
1459      return ((float)capture->control.value - v4l2_min) / (v4l2_max - v4l2_min);
1460
1461  } else {
1462    /* TODO: review this section */
1463    int retval = -1;
1464
1465    switch (property_id) {
1466      case CV_CAP_PROP_BRIGHTNESS:
1467        retval = capture->imageProperties.brightness;
1468        break;
1469      case CV_CAP_PROP_CONTRAST:
1470        retval = capture->imageProperties.contrast;
1471        break;
1472      case CV_CAP_PROP_SATURATION:
1473        retval = capture->imageProperties.colour;
1474        break;
1475      case CV_CAP_PROP_HUE:
1476        retval = capture->imageProperties.hue;
1477        break;
1478      case CV_CAP_PROP_GAIN:
1479        fprintf(stderr, "VIDEOIO ERROR: V4L: Gain control in V4L is not supported\n");
1480        return -1;
1481        break;
1482      case CV_CAP_PROP_EXPOSURE:
1483        fprintf(stderr, "VIDEOIO ERROR: V4L: Exposure control in V4L is not supported\n");
1484        return -1;
1485        break;
1486    }
1487
1488    if (retval == -1) {
1489      /* there was a problem */
1490      return -1;
1491    }
1492    /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
1493    return float (retval) / 0xFFFF;
1494  }
1495}
1496
1497static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h) {
1498
1499  if (capture->is_v4l2_device == 1)
1500  {
1501    char deviceName[MAX_DEVICE_DRIVER_NAME];
1502    sprintf(deviceName, "%s", capture->deviceName);
1503    icvCloseCAM_V4L(capture);
1504    _capture_V4L2(capture, deviceName);
1505
1506    int cropHeight;
1507    int cropWidth;
1508    switch (capture->mode) {
1509    case CV_CAP_MODE_GRAY:
1510      cropHeight = h*8;
1511      cropWidth = w*8;
1512      break;
1513    case CV_CAP_MODE_YUYV:
1514      cropHeight = h*16;
1515      cropWidth = w*16;
1516      break;
1517    default:
1518      cropHeight = h*24;
1519      cropWidth = w*24;
1520      break;
1521    }
1522    CLEAR (capture->crop);
1523    capture->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1524    capture->crop.c.left       = 0;
1525    capture->crop.c.top        = 0;
1526    capture->crop.c.height     = cropHeight;
1527    capture->crop.c.width      = cropWidth;
1528
1529    /* set the crop area, but don't exit if the device don't support croping */
1530    xioctl (capture->deviceHandle, VIDIOC_S_CROP, &capture->crop);
1531
1532    CLEAR (capture->form);
1533    capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1534
1535    /* read the current setting, mainly to retreive the pixelformat information */
1536    xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form);
1537
1538    /* set the values we want to change */
1539    capture->form.fmt.pix.width = w;
1540    capture->form.fmt.pix.height = h;
1541    capture->form.fmt.win.chromakey = 0;
1542    capture->form.fmt.win.field = V4L2_FIELD_ANY;
1543    capture->form.fmt.win.clips = 0;
1544    capture->form.fmt.win.clipcount = 0;
1545    capture->form.fmt.pix.field = V4L2_FIELD_ANY;
1546
1547    /* ask the device to change the size
1548     * don't test if the set of the size is ok, because some device
1549     * don't allow changing the size, and we will get the real size
1550     * later */
1551    xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form);
1552
1553    /* try to set framerate to 30 fps */
1554
1555    struct v4l2_streamparm setfps;
1556    memset (&setfps, 0, sizeof(struct v4l2_streamparm));
1557
1558    setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1559    setfps.parm.capture.timeperframe.numerator = 1;
1560    setfps.parm.capture.timeperframe.denominator = 30;
1561
1562    xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps);
1563
1564
1565    /* we need to re-initialize some things, like buffers, because the size has
1566     * changed */
1567    capture->FirstCapture = 1;
1568
1569    /* Get window info again, to get the real value */
1570    if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form))
1571    {
1572      fprintf(stderr, "VIDEOIO ERROR: V4L/V4L2: Could not obtain specifics of capture window.\n\n");
1573
1574      icvCloseCAM_V4L(capture);
1575
1576      return 0;
1577    }
1578
1579    return 0;
1580
1581  } else
1582  {
1583
1584    if (capture==0) return 0;
1585     if (w>capture->capability.maxwidth) {
1586       w=capture->capability.maxwidth;
1587     }
1588     if (h>capture->capability.maxheight) {
1589       h=capture->capability.maxheight;
1590     }
1591
1592     capture->captureWindow.width=w;
1593     capture->captureWindow.height=h;
1594
1595     if (ioctl(capture->deviceHandle, VIDIOCSWIN, &capture->captureWindow) < 0) {
1596       icvCloseCAM_V4L(capture);
1597       return 0;
1598     }
1599
1600     if (ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
1601       icvCloseCAM_V4L(capture);
1602       return 0;
1603     }
1604
1605     capture->FirstCapture = 1;
1606
1607  }
1608
1609  return 0;
1610
1611}
1612
1613static int icvSetControl (CvCaptureCAM_V4L* capture, int property_id, double value) {
1614  struct v4l2_control c;
1615  __s32 ctrl_value;
1616  char name[32];
1617  int is_v4l2  = 1;
1618  int v4l2_min = 0;
1619  int v4l2_max = 255;
1620  if (capture->v4l2_ctrl_ranges == NULL) {
1621    v4l2_scan_controls(capture);
1622  }
1623
1624  CLEAR (capture->control);
1625  CLEAR (capture->queryctrl);
1626
1627  /* get current values */
1628  switch (property_id) {
1629    case CV_CAP_PROP_BRIGHTNESS:
1630      sprintf(name, "Brightness");
1631      capture->control.id = V4L2_CID_BRIGHTNESS;
1632      break;
1633    case CV_CAP_PROP_CONTRAST:
1634      sprintf(name, "Contrast");
1635      capture->control.id = V4L2_CID_CONTRAST;
1636      break;
1637    case CV_CAP_PROP_SATURATION:
1638      sprintf(name, "Saturation");
1639      capture->control.id = V4L2_CID_SATURATION;
1640      break;
1641    case CV_CAP_PROP_HUE:
1642      sprintf(name, "Hue");
1643      capture->control.id = V4L2_CID_HUE;
1644      break;
1645    case CV_CAP_PROP_GAIN:
1646      sprintf(name, "Gain");
1647      capture->control.id = V4L2_CID_GAIN;
1648      break;
1649    case CV_CAP_PROP_EXPOSURE:
1650      sprintf(name, "Exposure");
1651      capture->control.id = V4L2_CID_EXPOSURE;
1652      break;
1653    default:
1654      sprintf(name, "<unknown property string>");
1655      capture->control.id = property_id;
1656  }
1657
1658  v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
1659  v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);
1660
1661  if ((v4l2_min == -1) && (v4l2_max == -1)) {
1662    fprintf(stderr, "VIDEOIO ERROR: V4L: Property %s(%u) not supported by device\n", name, property_id);
1663    return -1;
1664  }
1665
1666  if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &capture->control) == 0) {
1667    /* all went well */
1668  } else {
1669    fprintf(stderr, "VIDEOIO ERROR: V4L2: Unable to get property %s(%u) - %s\n", name, capture->control.id, strerror(errno));
1670  }
1671
1672  if (v4l2_max != 0) {
1673    double val = value;
1674    if (value < 0.0) {
1675      val = 0.0;
1676    } else if (value > 1.0) {
1677      val = 1.0;
1678    }
1679    ctrl_value = val * (double)(v4l2_max - v4l2_min) + v4l2_min;
1680  } else {
1681    ctrl_value = v4l2_get_ctrl_default(capture, capture->control.id) * (double)(v4l2_max - v4l2_min) + v4l2_min;
1682  }
1683
1684  /* try and set value as if it was a v4l2 device */
1685  c.id    = capture->control.id;
1686  c.value = ctrl_value;
1687  if (v4l2_ioctl(capture->deviceHandle, VIDIOC_S_CTRL, &c) != 0) {
1688    /* The driver may clamp the value or return ERANGE, ignored here */
1689    if (errno != ERANGE) {
1690      fprintf(stderr, "VIDEOIO ERROR: V4L2: Failed to set control \"%d\": %s (value %d)\n", c.id, strerror(errno), c.value);
1691      is_v4l2 = 0;
1692    } else {
1693      return 0;
1694    }
1695  } else {
1696    return 0;
1697  }
1698
1699  if (is_v4l2 == 0) { /* use v4l1_ioctl */
1700    fprintf(stderr, "VIDEOIO WARNING: Setting property %u through v4l2 failed. Trying with v4l1.\n", c.id);
1701    int v4l_value;
1702    /* scale the value to the wanted integer one */
1703    v4l_value = (int)(0xFFFF * value);
1704
1705    switch (property_id) {
1706      case CV_CAP_PROP_BRIGHTNESS:
1707        capture->imageProperties.brightness = v4l_value;
1708        break;
1709      case CV_CAP_PROP_CONTRAST:
1710        capture->imageProperties.contrast = v4l_value;
1711        break;
1712      case CV_CAP_PROP_SATURATION:
1713        capture->imageProperties.colour = v4l_value;
1714        break;
1715      case CV_CAP_PROP_HUE:
1716        capture->imageProperties.hue = v4l_value;
1717        break;
1718      case CV_CAP_PROP_GAIN:
1719          fprintf(stderr, "VIDEOIO ERROR: V4L: Gain control in V4L is not supported\n");
1720        return -1;
1721    case CV_CAP_PROP_EXPOSURE:
1722        fprintf(stderr, "VIDEOIO ERROR: V4L: Exposure control in V4L is not supported\n");
1723        return -1;
1724    default:
1725        fprintf(stderr, "VIDEOIO ERROR: V4L: property #%d is not supported\n", property_id);
1726        return -1;
1727    }
1728
1729    if (v4l1_ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties) < 0){
1730      fprintf(stderr, "VIDEOIO ERROR: V4L: Unable to set video informations\n");
1731      icvCloseCAM_V4L(capture);
1732      return -1;
1733    }
1734  }
1735
1736  /* all was OK */
1737  return 0;
1738}
1739
1740static int icvSetPropertyCAM_V4L(CvCaptureCAM_V4L* capture, int property_id, double value){
1741    static int width = 0, height = 0;
1742    int retval;
1743
1744    /* initialization */
1745    retval = 0;
1746
1747    /* two subsequent calls setting WIDTH and HEIGHT will change
1748       the video size */
1749    /* the first one will return an error, though. */
1750
1751    switch (property_id) {
1752    case CV_CAP_PROP_FRAME_WIDTH:
1753        width = cvRound(value);
1754        capture->width = width;
1755        if(width !=0 && height != 0) {
1756            retval = icvSetVideoSize( capture, width, height);
1757            width = height = 0;
1758        }
1759        break;
1760    case CV_CAP_PROP_FRAME_HEIGHT:
1761        height = cvRound(value);
1762        capture->height = height;
1763        if(width !=0 && height != 0) {
1764            retval = icvSetVideoSize( capture, width, height);
1765            width = height = 0;
1766        }
1767        break;
1768    case CV_CAP_PROP_MODE:
1769        int mode;
1770        mode = cvRound(value);
1771        if (capture->mode != mode) {
1772            switch (mode) {
1773            case CV_CAP_MODE_BGR:
1774            case CV_CAP_MODE_RGB:
1775            case CV_CAP_MODE_GRAY:
1776            case CV_CAP_MODE_YUYV:
1777                capture->mode = mode;
1778                /* recreate the capture buffer for the same output resolution
1779                   but a different pixel format */
1780                retval = icvSetVideoSize(capture, capture->width, capture->height);
1781                break;
1782            default:
1783                fprintf(stderr, "VIDEOIO ERROR: V4L/V4L2: Unsupported mode: %d\n", mode);
1784                retval=0;
1785                break;
1786            }
1787        }
1788        break;
1789    case CV_CAP_PROP_FPS:
1790        struct v4l2_streamparm setfps;
1791        memset (&setfps, 0, sizeof(struct v4l2_streamparm));
1792        setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1793        setfps.parm.capture.timeperframe.numerator = 1;
1794        setfps.parm.capture.timeperframe.denominator = value;
1795        if (xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps) < 0){
1796            fprintf(stderr, "VIDEOIO ERROR: V4L: Unable to set camera FPS\n");
1797            retval=0;
1798        }
1799        break;
1800    default:
1801        retval = icvSetControl(capture, property_id, value);
1802    }
1803
1804    /* return the the status */
1805    return retval;
1806}
1807
1808static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ){
1809   /* Deallocate space - Hopefully, no leaks */
1810   if (capture) {
1811     v4l2_free_ranges(capture);
1812     if (capture->is_v4l2_device == 0) {
1813       if (capture->mmaps) {
1814         free(capture->mmaps);
1815       }
1816       if (capture->memoryMap) {
1817         v4l1_munmap(capture->memoryMap, capture->memoryBuffer.size);
1818       }
1819       if (capture->deviceHandle != -1) {
1820         v4l1_close(capture->deviceHandle);
1821       }
1822     } else {
1823       capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1824       if (xioctl(capture->deviceHandle, VIDIOC_STREAMOFF, &capture->type) < 0) {
1825         perror ("Unable to stop the stream.");
1826       }
1827       for (unsigned int n_buffers2 = 0; n_buffers2 < capture->req.count; ++n_buffers2) {
1828         if (-1 == v4l2_munmap (capture->buffers[n_buffers2].start, capture->buffers[n_buffers2].length)) {
1829           perror ("munmap");
1830         }
1831       }
1832
1833       if (capture->deviceHandle != -1) {
1834         v4l2_close(capture->deviceHandle);
1835       }
1836     }
1837
1838     if (capture->frame.imageData)
1839       cvFree(&capture->frame.imageData);
1840
1841#ifdef USE_TEMP_BUFFER
1842     if (capture->buffers[MAX_V4L_BUFFERS].start) {
1843       free(capture->buffers[MAX_V4L_BUFFERS].start);
1844       capture->buffers[MAX_V4L_BUFFERS].start = NULL;
1845     }
1846#endif
1847
1848     free(capture->deviceName);
1849     capture->deviceName = NULL;
1850     //v4l2_free_ranges(capture);
1851     //cvFree((void **)capture);
1852   }
1853};
1854
1855
1856class CvCaptureCAM_V4L_CPP : CvCapture
1857{
1858public:
1859    CvCaptureCAM_V4L_CPP() { captureV4L = 0; }
1860    virtual ~CvCaptureCAM_V4L_CPP() { close(); }
1861
1862    virtual bool open( int index );
1863    virtual void close();
1864
1865    virtual double getProperty(int) const;
1866    virtual bool setProperty(int, double);
1867    virtual bool grabFrame();
1868    virtual IplImage* retrieveFrame(int);
1869protected:
1870
1871    CvCaptureCAM_V4L* captureV4L;
1872};
1873
1874bool CvCaptureCAM_V4L_CPP::open( int index )
1875{
1876    close();
1877    captureV4L = icvCaptureFromCAM_V4L(index);
1878    return captureV4L != 0;
1879}
1880
1881void CvCaptureCAM_V4L_CPP::close()
1882{
1883    if( captureV4L )
1884    {
1885        icvCloseCAM_V4L( captureV4L );
1886        cvFree( &captureV4L );
1887    }
1888}
1889
1890bool CvCaptureCAM_V4L_CPP::grabFrame()
1891{
1892    return captureV4L ? icvGrabFrameCAM_V4L( captureV4L ) != 0 : false;
1893}
1894
1895IplImage* CvCaptureCAM_V4L_CPP::retrieveFrame(int)
1896{
1897    return captureV4L ? icvRetrieveFrameCAM_V4L( captureV4L, 0 ) : 0;
1898}
1899
1900double CvCaptureCAM_V4L_CPP::getProperty( int propId ) const
1901{
1902    return captureV4L ? icvGetPropertyCAM_V4L( captureV4L, propId ) : 0.0;
1903}
1904
1905bool CvCaptureCAM_V4L_CPP::setProperty( int propId, double value )
1906{
1907    return captureV4L ? icvSetPropertyCAM_V4L( captureV4L, propId, value ) != 0 : false;
1908}
1909
1910CvCapture* cvCreateCameraCapture_V4L( int index )
1911{
1912    CvCaptureCAM_V4L_CPP* capture = new CvCaptureCAM_V4L_CPP;
1913
1914    if( capture->open( index ))
1915        return (CvCapture*)capture;
1916
1917    delete capture;
1918    return 0;
1919}
1920
1921#endif
1922