Merge pull request #1263 from abidrahmank:pyCLAHE_24
[profile/ivi/opencv.git] / modules / highgui / src / cap_libv4l.cpp
1 /* This is the contributed code:
2
3 File:             cvcap_v4l.cpp
4 Current Location: ../opencv-0.9.6/otherlibs/highgui
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 highgui 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 succesful 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 succesful 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 succesful 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 succesful 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 seting 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 seting 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 "_highgui.h")
183 */
184
185 /*M///////////////////////////////////////////////////////////////////////////////////////
186 //
187 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
188 //
189 //  By downloading, copying, installing or using the software you agree to this license.
190 //  If you do not agree to this license, do not download, install,
191 //  copy or use the software.
192 //
193 //
194 //                        Intel License Agreement
195 //                For Open Source Computer Vision Library
196 //
197 // Copyright (C) 2000, Intel Corporation, all rights reserved.
198 // Third party copyrights are property of their respective owners.
199 //
200 // Redistribution and use in source and binary forms, with or without modification,
201 // are permitted provided that the following conditions are met:
202 //
203 //   * Redistribution's of source code must retain the above copyright notice,
204 //     this list of conditions and the following disclaimer.
205 //
206 //   * Redistribution's in binary form must reproduce the above copyright notice,
207 //     this list of conditions and the following disclaimer in the documentation
208 //     and/or other materials provided with the distribution.
209 //
210 //   * The name of Intel Corporation may not be used to endorse or promote products
211 //     derived from this software without specific prior written permission.
212 //
213 // This software is provided by the copyright holders and contributors "as is" and
214 // any express or implied warranties, including, but not limited to, the implied
215 // warranties of merchantability and fitness for a particular purpose are disclaimed.
216 // In no event shall the Intel Corporation or contributors be liable for any direct,
217 // indirect, incidental, special, exemplary, or consequential damages
218 // (including, but not limited to, procurement of substitute goods or services;
219 // loss of use, data, or profits; or business interruption) however caused
220 // and on any theory of liability, whether in contract, strict liability,
221 // or tort (including negligence or otherwise) arising in any way out of
222 // the use of this software, even if advised of the possibility of such damage.
223 //
224 //M*/
225
226 #include "precomp.hpp"
227
228 #if !defined WIN32 && defined HAVE_LIBV4L
229
230 #define CLEAR(x) memset (&(x), 0, sizeof (x))
231
232 #include <stdio.h>
233 #include <unistd.h>
234 #include <fcntl.h>
235 #include <errno.h>
236 #include <sys/types.h>
237 #include <sys/mman.h>
238 #include <string.h>
239 #include <stdlib.h>
240 #include <asm/types.h>          /* for videodev2.h */
241 #include <assert.h>
242 #include <sys/stat.h>
243 #include <sys/ioctl.h>
244
245 #ifdef HAVE_CAMV4L
246 #include <linux/videodev.h>
247 #endif
248 #ifdef HAVE_CAMV4L2
249 #include <linux/videodev2.h>
250 #endif
251
252 #include <libv4l1.h>
253 #include <libv4l2.h>
254
255 /* Defaults - If your board can do better, set it here.  Set for the most common type inputs. */
256 #define DEFAULT_V4L_WIDTH  640
257 #define DEFAULT_V4L_HEIGHT 480
258
259 #define CHANNEL_NUMBER 1
260 #define MAX_CAMERAS 8
261
262
263 // default and maximum number of V4L buffers, not including last, 'special' buffer
264 #define MAX_V4L_BUFFERS 10
265 #define DEFAULT_V4L_BUFFERS 4
266
267 // if enabled, copies data from the buffer. this uses a bit more memory,
268 //  but much more reliable for some UVC cameras
269 #define USE_TEMP_BUFFER
270
271 #define MAX_DEVICE_DRIVER_NAME 80
272
273 /* Device Capture Objects */
274 /* V4L2 structure */
275 struct buffer
276 {
277   void *  start;
278   size_t  length;
279 };
280 static unsigned int n_buffers = 0;
281
282 /* TODO: Dilemas: */
283 /* TODO: Consider drop the use of this data structure and perform ioctl to obtain needed values */
284 /* TODO: Consider at program exit return controls to the initial values - See v4l2_free_ranges function */
285 /* TODO: Consider at program exit reset the device to default values - See v4l2_free_ranges function */
286 typedef struct v4l2_ctrl_range {
287   __u32 ctrl_id;
288   __s32 initial_value;
289   __s32 current_value;
290   __s32 minimum;
291   __s32 maximum;
292   __s32 default_value;
293 } v4l2_ctrl_range;
294
295 typedef struct CvCaptureCAM_V4L
296 {
297     char* deviceName;
298     int deviceHandle;
299     int bufferIndex;
300     int FirstCapture;
301
302     int width; int height;
303
304     struct video_capability capability;
305     struct video_window     captureWindow;
306     struct video_picture    imageProperties;
307     struct video_mbuf       memoryBuffer;
308     struct video_mmap       *mmaps;
309     char *memoryMap;
310     IplImage frame;
311
312    /* V4L2 variables */
313    buffer buffers[MAX_V4L_BUFFERS + 1];
314    struct v4l2_capability cap;
315    struct v4l2_input inp;
316    struct v4l2_format form;
317    struct v4l2_crop crop;
318    struct v4l2_cropcap cropcap;
319    struct v4l2_requestbuffers req;
320    struct v4l2_jpegcompression compr;
321    struct v4l2_control control;
322    enum v4l2_buf_type type;
323    struct v4l2_queryctrl queryctrl;
324    struct v4l2_querymenu querymenu;
325
326    /* V4L2 control variables */
327    v4l2_ctrl_range** v4l2_ctrl_ranges;
328    int v4l2_ctrl_count;
329
330    int is_v4l2_device;
331 }
332 CvCaptureCAM_V4L;
333
334 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture );
335
336 static int icvGrabFrameCAM_V4L( CvCaptureCAM_V4L* capture );
337 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int );
338 CvCapture* cvCreateCameraCapture_V4L( int index );
339
340 static double icvGetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id );
341 static int    icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id, double value );
342
343 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h);
344
345 /***********************   Implementations  ***************************************/
346
347 static int numCameras = 0;
348 static int indexList = 0;
349
350 // IOCTL handling for V4L2
351 #ifdef HAVE_IOCTL_ULONG
352 static int xioctl( int fd, unsigned long request, void *arg)
353 #else
354 static int xioctl( int fd, int request, void *arg)
355 #endif
356 {
357
358   int r;
359
360
361   do r = v4l2_ioctl (fd, request, arg);
362   while (-1 == r && EINTR == errno);
363
364   return r;
365
366 }
367
368
369 /* Simple test program: Find number of Video Sources available.
370    Start from 0 and go to MAX_CAMERAS while checking for the device with that name.
371    If it fails on the first attempt of /dev/video0, then check if /dev/video is valid.
372    Returns the global numCameras with the correct value (we hope) */
373
374 static void icvInitCapture_V4L() {
375    int deviceHandle;
376    int CameraNumber;
377    char deviceName[MAX_DEVICE_DRIVER_NAME];
378
379    CameraNumber = 0;
380    while(CameraNumber < MAX_CAMERAS) {
381       /* Print the CameraNumber at the end of the string with a width of one character */
382       sprintf(deviceName, "/dev/video%1d", CameraNumber);
383       /* Test using an open to see if this new device name really does exists. */
384       deviceHandle = open(deviceName, O_RDONLY);
385       if (deviceHandle != -1) {
386          /* This device does indeed exist - add it to the total so far */
387     // add indexList
388     indexList|=(1 << CameraNumber);
389         numCameras++;
390     }
391     if (deviceHandle != -1)
392       close(deviceHandle);
393       /* Set up to test the next /dev/video source in line */
394       CameraNumber++;
395    } /* End while */
396
397 }; /* End icvInitCapture_V4L */
398
399
400 static int try_init_v4l(CvCaptureCAM_V4L* capture, char *deviceName)
401
402 {
403
404   // if detect = -1 then unable to open device
405   // if detect = 0 then detected nothing
406   // if detect = 1 then V4L device
407   int detect = 0;
408
409
410   // Test device for V4L compability
411
412   /* Test using an open to see if this new device name really does exists. */
413   /* No matter what the name - it still must be opened! */
414   capture->deviceHandle = v4l1_open(deviceName, O_RDWR);
415
416
417   if (capture->deviceHandle == 0)
418   {
419     detect = -1;
420
421     icvCloseCAM_V4L(capture);
422   }
423
424   if (detect == 0)
425   {
426     /* Query the newly opened device for its capabilities */
427     if (v4l1_ioctl(capture->deviceHandle, VIDIOCGCAP, &capture->capability) < 0)
428     {
429       detect = 0;
430
431       icvCloseCAM_V4L(capture);
432     }
433       else
434     {
435       detect = 1;
436     }
437   }
438
439   return detect;
440
441 }
442
443
444 static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName)
445 {
446
447   // if detect = -1 then unable to open device
448   // if detect = 0 then detected nothing
449   // if detect = 1 then V4L2 device
450   int detect = 0;
451
452
453   // Test device for V4L2 compability
454
455   /* Open and test V4L2 device */
456   capture->deviceHandle = v4l2_open (deviceName, O_RDWR /* required */ | O_NONBLOCK, 0);
457
458
459
460   if (capture->deviceHandle == 0)
461   {
462     detect = -1;
463
464     icvCloseCAM_V4L(capture);
465   }
466
467   if (detect == 0)
468   {
469     CLEAR (capture->cap);
470     if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYCAP, &capture->cap))
471     {
472       detect = 0;
473
474       icvCloseCAM_V4L(capture);
475     }
476       else
477     {
478       CLEAR (capture->capability);
479       capture->capability.type = capture->cap.capabilities;
480
481       /* Query channels number */
482       if (-1 != xioctl (capture->deviceHandle, VIDIOC_G_INPUT, &capture->capability.channels))
483       {
484         detect = 1;
485       }
486     }
487   }
488
489   return detect;
490
491 }
492
493
494 static void v4l2_scan_controls_enumerate_menu(CvCaptureCAM_V4L* capture)
495 {
496 //  printf (" Menu items:\n");
497   CLEAR (capture->querymenu);
498   capture->querymenu.id = capture->queryctrl.id;
499   for (capture->querymenu.index = capture->queryctrl.minimum;
500        (int)capture->querymenu.index <= capture->queryctrl.maximum;
501        capture->querymenu.index++)
502   {
503     if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYMENU,
504                      &capture->querymenu))
505     {
506       //printf (" %s\n", capture->querymenu.name);
507     } else {
508         perror ("VIDIOC_QUERYMENU");
509     }
510   }
511 }
512
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
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
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
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
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
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_MENU) {
594         v4l2_scan_controls_enumerate_menu(capture);
595       }
596       if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
597          capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
598          capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
599         continue;
600       }
601       if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
602         v4l2_add_ctrl_range(capture, &c);
603       }
604
605     } while(0 == v4l2_ioctl (capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl));
606   } else
607 #endif
608   {
609     /* Check all the standard controls */
610     for(ctrl_id=V4L2_CID_BASE; ctrl_id<V4L2_CID_LASTP1; ctrl_id++) {
611       capture->queryctrl.id = ctrl_id;
612       if(v4l2_ioctl(capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl) == 0) {
613         if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
614           continue;
615         }
616         if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) {
617           v4l2_scan_controls_enumerate_menu(capture);
618         }
619         if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
620            capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
621            capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
622           continue;
623         }
624         c.id = ctrl_id;
625
626         if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
627           v4l2_add_ctrl_range(capture, &c);
628         }
629       }
630     }
631
632     /* Check any custom controls */
633     for(ctrl_id=V4L2_CID_PRIVATE_BASE; ; ctrl_id++) {
634       capture->queryctrl.id = ctrl_id;
635       if(v4l2_ioctl(capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl) == 0) {
636         if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
637           continue;
638         }
639
640         if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) {
641           v4l2_scan_controls_enumerate_menu(capture);
642         }
643
644         if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
645            capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
646            capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
647            continue;
648         }
649
650         c.id = ctrl_id;
651
652         if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
653           v4l2_add_ctrl_range(capture, &c);
654         }
655       } else {
656         break;
657       }
658     }
659   }
660 }
661
662 static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName)
663 {
664    int detect_v4l2 = 0;
665
666    capture->deviceName = strdup(deviceName);
667
668    detect_v4l2 = try_init_v4l2(capture, deviceName);
669
670    if (detect_v4l2 != 1) {
671        /* init of the v4l2 device is not OK */
672        return -1;
673    }
674
675    /* starting from here, we assume we are in V4L2 mode */
676    capture->is_v4l2_device = 1;
677
678    capture->v4l2_ctrl_ranges = NULL;
679    capture->v4l2_ctrl_count = 0;
680
681    /* Scan V4L2 controls */
682    v4l2_scan_controls(capture);
683
684    if ((capture->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
685       /* Nope. */
686       fprintf( stderr, "HIGHGUI ERROR: V4L2: device %s is unable to capture video memory.\n",deviceName);
687       icvCloseCAM_V4L(capture);
688       return -1;
689    }
690
691    /* The following code sets the CHANNEL_NUMBER of the video input.  Some video sources
692    have sub "Channel Numbers".  For a typical V4L TV capture card, this is usually 1.
693    I myself am using a simple NTSC video input capture card that uses the value of 1.
694    If you are not in North America or have a different video standard, you WILL have to change
695    the following settings and recompile/reinstall.  This set of settings is based on
696    the most commonly encountered input video source types (like my bttv card) */
697
698    if(capture->inp.index > 0) {
699        CLEAR (capture->inp);
700        capture->inp.index = CHANNEL_NUMBER;
701        /* Set only channel number to CHANNEL_NUMBER */
702        /* V4L2 have a status field from selected video mode */
703        if (-1 == xioctl (capture->deviceHandle, VIDIOC_ENUMINPUT, &capture->inp))
704        {
705          fprintf (stderr, "HIGHGUI ERROR: V4L2: Aren't able to set channel number\n");
706          icvCloseCAM_V4L (capture);
707          return -1;
708        }
709    } /* End if */
710
711    /* Find Window info */
712    CLEAR (capture->form);
713    capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
714
715    if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
716        fprintf( stderr, "HIGHGUI ERROR: V4L2: Could not obtain specifics of capture window.\n\n");
717        icvCloseCAM_V4L(capture);
718        return -1;
719    }
720
721   /* libv4l will convert from any format to V4L2_PIX_FMT_BGR24 */
722   CLEAR (capture->form);
723   capture->form.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
724   capture->form.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
725   capture->form.fmt.pix.field       = V4L2_FIELD_ANY;
726   capture->form.fmt.pix.width = capture->width;
727   capture->form.fmt.pix.height = capture->height;
728
729   if (-1 == xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form)) {
730       fprintf(stderr, "HIGHGUI ERROR: libv4l unable to ioctl S_FMT\n");
731       return -1;
732   }
733
734   if (V4L2_PIX_FMT_BGR24 != capture->form.fmt.pix.pixelformat) {
735       fprintf( stderr, "HIGHGUI ERROR: libv4l unable convert to requested pixfmt\n");
736       return -1;
737   }
738
739    /* icvSetVideoSize(capture, DEFAULT_V4L_WIDTH, DEFAULT_V4L_HEIGHT); */
740
741    unsigned int min;
742
743    /* Buggy driver paranoia. */
744    min = capture->form.fmt.pix.width * 2;
745
746    if (capture->form.fmt.pix.bytesperline < min)
747        capture->form.fmt.pix.bytesperline = min;
748
749    min = capture->form.fmt.pix.bytesperline * capture->form.fmt.pix.height;
750
751    if (capture->form.fmt.pix.sizeimage < min)
752        capture->form.fmt.pix.sizeimage = min;
753
754    CLEAR (capture->req);
755
756    unsigned int buffer_number = DEFAULT_V4L_BUFFERS;
757
758    try_again:
759
760    capture->req.count = buffer_number;
761    capture->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
762    capture->req.memory = V4L2_MEMORY_MMAP;
763
764    if (-1 == xioctl (capture->deviceHandle, VIDIOC_REQBUFS, &capture->req))
765    {
766        if (EINVAL == errno)
767        {
768          fprintf (stderr, "%s does not support memory mapping\n", deviceName);
769        } else {
770          perror ("VIDIOC_REQBUFS");
771        }
772        /* free capture, and returns an error code */
773        icvCloseCAM_V4L (capture);
774        return -1;
775    }
776
777    if (capture->req.count < buffer_number)
778    {
779        if (buffer_number == 1)
780        {
781            fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName);
782
783            /* free capture, and returns an error code */
784            icvCloseCAM_V4L (capture);
785            return -1;
786        } else {
787          buffer_number--;
788    fprintf (stderr, "Insufficient buffer memory on %s -- decreaseing buffers\n", deviceName);
789
790    goto try_again;
791        }
792    }
793
794    for (n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
795    {
796        struct v4l2_buffer buf;
797
798        CLEAR (buf);
799
800        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
801        buf.memory = V4L2_MEMORY_MMAP;
802        buf.index = n_buffers;
803
804        if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYBUF, &buf)) {
805            perror ("VIDIOC_QUERYBUF");
806
807            /* free capture, and returns an error code */
808            icvCloseCAM_V4L (capture);
809            return -1;
810        }
811
812        capture->buffers[n_buffers].length = buf.length;
813        capture->buffers[n_buffers].start =
814          v4l2_mmap (NULL /* start anywhere */,
815                     buf.length,
816                     PROT_READ | PROT_WRITE /* required */,
817                     MAP_SHARED /* recommended */,
818                     capture->deviceHandle, buf.m.offset);
819
820        if (MAP_FAILED == capture->buffers[n_buffers].start) {
821            perror ("mmap");
822
823            /* free capture, and returns an error code */
824            icvCloseCAM_V4L (capture);
825            return -1;
826        }
827
828 #ifdef USE_TEMP_BUFFER
829        if (n_buffers == 0) {
830            if (capture->buffers[MAX_V4L_BUFFERS].start) {
831                free(capture->buffers[MAX_V4L_BUFFERS].start);
832                capture->buffers[MAX_V4L_BUFFERS].start = NULL;
833        }
834
835            capture->buffers[MAX_V4L_BUFFERS].start = malloc(buf.length);
836            capture->buffers[MAX_V4L_BUFFERS].length = buf.length;
837        };
838 #endif
839    }
840
841    /* Set up Image data */
842    cvInitImageHeader( &capture->frame,
843                       cvSize( capture->captureWindow.width,
844                               capture->captureWindow.height ),
845                       IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
846    /* Allocate space for RGBA data */
847    capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
848
849    return 1;
850 }; /* End _capture_V4L2 */
851
852
853 static int _capture_V4L (CvCaptureCAM_V4L *capture, char *deviceName)
854 {
855    int detect_v4l = 0;
856
857    detect_v4l = try_init_v4l(capture, deviceName);
858
859    if ((detect_v4l == -1)
860        )
861    {
862      fprintf (stderr, "HIGHGUI ERROR: V4L"
863               ": device %s: Unable to open for READ ONLY\n", deviceName);
864
865      return -1;
866    }
867
868    if ((detect_v4l <= 0)
869        )
870    {
871      fprintf (stderr, "HIGHGUI ERROR: V4L"
872               ": device %s: Unable to query number of channels\n", deviceName);
873
874      return -1;
875    }
876
877    {
878      if ((capture->capability.type & VID_TYPE_CAPTURE) == 0) {
879        /* Nope. */
880        fprintf( stderr, "HIGHGUI ERROR: V4L: "
881                 "device %s is unable to capture video memory.\n",deviceName);
882        icvCloseCAM_V4L(capture);
883        return -1;
884      }
885
886    }
887
888
889    /* The following code sets the CHANNEL_NUMBER of the video input.  Some video sources
890    have sub "Channel Numbers".  For a typical V4L TV capture card, this is usually 1.
891    I myself am using a simple NTSC video input capture card that uses the value of 1.
892    If you are not in North America or have a different video standard, you WILL have to change
893    the following settings and recompile/reinstall.  This set of settings is based on
894    the most commonly encountered input video source types (like my bttv card) */
895
896    {
897
898      if(capture->capability.channels>0) {
899
900        struct video_channel selectedChannel;
901
902        selectedChannel.channel=CHANNEL_NUMBER;
903        if (v4l1_ioctl(capture->deviceHandle, VIDIOCGCHAN , &selectedChannel) != -1) {
904           /* set the video mode to ( VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM) */
905 //           selectedChannel.norm = VIDEO_MODE_NTSC;
906           if (v4l1_ioctl(capture->deviceHandle, VIDIOCSCHAN , &selectedChannel) == -1) {
907              /* Could not set selected channel - Oh well */
908              //printf("\n%d, %s not NTSC capable.\n",selectedChannel.channel, selectedChannel.name);
909           } /* End if */
910        } /* End if */
911      } /* End if */
912
913    }
914
915    {
916
917      if(v4l1_ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) == -1) {
918        fprintf( stderr, "HIGHGUI ERROR: V4L: "
919                 "Could not obtain specifics of capture window.\n\n");
920        icvCloseCAM_V4L(capture);
921        return -1;
922      }
923
924    }
925
926    {
927       if(v4l1_ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) {
928          fprintf( stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n");
929          icvCloseCAM_V4L(capture);
930          return -1;
931       }
932
933       capture->imageProperties.palette = VIDEO_PALETTE_RGB24;
934       capture->imageProperties.depth = 24;
935       if (v4l1_ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties) < 0) {
936         fprintf( stderr, "HIGHGUI ERROR: libv4l unable to ioctl VIDIOCSPICT\n\n");
937          icvCloseCAM_V4L(capture);
938         return -1;
939       }
940       if (v4l1_ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) {
941         fprintf( stderr, "HIGHGUI ERROR: libv4l unable to ioctl VIDIOCGPICT\n\n");
942          icvCloseCAM_V4L(capture);
943         return -1;
944       }
945       if (capture->imageProperties.palette != VIDEO_PALETTE_RGB24) {
946         fprintf( stderr, "HIGHGUI ERROR: libv4l unable convert to requested pixfmt\n\n");
947          icvCloseCAM_V4L(capture);
948         return -1;
949       }
950
951    }
952
953    {
954
955      v4l1_ioctl(capture->deviceHandle, VIDIOCGMBUF, &capture->memoryBuffer);
956      capture->memoryMap  = (char *)v4l1_mmap(0,
957                                    capture->memoryBuffer.size,
958                                    PROT_READ | PROT_WRITE,
959                                    MAP_SHARED,
960                                    capture->deviceHandle,
961                                    0);
962      if (capture->memoryMap == MAP_FAILED) {
963         fprintf( stderr, "HIGHGUI ERROR: V4L: Mapping Memmory from video source error: %s\n", strerror(errno));
964         icvCloseCAM_V4L(capture);
965         return -1;
966      }
967
968      /* Set up video_mmap structure pointing to this memory mapped area so each image may be
969         retrieved from an index value */
970      capture->mmaps = (struct video_mmap *)
971                  (malloc(capture->memoryBuffer.frames * sizeof(struct video_mmap)));
972      if (!capture->mmaps) {
973         fprintf( stderr, "HIGHGUI ERROR: V4L: Could not memory map video frames.\n");
974         icvCloseCAM_V4L(capture);
975         return -1;
976      }
977
978    }
979
980    /* Set up Image data */
981    cvInitImageHeader( &capture->frame,
982                       cvSize( capture->captureWindow.width,
983                               capture->captureWindow.height ),
984                       IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
985    /* Allocate space for RGBA data */
986    capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
987
988    return 1;
989 }; /* End _capture_V4L */
990
991 static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index)
992 {
993    static int autoindex;
994    autoindex = 0;
995
996    char deviceName[MAX_DEVICE_DRIVER_NAME];
997
998    if (!numCameras)
999       icvInitCapture_V4L(); /* Havent called icvInitCapture yet - do it now! */
1000    if (!numCameras)
1001      return NULL; /* Are there any /dev/video input sources? */
1002
1003    //search index in indexList
1004    if ( (index>-1) && ! ((1 << index) & indexList) )
1005    {
1006      fprintf( stderr, "HIGHGUI ERROR: V4L: index %d is not correct!\n",index);
1007      return NULL; /* Did someone ask for not correct video source number? */
1008    }
1009    /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL
1010       the handles for V4L processing */
1011    CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L));
1012    if (!capture) {
1013       fprintf( stderr, "HIGHGUI ERROR: V4L: Could not allocate memory for capture process.\n");
1014       return NULL;
1015    }
1016
1017 #ifdef USE_TEMP_BUFFER
1018    capture->buffers[MAX_V4L_BUFFERS].start = NULL;
1019 #endif
1020
1021    /* Select camera, or rather, V4L video source */
1022    if (index<0) { // Asking for the first device available
1023      for (; autoindex<MAX_CAMERAS;autoindex++)
1024     if (indexList & (1<<autoindex))
1025         break;
1026      if (autoindex==MAX_CAMERAS)
1027     return NULL;
1028      index=autoindex;
1029      autoindex++;// i can recall icvOpenCAM_V4l with index=-1 for next camera
1030    }
1031    /* Print the CameraNumber at the end of the string with a width of one character */
1032    sprintf(deviceName, "/dev/video%1d", index);
1033
1034    /* w/o memset some parts  arent initialized - AKA: Fill it with zeros so it is clean */
1035    memset(capture,0,sizeof(CvCaptureCAM_V4L));
1036    /* Present the routines needed for V4L funtionality.  They are inserted as part of
1037       the standard set of cv calls promoting transparency.  "Vector Table" insertion. */
1038    capture->FirstCapture = 1;
1039
1040    /* set the default size */
1041    capture->width  = DEFAULT_V4L_WIDTH;
1042    capture->height = DEFAULT_V4L_HEIGHT;
1043
1044    if (_capture_V4L2 (capture, deviceName) == -1) {
1045        icvCloseCAM_V4L(capture);
1046        capture->is_v4l2_device = 0;
1047        if (_capture_V4L (capture, deviceName) == -1) {
1048            icvCloseCAM_V4L(capture);
1049            return NULL;
1050        }
1051    } else {
1052        capture->is_v4l2_device = 1;
1053    }
1054
1055    return capture;
1056 }; /* End icvOpenCAM_V4L */
1057
1058 #ifdef HAVE_CAMV4L2
1059
1060 static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
1061     struct v4l2_buffer buf;
1062
1063     CLEAR (buf);
1064
1065     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1066     buf.memory = V4L2_MEMORY_MMAP;
1067
1068     if (-1 == xioctl (capture->deviceHandle, VIDIOC_DQBUF, &buf)) {
1069         switch (errno) {
1070         case EAGAIN:
1071             return 0;
1072
1073         case EIO:
1074             /* Could ignore EIO, see spec. */
1075
1076             /* fall through */
1077
1078         default:
1079             /* display the error and stop processing */
1080             perror ("VIDIOC_DQBUF");
1081             return 1;
1082         }
1083    }
1084
1085    assert(buf.index < capture->req.count);
1086
1087 #ifdef USE_TEMP_BUFFER
1088    memcpy(capture->buffers[MAX_V4L_BUFFERS].start,
1089     capture->buffers[buf.index].start,
1090     capture->buffers[MAX_V4L_BUFFERS].length );
1091    capture->bufferIndex = MAX_V4L_BUFFERS;
1092    //printf("got data in buff %d, len=%d, flags=0x%X, seq=%d, used=%d)\n",
1093    //   buf.index, buf.length, buf.flags, buf.sequence, buf.bytesused);
1094 #else
1095    capture->bufferIndex = buf.index;
1096 #endif
1097
1098    if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf))
1099        perror ("VIDIOC_QBUF");
1100
1101    return 1;
1102 }
1103
1104 static void mainloop_v4l2(CvCaptureCAM_V4L* capture) {
1105     unsigned int count;
1106
1107     count = 1;
1108
1109     while (count-- > 0) {
1110         for (;;) {
1111             fd_set fds;
1112             struct timeval tv;
1113             int r;
1114
1115             FD_ZERO (&fds);
1116             FD_SET (capture->deviceHandle, &fds);
1117
1118             /* Timeout. */
1119             tv.tv_sec = 10;
1120             tv.tv_usec = 0;
1121
1122             r = select (capture->deviceHandle+1, &fds, NULL, NULL, &tv);
1123
1124             if (-1 == r) {
1125                 if (EINTR == errno)
1126                     continue;
1127
1128                 perror ("select");
1129             }
1130
1131             if (0 == r) {
1132                 fprintf (stderr, "select timeout\n");
1133
1134                 /* end the infinite loop */
1135                 break;
1136             }
1137
1138             if (read_frame_v4l2 (capture))
1139                 break;
1140         }
1141     }
1142 }
1143
1144 static int icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) {
1145
1146    if (capture->FirstCapture) {
1147       /* Some general initialization must take place the first time through */
1148
1149       /* This is just a technicality, but all buffers must be filled up before any
1150          staggered SYNC is applied.  SO, filler up. (see V4L HowTo) */
1151
1152       if (capture->is_v4l2_device == 1)
1153       {
1154
1155         for (capture->bufferIndex = 0;
1156              capture->bufferIndex < ((int)capture->req.count);
1157              ++capture->bufferIndex)
1158         {
1159
1160           struct v4l2_buffer buf;
1161
1162           CLEAR (buf);
1163
1164           buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1165           buf.memory      = V4L2_MEMORY_MMAP;
1166           buf.index       = (unsigned long)capture->bufferIndex;
1167
1168           if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) {
1169               perror ("VIDIOC_QBUF");
1170               return 0;
1171           }
1172         }
1173
1174         /* enable the streaming */
1175         capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1176         if (-1 == xioctl (capture->deviceHandle, VIDIOC_STREAMON,
1177                           &capture->type)) {
1178             /* error enabling the stream */
1179             perror ("VIDIOC_STREAMON");
1180             return 0;
1181         }
1182       } else
1183       {
1184
1185         for (capture->bufferIndex = 0;
1186          capture->bufferIndex < (capture->memoryBuffer.frames-1);
1187          ++capture->bufferIndex) {
1188
1189           capture->mmaps[capture->bufferIndex].frame  = capture->bufferIndex;
1190           capture->mmaps[capture->bufferIndex].width  = capture->captureWindow.width;
1191           capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1192           capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1193
1194           if (v4l1_ioctl(capture->deviceHandle, VIDIOCMCAPTURE, &capture->mmaps[capture->bufferIndex]) == -1) {
1195             fprintf( stderr, "HIGHGUI ERROR: V4L: Initial Capture Error: Unable to load initial memory buffers.\n");
1196             return 0;
1197           }
1198         }
1199
1200       }
1201
1202       /* preparation is ok */
1203       capture->FirstCapture = 0;
1204    }
1205
1206    if (capture->is_v4l2_device == 1)
1207    {
1208
1209      mainloop_v4l2(capture);
1210
1211    } else
1212    {
1213
1214      capture->mmaps[capture->bufferIndex].frame  = capture->bufferIndex;
1215      capture->mmaps[capture->bufferIndex].width  = capture->captureWindow.width;
1216      capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1217      capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1218
1219      if (v4l1_ioctl (capture->deviceHandle, VIDIOCMCAPTURE,
1220     &capture->mmaps[capture->bufferIndex]) == -1) {
1221    /* capture is on the way, so just exit */
1222    return 1;
1223      }
1224
1225      ++capture->bufferIndex;
1226      if (capture->bufferIndex == capture->memoryBuffer.frames) {
1227         capture->bufferIndex = 0;
1228      }
1229
1230    }
1231
1232    return(1);
1233 }
1234
1235 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int) {
1236
1237   if (capture->is_v4l2_device == 0)
1238   {
1239
1240     /* [FD] this really belongs here */
1241     if (v4l1_ioctl(capture->deviceHandle, VIDIOCSYNC, &capture->mmaps[capture->bufferIndex].frame) == -1) {
1242       fprintf( stderr, "HIGHGUI ERROR: V4L: Could not SYNC to video stream. %s\n", strerror(errno));
1243     }
1244
1245   }
1246
1247    /* Now get what has already been captured as a IplImage return */
1248
1249    /* First, reallocate imageData if the frame size changed */
1250
1251   if (capture->is_v4l2_device == 1)
1252   {
1253
1254     if(((unsigned long)capture->frame.width != capture->form.fmt.pix.width)
1255        || ((unsigned long)capture->frame.height != capture->form.fmt.pix.height)) {
1256         cvFree(&capture->frame.imageData);
1257         cvInitImageHeader( &capture->frame,
1258               cvSize( capture->form.fmt.pix.width,
1259                   capture->form.fmt.pix.height ),
1260               IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
1261        capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1262     }
1263
1264   } else
1265   {
1266
1267     if((capture->frame.width != capture->mmaps[capture->bufferIndex].width)
1268       || (capture->frame.height != capture->mmaps[capture->bufferIndex].height)) {
1269        cvFree(&capture->frame.imageData);
1270        cvInitImageHeader( &capture->frame,
1271               cvSize( capture->captureWindow.width,
1272                   capture->captureWindow.height ),
1273               IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
1274        capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1275     }
1276
1277   }
1278
1279   if (capture->is_v4l2_device == 1)
1280   {
1281
1282     if(capture->buffers[capture->bufferIndex].start){
1283       memcpy((char *)capture->frame.imageData,
1284          (char *)capture->buffers[capture->bufferIndex].start,
1285          capture->frame.imageSize);
1286     }
1287
1288   } else
1289 #endif /* HAVE_CAMV4L2 */
1290   {
1291
1292     switch(capture->imageProperties.palette) {
1293       case VIDEO_PALETTE_RGB24:
1294         memcpy((char *)capture->frame.imageData,
1295            (char *)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
1296            capture->frame.imageSize);
1297         break;
1298       default:
1299         fprintf( stderr,
1300                  "HIGHGUI ERROR: V4L: Cannot convert from palette %d to RGB\n",
1301                  capture->imageProperties.palette);
1302         return 0;
1303     }
1304
1305   }
1306
1307    return(&capture->frame);
1308 }
1309
1310 /* TODO: review this adaptation */
1311 static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture,
1312                                      int property_id ) {
1313   char name[32];
1314   int is_v4l2_device = 0;
1315       /* initialize the control structure */
1316   switch (property_id) {
1317     case CV_CAP_PROP_FRAME_WIDTH:
1318     case CV_CAP_PROP_FRAME_HEIGHT:
1319       CLEAR (capture->form);
1320       capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1321       if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
1322           /* display an error message, and return an error code */
1323           perror ("VIDIOC_G_FMT");
1324         if (v4l1_ioctl (capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
1325           fprintf (stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n");
1326           icvCloseCAM_V4L(capture);
1327           return -1;
1328         } else {
1329           int retval = (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->captureWindow.width:capture->captureWindow.height;
1330           return retval / 0xFFFF;
1331         }
1332       }
1333       return (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->form.fmt.pix.width:capture->form.fmt.pix.height;
1334     case CV_CAP_PROP_BRIGHTNESS:
1335       sprintf(name, "Brightness");
1336       capture->control.id = V4L2_CID_BRIGHTNESS;
1337       break;
1338     case CV_CAP_PROP_CONTRAST:
1339       sprintf(name, "Contrast");
1340       capture->control.id = V4L2_CID_CONTRAST;
1341       break;
1342     case CV_CAP_PROP_SATURATION:
1343       sprintf(name, "Saturation");
1344       capture->control.id = V4L2_CID_SATURATION;
1345       break;
1346     case CV_CAP_PROP_HUE:
1347       sprintf(name, "Hue");
1348       capture->control.id = V4L2_CID_HUE;
1349       break;
1350     case CV_CAP_PROP_GAIN:
1351       sprintf(name, "Gain");
1352       capture->control.id = V4L2_CID_GAIN;
1353       break;
1354     case CV_CAP_PROP_EXPOSURE:
1355       sprintf(name, "Exposure");
1356       capture->control.id = V4L2_CID_EXPOSURE;
1357       break;
1358     default:
1359       sprintf(name, "<unknown property string>");
1360       capture->control.id = property_id;
1361   }
1362
1363   if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &capture->control) == 0) {
1364     /* all went well */
1365     is_v4l2_device = 1;
1366   } else {
1367     fprintf(stderr, "HIGHGUI ERROR: V4L2: Unable to get property %s(%u) - %s\n", name, capture->control.id, strerror(errno));
1368   }
1369
1370   if (is_v4l2_device == 1) {
1371       /* get the min/max values */
1372       int v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
1373       int v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);
1374
1375       if ((v4l2_min == -1) && (v4l2_max == -1)) {
1376         fprintf(stderr, "HIGHGUI ERROR: V4L2: Property %s(%u) not supported by device\n", name, property_id);
1377         return -1;
1378       }
1379
1380       /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
1381       return ((float)capture->control.value - v4l2_min) / (v4l2_max - v4l2_min);
1382
1383   } else {
1384     /* TODO: review this section */
1385     int retval = -1;
1386
1387     switch (property_id) {
1388       case CV_CAP_PROP_BRIGHTNESS:
1389         retval = capture->imageProperties.brightness;
1390         break;
1391       case CV_CAP_PROP_CONTRAST:
1392         retval = capture->imageProperties.contrast;
1393         break;
1394       case CV_CAP_PROP_SATURATION:
1395         retval = capture->imageProperties.colour;
1396         break;
1397       case CV_CAP_PROP_HUE:
1398         retval = capture->imageProperties.hue;
1399         break;
1400       case CV_CAP_PROP_GAIN:
1401         fprintf(stderr, "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
1402         return -1;
1403         break;
1404       case CV_CAP_PROP_EXPOSURE:
1405         fprintf(stderr, "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n");
1406         return -1;
1407         break;
1408     }
1409
1410     if (retval == -1) {
1411       /* there was a problem */
1412       return -1;
1413     }
1414     /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
1415     return float (retval) / 0xFFFF;
1416   }
1417 }
1418
1419 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h) {
1420
1421   if (capture->is_v4l2_device == 1)
1422   {
1423     char deviceName[MAX_DEVICE_DRIVER_NAME];
1424     sprintf(deviceName, "%s", capture->deviceName);
1425     icvCloseCAM_V4L(capture);
1426     _capture_V4L2(capture, deviceName);
1427
1428     CLEAR (capture->crop);
1429     capture->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1430     capture->crop.c.left       = 0;
1431     capture->crop.c.top        = 0;
1432     capture->crop.c.height     = h*24;
1433     capture->crop.c.width      = w*24;
1434
1435     /* set the crop area, but don't exit if the device don't support croping */
1436     xioctl (capture->deviceHandle, VIDIOC_S_CROP, &capture->crop);
1437
1438     CLEAR (capture->form);
1439     capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1440
1441     /* read the current setting, mainly to retreive the pixelformat information */
1442     xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form);
1443
1444     /* set the values we want to change */
1445     capture->form.fmt.pix.width = w;
1446     capture->form.fmt.pix.height = h;
1447     capture->form.fmt.win.chromakey = 0;
1448     capture->form.fmt.win.field = V4L2_FIELD_ANY;
1449     capture->form.fmt.win.clips = 0;
1450     capture->form.fmt.win.clipcount = 0;
1451     capture->form.fmt.pix.field = V4L2_FIELD_ANY;
1452
1453     /* ask the device to change the size
1454      * don't test if the set of the size is ok, because some device
1455      * don't allow changing the size, and we will get the real size
1456      * later */
1457     xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form);
1458
1459     /* try to set framerate to 30 fps */
1460     struct v4l2_streamparm setfps;
1461     memset (&setfps, 0, sizeof(struct v4l2_streamparm));
1462     setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1463     setfps.parm.capture.timeperframe.numerator = 1;
1464     setfps.parm.capture.timeperframe.denominator = 30;
1465     xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps);
1466
1467     /* we need to re-initialize some things, like buffers, because the size has
1468      * changed */
1469     capture->FirstCapture = 1;
1470
1471     /* Get window info again, to get the real value */
1472     if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form))
1473     {
1474       fprintf(stderr, "HIGHGUI ERROR: V4L/V4L2: Could not obtain specifics of capture window.\n\n");
1475
1476       icvCloseCAM_V4L(capture);
1477
1478       return 0;
1479     }
1480
1481     return 0;
1482
1483   } else
1484   {
1485
1486     if (capture==0) return 0;
1487      if (w>capture->capability.maxwidth) {
1488        w=capture->capability.maxwidth;
1489      }
1490      if (h>capture->capability.maxheight) {
1491        h=capture->capability.maxheight;
1492      }
1493
1494      capture->captureWindow.width=w;
1495      capture->captureWindow.height=h;
1496
1497      if (ioctl(capture->deviceHandle, VIDIOCSWIN, &capture->captureWindow) < 0) {
1498        icvCloseCAM_V4L(capture);
1499        return 0;
1500      }
1501
1502      if (ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
1503        icvCloseCAM_V4L(capture);
1504        return 0;
1505      }
1506
1507      capture->FirstCapture = 1;
1508
1509   }
1510
1511   return 0;
1512
1513 }
1514
1515 static int icvSetControl (CvCaptureCAM_V4L* capture, int property_id, double value) {
1516   struct v4l2_control c;
1517   __s32 ctrl_value;
1518   char name[32];
1519   int is_v4l2  = 1;
1520   int v4l2_min = 0;
1521   int v4l2_max = 255;
1522   if (capture->v4l2_ctrl_ranges == NULL) {
1523     v4l2_scan_controls(capture);
1524   }
1525
1526   CLEAR (capture->control);
1527   CLEAR (capture->queryctrl);
1528
1529   /* get current values */
1530   switch (property_id) {
1531     case CV_CAP_PROP_BRIGHTNESS:
1532       sprintf(name, "Brightness");
1533       capture->control.id = V4L2_CID_BRIGHTNESS;
1534       break;
1535     case CV_CAP_PROP_CONTRAST:
1536       sprintf(name, "Contrast");
1537       capture->control.id = V4L2_CID_CONTRAST;
1538       break;
1539     case CV_CAP_PROP_SATURATION:
1540       sprintf(name, "Saturation");
1541       capture->control.id = V4L2_CID_SATURATION;
1542       break;
1543     case CV_CAP_PROP_HUE:
1544       sprintf(name, "Hue");
1545       capture->control.id = V4L2_CID_HUE;
1546       break;
1547     case CV_CAP_PROP_GAIN:
1548       sprintf(name, "Gain");
1549       capture->control.id = V4L2_CID_GAIN;
1550       break;
1551     case CV_CAP_PROP_EXPOSURE:
1552       sprintf(name, "Exposure");
1553       capture->control.id = V4L2_CID_EXPOSURE;
1554       break;
1555     default:
1556       sprintf(name, "<unknown property string>");
1557       capture->control.id = property_id;
1558   }
1559
1560   v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
1561   v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);
1562
1563   if ((v4l2_min == -1) && (v4l2_max == -1)) {
1564     fprintf(stderr, "HIGHGUI ERROR: V4L: Property %s(%u) not supported by device\n", name, property_id);
1565     return -1;
1566   }
1567
1568   if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &capture->control) == 0) {
1569     /* all went well */
1570   } else {
1571     fprintf(stderr, "HIGHGUI ERROR: V4L2: Unable to get property %s(%u) - %s\n", name, capture->control.id, strerror(errno));
1572   }
1573
1574   if (v4l2_max != 0) {
1575     double val = value;
1576     if (value < 0.0) {
1577       val = 0.0;
1578     } else if (value > 1.0) {
1579       val = 1.0;
1580     }
1581     ctrl_value = val * (double)(v4l2_max - v4l2_min) + v4l2_min;
1582   } else {
1583     ctrl_value = v4l2_get_ctrl_default(capture, capture->control.id) * (double)(v4l2_max - v4l2_min) + v4l2_min;
1584   }
1585
1586   /* try and set value as if it was a v4l2 device */
1587   c.id    = capture->control.id;
1588   c.value = ctrl_value;
1589   if (v4l2_ioctl(capture->deviceHandle, VIDIOC_S_CTRL, &c) != 0) {
1590     /* The driver may clamp the value or return ERANGE, ignored here */
1591     if (errno != ERANGE) {
1592       fprintf(stderr, "HIGHGUI ERROR: V4L2: Failed to set control \"%d\": %s (value %d)\n", c.id, strerror(errno), c.value);
1593       is_v4l2 = 0;
1594     } else {
1595       return 0;
1596     }
1597   } else {
1598     return 0;
1599   }
1600
1601   if (is_v4l2 == 0) { /* use v4l1_ioctl */
1602     fprintf(stderr, "HIGHGUI WARNING: Setting property %u through v4l2 failed. Trying with v4l1.\n", c.id);
1603     int v4l_value;
1604     /* scale the value to the wanted integer one */
1605     v4l_value = (int)(0xFFFF * value);
1606
1607     switch (property_id) {
1608       case CV_CAP_PROP_BRIGHTNESS:
1609         capture->imageProperties.brightness = v4l_value;
1610         break;
1611       case CV_CAP_PROP_CONTRAST:
1612         capture->imageProperties.contrast = v4l_value;
1613         break;
1614       case CV_CAP_PROP_SATURATION:
1615         capture->imageProperties.colour = v4l_value;
1616         break;
1617       case CV_CAP_PROP_HUE:
1618         capture->imageProperties.hue = v4l_value;
1619         break;
1620       case CV_CAP_PROP_GAIN:
1621           fprintf(stderr, "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
1622         return -1;
1623     case CV_CAP_PROP_EXPOSURE:
1624         fprintf(stderr, "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n");
1625         return -1;
1626     default:
1627         fprintf(stderr, "HIGHGUI ERROR: V4L: property #%d is not supported\n", property_id);
1628         return -1;
1629     }
1630
1631     if (v4l1_ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties) < 0){
1632       fprintf(stderr, "HIGHGUI ERROR: V4L: Unable to set video informations\n");
1633       icvCloseCAM_V4L(capture);
1634       return -1;
1635     }
1636   }
1637
1638   /* all was OK */
1639   return 0;
1640 }
1641
1642 static int icvSetPropertyCAM_V4L(CvCaptureCAM_V4L* capture, int property_id, double value){
1643     static int width = 0, height = 0;
1644     int retval;
1645
1646     /* initialization */
1647     retval = 0;
1648
1649     /* two subsequent calls setting WIDTH and HEIGHT will change
1650        the video size */
1651     /* the first one will return an error, though. */
1652
1653     switch (property_id) {
1654     case CV_CAP_PROP_FRAME_WIDTH:
1655         width = cvRound(value);
1656         capture->width = width;
1657         if(width !=0 && height != 0) {
1658             retval = icvSetVideoSize( capture, width, height);
1659             width = height = 0;
1660         }
1661         break;
1662     case CV_CAP_PROP_FRAME_HEIGHT:
1663         height = cvRound(value);
1664         capture->height = height;
1665         if(width !=0 && height != 0) {
1666             retval = icvSetVideoSize( capture, width, height);
1667             width = height = 0;
1668         }
1669         break;
1670     case CV_CAP_PROP_FPS:
1671         struct v4l2_streamparm setfps;
1672         memset (&setfps, 0, sizeof(struct v4l2_streamparm));
1673         setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1674         setfps.parm.capture.timeperframe.numerator = 1;
1675         setfps.parm.capture.timeperframe.denominator = value;
1676         if (xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps) < 0){
1677             fprintf(stderr, "HIGHGUI ERROR: V4L: Unable to set camera FPS\n");
1678             retval=0;
1679         }
1680         break;
1681     default:
1682         retval = icvSetControl(capture, property_id, value);
1683     }
1684
1685     /* return the the status */
1686     return retval;
1687 }
1688
1689 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ){
1690    /* Deallocate space - Hopefully, no leaks */
1691    if (capture) {
1692      v4l2_free_ranges(capture);
1693      if (capture->is_v4l2_device == 0) {
1694        if (capture->mmaps) {
1695          free(capture->mmaps);
1696        }
1697        if (capture->memoryMap) {
1698          v4l1_munmap(capture->memoryMap, capture->memoryBuffer.size);
1699        }
1700        if (capture->deviceHandle != -1) {
1701          v4l1_close(capture->deviceHandle);
1702        }
1703      } else {
1704        capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1705        if (xioctl(capture->deviceHandle, VIDIOC_STREAMOFF, &capture->type) < 0) {
1706          perror ("Unable to stop the stream.");
1707        }
1708        for (unsigned int n_buffers2 = 0; n_buffers2 < capture->req.count; ++n_buffers2) {
1709          if (-1 == v4l2_munmap (capture->buffers[n_buffers2].start, capture->buffers[n_buffers2].length)) {
1710            perror ("munmap");
1711          }
1712        }
1713
1714        if (capture->deviceHandle != -1) {
1715          v4l2_close(capture->deviceHandle);
1716        }
1717      }
1718
1719      if (capture->frame.imageData)
1720        cvFree(&capture->frame.imageData);
1721
1722 #ifdef USE_TEMP_BUFFER
1723      if (capture->buffers[MAX_V4L_BUFFERS].start) {
1724        free(capture->buffers[MAX_V4L_BUFFERS].start);
1725        capture->buffers[MAX_V4L_BUFFERS].start = NULL;
1726      }
1727 #endif
1728
1729      free(capture->deviceName);
1730      capture->deviceName = NULL;
1731      //v4l2_free_ranges(capture);
1732      //cvFree((void **)capture);
1733    }
1734 };
1735
1736
1737 class CvCaptureCAM_V4L_CPP : CvCapture
1738 {
1739 public:
1740     CvCaptureCAM_V4L_CPP() { captureV4L = 0; }
1741     virtual ~CvCaptureCAM_V4L_CPP() { close(); }
1742
1743     virtual bool open( int index );
1744     virtual void close();
1745
1746     virtual double getProperty(int);
1747     virtual bool setProperty(int, double);
1748     virtual bool grabFrame();
1749     virtual IplImage* retrieveFrame(int);
1750 protected:
1751
1752     CvCaptureCAM_V4L* captureV4L;
1753 };
1754
1755 bool CvCaptureCAM_V4L_CPP::open( int index )
1756 {
1757     close();
1758     captureV4L = icvCaptureFromCAM_V4L(index);
1759     return captureV4L != 0;
1760 }
1761
1762 void CvCaptureCAM_V4L_CPP::close()
1763 {
1764     if( captureV4L )
1765     {
1766         icvCloseCAM_V4L( captureV4L );
1767         cvFree( &captureV4L );
1768     }
1769 }
1770
1771 bool CvCaptureCAM_V4L_CPP::grabFrame()
1772 {
1773     return captureV4L ? icvGrabFrameCAM_V4L( captureV4L ) != 0 : false;
1774 }
1775
1776 IplImage* CvCaptureCAM_V4L_CPP::retrieveFrame(int)
1777 {
1778     return captureV4L ? icvRetrieveFrameCAM_V4L( captureV4L, 0 ) : 0;
1779 }
1780
1781 double CvCaptureCAM_V4L_CPP::getProperty( int propId )
1782 {
1783     return captureV4L ? icvGetPropertyCAM_V4L( captureV4L, propId ) : 0.0;
1784 }
1785
1786 bool CvCaptureCAM_V4L_CPP::setProperty( int propId, double value )
1787 {
1788     return captureV4L ? icvSetPropertyCAM_V4L( captureV4L, propId, value ) != 0 : false;
1789 }
1790
1791 CvCapture* cvCreateCameraCapture_V4L( int index )
1792 {
1793     CvCaptureCAM_V4L_CPP* capture = new CvCaptureCAM_V4L_CPP;
1794
1795     if( capture->open( index ))
1796         return (CvCapture*)capture;
1797
1798     delete capture;
1799     return 0;
1800 }
1801
1802 #endif