793e4ba8c9760a00c4cbf6403fcf0b2527a7b3b8
[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  640
223 #define DEFAULT_V4L_HEIGHT 480
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    icvSetVideoSize(capture, DEFAULT_V4L_WIDTH, DEFAULT_V4L_HEIGHT);
849
850    unsigned int min;
851
852    /* Buggy driver paranoia. */
853    min = capture->form.fmt.pix.width * 2;
854
855    if (capture->form.fmt.pix.bytesperline < min)
856        capture->form.fmt.pix.bytesperline = min;
857
858    min = capture->form.fmt.pix.bytesperline * capture->form.fmt.pix.height;
859  
860    if (capture->form.fmt.pix.sizeimage < min)
861        capture->form.fmt.pix.sizeimage = min;
862
863    CLEAR (capture->req);
864    
865    unsigned int buffer_number = 4;
866
867    try_again:
868    
869    capture->req.count = buffer_number;
870    capture->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
871    capture->req.memory = V4L2_MEMORY_MMAP;
872
873    if (-1 == xioctl (capture->deviceHandle, VIDIOC_REQBUFS, &capture->req))
874    {
875        if (EINVAL == errno)
876        {
877          fprintf (stderr, "%s does not support memory mapping\n", deviceName);
878        } else {
879          perror ("VIDIOC_REQBUFS");
880        }
881        /* free capture, and returns an error code */
882        icvCloseCAM_V4L (capture);
883        return -1;
884    }
885
886    if (capture->req.count < buffer_number)
887    {
888        if (buffer_number == 1)
889        {
890            fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName);
891
892            /* free capture, and returns an error code */
893            icvCloseCAM_V4L (capture);
894            return -1;
895        } else {
896          buffer_number--;
897          
898          goto try_again;
899        }
900    }
901
902    for (n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
903    {
904        struct v4l2_buffer buf;
905
906        CLEAR (buf);
907
908        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
909        buf.memory = V4L2_MEMORY_MMAP;
910        buf.index = n_buffers;
911
912        if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYBUF, &buf)) {
913            perror ("VIDIOC_QUERYBUF");
914        
915            /* free capture, and returns an error code */
916            icvCloseCAM_V4L (capture);
917            return -1;
918        }
919
920        capture->buffers[n_buffers].length = buf.length;
921        capture->buffers[n_buffers].start =
922          mmap (NULL /* start anywhere */,
923                buf.length,
924                PROT_READ | PROT_WRITE /* required */,
925                MAP_SHARED /* recommended */,
926                capture->deviceHandle, buf.m.offset);
927
928        if (MAP_FAILED == capture->buffers[n_buffers].start) {
929            perror ("mmap");
930        
931            /* free capture, and returns an error code */
932            icvCloseCAM_V4L (capture);
933            return -1;
934        }
935    }
936
937    /* Set up Image data */
938    cvInitImageHeader( &capture->frame,
939                       cvSize( capture->captureWindow.width,
940                               capture->captureWindow.height ),
941                       IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
942    /* Allocate space for RGBA data */
943    capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
944    
945    return 1;
946 }; /* End _capture_V4L2 */
947
948 #endif /* HAVE_CAMV4L2 */
949
950 static int _capture_V4L (CvCaptureCAM_V4L *capture, char *deviceName)
951 {
952    int detect_v4l = 0;
953
954    detect_v4l = try_init_v4l(capture, deviceName);
955
956    if ((detect_v4l == -1)
957        )
958    {
959      fprintf (stderr, "HIGHGUI ERROR: V4L"
960               ": device %s: Unable to open for READ ONLY\n", deviceName);
961
962      return -1;
963    }
964
965    if ((detect_v4l <= 0)
966        )
967    {
968      fprintf (stderr, "HIGHGUI ERROR: V4L"
969               ": device %s: Unable to query number of channels\n", deviceName);
970
971      return -1;
972    }
973    
974    {
975      if ((capture->capability.type & VID_TYPE_CAPTURE) == 0) {
976        /* Nope. */
977        fprintf( stderr, "HIGHGUI ERROR: V4L: "
978                 "device %s is unable to capture video memory.\n",deviceName);
979        icvCloseCAM_V4L(capture);
980        return -1;
981      }
982
983    }
984
985
986    /* The following code sets the CHANNEL_NUMBER of the video input.  Some video sources
987    have sub "Channel Numbers".  For a typical V4L TV capture card, this is usually 1.
988    I myself am using a simple NTSC video input capture card that uses the value of 1.
989    If you are not in North America or have a different video standard, you WILL have to change
990    the following settings and recompile/reinstall.  This set of settings is based on
991    the most commonly encountered input video source types (like my bttv card) */
992
993    {
994
995      if(capture->capability.channels>0) {
996
997        struct video_channel selectedChannel;
998
999        selectedChannel.channel=CHANNEL_NUMBER;
1000        if (ioctl(capture->deviceHandle, VIDIOCGCHAN , &selectedChannel) != -1) {
1001           /* set the video mode to ( VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM) */
1002 //           selectedChannel.norm = VIDEO_MODE_NTSC;
1003           if (ioctl(capture->deviceHandle, VIDIOCSCHAN , &selectedChannel) == -1) {
1004              /* Could not set selected channel - Oh well */
1005              //printf("\n%d, %s not NTSC capable.\n",selectedChannel.channel, selectedChannel.name);
1006           } /* End if */
1007        } /* End if */ 
1008      } /* End if */
1009
1010    }
1011
1012    {
1013
1014      if(ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) == -1) {
1015        fprintf( stderr, "HIGHGUI ERROR: V4L: "
1016                 "Could not obtain specifics of capture window.\n\n");
1017        icvCloseCAM_V4L(capture);
1018        return -1;
1019      }
1020
1021    }
1022
1023    {
1024
1025      if (autosetup_capture_mode_v4l(capture) == -1)
1026        return -1;
1027
1028    }
1029
1030    {
1031
1032      ioctl(capture->deviceHandle, VIDIOCGMBUF, &capture->memoryBuffer);
1033      capture->memoryMap  = (char *)mmap(0, 
1034                                    capture->memoryBuffer.size,
1035                                    PROT_READ | PROT_WRITE,
1036                                    MAP_SHARED,
1037                                    capture->deviceHandle,
1038                                    0);
1039      if (capture->memoryMap == MAP_FAILED) {
1040         fprintf( stderr, "HIGHGUI ERROR: V4L: Mapping Memmory from video source error: %s\n", strerror(errno));
1041         icvCloseCAM_V4L(capture);
1042      }
1043      
1044      /* Set up video_mmap structure pointing to this memory mapped area so each image may be
1045         retrieved from an index value */
1046      capture->mmaps = (struct video_mmap *)
1047                  (malloc(capture->memoryBuffer.frames * sizeof(struct video_mmap)));
1048      if (!capture->mmaps) {
1049         fprintf( stderr, "HIGHGUI ERROR: V4L: Could not memory map video frames.\n");
1050         icvCloseCAM_V4L(capture);
1051         return -1;
1052      }
1053
1054    }
1055
1056    /* Set up Image data */
1057    cvInitImageHeader( &capture->frame,
1058                       cvSize( capture->captureWindow.width,
1059                               capture->captureWindow.height ),
1060                       IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
1061    /* Allocate space for RGBA data */
1062    capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1063    
1064    return 1;
1065 }; /* End _capture_V4L */
1066
1067 static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index)
1068 {
1069    static int autoindex=0;
1070
1071    char deviceName[MAX_DEVICE_DRIVER_NAME];
1072    
1073    
1074    if (!numCameras)
1075       icvInitCapture_V4L(); /* Havent called icvInitCapture yet - do it now! */
1076    if (!numCameras)
1077      return NULL; /* Are there any /dev/video input sources? */
1078
1079    //search index in indexList
1080    if ( (index>-1) && ! ((1 << index) & indexList) ) 
1081    {
1082      fprintf( stderr, "HIGHGUI ERROR: V4L: index %d is not correct!\n",index);
1083      return NULL; /* Did someone ask for not correct video source number? */
1084    }
1085    /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL
1086       the handles for V4L processing */
1087    CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L));
1088    if (!capture) {
1089       fprintf( stderr, "HIGHGUI ERROR: V4L: Could not allocate memory for capture process.\n");
1090       return NULL;
1091    }
1092    /* Select camera, or rather, V4L video source */
1093    if (index<0) { // Asking for the first device available 
1094      for (; autoindex<MAX_CAMERAS;autoindex++)
1095     if (indexList & (1<<autoindex))
1096         break;
1097      if (autoindex==MAX_CAMERAS)
1098     return NULL; 
1099      index=autoindex;
1100      autoindex++;// i can recall icvOpenCAM_V4l with index=-1 for next camera
1101    }
1102    /* Print the CameraNumber at the end of the string with a width of one character */
1103    sprintf(deviceName, "/dev/video%1d", index);
1104    
1105    /* w/o memset some parts  arent initialized - AKA: Fill it with zeros so it is clean */
1106    memset(capture,0,sizeof(CvCaptureCAM_V4L));
1107    /* Present the routines needed for V4L funtionality.  They are inserted as part of
1108       the standard set of cv calls promoting transparency.  "Vector Table" insertion. */
1109    capture->FirstCapture = 1;
1110    
1111 #ifdef HAVE_CAMV4L2
1112    if (_capture_V4L2 (capture, deviceName) == -1) {
1113        icvCloseCAM_V4L(capture);
1114        V4L2_SUPPORT = 0;
1115 #endif  /* HAVE_CAMV4L2 */
1116        if (_capture_V4L (capture, deviceName) == -1) {
1117            icvCloseCAM_V4L(capture);
1118            return NULL;
1119        }
1120 #ifdef HAVE_CAMV4L2
1121    } else {
1122        V4L2_SUPPORT = 1;
1123    }
1124 #endif  /* HAVE_CAMV4L2 */
1125
1126    return capture;
1127 }; /* End icvOpenCAM_V4L */
1128
1129 #ifdef HAVE_CAMV4L2
1130
1131 static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
1132     struct v4l2_buffer buf;
1133
1134     CLEAR (buf);
1135
1136     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1137     buf.memory = V4L2_MEMORY_MMAP;
1138
1139     if (-1 == xioctl (capture->deviceHandle, VIDIOC_DQBUF, &buf)) {
1140         switch (errno) {
1141         case EAGAIN:
1142             return 0;
1143
1144         case EIO:
1145             /* Could ignore EIO, see spec. */
1146
1147             /* fall through */
1148
1149         default:
1150             /* display the error and stop processing */
1151             perror ("VIDIOC_DQBUF");
1152             return 1;
1153         }
1154    }
1155
1156    assert(buf.index < capture->req.count);
1157    
1158    capture->bufferIndex = buf.index;
1159
1160    if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf))
1161        perror ("VIDIOC_QBUF");
1162
1163    return 1;
1164 }
1165
1166 static void mainloop_v4l2(CvCaptureCAM_V4L* capture) {
1167     unsigned int count;
1168
1169     count = 1;
1170
1171     while (count-- > 0) {
1172         for (;;) {
1173             fd_set fds;
1174             struct timeval tv;
1175             int r;
1176
1177             FD_ZERO (&fds);
1178             FD_SET (capture->deviceHandle, &fds);
1179
1180             /* Timeout. */
1181             tv.tv_sec = 2;
1182             tv.tv_usec = 0;
1183
1184             r = select (capture->deviceHandle+1, &fds, NULL, NULL, &tv);
1185
1186             if (-1 == r) {
1187                 if (EINTR == errno)
1188                     continue;
1189
1190                 perror ("select");
1191             }
1192
1193             if (0 == r) {
1194                 fprintf (stderr, "select timeout\n");
1195
1196                 /* end the infinite loop */
1197                 break;
1198             }
1199
1200             if (read_frame_v4l2 (capture))
1201                 break;
1202         }
1203     }
1204 }
1205
1206 #endif /* HAVE_CAMV4L2 */
1207
1208 static int icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) {
1209
1210    if (capture->FirstCapture) { 
1211       /* Some general initialization must take place the first time through */
1212
1213       /* This is just a technicality, but all buffers must be filled up before any
1214          staggered SYNC is applied.  SO, filler up. (see V4L HowTo) */
1215
1216 #ifdef HAVE_CAMV4L2
1217
1218       if (V4L2_SUPPORT == 1)
1219       {
1220
1221         for (capture->bufferIndex = 0;
1222              capture->bufferIndex < ((int)capture->req.count);
1223              ++capture->bufferIndex)
1224         {
1225
1226           struct v4l2_buffer buf;
1227
1228           CLEAR (buf);
1229
1230           buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1231           buf.memory      = V4L2_MEMORY_MMAP;
1232           buf.index       = (unsigned long)capture->bufferIndex;
1233
1234           if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) {
1235               perror ("VIDIOC_QBUF");
1236               return 0;
1237           }
1238         }
1239
1240         /* enable the streaming */
1241         capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1242         if (-1 == xioctl (capture->deviceHandle, VIDIOC_STREAMON,
1243                           &capture->type)) {
1244             /* error enabling the stream */
1245             perror ("VIDIOC_STREAMON");
1246             return 0;
1247         }
1248       } else
1249 #endif /* HAVE_CAMV4L2 */
1250       {
1251
1252         for (capture->bufferIndex = 0;
1253          capture->bufferIndex < (capture->memoryBuffer.frames-1);
1254          ++capture->bufferIndex) {
1255
1256           capture->mmaps[capture->bufferIndex].frame  = capture->bufferIndex;
1257           capture->mmaps[capture->bufferIndex].width  = capture->captureWindow.width;
1258           capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1259           capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1260
1261           if (ioctl(capture->deviceHandle, VIDIOCMCAPTURE, &capture->mmaps[capture->bufferIndex]) == -1) {
1262             fprintf( stderr, "HIGHGUI ERROR: V4L: Initial Capture Error: Unable to load initial memory buffers.\n");
1263             return 0;
1264           }
1265         }
1266       
1267       }
1268
1269       /* preparation is ok */
1270       capture->FirstCapture = 0;
1271    }
1272
1273 #ifdef HAVE_CAMV4L2
1274
1275    if (V4L2_SUPPORT == 1)
1276    {
1277
1278      mainloop_v4l2(capture);
1279
1280    } else
1281 #endif /* HAVE_CAMV4L2 */
1282    {
1283    
1284      capture->mmaps[capture->bufferIndex].frame  = capture->bufferIndex;
1285      capture->mmaps[capture->bufferIndex].width  = capture->captureWindow.width;
1286      capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1287      capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1288
1289      if (ioctl (capture->deviceHandle, VIDIOCMCAPTURE,
1290                 &capture->mmaps[capture->bufferIndex]) == -1) {
1291          /* capture is on the way, so just exit */
1292          return 1;
1293      }
1294
1295      ++capture->bufferIndex;
1296      if (capture->bufferIndex == capture->memoryBuffer.frames) {
1297         capture->bufferIndex = 0;
1298      }
1299
1300    }
1301
1302    return(1);
1303 }
1304
1305 /*
1306  * Turn a YUV4:2:0 block into an RGB block
1307  *
1308  * Video4Linux seems to use the blue, green, red channel
1309  * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
1310  *
1311  * Color space conversion coefficients taken from the excellent
1312  * http://www.inforamp.net/~poynton/ColorFAQ.html
1313  * In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
1314  * Y values are given for all 4 pixels, but the U (Pb)
1315  * and V (Pr) are assumed constant over the 2x2 block.
1316  *
1317  * To avoid floating point arithmetic, the color conversion
1318  * coefficients are scaled into 16.16 fixed-point integers.
1319  * They were determined as follows:
1320  *
1321  *  double brightness = 1.0;  (0->black; 1->full scale) 
1322  *  double saturation = 1.0;  (0->greyscale; 1->full color)
1323  *  double fixScale = brightness * 256 * 256;
1324  *  int rvScale = (int)(1.402 * saturation * fixScale);
1325  *  int guScale = (int)(-0.344136 * saturation * fixScale);
1326  *  int gvScale = (int)(-0.714136 * saturation * fixScale);
1327  *  int buScale = (int)(1.772 * saturation * fixScale);
1328  *  int yScale = (int)(fixScale);   
1329  */
1330
1331 /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
1332 #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
1333
1334 static inline void
1335 move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
1336            int rowPixels, unsigned char * rgb)
1337 {
1338     const int rvScale = 91881;
1339     const int guScale = -22553;
1340     const int gvScale = -46801;
1341     const int buScale = 116129;
1342     const int yScale  = 65536;
1343     int r, g, b;
1344
1345     g = guScale * u + gvScale * v;
1346 //  if (force_rgb) {
1347 //      r = buScale * u;
1348 //      b = rvScale * v;
1349 //  } else {
1350         r = rvScale * v;
1351         b = buScale * u;
1352 //  }
1353
1354     yTL *= yScale; yTR *= yScale;
1355     yBL *= yScale; yBR *= yScale;
1356
1357     /* Write out top two pixels */
1358     rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL);
1359     rgb[2] = LIMIT(r+yTL);
1360
1361     rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR);
1362     rgb[5] = LIMIT(r+yTR);
1363
1364     /* Skip down to next line to write out bottom two pixels */
1365     rgb += 3 * rowPixels;
1366     rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL);
1367     rgb[2] = LIMIT(r+yBL);
1368
1369     rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR);
1370     rgb[5] = LIMIT(r+yBR);
1371 }
1372
1373 static inline void
1374 move_411_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
1375            int rowPixels, unsigned char * rgb)
1376 {
1377     const int rvScale = 91881;
1378     const int guScale = -22553;
1379     const int gvScale = -46801;
1380     const int buScale = 116129;
1381     const int yScale  = 65536;
1382     int r, g, b;
1383
1384     g = guScale * u + gvScale * v;
1385 //  if (force_rgb) {
1386 //      r = buScale * u;
1387 //      b = rvScale * v;
1388 //  } else {
1389         r = rvScale * v;
1390         b = buScale * u;
1391 //  }
1392
1393     yTL *= yScale; yTR *= yScale;
1394     yBL *= yScale; yBR *= yScale;
1395
1396     /* Write out top two first pixels */
1397     rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL);
1398     rgb[2] = LIMIT(r+yTL);
1399
1400     rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR);
1401     rgb[5] = LIMIT(r+yTR);
1402
1403     /* Write out top two last pixels */
1404     rgb += 6;
1405     rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL);
1406     rgb[2] = LIMIT(r+yBL);
1407
1408     rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR);
1409     rgb[5] = LIMIT(r+yBR);
1410 }
1411
1412 // Consider a YUV420P image of 8x2 pixels.
1413 //
1414 // A plane of Y values    A B C D E F G H
1415 //                        I J K L M N O P
1416 //
1417 // A plane of U values    1   2   3   4 
1418 // A plane of V values    1   2   3   4 ....
1419 //
1420 // The U1/V1 samples correspond to the ABIJ pixels.
1421 //     U2/V2 samples correspond to the CDKL pixels.
1422 //
1423 /* Converts from planar YUV420P to RGB24. */
1424 static void 
1425 yuv420p_to_rgb24(int width, int height,
1426            unsigned char *pIn0, unsigned char *pOut0)
1427 {
1428     const int numpix = width * height;
1429     const int bytes = 24 >> 3;
1430     int i, j, y00, y01, y10, y11, u, v;
1431     unsigned char *pY = pIn0;
1432     unsigned char *pU = pY + numpix;
1433     unsigned char *pV = pU + numpix / 4;
1434     unsigned char *pOut = pOut0;
1435
1436     for (j = 0; j <= height - 2; j += 2) {
1437         for (i = 0; i <= width - 2; i += 2) {
1438             y00 = *pY;
1439             y01 = *(pY + 1);
1440             y10 = *(pY + width);
1441             y11 = *(pY + width + 1);
1442             u = (*pU++) - 128;
1443             v = (*pV++) - 128;
1444
1445             move_420_block(y00, y01, y10, y11, u, v,
1446                        width, pOut);
1447     
1448             pY += 2;
1449             pOut += 2 * bytes;
1450
1451         }
1452         pY += width;
1453         pOut += width * bytes;
1454     }
1455 }
1456
1457 // Consider a YUV420 image of 6x2 pixels.
1458 //
1459 // A B C D U1 U2
1460 // I J K L V1 V2
1461 //
1462 // The U1/V1 samples correspond to the ABIJ pixels.
1463 //     U2/V2 samples correspond to the CDKL pixels.
1464 //
1465 /* Converts from interlaced YUV420 to RGB24. */
1466 /* [FD] untested... */
1467 static void 
1468 yuv420_to_rgb24(int width, int height,
1469         unsigned char *pIn0, unsigned char *pOut0)
1470 {
1471     const int bytes = 24 >> 3;
1472     int i, j, y00, y01, y10, y11, u, v;
1473     unsigned char *pY = pIn0;
1474     unsigned char *pU = pY + 4;
1475     unsigned char *pV = pU + width;
1476     unsigned char *pOut = pOut0;
1477
1478     for (j = 0; j <= height - 2; j += 2) {
1479         for (i = 0; i <= width - 4; i += 4) {
1480             y00 = *pY;
1481             y01 = *(pY + 1);
1482             y10 = *(pY + width);
1483             y11 = *(pY + width + 1);
1484             u = (*pU++) - 128;
1485             v = (*pV++) - 128;
1486
1487             move_420_block(y00, y01, y10, y11, u, v,
1488                        width, pOut);
1489     
1490             pY += 2;
1491             pOut += 2 * bytes;
1492
1493             y00 = *pY;
1494             y01 = *(pY + 1);
1495             y10 = *(pY + width);
1496             y11 = *(pY + width + 1);
1497             u = (*pU++) - 128;
1498             v = (*pV++) - 128;
1499
1500             move_420_block(y00, y01, y10, y11, u, v,
1501                        width, pOut);
1502     
1503             pY += 4; // skip UV
1504             pOut += 2 * bytes;
1505
1506         }
1507         pY += width;
1508         pOut += width * bytes;
1509     }
1510 }
1511
1512 // Consider a YUV411P image of 8x2 pixels.
1513 //
1514 // A plane of Y values as before.
1515 //
1516 // A plane of U values    1       2
1517 //                        3       4
1518 //
1519 // A plane of V values    1       2
1520 //                        3       4
1521 //
1522 // The U1/V1 samples correspond to the ABCD pixels.
1523 //     U2/V2 samples correspond to the EFGH pixels.
1524 //
1525 /* Converts from planar YUV411P to RGB24. */
1526 /* [FD] untested... */
1527 static void 
1528 yuv411p_to_rgb24(int width, int height,
1529            unsigned char *pIn0, unsigned char *pOut0)
1530 {
1531     const int numpix = width * height;
1532     const int bytes = 24 >> 3;
1533     int i, j, y00, y01, y10, y11, u, v;
1534     unsigned char *pY = pIn0;
1535     unsigned char *pU = pY + numpix;
1536     unsigned char *pV = pU + numpix / 4;
1537     unsigned char *pOut = pOut0;
1538
1539     for (j = 0; j <= height; j++) {
1540         for (i = 0; i <= width - 4; i += 4) {
1541             y00 = *pY;
1542             y01 = *(pY + 1);
1543             y10 = *(pY + 2);
1544             y11 = *(pY + 3);
1545             u = (*pU++) - 128;
1546             v = (*pV++) - 128;
1547
1548             move_411_block(y00, y01, y10, y11, u, v,
1549                        width, pOut);
1550     
1551             pY += 4;
1552             pOut += 4 * bytes;
1553
1554         }
1555     }
1556 }
1557
1558 /* convert from 4:2:2 YUYV interlaced to RGB24 */
1559 /* based on ccvt_yuyv_bgr32() from camstream */
1560 #define SAT(c) \
1561         if (c & (~255)) { if (c < 0) c = 0; else c = 255; }
1562 static void 
1563 yuyv_to_rgb24 (int width, int height, unsigned char *src, unsigned char *dst)
1564 {
1565    unsigned char *s;
1566    unsigned char *d;
1567    int l, c;
1568    int r, g, b, cr, cg, cb, y1, y2;
1569    
1570    l = height;
1571    s = src;
1572    d = dst;
1573    while (l--) {
1574       c = width >> 1;
1575       while (c--) {
1576          y1 = *s++;
1577          cb = ((*s - 128) * 454) >> 8;
1578          cg = (*s++ - 128) * 88;
1579          y2 = *s++;
1580          cr = ((*s - 128) * 359) >> 8;
1581          cg = (cg + (*s++ - 128) * 183) >> 8;
1582
1583          r = y1 + cr;
1584          b = y1 + cb;
1585          g = y1 - cg;
1586          SAT(r);
1587          SAT(g);
1588          SAT(b);
1589
1590          *d++ = b;
1591          *d++ = g;
1592          *d++ = r;
1593
1594          r = y2 + cr;
1595          b = y2 + cb;
1596          g = y2 - cg;
1597          SAT(r);
1598          SAT(g);
1599          SAT(b);
1600
1601          *d++ = b;
1602          *d++ = g;
1603          *d++ = r;
1604       }
1605    }
1606 }
1607
1608 static void 
1609 uyvy_to_rgb24 (int width, int height, unsigned char *src, unsigned char *dst)
1610 {
1611    unsigned char *s;
1612    unsigned char *d;
1613    int l, c;
1614    int r, g, b, cr, cg, cb, y1, y2;
1615    
1616    l = height;
1617    s = src;
1618    d = dst;
1619    while (l--) {
1620       c = width >> 1;
1621       while (c--) {
1622          cb = ((*s - 128) * 454) >> 8;
1623          cg = (*s++ - 128) * 88;
1624          y1 = *s++;
1625          cr = ((*s - 128) * 359) >> 8;
1626          cg = (cg + (*s++ - 128) * 183) >> 8;
1627          y2 = *s++;
1628
1629          r = y1 + cr;
1630          b = y1 + cb;
1631          g = y1 - cg;
1632          SAT(r);
1633          SAT(g);
1634          SAT(b);
1635
1636          *d++ = b;
1637          *d++ = g;
1638          *d++ = r;
1639
1640          r = y2 + cr;
1641          b = y2 + cb;
1642          g = y2 - cg;
1643          SAT(r);
1644          SAT(g);
1645          SAT(b);
1646
1647          *d++ = b;
1648          *d++ = g;
1649          *d++ = r;
1650       }
1651    }
1652 }
1653
1654 #ifdef HAVE_JPEG
1655 #ifdef __USE_GNU
1656 /* support for MJPEG is only available with libjpeg and gcc,
1657    because it's use libjepg and fmemopen()
1658 */
1659
1660 /* include headers to be able to use libjpeg and GrFmtJpegReader */
1661 #include "grfmts.h"
1662 extern "C" {
1663 #include "jpeglib.h"
1664 }
1665
1666 /* define a new class for using fmemopen() instead of fopen() */
1667 class MyMJpegReader : public GrFmtJpegReader {
1668 public:
1669     MyMJpegReader (unsigned char *src, size_t src_size);
1670     bool  ReadHeader ();
1671 protected:
1672     unsigned char *my_src;
1673     size_t my_src_size;
1674 };
1675
1676 /////////////////////// Error processing /////////////////////
1677
1678 typedef struct GrFmtJpegErrorMgr
1679 {
1680     struct jpeg_error_mgr pub;    /* "parent" structure */
1681     jmp_buf setjmp_buffer;        /* jump label */
1682 }
1683 GrFmtJpegErrorMgr;
1684
1685
1686 METHODDEF(void)
1687 error_exit( j_common_ptr cinfo )
1688 {
1689     GrFmtJpegErrorMgr* err_mgr = (GrFmtJpegErrorMgr*)(cinfo->err);
1690     
1691     /* Return control to the setjmp point */
1692     longjmp( err_mgr->setjmp_buffer, 1 );
1693 }
1694
1695 /////////////////////// MyMJpegReader ///////////////////
1696
1697 /* constructor just call the parent constructor, but without real filename */
1698 MyMJpegReader::MyMJpegReader (unsigned char *src, size_t src_size)
1699     : GrFmtJpegReader ("/dev/null") {
1700     /* memorize the given src memory area, with it's size */
1701     my_src = src;
1702     my_src_size = src_size;
1703 }
1704
1705 /* 
1706    MyMJpegReader::ReadHeader is almost like GrFmtJpegReader::ReadHeader,
1707    just use fmemopen() instead of fopen()
1708 */
1709 bool  MyMJpegReader::ReadHeader () {
1710     bool result = false;
1711     Close();
1712
1713     jpeg_decompress_struct* cinfo = new jpeg_decompress_struct;
1714     GrFmtJpegErrorMgr* jerr = new GrFmtJpegErrorMgr;
1715
1716     cinfo->err = jpeg_std_error(&jerr->pub);
1717     jerr->pub.error_exit = error_exit;
1718
1719     m_cinfo = cinfo;
1720     m_jerr = jerr;
1721
1722     if( setjmp( jerr->setjmp_buffer ) == 0 )
1723     {
1724         jpeg_create_decompress( cinfo );
1725
1726         m_f = fmemopen( my_src, my_src_size, "rb" );
1727         if( m_f )
1728         {
1729             jpeg_stdio_src( cinfo, m_f );
1730             jpeg_read_header( cinfo, TRUE );
1731
1732             m_width = cinfo->image_width;
1733             m_height = cinfo->image_height;
1734             m_iscolor = cinfo->num_components > 1;
1735
1736             result = true;
1737         }
1738     }
1739
1740     if( !result )
1741         Close();
1742
1743     return result;
1744 }
1745
1746 /* convert from mjpeg to rgb24 */
1747 static void 
1748 mjpeg_to_rgb24 (int width, int height,
1749                 unsigned char *src, int length,
1750                 unsigned char *dst)
1751 {
1752     /* use a MyMJpegReader reader for doing the conversion */
1753     MyMJpegReader* reader = 0;
1754     reader = new MyMJpegReader (src, length);
1755     reader->ReadHeader ();
1756     reader->ReadData (dst, width * 3, 1 );
1757     delete reader;
1758
1759 }
1760
1761 #endif
1762 #endif
1763
1764 /*
1765  * BAYER2RGB24 ROUTINE TAKEN FROM:
1766  *
1767  * Sonix SN9C10x based webcam basic I/F routines
1768  * Takafumi Mizuno <taka-qce@ls-a.jp>
1769  *
1770  */
1771
1772 void bayer2rgb24(long int WIDTH, long int HEIGHT, unsigned char *src, unsigned char *dst)
1773 {
1774     long int i;
1775     unsigned char *rawpt, *scanpt;
1776     long int size;
1777
1778     rawpt = src;
1779     scanpt = dst;
1780     size = WIDTH*HEIGHT;
1781
1782     for ( i = 0; i < size; i++ ) {
1783   if ( (i/WIDTH) % 2 == 0 ) {
1784       if ( (i % 2) == 0 ) {
1785     /* B */
1786     if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
1787         *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
1788          *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;  /* R */
1789         *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
1790          *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;      /* G */
1791         *scanpt++ = *rawpt;                                     /* B */
1792     } else {
1793         /* first line or left column */
1794         *scanpt++ = *(rawpt+WIDTH+1);           /* R */
1795         *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;      /* G */
1796         *scanpt++ = *rawpt;                             /* B */
1797     }
1798       } else {
1799     /* (B)G */
1800     if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
1801         *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;  /* R */
1802         *scanpt++ = *rawpt;                                     /* G */
1803         *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;          /* B */
1804     } else {
1805         /* first line or right column */
1806         *scanpt++ = *(rawpt+WIDTH);     /* R */
1807         *scanpt++ = *rawpt;             /* G */
1808         *scanpt++ = *(rawpt-1); /* B */
1809     }
1810       }
1811   } else {
1812       if ( (i % 2) == 0 ) {
1813     /* G(R) */
1814     if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
1815         *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;          /* R */
1816         *scanpt++ = *rawpt;                                     /* G */
1817         *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;  /* B */
1818     } else {
1819         /* bottom line or left column */
1820         *scanpt++ = *(rawpt+1);         /* R */
1821         *scanpt++ = *rawpt;                     /* G */
1822         *scanpt++ = *(rawpt-WIDTH);             /* B */
1823     }
1824       } else {
1825     /* R */
1826     if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
1827         *scanpt++ = *rawpt;                                     /* R */
1828         *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
1829          *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;      /* G */
1830         *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
1831          *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;  /* B */
1832     } else {
1833         /* bottom line or right column */
1834         *scanpt++ = *rawpt;                             /* R */
1835         *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;      /* G */
1836         *scanpt++ = *(rawpt-WIDTH-1);           /* B */
1837     }
1838       }
1839   }
1840   rawpt++;
1841     }
1842
1843 }
1844
1845
1846 #define CLAMP(x)        ((x)<0?0:((x)>255)?255:(x))
1847
1848 typedef struct {
1849   int is_abs;
1850   int len;
1851   int val;
1852 } code_table_t;
1853
1854
1855 /* local storage */
1856 static code_table_t table[256];
1857 static int init_done = 0;
1858
1859
1860 /*
1861   sonix_decompress_init
1862   =====================
1863     pre-calculates a locally stored table for efficient huffman-decoding.
1864
1865   Each entry at index x in the table represents the codeword
1866   present at the MSB of byte x.
1867
1868 */
1869 void sonix_decompress_init(void)
1870 {
1871   int i;
1872   int is_abs, val, len;
1873
1874   for (i = 0; i < 256; i++) {
1875     is_abs = 0;
1876     val = 0;
1877     len = 0;
1878     if ((i & 0x80) == 0) {
1879       /* code 0 */
1880       val = 0;
1881       len = 1;
1882     }
1883     else if ((i & 0xE0) == 0x80) {
1884       /* code 100 */
1885       val = +4;
1886       len = 3;
1887     }
1888     else if ((i & 0xE0) == 0xA0) {
1889       /* code 101 */
1890       val = -4;
1891       len = 3;
1892     }
1893     else if ((i & 0xF0) == 0xD0) {
1894       /* code 1101 */
1895       val = +11;
1896       len = 4;
1897     }
1898     else if ((i & 0xF0) == 0xF0) {
1899       /* code 1111 */
1900       val = -11;
1901       len = 4;
1902     }
1903     else if ((i & 0xF8) == 0xC8) {
1904       /* code 11001 */
1905       val = +20;
1906       len = 5;
1907     }
1908     else if ((i & 0xFC) == 0xC0) {
1909       /* code 110000 */
1910       val = -20;
1911       len = 6;
1912     }
1913     else if ((i & 0xFC) == 0xC4) {
1914       /* code 110001xx: unknown */
1915       val = 0;
1916       len = 8;
1917     }
1918     else if ((i & 0xF0) == 0xE0) {
1919       /* code 1110xxxx */
1920       is_abs = 1;
1921       val = (i & 0x0F) << 4;
1922       len = 8;
1923     }
1924     table[i].is_abs = is_abs;
1925     table[i].val = val;
1926     table[i].len = len;
1927   }
1928
1929   init_done = 1;
1930 }
1931
1932
1933 /*
1934   sonix_decompress
1935   ================
1936     decompresses an image encoded by a SN9C101 camera controller chip.
1937
1938   IN    width
1939     height
1940     inp         pointer to compressed frame (with header already stripped)
1941   OUT   outp    pointer to decompressed frame
1942
1943   Returns 0 if the operation was successful.
1944   Returns <0 if operation failed.
1945
1946 */
1947 int sonix_decompress(int width, int height, unsigned char *inp, unsigned char *outp)
1948 {
1949   int row, col;
1950   int val;
1951   int bitpos;
1952   unsigned char code;
1953   unsigned char *addr;
1954
1955   if (!init_done) {
1956     /* do sonix_decompress_init first! */
1957     return -1;
1958   }
1959
1960   bitpos = 0;
1961   for (row = 0; row < height; row++) {
1962
1963     col = 0;
1964
1965
1966
1967     /* first two pixels in first two rows are stored as raw 8-bit */
1968     if (row < 2) {
1969       addr = inp + (bitpos >> 3);
1970       code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
1971       bitpos += 8;
1972       *outp++ = code;
1973
1974       addr = inp + (bitpos >> 3);
1975       code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
1976       bitpos += 8;
1977       *outp++ = code;
1978
1979       col += 2;
1980     }
1981
1982     while (col < width) {
1983       /* get bitcode from bitstream */
1984       addr = inp + (bitpos >> 3);
1985       code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
1986
1987       /* update bit position */
1988       bitpos += table[code].len;
1989
1990       /* calculate pixel value */
1991       val = table[code].val;
1992       if (!table[code].is_abs) {
1993         /* value is relative to top and left pixel */
1994         if (col < 2) {
1995           /* left column: relative to top pixel */
1996           val += outp[-2*width];
1997         }
1998         else if (row < 2) {
1999           /* top row: relative to left pixel */
2000           val += outp[-2];
2001         }
2002         else {
2003           /* main area: average of left pixel and top pixel */
2004           val += (outp[-2] + outp[-2*width]) / 2;
2005         }
2006       }
2007
2008       /* store pixel */
2009       *outp++ = CLAMP(val);
2010       col++;
2011     }
2012   }
2013
2014   return 0;
2015 }
2016
2017
2018 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture) {
2019
2020 #ifdef HAVE_CAMV4L2
2021   if (V4L2_SUPPORT == 0)
2022 #endif /* HAVE_CAMV4L2 */
2023   {
2024
2025     /* [FD] this really belongs here */
2026     if (ioctl(capture->deviceHandle, VIDIOCSYNC, &capture->mmaps[capture->bufferIndex].frame) == -1) {
2027       fprintf( stderr, "HIGHGUI ERROR: V4L: Could not SYNC to video stream. %s\n", strerror(errno));
2028     }
2029
2030   }
2031
2032    /* Now get what has already been captured as a IplImage return */
2033
2034    /* First, reallocate imageData if the frame size changed */
2035
2036 #ifdef HAVE_CAMV4L2
2037
2038   if (V4L2_SUPPORT == 1)
2039   {
2040
2041     if(((unsigned long)capture->frame.width != capture->form.fmt.pix.width)
2042        || ((unsigned long)capture->frame.height != capture->form.fmt.pix.height)) {
2043         cvFree(&capture->frame.imageData);
2044         cvInitImageHeader( &capture->frame,
2045               cvSize( capture->form.fmt.pix.width,
2046                   capture->form.fmt.pix.height ),
2047               IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
2048        capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
2049     }
2050
2051   } else
2052 #endif /* HAVE_CAMV4L2 */
2053   {
2054
2055     if((capture->frame.width != capture->mmaps[capture->bufferIndex].width)
2056       || (capture->frame.height != capture->mmaps[capture->bufferIndex].height)) {
2057        cvFree(&capture->frame.imageData);
2058        cvInitImageHeader( &capture->frame,
2059               cvSize( capture->captureWindow.width,
2060                   capture->captureWindow.height ),
2061               IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
2062        capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
2063     }
2064  
2065   }
2066
2067 #ifdef HAVE_CAMV4L2
2068
2069   if (V4L2_SUPPORT == 1)
2070   {
2071
2072     if (PALETTE_BGR24 == 1)
2073       memcpy((char *)capture->frame.imageData, 
2074              (char *)capture->buffers[capture->bufferIndex].start,
2075              capture->frame.imageSize);
2076
2077     if (PALETTE_YVU420 == 1)
2078       yuv420p_to_rgb24(capture->form.fmt.pix.width,
2079                        capture->form.fmt.pix.height,
2080                        (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2081                        (unsigned char*)capture->frame.imageData);
2082
2083     if (PALETTE_YUV411P == 1)
2084       yuv411p_to_rgb24(capture->form.fmt.pix.width,
2085                        capture->form.fmt.pix.height,
2086                        (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2087                        (unsigned char*)capture->frame.imageData);
2088
2089 #ifdef HAVE_JPEG
2090 #ifdef __USE_GNU
2091     /* support for MJPEG is only available with libjpeg and gcc,
2092        because it's use libjepg and fmemopen()
2093     */
2094     if (PALETTE_MJPEG == 1)
2095       mjpeg_to_rgb24(capture->form.fmt.pix.width,
2096                      capture->form.fmt.pix.height,
2097                      (unsigned char*)(capture->buffers[capture->bufferIndex]
2098                                       .start),
2099                      capture->buffers[capture->bufferIndex].length,
2100                      (unsigned char*)capture->frame.imageData);
2101 #endif
2102 #endif
2103
2104     if (PALETTE_YUYV == 1)
2105         yuyv_to_rgb24(capture->form.fmt.pix.width,
2106                       capture->form.fmt.pix.height,
2107                       (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2108                       (unsigned char*)capture->frame.imageData);
2109
2110     if (PALETTE_UYVY == 1)
2111         uyvy_to_rgb24(capture->form.fmt.pix.width,
2112                       capture->form.fmt.pix.height,
2113                       (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2114                       (unsigned char*)capture->frame.imageData);
2115
2116     if (PALETTE_SBGGR8 == 1)
2117     {
2118       bayer2rgb24(capture->form.fmt.pix.width,
2119                   capture->form.fmt.pix.height,
2120                   (unsigned char*)capture->buffers[capture->bufferIndex].start,
2121                   (unsigned char*)capture->frame.imageData);
2122     }
2123
2124     if (PALETTE_SN9C10X == 1)
2125     {
2126       sonix_decompress_init();
2127       
2128       sonix_decompress(capture->form.fmt.pix.width,
2129                        capture->form.fmt.pix.height,
2130                        (unsigned char*)capture->buffers[capture->bufferIndex].start,
2131                        (unsigned char*)capture->buffers[(capture->bufferIndex+1) % capture->req.count].start);
2132
2133       bayer2rgb24(capture->form.fmt.pix.width,
2134                   capture->form.fmt.pix.height,
2135                   (unsigned char*)capture->buffers[(capture->bufferIndex+1) % capture->req.count].start,
2136                   (unsigned char*)capture->frame.imageData);
2137     }
2138
2139   } else
2140 #endif /* HAVE_CAMV4L2 */
2141   {
2142
2143     switch(capture->imageProperties.palette) {
2144       case VIDEO_PALETTE_RGB24:
2145         memcpy((char *)capture->frame.imageData, 
2146            (char *)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2147            capture->frame.imageSize);
2148         break;
2149       case VIDEO_PALETTE_YUV420P:
2150         yuv420p_to_rgb24(capture->captureWindow.width,
2151              capture->captureWindow.height,
2152              (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2153              (unsigned char*)capture->frame.imageData);
2154         break;
2155       case VIDEO_PALETTE_YUV420:
2156         yuv420_to_rgb24(capture->captureWindow.width,
2157           capture->captureWindow.height,
2158           (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2159           (unsigned char*)capture->frame.imageData);
2160         break;
2161       case VIDEO_PALETTE_YUV411P:
2162         yuv411p_to_rgb24(capture->captureWindow.width,
2163           capture->captureWindow.height,
2164           (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2165           (unsigned char*)capture->frame.imageData);
2166         break;
2167       default:
2168         fprintf( stderr,
2169                  "HIGHGUI ERROR: V4L: Cannot convert from palette %d to RGB\n",
2170                  capture->imageProperties.palette);
2171
2172         return 0;
2173     }
2174
2175   }
2176
2177    return(&capture->frame);
2178 }
2179
2180 static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture,
2181                                      int property_id ) {
2182
2183 #ifdef HAVE_CAMV4L2
2184
2185   if (V4L2_SUPPORT == 1)
2186   {
2187
2188       /* default value for min and max */
2189       int v4l2_min = 0;
2190       int v4l2_max = 255;
2191
2192       CLEAR (capture->form);
2193       capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2194       if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
2195           /* display an error message, and return an error code */
2196           perror ("VIDIOC_G_FMT");
2197           return -1;
2198       }
2199
2200       switch (property_id) {
2201       case CV_CAP_PROP_FRAME_WIDTH:
2202           return capture->form.fmt.pix.width;
2203       case CV_CAP_PROP_FRAME_HEIGHT:
2204           return capture->form.fmt.pix.height;
2205       }
2206
2207       /* initialize the control structure */
2208
2209       switch (property_id) {
2210       case CV_CAP_PROP_BRIGHTNESS:
2211           capture->control.id = V4L2_CID_BRIGHTNESS;
2212           break;
2213       case CV_CAP_PROP_CONTRAST:
2214           capture->control.id = V4L2_CID_CONTRAST;
2215           break;
2216       case CV_CAP_PROP_SATURATION:
2217           capture->control.id = V4L2_CID_SATURATION;
2218           break;
2219       case CV_CAP_PROP_HUE:
2220           capture->control.id = V4L2_CID_HUE;
2221           break;
2222       case CV_CAP_PROP_GAIN:
2223           capture->control.id = V4L2_CID_GAIN;
2224           break;
2225       default:
2226         fprintf(stderr,
2227                 "HIGHGUI ERROR: V4L2: getting property #%d is not supported\n",
2228                 property_id);
2229         return -1;
2230       }
2231
2232       if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_CTRL,
2233                         &capture->control)) {
2234
2235           fprintf( stderr, "HIGHGUI ERROR: V4L2: ");
2236           switch (property_id) {
2237           case CV_CAP_PROP_BRIGHTNESS:
2238               fprintf (stderr, "Brightness");
2239               break;
2240           case CV_CAP_PROP_CONTRAST:
2241               fprintf (stderr, "Contrast");
2242               break;
2243           case CV_CAP_PROP_SATURATION:
2244               fprintf (stderr, "Saturation");
2245               break;
2246           case CV_CAP_PROP_HUE:
2247               fprintf (stderr, "Hue");
2248               break;
2249           case CV_CAP_PROP_GAIN:
2250               fprintf (stderr, "Gain");
2251               break;
2252           }
2253           fprintf (stderr, " is not supported by your device\n");
2254
2255           return -1;
2256       }
2257
2258       /* get the min/max values */
2259       switch (property_id) {
2260
2261       case CV_CAP_PROP_BRIGHTNESS:
2262           v4l2_min = capture->v4l2_brightness_min;
2263           v4l2_max = capture->v4l2_brightness_max;
2264           break;
2265       case CV_CAP_PROP_CONTRAST:
2266           v4l2_min = capture->v4l2_contrast_min;
2267           v4l2_max = capture->v4l2_contrast_max;
2268           break;
2269       case CV_CAP_PROP_SATURATION:
2270           v4l2_min = capture->v4l2_saturation_min;
2271           v4l2_max = capture->v4l2_saturation_max;
2272           break;
2273       case CV_CAP_PROP_HUE:
2274           v4l2_min = capture->v4l2_hue_min;
2275           v4l2_max = capture->v4l2_hue_max;
2276           break;
2277       case CV_CAP_PROP_GAIN:
2278           v4l2_min = capture->v4l2_gain_min;
2279           v4l2_max = capture->v4l2_gain_max;
2280           break;
2281       }
2282
2283       /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
2284       return ((float)capture->control.value - v4l2_min + 1) / (v4l2_max - v4l2_min);
2285
2286   } else
2287 #endif /* HAVE_CAMV4L2 */
2288   {
2289
2290     int retval = -1;
2291
2292     if (ioctl (capture->deviceHandle,
2293                VIDIOCGWIN, &capture->captureWindow) < 0) {
2294         fprintf (stderr,
2295                  "HIGHGUI ERROR: V4L: "
2296                  "Unable to determine size of incoming image\n");
2297         icvCloseCAM_V4L(capture);
2298         return -1;
2299     }
2300
2301     switch (property_id) {
2302     case CV_CAP_PROP_FRAME_WIDTH:
2303         retval = capture->captureWindow.width;
2304         break;
2305     case CV_CAP_PROP_FRAME_HEIGHT:
2306         retval = capture->captureWindow.height;
2307         break;
2308     case CV_CAP_PROP_BRIGHTNESS:
2309         retval = capture->imageProperties.brightness;
2310         break;
2311     case CV_CAP_PROP_CONTRAST:
2312         retval = capture->imageProperties.contrast;
2313         break;
2314     case CV_CAP_PROP_SATURATION:
2315         retval = capture->imageProperties.colour;
2316         break;
2317     case CV_CAP_PROP_HUE:
2318         retval = capture->imageProperties.hue;
2319         break;
2320     case CV_CAP_PROP_GAIN:
2321         fprintf(stderr,
2322                 "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
2323         return -1;
2324         break;
2325     default:
2326         fprintf(stderr,
2327                 "HIGHGUI ERROR: V4L: getting property #%d is not supported\n",
2328                 property_id);
2329     }
2330
2331     if (retval == -1) {
2332         /* there was a problem */
2333         return -1;
2334     }
2335
2336     /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
2337     return float (retval) / 0xFFFF;
2338
2339   }
2340
2341 };
2342
2343 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h) {
2344
2345 #ifdef HAVE_CAMV4L2
2346
2347   if (V4L2_SUPPORT == 1)
2348   {
2349
2350     CLEAR (capture->crop);
2351     capture->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2352     capture->crop.c.left       = 0; 
2353     capture->crop.c.top        = 0; 
2354     capture->crop.c.height     = h*24;
2355     capture->crop.c.width      = w*24;
2356
2357     /* set the crop area, but don't exit if the device don't support croping */
2358     xioctl (capture->deviceHandle, VIDIOC_S_CROP, &capture->crop);
2359
2360     CLEAR (capture->form);
2361     capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2362
2363     /* read the current setting, mainly to retreive the pixelformat information */
2364     xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form);
2365
2366     /* set the values we want to change */
2367     capture->form.fmt.pix.width = w; 
2368     capture->form.fmt.pix.height = h;
2369     capture->form.fmt.win.chromakey = 0;
2370     capture->form.fmt.win.field = V4L2_FIELD_ANY;
2371     capture->form.fmt.win.clips = 0;
2372     capture->form.fmt.win.clipcount = 0;
2373     capture->form.fmt.pix.field = V4L2_FIELD_ANY;
2374
2375     /* ask the device to change the size
2376      * don't test if the set of the size is ok, because some device
2377      * don't allow changing the size, and we will get the real size
2378      * later */
2379     xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form);
2380
2381     /* try to set framerate to 30 fps */
2382     struct v4l2_streamparm setfps;  
2383     memset (&setfps, 0, sizeof(struct v4l2_streamparm));
2384     setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2385     setfps.parm.capture.timeperframe.numerator = 1;
2386     setfps.parm.capture.timeperframe.denominator = 30;
2387     xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps);
2388
2389     /* we need to re-initialize some things, like buffers, because the size has
2390      * changed */
2391     capture->FirstCapture = 1;
2392
2393     /* Get window info again, to get the real value */
2394     if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form))
2395     {
2396       fprintf(stderr, "HIGHGUI ERROR: V4L/V4L2: Could not obtain specifics of capture window.\n\n");
2397
2398       icvCloseCAM_V4L(capture);
2399
2400       return 0;
2401     }
2402
2403     return 0;
2404
2405   } else
2406 #endif /* HAVE_CAMV4L2 */
2407   {
2408   
2409     if (capture==0) return 0;
2410      if (w>capture->capability.maxwidth) {
2411        w=capture->capability.maxwidth;
2412      }
2413      if (h>capture->capability.maxheight) {
2414        h=capture->capability.maxheight;
2415      }
2416
2417      capture->captureWindow.width=w;
2418      capture->captureWindow.height=h;
2419
2420      if (ioctl(capture->deviceHandle, VIDIOCSWIN, &capture->captureWindow) < 0) {
2421        icvCloseCAM_V4L(capture);
2422        return 0;
2423      }
2424
2425      if (ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
2426        icvCloseCAM_V4L(capture);
2427        return 0;
2428      }
2429
2430      capture->FirstCapture = 1;
2431    
2432   }
2433    
2434   return 0;
2435
2436 }
2437
2438 static int icvSetControl (CvCaptureCAM_V4L* capture,
2439                           int property_id, double value) {
2440   
2441   /* limitation of the input value */
2442   if (value < 0.0) {
2443     value = 0.0;
2444   } else if (value > 1.0) {
2445     value = 1.0;
2446   }
2447
2448 #ifdef HAVE_CAMV4L2
2449
2450   if (V4L2_SUPPORT == 1)
2451   {
2452
2453     /* default value for min and max */
2454     int v4l2_min = 0;
2455     int v4l2_max = 255;
2456
2457     /* initialisations */
2458     CLEAR (capture->control);
2459
2460     /* set which control we want to set */
2461     switch (property_id) {
2462
2463     case CV_CAP_PROP_BRIGHTNESS:
2464         capture->control.id = V4L2_CID_BRIGHTNESS;
2465         break;
2466     case CV_CAP_PROP_CONTRAST:
2467         capture->control.id = V4L2_CID_CONTRAST;
2468         break;
2469     case CV_CAP_PROP_SATURATION:
2470         capture->control.id = V4L2_CID_SATURATION;
2471         break;
2472     case CV_CAP_PROP_HUE:
2473         capture->control.id = V4L2_CID_HUE;
2474         break;
2475     case CV_CAP_PROP_GAIN:
2476         capture->control.id = V4L2_CID_GAIN;
2477         break;
2478     default:
2479         fprintf(stderr,
2480                 "HIGHGUI ERROR: V4L2: setting property #%d is not supported\n",
2481                 property_id);
2482         return -1;
2483     }
2484
2485     /* get the min and max values */
2486     if (-1 == xioctl (capture->deviceHandle,
2487                       VIDIOC_G_CTRL, &capture->control)) {
2488 //          perror ("VIDIOC_G_CTRL for getting min/max values");
2489           return -1;
2490     }
2491
2492     /* get the min/max values */
2493     switch (property_id) {
2494
2495     case CV_CAP_PROP_BRIGHTNESS:
2496         v4l2_min = capture->v4l2_brightness_min;
2497         v4l2_max = capture->v4l2_brightness_max;
2498         break;
2499     case CV_CAP_PROP_CONTRAST:
2500         v4l2_min = capture->v4l2_contrast_min;
2501         v4l2_max = capture->v4l2_contrast_max;
2502         break;
2503     case CV_CAP_PROP_SATURATION:
2504         v4l2_min = capture->v4l2_saturation_min;
2505         v4l2_max = capture->v4l2_saturation_max;
2506         break;
2507     case CV_CAP_PROP_HUE:
2508         v4l2_min = capture->v4l2_hue_min;
2509         v4l2_max = capture->v4l2_hue_max;
2510         break;
2511     case CV_CAP_PROP_GAIN:
2512         v4l2_min = capture->v4l2_gain_min;
2513         v4l2_max = capture->v4l2_gain_max;
2514         break;
2515     }
2516
2517     /* initialisations */
2518     CLEAR (capture->control);
2519
2520     /* set which control we want to set */
2521     switch (property_id) {
2522
2523     case CV_CAP_PROP_BRIGHTNESS:
2524         capture->control.id = V4L2_CID_BRIGHTNESS;
2525         break;
2526     case CV_CAP_PROP_CONTRAST:
2527         capture->control.id = V4L2_CID_CONTRAST;
2528         break;
2529     case CV_CAP_PROP_SATURATION:
2530         capture->control.id = V4L2_CID_SATURATION;
2531         break;
2532     case CV_CAP_PROP_HUE:
2533         capture->control.id = V4L2_CID_HUE;
2534         break;
2535     case CV_CAP_PROP_GAIN:
2536         capture->control.id = V4L2_CID_GAIN;
2537         break;
2538     default:
2539         fprintf(stderr,
2540                 "HIGHGUI ERROR: V4L2: setting property #%d is not supported\n",
2541                 property_id);
2542         return -1;
2543     }
2544
2545     /* set the value we want to set to the scaled the value */
2546     capture->control.value = (int)(value * (v4l2_max - v4l2_min) + v4l2_min);
2547
2548     /* The driver may clamp the value or return ERANGE, ignored here */
2549     if (-1 == xioctl (capture->deviceHandle,
2550                       VIDIOC_S_CTRL, &capture->control) && errno != ERANGE) {
2551         perror ("VIDIOC_S_CTRL");
2552         return -1;
2553     }
2554   } else
2555 #endif /* HAVE_CAMV4L2 */
2556   {
2557
2558     int v4l_value;
2559
2560     /* scale the value to the wanted integer one */
2561     v4l_value = (int)(0xFFFF * value);
2562   
2563     switch (property_id) {
2564     case CV_CAP_PROP_BRIGHTNESS:
2565       capture->imageProperties.brightness = v4l_value;
2566       break;
2567     case CV_CAP_PROP_CONTRAST:
2568       capture->imageProperties.contrast = v4l_value;
2569       break;
2570     case CV_CAP_PROP_SATURATION:
2571       capture->imageProperties.colour = v4l_value;
2572       break;
2573     case CV_CAP_PROP_HUE:
2574       capture->imageProperties.hue = v4l_value;
2575       break;
2576     case CV_CAP_PROP_GAIN:
2577         fprintf(stderr,
2578                 "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
2579         return -1;
2580     default:
2581         fprintf(stderr,
2582                 "HIGHGUI ERROR: V4L: property #%d is not supported\n",
2583                 property_id);
2584         return -1;
2585     }
2586     
2587     if (ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties)
2588         < 0)
2589     {
2590        fprintf(stderr,
2591                "HIGHGUI ERROR: V4L: Unable to set video informations\n");
2592        icvCloseCAM_V4L(capture);
2593        return -1;
2594     }
2595   }
2596
2597   /* all was OK */
2598   return 0;
2599
2600 }
2601  
2602 static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture,
2603                                   int property_id, double value ){
2604     static int width = 0, height = 0;
2605     int retval;
2606
2607     /* initialization */
2608     retval = 0;
2609
2610     /* two subsequent calls setting WIDTH and HEIGHT will change
2611        the video size */
2612     /* the first one will return an error, though. */
2613
2614     switch (property_id) {
2615     case CV_CAP_PROP_FRAME_WIDTH:
2616         width = cvRound(value);
2617         if(width !=0 && height != 0) {
2618             retval = icvSetVideoSize( capture, width, height);
2619             width = height = 0;
2620         }
2621         break;
2622     case CV_CAP_PROP_FRAME_HEIGHT:
2623         height = cvRound(value);
2624         if(width !=0 && height != 0) {
2625             retval = icvSetVideoSize( capture, width, height);
2626             width = height = 0;
2627         }
2628         break;
2629     case CV_CAP_PROP_BRIGHTNESS:
2630     case CV_CAP_PROP_CONTRAST:
2631     case CV_CAP_PROP_SATURATION:
2632     case CV_CAP_PROP_HUE:
2633     case CV_CAP_PROP_GAIN:
2634         retval = icvSetControl(capture, property_id, value);
2635         break;
2636     default:
2637         fprintf(stderr,
2638                 "HIGHGUI ERROR: V4L: setting property #%d is not supported\n",
2639                 property_id);
2640     }
2641
2642     /* return the the status */
2643     return retval;
2644 }
2645
2646 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ){
2647    /* Deallocate space - Hopefully, no leaks */ 
2648
2649    if (capture)
2650    {
2651
2652 #ifdef HAVE_CAMV4L2
2653      if (V4L2_SUPPORT == 0)
2654 #endif /* HAVE_CAMV4L2 */
2655      {
2656
2657        if (capture->mmaps)
2658          free(capture->mmaps);
2659        if (capture->memoryMap)
2660          munmap(capture->memoryMap, capture->memoryBuffer.size);
2661
2662      }
2663 #ifdef HAVE_CAMV4L2
2664      else {
2665
2666        for (unsigned int n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
2667        {
2668            if (-1 == munmap (capture->buffers[n_buffers].start, capture->buffers[n_buffers].length)) {
2669                perror ("munmap");
2670            }
2671        }
2672
2673      }
2674 #endif /* HAVE_CAMV4L2 */
2675
2676      if (capture->deviceHandle > 0) close(capture->deviceHandle);
2677
2678      if (capture->frame.imageData) cvFree(&capture->frame.imageData);
2679       //cvFree((void **)capture);
2680    }
2681 };
2682
2683
2684 class CvCaptureCAM_V4L_CPP : CvCapture
2685 {
2686 public:
2687     CvCaptureCAM_V4L_CPP() { captureV4L = 0; }
2688     virtual ~CvCaptureCAM_V4L_CPP() { close(); }
2689
2690     virtual bool open( int index );
2691     virtual void close();
2692
2693     virtual double getProperty(int);
2694     virtual bool setProperty(int, double);
2695     virtual bool grabFrame();
2696     virtual IplImage* retrieveFrame();
2697 protected:
2698
2699     CvCaptureCAM_V4L* captureV4L;
2700 };
2701
2702 bool CvCaptureCAM_V4L_CPP::open( int index )
2703 {
2704     close();
2705     captureV4L = icvCaptureFromCAM_V4L(index);
2706     return captureV4L != 0;
2707 }
2708
2709 void CvCaptureCAM_V4L_CPP::close()
2710 {
2711     if( captureV4L )
2712     {
2713         icvCloseCAM_V4L( captureV4L );
2714         cvFree( &captureV4L );
2715     }
2716 }
2717
2718 bool CvCaptureCAM_V4L_CPP::grabFrame()
2719 {
2720     return captureV4L ? icvGrabFrameCAM_V4L( captureV4L ) != 0 : false;
2721 }
2722
2723 IplImage* CvCaptureCAM_V4L_CPP::retrieveFrame()
2724 {
2725     return captureV4L ? icvRetrieveFrameCAM_V4L( captureV4L ) : 0;
2726 }
2727
2728 double CvCaptureCAM_V4L_CPP::getProperty( int propId )
2729 {
2730     return captureV4L ? icvGetPropertyCAM_V4L( captureV4L, propId ) : 0.0;
2731 }
2732
2733 bool CvCaptureCAM_V4L_CPP::setProperty( int propId, double value )
2734 {
2735     return captureV4L ? icvSetPropertyCAM_V4L( captureV4L, propId, value ) != 0 : false;
2736 }
2737
2738 CvCapture* cvCreateCameraCapture_V4L( int index )
2739 {
2740     CvCaptureCAM_V4L_CPP* capture = new CvCaptureCAM_V4L_CPP;
2741
2742     if( capture->open( index ))
2743         return (CvCapture*)capture;
2744
2745     delete capture;
2746     return 0;
2747 }
2748
2749 #endif