e47f279bb41dbde12fd8196f93ff148ad529509e
[opencv] / otherlibs / highgui / cvcap_v4l.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 make & enjoy!
150
151 */
152
153 /*M///////////////////////////////////////////////////////////////////////////////////////
154 //
155 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
156 //
157 //  By downloading, copying, installing or using the software you agree to this license.
158 //  If you do not agree to this license, do not download, install,
159 //  copy or use the software.
160 //
161 //
162 //                        Intel License Agreement
163 //                For Open Source Computer Vision Library
164 //
165 // Copyright (C) 2000, Intel Corporation, all rights reserved.
166 // Third party copyrights are property of their respective owners.
167 //
168 // Redistribution and use in source and binary forms, with or without modification,
169 // are permitted provided that the following conditions are met:
170 //
171 //   * Redistribution's of source code must retain the above copyright notice,
172 //     this list of conditions and the following disclaimer.
173 //
174 //   * Redistribution's in binary form must reproduce the above copyright notice,
175 //     this list of conditions and the following disclaimer in the documentation
176 //     and/or other materials provided with the distribution.
177 //
178 //   * The name of Intel Corporation may not be used to endorse or promote products
179 //     derived from this software without specific prior written permission.
180 //
181 // This software is provided by the copyright holders and contributors "as is" and
182 // any express or implied warranties, including, but not limited to, the implied
183 // warranties of merchantability and fitness for a particular purpose are disclaimed.
184 // In no event shall the Intel Corporation or contributors be liable for any direct,
185 // indirect, incidental, special, exemplary, or consequential damages
186 // (including, but not limited to, procurement of substitute goods or services;
187 // loss of use, data, or profits; or business interruption) however caused
188 // and on any theory of liability, whether in contract, strict liability,
189 // or tort (including negligence or otherwise) arising in any way out of
190 // the use of this software, even if advised of the possibility of such damage.
191 //
192 //M*/
193
194 #include "_highgui.h"
195
196 #if !defined WIN32 && defined HAVE_CAMV4L
197
198 #define CLEAR(x) memset (&(x), 0, sizeof (x))
199
200 #include <stdio.h>
201 #include <unistd.h>
202 #include <fcntl.h>
203 #include <errno.h>
204 #include <sys/ioctl.h>
205 #include <sys/types.h>
206 #include <sys/mman.h>
207
208 #include <linux/videodev.h>
209
210 #include <string.h>
211 #include <stdlib.h>
212 #include <asm/types.h>          /* for videodev2.h */
213 #include <assert.h>
214 #include <sys/stat.h>
215 #include <sys/ioctl.h>
216
217 #ifdef HAVE_CAMV4L2
218 #include <linux/videodev2.h>
219 #endif
220
221 /* Defaults - If your board can do better, set it here.  Set for the most common type inputs. */
222 #define DEFAULT_V4L_WIDTH  320
223 #define DEFAULT_V4L_HEIGHT 240
224
225 #define CHANNEL_NUMBER 1
226 #define MAX_CAMERAS 8
227
228 #define MAX_DEVICE_DRIVER_NAME 80
229
230 /* Device Capture Objects */
231
232 #ifdef HAVE_CAMV4L2
233
234 /* V4L2 structure */
235 struct buffer
236 {
237   void *  start;
238   size_t  length;
239 };
240
241 static unsigned int n_buffers = 0;
242
243 /* Additional V4L2 pixelformats support for Sonix SN9C10x base webcams */
244 #ifndef V4L2_PIX_FMT_SBGGR8
245 #define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */
246 #endif
247 #ifndef V4L2_PIX_FMT_SN9C10X
248 #define V4L2_PIX_FMT_SN9C10X  v4l2_fourcc('S','9','1','0') /* SN9C10x cmpr. */
249 #endif
250
251 #endif  /* HAVE_CAMV4L2 */
252
253 int  PALETTE_BGR24 = 0,
254      PALETTE_YVU420 = 0,
255      PALETTE_YUV411P = 0,
256      PALETTE_YUYV = 0,
257      PALETTE_UYVY= 0,
258      PALETTE_SBGGR8 = 0,
259      PALETTE_SN9C10X = 0,
260      PALETTE_MJPEG = 0;
261
262 typedef struct CvCaptureCAM_V4L
263 {
264     int deviceHandle;
265     int bufferIndex;
266     int FirstCapture;
267     struct video_capability capability;
268     struct video_window     captureWindow;
269     struct video_picture    imageProperties; 
270     struct video_mbuf       memoryBuffer;
271     struct video_mmap       *mmaps;
272     char *memoryMap;
273     IplImage frame;
274
275 #ifdef HAVE_CAMV4L2
276
277    /* V4L2 variables */
278    buffer buffers[10];
279    struct v4l2_capability cap;
280    struct v4l2_input inp;
281    struct v4l2_format form;
282    struct v4l2_crop crop;
283    struct v4l2_cropcap cropcap;
284    struct v4l2_requestbuffers req;
285    struct v4l2_jpegcompression compr;
286    struct v4l2_control control;
287    enum v4l2_buf_type type;
288    struct v4l2_queryctrl queryctrl;
289    struct v4l2_querymenu querymenu;
290
291    /* V4L2 control variables */
292    int v4l2_brightness, v4l2_brightness_min, v4l2_brightness_max;
293    int v4l2_contrast, v4l2_contrast_min, v4l2_contrast_max;
294    int v4l2_saturation, v4l2_saturation_min, v4l2_saturation_max;
295    int v4l2_hue, v4l2_hue_min, v4l2_hue_max;
296    int v4l2_gain, v4l2_gain_min, v4l2_gain_max;
297
298 #endif /* HAVE_CAMV4L2 */
299
300 }
301 CvCaptureCAM_V4L;
302
303 #ifdef HAVE_CAMV4L2
304
305 int V4L2_SUPPORT = 0;
306
307 #endif /* HAVE_CAMV4L2 */
308
309 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture );
310
311 static int icvGrabFrameCAM_V4L( CvCaptureCAM_V4L* capture );
312 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture );
313
314 static double icvGetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id );
315 static int    icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id, double value );
316
317 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h);
318
319 /***********************   Implementations  ***************************************/
320
321 static int numCameras = 0;
322 static int indexList = 0; 
323
324 #ifdef HAVE_CAMV4L2
325
326 // IOCTL handling for V4L2
327 static int xioctl( int fd, int request, void *arg)
328 {
329
330   int r;
331
332
333   do r = ioctl (fd, request, arg);
334   while (-1 == r && EINTR == errno);
335
336   return r;
337
338 }
339  
340 #endif /* HAVE_CAMV4L2 */
341
342 /* Simple test program: Find number of Video Sources available.
343    Start from 0 and go to MAX_CAMERAS while checking for the device with that name.
344    If it fails on the first attempt of /dev/video0, then check if /dev/video is valid.
345    Returns the global numCameras with the correct value (we hope) */
346
347 static void icvInitCapture_V4L() {
348    int deviceHandle;
349    int CameraNumber;
350    char deviceName[MAX_DEVICE_DRIVER_NAME];
351
352    CameraNumber = 0;
353    while(CameraNumber < MAX_CAMERAS) {
354       /* Print the CameraNumber at the end of the string with a width of one character */
355       sprintf(deviceName, "/dev/video%1d", CameraNumber);
356       /* Test using an open to see if this new device name really does exists. */
357       deviceHandle = open(deviceName, O_RDONLY);
358       if (deviceHandle != -1) {
359          /* This device does indeed exist - add it to the total so far */
360     // add indexList
361     indexList|=(1 << CameraNumber);
362         numCameras++;
363     }        
364     close(deviceHandle);
365       /* Set up to test the next /dev/video source in line */
366       CameraNumber++;
367    } /* End while */
368       
369 }; /* End icvInitCapture_V4L */
370
371 static int
372 try_palette(int fd,
373             struct video_picture *cam_pic,
374             int pal,
375             int depth)
376 {
377   cam_pic->palette = pal;
378   cam_pic->depth = depth;
379   if (ioctl(fd, VIDIOCSPICT, cam_pic) < 0)
380     return 0;
381   if (ioctl(fd, VIDIOCGPICT, cam_pic) < 0)
382     return 0;
383   if (cam_pic->palette == pal)
384     return 1;
385   return 0;
386 }
387
388 #ifdef HAVE_CAMV4L2
389
390 static int try_palette_v4l2(CvCaptureCAM_V4L* capture, unsigned long colorspace)
391 {
392   CLEAR (capture->form);
393
394   capture->form.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
395   capture->form.fmt.pix.pixelformat = colorspace;
396   capture->form.fmt.pix.field       = V4L2_FIELD_ANY;
397   capture->form.fmt.pix.width = DEFAULT_V4L_WIDTH;
398   capture->form.fmt.pix.height = DEFAULT_V4L_HEIGHT;
399   
400   if (-1 == xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form))
401       return -1;
402
403   
404   if (colorspace != capture->form.fmt.pix.pixelformat)
405     return -1;
406   else
407     return 0;
408 }
409
410 #endif /* HAVE_CAMV4L2 */
411
412 static int try_init_v4l(CvCaptureCAM_V4L* capture, char *deviceName)
413 {
414
415   // if detect = -1 then unable to open device
416   // if detect = 0 then detected nothing
417   // if detect = 1 then V4L device 
418   int detect = 0;
419
420
421   // Test device for V4L compability
422
423   /* Test using an open to see if this new device name really does exists. */
424   /* No matter what the name - it still must be opened! */
425   capture->deviceHandle = open(deviceName, O_RDWR);
426
427
428   if (capture->deviceHandle == 0)
429   {
430     detect = -1;
431
432     icvCloseCAM_V4L(capture);
433   }
434   
435   if (detect == 0)
436   {
437     /* Query the newly opened device for its capabilities */
438     if (ioctl(capture->deviceHandle, VIDIOCGCAP, &capture->capability) < 0)
439     {
440       detect = 0;
441
442       icvCloseCAM_V4L(capture);
443     }
444       else
445     {
446       detect = 1;
447     }
448   }
449   
450   return detect;
451
452 }
453
454 #ifdef HAVE_CAMV4L2
455
456 static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName)
457 {
458
459   // if detect = -1 then unable to open device
460   // if detect = 0 then detected nothing
461   // if detect = 1 then V4L2 device 
462   int detect = 0;
463
464
465   // Test device for V4L2 compability
466
467   /* Open and test V4L2 device */
468   capture->deviceHandle = open (deviceName, O_RDWR /* required */ | O_NONBLOCK, 0);
469   
470
471
472   if (capture->deviceHandle == 0)
473   {
474     detect = -1;
475
476     icvCloseCAM_V4L(capture);
477   }
478
479   if (detect == 0)
480   {
481     CLEAR (capture->cap);
482     if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYCAP, &capture->cap))
483     {
484       detect = 0;
485
486       icvCloseCAM_V4L(capture);
487     }
488       else
489     {
490       CLEAR (capture->capability);
491       capture->capability.type = capture->cap.capabilities;
492      
493       /* Query channels number */
494       if (-1 != xioctl (capture->deviceHandle, VIDIOC_G_INPUT, &capture->capability.channels))
495       {
496         detect = 1;
497       }
498     }
499   }
500
501   return detect;
502
503 }
504
505 static int autosetup_capture_mode_v4l2(CvCaptureCAM_V4L* capture)
506 {
507   if (try_palette_v4l2(capture, V4L2_PIX_FMT_BGR24) == 0)
508   {
509     PALETTE_BGR24 = 1;
510   }
511   else
512   if (try_palette_v4l2(capture, V4L2_PIX_FMT_YVU420) == 0)
513   {
514     PALETTE_YVU420 = 1;
515   }
516   else
517   if (try_palette_v4l2(capture, V4L2_PIX_FMT_YUV411P) == 0)
518   {
519     PALETTE_YUV411P = 1;
520   }
521   else
522
523 #ifdef HAVE_JPEG
524 #ifdef __USE_GNU
525       /* support for MJPEG is only available with libjpeg and gcc,
526          because it's use libjepg and fmemopen()
527       */
528   if (try_palette_v4l2(capture, V4L2_PIX_FMT_MJPEG) == 0)
529   {
530     PALETTE_MJPEG = 1;
531   }
532   else
533 #endif
534 #endif
535
536   if (try_palette_v4l2(capture, V4L2_PIX_FMT_YUYV) == 0)
537   {
538     PALETTE_YUYV = 1;
539   }
540   else if (try_palette_v4l2(capture, V4L2_PIX_FMT_UYVY) == 0)
541   {
542     PALETTE_UYVY = 1;
543   }
544   else
545   if (try_palette_v4l2(capture, V4L2_PIX_FMT_SN9C10X) == 0)
546   {
547     CLEAR (capture->compr);
548     if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_JPEGCOMP, &capture->compr)) {
549         perror ("VIDIOC_G_JPEGCOMP");
550         return -1;
551     }
552          
553     capture->compr.quality = 0;
554
555     if (-1 == xioctl (capture->deviceHandle, VIDIOC_S_JPEGCOMP, &capture->compr)) {
556         perror ("VIDIOC_S_JPEGCOMP");
557         return -1;
558     }
559
560     PALETTE_SN9C10X = 1;
561   } else
562   if (try_palette_v4l2(capture, V4L2_PIX_FMT_SBGGR8) == 0)
563   {
564     PALETTE_SBGGR8 = 1;
565   } 
566   else
567   {
568         fprintf(stderr, "HIGHGUI ERROR: V4L2: Pixel format of incoming image is unsupported by OpenCV\n");
569     icvCloseCAM_V4L(capture);
570     return -1;
571   }
572   
573   return 0;
574
575 }
576
577 #endif /* HAVE_CAMV4L2 */
578
579 static int autosetup_capture_mode_v4l(CvCaptureCAM_V4L* capture)
580 {
581
582   if(ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) {
583      fprintf( stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n");
584      icvCloseCAM_V4L(capture);
585      return -1;
586   }
587
588   /* Yet MORE things that might have to be changes with your frame capture card */
589   /* This sets the scale to the center of a 2^16 number */
590   if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_RGB24, 24)) {
591       //printf("negotiated palette RGB24\n");
592   }
593   else if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_YUV420P, 16)) {
594       //printf("negotiated palette YUV420P\n");
595   }
596   else if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_YUV420, 16)) {
597       //printf("negotiated palette YUV420\n");
598   }
599   else if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_YUV411P, 16)) {
600       //printf("negotiated palette YUV420P\n");
601   }
602   else {
603         fprintf(stderr, "HIGHGUI ERROR: V4L: Pixel format of incoming image is unsupported by OpenCV\n");
604     icvCloseCAM_V4L(capture);
605     return -1;
606   }
607
608   return 0;
609
610 }
611
612 #ifdef HAVE_CAMV4L2
613
614 static void v4l2_scan_controls_enumerate_menu(CvCaptureCAM_V4L* capture)
615 {
616 //  printf (" Menu items:\n");
617   CLEAR (capture->querymenu);
618   capture->querymenu.id = capture->queryctrl.id;
619   for (capture->querymenu.index = capture->queryctrl.minimum;
620        (int)capture->querymenu.index <= capture->queryctrl.maximum;
621        capture->querymenu.index++)
622   {
623     if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYMENU,
624                      &capture->querymenu))
625     {
626 //      printf (" %s\n", capture->querymenu.name);
627     } else {
628         perror ("VIDIOC_QUERYMENU");
629     }
630   }
631 }
632
633 static void v4l2_scan_controls(CvCaptureCAM_V4L* capture)
634 {
635
636   __u32 ctrl_id;
637
638   for (ctrl_id = V4L2_CID_BASE;
639        ctrl_id < V4L2_CID_LASTP1;
640        ctrl_id++)
641   {
642
643     /* set the id we will query now */
644     CLEAR (capture->queryctrl);
645     capture->queryctrl.id = ctrl_id;
646
647     if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYCTRL,
648                      &capture->queryctrl))
649     {
650
651       if (capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
652         continue;
653       
654       if (capture->queryctrl.id == V4L2_CID_BRIGHTNESS)
655       {
656         capture->v4l2_brightness = 1;
657         capture->v4l2_brightness_min = capture->queryctrl.minimum;
658         capture->v4l2_brightness_max = capture->queryctrl.maximum;
659       }
660
661       if (capture->queryctrl.id == V4L2_CID_CONTRAST)
662       {
663         capture->v4l2_contrast = 1;
664         capture->v4l2_contrast_min = capture->queryctrl.minimum;
665         capture->v4l2_contrast_max = capture->queryctrl.maximum;
666       }
667
668       if (capture->queryctrl.id == V4L2_CID_SATURATION)
669       {
670         capture->v4l2_saturation = 1;
671         capture->v4l2_saturation_min = capture->queryctrl.minimum;
672         capture->v4l2_saturation_max = capture->queryctrl.maximum;
673       }
674
675       if (capture->queryctrl.id == V4L2_CID_HUE)
676       {
677         capture->v4l2_hue = 1;
678         capture->v4l2_hue_min = capture->queryctrl.minimum;
679         capture->v4l2_hue_max = capture->queryctrl.maximum;
680       }
681
682       if (capture->queryctrl.id == V4L2_CID_GAIN)
683       {
684         capture->v4l2_gain = 1;
685         capture->v4l2_gain_min = capture->queryctrl.minimum;
686         capture->v4l2_gain_max = capture->queryctrl.maximum;
687       }
688
689       if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU)
690         v4l2_scan_controls_enumerate_menu(capture);
691
692     } else {
693     
694       if (errno == EINVAL)
695         continue;
696         
697       perror ("VIDIOC_QUERYCTRL");
698
699     }
700
701   }
702
703   for (ctrl_id = V4L2_CID_PRIVATE_BASE;;ctrl_id++)
704   {
705
706     /* set the id we will query now */
707     CLEAR (capture->queryctrl);
708     capture->queryctrl.id = ctrl_id;
709
710     if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYCTRL,
711                      &capture->queryctrl))
712     {
713
714       if (capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
715         continue;
716
717       if (capture->queryctrl.id == V4L2_CID_BRIGHTNESS)
718       {
719         capture->v4l2_brightness = 1;
720         capture->v4l2_brightness_min = capture->queryctrl.minimum;
721         capture->v4l2_brightness_max = capture->queryctrl.maximum;
722       }
723
724       if (capture->queryctrl.id == V4L2_CID_CONTRAST)
725       {
726         capture->v4l2_contrast = 1;
727         capture->v4l2_contrast_min = capture->queryctrl.minimum;
728         capture->v4l2_contrast_max = capture->queryctrl.maximum;
729       }
730
731       if (capture->queryctrl.id == V4L2_CID_SATURATION)
732       {
733         capture->v4l2_saturation = 1;
734         capture->v4l2_saturation_min = capture->queryctrl.minimum;
735         capture->v4l2_saturation_max = capture->queryctrl.maximum;
736       }
737
738       if (capture->queryctrl.id == V4L2_CID_HUE)
739       {
740         capture->v4l2_hue = 1;
741         capture->v4l2_hue_min = capture->queryctrl.minimum;
742         capture->v4l2_hue_max = capture->queryctrl.maximum;
743       }
744
745       if (capture->queryctrl.id == V4L2_CID_GAIN)
746       {
747         capture->v4l2_gain = 1;
748         capture->v4l2_gain_min = capture->queryctrl.minimum;
749         capture->v4l2_gain_max = capture->queryctrl.maximum;
750       }
751
752       if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU)
753         v4l2_scan_controls_enumerate_menu(capture);
754
755     } else {
756
757       if (errno == EINVAL)
758         break;
759
760       perror ("VIDIOC_QUERYCTRL");
761
762     }
763
764   }
765
766 }
767
768 static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName)
769 {
770    int detect_v4l2 = 0;
771
772    detect_v4l2 = try_init_v4l2(capture, deviceName);
773
774    if (detect_v4l2 != 1) {
775        /* init of the v4l2 device is not OK */
776        return -1;
777    }
778
779    /* starting from here, we assume we are in V4L2 mode */
780    V4L2_SUPPORT = 1;
781
782    /* Init V4L2 control variables */
783    capture->v4l2_brightness = 0;
784    capture->v4l2_contrast = 0;
785    capture->v4l2_saturation = 0;
786    capture->v4l2_hue = 0;
787    capture->v4l2_gain = 0;
788
789    capture->v4l2_brightness_min = 0;
790    capture->v4l2_contrast_min = 0;
791    capture->v4l2_saturation_min = 0;
792    capture->v4l2_hue_min = 0;
793    capture->v4l2_gain_min = 0;
794
795    capture->v4l2_brightness_max = 0;
796    capture->v4l2_contrast_max = 0;
797    capture->v4l2_saturation_max = 0;
798    capture->v4l2_hue_max = 0;
799    capture->v4l2_gain_max = 0;
800      
801    /* Scan V4L2 controls */
802    v4l2_scan_controls(capture);
803
804    if ((capture->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
805       /* Nope. */
806       fprintf( stderr, "HIGHGUI ERROR: V4L2: device %s is unable to capture video memory.\n",deviceName);
807       icvCloseCAM_V4L(capture);
808       return -1;
809    }
810
811    /* The following code sets the CHANNEL_NUMBER of the video input.  Some video sources
812    have sub "Channel Numbers".  For a typical V4L TV capture card, this is usually 1.
813    I myself am using a simple NTSC video input capture card that uses the value of 1.
814    If you are not in North America or have a different video standard, you WILL have to change
815    the following settings and recompile/reinstall.  This set of settings is based on
816    the most commonly encountered input video source types (like my bttv card) */
817
818    if(capture->inp.index > 0) {
819        CLEAR (capture->inp);
820        capture->inp.index = CHANNEL_NUMBER;
821        /* Set only channel number to CHANNEL_NUMBER */
822        /* V4L2 have a status field from selected video mode */
823        if (-1 == xioctl (capture->deviceHandle, VIDIOC_ENUMINPUT, &capture->inp))
824        {
825          fprintf (stderr, "HIGHGUI ERROR: V4L2: Aren't able to set channel number\n");
826          icvCloseCAM_V4L (capture);
827          return -1;
828        }
829    } /* End if */
830
831    /* Find Window info */
832    CLEAR (capture->form);
833    capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
834         
835    if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
836        fprintf( stderr, "HIGHGUI ERROR: V4L2: Could not obtain specifics of capture window.\n\n");
837        icvCloseCAM_V4L(capture);
838        return -1;
839    }
840
841    if (V4L2_SUPPORT == 0)
842    {
843    }
844
845    if (autosetup_capture_mode_v4l2(capture) == -1)
846        return -1;
847
848    /* default capture size is already set */
849 //   icvSetVideoSize(capture, DEFAULT_V4L_WIDTH, DEFAULT_V4L_HEIGHT);
850
851    unsigned int min;
852
853    /* Buggy driver paranoia. */
854    min = capture->form.fmt.pix.width * 2;
855
856    if (capture->form.fmt.pix.bytesperline < min)
857        capture->form.fmt.pix.bytesperline = min;
858
859    min = capture->form.fmt.pix.bytesperline * capture->form.fmt.pix.height;
860  
861    if (capture->form.fmt.pix.sizeimage < min)
862        capture->form.fmt.pix.sizeimage = min;
863
864    CLEAR (capture->req);
865    
866    unsigned int buffer_number = 4;
867
868    try_again:
869    
870    capture->req.count = buffer_number;
871    capture->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
872    capture->req.memory = V4L2_MEMORY_MMAP;
873
874    if (-1 == xioctl (capture->deviceHandle, VIDIOC_REQBUFS, &capture->req))
875    {
876        if (EINVAL == errno)
877        {
878          fprintf (stderr, "%s does not support memory mapping\n", deviceName);
879        } else {
880          perror ("VIDIOC_REQBUFS");
881        }
882        /* free capture, and returns an error code */
883        icvCloseCAM_V4L (capture);
884        return -1;
885    }
886
887    if (capture->req.count < buffer_number)
888    {
889        if (buffer_number == 1)
890        {
891            fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName);
892
893            /* free capture, and returns an error code */
894            icvCloseCAM_V4L (capture);
895            return -1;
896        } else {
897          buffer_number--;
898          
899          goto try_again;
900        }
901    }
902
903    for (n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
904    {
905        struct v4l2_buffer buf;
906
907        CLEAR (buf);
908
909        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
910        buf.memory = V4L2_MEMORY_MMAP;
911        buf.index = n_buffers;
912
913        if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYBUF, &buf)) {
914            perror ("VIDIOC_QUERYBUF");
915        
916            /* free capture, and returns an error code */
917            icvCloseCAM_V4L (capture);
918            return -1;
919        }
920
921        capture->buffers[n_buffers].length = buf.length;
922        capture->buffers[n_buffers].start =
923          mmap (NULL /* start anywhere */,
924                buf.length,
925                PROT_READ | PROT_WRITE /* required */,
926                MAP_SHARED /* recommended */,
927                capture->deviceHandle, buf.m.offset);
928
929        if (MAP_FAILED == capture->buffers[n_buffers].start) {
930            perror ("mmap");
931        
932            /* free capture, and returns an error code */
933            icvCloseCAM_V4L (capture);
934            return -1;
935        }
936    }
937
938    /* Set up Image data */
939    cvInitImageHeader( &capture->frame,
940                       cvSize( capture->captureWindow.width,
941                               capture->captureWindow.height ),
942                       IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
943    /* Allocate space for RGBA data */
944    capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
945    
946    return 1;
947 }; /* End _capture_V4L2 */
948
949 #endif /* HAVE_CAMV4L2 */
950
951 static int _capture_V4L (CvCaptureCAM_V4L *capture, char *deviceName)
952 {
953    int detect_v4l = 0;
954
955    detect_v4l = try_init_v4l(capture, deviceName);
956
957    if ((detect_v4l == -1)
958        )
959    {
960      fprintf (stderr, "HIGHGUI ERROR: V4L"
961               ": device %s: Unable to open for READ ONLY\n", deviceName);
962
963      return -1;
964    }
965
966    if ((detect_v4l <= 0)
967        )
968    {
969      fprintf (stderr, "HIGHGUI ERROR: V4L"
970               ": device %s: Unable to query number of channels\n", deviceName);
971
972      return -1;
973    }
974    
975    {
976      if ((capture->capability.type & VID_TYPE_CAPTURE) == 0) {
977        /* Nope. */
978        fprintf( stderr, "HIGHGUI ERROR: V4L: "
979                 "device %s is unable to capture video memory.\n",deviceName);
980        icvCloseCAM_V4L(capture);
981        return -1;
982      }
983
984    }
985
986
987    /* The following code sets the CHANNEL_NUMBER of the video input.  Some video sources
988    have sub "Channel Numbers".  For a typical V4L TV capture card, this is usually 1.
989    I myself am using a simple NTSC video input capture card that uses the value of 1.
990    If you are not in North America or have a different video standard, you WILL have to change
991    the following settings and recompile/reinstall.  This set of settings is based on
992    the most commonly encountered input video source types (like my bttv card) */
993
994    {
995
996      if(capture->capability.channels>0) {
997
998        struct video_channel selectedChannel;
999
1000        selectedChannel.channel=CHANNEL_NUMBER;
1001        if (ioctl(capture->deviceHandle, VIDIOCGCHAN , &selectedChannel) != -1) {
1002           /* set the video mode to ( VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM) */
1003 //           selectedChannel.norm = VIDEO_MODE_NTSC;
1004           if (ioctl(capture->deviceHandle, VIDIOCSCHAN , &selectedChannel) == -1) {
1005              /* Could not set selected channel - Oh well */
1006              //printf("\n%d, %s not NTSC capable.\n",selectedChannel.channel, selectedChannel.name);
1007           } /* End if */
1008        } /* End if */ 
1009      } /* End if */
1010
1011    }
1012
1013    {
1014
1015      if(ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) == -1) {
1016        fprintf( stderr, "HIGHGUI ERROR: V4L: "
1017                 "Could not obtain specifics of capture window.\n\n");
1018        icvCloseCAM_V4L(capture);
1019        return -1;
1020      }
1021
1022    }
1023
1024    {
1025
1026      if (autosetup_capture_mode_v4l(capture) == -1)
1027        return -1;
1028
1029    }
1030
1031    {
1032
1033      ioctl(capture->deviceHandle, VIDIOCGMBUF, &capture->memoryBuffer);
1034      capture->memoryMap  = (char *)mmap(0, 
1035                                    capture->memoryBuffer.size,
1036                                    PROT_READ | PROT_WRITE,
1037                                    MAP_SHARED,
1038                                    capture->deviceHandle,
1039                                    0);
1040      if (capture->memoryMap == MAP_FAILED) {
1041         fprintf( stderr, "HIGHGUI ERROR: V4L: Mapping Memmory from video source error: %s\n", strerror(errno));
1042         icvCloseCAM_V4L(capture);
1043      }
1044      
1045      /* Set up video_mmap structure pointing to this memory mapped area so each image may be
1046         retrieved from an index value */
1047      capture->mmaps = (struct video_mmap *)
1048                  (malloc(capture->memoryBuffer.frames * sizeof(struct video_mmap)));
1049      if (!capture->mmaps) {
1050         fprintf( stderr, "HIGHGUI ERROR: V4L: Could not memory map video frames.\n");
1051         icvCloseCAM_V4L(capture);
1052         return -1;
1053      }
1054
1055    }
1056
1057    /* Set up Image data */
1058    cvInitImageHeader( &capture->frame,
1059                       cvSize( capture->captureWindow.width,
1060                               capture->captureWindow.height ),
1061                       IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
1062    /* Allocate space for RGBA data */
1063    capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1064    
1065    return 1;
1066 }; /* End _capture_V4L */
1067
1068 static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index)
1069 {
1070    static int autoindex=0;
1071
1072    char deviceName[MAX_DEVICE_DRIVER_NAME];
1073    
1074    
1075    if (!numCameras)
1076       icvInitCapture_V4L(); /* Havent called icvInitCapture yet - do it now! */
1077    if (!numCameras)
1078      return NULL; /* Are there any /dev/video input sources? */
1079
1080    //search index in indexList
1081    if ( (index>-1) && ! ((1 << index) & indexList) ) 
1082    {
1083      fprintf( stderr, "HIGHGUI ERROR: V4L: index %d is not correct!\n",index);
1084      return NULL; /* Did someone ask for not correct video source number? */
1085    }
1086    /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL
1087       the handles for V4L processing */
1088    CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L));
1089    if (!capture) {
1090       fprintf( stderr, "HIGHGUI ERROR: V4L: Could not allocate memory for capture process.\n");
1091       return NULL;
1092    }
1093    /* Select camera, or rather, V4L video source */
1094    if (index<0) { // Asking for the first device available 
1095      for (; autoindex<MAX_CAMERAS;autoindex++)
1096     if (indexList & (1<<autoindex))
1097         break;
1098      if (autoindex==MAX_CAMERAS)
1099     return NULL; 
1100      index=autoindex;
1101      autoindex++;// i can recall icvOpenCAM_V4l with index=-1 for next camera
1102    }
1103    /* Print the CameraNumber at the end of the string with a width of one character */
1104    sprintf(deviceName, "/dev/video%1d", index);
1105    
1106    /* w/o memset some parts  arent initialized - AKA: Fill it with zeros so it is clean */
1107    memset(capture,0,sizeof(CvCaptureCAM_V4L));
1108    /* Present the routines needed for V4L funtionality.  They are inserted as part of
1109       the standard set of cv calls promoting transparency.  "Vector Table" insertion. */
1110    capture->FirstCapture = 1;
1111    
1112 #ifdef HAVE_CAMV4L2
1113    if (_capture_V4L2 (capture, deviceName) == -1) {
1114        icvCloseCAM_V4L(capture);
1115        V4L2_SUPPORT = 0;
1116 #endif  /* HAVE_CAMV4L2 */
1117        if (_capture_V4L (capture, deviceName) == -1) {
1118            icvCloseCAM_V4L(capture);
1119            return NULL;
1120        }
1121 #ifdef HAVE_CAMV4L2
1122    } else {
1123        V4L2_SUPPORT = 1;
1124    }
1125 #endif  /* HAVE_CAMV4L2 */
1126
1127    return capture;
1128 }; /* End icvOpenCAM_V4L */
1129
1130 #ifdef HAVE_CAMV4L2
1131
1132 static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
1133     struct v4l2_buffer buf;
1134
1135     CLEAR (buf);
1136
1137     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1138     buf.memory = V4L2_MEMORY_MMAP;
1139
1140     if (-1 == xioctl (capture->deviceHandle, VIDIOC_DQBUF, &buf)) {
1141         switch (errno) {
1142         case EAGAIN:
1143             return 0;
1144
1145         case EIO:
1146             /* Could ignore EIO, see spec. */
1147
1148             /* fall through */
1149
1150         default:
1151             /* display the error and stop processing */
1152             perror ("VIDIOC_DQBUF");
1153             return 1;
1154         }
1155    }
1156
1157    assert(buf.index < capture->req.count);
1158    
1159    capture->bufferIndex = buf.index;
1160
1161    if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf))
1162        perror ("VIDIOC_QBUF");
1163
1164    return 1;
1165 }
1166
1167 static void mainloop_v4l2(CvCaptureCAM_V4L* capture) {
1168     unsigned int count;
1169
1170     count = 1;
1171
1172     while (count-- > 0) {
1173         for (;;) {
1174             fd_set fds;
1175             struct timeval tv;
1176             int r;
1177
1178             FD_ZERO (&fds);
1179             FD_SET (capture->deviceHandle, &fds);
1180
1181             /* Timeout. */
1182             tv.tv_sec = 2;
1183             tv.tv_usec = 0;
1184
1185             r = select (capture->deviceHandle+1, &fds, NULL, NULL, &tv);
1186
1187             if (-1 == r) {
1188                 if (EINTR == errno)
1189                     continue;
1190
1191                 perror ("select");
1192             }
1193
1194             if (0 == r) {
1195                 fprintf (stderr, "select timeout\n");
1196
1197                 /* end the infinite loop */
1198                 break;
1199             }
1200
1201             if (read_frame_v4l2 (capture))
1202                 break;
1203         }
1204     }
1205 }
1206
1207 #endif /* HAVE_CAMV4L2 */
1208
1209 static int icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) {
1210
1211    if (capture->FirstCapture) { 
1212       /* Some general initialization must take place the first time through */
1213
1214       /* This is just a technicality, but all buffers must be filled up before any
1215          staggered SYNC is applied.  SO, filler up. (see V4L HowTo) */
1216
1217 #ifdef HAVE_CAMV4L2
1218
1219       if (V4L2_SUPPORT == 1)
1220       {
1221
1222         for (capture->bufferIndex = 0;
1223              capture->bufferIndex < ((int)capture->req.count);
1224              ++capture->bufferIndex)
1225         {
1226
1227           struct v4l2_buffer buf;
1228
1229           CLEAR (buf);
1230
1231           buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1232           buf.memory      = V4L2_MEMORY_MMAP;
1233           buf.index       = (unsigned long)capture->bufferIndex;
1234
1235           if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) {
1236               perror ("VIDIOC_QBUF");
1237               return 0;
1238           }
1239         }
1240
1241         /* enable the streaming */
1242         capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1243         if (-1 == xioctl (capture->deviceHandle, VIDIOC_STREAMON,
1244                           &capture->type)) {
1245             /* error enabling the stream */
1246             perror ("VIDIOC_STREAMON");
1247             return 0;
1248         }
1249       } else
1250 #endif /* HAVE_CAMV4L2 */
1251       {
1252
1253         for (capture->bufferIndex = 0;
1254          capture->bufferIndex < (capture->memoryBuffer.frames-1);
1255          ++capture->bufferIndex) {
1256
1257           capture->mmaps[capture->bufferIndex].frame  = capture->bufferIndex;
1258           capture->mmaps[capture->bufferIndex].width  = capture->captureWindow.width;
1259           capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1260           capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1261
1262           if (ioctl(capture->deviceHandle, VIDIOCMCAPTURE, &capture->mmaps[capture->bufferIndex]) == -1) {
1263             fprintf( stderr, "HIGHGUI ERROR: V4L: Initial Capture Error: Unable to load initial memory buffers.\n");
1264             return 0;
1265           }
1266         }
1267       
1268       }
1269
1270       /* preparation is ok */
1271       capture->FirstCapture = 0;
1272    }
1273
1274 #ifdef HAVE_CAMV4L2
1275
1276    if (V4L2_SUPPORT == 1)
1277    {
1278
1279      mainloop_v4l2(capture);
1280
1281    } else
1282 #endif /* HAVE_CAMV4L2 */
1283    {
1284    
1285      capture->mmaps[capture->bufferIndex].frame  = capture->bufferIndex;
1286      capture->mmaps[capture->bufferIndex].width  = capture->captureWindow.width;
1287      capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1288      capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1289
1290      if (ioctl (capture->deviceHandle, VIDIOCMCAPTURE,
1291                 &capture->mmaps[capture->bufferIndex]) == -1) {
1292          /* capture is on the way, so just exit */
1293          return 1;
1294      }
1295
1296      ++capture->bufferIndex;
1297      if (capture->bufferIndex == capture->memoryBuffer.frames) {
1298         capture->bufferIndex = 0;
1299      }
1300
1301    }
1302
1303    return(1);
1304 }
1305
1306 /*
1307  * Turn a YUV4:2:0 block into an RGB block
1308  *
1309  * Video4Linux seems to use the blue, green, red channel
1310  * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
1311  *
1312  * Color space conversion coefficients taken from the excellent
1313  * http://www.inforamp.net/~poynton/ColorFAQ.html
1314  * In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
1315  * Y values are given for all 4 pixels, but the U (Pb)
1316  * and V (Pr) are assumed constant over the 2x2 block.
1317  *
1318  * To avoid floating point arithmetic, the color conversion
1319  * coefficients are scaled into 16.16 fixed-point integers.
1320  * They were determined as follows:
1321  *
1322  *  double brightness = 1.0;  (0->black; 1->full scale) 
1323  *  double saturation = 1.0;  (0->greyscale; 1->full color)
1324  *  double fixScale = brightness * 256 * 256;
1325  *  int rvScale = (int)(1.402 * saturation * fixScale);
1326  *  int guScale = (int)(-0.344136 * saturation * fixScale);
1327  *  int gvScale = (int)(-0.714136 * saturation * fixScale);
1328  *  int buScale = (int)(1.772 * saturation * fixScale);
1329  *  int yScale = (int)(fixScale);   
1330  */
1331
1332 /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
1333 #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
1334
1335 static inline void
1336 move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
1337            int rowPixels, unsigned char * rgb)
1338 {
1339     const int rvScale = 91881;
1340     const int guScale = -22553;
1341     const int gvScale = -46801;
1342     const int buScale = 116129;
1343     const int yScale  = 65536;
1344     int r, g, b;
1345
1346     g = guScale * u + gvScale * v;
1347 //  if (force_rgb) {
1348 //      r = buScale * u;
1349 //      b = rvScale * v;
1350 //  } else {
1351         r = rvScale * v;
1352         b = buScale * u;
1353 //  }
1354
1355     yTL *= yScale; yTR *= yScale;
1356     yBL *= yScale; yBR *= yScale;
1357
1358     /* Write out top two pixels */
1359     rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL);
1360     rgb[2] = LIMIT(r+yTL);
1361
1362     rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR);
1363     rgb[5] = LIMIT(r+yTR);
1364
1365     /* Skip down to next line to write out bottom two pixels */
1366     rgb += 3 * rowPixels;
1367     rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL);
1368     rgb[2] = LIMIT(r+yBL);
1369
1370     rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR);
1371     rgb[5] = LIMIT(r+yBR);
1372 }
1373
1374 static inline void
1375 move_411_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
1376            int rowPixels, unsigned char * rgb)
1377 {
1378     const int rvScale = 91881;
1379     const int guScale = -22553;
1380     const int gvScale = -46801;
1381     const int buScale = 116129;
1382     const int yScale  = 65536;
1383     int r, g, b;
1384
1385     g = guScale * u + gvScale * v;
1386 //  if (force_rgb) {
1387 //      r = buScale * u;
1388 //      b = rvScale * v;
1389 //  } else {
1390         r = rvScale * v;
1391         b = buScale * u;
1392 //  }
1393
1394     yTL *= yScale; yTR *= yScale;
1395     yBL *= yScale; yBR *= yScale;
1396
1397     /* Write out top two first pixels */
1398     rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL);
1399     rgb[2] = LIMIT(r+yTL);
1400
1401     rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR);
1402     rgb[5] = LIMIT(r+yTR);
1403
1404     /* Write out top two last pixels */
1405     rgb += 6;
1406     rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL);
1407     rgb[2] = LIMIT(r+yBL);
1408
1409     rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR);
1410     rgb[5] = LIMIT(r+yBR);
1411 }
1412
1413 // Consider a YUV420P image of 8x2 pixels.
1414 //
1415 // A plane of Y values    A B C D E F G H
1416 //                        I J K L M N O P
1417 //
1418 // A plane of U values    1   2   3   4 
1419 // A plane of V values    1   2   3   4 ....
1420 //
1421 // The U1/V1 samples correspond to the ABIJ pixels.
1422 //     U2/V2 samples correspond to the CDKL pixels.
1423 //
1424 /* Converts from planar YUV420P to RGB24. */
1425 static void 
1426 yuv420p_to_rgb24(int width, int height,
1427            unsigned char *pIn0, unsigned char *pOut0)
1428 {
1429     const int numpix = width * height;
1430     const int bytes = 24 >> 3;
1431     int i, j, y00, y01, y10, y11, u, v;
1432     unsigned char *pY = pIn0;
1433     unsigned char *pU = pY + numpix;
1434     unsigned char *pV = pU + numpix / 4;
1435     unsigned char *pOut = pOut0;
1436
1437     for (j = 0; j <= height - 2; j += 2) {
1438         for (i = 0; i <= width - 2; i += 2) {
1439             y00 = *pY;
1440             y01 = *(pY + 1);
1441             y10 = *(pY + width);
1442             y11 = *(pY + width + 1);
1443             u = (*pU++) - 128;
1444             v = (*pV++) - 128;
1445
1446             move_420_block(y00, y01, y10, y11, u, v,
1447                        width, pOut);
1448     
1449             pY += 2;
1450             pOut += 2 * bytes;
1451
1452         }
1453         pY += width;
1454         pOut += width * bytes;
1455     }
1456 }
1457
1458 // Consider a YUV420 image of 6x2 pixels.
1459 //
1460 // A B C D U1 U2
1461 // I J K L V1 V2
1462 //
1463 // The U1/V1 samples correspond to the ABIJ pixels.
1464 //     U2/V2 samples correspond to the CDKL pixels.
1465 //
1466 /* Converts from interlaced YUV420 to RGB24. */
1467 /* [FD] untested... */
1468 static void 
1469 yuv420_to_rgb24(int width, int height,
1470         unsigned char *pIn0, unsigned char *pOut0)
1471 {
1472     const int bytes = 24 >> 3;
1473     int i, j, y00, y01, y10, y11, u, v;
1474     unsigned char *pY = pIn0;
1475     unsigned char *pU = pY + 4;
1476     unsigned char *pV = pU + width;
1477     unsigned char *pOut = pOut0;
1478
1479     for (j = 0; j <= height - 2; j += 2) {
1480         for (i = 0; i <= width - 4; i += 4) {
1481             y00 = *pY;
1482             y01 = *(pY + 1);
1483             y10 = *(pY + width);
1484             y11 = *(pY + width + 1);
1485             u = (*pU++) - 128;
1486             v = (*pV++) - 128;
1487
1488             move_420_block(y00, y01, y10, y11, u, v,
1489                        width, pOut);
1490     
1491             pY += 2;
1492             pOut += 2 * bytes;
1493
1494             y00 = *pY;
1495             y01 = *(pY + 1);
1496             y10 = *(pY + width);
1497             y11 = *(pY + width + 1);
1498             u = (*pU++) - 128;
1499             v = (*pV++) - 128;
1500
1501             move_420_block(y00, y01, y10, y11, u, v,
1502                        width, pOut);
1503     
1504             pY += 4; // skip UV
1505             pOut += 2 * bytes;
1506
1507         }
1508         pY += width;
1509         pOut += width * bytes;
1510     }
1511 }
1512
1513 // Consider a YUV411P image of 8x2 pixels.
1514 //
1515 // A plane of Y values as before.
1516 //
1517 // A plane of U values    1       2
1518 //                        3       4
1519 //
1520 // A plane of V values    1       2
1521 //                        3       4
1522 //
1523 // The U1/V1 samples correspond to the ABCD pixels.
1524 //     U2/V2 samples correspond to the EFGH pixels.
1525 //
1526 /* Converts from planar YUV411P to RGB24. */
1527 /* [FD] untested... */
1528 static void 
1529 yuv411p_to_rgb24(int width, int height,
1530            unsigned char *pIn0, unsigned char *pOut0)
1531 {
1532     const int numpix = width * height;
1533     const int bytes = 24 >> 3;
1534     int i, j, y00, y01, y10, y11, u, v;
1535     unsigned char *pY = pIn0;
1536     unsigned char *pU = pY + numpix;
1537     unsigned char *pV = pU + numpix / 4;
1538     unsigned char *pOut = pOut0;
1539
1540     for (j = 0; j <= height; j++) {
1541         for (i = 0; i <= width - 4; i += 4) {
1542             y00 = *pY;
1543             y01 = *(pY + 1);
1544             y10 = *(pY + 2);
1545             y11 = *(pY + 3);
1546             u = (*pU++) - 128;
1547             v = (*pV++) - 128;
1548
1549             move_411_block(y00, y01, y10, y11, u, v,
1550                        width, pOut);
1551     
1552             pY += 4;
1553             pOut += 4 * bytes;
1554
1555         }
1556     }
1557 }
1558
1559 /* convert from 4:2:2 YUYV interlaced to RGB24 */
1560 /* based on ccvt_yuyv_bgr32() from camstream */
1561 #define SAT(c) \
1562         if (c & (~255)) { if (c < 0) c = 0; else c = 255; }
1563 static void 
1564 yuyv_to_rgb24 (int width, int height, unsigned char *src, unsigned char *dst)
1565 {
1566    unsigned char *s;
1567    unsigned char *d;
1568    int l, c;
1569    int r, g, b, cr, cg, cb, y1, y2;
1570    
1571    l = height;
1572    s = src;
1573    d = dst;
1574    while (l--) {
1575       c = width >> 1;
1576       while (c--) {
1577          y1 = *s++;
1578          cb = ((*s - 128) * 454) >> 8;
1579          cg = (*s++ - 128) * 88;
1580          y2 = *s++;
1581          cr = ((*s - 128) * 359) >> 8;
1582          cg = (cg + (*s++ - 128) * 183) >> 8;
1583
1584          r = y1 + cr;
1585          b = y1 + cb;
1586          g = y1 - cg;
1587          SAT(r);
1588          SAT(g);
1589          SAT(b);
1590
1591          *d++ = b;
1592          *d++ = g;
1593          *d++ = r;
1594
1595          r = y2 + cr;
1596          b = y2 + cb;
1597          g = y2 - cg;
1598          SAT(r);
1599          SAT(g);
1600          SAT(b);
1601
1602          *d++ = b;
1603          *d++ = g;
1604          *d++ = r;
1605       }
1606    }
1607 }
1608
1609 static void 
1610 uyvy_to_rgb24 (int width, int height, unsigned char *src, unsigned char *dst)
1611 {
1612    unsigned char *s;
1613    unsigned char *d;
1614    int l, c;
1615    int r, g, b, cr, cg, cb, y1, y2;
1616    
1617    l = height;
1618    s = src;
1619    d = dst;
1620    while (l--) {
1621       c = width >> 1;
1622       while (c--) {
1623          cb = ((*s - 128) * 454) >> 8;
1624          cg = (*s++ - 128) * 88;
1625          y1 = *s++;
1626          cr = ((*s - 128) * 359) >> 8;
1627          cg = (cg + (*s++ - 128) * 183) >> 8;
1628          y2 = *s++;
1629
1630          r = y1 + cr;
1631          b = y1 + cb;
1632          g = y1 - cg;
1633          SAT(r);
1634          SAT(g);
1635          SAT(b);
1636
1637          *d++ = b;
1638          *d++ = g;
1639          *d++ = r;
1640
1641          r = y2 + cr;
1642          b = y2 + cb;
1643          g = y2 - cg;
1644          SAT(r);
1645          SAT(g);
1646          SAT(b);
1647
1648          *d++ = b;
1649          *d++ = g;
1650          *d++ = r;
1651       }
1652    }
1653 }
1654
1655 #ifdef HAVE_JPEG
1656 #ifdef __USE_GNU
1657 /* support for MJPEG is only available with libjpeg and gcc,
1658    because it's use libjepg and fmemopen()
1659 */
1660
1661 /* include headers to be able to use libjpeg and GrFmtJpegReader */
1662 #include "grfmts.h"
1663 extern "C" {
1664 #include "jpeglib.h"
1665 }
1666
1667 /* define a new class for using fmemopen() instead of fopen() */
1668 class MyMJpegReader : public GrFmtJpegReader {
1669 public:
1670     MyMJpegReader (unsigned char *src, size_t src_size);
1671     bool  ReadHeader ();
1672 protected:
1673     unsigned char *my_src;
1674     size_t my_src_size;
1675 };
1676
1677 /////////////////////// Error processing /////////////////////
1678
1679 typedef struct GrFmtJpegErrorMgr
1680 {
1681     struct jpeg_error_mgr pub;    /* "parent" structure */
1682     jmp_buf setjmp_buffer;        /* jump label */
1683 }
1684 GrFmtJpegErrorMgr;
1685
1686
1687 METHODDEF(void)
1688 error_exit( j_common_ptr cinfo )
1689 {
1690     GrFmtJpegErrorMgr* err_mgr = (GrFmtJpegErrorMgr*)(cinfo->err);
1691     
1692     /* Return control to the setjmp point */
1693     longjmp( err_mgr->setjmp_buffer, 1 );
1694 }
1695
1696 /////////////////////// MyMJpegReader ///////////////////
1697
1698 /* constructor just call the parent constructor, but without real filename */
1699 MyMJpegReader::MyMJpegReader (unsigned char *src, size_t src_size)
1700     : GrFmtJpegReader ("/dev/null") {
1701     /* memorize the given src memory area, with it's size */
1702     my_src = src;
1703     my_src_size = src_size;
1704 }
1705
1706 /* 
1707    MyMJpegReader::ReadHeader is almost like GrFmtJpegReader::ReadHeader,
1708    just use fmemopen() instead of fopen()
1709 */
1710 bool  MyMJpegReader::ReadHeader () {
1711     bool result = false;
1712     Close();
1713
1714     jpeg_decompress_struct* cinfo = new jpeg_decompress_struct;
1715     GrFmtJpegErrorMgr* jerr = new GrFmtJpegErrorMgr;
1716
1717     cinfo->err = jpeg_std_error(&jerr->pub);
1718     jerr->pub.error_exit = error_exit;
1719
1720     m_cinfo = cinfo;
1721     m_jerr = jerr;
1722
1723     if( setjmp( jerr->setjmp_buffer ) == 0 )
1724     {
1725         jpeg_create_decompress( cinfo );
1726
1727         m_f = fmemopen( my_src, my_src_size, "rb" );
1728         if( m_f )
1729         {
1730             jpeg_stdio_src( cinfo, m_f );
1731             jpeg_read_header( cinfo, TRUE );
1732
1733             m_width = cinfo->image_width;
1734             m_height = cinfo->image_height;
1735             m_iscolor = cinfo->num_components > 1;
1736
1737             result = true;
1738         }
1739     }
1740
1741     if( !result )
1742         Close();
1743
1744     return result;
1745 }
1746
1747 /* convert from mjpeg to rgb24 */
1748 static void 
1749 mjpeg_to_rgb24 (int width, int height,
1750                 unsigned char *src, int length,
1751                 unsigned char *dst)
1752 {
1753     /* use a MyMJpegReader reader for doing the conversion */
1754     MyMJpegReader* reader = 0;
1755     reader = new MyMJpegReader (src, length);
1756     reader->ReadHeader ();
1757     reader->ReadData (dst, width * 3, 1 );
1758     delete reader;
1759
1760 }
1761
1762 #endif
1763 #endif
1764
1765 /*
1766  * BAYER2RGB24 ROUTINE TAKEN FROM:
1767  *
1768  * Sonix SN9C10x based webcam basic I/F routines
1769  * Takafumi Mizuno <taka-qce@ls-a.jp>
1770  *
1771  */
1772
1773 void bayer2rgb24(long int WIDTH, long int HEIGHT, unsigned char *src, unsigned char *dst)
1774 {
1775     long int i;
1776     unsigned char *rawpt, *scanpt;
1777     long int size;
1778
1779     rawpt = src;
1780     scanpt = dst;
1781     size = WIDTH*HEIGHT;
1782
1783     for ( i = 0; i < size; i++ ) {
1784   if ( (i/WIDTH) % 2 == 0 ) {
1785       if ( (i % 2) == 0 ) {
1786     /* B */
1787     if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
1788         *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
1789          *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;  /* R */
1790         *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
1791          *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;      /* G */
1792         *scanpt++ = *rawpt;                                     /* B */
1793     } else {
1794         /* first line or left column */
1795         *scanpt++ = *(rawpt+WIDTH+1);           /* R */
1796         *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;      /* G */
1797         *scanpt++ = *rawpt;                             /* B */
1798     }
1799       } else {
1800     /* (B)G */
1801     if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
1802         *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;  /* R */
1803         *scanpt++ = *rawpt;                                     /* G */
1804         *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;          /* B */
1805     } else {
1806         /* first line or right column */
1807         *scanpt++ = *(rawpt+WIDTH);     /* R */
1808         *scanpt++ = *rawpt;             /* G */
1809         *scanpt++ = *(rawpt-1); /* B */
1810     }
1811       }
1812   } else {
1813       if ( (i % 2) == 0 ) {
1814     /* G(R) */
1815     if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
1816         *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;          /* R */
1817         *scanpt++ = *rawpt;                                     /* G */
1818         *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;  /* B */
1819     } else {
1820         /* bottom line or left column */
1821         *scanpt++ = *(rawpt+1);         /* R */
1822         *scanpt++ = *rawpt;                     /* G */
1823         *scanpt++ = *(rawpt-WIDTH);             /* B */
1824     }
1825       } else {
1826     /* R */
1827     if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
1828         *scanpt++ = *rawpt;                                     /* R */
1829         *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
1830          *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;      /* G */
1831         *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
1832          *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;  /* B */
1833     } else {
1834         /* bottom line or right column */
1835         *scanpt++ = *rawpt;                             /* R */
1836         *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;      /* G */
1837         *scanpt++ = *(rawpt-WIDTH-1);           /* B */
1838     }
1839       }
1840   }
1841   rawpt++;
1842     }
1843
1844 }
1845
1846
1847 #define CLAMP(x)        ((x)<0?0:((x)>255)?255:(x))
1848
1849 typedef struct {
1850   int is_abs;
1851   int len;
1852   int val;
1853 } code_table_t;
1854
1855
1856 /* local storage */
1857 static code_table_t table[256];
1858 static int init_done = 0;
1859
1860
1861 /*
1862   sonix_decompress_init
1863   =====================
1864     pre-calculates a locally stored table for efficient huffman-decoding.
1865
1866   Each entry at index x in the table represents the codeword
1867   present at the MSB of byte x.
1868
1869 */
1870 void sonix_decompress_init(void)
1871 {
1872   int i;
1873   int is_abs, val, len;
1874
1875   for (i = 0; i < 256; i++) {
1876     is_abs = 0;
1877     val = 0;
1878     len = 0;
1879     if ((i & 0x80) == 0) {
1880       /* code 0 */
1881       val = 0;
1882       len = 1;
1883     }
1884     else if ((i & 0xE0) == 0x80) {
1885       /* code 100 */
1886       val = +4;
1887       len = 3;
1888     }
1889     else if ((i & 0xE0) == 0xA0) {
1890       /* code 101 */
1891       val = -4;
1892       len = 3;
1893     }
1894     else if ((i & 0xF0) == 0xD0) {
1895       /* code 1101 */
1896       val = +11;
1897       len = 4;
1898     }
1899     else if ((i & 0xF0) == 0xF0) {
1900       /* code 1111 */
1901       val = -11;
1902       len = 4;
1903     }
1904     else if ((i & 0xF8) == 0xC8) {
1905       /* code 11001 */
1906       val = +20;
1907       len = 5;
1908     }
1909     else if ((i & 0xFC) == 0xC0) {
1910       /* code 110000 */
1911       val = -20;
1912       len = 6;
1913     }
1914     else if ((i & 0xFC) == 0xC4) {
1915       /* code 110001xx: unknown */
1916       val = 0;
1917       len = 8;
1918     }
1919     else if ((i & 0xF0) == 0xE0) {
1920       /* code 1110xxxx */
1921       is_abs = 1;
1922       val = (i & 0x0F) << 4;
1923       len = 8;
1924     }
1925     table[i].is_abs = is_abs;
1926     table[i].val = val;
1927     table[i].len = len;
1928   }
1929
1930   init_done = 1;
1931 }
1932
1933
1934 /*
1935   sonix_decompress
1936   ================
1937     decompresses an image encoded by a SN9C101 camera controller chip.
1938
1939   IN    width
1940     height
1941     inp         pointer to compressed frame (with header already stripped)
1942   OUT   outp    pointer to decompressed frame
1943
1944   Returns 0 if the operation was successful.
1945   Returns <0 if operation failed.
1946
1947 */
1948 int sonix_decompress(int width, int height, unsigned char *inp, unsigned char *outp)
1949 {
1950   int row, col;
1951   int val;
1952   int bitpos;
1953   unsigned char code;
1954   unsigned char *addr;
1955
1956   if (!init_done) {
1957     /* do sonix_decompress_init first! */
1958     return -1;
1959   }
1960
1961   bitpos = 0;
1962   for (row = 0; row < height; row++) {
1963
1964     col = 0;
1965
1966
1967
1968     /* first two pixels in first two rows are stored as raw 8-bit */
1969     if (row < 2) {
1970       addr = inp + (bitpos >> 3);
1971       code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
1972       bitpos += 8;
1973       *outp++ = code;
1974
1975       addr = inp + (bitpos >> 3);
1976       code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
1977       bitpos += 8;
1978       *outp++ = code;
1979
1980       col += 2;
1981     }
1982
1983     while (col < width) {
1984       /* get bitcode from bitstream */
1985       addr = inp + (bitpos >> 3);
1986       code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
1987
1988       /* update bit position */
1989       bitpos += table[code].len;
1990
1991       /* calculate pixel value */
1992       val = table[code].val;
1993       if (!table[code].is_abs) {
1994         /* value is relative to top and left pixel */
1995         if (col < 2) {
1996           /* left column: relative to top pixel */
1997           val += outp[-2*width];
1998         }
1999         else if (row < 2) {
2000           /* top row: relative to left pixel */
2001           val += outp[-2];
2002         }
2003         else {
2004           /* main area: average of left pixel and top pixel */
2005           val += (outp[-2] + outp[-2*width]) / 2;
2006         }
2007       }
2008
2009       /* store pixel */
2010       *outp++ = CLAMP(val);
2011       col++;
2012     }
2013   }
2014
2015   return 0;
2016 }
2017
2018
2019 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture) {
2020
2021 #ifdef HAVE_CAMV4L2
2022   if (V4L2_SUPPORT == 0)
2023 #endif /* HAVE_CAMV4L2 */
2024   {
2025
2026     /* [FD] this really belongs here */
2027     if (ioctl(capture->deviceHandle, VIDIOCSYNC, &capture->mmaps[capture->bufferIndex].frame) == -1) {
2028       fprintf( stderr, "HIGHGUI ERROR: V4L: Could not SYNC to video stream. %s\n", strerror(errno));
2029     }
2030
2031   }
2032
2033    /* Now get what has already been captured as a IplImage return */
2034
2035    /* First, reallocate imageData if the frame size changed */
2036
2037 #ifdef HAVE_CAMV4L2
2038
2039   if (V4L2_SUPPORT == 1)
2040   {
2041
2042     if(((unsigned long)capture->frame.width != capture->form.fmt.pix.width)
2043        || ((unsigned long)capture->frame.height != capture->form.fmt.pix.height)) {
2044         cvFree(&capture->frame.imageData);
2045         cvInitImageHeader( &capture->frame,
2046               cvSize( capture->form.fmt.pix.width,
2047                   capture->form.fmt.pix.height ),
2048               IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
2049        capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
2050     }
2051
2052   } else
2053 #endif /* HAVE_CAMV4L2 */
2054   {
2055
2056     if((capture->frame.width != capture->mmaps[capture->bufferIndex].width)
2057       || (capture->frame.height != capture->mmaps[capture->bufferIndex].height)) {
2058        cvFree(&capture->frame.imageData);
2059        cvInitImageHeader( &capture->frame,
2060               cvSize( capture->captureWindow.width,
2061                   capture->captureWindow.height ),
2062               IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
2063        capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
2064     }
2065  
2066   }
2067
2068 #ifdef HAVE_CAMV4L2
2069
2070   if (V4L2_SUPPORT == 1)
2071   {
2072
2073     if (PALETTE_BGR24 == 1)
2074       memcpy((char *)capture->frame.imageData, 
2075              (char *)capture->buffers[capture->bufferIndex].start,
2076              capture->frame.imageSize);
2077
2078     if (PALETTE_YVU420 == 1)
2079       yuv420p_to_rgb24(capture->form.fmt.pix.width,
2080                        capture->form.fmt.pix.height,
2081                        (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2082                        (unsigned char*)capture->frame.imageData);
2083
2084     if (PALETTE_YUV411P == 1)
2085       yuv411p_to_rgb24(capture->form.fmt.pix.width,
2086                        capture->form.fmt.pix.height,
2087                        (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2088                        (unsigned char*)capture->frame.imageData);
2089
2090 #ifdef HAVE_JPEG
2091 #ifdef __USE_GNU
2092     /* support for MJPEG is only available with libjpeg and gcc,
2093        because it's use libjepg and fmemopen()
2094     */
2095     if (PALETTE_MJPEG == 1)
2096       mjpeg_to_rgb24(capture->form.fmt.pix.width,
2097                      capture->form.fmt.pix.height,
2098                      (unsigned char*)(capture->buffers[capture->bufferIndex]
2099                                       .start),
2100                      capture->buffers[capture->bufferIndex].length,
2101                      (unsigned char*)capture->frame.imageData);
2102 #endif
2103 #endif
2104
2105     if (PALETTE_YUYV == 1)
2106         yuyv_to_rgb24(capture->form.fmt.pix.width,
2107                       capture->form.fmt.pix.height,
2108                       (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2109                       (unsigned char*)capture->frame.imageData);
2110
2111     if (PALETTE_UYVY == 1)
2112         uyvy_to_rgb24(capture->form.fmt.pix.width,
2113                       capture->form.fmt.pix.height,
2114                       (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2115                       (unsigned char*)capture->frame.imageData);
2116
2117     if (PALETTE_SBGGR8 == 1)
2118     {
2119       bayer2rgb24(capture->form.fmt.pix.width,
2120                   capture->form.fmt.pix.height,
2121                   (unsigned char*)capture->buffers[capture->bufferIndex].start,
2122                   (unsigned char*)capture->frame.imageData);
2123     }
2124
2125     if (PALETTE_SN9C10X == 1)
2126     {
2127       sonix_decompress_init();
2128       
2129       sonix_decompress(capture->form.fmt.pix.width,
2130                        capture->form.fmt.pix.height,
2131                        (unsigned char*)capture->buffers[capture->bufferIndex].start,
2132                        (unsigned char*)capture->buffers[(capture->bufferIndex+1) % capture->req.count].start);
2133
2134       bayer2rgb24(capture->form.fmt.pix.width,
2135                   capture->form.fmt.pix.height,
2136                   (unsigned char*)capture->buffers[(capture->bufferIndex+1) % capture->req.count].start,
2137                   (unsigned char*)capture->frame.imageData);
2138     }
2139
2140   } else
2141 #endif /* HAVE_CAMV4L2 */
2142   {
2143
2144     switch(capture->imageProperties.palette) {
2145       case VIDEO_PALETTE_RGB24:
2146         memcpy((char *)capture->frame.imageData, 
2147            (char *)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2148            capture->frame.imageSize);
2149         break;
2150       case VIDEO_PALETTE_YUV420P:
2151         yuv420p_to_rgb24(capture->captureWindow.width,
2152              capture->captureWindow.height,
2153              (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2154              (unsigned char*)capture->frame.imageData);
2155         break;
2156       case VIDEO_PALETTE_YUV420:
2157         yuv420_to_rgb24(capture->captureWindow.width,
2158           capture->captureWindow.height,
2159           (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2160           (unsigned char*)capture->frame.imageData);
2161         break;
2162       case VIDEO_PALETTE_YUV411P:
2163         yuv411p_to_rgb24(capture->captureWindow.width,
2164           capture->captureWindow.height,
2165           (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2166           (unsigned char*)capture->frame.imageData);
2167         break;
2168       default:
2169         fprintf( stderr,
2170                  "HIGHGUI ERROR: V4L: Cannot convert from palette %d to RGB\n",
2171                  capture->imageProperties.palette);
2172
2173         return 0;
2174     }
2175
2176   }
2177
2178    return(&capture->frame);
2179 }
2180
2181 static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture,
2182                                      int property_id ) {
2183
2184 #ifdef HAVE_CAMV4L2
2185
2186   if (V4L2_SUPPORT == 1)
2187   {
2188
2189       /* default value for min and max */
2190       int v4l2_min = 0;
2191       int v4l2_max = 255;
2192
2193       CLEAR (capture->form);
2194       capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2195       if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
2196           /* display an error message, and return an error code */
2197           perror ("VIDIOC_G_FMT");
2198           return -1;
2199       }
2200
2201       switch (property_id) {
2202       case CV_CAP_PROP_FRAME_WIDTH:
2203           return capture->form.fmt.pix.width;
2204       case CV_CAP_PROP_FRAME_HEIGHT:
2205           return capture->form.fmt.pix.height;
2206       }
2207
2208       /* initialize the control structure */
2209
2210       switch (property_id) {
2211       case CV_CAP_PROP_BRIGHTNESS:
2212           capture->control.id = V4L2_CID_BRIGHTNESS;
2213           break;
2214       case CV_CAP_PROP_CONTRAST:
2215           capture->control.id = V4L2_CID_CONTRAST;
2216           break;
2217       case CV_CAP_PROP_SATURATION:
2218           capture->control.id = V4L2_CID_SATURATION;
2219           break;
2220       case CV_CAP_PROP_HUE:
2221           capture->control.id = V4L2_CID_HUE;
2222           break;
2223       case CV_CAP_PROP_GAIN:
2224           capture->control.id = V4L2_CID_GAIN;
2225           break;
2226       default:
2227         fprintf(stderr,
2228                 "HIGHGUI ERROR: V4L2: getting property #%d is not supported\n",
2229                 property_id);
2230         return -1;
2231       }
2232
2233       if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_CTRL,
2234                         &capture->control)) {
2235
2236           fprintf( stderr, "HIGHGUI ERROR: V4L2: ");
2237           switch (property_id) {
2238           case CV_CAP_PROP_BRIGHTNESS:
2239               fprintf (stderr, "Brightness");
2240               break;
2241           case CV_CAP_PROP_CONTRAST:
2242               fprintf (stderr, "Contrast");
2243               break;
2244           case CV_CAP_PROP_SATURATION:
2245               fprintf (stderr, "Saturation");
2246               break;
2247           case CV_CAP_PROP_HUE:
2248               fprintf (stderr, "Hue");
2249               break;
2250           case CV_CAP_PROP_GAIN:
2251               fprintf (stderr, "Gain");
2252               break;
2253           }
2254           fprintf (stderr, " is not supported by your device\n");
2255
2256           return -1;
2257       }
2258
2259       /* get the min/max values */
2260       switch (property_id) {
2261
2262       case CV_CAP_PROP_BRIGHTNESS:
2263           v4l2_min = capture->v4l2_brightness_min;
2264           v4l2_max = capture->v4l2_brightness_max;
2265           break;
2266       case CV_CAP_PROP_CONTRAST:
2267           v4l2_min = capture->v4l2_contrast_min;
2268           v4l2_max = capture->v4l2_contrast_max;
2269           break;
2270       case CV_CAP_PROP_SATURATION:
2271           v4l2_min = capture->v4l2_saturation_min;
2272           v4l2_max = capture->v4l2_saturation_max;
2273           break;
2274       case CV_CAP_PROP_HUE:
2275           v4l2_min = capture->v4l2_hue_min;
2276           v4l2_max = capture->v4l2_hue_max;
2277           break;
2278       case CV_CAP_PROP_GAIN:
2279           v4l2_min = capture->v4l2_gain_min;
2280           v4l2_max = capture->v4l2_gain_max;
2281           break;
2282       }
2283
2284       /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
2285       return ((float)capture->control.value - v4l2_min + 1) / (v4l2_max - v4l2_min);
2286
2287   } else
2288 #endif /* HAVE_CAMV4L2 */
2289   {
2290
2291     int retval = -1;
2292
2293     if (ioctl (capture->deviceHandle,
2294                VIDIOCGWIN, &capture->captureWindow) < 0) {
2295         fprintf (stderr,
2296                  "HIGHGUI ERROR: V4L: "
2297                  "Unable to determine size of incoming image\n");
2298         icvCloseCAM_V4L(capture);
2299         return -1;
2300     }
2301
2302     switch (property_id) {
2303     case CV_CAP_PROP_FRAME_WIDTH:
2304         retval = capture->captureWindow.width;
2305         break;
2306     case CV_CAP_PROP_FRAME_HEIGHT:
2307         retval = capture->captureWindow.height;
2308         break;
2309     case CV_CAP_PROP_BRIGHTNESS:
2310         retval = capture->imageProperties.brightness;
2311         break;
2312     case CV_CAP_PROP_CONTRAST:
2313         retval = capture->imageProperties.contrast;
2314         break;
2315     case CV_CAP_PROP_SATURATION:
2316         retval = capture->imageProperties.colour;
2317         break;
2318     case CV_CAP_PROP_HUE:
2319         retval = capture->imageProperties.hue;
2320         break;
2321     case CV_CAP_PROP_GAIN:
2322         fprintf(stderr,
2323                 "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
2324         return -1;
2325         break;
2326     default:
2327         fprintf(stderr,
2328                 "HIGHGUI ERROR: V4L: getting property #%d is not supported\n",
2329                 property_id);
2330     }
2331
2332     if (retval == -1) {
2333         /* there was a problem */
2334         return -1;
2335     }
2336
2337     /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
2338     return float (retval) / 0xFFFF;
2339
2340   }
2341
2342 };
2343
2344 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h) {
2345
2346 #ifdef HAVE_CAMV4L2
2347
2348   if (V4L2_SUPPORT == 1)
2349   {
2350
2351     CLEAR (capture->crop);
2352     capture->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2353     capture->crop.c.left       = 0; 
2354     capture->crop.c.top        = 0; 
2355     capture->crop.c.height     = h*24;
2356     capture->crop.c.width      = w*24;
2357
2358     /* set the crop area, but don't exit if the device don't support croping */
2359     xioctl (capture->deviceHandle, VIDIOC_S_CROP, &capture->crop);
2360
2361     CLEAR (capture->form);
2362     capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2363
2364     /* read the current setting, mainly to retreive the pixelformat information */
2365     xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form);
2366
2367     /* set the values we want to change */
2368     capture->form.fmt.pix.width = w; 
2369     capture->form.fmt.pix.height = h;
2370     capture->form.fmt.win.chromakey = 0;
2371     capture->form.fmt.win.field = V4L2_FIELD_ANY;
2372     capture->form.fmt.win.clips = 0;
2373     capture->form.fmt.win.clipcount = 0;
2374     capture->form.fmt.pix.field = V4L2_FIELD_ANY;
2375
2376     /* ask the device to change the size
2377      * don't test if the set of the size is ok, because some device
2378      * don't allow changing the size, and we will get the real size
2379      * later */
2380     xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form);
2381
2382     /* try to set framerate to 30 fps */
2383     struct v4l2_streamparm setfps;  
2384     memset (&setfps, 0, sizeof(struct v4l2_streamparm));
2385     setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2386     setfps.parm.capture.timeperframe.numerator = 1;
2387     setfps.parm.capture.timeperframe.denominator = 30;
2388     xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps);
2389
2390     /* we need to re-initialize some things, like buffers, because the size has
2391      * changed */
2392     capture->FirstCapture = 1;
2393
2394     /* Get window info again, to get the real value */
2395     if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form))
2396     {
2397       fprintf(stderr, "HIGHGUI WARNING: V4L/V4L2: Could not obtain specifics of capture window.\n\n");
2398
2399 //      icvCloseCAM_V4L(capture);
2400
2401       return 0;
2402     }
2403
2404     return 0;
2405
2406   } else
2407 #endif /* HAVE_CAMV4L2 */
2408   {
2409   
2410     if (capture==0) return 0;
2411      if (w>capture->capability.maxwidth) {
2412        w=capture->capability.maxwidth;
2413      }
2414      if (h>capture->capability.maxheight) {
2415        h=capture->capability.maxheight;
2416      }
2417
2418      capture->captureWindow.width=w;
2419      capture->captureWindow.height=h;
2420
2421      if (ioctl(capture->deviceHandle, VIDIOCSWIN, &capture->captureWindow) < 0) {
2422        icvCloseCAM_V4L(capture);
2423        return 0;
2424      }
2425
2426      if (ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
2427        icvCloseCAM_V4L(capture);
2428        return 0;
2429      }
2430
2431      capture->FirstCapture = 1;
2432    
2433   }
2434    
2435   return 0;
2436
2437 }
2438
2439 static int icvSetControl (CvCaptureCAM_V4L* capture,
2440                           int property_id, double value) {
2441   
2442   /* limitation of the input value */
2443   if (value < 0.0) {
2444     value = 0.0;
2445   } else if (value > 1.0) {
2446     value = 1.0;
2447   }
2448
2449 #ifdef HAVE_CAMV4L2
2450
2451   if (V4L2_SUPPORT == 1)
2452   {
2453
2454     /* default value for min and max */
2455     int v4l2_min = 0;
2456     int v4l2_max = 255;
2457
2458     /* initialisations */
2459     CLEAR (capture->control);
2460
2461     /* set which control we want to set */
2462     switch (property_id) {
2463
2464     case CV_CAP_PROP_BRIGHTNESS:
2465         capture->control.id = V4L2_CID_BRIGHTNESS;
2466         break;
2467     case CV_CAP_PROP_CONTRAST:
2468         capture->control.id = V4L2_CID_CONTRAST;
2469         break;
2470     case CV_CAP_PROP_SATURATION:
2471         capture->control.id = V4L2_CID_SATURATION;
2472         break;
2473     case CV_CAP_PROP_HUE:
2474         capture->control.id = V4L2_CID_HUE;
2475         break;
2476     case CV_CAP_PROP_GAIN:
2477         capture->control.id = V4L2_CID_GAIN;
2478         break;
2479     default:
2480         fprintf(stderr,
2481                 "HIGHGUI ERROR: V4L2: setting property #%d is not supported\n",
2482                 property_id);
2483         return -1;
2484     }
2485
2486     /* get the min and max values */
2487     if (-1 == xioctl (capture->deviceHandle,
2488                       VIDIOC_G_CTRL, &capture->control)) {
2489 //          perror ("VIDIOC_G_CTRL for getting min/max values");
2490           return -1;
2491     }
2492
2493     /* get the min/max values */
2494     switch (property_id) {
2495
2496     case CV_CAP_PROP_BRIGHTNESS:
2497         v4l2_min = capture->v4l2_brightness_min;
2498         v4l2_max = capture->v4l2_brightness_max;
2499         break;
2500     case CV_CAP_PROP_CONTRAST:
2501         v4l2_min = capture->v4l2_contrast_min;
2502         v4l2_max = capture->v4l2_contrast_max;
2503         break;
2504     case CV_CAP_PROP_SATURATION:
2505         v4l2_min = capture->v4l2_saturation_min;
2506         v4l2_max = capture->v4l2_saturation_max;
2507         break;
2508     case CV_CAP_PROP_HUE:
2509         v4l2_min = capture->v4l2_hue_min;
2510         v4l2_max = capture->v4l2_hue_max;
2511         break;
2512     case CV_CAP_PROP_GAIN:
2513         v4l2_min = capture->v4l2_gain_min;
2514         v4l2_max = capture->v4l2_gain_max;
2515         break;
2516     }
2517
2518     /* initialisations */
2519     CLEAR (capture->control);
2520
2521     /* set which control we want to set */
2522     switch (property_id) {
2523
2524     case CV_CAP_PROP_BRIGHTNESS:
2525         capture->control.id = V4L2_CID_BRIGHTNESS;
2526         break;
2527     case CV_CAP_PROP_CONTRAST:
2528         capture->control.id = V4L2_CID_CONTRAST;
2529         break;
2530     case CV_CAP_PROP_SATURATION:
2531         capture->control.id = V4L2_CID_SATURATION;
2532         break;
2533     case CV_CAP_PROP_HUE:
2534         capture->control.id = V4L2_CID_HUE;
2535         break;
2536     case CV_CAP_PROP_GAIN:
2537         capture->control.id = V4L2_CID_GAIN;
2538         break;
2539     default:
2540         fprintf(stderr,
2541                 "HIGHGUI ERROR: V4L2: setting property #%d is not supported\n",
2542                 property_id);
2543         return -1;
2544     }
2545
2546     /* set the value we want to set to the scaled the value */
2547     capture->control.value = (int)(value * (v4l2_max - v4l2_min) + v4l2_min);
2548
2549     /* The driver may clamp the value or return ERANGE, ignored here */
2550     if (-1 == xioctl (capture->deviceHandle,
2551                       VIDIOC_S_CTRL, &capture->control) && errno != ERANGE) {
2552         perror ("VIDIOC_S_CTRL");
2553         return -1;
2554     }
2555   } else
2556 #endif /* HAVE_CAMV4L2 */
2557   {
2558
2559     int v4l_value;
2560
2561     /* scale the value to the wanted integer one */
2562     v4l_value = (int)(0xFFFF * value);
2563   
2564     switch (property_id) {
2565     case CV_CAP_PROP_BRIGHTNESS:
2566       capture->imageProperties.brightness = v4l_value;
2567       break;
2568     case CV_CAP_PROP_CONTRAST:
2569       capture->imageProperties.contrast = v4l_value;
2570       break;
2571     case CV_CAP_PROP_SATURATION:
2572       capture->imageProperties.colour = v4l_value;
2573       break;
2574     case CV_CAP_PROP_HUE:
2575       capture->imageProperties.hue = v4l_value;
2576       break;
2577     case CV_CAP_PROP_GAIN:
2578         fprintf(stderr,
2579                 "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
2580         return -1;
2581     default:
2582         fprintf(stderr,
2583                 "HIGHGUI ERROR: V4L: property #%d is not supported\n",
2584                 property_id);
2585         return -1;
2586     }
2587     
2588     if (ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties)
2589         < 0)
2590     {
2591        fprintf(stderr,
2592                "HIGHGUI ERROR: V4L: Unable to set video informations\n");
2593        icvCloseCAM_V4L(capture);
2594        return -1;
2595     }
2596   }
2597
2598   /* all was OK */
2599   return 0;
2600
2601 }
2602  
2603 static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture,
2604                                   int property_id, double value ){
2605     static int width = 0, height = 0;
2606     int retval;
2607
2608     /* initialization */
2609     retval = 0;
2610
2611     /* two subsequent calls setting WIDTH and HEIGHT will change
2612        the video size */
2613     /* the first one will return an error, though. */
2614
2615     switch (property_id) {
2616     case CV_CAP_PROP_FRAME_WIDTH:
2617         width = cvRound(value);
2618         if(width !=0 && height != 0) {
2619             retval = icvSetVideoSize( capture, width, height);
2620             width = height = 0;
2621         }
2622         break;
2623     case CV_CAP_PROP_FRAME_HEIGHT:
2624         height = cvRound(value);
2625         if(width !=0 && height != 0) {
2626             retval = icvSetVideoSize( capture, width, height);
2627             width = height = 0;
2628         }
2629         break;
2630     case CV_CAP_PROP_BRIGHTNESS:
2631     case CV_CAP_PROP_CONTRAST:
2632     case CV_CAP_PROP_SATURATION:
2633     case CV_CAP_PROP_HUE:
2634     case CV_CAP_PROP_GAIN:
2635         retval = icvSetControl(capture, property_id, value);
2636         break;
2637     default:
2638         fprintf(stderr,
2639                 "HIGHGUI ERROR: V4L: setting property #%d is not supported\n",
2640                 property_id);
2641     }
2642
2643     /* return the the status */
2644     return retval;
2645 }
2646
2647 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ){
2648    /* Deallocate space - Hopefully, no leaks */ 
2649
2650    if (capture)
2651    {
2652
2653 #ifdef HAVE_CAMV4L2
2654      if (V4L2_SUPPORT == 0)
2655 #endif /* HAVE_CAMV4L2 */
2656      {
2657
2658        if (capture->mmaps)
2659          free(capture->mmaps);
2660        if (capture->memoryMap)
2661          munmap(capture->memoryMap, capture->memoryBuffer.size);
2662
2663      }
2664 #ifdef HAVE_CAMV4L2
2665      else {
2666
2667        for (unsigned int n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
2668        {
2669            if (-1 == munmap (capture->buffers[n_buffers].start, capture->buffers[n_buffers].length)) {
2670                perror ("munmap");
2671            }
2672        }
2673
2674      }
2675 #endif /* HAVE_CAMV4L2 */
2676
2677      if (capture->deviceHandle > 0) close(capture->deviceHandle);
2678
2679      if (capture->frame.imageData) cvFree(&capture->frame.imageData);
2680       //cvFree((void **)capture);
2681    }
2682 };
2683
2684
2685 class CvCaptureCAM_V4L_CPP : CvCapture
2686 {
2687 public:
2688     CvCaptureCAM_V4L_CPP() { captureV4L = 0; }
2689     virtual ~CvCaptureCAM_V4L_CPP() { close(); }
2690
2691     virtual bool open( int index );
2692     virtual void close();
2693
2694     virtual double getProperty(int);
2695     virtual bool setProperty(int, double);
2696     virtual bool grabFrame();
2697     virtual IplImage* retrieveFrame();
2698 protected:
2699
2700     CvCaptureCAM_V4L* captureV4L;
2701 };
2702
2703 bool CvCaptureCAM_V4L_CPP::open( int index )
2704 {
2705     close();
2706     captureV4L = icvCaptureFromCAM_V4L(index);
2707     return captureV4L != 0;
2708 }
2709
2710 void CvCaptureCAM_V4L_CPP::close()
2711 {
2712     if( captureV4L )
2713     {
2714         icvCloseCAM_V4L( captureV4L );
2715         cvFree( &captureV4L );
2716     }
2717 }
2718
2719 bool CvCaptureCAM_V4L_CPP::grabFrame()
2720 {
2721     return captureV4L ? icvGrabFrameCAM_V4L( captureV4L ) != 0 : false;
2722 }
2723
2724 IplImage* CvCaptureCAM_V4L_CPP::retrieveFrame()
2725 {
2726     return captureV4L ? icvRetrieveFrameCAM_V4L( captureV4L ) : 0;
2727 }
2728
2729 double CvCaptureCAM_V4L_CPP::getProperty( int propId )
2730 {
2731     return captureV4L ? icvGetPropertyCAM_V4L( captureV4L, propId ) : 0.0;
2732 }
2733
2734 bool CvCaptureCAM_V4L_CPP::setProperty( int propId, double value )
2735 {
2736     return captureV4L ? icvSetPropertyCAM_V4L( captureV4L, propId, value ) != 0 : false;
2737 }
2738
2739 CvCapture* cvCreateCameraCapture_V4L( int index )
2740 {
2741     CvCaptureCAM_V4L_CPP* capture = new CvCaptureCAM_V4L_CPP;
2742
2743     if( capture->open( index ))
2744         return (CvCapture*)capture;
2745
2746     delete capture;
2747     return 0;
2748 }
2749
2750 #endif