1 /* This is the contributed code:
4 Current Location: ../opencv-0.9.6/otherlibs/highgui
6 Original Version: 2003-03-12 Magnus Lundin lundin@mlu.mine.nu
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
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
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.
27 These drivers should work with other V4L frame capture cards other then my bttv
28 driven frame capture card.
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.
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.
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.
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.
58 Second Patch: August 28, 2004 Sfuncia Fabio fiblan@yahoo.it
59 For Release: OpenCV-Linux Beta4 Opencv-0.9.6
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.
66 Third Patch: December 9, 2004 Frederic Devernay Frederic.Devernay@inria.fr
67 For Release: OpenCV-Linux Beta4 Opencv-0.9.6
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
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
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.
88 Fourth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu
89 For Release: OpenCV-Linux Beta5 OpenCV-0.9.7
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
107 Fifth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu
108 For Release: OpenCV-Linux Beta5 OpenCV-0.9.7
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)
116 Sixth Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu
117 For Release: OpenCV-Linux Beta5 OpenCV-0.9.7
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)
126 Seventh Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu
127 For Release: OpenCV-Linux Beta5 OpenCV-0.9.7
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)
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/
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.
149 10th patch: July 02, 2008, Mikhail Afanasyev fopencv@theamk.com
150 Fix reliability problems with high-resolution UVC cameras on linux
151 the symptoms were damaged image and 'Corrupt JPEG data: premature end of data segment' on stderr
152 - V4L_ABORT_BADJPEG detects JPEG warnings and turns them into errors, so bad images
153 could be filtered out
154 - USE_TEMP_BUFFER fixes the main problem (improper buffer management) and
155 prevents bad images in the first place
162 /*M///////////////////////////////////////////////////////////////////////////////////////
164 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
166 // By downloading, copying, installing or using the software you agree to this license.
167 // If you do not agree to this license, do not download, install,
168 // copy or use the software.
171 // Intel License Agreement
172 // For Open Source Computer Vision Library
174 // Copyright (C) 2000, Intel Corporation, all rights reserved.
175 // Third party copyrights are property of their respective owners.
177 // Redistribution and use in source and binary forms, with or without modification,
178 // are permitted provided that the following conditions are met:
180 // * Redistribution's of source code must retain the above copyright notice,
181 // this list of conditions and the following disclaimer.
183 // * Redistribution's in binary form must reproduce the above copyright notice,
184 // this list of conditions and the following disclaimer in the documentation
185 // and/or other materials provided with the distribution.
187 // * The name of Intel Corporation may not be used to endorse or promote products
188 // derived from this software without specific prior written permission.
190 // This software is provided by the copyright holders and contributors "as is" and
191 // any express or implied warranties, including, but not limited to, the implied
192 // warranties of merchantability and fitness for a particular purpose are disclaimed.
193 // In no event shall the Intel Corporation or contributors be liable for any direct,
194 // indirect, incidental, special, exemplary, or consequential damages
195 // (including, but not limited to, procurement of substitute goods or services;
196 // loss of use, data, or profits; or business interruption) however caused
197 // and on any theory of liability, whether in contract, strict liability,
198 // or tort (including negligence or otherwise) arising in any way out of
199 // the use of this software, even if advised of the possibility of such damage.
203 #include "_highgui.h"
205 #if !defined WIN32 && defined HAVE_CAMV4L
207 #define CLEAR(x) memset (&(x), 0, sizeof (x))
213 #include <sys/ioctl.h>
214 #include <sys/types.h>
215 #include <sys/mman.h>
217 #include <linux/videodev.h>
221 #include <asm/types.h> /* for videodev2.h */
223 #include <sys/stat.h>
224 #include <sys/ioctl.h>
227 #include <linux/videodev2.h>
230 /* Defaults - If your board can do better, set it here. Set for the most common type inputs. */
231 #define DEFAULT_V4L_WIDTH 640
232 #define DEFAULT_V4L_HEIGHT 480
234 #define CHANNEL_NUMBER 1
235 #define MAX_CAMERAS 8
238 // default and maximum number of V4L buffers, not including last, 'special' buffer
239 #define MAX_V4L_BUFFERS 10
240 #define DEFAULT_V4L_BUFFERS 4
242 // if enabled, then bad JPEG warnings become errors and cause NULL returned instead of image
243 #define V4L_ABORT_BADJPEG
245 #define MAX_DEVICE_DRIVER_NAME 80
247 /* Device Capture Objects */
258 static unsigned int n_buffers = 0;
260 /* Additional V4L2 pixelformats support for Sonix SN9C10x base webcams */
261 #ifndef V4L2_PIX_FMT_SBGGR8
262 #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */
264 #ifndef V4L2_PIX_FMT_SN9C10X
265 #define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S','9','1','0') /* SN9C10x cmpr. */
268 #ifndef V4L2_PIX_FMT_SGBRG
269 #define V4L2_PIX_FMT_SGBRG v4l2_fourcc('G','B','R','G') /* bayer GBRG GBGB.. RGRG.. */
272 #endif /* HAVE_CAMV4L2 */
274 int PALETTE_BGR24 = 0,
284 typedef struct CvCaptureCAM_V4L
289 struct video_capability capability;
290 struct video_window captureWindow;
291 struct video_picture imageProperties;
292 struct video_mbuf memoryBuffer;
293 struct video_mmap *mmaps;
300 buffer buffers[MAX_V4L_BUFFERS + 1];
301 struct v4l2_capability cap;
302 struct v4l2_input inp;
303 struct v4l2_format form;
304 struct v4l2_crop crop;
305 struct v4l2_cropcap cropcap;
306 struct v4l2_requestbuffers req;
307 struct v4l2_control control;
308 enum v4l2_buf_type type;
309 struct v4l2_queryctrl queryctrl;
310 struct v4l2_querymenu querymenu;
312 /* V4L2 control variables */
313 int v4l2_brightness, v4l2_brightness_min, v4l2_brightness_max;
314 int v4l2_contrast, v4l2_contrast_min, v4l2_contrast_max;
315 int v4l2_saturation, v4l2_saturation_min, v4l2_saturation_max;
316 int v4l2_hue, v4l2_hue_min, v4l2_hue_max;
317 int v4l2_gain, v4l2_gain_min, v4l2_gain_max;
318 int v4l2_exposure, v4l2_exposure_min, v4l2_exposure_max;
320 #endif /* HAVE_CAMV4L2 */
327 int V4L2_SUPPORT = 0;
329 #endif /* HAVE_CAMV4L2 */
331 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture );
333 static int icvGrabFrameCAM_V4L( CvCaptureCAM_V4L* capture );
334 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int );
336 static double icvGetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id );
337 static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id, double value );
339 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h);
341 /*********************** Implementations ***************************************/
343 static int numCameras = 0;
344 static int indexList = 0;
348 // IOCTL handling for V4L2
349 static int xioctl( int fd, int request, void *arg)
355 do r = ioctl (fd, request, arg);
356 while (-1 == r && EINTR == errno);
362 #endif /* HAVE_CAMV4L2 */
364 /* Simple test program: Find number of Video Sources available.
365 Start from 0 and go to MAX_CAMERAS while checking for the device with that name.
366 If it fails on the first attempt of /dev/video0, then check if /dev/video is valid.
367 Returns the global numCameras with the correct value (we hope) */
369 static void icvInitCapture_V4L() {
372 char deviceName[MAX_DEVICE_DRIVER_NAME];
375 while(CameraNumber < MAX_CAMERAS) {
376 /* Print the CameraNumber at the end of the string with a width of one character */
377 sprintf(deviceName, "/dev/video%1d", CameraNumber);
378 /* Test using an open to see if this new device name really does exists. */
379 deviceHandle = open(deviceName, O_RDONLY);
380 if (deviceHandle != -1) {
381 /* This device does indeed exist - add it to the total so far */
383 indexList|=(1 << CameraNumber);
386 if (deviceHandle != -1)
388 /* Set up to test the next /dev/video source in line */
392 }; /* End icvInitCapture_V4L */
396 struct video_picture *cam_pic,
400 cam_pic->palette = pal;
401 cam_pic->depth = depth;
402 if (ioctl(fd, VIDIOCSPICT, cam_pic) < 0)
404 if (ioctl(fd, VIDIOCGPICT, cam_pic) < 0)
406 if (cam_pic->palette == pal)
413 static int try_palette_v4l2(CvCaptureCAM_V4L* capture, unsigned long colorspace)
415 CLEAR (capture->form);
417 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
418 capture->form.fmt.pix.pixelformat = colorspace;
419 capture->form.fmt.pix.field = V4L2_FIELD_ANY;
420 capture->form.fmt.pix.width = DEFAULT_V4L_WIDTH;
421 capture->form.fmt.pix.height = DEFAULT_V4L_HEIGHT;
423 if (-1 == xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form))
427 if (colorspace != capture->form.fmt.pix.pixelformat)
433 #endif /* HAVE_CAMV4L2 */
435 static int try_init_v4l(CvCaptureCAM_V4L* capture, char *deviceName)
438 // if detect = -1 then unable to open device
439 // if detect = 0 then detected nothing
440 // if detect = 1 then V4L device
444 // Test device for V4L compability
446 /* Test using an open to see if this new device name really does exists. */
447 /* No matter what the name - it still must be opened! */
448 capture->deviceHandle = open(deviceName, O_RDWR);
451 if (capture->deviceHandle == 0)
455 icvCloseCAM_V4L(capture);
460 /* Query the newly opened device for its capabilities */
461 if (ioctl(capture->deviceHandle, VIDIOCGCAP, &capture->capability) < 0)
465 icvCloseCAM_V4L(capture);
479 static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName)
482 // if detect = -1 then unable to open device
483 // if detect = 0 then detected nothing
484 // if detect = 1 then V4L2 device
488 // Test device for V4L2 compability
490 /* Open and test V4L2 device */
491 capture->deviceHandle = open (deviceName, O_RDWR /* required */ | O_NONBLOCK, 0);
495 if (capture->deviceHandle == 0)
499 icvCloseCAM_V4L(capture);
504 CLEAR (capture->cap);
505 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYCAP, &capture->cap))
509 icvCloseCAM_V4L(capture);
513 CLEAR (capture->capability);
514 capture->capability.type = capture->cap.capabilities;
516 /* Query channels number */
517 if (-1 != xioctl (capture->deviceHandle, VIDIOC_G_INPUT, &capture->capability.channels))
528 static int autosetup_capture_mode_v4l2(CvCaptureCAM_V4L* capture)
530 if (try_palette_v4l2(capture, V4L2_PIX_FMT_BGR24) == 0)
535 if (try_palette_v4l2(capture, V4L2_PIX_FMT_YVU420) == 0)
540 if (try_palette_v4l2(capture, V4L2_PIX_FMT_YUV411P) == 0)
548 /* support for MJPEG is only available with libjpeg and gcc,
549 because it's use libjepg and fmemopen()
551 if (try_palette_v4l2(capture, V4L2_PIX_FMT_MJPEG) == 0 ||
552 try_palette_v4l2(capture, V4L2_PIX_FMT_JPEG) == 0)
560 if (try_palette_v4l2(capture, V4L2_PIX_FMT_YUYV) == 0)
564 else if (try_palette_v4l2(capture, V4L2_PIX_FMT_UYVY) == 0)
569 if (try_palette_v4l2(capture, V4L2_PIX_FMT_SN9C10X) == 0)
573 if (try_palette_v4l2(capture, V4L2_PIX_FMT_SBGGR8) == 0)
577 if (try_palette_v4l2(capture, V4L2_PIX_FMT_SGBRG) == 0)
583 fprintf(stderr, "HIGHGUI ERROR: V4L2: Pixel format of incoming image is unsupported by OpenCV\n");
584 icvCloseCAM_V4L(capture);
592 #endif /* HAVE_CAMV4L2 */
594 static int autosetup_capture_mode_v4l(CvCaptureCAM_V4L* capture)
597 if(ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) {
598 fprintf( stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n");
599 icvCloseCAM_V4L(capture);
603 /* Yet MORE things that might have to be changes with your frame capture card */
604 /* This sets the scale to the center of a 2^16 number */
605 if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_RGB24, 24)) {
606 //printf("negotiated palette RGB24\n");
608 else if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_YUV420P, 16)) {
609 //printf("negotiated palette YUV420P\n");
611 else if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_YUV420, 16)) {
612 //printf("negotiated palette YUV420\n");
614 else if (try_palette(capture->deviceHandle, &capture->imageProperties, VIDEO_PALETTE_YUV411P, 16)) {
615 //printf("negotiated palette YUV420P\n");
618 fprintf(stderr, "HIGHGUI ERROR: V4L: Pixel format of incoming image is unsupported by OpenCV\n");
619 icvCloseCAM_V4L(capture);
629 static void v4l2_scan_controls_enumerate_menu(CvCaptureCAM_V4L* capture)
631 // printf (" Menu items:\n");
632 CLEAR (capture->querymenu);
633 capture->querymenu.id = capture->queryctrl.id;
634 for (capture->querymenu.index = capture->queryctrl.minimum;
635 (int)capture->querymenu.index <= capture->queryctrl.maximum;
636 capture->querymenu.index++)
638 if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYMENU,
639 &capture->querymenu))
641 // printf (" %s\n", capture->querymenu.name);
643 perror ("VIDIOC_QUERYMENU");
648 static void v4l2_scan_controls(CvCaptureCAM_V4L* capture)
653 for (ctrl_id = V4L2_CID_BASE;
654 ctrl_id < V4L2_CID_LASTP1;
658 /* set the id we will query now */
659 CLEAR (capture->queryctrl);
660 capture->queryctrl.id = ctrl_id;
662 if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYCTRL,
663 &capture->queryctrl))
666 if (capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
669 if (capture->queryctrl.id == V4L2_CID_BRIGHTNESS)
671 capture->v4l2_brightness = 1;
672 capture->v4l2_brightness_min = capture->queryctrl.minimum;
673 capture->v4l2_brightness_max = capture->queryctrl.maximum;
676 if (capture->queryctrl.id == V4L2_CID_CONTRAST)
678 capture->v4l2_contrast = 1;
679 capture->v4l2_contrast_min = capture->queryctrl.minimum;
680 capture->v4l2_contrast_max = capture->queryctrl.maximum;
683 if (capture->queryctrl.id == V4L2_CID_SATURATION)
685 capture->v4l2_saturation = 1;
686 capture->v4l2_saturation_min = capture->queryctrl.minimum;
687 capture->v4l2_saturation_max = capture->queryctrl.maximum;
690 if (capture->queryctrl.id == V4L2_CID_HUE)
692 capture->v4l2_hue = 1;
693 capture->v4l2_hue_min = capture->queryctrl.minimum;
694 capture->v4l2_hue_max = capture->queryctrl.maximum;
697 if (capture->queryctrl.id == V4L2_CID_GAIN)
699 capture->v4l2_gain = 1;
700 capture->v4l2_gain_min = capture->queryctrl.minimum;
701 capture->v4l2_gain_max = capture->queryctrl.maximum;
704 if (capture->queryctrl.id == V4L2_CID_EXPOSURE)
706 capture->v4l2_exposure = 1;
707 capture->v4l2_exposure_min = capture->queryctrl.minimum;
708 capture->v4l2_exposure_max = capture->queryctrl.maximum;
711 if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU)
712 v4l2_scan_controls_enumerate_menu(capture);
719 perror ("VIDIOC_QUERYCTRL");
725 for (ctrl_id = V4L2_CID_PRIVATE_BASE;;ctrl_id++)
728 /* set the id we will query now */
729 CLEAR (capture->queryctrl);
730 capture->queryctrl.id = ctrl_id;
732 if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYCTRL,
733 &capture->queryctrl))
736 if (capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
739 if (capture->queryctrl.id == V4L2_CID_BRIGHTNESS)
741 capture->v4l2_brightness = 1;
742 capture->v4l2_brightness_min = capture->queryctrl.minimum;
743 capture->v4l2_brightness_max = capture->queryctrl.maximum;
746 if (capture->queryctrl.id == V4L2_CID_CONTRAST)
748 capture->v4l2_contrast = 1;
749 capture->v4l2_contrast_min = capture->queryctrl.minimum;
750 capture->v4l2_contrast_max = capture->queryctrl.maximum;
753 if (capture->queryctrl.id == V4L2_CID_SATURATION)
755 capture->v4l2_saturation = 1;
756 capture->v4l2_saturation_min = capture->queryctrl.minimum;
757 capture->v4l2_saturation_max = capture->queryctrl.maximum;
760 if (capture->queryctrl.id == V4L2_CID_HUE)
762 capture->v4l2_hue = 1;
763 capture->v4l2_hue_min = capture->queryctrl.minimum;
764 capture->v4l2_hue_max = capture->queryctrl.maximum;
767 if (capture->queryctrl.id == V4L2_CID_GAIN)
769 capture->v4l2_gain = 1;
770 capture->v4l2_gain_min = capture->queryctrl.minimum;
771 capture->v4l2_gain_max = capture->queryctrl.maximum;
774 if (capture->queryctrl.id == V4L2_CID_EXPOSURE)
776 capture->v4l2_exposure = 1;
777 capture->v4l2_exposure_min = capture->queryctrl.minimum;
778 capture->v4l2_exposure_max = capture->queryctrl.maximum;
781 if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU)
782 v4l2_scan_controls_enumerate_menu(capture);
789 perror ("VIDIOC_QUERYCTRL");
797 static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName)
801 detect_v4l2 = try_init_v4l2(capture, deviceName);
803 if (detect_v4l2 != 1) {
804 /* init of the v4l2 device is not OK */
808 /* starting from here, we assume we are in V4L2 mode */
811 /* Init V4L2 control variables */
812 capture->v4l2_brightness = 0;
813 capture->v4l2_contrast = 0;
814 capture->v4l2_saturation = 0;
815 capture->v4l2_hue = 0;
816 capture->v4l2_gain = 0;
817 capture->v4l2_exposure = 0;
819 capture->v4l2_brightness_min = 0;
820 capture->v4l2_contrast_min = 0;
821 capture->v4l2_saturation_min = 0;
822 capture->v4l2_hue_min = 0;
823 capture->v4l2_gain_min = 0;
824 capture->v4l2_exposure_min = 0;
826 capture->v4l2_brightness_max = 0;
827 capture->v4l2_contrast_max = 0;
828 capture->v4l2_saturation_max = 0;
829 capture->v4l2_hue_max = 0;
830 capture->v4l2_gain_max = 0;
831 capture->v4l2_exposure_max = 0;
833 /* Scan V4L2 controls */
834 v4l2_scan_controls(capture);
836 if ((capture->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
838 fprintf( stderr, "HIGHGUI ERROR: V4L2: device %s is unable to capture video memory.\n",deviceName);
839 icvCloseCAM_V4L(capture);
843 /* The following code sets the CHANNEL_NUMBER of the video input. Some video sources
844 have sub "Channel Numbers". For a typical V4L TV capture card, this is usually 1.
845 I myself am using a simple NTSC video input capture card that uses the value of 1.
846 If you are not in North America or have a different video standard, you WILL have to change
847 the following settings and recompile/reinstall. This set of settings is based on
848 the most commonly encountered input video source types (like my bttv card) */
850 if(capture->inp.index > 0) {
851 CLEAR (capture->inp);
852 capture->inp.index = CHANNEL_NUMBER;
853 /* Set only channel number to CHANNEL_NUMBER */
854 /* V4L2 have a status field from selected video mode */
855 if (-1 == xioctl (capture->deviceHandle, VIDIOC_ENUMINPUT, &capture->inp))
857 fprintf (stderr, "HIGHGUI ERROR: V4L2: Aren't able to set channel number\n");
858 icvCloseCAM_V4L (capture);
863 /* Find Window info */
864 CLEAR (capture->form);
865 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
867 if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
868 fprintf( stderr, "HIGHGUI ERROR: V4L2: Could not obtain specifics of capture window.\n\n");
869 icvCloseCAM_V4L(capture);
873 if (V4L2_SUPPORT == 0)
877 if (autosetup_capture_mode_v4l2(capture) == -1)
880 icvSetVideoSize(capture, DEFAULT_V4L_WIDTH, DEFAULT_V4L_HEIGHT);
884 /* Buggy driver paranoia. */
885 min = capture->form.fmt.pix.width * 2;
887 if (capture->form.fmt.pix.bytesperline < min)
888 capture->form.fmt.pix.bytesperline = min;
890 min = capture->form.fmt.pix.bytesperline * capture->form.fmt.pix.height;
892 if (capture->form.fmt.pix.sizeimage < min)
893 capture->form.fmt.pix.sizeimage = min;
895 CLEAR (capture->req);
897 unsigned int buffer_number = DEFAULT_V4L_BUFFERS;
901 capture->req.count = buffer_number;
902 capture->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
903 capture->req.memory = V4L2_MEMORY_MMAP;
905 if (-1 == xioctl (capture->deviceHandle, VIDIOC_REQBUFS, &capture->req))
909 fprintf (stderr, "%s does not support memory mapping\n", deviceName);
911 perror ("VIDIOC_REQBUFS");
913 /* free capture, and returns an error code */
914 icvCloseCAM_V4L (capture);
918 if (capture->req.count < buffer_number)
920 if (buffer_number == 1)
922 fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName);
924 /* free capture, and returns an error code */
925 icvCloseCAM_V4L (capture);
929 fprintf (stderr, "Insufficient buffer memory on %s -- decreaseing buffers\n", deviceName);
935 for (n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
937 struct v4l2_buffer buf;
941 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
942 buf.memory = V4L2_MEMORY_MMAP;
943 buf.index = n_buffers;
945 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYBUF, &buf)) {
946 perror ("VIDIOC_QUERYBUF");
948 /* free capture, and returns an error code */
949 icvCloseCAM_V4L (capture);
953 capture->buffers[n_buffers].length = buf.length;
954 capture->buffers[n_buffers].start =
955 mmap (NULL /* start anywhere */,
957 PROT_READ | PROT_WRITE /* required */,
958 MAP_SHARED /* recommended */,
959 capture->deviceHandle, buf.m.offset);
961 if (MAP_FAILED == capture->buffers[n_buffers].start) {
964 /* free capture, and returns an error code */
965 icvCloseCAM_V4L (capture);
969 if (n_buffers == 0) {
970 capture->buffers[MAX_V4L_BUFFERS].start = malloc( buf.length );
971 capture->buffers[MAX_V4L_BUFFERS].length = buf.length;
975 /* Set up Image data */
976 cvInitImageHeader( &capture->frame,
977 cvSize( capture->captureWindow.width,
978 capture->captureWindow.height ),
979 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
980 /* Allocate space for RGBA data */
981 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
984 }; /* End _capture_V4L2 */
986 #endif /* HAVE_CAMV4L2 */
988 static int _capture_V4L (CvCaptureCAM_V4L *capture, char *deviceName)
992 detect_v4l = try_init_v4l(capture, deviceName);
994 if ((detect_v4l == -1)
997 fprintf (stderr, "HIGHGUI ERROR: V4L"
998 ": device %s: Unable to open for READ ONLY\n", deviceName);
1003 if ((detect_v4l <= 0)
1006 fprintf (stderr, "HIGHGUI ERROR: V4L"
1007 ": device %s: Unable to query number of channels\n", deviceName);
1013 if ((capture->capability.type & VID_TYPE_CAPTURE) == 0) {
1015 fprintf( stderr, "HIGHGUI ERROR: V4L: "
1016 "device %s is unable to capture video memory.\n",deviceName);
1017 icvCloseCAM_V4L(capture);
1024 /* The following code sets the CHANNEL_NUMBER of the video input. Some video sources
1025 have sub "Channel Numbers". For a typical V4L TV capture card, this is usually 1.
1026 I myself am using a simple NTSC video input capture card that uses the value of 1.
1027 If you are not in North America or have a different video standard, you WILL have to change
1028 the following settings and recompile/reinstall. This set of settings is based on
1029 the most commonly encountered input video source types (like my bttv card) */
1033 if(capture->capability.channels>0) {
1035 struct video_channel selectedChannel;
1036 memset(&selectedChannel, 0, sizeof(selectedChannel));
1038 selectedChannel.channel=CHANNEL_NUMBER;
1039 if (ioctl(capture->deviceHandle, VIDIOCGCHAN , &selectedChannel) != -1) {
1040 /* set the video mode to ( VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM) */
1041 // selectedChannel.norm = VIDEO_MODE_NTSC;
1042 if (ioctl(capture->deviceHandle, VIDIOCSCHAN , &selectedChannel) == -1) {
1043 /* Could not set selected channel - Oh well */
1044 //printf("\n%d, %s not NTSC capable.\n",selectedChannel.channel, selectedChannel.name);
1053 if(ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) == -1) {
1054 fprintf( stderr, "HIGHGUI ERROR: V4L: "
1055 "Could not obtain specifics of capture window.\n\n");
1056 icvCloseCAM_V4L(capture);
1064 if (autosetup_capture_mode_v4l(capture) == -1)
1071 ioctl(capture->deviceHandle, VIDIOCGMBUF, &capture->memoryBuffer);
1072 capture->memoryMap = (char *)mmap(0,
1073 capture->memoryBuffer.size,
1074 PROT_READ | PROT_WRITE,
1076 capture->deviceHandle,
1078 if (capture->memoryMap == MAP_FAILED) {
1079 fprintf( stderr, "HIGHGUI ERROR: V4L: Mapping Memmory from video source error: %s\n", strerror(errno));
1080 icvCloseCAM_V4L(capture);
1083 /* Set up video_mmap structure pointing to this memory mapped area so each image may be
1084 retrieved from an index value */
1085 capture->mmaps = (struct video_mmap *)
1086 (malloc(capture->memoryBuffer.frames * sizeof(struct video_mmap)));
1087 if (!capture->mmaps) {
1088 fprintf( stderr, "HIGHGUI ERROR: V4L: Could not memory map video frames.\n");
1089 icvCloseCAM_V4L(capture);
1095 /* Set up Image data */
1096 cvInitImageHeader( &capture->frame,
1097 cvSize( capture->captureWindow.width,
1098 capture->captureWindow.height ),
1099 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
1100 /* Allocate space for RGBA data */
1101 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1104 }; /* End _capture_V4L */
1106 static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index)
1108 static int autoindex;
1111 char deviceName[MAX_DEVICE_DRIVER_NAME];
1114 icvInitCapture_V4L(); /* Havent called icvInitCapture yet - do it now! */
1116 return NULL; /* Are there any /dev/video input sources? */
1118 //search index in indexList
1119 if ( (index>-1) && ! ((1 << index) & indexList) )
1121 fprintf( stderr, "HIGHGUI ERROR: V4L: index %d is not correct!\n",index);
1122 return NULL; /* Did someone ask for not correct video source number? */
1124 /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL
1125 the handles for V4L processing */
1126 CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L));
1128 fprintf( stderr, "HIGHGUI ERROR: V4L: Could not allocate memory for capture process.\n");
1131 /* Select camera, or rather, V4L video source */
1132 if (index<0) { // Asking for the first device available
1133 for (; autoindex<MAX_CAMERAS;autoindex++)
1134 if (indexList & (1<<autoindex))
1136 if (autoindex==MAX_CAMERAS)
1139 autoindex++;// i can recall icvOpenCAM_V4l with index=-1 for next camera
1141 /* Print the CameraNumber at the end of the string with a width of one character */
1142 sprintf(deviceName, "/dev/video%1d", index);
1144 /* w/o memset some parts arent initialized - AKA: Fill it with zeros so it is clean */
1145 memset(capture,0,sizeof(CvCaptureCAM_V4L));
1146 /* Present the routines needed for V4L funtionality. They are inserted as part of
1147 the standard set of cv calls promoting transparency. "Vector Table" insertion. */
1148 capture->FirstCapture = 1;
1151 if (_capture_V4L2 (capture, deviceName) == -1) {
1152 icvCloseCAM_V4L(capture);
1154 #endif /* HAVE_CAMV4L2 */
1155 if (_capture_V4L (capture, deviceName) == -1) {
1156 icvCloseCAM_V4L(capture);
1163 #endif /* HAVE_CAMV4L2 */
1166 }; /* End icvOpenCAM_V4L */
1170 static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
1171 struct v4l2_buffer buf;
1175 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1176 buf.memory = V4L2_MEMORY_MMAP;
1178 if (-1 == xioctl (capture->deviceHandle, VIDIOC_DQBUF, &buf)) {
1184 if (!(buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)))
1186 if (xioctl(capture->deviceHandle, VIDIOC_QBUF, &buf) == -1)
1194 /* display the error and stop processing */
1195 perror ("VIDIOC_DQBUF");
1200 assert(buf.index < capture->req.count);
1202 memcpy(capture->buffers[MAX_V4L_BUFFERS].start,
1203 capture->buffers[buf.index].start,
1204 capture->buffers[MAX_V4L_BUFFERS].length );
1205 capture->bufferIndex = MAX_V4L_BUFFERS;
1206 //printf("got data in buff %d, len=%d, flags=0x%X, seq=%d, used=%d)\n",
1207 // buf.index, buf.length, buf.flags, buf.sequence, buf.bytesused);
1209 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf))
1210 perror ("VIDIOC_QBUF");
1215 static void mainloop_v4l2(CvCaptureCAM_V4L* capture) {
1220 while (count-- > 0) {
1227 FD_SET (capture->deviceHandle, &fds);
1233 r = select (capture->deviceHandle+1, &fds, NULL, NULL, &tv);
1243 fprintf (stderr, "select timeout\n");
1245 /* end the infinite loop */
1249 if (read_frame_v4l2 (capture))
1255 #endif /* HAVE_CAMV4L2 */
1257 static int icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) {
1259 if (capture->FirstCapture) {
1260 /* Some general initialization must take place the first time through */
1262 /* This is just a technicality, but all buffers must be filled up before any
1263 staggered SYNC is applied. SO, filler up. (see V4L HowTo) */
1267 if (V4L2_SUPPORT == 1)
1270 for (capture->bufferIndex = 0;
1271 capture->bufferIndex < ((int)capture->req.count);
1272 ++capture->bufferIndex)
1275 struct v4l2_buffer buf;
1279 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1280 buf.memory = V4L2_MEMORY_MMAP;
1281 buf.index = (unsigned long)capture->bufferIndex;
1283 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) {
1284 perror ("VIDIOC_QBUF");
1289 /* enable the streaming */
1290 capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1291 if (-1 == xioctl (capture->deviceHandle, VIDIOC_STREAMON,
1293 /* error enabling the stream */
1294 perror ("VIDIOC_STREAMON");
1298 #endif /* HAVE_CAMV4L2 */
1301 for (capture->bufferIndex = 0;
1302 capture->bufferIndex < (capture->memoryBuffer.frames-1);
1303 ++capture->bufferIndex) {
1305 capture->mmaps[capture->bufferIndex].frame = capture->bufferIndex;
1306 capture->mmaps[capture->bufferIndex].width = capture->captureWindow.width;
1307 capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1308 capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1310 if (ioctl(capture->deviceHandle, VIDIOCMCAPTURE, &capture->mmaps[capture->bufferIndex]) == -1) {
1311 fprintf( stderr, "HIGHGUI ERROR: V4L: Initial Capture Error: Unable to load initial memory buffers.\n");
1318 #if defined(V4L_ABORT_BADJPEG) && defined(HAVE_CAMV4L2)
1319 if (V4L2_SUPPORT == 1)
1321 // skip first frame. it is often bad -- this is unnotied in traditional apps,
1322 // but could be fatal if bad jpeg is enabled
1323 mainloop_v4l2(capture);
1327 /* preparation is ok */
1328 capture->FirstCapture = 0;
1333 if (V4L2_SUPPORT == 1)
1336 mainloop_v4l2(capture);
1339 #endif /* HAVE_CAMV4L2 */
1342 capture->mmaps[capture->bufferIndex].frame = capture->bufferIndex;
1343 capture->mmaps[capture->bufferIndex].width = capture->captureWindow.width;
1344 capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1345 capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1347 if (ioctl (capture->deviceHandle, VIDIOCMCAPTURE,
1348 &capture->mmaps[capture->bufferIndex]) == -1) {
1349 /* capture is on the way, so just exit */
1353 ++capture->bufferIndex;
1354 if (capture->bufferIndex == capture->memoryBuffer.frames) {
1355 capture->bufferIndex = 0;
1364 * Turn a YUV4:2:0 block into an RGB block
1366 * Video4Linux seems to use the blue, green, red channel
1367 * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
1369 * Color space conversion coefficients taken from the excellent
1370 * http://www.inforamp.net/~poynton/ColorFAQ.html
1371 * In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
1372 * Y values are given for all 4 pixels, but the U (Pb)
1373 * and V (Pr) are assumed constant over the 2x2 block.
1375 * To avoid floating point arithmetic, the color conversion
1376 * coefficients are scaled into 16.16 fixed-point integers.
1377 * They were determined as follows:
1379 * double brightness = 1.0; (0->black; 1->full scale)
1380 * double saturation = 1.0; (0->greyscale; 1->full color)
1381 * double fixScale = brightness * 256 * 256;
1382 * int rvScale = (int)(1.402 * saturation * fixScale);
1383 * int guScale = (int)(-0.344136 * saturation * fixScale);
1384 * int gvScale = (int)(-0.714136 * saturation * fixScale);
1385 * int buScale = (int)(1.772 * saturation * fixScale);
1386 * int yScale = (int)(fixScale);
1389 /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
1390 #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
1393 move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
1394 int rowPixels, unsigned char * rgb)
1396 const int rvScale = 91881;
1397 const int guScale = -22553;
1398 const int gvScale = -46801;
1399 const int buScale = 116129;
1400 const int yScale = 65536;
1403 g = guScale * u + gvScale * v;
1412 yTL *= yScale; yTR *= yScale;
1413 yBL *= yScale; yBR *= yScale;
1415 /* Write out top two pixels */
1416 rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL);
1417 rgb[2] = LIMIT(r+yTL);
1419 rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR);
1420 rgb[5] = LIMIT(r+yTR);
1422 /* Skip down to next line to write out bottom two pixels */
1423 rgb += 3 * rowPixels;
1424 rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL);
1425 rgb[2] = LIMIT(r+yBL);
1427 rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR);
1428 rgb[5] = LIMIT(r+yBR);
1432 move_411_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
1433 int rowPixels, unsigned char * rgb)
1435 const int rvScale = 91881;
1436 const int guScale = -22553;
1437 const int gvScale = -46801;
1438 const int buScale = 116129;
1439 const int yScale = 65536;
1442 g = guScale * u + gvScale * v;
1451 yTL *= yScale; yTR *= yScale;
1452 yBL *= yScale; yBR *= yScale;
1454 /* Write out top two first pixels */
1455 rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL);
1456 rgb[2] = LIMIT(r+yTL);
1458 rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR);
1459 rgb[5] = LIMIT(r+yTR);
1461 /* Write out top two last pixels */
1463 rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL);
1464 rgb[2] = LIMIT(r+yBL);
1466 rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR);
1467 rgb[5] = LIMIT(r+yBR);
1470 // Consider a YUV420P image of 8x2 pixels.
1472 // A plane of Y values A B C D E F G H
1475 // A plane of U values 1 2 3 4
1476 // A plane of V values 1 2 3 4 ....
1478 // The U1/V1 samples correspond to the ABIJ pixels.
1479 // U2/V2 samples correspond to the CDKL pixels.
1481 /* Converts from planar YUV420P to RGB24. */
1483 yuv420p_to_rgb24(int width, int height,
1484 unsigned char *pIn0, unsigned char *pOut0)
1486 const int numpix = width * height;
1487 const int bytes = 24 >> 3;
1488 int i, j, y00, y01, y10, y11, u, v;
1489 unsigned char *pY = pIn0;
1490 unsigned char *pU = pY + numpix;
1491 unsigned char *pV = pU + numpix / 4;
1492 unsigned char *pOut = pOut0;
1494 for (j = 0; j <= height - 2; j += 2) {
1495 for (i = 0; i <= width - 2; i += 2) {
1498 y10 = *(pY + width);
1499 y11 = *(pY + width + 1);
1503 move_420_block(y00, y01, y10, y11, u, v,
1511 pOut += width * bytes;
1515 // Consider a YUV420 image of 6x2 pixels.
1520 // The U1/V1 samples correspond to the ABIJ pixels.
1521 // U2/V2 samples correspond to the CDKL pixels.
1523 /* Converts from interlaced YUV420 to RGB24. */
1524 /* [FD] untested... */
1526 yuv420_to_rgb24(int width, int height,
1527 unsigned char *pIn0, unsigned char *pOut0)
1529 const int bytes = 24 >> 3;
1530 int i, j, y00, y01, y10, y11, u, v;
1531 unsigned char *pY = pIn0;
1532 unsigned char *pU = pY + 4;
1533 unsigned char *pV = pU + width;
1534 unsigned char *pOut = pOut0;
1536 for (j = 0; j <= height - 2; j += 2) {
1537 for (i = 0; i <= width - 4; i += 4) {
1540 y10 = *(pY + width);
1541 y11 = *(pY + width + 1);
1545 move_420_block(y00, y01, y10, y11, u, v,
1553 y10 = *(pY + width);
1554 y11 = *(pY + width + 1);
1558 move_420_block(y00, y01, y10, y11, u, v,
1566 pOut += width * bytes;
1570 // Consider a YUV411P image of 8x2 pixels.
1572 // A plane of Y values as before.
1574 // A plane of U values 1 2
1577 // A plane of V values 1 2
1580 // The U1/V1 samples correspond to the ABCD pixels.
1581 // U2/V2 samples correspond to the EFGH pixels.
1583 /* Converts from planar YUV411P to RGB24. */
1584 /* [FD] untested... */
1586 yuv411p_to_rgb24(int width, int height,
1587 unsigned char *pIn0, unsigned char *pOut0)
1589 const int numpix = width * height;
1590 const int bytes = 24 >> 3;
1591 int i, j, y00, y01, y10, y11, u, v;
1592 unsigned char *pY = pIn0;
1593 unsigned char *pU = pY + numpix;
1594 unsigned char *pV = pU + numpix / 4;
1595 unsigned char *pOut = pOut0;
1597 for (j = 0; j <= height; j++) {
1598 for (i = 0; i <= width - 4; i += 4) {
1606 move_411_block(y00, y01, y10, y11, u, v,
1616 /* convert from 4:2:2 YUYV interlaced to RGB24 */
1617 /* based on ccvt_yuyv_bgr32() from camstream */
1619 if (c & (~255)) { if (c < 0) c = 0; else c = 255; }
1621 yuyv_to_rgb24 (int width, int height, unsigned char *src, unsigned char *dst)
1626 int r, g, b, cr, cg, cb, y1, y2;
1635 cb = ((*s - 128) * 454) >> 8;
1636 cg = (*s++ - 128) * 88;
1638 cr = ((*s - 128) * 359) >> 8;
1639 cg = (cg + (*s++ - 128) * 183) >> 8;
1667 uyvy_to_rgb24 (int width, int height, unsigned char *src, unsigned char *dst)
1672 int r, g, b, cr, cg, cb, y1, y2;
1680 cb = ((*s - 128) * 454) >> 8;
1681 cg = (*s++ - 128) * 88;
1683 cr = ((*s - 128) * 359) >> 8;
1684 cg = (cg + (*s++ - 128) * 183) >> 8;
1714 /* convert from mjpeg to rgb24 */
1716 mjpeg_to_rgb24 (int width, int height,
1717 unsigned char *src, int length,
1720 cv::Mat temp=cv::imdecode(cv::vector<uchar>(src, src + length), 1);
1721 if( !temp.data || temp.cols != width || temp.rows != height )
1723 memcpy(dst, temp.data, width*height*3);
1730 * BAYER2RGB24 ROUTINE TAKEN FROM:
1732 * Sonix SN9C10x based webcam basic I/F routines
1733 * Takafumi Mizuno <taka-qce@ls-a.jp>
1737 void bayer2rgb24(long int WIDTH, long int HEIGHT, unsigned char *src, unsigned char *dst)
1740 unsigned char *rawpt, *scanpt;
1745 size = WIDTH*HEIGHT;
1747 for ( i = 0; i < size; i++ ) {
1748 if ( (i/WIDTH) % 2 == 0 ) {
1749 if ( (i % 2) == 0 ) {
1751 if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
1752 *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
1753 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* R */
1754 *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
1755 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4; /* G */
1756 *scanpt++ = *rawpt; /* B */
1758 /* first line or left column */
1759 *scanpt++ = *(rawpt+WIDTH+1); /* R */
1760 *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2; /* G */
1761 *scanpt++ = *rawpt; /* B */
1765 if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
1766 *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* R */
1767 *scanpt++ = *rawpt; /* G */
1768 *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */
1770 /* first line or right column */
1771 *scanpt++ = *(rawpt+WIDTH); /* R */
1772 *scanpt++ = *rawpt; /* G */
1773 *scanpt++ = *(rawpt-1); /* B */
1777 if ( (i % 2) == 0 ) {
1779 if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
1780 *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */
1781 *scanpt++ = *rawpt; /* G */
1782 *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* B */
1784 /* bottom line or left column */
1785 *scanpt++ = *(rawpt+1); /* R */
1786 *scanpt++ = *rawpt; /* G */
1787 *scanpt++ = *(rawpt-WIDTH); /* B */
1791 if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
1792 *scanpt++ = *rawpt; /* R */
1793 *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
1794 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */
1795 *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
1796 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* B */
1798 /* bottom line or right column */
1799 *scanpt++ = *rawpt; /* R */
1800 *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2; /* G */
1801 *scanpt++ = *(rawpt-WIDTH-1); /* B */
1811 // for some reason, red and blue needs to be swapped
1812 // at least for 046d:092f Logitech, Inc. QuickCam Express Plus to work
1813 //see: http://www.siliconimaging.com/RGB%20Bayer.htm
1814 //and 4.6 at http://tldp.org/HOWTO/html_single/libdc1394-HOWTO/
1815 void sgbrg2rgb24(long int WIDTH, long int HEIGHT, unsigned char *src, unsigned char *dst)
1818 unsigned char *rawpt, *scanpt;
1823 size = WIDTH*HEIGHT;
1825 for ( i = 0; i < size; i++ )
1827 if ( (i/WIDTH) % 2 == 0 ) //even row
1829 if ( (i % 2) == 0 ) //even pixel
1831 if ( (i > WIDTH) && ((i % WIDTH) > 0) )
1833 *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */
1834 *scanpt++ = *(rawpt); /* G */
1835 *scanpt++ = (*(rawpt-WIDTH) + *(rawpt+WIDTH))/2; /* B */
1838 /* first line or left column */
1840 *scanpt++ = *(rawpt+1); /* R */
1841 *scanpt++ = *(rawpt); /* G */
1842 *scanpt++ = *(rawpt+WIDTH); /* B */
1846 if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) )
1848 *scanpt++ = *(rawpt); /* R */
1849 *scanpt++ = (*(rawpt-1)+*(rawpt+1)+*(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */
1850 *scanpt++ = (*(rawpt-WIDTH-1) + *(rawpt-WIDTH+1) + *(rawpt+WIDTH-1) + *(rawpt+WIDTH+1))/4; /* B */
1853 /* first line or right column */
1855 *scanpt++ = *(rawpt); /* R */
1856 *scanpt++ = (*(rawpt-1)+*(rawpt+WIDTH))/2; /* G */
1857 *scanpt++ = *(rawpt+WIDTH-1); /* B */
1862 if ( (i % 2) == 0 ) //even pixel
1864 if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) )
1866 *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+*(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* R */
1867 *scanpt++ = (*(rawpt-1)+*(rawpt+1)+*(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */
1868 *scanpt++ = *(rawpt); /* B */
1871 /* bottom line or left column */
1873 *scanpt++ = *(rawpt-WIDTH+1); /* R */
1874 *scanpt++ = (*(rawpt+1)+*(rawpt-WIDTH))/2; /* G */
1875 *scanpt++ = *(rawpt); /* B */
1879 if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) )
1881 *scanpt++ = (*(rawpt-WIDTH)+*(rawpt+WIDTH))/2; /* R */
1882 *scanpt++ = *(rawpt); /* G */
1883 *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */
1886 /* bottom line or right column */
1888 *scanpt++ = (*(rawpt-WIDTH)); /* R */
1889 *scanpt++ = *(rawpt); /* G */
1890 *scanpt++ = (*(rawpt-1)); /* B */
1899 #define CLAMP(x) ((x)<0?0:((x)>255)?255:(x))
1909 static code_table_t table[256];
1910 static int init_done = 0;
1914 sonix_decompress_init
1915 =====================
1916 pre-calculates a locally stored table for efficient huffman-decoding.
1918 Each entry at index x in the table represents the codeword
1919 present at the MSB of byte x.
1922 void sonix_decompress_init(void)
1925 int is_abs, val, len;
1927 for (i = 0; i < 256; i++) {
1931 if ((i & 0x80) == 0) {
1936 else if ((i & 0xE0) == 0x80) {
1941 else if ((i & 0xE0) == 0xA0) {
1946 else if ((i & 0xF0) == 0xD0) {
1951 else if ((i & 0xF0) == 0xF0) {
1956 else if ((i & 0xF8) == 0xC8) {
1961 else if ((i & 0xFC) == 0xC0) {
1966 else if ((i & 0xFC) == 0xC4) {
1967 /* code 110001xx: unknown */
1971 else if ((i & 0xF0) == 0xE0) {
1974 val = (i & 0x0F) << 4;
1977 table[i].is_abs = is_abs;
1989 decompresses an image encoded by a SN9C101 camera controller chip.
1993 inp pointer to compressed frame (with header already stripped)
1994 OUT outp pointer to decompressed frame
1996 Returns 0 if the operation was successful.
1997 Returns <0 if operation failed.
2000 int sonix_decompress(int width, int height, unsigned char *inp, unsigned char *outp)
2006 unsigned char *addr;
2009 /* do sonix_decompress_init first! */
2014 for (row = 0; row < height; row++) {
2020 /* first two pixels in first two rows are stored as raw 8-bit */
2022 addr = inp + (bitpos >> 3);
2023 code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
2027 addr = inp + (bitpos >> 3);
2028 code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
2035 while (col < width) {
2036 /* get bitcode from bitstream */
2037 addr = inp + (bitpos >> 3);
2038 code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
2040 /* update bit position */
2041 bitpos += table[code].len;
2043 /* calculate pixel value */
2044 val = table[code].val;
2045 if (!table[code].is_abs) {
2046 /* value is relative to top and left pixel */
2048 /* left column: relative to top pixel */
2049 val += outp[-2*width];
2052 /* top row: relative to left pixel */
2056 /* main area: average of left pixel and top pixel */
2057 val += (outp[-2] + outp[-2*width]) / 2;
2062 *outp++ = CLAMP(val);
2071 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int) {
2074 if (V4L2_SUPPORT == 0)
2075 #endif /* HAVE_CAMV4L2 */
2078 /* [FD] this really belongs here */
2079 if (ioctl(capture->deviceHandle, VIDIOCSYNC, &capture->mmaps[capture->bufferIndex].frame) == -1) {
2080 fprintf( stderr, "HIGHGUI ERROR: V4L: Could not SYNC to video stream. %s\n", strerror(errno));
2085 /* Now get what has already been captured as a IplImage return */
2087 /* First, reallocate imageData if the frame size changed */
2091 if (V4L2_SUPPORT == 1)
2094 if(((unsigned long)capture->frame.width != capture->form.fmt.pix.width)
2095 || ((unsigned long)capture->frame.height != capture->form.fmt.pix.height)) {
2096 cvFree(&capture->frame.imageData);
2097 cvInitImageHeader( &capture->frame,
2098 cvSize( capture->form.fmt.pix.width,
2099 capture->form.fmt.pix.height ),
2100 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
2101 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
2105 #endif /* HAVE_CAMV4L2 */
2108 if((capture->frame.width != capture->mmaps[capture->bufferIndex].width)
2109 || (capture->frame.height != capture->mmaps[capture->bufferIndex].height)) {
2110 cvFree(&capture->frame.imageData);
2111 cvInitImageHeader( &capture->frame,
2112 cvSize( capture->captureWindow.width,
2113 capture->captureWindow.height ),
2114 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
2115 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
2122 if (V4L2_SUPPORT == 1)
2125 if (PALETTE_BGR24 == 1)
2126 memcpy((char *)capture->frame.imageData,
2127 (char *)capture->buffers[capture->bufferIndex].start,
2128 capture->frame.imageSize);
2130 if (PALETTE_YVU420 == 1)
2131 yuv420p_to_rgb24(capture->form.fmt.pix.width,
2132 capture->form.fmt.pix.height,
2133 (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2134 (unsigned char*)capture->frame.imageData);
2136 if (PALETTE_YUV411P == 1)
2137 yuv411p_to_rgb24(capture->form.fmt.pix.width,
2138 capture->form.fmt.pix.height,
2139 (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2140 (unsigned char*)capture->frame.imageData);
2144 /* support for MJPEG is only available with libjpeg and gcc,
2145 because it's use libjepg and fmemopen()
2147 if (PALETTE_MJPEG == 1)
2148 if (!mjpeg_to_rgb24(capture->form.fmt.pix.width,
2149 capture->form.fmt.pix.height,
2150 (unsigned char*)(capture->buffers[capture->bufferIndex]
2152 capture->buffers[capture->bufferIndex].length,
2153 (unsigned char*)capture->frame.imageData))
2158 if (PALETTE_YUYV == 1)
2159 yuyv_to_rgb24(capture->form.fmt.pix.width,
2160 capture->form.fmt.pix.height,
2161 (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2162 (unsigned char*)capture->frame.imageData);
2164 if (PALETTE_UYVY == 1)
2165 uyvy_to_rgb24(capture->form.fmt.pix.width,
2166 capture->form.fmt.pix.height,
2167 (unsigned char*)(capture->buffers[capture->bufferIndex].start),
2168 (unsigned char*)capture->frame.imageData);
2170 if (PALETTE_SBGGR8 == 1)
2172 bayer2rgb24(capture->form.fmt.pix.width,
2173 capture->form.fmt.pix.height,
2174 (unsigned char*)capture->buffers[capture->bufferIndex].start,
2175 (unsigned char*)capture->frame.imageData);
2178 if (PALETTE_SN9C10X == 1)
2180 sonix_decompress_init();
2182 sonix_decompress(capture->form.fmt.pix.width,
2183 capture->form.fmt.pix.height,
2184 (unsigned char*)capture->buffers[capture->bufferIndex].start,
2185 (unsigned char*)capture->buffers[(capture->bufferIndex+1) % capture->req.count].start);
2187 bayer2rgb24(capture->form.fmt.pix.width,
2188 capture->form.fmt.pix.height,
2189 (unsigned char*)capture->buffers[(capture->bufferIndex+1) % capture->req.count].start,
2190 (unsigned char*)capture->frame.imageData);
2193 if (PALETTE_SGBRG == 1)
2195 sgbrg2rgb24(capture->form.fmt.pix.width,
2196 capture->form.fmt.pix.height,
2197 (unsigned char*)capture->buffers[(capture->bufferIndex+1) % capture->req.count].start,
2198 (unsigned char*)capture->frame.imageData);
2202 #endif /* HAVE_CAMV4L2 */
2205 switch(capture->imageProperties.palette) {
2206 case VIDEO_PALETTE_RGB24:
2207 memcpy((char *)capture->frame.imageData,
2208 (char *)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2209 capture->frame.imageSize);
2211 case VIDEO_PALETTE_YUV420P:
2212 yuv420p_to_rgb24(capture->captureWindow.width,
2213 capture->captureWindow.height,
2214 (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2215 (unsigned char*)capture->frame.imageData);
2217 case VIDEO_PALETTE_YUV420:
2218 yuv420_to_rgb24(capture->captureWindow.width,
2219 capture->captureWindow.height,
2220 (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2221 (unsigned char*)capture->frame.imageData);
2223 case VIDEO_PALETTE_YUV411P:
2224 yuv411p_to_rgb24(capture->captureWindow.width,
2225 capture->captureWindow.height,
2226 (unsigned char*)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
2227 (unsigned char*)capture->frame.imageData);
2231 "HIGHGUI ERROR: V4L: Cannot convert from palette %d to RGB\n",
2232 capture->imageProperties.palette);
2239 return(&capture->frame);
2242 static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture,
2247 if (V4L2_SUPPORT == 1)
2250 /* default value for min and max */
2254 CLEAR (capture->form);
2255 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2256 if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
2257 /* display an error message, and return an error code */
2258 perror ("VIDIOC_G_FMT");
2262 switch (property_id) {
2263 case CV_CAP_PROP_FRAME_WIDTH:
2264 return capture->form.fmt.pix.width;
2265 case CV_CAP_PROP_FRAME_HEIGHT:
2266 return capture->form.fmt.pix.height;
2269 /* initialize the control structure */
2271 switch (property_id) {
2272 case CV_CAP_PROP_BRIGHTNESS:
2273 capture->control.id = V4L2_CID_BRIGHTNESS;
2275 case CV_CAP_PROP_CONTRAST:
2276 capture->control.id = V4L2_CID_CONTRAST;
2278 case CV_CAP_PROP_SATURATION:
2279 capture->control.id = V4L2_CID_SATURATION;
2281 case CV_CAP_PROP_HUE:
2282 capture->control.id = V4L2_CID_HUE;
2284 case CV_CAP_PROP_GAIN:
2285 capture->control.id = V4L2_CID_GAIN;
2287 case CV_CAP_PROP_EXPOSURE:
2288 capture->control.id = V4L2_CID_EXPOSURE;
2292 "HIGHGUI ERROR: V4L2: getting property #%d is not supported\n",
2297 if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_CTRL,
2298 &capture->control)) {
2300 fprintf( stderr, "HIGHGUI ERROR: V4L2: ");
2301 switch (property_id) {
2302 case CV_CAP_PROP_BRIGHTNESS:
2303 fprintf (stderr, "Brightness");
2305 case CV_CAP_PROP_CONTRAST:
2306 fprintf (stderr, "Contrast");
2308 case CV_CAP_PROP_SATURATION:
2309 fprintf (stderr, "Saturation");
2311 case CV_CAP_PROP_HUE:
2312 fprintf (stderr, "Hue");
2314 case CV_CAP_PROP_GAIN:
2315 fprintf (stderr, "Gain");
2317 case CV_CAP_PROP_EXPOSURE:
2318 fprintf (stderr, "Exposure");
2321 fprintf (stderr, " is not supported by your device\n");
2326 /* get the min/max values */
2327 switch (property_id) {
2329 case CV_CAP_PROP_BRIGHTNESS:
2330 v4l2_min = capture->v4l2_brightness_min;
2331 v4l2_max = capture->v4l2_brightness_max;
2333 case CV_CAP_PROP_CONTRAST:
2334 v4l2_min = capture->v4l2_contrast_min;
2335 v4l2_max = capture->v4l2_contrast_max;
2337 case CV_CAP_PROP_SATURATION:
2338 v4l2_min = capture->v4l2_saturation_min;
2339 v4l2_max = capture->v4l2_saturation_max;
2341 case CV_CAP_PROP_HUE:
2342 v4l2_min = capture->v4l2_hue_min;
2343 v4l2_max = capture->v4l2_hue_max;
2345 case CV_CAP_PROP_GAIN:
2346 v4l2_min = capture->v4l2_gain_min;
2347 v4l2_max = capture->v4l2_gain_max;
2349 case CV_CAP_PROP_EXPOSURE:
2350 v4l2_min = capture->v4l2_exposure_min;
2351 v4l2_max = capture->v4l2_exposure_max;
2355 /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
2356 return ((float)capture->control.value - v4l2_min + 1) / (v4l2_max - v4l2_min);
2359 #endif /* HAVE_CAMV4L2 */
2364 if (ioctl (capture->deviceHandle,
2365 VIDIOCGWIN, &capture->captureWindow) < 0) {
2367 "HIGHGUI ERROR: V4L: "
2368 "Unable to determine size of incoming image\n");
2369 icvCloseCAM_V4L(capture);
2373 switch (property_id) {
2374 case CV_CAP_PROP_FRAME_WIDTH:
2375 retval = capture->captureWindow.width;
2377 case CV_CAP_PROP_FRAME_HEIGHT:
2378 retval = capture->captureWindow.height;
2380 case CV_CAP_PROP_BRIGHTNESS:
2381 retval = capture->imageProperties.brightness;
2383 case CV_CAP_PROP_CONTRAST:
2384 retval = capture->imageProperties.contrast;
2386 case CV_CAP_PROP_SATURATION:
2387 retval = capture->imageProperties.colour;
2389 case CV_CAP_PROP_HUE:
2390 retval = capture->imageProperties.hue;
2392 case CV_CAP_PROP_GAIN:
2394 "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
2397 case CV_CAP_PROP_EXPOSURE:
2399 "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n");
2404 "HIGHGUI ERROR: V4L: getting property #%d is not supported\n",
2409 /* there was a problem */
2413 /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
2414 return float (retval) / 0xFFFF;
2420 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h) {
2424 if (V4L2_SUPPORT == 1)
2427 CLEAR (capture->crop);
2428 capture->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2429 capture->crop.c.left = 0;
2430 capture->crop.c.top = 0;
2431 capture->crop.c.height = h*24;
2432 capture->crop.c.width = w*24;
2434 /* set the crop area, but don't exit if the device don't support croping */
2435 xioctl (capture->deviceHandle, VIDIOC_S_CROP, &capture->crop);
2437 CLEAR (capture->form);
2438 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2440 /* read the current setting, mainly to retreive the pixelformat information */
2441 xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form);
2443 /* set the values we want to change */
2444 capture->form.fmt.pix.width = w;
2445 capture->form.fmt.pix.height = h;
2446 capture->form.fmt.win.chromakey = 0;
2447 capture->form.fmt.win.field = V4L2_FIELD_ANY;
2448 capture->form.fmt.win.clips = 0;
2449 capture->form.fmt.win.clipcount = 0;
2450 capture->form.fmt.pix.field = V4L2_FIELD_ANY;
2452 /* ask the device to change the size
2453 * don't test if the set of the size is ok, because some device
2454 * don't allow changing the size, and we will get the real size
2456 xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form);
2458 /* try to set framerate to 30 fps */
2459 struct v4l2_streamparm setfps;
2460 memset (&setfps, 0, sizeof(struct v4l2_streamparm));
2461 setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2462 setfps.parm.capture.timeperframe.numerator = 1;
2463 setfps.parm.capture.timeperframe.denominator = 30;
2464 xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps);
2466 /* we need to re-initialize some things, like buffers, because the size has
2468 capture->FirstCapture = 1;
2470 /* Get window info again, to get the real value */
2471 if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form))
2473 fprintf(stderr, "HIGHGUI ERROR: V4L/V4L2: Could not obtain specifics of capture window.\n\n");
2475 icvCloseCAM_V4L(capture);
2483 #endif /* HAVE_CAMV4L2 */
2486 if (capture==0) return 0;
2487 if (w>capture->capability.maxwidth) {
2488 w=capture->capability.maxwidth;
2490 if (h>capture->capability.maxheight) {
2491 h=capture->capability.maxheight;
2494 capture->captureWindow.width=w;
2495 capture->captureWindow.height=h;
2497 if (ioctl(capture->deviceHandle, VIDIOCSWIN, &capture->captureWindow) < 0) {
2498 icvCloseCAM_V4L(capture);
2502 if (ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
2503 icvCloseCAM_V4L(capture);
2507 capture->FirstCapture = 1;
2515 static int icvSetControl (CvCaptureCAM_V4L* capture,
2516 int property_id, double value) {
2518 /* limitation of the input value */
2521 } else if (value > 1.0) {
2527 if (V4L2_SUPPORT == 1)
2530 /* default value for min and max */
2534 /* initialisations */
2535 CLEAR (capture->control);
2537 /* set which control we want to set */
2538 switch (property_id) {
2540 case CV_CAP_PROP_BRIGHTNESS:
2541 capture->control.id = V4L2_CID_BRIGHTNESS;
2543 case CV_CAP_PROP_CONTRAST:
2544 capture->control.id = V4L2_CID_CONTRAST;
2546 case CV_CAP_PROP_SATURATION:
2547 capture->control.id = V4L2_CID_SATURATION;
2549 case CV_CAP_PROP_HUE:
2550 capture->control.id = V4L2_CID_HUE;
2552 case CV_CAP_PROP_GAIN:
2553 capture->control.id = V4L2_CID_GAIN;
2555 case CV_CAP_PROP_EXPOSURE:
2556 capture->control.id = V4L2_CID_EXPOSURE;
2560 "HIGHGUI ERROR: V4L2: setting property #%d is not supported\n",
2565 /* get the min and max values */
2566 if (-1 == xioctl (capture->deviceHandle,
2567 VIDIOC_G_CTRL, &capture->control)) {
2568 // perror ("VIDIOC_G_CTRL for getting min/max values");
2572 /* get the min/max values */
2573 switch (property_id) {
2575 case CV_CAP_PROP_BRIGHTNESS:
2576 v4l2_min = capture->v4l2_brightness_min;
2577 v4l2_max = capture->v4l2_brightness_max;
2579 case CV_CAP_PROP_CONTRAST:
2580 v4l2_min = capture->v4l2_contrast_min;
2581 v4l2_max = capture->v4l2_contrast_max;
2583 case CV_CAP_PROP_SATURATION:
2584 v4l2_min = capture->v4l2_saturation_min;
2585 v4l2_max = capture->v4l2_saturation_max;
2587 case CV_CAP_PROP_HUE:
2588 v4l2_min = capture->v4l2_hue_min;
2589 v4l2_max = capture->v4l2_hue_max;
2591 case CV_CAP_PROP_GAIN:
2592 v4l2_min = capture->v4l2_gain_min;
2593 v4l2_max = capture->v4l2_gain_max;
2595 case CV_CAP_PROP_EXPOSURE:
2596 v4l2_min = capture->v4l2_exposure_min;
2597 v4l2_max = capture->v4l2_exposure_max;
2601 /* initialisations */
2602 CLEAR (capture->control);
2604 /* set which control we want to set */
2605 switch (property_id) {
2607 case CV_CAP_PROP_BRIGHTNESS:
2608 capture->control.id = V4L2_CID_BRIGHTNESS;
2610 case CV_CAP_PROP_CONTRAST:
2611 capture->control.id = V4L2_CID_CONTRAST;
2613 case CV_CAP_PROP_SATURATION:
2614 capture->control.id = V4L2_CID_SATURATION;
2616 case CV_CAP_PROP_HUE:
2617 capture->control.id = V4L2_CID_HUE;
2619 case CV_CAP_PROP_GAIN:
2620 capture->control.id = V4L2_CID_GAIN;
2622 case CV_CAP_PROP_EXPOSURE:
2623 capture->control.id = V4L2_CID_EXPOSURE;
2627 "HIGHGUI ERROR: V4L2: setting property #%d is not supported\n",
2632 /* set the value we want to set to the scaled the value */
2633 capture->control.value = (int)(value * (v4l2_max - v4l2_min) + v4l2_min);
2635 /* The driver may clamp the value or return ERANGE, ignored here */
2636 if (-1 == xioctl (capture->deviceHandle,
2637 VIDIOC_S_CTRL, &capture->control) && errno != ERANGE) {
2638 perror ("VIDIOC_S_CTRL");
2642 #endif /* HAVE_CAMV4L2 */
2647 /* scale the value to the wanted integer one */
2648 v4l_value = (int)(0xFFFF * value);
2650 switch (property_id) {
2651 case CV_CAP_PROP_BRIGHTNESS:
2652 capture->imageProperties.brightness = v4l_value;
2654 case CV_CAP_PROP_CONTRAST:
2655 capture->imageProperties.contrast = v4l_value;
2657 case CV_CAP_PROP_SATURATION:
2658 capture->imageProperties.colour = v4l_value;
2660 case CV_CAP_PROP_HUE:
2661 capture->imageProperties.hue = v4l_value;
2663 case CV_CAP_PROP_GAIN:
2665 "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
2667 case CV_CAP_PROP_EXPOSURE:
2669 "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n");
2673 "HIGHGUI ERROR: V4L: property #%d is not supported\n",
2678 if (ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties)
2682 "HIGHGUI ERROR: V4L: Unable to set video informations\n");
2683 icvCloseCAM_V4L(capture);
2693 static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture,
2694 int property_id, double value ){
2695 static int width = 0, height = 0;
2698 /* initialization */
2701 /* two subsequent calls setting WIDTH and HEIGHT will change
2703 /* the first one will return an error, though. */
2705 switch (property_id) {
2706 case CV_CAP_PROP_FRAME_WIDTH:
2707 width = cvRound(value);
2708 if(width !=0 && height != 0) {
2709 retval = icvSetVideoSize( capture, width, height);
2713 case CV_CAP_PROP_FRAME_HEIGHT:
2714 height = cvRound(value);
2715 if(width !=0 && height != 0) {
2716 retval = icvSetVideoSize( capture, width, height);
2720 case CV_CAP_PROP_BRIGHTNESS:
2721 case CV_CAP_PROP_CONTRAST:
2722 case CV_CAP_PROP_SATURATION:
2723 case CV_CAP_PROP_HUE:
2724 case CV_CAP_PROP_GAIN:
2725 case CV_CAP_PROP_EXPOSURE:
2726 retval = icvSetControl(capture, property_id, value);
2730 "HIGHGUI ERROR: V4L: setting property #%d is not supported\n",
2734 /* return the the status */
2738 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ){
2739 /* Deallocate space - Hopefully, no leaks */
2745 if (V4L2_SUPPORT == 0)
2746 #endif /* HAVE_CAMV4L2 */
2750 free(capture->mmaps);
2751 if (capture->memoryMap)
2752 munmap(capture->memoryMap, capture->memoryBuffer.size);
2757 capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2758 if (ioctl(capture->deviceHandle, VIDIOC_STREAMOFF, &capture->type) < 0) {
2759 perror ("Unable to stop the stream.");
2762 for (unsigned int n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
2764 if (-1 == munmap (capture->buffers[n_buffers].start, capture->buffers[n_buffers].length)) {
2769 if (capture->buffers[MAX_V4L_BUFFERS].start)
2771 free(capture->buffers[MAX_V4L_BUFFERS].start);
2772 capture->buffers[MAX_V4L_BUFFERS].start = 0;
2775 #endif /* HAVE_CAMV4L2 */
2777 if (capture->deviceHandle != -1)
2778 close(capture->deviceHandle);
2780 if (capture->frame.imageData) cvFree(&capture->frame.imageData);
2781 //cvFree((void **)capture);
2786 class CvCaptureCAM_V4L_CPP : CvCapture
2789 CvCaptureCAM_V4L_CPP() { captureV4L = 0; }
2790 virtual ~CvCaptureCAM_V4L_CPP() { close(); }
2792 virtual bool open( int index );
2793 virtual void close();
2795 virtual double getProperty(int);
2796 virtual bool setProperty(int, double);
2797 virtual bool grabFrame();
2798 virtual IplImage* retrieveFrame(int);
2801 CvCaptureCAM_V4L* captureV4L;
2804 bool CvCaptureCAM_V4L_CPP::open( int index )
2807 captureV4L = icvCaptureFromCAM_V4L(index);
2808 return captureV4L != 0;
2811 void CvCaptureCAM_V4L_CPP::close()
2815 icvCloseCAM_V4L( captureV4L );
2816 cvFree( &captureV4L );
2820 bool CvCaptureCAM_V4L_CPP::grabFrame()
2822 return captureV4L ? icvGrabFrameCAM_V4L( captureV4L ) != 0 : false;
2825 IplImage* CvCaptureCAM_V4L_CPP::retrieveFrame(int)
2827 return captureV4L ? icvRetrieveFrameCAM_V4L( captureV4L, 0 ) : 0;
2830 double CvCaptureCAM_V4L_CPP::getProperty( int propId )
2832 return captureV4L ? icvGetPropertyCAM_V4L( captureV4L, propId ) : 0.0;
2835 bool CvCaptureCAM_V4L_CPP::setProperty( int propId, double value )
2837 return captureV4L ? icvSetPropertyCAM_V4L( captureV4L, propId, value ) != 0 : false;
2840 CvCapture* cvCreateCameraCapture_V4L( int index )
2842 CvCaptureCAM_V4L_CPP* capture = new CvCaptureCAM_V4L_CPP;
2844 if( capture->open( index ))
2845 return (CvCapture*)capture;