1 /* This is the contributed code:
2 
3 File:             cvcap_v4l.cpp
4 Current Location: ../opencv-0.9.6/otherlibs/videoio
5 
6 Original Version: 2003-03-12  Magnus Lundin lundin@mlu.mine.nu
7 Original Comments:
8 
9 ML:This set of files adds support for firevre and usb cameras.
10 First it tries to install a firewire camera,
11 if that fails it tries a v4l/USB camera
12 It has been tested with the motempl sample program
13 
14 First Patch:  August 24, 2004 Travis Wood   TravisOCV@tkwood.com
15 For Release:  OpenCV-Linux Beta4  opencv-0.9.6
16 Tested On:    LMLBT44 with 8 video inputs
17 Problems?     Post your questions at answers.opencv.org,
18               Report bugs at code.opencv.org,
19               Submit your fixes at https://github.com/Itseez/opencv/
20 Patched Comments:
21 
22 TW: The cv cam utils that came with the initial release of OpenCV for LINUX Beta4
23 were not working.  I have rewritten them so they work for me. At the same time, trying
24 to keep the original code as ML wrote it as unchanged as possible.  No one likes to debug
25 someone elses code, so I resisted changes as much as possible.  I have tried to keep the
26 same "ideas" where applicable, that is, where I could figure out what the previous author
27 intended. Some areas I just could not help myself and had to "spiffy-it-up" my way.
28 
29 These drivers should work with other V4L frame capture cards other then my bttv
30 driven frame capture card.
31 
32 Re Written driver for standard V4L mode. Tested using LMLBT44 video capture card.
33 Standard bttv drivers are on the LMLBT44 with up to 8 Inputs.
34 
35 This utility was written with the help of the document:
36 http://pages.cpsc.ucalgary.ca/~sayles/VFL_HowTo
37 as a general guide for interfacing into the V4l standard.
38 
39 Made the index value passed for icvOpenCAM_V4L(index) be the number of the
40 video device source in the /dev tree. The -1 uses original /dev/video.
41 
42 Index  Device
43   0    /dev/video0
44   1    /dev/video1
45   2    /dev/video2
46   3    /dev/video3
47   ...
48   7    /dev/video7
49 with
50   -1   /dev/video
51 
52 TW: You can select any video source, but this package was limited from the start to only
53 ONE camera opened at any ONE time.
54 This is an original program limitation.
55 If you are interested, I will make my version available to other OpenCV users.  The big
56 difference in mine is you may pass the camera number as part of the cv argument, but this
57 convention is non standard for current OpenCV calls and the camera number is not currently
58 passed into the called routine.
59 
60 Second Patch:   August 28, 2004 Sfuncia Fabio fiblan@yahoo.it
61 For Release:  OpenCV-Linux Beta4 Opencv-0.9.6
62 
63 FS: 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 
68 Third Patch:   December 9, 2004 Frederic Devernay Frederic.Devernay@inria.fr
69 For 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 
90 Fourth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu
91 For Release:  OpenCV-Linux Beta5 OpenCV-0.9.7
92 
93 I 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 
109 Fifth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu
110 For Release:  OpenCV-Linux Beta5 OpenCV-0.9.7
111 
112 I 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 
118 Sixth Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu
119 For Release:  OpenCV-Linux Beta5 OpenCV-0.9.7
120 
121 I 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 
128 Seventh Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu
129 For Release:  OpenCV-Linux Beta5 OpenCV-0.9.7
130 
131 I 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 
137 8th patch: Jan 5, 2006, Olivier.Bornet@idiap.ch
138 Add support of V4L2_PIX_FMT_YUYV and V4L2_PIX_FMT_MJPEG.
139 With this patch, new webcams of Logitech, like QuickCam Fusion works.
140 Note: For use these webcams, look at the UVC driver at
141 http://linux-uvc.berlios.de/
142 
143 9th 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 
151 10th patch: July 02, 2008, Mikhail Afanasyev fopencv@theamk.com
152 Fix reliability problems with high-resolution UVC cameras on linux
153 the 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 
159 11th 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 
163 12th 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 
171 13th 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)
173 make & enjoy!
174 
175 14th 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 
181 15th patch: May 12, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
182 - Broken compile of library (include "_videoio.h")
183 
184 16th 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 
194 17th 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 */
289 struct buffer
290 {
291   void *  start;
292   size_t  length;
293 };
294 static 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 */
300 typedef 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 
309 typedef 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 }
351 CvCaptureCAM_V4L;
352 
353 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture );
354 
355 static int icvGrabFrameCAM_V4L( CvCaptureCAM_V4L* capture );
356 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int );
357 CvCapture* cvCreateCameraCapture_V4L( int index );
358 
359 static double icvGetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id );
360 static int    icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id, double value );
361 
362 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h);
363 
364 /***********************   Implementations  ***************************************/
365 
366 static int numCameras = 0;
367 static int indexList = 0;
368 
369 // IOCTL handling for V4L2
370 #ifdef HAVE_IOCTL_ULONG
xioctl(int fd,unsigned long request,void * arg)371 static int xioctl( int fd, unsigned long request, void *arg)
372 #else
373 static 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 
icvInitCapture_V4L()393 static 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 
try_init_v4l(CvCaptureCAM_V4L * capture,char * deviceName)419 static 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 
try_init_v4l2(CvCaptureCAM_V4L * capture,char * deviceName)463 static 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 
v4l2_free_ranges(CvCaptureCAM_V4L * capture)513 static 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 
v4l2_add_ctrl_range(CvCaptureCAM_V4L * capture,v4l2_control * ctrl)531 static 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 
v4l2_get_ctrl_default(CvCaptureCAM_V4L * capture,__u32 id)544 static 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 
v4l2_get_ctrl_min(CvCaptureCAM_V4L * capture,__u32 id)554 static 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 
v4l2_get_ctrl_max(CvCaptureCAM_V4L * capture,__u32 id)564 static 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 
v4l2_scan_controls(CvCaptureCAM_V4L * capture)575 static 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 
channels_for_mode(int mode)653 static 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 
_capture_V4L2(CvCaptureCAM_V4L * capture,char * deviceName)665 static 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 
_capture_V4L(CvCaptureCAM_V4L * capture,char * deviceName)873 static 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 
icvCaptureFromCAM_V4L(int index)1026 static 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 
read_frame_v4l2(CvCaptureCAM_V4L * capture)1095 static 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 
mainloop_v4l2(CvCaptureCAM_V4L * capture)1144 static 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 
icvGrabFrameCAM_V4L(CvCaptureCAM_V4L * capture)1184 static 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 
icvRetrieveFrameCAM_V4L(CvCaptureCAM_V4L * capture,int)1275 static 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 */
icvGetPropertyCAM_V4L(CvCaptureCAM_V4L * capture,int property_id)1356 static 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 
icvSetVideoSize(CvCaptureCAM_V4L * capture,int w,int h)1497 static 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 
icvSetControl(CvCaptureCAM_V4L * capture,int property_id,double value)1613 static 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 
icvSetPropertyCAM_V4L(CvCaptureCAM_V4L * capture,int property_id,double value)1740 static 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 
icvCloseCAM_V4L(CvCaptureCAM_V4L * capture)1808 static 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 
1856 class CvCaptureCAM_V4L_CPP : CvCapture
1857 {
1858 public:
CvCaptureCAM_V4L_CPP()1859     CvCaptureCAM_V4L_CPP() { captureV4L = 0; }
~CvCaptureCAM_V4L_CPP()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);
1869 protected:
1870 
1871     CvCaptureCAM_V4L* captureV4L;
1872 };
1873 
open(int index)1874 bool CvCaptureCAM_V4L_CPP::open( int index )
1875 {
1876     close();
1877     captureV4L = icvCaptureFromCAM_V4L(index);
1878     return captureV4L != 0;
1879 }
1880 
close()1881 void CvCaptureCAM_V4L_CPP::close()
1882 {
1883     if( captureV4L )
1884     {
1885         icvCloseCAM_V4L( captureV4L );
1886         cvFree( &captureV4L );
1887     }
1888 }
1889 
grabFrame()1890 bool CvCaptureCAM_V4L_CPP::grabFrame()
1891 {
1892     return captureV4L ? icvGrabFrameCAM_V4L( captureV4L ) != 0 : false;
1893 }
1894 
retrieveFrame(int)1895 IplImage* CvCaptureCAM_V4L_CPP::retrieveFrame(int)
1896 {
1897     return captureV4L ? icvRetrieveFrameCAM_V4L( captureV4L, 0 ) : 0;
1898 }
1899 
getProperty(int propId) const1900 double CvCaptureCAM_V4L_CPP::getProperty( int propId ) const
1901 {
1902     return captureV4L ? icvGetPropertyCAM_V4L( captureV4L, propId ) : 0.0;
1903 }
1904 
setProperty(int propId,double value)1905 bool CvCaptureCAM_V4L_CPP::setProperty( int propId, double value )
1906 {
1907     return captureV4L ? icvSetPropertyCAM_V4L( captureV4L, propId, value ) != 0 : false;
1908 }
1909 
cvCreateCameraCapture_V4L(int index)1910 CvCapture* 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