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 your questions at answers.opencv.org,
18 Report bugs at code.opencv.org,
19 Submit your fixes at https://github.com/Itseez/opencv/
22 TW: The cv cam utils that came with the initial release of OpenCV for LINUX Beta4
23 were not working. I have rewritten them so they work for me. At the same time, trying
24 to keep the original code as ML wrote it as unchanged as possible. No one likes to debug
25 someone elses code, so I resisted changes as much as possible. I have tried to keep the
26 same "ideas" where applicable, that is, where I could figure out what the previous author
27 intended. Some areas I just could not help myself and had to "spiffy-it-up" my way.
29 These drivers should work with other V4L frame capture cards other then my bttv
30 driven frame capture card.
32 Re Written driver for standard V4L mode. Tested using LMLBT44 video capture card.
33 Standard bttv drivers are on the LMLBT44 with up to 8 Inputs.
35 This utility was written with the help of the document:
36 http://pages.cpsc.ucalgary.ca/~sayles/VFL_HowTo
37 as a general guide for interfacing into the V4l standard.
39 Made the index value passed for icvOpenCAM_V4L(index) be the number of the
40 video device source in the /dev tree. The -1 uses original /dev/video.
52 TW: You can select any video source, but this package was limited from the start to only
53 ONE camera opened at any ONE time.
54 This is an original program limitation.
55 If you are interested, I will make my version available to other OpenCV users. The big
56 difference in mine is you may pass the camera number as part of the cv argument, but this
57 convention is non standard for current OpenCV calls and the camera number is not currently
58 passed into the called routine.
60 Second Patch: August 28, 2004 Sfuncia Fabio fiblan@yahoo.it
61 For Release: OpenCV-Linux Beta4 Opencv-0.9.6
63 FS: this patch fix not sequential index of device (unplugged device), and real numCameras.
64 for -1 index (icvOpenCAM_V4L) i dont use /dev/video but real device available, because
65 if /dev/video is a link to /dev/video0 and i unplugged device on /dev/video0, /dev/video
66 is a bad link. I search the first available device with indexList.
68 Third Patch: December 9, 2004 Frederic Devernay Frederic.Devernay@inria.fr
69 For Release: OpenCV-Linux Beta4 Opencv-0.9.6
71 [FD] I modified the following:
72 - handle YUV420P, YUV420, and YUV411P palettes (for many webcams) without using floating-point
73 - cvGrabFrame should not wait for the end of the first frame, and should return quickly
75 - cvRetrieveFrame should in turn wait for the end of frame capture, and should not
76 trigger the capture of the next frame (the user choses when to do it using GrabFrame)
77 To get the old behavior, re-call cvRetrieveFrame just after cvGrabFrame.
78 - having global bufferIndex and FirstCapture variables makes the code non-reentrant
79 (e.g. when using several cameras), put these in the CvCapture struct.
80 - according to V4L HowTo, incrementing the buffer index must be done before VIDIOCMCAPTURE.
81 - the VID_TYPE_SCALES stuff from V4L HowTo is wrong: image size can be changed
82 even if the hardware does not support scaling (e.g. webcams can have several
83 resolutions available). Just don't try to set the size at 640x480 if the hardware supports
84 scaling: open with the default (probably best) image size, and let the user scale it
86 - image size can be changed by two subsequent calls to SetProperty (for width and height)
87 - bug fix: if the image size changes, realloc the new image only when it is grabbed
88 - issue errors only when necessary, fix error message formatting.
90 Fourth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu
91 For Release: OpenCV-Linux Beta5 OpenCV-0.9.7
93 I modified the following:
94 - Additional Video4Linux2 support :)
95 - Use mmap functions (v4l2)
96 - New methods are internal:
97 try_palette_v4l2 -> rewrite try_palette for v4l2
98 mainloop_v4l2, read_image_v4l2 -> this methods are moved from official v4l2 capture.c example
99 try_init_v4l -> device v4l initialisation
100 try_init_v4l2 -> device v4l2 initialisation
101 autosetup_capture_mode_v4l -> autodetect capture modes for v4l
102 autosetup_capture_mode_v4l2 -> autodetect capture modes for v4l2
103 - Modifications are according with Video4Linux old codes
104 - Video4Linux handling is automatically if it does not recognize a Video4Linux2 device
105 - Tested succesful with Logitech Quickcam Express (V4L), Creative Vista (V4L) and Genius VideoCam Notebook (V4L2)
106 - Correct source lines with compiler warning messages
107 - Information message from v4l/v4l2 detection
109 Fifth Patch: Sept 7, 2005 Csaba Kertesz sign@freemail.hu
110 For Release: OpenCV-Linux Beta5 OpenCV-0.9.7
112 I modified the following:
113 - SN9C10x chip based webcams support
114 - New methods are internal:
115 bayer2rgb24, sonix_decompress -> decoder routines for SN9C10x decoding from Takafumi Mizuno <taka-qce@ls-a.jp> with his pleasure :)
116 - Tested succesful with Genius VideoCam Notebook (V4L2)
118 Sixth Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu
119 For Release: OpenCV-Linux Beta5 OpenCV-0.9.7
121 I added the following:
122 - Add capture control support (hue, saturation, brightness, contrast, gain)
123 - Get and change V4L capture controls (hue, saturation, brightness, contrast)
124 - New method is internal:
125 icvSetControl -> set capture controls
126 - Tested succesful with Creative Vista (V4L)
128 Seventh Patch: Sept 10, 2005 Csaba Kertesz sign@freemail.hu
129 For Release: OpenCV-Linux Beta5 OpenCV-0.9.7
131 I added the following:
132 - Detect, get and change V4L2 capture controls (hue, saturation, brightness, contrast, gain)
133 - New methods are internal:
134 v4l2_scan_controls_enumerate_menu, v4l2_scan_controls -> detect capture control intervals
135 - Tested succesful with Genius VideoCam Notebook (V4L2)
137 8th patch: Jan 5, 2006, Olivier.Bornet@idiap.ch
138 Add support of V4L2_PIX_FMT_YUYV and V4L2_PIX_FMT_MJPEG.
139 With this patch, new webcams of Logitech, like QuickCam Fusion works.
140 Note: For use these webcams, look at the UVC driver at
141 http://linux-uvc.berlios.de/
143 9th patch: Mar 4, 2006, Olivier.Bornet@idiap.ch
144 - try V4L2 before V4L, because some devices are V4L2 by default,
145 but they try to implement the V4L compatibility layer.
146 So, I think this is better to support V4L2 before V4L.
147 - better separation between V4L2 and V4L initialization. (this was needed to support
148 some drivers working, but not fully with V4L2. (so, we do not know when we
149 need to switch from V4L2 to V4L.
151 10th patch: July 02, 2008, Mikhail Afanasyev fopencv@theamk.com
152 Fix reliability problems with high-resolution UVC cameras on linux
153 the symptoms were damaged image and 'Corrupt JPEG data: premature end of data segment' on stderr
154 - V4L_ABORT_BADJPEG detects JPEG warnings and turns them into errors, so bad images
155 could be filtered out
156 - USE_TEMP_BUFFER fixes the main problem (improper buffer management) and
157 prevents bad images in the first place
159 11th patch: Apr 13, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
160 - Tries to setup all properties first through v4l2_ioctl call.
161 - Allows seting up all Video4Linux properties through cvSetCaptureProperty instead of only CV_CAP_PROP_BRIGHTNESS, CV_CAP_PROP_CONTRAST, CV_CAP_PROP_SATURATION, CV_CAP_PROP_HUE, CV_CAP_PROP_GAIN and CV_CAP_PROP_EXPOSURE.
163 12th patch: Apr 16, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
164 - CvCaptureCAM_V4L structure cleanup (no longer needs <PROPERTY>_{min,max,} variables)
165 - Introduction of v4l2_ctrl_range - minimum and maximum allowed values for v4l controls
166 - Allows seting up all Video4Linux properties through cvSetCaptureProperty using input values between 0.0 and 1.0
167 - Gets v4l properties first through v4l2_ioctl call (ignores capture->is_v4l2_device)
168 - cvGetCaptureProperty adjusted to support the changes
169 - Returns device properties to initial values after device closes
171 13th patch: Apr 27, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
172 - Solved problem mmaping the device using uvcvideo driver (use o v4l2_mmap instead of mmap)
175 14th patch: May 10, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
176 - Bug #142: Solved/Workaround "setting frame width and height does not work"
177 There was a problem setting up the size when the input is a v4l2 device
178 The workaround closes the camera and reopens it with the new definition
179 Planning for future rewrite of this whole library (July/August 2010)
181 15th patch: May 12, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
182 - Broken compile of library (include "_highgui.h")
185 /*M///////////////////////////////////////////////////////////////////////////////////////
187 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
189 // By downloading, copying, installing or using the software you agree to this license.
190 // If you do not agree to this license, do not download, install,
191 // copy or use the software.
194 // Intel License Agreement
195 // For Open Source Computer Vision Library
197 // Copyright (C) 2000, Intel Corporation, all rights reserved.
198 // Third party copyrights are property of their respective owners.
200 // Redistribution and use in source and binary forms, with or without modification,
201 // are permitted provided that the following conditions are met:
203 // * Redistribution's of source code must retain the above copyright notice,
204 // this list of conditions and the following disclaimer.
206 // * Redistribution's in binary form must reproduce the above copyright notice,
207 // this list of conditions and the following disclaimer in the documentation
208 // and/or other materials provided with the distribution.
210 // * The name of Intel Corporation may not be used to endorse or promote products
211 // derived from this software without specific prior written permission.
213 // This software is provided by the copyright holders and contributors "as is" and
214 // any express or implied warranties, including, but not limited to, the implied
215 // warranties of merchantability and fitness for a particular purpose are disclaimed.
216 // In no event shall the Intel Corporation or contributors be liable for any direct,
217 // indirect, incidental, special, exemplary, or consequential damages
218 // (including, but not limited to, procurement of substitute goods or services;
219 // loss of use, data, or profits; or business interruption) however caused
220 // and on any theory of liability, whether in contract, strict liability,
221 // or tort (including negligence or otherwise) arising in any way out of
222 // the use of this software, even if advised of the possibility of such damage.
226 #include "precomp.hpp"
228 #if !defined WIN32 && defined HAVE_LIBV4L
230 #define CLEAR(x) memset (&(x), 0, sizeof (x))
236 #include <sys/types.h>
237 #include <sys/mman.h>
240 #include <asm/types.h> /* for videodev2.h */
242 #include <sys/stat.h>
243 #include <sys/ioctl.h>
246 #include <linux/videodev.h>
249 #include <linux/videodev2.h>
255 /* Defaults - If your board can do better, set it here. Set for the most common type inputs. */
256 #define DEFAULT_V4L_WIDTH 640
257 #define DEFAULT_V4L_HEIGHT 480
259 #define CHANNEL_NUMBER 1
260 #define MAX_CAMERAS 8
263 // default and maximum number of V4L buffers, not including last, 'special' buffer
264 #define MAX_V4L_BUFFERS 10
265 #define DEFAULT_V4L_BUFFERS 4
267 // if enabled, copies data from the buffer. this uses a bit more memory,
268 // but much more reliable for some UVC cameras
269 #define USE_TEMP_BUFFER
271 #define MAX_DEVICE_DRIVER_NAME 80
273 /* Device Capture Objects */
280 static unsigned int n_buffers = 0;
283 /* TODO: Consider drop the use of this data structure and perform ioctl to obtain needed values */
284 /* TODO: Consider at program exit return controls to the initial values - See v4l2_free_ranges function */
285 /* TODO: Consider at program exit reset the device to default values - See v4l2_free_ranges function */
286 typedef struct v4l2_ctrl_range {
295 typedef struct CvCaptureCAM_V4L
302 int width; int height;
304 struct video_capability capability;
305 struct video_window captureWindow;
306 struct video_picture imageProperties;
307 struct video_mbuf memoryBuffer;
308 struct video_mmap *mmaps;
313 buffer buffers[MAX_V4L_BUFFERS + 1];
314 struct v4l2_capability cap;
315 struct v4l2_input inp;
316 struct v4l2_format form;
317 struct v4l2_crop crop;
318 struct v4l2_cropcap cropcap;
319 struct v4l2_requestbuffers req;
320 struct v4l2_jpegcompression compr;
321 struct v4l2_control control;
322 enum v4l2_buf_type type;
323 struct v4l2_queryctrl queryctrl;
324 struct v4l2_querymenu querymenu;
326 /* V4L2 control variables */
327 v4l2_ctrl_range** v4l2_ctrl_ranges;
334 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture );
336 static int icvGrabFrameCAM_V4L( CvCaptureCAM_V4L* capture );
337 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int );
338 CvCapture* cvCreateCameraCapture_V4L( int index );
340 static double icvGetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id );
341 static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id, double value );
343 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h);
345 /*********************** Implementations ***************************************/
347 static int numCameras = 0;
348 static int indexList = 0;
350 // IOCTL handling for V4L2
351 #ifdef HAVE_IOCTL_ULONG
352 static int xioctl( int fd, unsigned long request, void *arg)
354 static int xioctl( int fd, int request, void *arg)
361 do r = v4l2_ioctl (fd, request, arg);
362 while (-1 == r && EINTR == errno);
369 /* Simple test program: Find number of Video Sources available.
370 Start from 0 and go to MAX_CAMERAS while checking for the device with that name.
371 If it fails on the first attempt of /dev/video0, then check if /dev/video is valid.
372 Returns the global numCameras with the correct value (we hope) */
374 static void icvInitCapture_V4L() {
377 char deviceName[MAX_DEVICE_DRIVER_NAME];
380 while(CameraNumber < MAX_CAMERAS) {
381 /* Print the CameraNumber at the end of the string with a width of one character */
382 sprintf(deviceName, "/dev/video%1d", CameraNumber);
383 /* Test using an open to see if this new device name really does exists. */
384 deviceHandle = open(deviceName, O_RDONLY);
385 if (deviceHandle != -1) {
386 /* This device does indeed exist - add it to the total so far */
388 indexList|=(1 << CameraNumber);
391 if (deviceHandle != -1)
393 /* Set up to test the next /dev/video source in line */
397 }; /* End icvInitCapture_V4L */
400 static int try_init_v4l(CvCaptureCAM_V4L* capture, char *deviceName)
404 // if detect = -1 then unable to open device
405 // if detect = 0 then detected nothing
406 // if detect = 1 then V4L device
410 // Test device for V4L compability
412 /* Test using an open to see if this new device name really does exists. */
413 /* No matter what the name - it still must be opened! */
414 capture->deviceHandle = v4l1_open(deviceName, O_RDWR);
417 if (capture->deviceHandle == 0)
421 icvCloseCAM_V4L(capture);
426 /* Query the newly opened device for its capabilities */
427 if (v4l1_ioctl(capture->deviceHandle, VIDIOCGCAP, &capture->capability) < 0)
431 icvCloseCAM_V4L(capture);
444 static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName)
447 // if detect = -1 then unable to open device
448 // if detect = 0 then detected nothing
449 // if detect = 1 then V4L2 device
453 // Test device for V4L2 compability
455 /* Open and test V4L2 device */
456 capture->deviceHandle = v4l2_open (deviceName, O_RDWR /* required */ | O_NONBLOCK, 0);
460 if (capture->deviceHandle == 0)
464 icvCloseCAM_V4L(capture);
469 CLEAR (capture->cap);
470 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYCAP, &capture->cap))
474 icvCloseCAM_V4L(capture);
478 CLEAR (capture->capability);
479 capture->capability.type = capture->cap.capabilities;
481 /* Query channels number */
482 if (-1 != xioctl (capture->deviceHandle, VIDIOC_G_INPUT, &capture->capability.channels))
494 static void v4l2_scan_controls_enumerate_menu(CvCaptureCAM_V4L* capture)
496 // printf (" Menu items:\n");
497 CLEAR (capture->querymenu);
498 capture->querymenu.id = capture->queryctrl.id;
499 for (capture->querymenu.index = capture->queryctrl.minimum;
500 (int)capture->querymenu.index <= capture->queryctrl.maximum;
501 capture->querymenu.index++)
503 if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYMENU,
504 &capture->querymenu))
506 //printf (" %s\n", capture->querymenu.name);
508 perror ("VIDIOC_QUERYMENU");
513 static void v4l2_free_ranges(CvCaptureCAM_V4L* capture) {
515 if (capture->v4l2_ctrl_ranges != NULL) {
516 for (i = 0; i < capture->v4l2_ctrl_count; i++) {
517 /* Return device to initial values: */
518 /* double value = (capture->v4l2_ctrl_ranges[i]->initial_value == 0)?0.0:((float)capture->v4l2_ctrl_ranges[i]->initial_value - capture->v4l2_ctrl_ranges[i]->minimum) / (capture->v4l2_ctrl_ranges[i]->maximum - capture->v4l2_ctrl_ranges[i]->minimum); */
519 /* Return device to default values: */
520 /* double value = (capture->v4l2_ctrl_ranges[i]->default_value == 0)?0.0:((float)capture->v4l2_ctrl_ranges[i]->default_value - capture->v4l2_ctrl_ranges[i]->minimum + 1) / (capture->v4l2_ctrl_ranges[i]->maximum - capture->v4l2_ctrl_ranges[i]->minimum); */
522 /* icvSetPropertyCAM_V4L(capture, capture->v4l2_ctrl_ranges[i]->ctrl_id, value); */
523 free(capture->v4l2_ctrl_ranges[i]);
526 free(capture->v4l2_ctrl_ranges);
527 capture->v4l2_ctrl_count = 0;
528 capture->v4l2_ctrl_ranges = NULL;
531 static void v4l2_add_ctrl_range(CvCaptureCAM_V4L* capture, v4l2_control* ctrl) {
532 v4l2_ctrl_range* range = (v4l2_ctrl_range*)malloc(sizeof(v4l2_ctrl_range));
533 range->ctrl_id = ctrl->id;
534 range->initial_value = ctrl->value;
535 range->current_value = ctrl->value;
536 range->minimum = capture->queryctrl.minimum;
537 range->maximum = capture->queryctrl.maximum;
538 range->default_value = capture->queryctrl.default_value;
539 capture->v4l2_ctrl_ranges[capture->v4l2_ctrl_count] = range;
540 capture->v4l2_ctrl_count += 1;
541 capture->v4l2_ctrl_ranges = (v4l2_ctrl_range**)realloc((v4l2_ctrl_range**)capture->v4l2_ctrl_ranges, (capture->v4l2_ctrl_count + 1) * sizeof(v4l2_ctrl_range*));
544 static int v4l2_get_ctrl_default(CvCaptureCAM_V4L* capture, __u32 id) {
546 for (i = 0; i < capture->v4l2_ctrl_count; i++) {
547 if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) {
548 return capture->v4l2_ctrl_ranges[i]->default_value;
554 static int v4l2_get_ctrl_min(CvCaptureCAM_V4L* capture, __u32 id) {
556 for (i = 0; i < capture->v4l2_ctrl_count; i++) {
557 if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) {
558 return capture->v4l2_ctrl_ranges[i]->minimum;
564 static int v4l2_get_ctrl_max(CvCaptureCAM_V4L* capture, __u32 id) {
566 for (i = 0; i < capture->v4l2_ctrl_count; i++) {
567 if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) {
568 return capture->v4l2_ctrl_ranges[i]->maximum;
575 static void v4l2_scan_controls(CvCaptureCAM_V4L* capture) {
578 struct v4l2_control c;
579 if (capture->v4l2_ctrl_ranges != NULL) {
580 v4l2_free_ranges(capture);
582 capture->v4l2_ctrl_ranges = (v4l2_ctrl_range**)malloc(sizeof(v4l2_ctrl_range*));
583 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL
584 /* Try the extended control API first */
585 capture->queryctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
586 if(0 == v4l2_ioctl (capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl)) {
588 c.id = capture->queryctrl.id;
589 capture->queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
590 if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
593 if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) {
594 v4l2_scan_controls_enumerate_menu(capture);
596 if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
597 capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
598 capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
601 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
602 v4l2_add_ctrl_range(capture, &c);
605 } while(0 == v4l2_ioctl (capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl));
609 /* Check all the standard controls */
610 for(ctrl_id=V4L2_CID_BASE; ctrl_id<V4L2_CID_LASTP1; ctrl_id++) {
611 capture->queryctrl.id = ctrl_id;
612 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl) == 0) {
613 if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
616 if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) {
617 v4l2_scan_controls_enumerate_menu(capture);
619 if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
620 capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
621 capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
626 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
627 v4l2_add_ctrl_range(capture, &c);
632 /* Check any custom controls */
633 for(ctrl_id=V4L2_CID_PRIVATE_BASE; ; ctrl_id++) {
634 capture->queryctrl.id = ctrl_id;
635 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl) == 0) {
636 if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
640 if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) {
641 v4l2_scan_controls_enumerate_menu(capture);
644 if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
645 capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
646 capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
652 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
653 v4l2_add_ctrl_range(capture, &c);
662 static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName)
666 capture->deviceName = strdup(deviceName);
668 detect_v4l2 = try_init_v4l2(capture, deviceName);
670 if (detect_v4l2 != 1) {
671 /* init of the v4l2 device is not OK */
675 /* starting from here, we assume we are in V4L2 mode */
676 capture->is_v4l2_device = 1;
678 capture->v4l2_ctrl_ranges = NULL;
679 capture->v4l2_ctrl_count = 0;
681 /* Scan V4L2 controls */
682 v4l2_scan_controls(capture);
684 if ((capture->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
686 fprintf( stderr, "HIGHGUI ERROR: V4L2: device %s is unable to capture video memory.\n",deviceName);
687 icvCloseCAM_V4L(capture);
691 /* The following code sets the CHANNEL_NUMBER of the video input. Some video sources
692 have sub "Channel Numbers". For a typical V4L TV capture card, this is usually 1.
693 I myself am using a simple NTSC video input capture card that uses the value of 1.
694 If you are not in North America or have a different video standard, you WILL have to change
695 the following settings and recompile/reinstall. This set of settings is based on
696 the most commonly encountered input video source types (like my bttv card) */
698 if(capture->inp.index > 0) {
699 CLEAR (capture->inp);
700 capture->inp.index = CHANNEL_NUMBER;
701 /* Set only channel number to CHANNEL_NUMBER */
702 /* V4L2 have a status field from selected video mode */
703 if (-1 == xioctl (capture->deviceHandle, VIDIOC_ENUMINPUT, &capture->inp))
705 fprintf (stderr, "HIGHGUI ERROR: V4L2: Aren't able to set channel number\n");
706 icvCloseCAM_V4L (capture);
711 /* Find Window info */
712 CLEAR (capture->form);
713 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
715 if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
716 fprintf( stderr, "HIGHGUI ERROR: V4L2: Could not obtain specifics of capture window.\n\n");
717 icvCloseCAM_V4L(capture);
721 /* libv4l will convert from any format to V4L2_PIX_FMT_BGR24 */
722 CLEAR (capture->form);
723 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
724 capture->form.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
725 capture->form.fmt.pix.field = V4L2_FIELD_ANY;
726 capture->form.fmt.pix.width = capture->width;
727 capture->form.fmt.pix.height = capture->height;
729 if (-1 == xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form)) {
730 fprintf(stderr, "HIGHGUI ERROR: libv4l unable to ioctl S_FMT\n");
734 if (V4L2_PIX_FMT_BGR24 != capture->form.fmt.pix.pixelformat) {
735 fprintf( stderr, "HIGHGUI ERROR: libv4l unable convert to requested pixfmt\n");
739 /* icvSetVideoSize(capture, DEFAULT_V4L_WIDTH, DEFAULT_V4L_HEIGHT); */
743 /* Buggy driver paranoia. */
744 min = capture->form.fmt.pix.width * 2;
746 if (capture->form.fmt.pix.bytesperline < min)
747 capture->form.fmt.pix.bytesperline = min;
749 min = capture->form.fmt.pix.bytesperline * capture->form.fmt.pix.height;
751 if (capture->form.fmt.pix.sizeimage < min)
752 capture->form.fmt.pix.sizeimage = min;
754 CLEAR (capture->req);
756 unsigned int buffer_number = DEFAULT_V4L_BUFFERS;
760 capture->req.count = buffer_number;
761 capture->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
762 capture->req.memory = V4L2_MEMORY_MMAP;
764 if (-1 == xioctl (capture->deviceHandle, VIDIOC_REQBUFS, &capture->req))
768 fprintf (stderr, "%s does not support memory mapping\n", deviceName);
770 perror ("VIDIOC_REQBUFS");
772 /* free capture, and returns an error code */
773 icvCloseCAM_V4L (capture);
777 if (capture->req.count < buffer_number)
779 if (buffer_number == 1)
781 fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName);
783 /* free capture, and returns an error code */
784 icvCloseCAM_V4L (capture);
788 fprintf (stderr, "Insufficient buffer memory on %s -- decreaseing buffers\n", deviceName);
794 for (n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
796 struct v4l2_buffer buf;
800 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
801 buf.memory = V4L2_MEMORY_MMAP;
802 buf.index = n_buffers;
804 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYBUF, &buf)) {
805 perror ("VIDIOC_QUERYBUF");
807 /* free capture, and returns an error code */
808 icvCloseCAM_V4L (capture);
812 capture->buffers[n_buffers].length = buf.length;
813 capture->buffers[n_buffers].start =
814 v4l2_mmap (NULL /* start anywhere */,
816 PROT_READ | PROT_WRITE /* required */,
817 MAP_SHARED /* recommended */,
818 capture->deviceHandle, buf.m.offset);
820 if (MAP_FAILED == capture->buffers[n_buffers].start) {
823 /* free capture, and returns an error code */
824 icvCloseCAM_V4L (capture);
828 #ifdef USE_TEMP_BUFFER
829 if (n_buffers == 0) {
830 if (capture->buffers[MAX_V4L_BUFFERS].start) {
831 free(capture->buffers[MAX_V4L_BUFFERS].start);
832 capture->buffers[MAX_V4L_BUFFERS].start = NULL;
835 capture->buffers[MAX_V4L_BUFFERS].start = malloc(buf.length);
836 capture->buffers[MAX_V4L_BUFFERS].length = buf.length;
841 /* Set up Image data */
842 cvInitImageHeader( &capture->frame,
843 cvSize( capture->captureWindow.width,
844 capture->captureWindow.height ),
845 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
846 /* Allocate space for RGBA data */
847 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
850 }; /* End _capture_V4L2 */
853 static int _capture_V4L (CvCaptureCAM_V4L *capture, char *deviceName)
857 detect_v4l = try_init_v4l(capture, deviceName);
859 if ((detect_v4l == -1)
862 fprintf (stderr, "HIGHGUI ERROR: V4L"
863 ": device %s: Unable to open for READ ONLY\n", deviceName);
868 if ((detect_v4l <= 0)
871 fprintf (stderr, "HIGHGUI ERROR: V4L"
872 ": device %s: Unable to query number of channels\n", deviceName);
878 if ((capture->capability.type & VID_TYPE_CAPTURE) == 0) {
880 fprintf( stderr, "HIGHGUI ERROR: V4L: "
881 "device %s is unable to capture video memory.\n",deviceName);
882 icvCloseCAM_V4L(capture);
889 /* The following code sets the CHANNEL_NUMBER of the video input. Some video sources
890 have sub "Channel Numbers". For a typical V4L TV capture card, this is usually 1.
891 I myself am using a simple NTSC video input capture card that uses the value of 1.
892 If you are not in North America or have a different video standard, you WILL have to change
893 the following settings and recompile/reinstall. This set of settings is based on
894 the most commonly encountered input video source types (like my bttv card) */
898 if(capture->capability.channels>0) {
900 struct video_channel selectedChannel;
902 selectedChannel.channel=CHANNEL_NUMBER;
903 if (v4l1_ioctl(capture->deviceHandle, VIDIOCGCHAN , &selectedChannel) != -1) {
904 /* set the video mode to ( VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM) */
905 // selectedChannel.norm = VIDEO_MODE_NTSC;
906 if (v4l1_ioctl(capture->deviceHandle, VIDIOCSCHAN , &selectedChannel) == -1) {
907 /* Could not set selected channel - Oh well */
908 //printf("\n%d, %s not NTSC capable.\n",selectedChannel.channel, selectedChannel.name);
917 if(v4l1_ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) == -1) {
918 fprintf( stderr, "HIGHGUI ERROR: V4L: "
919 "Could not obtain specifics of capture window.\n\n");
920 icvCloseCAM_V4L(capture);
927 if(v4l1_ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) {
928 fprintf( stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n");
929 icvCloseCAM_V4L(capture);
933 capture->imageProperties.palette = VIDEO_PALETTE_RGB24;
934 capture->imageProperties.depth = 24;
935 if (v4l1_ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties) < 0) {
936 fprintf( stderr, "HIGHGUI ERROR: libv4l unable to ioctl VIDIOCSPICT\n\n");
937 icvCloseCAM_V4L(capture);
940 if (v4l1_ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) {
941 fprintf( stderr, "HIGHGUI ERROR: libv4l unable to ioctl VIDIOCGPICT\n\n");
942 icvCloseCAM_V4L(capture);
945 if (capture->imageProperties.palette != VIDEO_PALETTE_RGB24) {
946 fprintf( stderr, "HIGHGUI ERROR: libv4l unable convert to requested pixfmt\n\n");
947 icvCloseCAM_V4L(capture);
955 v4l1_ioctl(capture->deviceHandle, VIDIOCGMBUF, &capture->memoryBuffer);
956 capture->memoryMap = (char *)v4l1_mmap(0,
957 capture->memoryBuffer.size,
958 PROT_READ | PROT_WRITE,
960 capture->deviceHandle,
962 if (capture->memoryMap == MAP_FAILED) {
963 fprintf( stderr, "HIGHGUI ERROR: V4L: Mapping Memmory from video source error: %s\n", strerror(errno));
964 icvCloseCAM_V4L(capture);
968 /* Set up video_mmap structure pointing to this memory mapped area so each image may be
969 retrieved from an index value */
970 capture->mmaps = (struct video_mmap *)
971 (malloc(capture->memoryBuffer.frames * sizeof(struct video_mmap)));
972 if (!capture->mmaps) {
973 fprintf( stderr, "HIGHGUI ERROR: V4L: Could not memory map video frames.\n");
974 icvCloseCAM_V4L(capture);
980 /* Set up Image data */
981 cvInitImageHeader( &capture->frame,
982 cvSize( capture->captureWindow.width,
983 capture->captureWindow.height ),
984 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
985 /* Allocate space for RGBA data */
986 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
989 }; /* End _capture_V4L */
991 static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index)
993 static int autoindex;
996 char deviceName[MAX_DEVICE_DRIVER_NAME];
999 icvInitCapture_V4L(); /* Havent called icvInitCapture yet - do it now! */
1001 return NULL; /* Are there any /dev/video input sources? */
1003 //search index in indexList
1004 if ( (index>-1) && ! ((1 << index) & indexList) )
1006 fprintf( stderr, "HIGHGUI ERROR: V4L: index %d is not correct!\n",index);
1007 return NULL; /* Did someone ask for not correct video source number? */
1009 /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL
1010 the handles for V4L processing */
1011 CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L));
1013 fprintf( stderr, "HIGHGUI ERROR: V4L: Could not allocate memory for capture process.\n");
1017 #ifdef USE_TEMP_BUFFER
1018 capture->buffers[MAX_V4L_BUFFERS].start = NULL;
1021 /* Select camera, or rather, V4L video source */
1022 if (index<0) { // Asking for the first device available
1023 for (; autoindex<MAX_CAMERAS;autoindex++)
1024 if (indexList & (1<<autoindex))
1026 if (autoindex==MAX_CAMERAS)
1029 autoindex++;// i can recall icvOpenCAM_V4l with index=-1 for next camera
1031 /* Print the CameraNumber at the end of the string with a width of one character */
1032 sprintf(deviceName, "/dev/video%1d", index);
1034 /* w/o memset some parts arent initialized - AKA: Fill it with zeros so it is clean */
1035 memset(capture,0,sizeof(CvCaptureCAM_V4L));
1036 /* Present the routines needed for V4L funtionality. They are inserted as part of
1037 the standard set of cv calls promoting transparency. "Vector Table" insertion. */
1038 capture->FirstCapture = 1;
1040 /* set the default size */
1041 capture->width = DEFAULT_V4L_WIDTH;
1042 capture->height = DEFAULT_V4L_HEIGHT;
1044 if (_capture_V4L2 (capture, deviceName) == -1) {
1045 icvCloseCAM_V4L(capture);
1046 capture->is_v4l2_device = 0;
1047 if (_capture_V4L (capture, deviceName) == -1) {
1048 icvCloseCAM_V4L(capture);
1052 capture->is_v4l2_device = 1;
1056 }; /* End icvOpenCAM_V4L */
1060 static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
1061 struct v4l2_buffer buf;
1065 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1066 buf.memory = V4L2_MEMORY_MMAP;
1068 if (-1 == xioctl (capture->deviceHandle, VIDIOC_DQBUF, &buf)) {
1074 /* Could ignore EIO, see spec. */
1079 /* display the error and stop processing */
1080 perror ("VIDIOC_DQBUF");
1085 assert(buf.index < capture->req.count);
1087 #ifdef USE_TEMP_BUFFER
1088 memcpy(capture->buffers[MAX_V4L_BUFFERS].start,
1089 capture->buffers[buf.index].start,
1090 capture->buffers[MAX_V4L_BUFFERS].length );
1091 capture->bufferIndex = MAX_V4L_BUFFERS;
1092 //printf("got data in buff %d, len=%d, flags=0x%X, seq=%d, used=%d)\n",
1093 // buf.index, buf.length, buf.flags, buf.sequence, buf.bytesused);
1095 capture->bufferIndex = buf.index;
1098 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf))
1099 perror ("VIDIOC_QBUF");
1104 static void mainloop_v4l2(CvCaptureCAM_V4L* capture) {
1109 while (count-- > 0) {
1116 FD_SET (capture->deviceHandle, &fds);
1122 r = select (capture->deviceHandle+1, &fds, NULL, NULL, &tv);
1132 fprintf (stderr, "select timeout\n");
1134 /* end the infinite loop */
1138 if (read_frame_v4l2 (capture))
1144 static int icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) {
1146 if (capture->FirstCapture) {
1147 /* Some general initialization must take place the first time through */
1149 /* This is just a technicality, but all buffers must be filled up before any
1150 staggered SYNC is applied. SO, filler up. (see V4L HowTo) */
1152 if (capture->is_v4l2_device == 1)
1155 for (capture->bufferIndex = 0;
1156 capture->bufferIndex < ((int)capture->req.count);
1157 ++capture->bufferIndex)
1160 struct v4l2_buffer buf;
1164 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1165 buf.memory = V4L2_MEMORY_MMAP;
1166 buf.index = (unsigned long)capture->bufferIndex;
1168 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) {
1169 perror ("VIDIOC_QBUF");
1174 /* enable the streaming */
1175 capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1176 if (-1 == xioctl (capture->deviceHandle, VIDIOC_STREAMON,
1178 /* error enabling the stream */
1179 perror ("VIDIOC_STREAMON");
1185 for (capture->bufferIndex = 0;
1186 capture->bufferIndex < (capture->memoryBuffer.frames-1);
1187 ++capture->bufferIndex) {
1189 capture->mmaps[capture->bufferIndex].frame = capture->bufferIndex;
1190 capture->mmaps[capture->bufferIndex].width = capture->captureWindow.width;
1191 capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1192 capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1194 if (v4l1_ioctl(capture->deviceHandle, VIDIOCMCAPTURE, &capture->mmaps[capture->bufferIndex]) == -1) {
1195 fprintf( stderr, "HIGHGUI ERROR: V4L: Initial Capture Error: Unable to load initial memory buffers.\n");
1202 /* preparation is ok */
1203 capture->FirstCapture = 0;
1206 if (capture->is_v4l2_device == 1)
1209 mainloop_v4l2(capture);
1214 capture->mmaps[capture->bufferIndex].frame = capture->bufferIndex;
1215 capture->mmaps[capture->bufferIndex].width = capture->captureWindow.width;
1216 capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1217 capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1219 if (v4l1_ioctl (capture->deviceHandle, VIDIOCMCAPTURE,
1220 &capture->mmaps[capture->bufferIndex]) == -1) {
1221 /* capture is on the way, so just exit */
1225 ++capture->bufferIndex;
1226 if (capture->bufferIndex == capture->memoryBuffer.frames) {
1227 capture->bufferIndex = 0;
1235 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int) {
1237 if (capture->is_v4l2_device == 0)
1240 /* [FD] this really belongs here */
1241 if (v4l1_ioctl(capture->deviceHandle, VIDIOCSYNC, &capture->mmaps[capture->bufferIndex].frame) == -1) {
1242 fprintf( stderr, "HIGHGUI ERROR: V4L: Could not SYNC to video stream. %s\n", strerror(errno));
1247 /* Now get what has already been captured as a IplImage return */
1249 /* First, reallocate imageData if the frame size changed */
1251 if (capture->is_v4l2_device == 1)
1254 if(((unsigned long)capture->frame.width != capture->form.fmt.pix.width)
1255 || ((unsigned long)capture->frame.height != capture->form.fmt.pix.height)) {
1256 cvFree(&capture->frame.imageData);
1257 cvInitImageHeader( &capture->frame,
1258 cvSize( capture->form.fmt.pix.width,
1259 capture->form.fmt.pix.height ),
1260 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
1261 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1267 if((capture->frame.width != capture->mmaps[capture->bufferIndex].width)
1268 || (capture->frame.height != capture->mmaps[capture->bufferIndex].height)) {
1269 cvFree(&capture->frame.imageData);
1270 cvInitImageHeader( &capture->frame,
1271 cvSize( capture->captureWindow.width,
1272 capture->captureWindow.height ),
1273 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
1274 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1279 if (capture->is_v4l2_device == 1)
1282 if(capture->buffers[capture->bufferIndex].start){
1283 memcpy((char *)capture->frame.imageData,
1284 (char *)capture->buffers[capture->bufferIndex].start,
1285 capture->frame.imageSize);
1289 #endif /* HAVE_CAMV4L2 */
1292 switch(capture->imageProperties.palette) {
1293 case VIDEO_PALETTE_RGB24:
1294 memcpy((char *)capture->frame.imageData,
1295 (char *)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
1296 capture->frame.imageSize);
1300 "HIGHGUI ERROR: V4L: Cannot convert from palette %d to RGB\n",
1301 capture->imageProperties.palette);
1307 return(&capture->frame);
1310 /* TODO: review this adaptation */
1311 static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture,
1314 int is_v4l2_device = 0;
1315 /* initialize the control structure */
1316 switch (property_id) {
1317 case CV_CAP_PROP_FRAME_WIDTH:
1318 case CV_CAP_PROP_FRAME_HEIGHT:
1319 CLEAR (capture->form);
1320 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1321 if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
1322 /* display an error message, and return an error code */
1323 perror ("VIDIOC_G_FMT");
1324 if (v4l1_ioctl (capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
1325 fprintf (stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n");
1326 icvCloseCAM_V4L(capture);
1329 int retval = (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->captureWindow.width:capture->captureWindow.height;
1330 return retval / 0xFFFF;
1333 return (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->form.fmt.pix.width:capture->form.fmt.pix.height;
1334 case CV_CAP_PROP_BRIGHTNESS:
1335 sprintf(name, "Brightness");
1336 capture->control.id = V4L2_CID_BRIGHTNESS;
1338 case CV_CAP_PROP_CONTRAST:
1339 sprintf(name, "Contrast");
1340 capture->control.id = V4L2_CID_CONTRAST;
1342 case CV_CAP_PROP_SATURATION:
1343 sprintf(name, "Saturation");
1344 capture->control.id = V4L2_CID_SATURATION;
1346 case CV_CAP_PROP_HUE:
1347 sprintf(name, "Hue");
1348 capture->control.id = V4L2_CID_HUE;
1350 case CV_CAP_PROP_GAIN:
1351 sprintf(name, "Gain");
1352 capture->control.id = V4L2_CID_GAIN;
1354 case CV_CAP_PROP_EXPOSURE:
1355 sprintf(name, "Exposure");
1356 capture->control.id = V4L2_CID_EXPOSURE;
1359 sprintf(name, "<unknown property string>");
1360 capture->control.id = property_id;
1363 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &capture->control) == 0) {
1367 fprintf(stderr, "HIGHGUI ERROR: V4L2: Unable to get property %s(%u) - %s\n", name, capture->control.id, strerror(errno));
1370 if (is_v4l2_device == 1) {
1371 /* get the min/max values */
1372 int v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
1373 int v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);
1375 if ((v4l2_min == -1) && (v4l2_max == -1)) {
1376 fprintf(stderr, "HIGHGUI ERROR: V4L2: Property %s(%u) not supported by device\n", name, property_id);
1380 /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
1381 return ((float)capture->control.value - v4l2_min) / (v4l2_max - v4l2_min);
1384 /* TODO: review this section */
1387 switch (property_id) {
1388 case CV_CAP_PROP_BRIGHTNESS:
1389 retval = capture->imageProperties.brightness;
1391 case CV_CAP_PROP_CONTRAST:
1392 retval = capture->imageProperties.contrast;
1394 case CV_CAP_PROP_SATURATION:
1395 retval = capture->imageProperties.colour;
1397 case CV_CAP_PROP_HUE:
1398 retval = capture->imageProperties.hue;
1400 case CV_CAP_PROP_GAIN:
1401 fprintf(stderr, "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
1404 case CV_CAP_PROP_EXPOSURE:
1405 fprintf(stderr, "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n");
1411 /* there was a problem */
1414 /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
1415 return float (retval) / 0xFFFF;
1419 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h) {
1421 if (capture->is_v4l2_device == 1)
1423 char deviceName[MAX_DEVICE_DRIVER_NAME];
1424 sprintf(deviceName, "%s", capture->deviceName);
1425 icvCloseCAM_V4L(capture);
1426 _capture_V4L2(capture, deviceName);
1428 CLEAR (capture->crop);
1429 capture->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1430 capture->crop.c.left = 0;
1431 capture->crop.c.top = 0;
1432 capture->crop.c.height = h*24;
1433 capture->crop.c.width = w*24;
1435 /* set the crop area, but don't exit if the device don't support croping */
1436 xioctl (capture->deviceHandle, VIDIOC_S_CROP, &capture->crop);
1438 CLEAR (capture->form);
1439 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1441 /* read the current setting, mainly to retreive the pixelformat information */
1442 xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form);
1444 /* set the values we want to change */
1445 capture->form.fmt.pix.width = w;
1446 capture->form.fmt.pix.height = h;
1447 capture->form.fmt.win.chromakey = 0;
1448 capture->form.fmt.win.field = V4L2_FIELD_ANY;
1449 capture->form.fmt.win.clips = 0;
1450 capture->form.fmt.win.clipcount = 0;
1451 capture->form.fmt.pix.field = V4L2_FIELD_ANY;
1453 /* ask the device to change the size
1454 * don't test if the set of the size is ok, because some device
1455 * don't allow changing the size, and we will get the real size
1457 xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form);
1459 /* try to set framerate to 30 fps */
1460 struct v4l2_streamparm setfps;
1461 memset (&setfps, 0, sizeof(struct v4l2_streamparm));
1462 setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1463 setfps.parm.capture.timeperframe.numerator = 1;
1464 setfps.parm.capture.timeperframe.denominator = 30;
1465 xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps);
1467 /* we need to re-initialize some things, like buffers, because the size has
1469 capture->FirstCapture = 1;
1471 /* Get window info again, to get the real value */
1472 if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form))
1474 fprintf(stderr, "HIGHGUI ERROR: V4L/V4L2: Could not obtain specifics of capture window.\n\n");
1476 icvCloseCAM_V4L(capture);
1486 if (capture==0) return 0;
1487 if (w>capture->capability.maxwidth) {
1488 w=capture->capability.maxwidth;
1490 if (h>capture->capability.maxheight) {
1491 h=capture->capability.maxheight;
1494 capture->captureWindow.width=w;
1495 capture->captureWindow.height=h;
1497 if (ioctl(capture->deviceHandle, VIDIOCSWIN, &capture->captureWindow) < 0) {
1498 icvCloseCAM_V4L(capture);
1502 if (ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
1503 icvCloseCAM_V4L(capture);
1507 capture->FirstCapture = 1;
1515 static int icvSetControl (CvCaptureCAM_V4L* capture, int property_id, double value) {
1516 struct v4l2_control c;
1522 if (capture->v4l2_ctrl_ranges == NULL) {
1523 v4l2_scan_controls(capture);
1526 CLEAR (capture->control);
1527 CLEAR (capture->queryctrl);
1529 /* get current values */
1530 switch (property_id) {
1531 case CV_CAP_PROP_BRIGHTNESS:
1532 sprintf(name, "Brightness");
1533 capture->control.id = V4L2_CID_BRIGHTNESS;
1535 case CV_CAP_PROP_CONTRAST:
1536 sprintf(name, "Contrast");
1537 capture->control.id = V4L2_CID_CONTRAST;
1539 case CV_CAP_PROP_SATURATION:
1540 sprintf(name, "Saturation");
1541 capture->control.id = V4L2_CID_SATURATION;
1543 case CV_CAP_PROP_HUE:
1544 sprintf(name, "Hue");
1545 capture->control.id = V4L2_CID_HUE;
1547 case CV_CAP_PROP_GAIN:
1548 sprintf(name, "Gain");
1549 capture->control.id = V4L2_CID_GAIN;
1551 case CV_CAP_PROP_EXPOSURE:
1552 sprintf(name, "Exposure");
1553 capture->control.id = V4L2_CID_EXPOSURE;
1556 sprintf(name, "<unknown property string>");
1557 capture->control.id = property_id;
1560 v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
1561 v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);
1563 if ((v4l2_min == -1) && (v4l2_max == -1)) {
1564 fprintf(stderr, "HIGHGUI ERROR: V4L: Property %s(%u) not supported by device\n", name, property_id);
1568 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &capture->control) == 0) {
1571 fprintf(stderr, "HIGHGUI ERROR: V4L2: Unable to get property %s(%u) - %s\n", name, capture->control.id, strerror(errno));
1574 if (v4l2_max != 0) {
1578 } else if (value > 1.0) {
1581 ctrl_value = val * (double)(v4l2_max - v4l2_min) + v4l2_min;
1583 ctrl_value = v4l2_get_ctrl_default(capture, capture->control.id) * (double)(v4l2_max - v4l2_min) + v4l2_min;
1586 /* try and set value as if it was a v4l2 device */
1587 c.id = capture->control.id;
1588 c.value = ctrl_value;
1589 if (v4l2_ioctl(capture->deviceHandle, VIDIOC_S_CTRL, &c) != 0) {
1590 /* The driver may clamp the value or return ERANGE, ignored here */
1591 if (errno != ERANGE) {
1592 fprintf(stderr, "HIGHGUI ERROR: V4L2: Failed to set control \"%d\": %s (value %d)\n", c.id, strerror(errno), c.value);
1601 if (is_v4l2 == 0) { /* use v4l1_ioctl */
1602 fprintf(stderr, "HIGHGUI WARNING: Setting property %u through v4l2 failed. Trying with v4l1.\n", c.id);
1604 /* scale the value to the wanted integer one */
1605 v4l_value = (int)(0xFFFF * value);
1607 switch (property_id) {
1608 case CV_CAP_PROP_BRIGHTNESS:
1609 capture->imageProperties.brightness = v4l_value;
1611 case CV_CAP_PROP_CONTRAST:
1612 capture->imageProperties.contrast = v4l_value;
1614 case CV_CAP_PROP_SATURATION:
1615 capture->imageProperties.colour = v4l_value;
1617 case CV_CAP_PROP_HUE:
1618 capture->imageProperties.hue = v4l_value;
1620 case CV_CAP_PROP_GAIN:
1621 fprintf(stderr, "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
1623 case CV_CAP_PROP_EXPOSURE:
1624 fprintf(stderr, "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n");
1627 fprintf(stderr, "HIGHGUI ERROR: V4L: property #%d is not supported\n", property_id);
1631 if (v4l1_ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties) < 0){
1632 fprintf(stderr, "HIGHGUI ERROR: V4L: Unable to set video informations\n");
1633 icvCloseCAM_V4L(capture);
1642 static int icvSetPropertyCAM_V4L(CvCaptureCAM_V4L* capture, int property_id, double value){
1643 static int width = 0, height = 0;
1646 /* initialization */
1649 /* two subsequent calls setting WIDTH and HEIGHT will change
1651 /* the first one will return an error, though. */
1653 switch (property_id) {
1654 case CV_CAP_PROP_FRAME_WIDTH:
1655 width = cvRound(value);
1656 capture->width = width;
1657 if(width !=0 && height != 0) {
1658 retval = icvSetVideoSize( capture, width, height);
1662 case CV_CAP_PROP_FRAME_HEIGHT:
1663 height = cvRound(value);
1664 capture->height = height;
1665 if(width !=0 && height != 0) {
1666 retval = icvSetVideoSize( capture, width, height);
1670 case CV_CAP_PROP_FPS:
1671 struct v4l2_streamparm setfps;
1672 memset (&setfps, 0, sizeof(struct v4l2_streamparm));
1673 setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1674 setfps.parm.capture.timeperframe.numerator = 1;
1675 setfps.parm.capture.timeperframe.denominator = value;
1676 if (xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps) < 0){
1677 fprintf(stderr, "HIGHGUI ERROR: V4L: Unable to set camera FPS\n");
1682 retval = icvSetControl(capture, property_id, value);
1685 /* return the the status */
1689 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ){
1690 /* Deallocate space - Hopefully, no leaks */
1692 v4l2_free_ranges(capture);
1693 if (capture->is_v4l2_device == 0) {
1694 if (capture->mmaps) {
1695 free(capture->mmaps);
1697 if (capture->memoryMap) {
1698 v4l1_munmap(capture->memoryMap, capture->memoryBuffer.size);
1700 if (capture->deviceHandle != -1) {
1701 v4l1_close(capture->deviceHandle);
1704 capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1705 if (xioctl(capture->deviceHandle, VIDIOC_STREAMOFF, &capture->type) < 0) {
1706 perror ("Unable to stop the stream.");
1708 for (unsigned int n_buffers2 = 0; n_buffers2 < capture->req.count; ++n_buffers2) {
1709 if (-1 == v4l2_munmap (capture->buffers[n_buffers2].start, capture->buffers[n_buffers2].length)) {
1714 if (capture->deviceHandle != -1) {
1715 v4l2_close(capture->deviceHandle);
1719 if (capture->frame.imageData)
1720 cvFree(&capture->frame.imageData);
1722 #ifdef USE_TEMP_BUFFER
1723 if (capture->buffers[MAX_V4L_BUFFERS].start) {
1724 free(capture->buffers[MAX_V4L_BUFFERS].start);
1725 capture->buffers[MAX_V4L_BUFFERS].start = NULL;
1729 free(capture->deviceName);
1730 capture->deviceName = NULL;
1731 //v4l2_free_ranges(capture);
1732 //cvFree((void **)capture);
1737 class CvCaptureCAM_V4L_CPP : CvCapture
1740 CvCaptureCAM_V4L_CPP() { captureV4L = 0; }
1741 virtual ~CvCaptureCAM_V4L_CPP() { close(); }
1743 virtual bool open( int index );
1744 virtual void close();
1746 virtual double getProperty(int);
1747 virtual bool setProperty(int, double);
1748 virtual bool grabFrame();
1749 virtual IplImage* retrieveFrame(int);
1752 CvCaptureCAM_V4L* captureV4L;
1755 bool CvCaptureCAM_V4L_CPP::open( int index )
1758 captureV4L = icvCaptureFromCAM_V4L(index);
1759 return captureV4L != 0;
1762 void CvCaptureCAM_V4L_CPP::close()
1766 icvCloseCAM_V4L( captureV4L );
1767 cvFree( &captureV4L );
1771 bool CvCaptureCAM_V4L_CPP::grabFrame()
1773 return captureV4L ? icvGrabFrameCAM_V4L( captureV4L ) != 0 : false;
1776 IplImage* CvCaptureCAM_V4L_CPP::retrieveFrame(int)
1778 return captureV4L ? icvRetrieveFrameCAM_V4L( captureV4L, 0 ) : 0;
1781 double CvCaptureCAM_V4L_CPP::getProperty( int propId )
1783 return captureV4L ? icvGetPropertyCAM_V4L( captureV4L, propId ) : 0.0;
1786 bool CvCaptureCAM_V4L_CPP::setProperty( int propId, double value )
1788 return captureV4L ? icvSetPropertyCAM_V4L( captureV4L, propId, value ) != 0 : false;
1791 CvCapture* cvCreateCameraCapture_V4L( int index )
1793 CvCaptureCAM_V4L_CPP* capture = new CvCaptureCAM_V4L_CPP;
1795 if( capture->open( index ))
1796 return (CvCapture*)capture;