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