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
157 11th patch: Apr 13, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
158 - Tries to setup all properties first through v4l2_ioctl call.
159 - 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.
161 12th patch: Apr 16, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
162 - CvCaptureCAM_V4L structure cleanup (no longer needs <PROPERTY>_{min,max,} variables)
163 - Introduction of v4l2_ctrl_range - minimum and maximum allowed values for v4l controls
164 - Allows seting up all Video4Linux properties through cvSetCaptureProperty using input values between 0.0 and 1.0
165 - Gets v4l properties first through v4l2_ioctl call (ignores capture->is_v4l2_device)
166 - cvGetCaptureProperty adjusted to support the changes
167 - Returns device properties to initial values after device closes
169 13th patch: Apr 27, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
170 - Solved problem mmaping the device using uvcvideo driver (use o v4l2_mmap instead of mmap)
173 14th patch: May 10, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
174 - Bug #142: Solved/Workaround "setting frame width and height does not work"
175 There was a problem setting up the size when the input is a v4l2 device
176 The workaround closes the camera and reopens it with the new definition
177 Planning for future rewrite of this whole library (July/August 2010)
179 15th patch: May 12, 2010, Filipe Almeida filipe.almeida@ist.utl.pt
180 - Broken compile of library (include "_highgui.h")
183 /*M///////////////////////////////////////////////////////////////////////////////////////
185 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
187 // By downloading, copying, installing or using the software you agree to this license.
188 // If you do not agree to this license, do not download, install,
189 // copy or use the software.
192 // Intel License Agreement
193 // For Open Source Computer Vision Library
195 // Copyright (C) 2000, Intel Corporation, all rights reserved.
196 // Third party copyrights are property of their respective owners.
198 // Redistribution and use in source and binary forms, with or without modification,
199 // are permitted provided that the following conditions are met:
201 // * Redistribution's of source code must retain the above copyright notice,
202 // this list of conditions and the following disclaimer.
204 // * Redistribution's in binary form must reproduce the above copyright notice,
205 // this list of conditions and the following disclaimer in the documentation
206 // and/or other materials provided with the distribution.
208 // * The name of Intel Corporation may not be used to endorse or promote products
209 // derived from this software without specific prior written permission.
211 // This software is provided by the copyright holders and contributors "as is" and
212 // any express or implied warranties, including, but not limited to, the implied
213 // warranties of merchantability and fitness for a particular purpose are disclaimed.
214 // In no event shall the Intel Corporation or contributors be liable for any direct,
215 // indirect, incidental, special, exemplary, or consequential damages
216 // (including, but not limited to, procurement of substitute goods or services;
217 // loss of use, data, or profits; or business interruption) however caused
218 // and on any theory of liability, whether in contract, strict liability,
219 // or tort (including negligence or otherwise) arising in any way out of
220 // the use of this software, even if advised of the possibility of such damage.
224 #include "precomp.hpp"
226 #if !defined WIN32 && defined HAVE_LIBV4L
228 #define CLEAR(x) memset (&(x), 0, sizeof (x))
234 #include <sys/types.h>
235 #include <sys/mman.h>
238 #include <asm/types.h> /* for videodev2.h */
240 #include <sys/stat.h>
241 #include <sys/ioctl.h>
244 #include <linux/videodev.h>
247 #include <linux/videodev2.h>
253 /* Defaults - If your board can do better, set it here. Set for the most common type inputs. */
254 #define DEFAULT_V4L_WIDTH 640
255 #define DEFAULT_V4L_HEIGHT 480
257 #define CHANNEL_NUMBER 1
258 #define MAX_CAMERAS 8
261 // default and maximum number of V4L buffers, not including last, 'special' buffer
262 #define MAX_V4L_BUFFERS 10
263 #define DEFAULT_V4L_BUFFERS 4
265 // if enabled, copies data from the buffer. this uses a bit more memory,
266 // but much more reliable for some UVC cameras
267 #define USE_TEMP_BUFFER
269 #define MAX_DEVICE_DRIVER_NAME 80
271 /* Device Capture Objects */
278 static unsigned int n_buffers = 0;
281 /* TODO: Consider drop the use of this data structure and perform ioctl to obtain needed values */
282 /* TODO: Consider at program exit return controls to the initial values - See v4l2_free_ranges function */
283 /* TODO: Consider at program exit reset the device to default values - See v4l2_free_ranges function */
284 typedef struct v4l2_ctrl_range {
293 typedef struct CvCaptureCAM_V4L
300 int width; int height;
302 struct video_capability capability;
303 struct video_window captureWindow;
304 struct video_picture imageProperties;
305 struct video_mbuf memoryBuffer;
306 struct video_mmap *mmaps;
311 buffer buffers[MAX_V4L_BUFFERS + 1];
312 struct v4l2_capability cap;
313 struct v4l2_input inp;
314 struct v4l2_format form;
315 struct v4l2_crop crop;
316 struct v4l2_cropcap cropcap;
317 struct v4l2_requestbuffers req;
318 struct v4l2_jpegcompression compr;
319 struct v4l2_control control;
320 enum v4l2_buf_type type;
321 struct v4l2_queryctrl queryctrl;
322 struct v4l2_querymenu querymenu;
324 /* V4L2 control variables */
325 v4l2_ctrl_range** v4l2_ctrl_ranges;
332 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture );
334 static int icvGrabFrameCAM_V4L( CvCaptureCAM_V4L* capture );
335 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int );
336 CvCapture* cvCreateCameraCapture_V4L( int index );
338 static double icvGetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id );
339 static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id, double value );
341 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h);
343 /*********************** Implementations ***************************************/
345 static int numCameras = 0;
346 static int indexList = 0;
348 // IOCTL handling for V4L2
349 #ifdef HAVE_IOCTL_ULONG
350 static int xioctl( int fd, unsigned long request, void *arg)
352 static int xioctl( int fd, int request, void *arg)
359 do r = v4l2_ioctl (fd, request, arg);
360 while (-1 == r && EINTR == errno);
367 /* Simple test program: Find number of Video Sources available.
368 Start from 0 and go to MAX_CAMERAS while checking for the device with that name.
369 If it fails on the first attempt of /dev/video0, then check if /dev/video is valid.
370 Returns the global numCameras with the correct value (we hope) */
372 static void icvInitCapture_V4L() {
375 char deviceName[MAX_DEVICE_DRIVER_NAME];
378 while(CameraNumber < MAX_CAMERAS) {
379 /* Print the CameraNumber at the end of the string with a width of one character */
380 sprintf(deviceName, "/dev/video%1d", CameraNumber);
381 /* Test using an open to see if this new device name really does exists. */
382 deviceHandle = open(deviceName, O_RDONLY);
383 if (deviceHandle != -1) {
384 /* This device does indeed exist - add it to the total so far */
386 indexList|=(1 << CameraNumber);
389 if (deviceHandle != -1)
391 /* Set up to test the next /dev/video source in line */
395 }; /* End icvInitCapture_V4L */
398 static int try_init_v4l(CvCaptureCAM_V4L* capture, char *deviceName)
402 // if detect = -1 then unable to open device
403 // if detect = 0 then detected nothing
404 // if detect = 1 then V4L device
408 // Test device for V4L compability
410 /* Test using an open to see if this new device name really does exists. */
411 /* No matter what the name - it still must be opened! */
412 capture->deviceHandle = v4l1_open(deviceName, O_RDWR);
415 if (capture->deviceHandle == 0)
419 icvCloseCAM_V4L(capture);
424 /* Query the newly opened device for its capabilities */
425 if (v4l1_ioctl(capture->deviceHandle, VIDIOCGCAP, &capture->capability) < 0)
429 icvCloseCAM_V4L(capture);
442 static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName)
445 // if detect = -1 then unable to open device
446 // if detect = 0 then detected nothing
447 // if detect = 1 then V4L2 device
451 // Test device for V4L2 compability
453 /* Open and test V4L2 device */
454 capture->deviceHandle = v4l2_open (deviceName, O_RDWR /* required */ | O_NONBLOCK, 0);
458 if (capture->deviceHandle == 0)
462 icvCloseCAM_V4L(capture);
467 CLEAR (capture->cap);
468 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYCAP, &capture->cap))
472 icvCloseCAM_V4L(capture);
476 CLEAR (capture->capability);
477 capture->capability.type = capture->cap.capabilities;
479 /* Query channels number */
480 if (-1 != xioctl (capture->deviceHandle, VIDIOC_G_INPUT, &capture->capability.channels))
492 static void v4l2_scan_controls_enumerate_menu(CvCaptureCAM_V4L* capture)
494 // printf (" Menu items:\n");
495 CLEAR (capture->querymenu);
496 capture->querymenu.id = capture->queryctrl.id;
497 for (capture->querymenu.index = capture->queryctrl.minimum;
498 (int)capture->querymenu.index <= capture->queryctrl.maximum;
499 capture->querymenu.index++)
501 if (0 == xioctl (capture->deviceHandle, VIDIOC_QUERYMENU,
502 &capture->querymenu))
504 //printf (" %s\n", capture->querymenu.name);
506 perror ("VIDIOC_QUERYMENU");
511 static void v4l2_free_ranges(CvCaptureCAM_V4L* capture) {
513 if (capture->v4l2_ctrl_ranges != NULL) {
514 for (i = 0; i < capture->v4l2_ctrl_count; i++) {
515 /* Return device to initial values: */
516 /* 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); */
517 /* Return device to default values: */
518 /* 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); */
520 /* icvSetPropertyCAM_V4L(capture, capture->v4l2_ctrl_ranges[i]->ctrl_id, value); */
521 free(capture->v4l2_ctrl_ranges[i]);
524 free(capture->v4l2_ctrl_ranges);
525 capture->v4l2_ctrl_count = 0;
526 capture->v4l2_ctrl_ranges = NULL;
529 static void v4l2_add_ctrl_range(CvCaptureCAM_V4L* capture, v4l2_control* ctrl) {
530 v4l2_ctrl_range* range = (v4l2_ctrl_range*)malloc(sizeof(v4l2_ctrl_range));
531 range->ctrl_id = ctrl->id;
532 range->initial_value = ctrl->value;
533 range->current_value = ctrl->value;
534 range->minimum = capture->queryctrl.minimum;
535 range->maximum = capture->queryctrl.maximum;
536 range->default_value = capture->queryctrl.default_value;
537 capture->v4l2_ctrl_ranges[capture->v4l2_ctrl_count] = range;
538 capture->v4l2_ctrl_count += 1;
539 capture->v4l2_ctrl_ranges = (v4l2_ctrl_range**)realloc((v4l2_ctrl_range**)capture->v4l2_ctrl_ranges, (capture->v4l2_ctrl_count + 1) * sizeof(v4l2_ctrl_range*));
542 static int v4l2_get_ctrl_default(CvCaptureCAM_V4L* capture, __u32 id) {
544 for (i = 0; i < capture->v4l2_ctrl_count; i++) {
545 if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) {
546 return capture->v4l2_ctrl_ranges[i]->default_value;
552 static int v4l2_get_ctrl_min(CvCaptureCAM_V4L* capture, __u32 id) {
554 for (i = 0; i < capture->v4l2_ctrl_count; i++) {
555 if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) {
556 return capture->v4l2_ctrl_ranges[i]->minimum;
562 static int v4l2_get_ctrl_max(CvCaptureCAM_V4L* capture, __u32 id) {
564 for (i = 0; i < capture->v4l2_ctrl_count; i++) {
565 if (id == capture->v4l2_ctrl_ranges[i]->ctrl_id) {
566 return capture->v4l2_ctrl_ranges[i]->maximum;
573 static void v4l2_scan_controls(CvCaptureCAM_V4L* capture) {
576 struct v4l2_control c;
577 if (capture->v4l2_ctrl_ranges != NULL) {
578 v4l2_free_ranges(capture);
580 capture->v4l2_ctrl_ranges = (v4l2_ctrl_range**)malloc(sizeof(v4l2_ctrl_range*));
581 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL
582 /* Try the extended control API first */
583 capture->queryctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
584 if(0 == v4l2_ioctl (capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl)) {
586 c.id = capture->queryctrl.id;
587 capture->queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
588 if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
591 if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) {
592 v4l2_scan_controls_enumerate_menu(capture);
594 if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
595 capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
596 capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
599 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
600 v4l2_add_ctrl_range(capture, &c);
603 } while(0 == v4l2_ioctl (capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl));
607 /* Check all the standard controls */
608 for(ctrl_id=V4L2_CID_BASE; ctrl_id<V4L2_CID_LASTP1; ctrl_id++) {
609 capture->queryctrl.id = ctrl_id;
610 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl) == 0) {
611 if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
614 if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) {
615 v4l2_scan_controls_enumerate_menu(capture);
617 if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
618 capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
619 capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
624 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
625 v4l2_add_ctrl_range(capture, &c);
630 /* Check any custom controls */
631 for(ctrl_id=V4L2_CID_PRIVATE_BASE; ; ctrl_id++) {
632 capture->queryctrl.id = ctrl_id;
633 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_QUERYCTRL, &capture->queryctrl) == 0) {
634 if(capture->queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
638 if (capture->queryctrl.type == V4L2_CTRL_TYPE_MENU) {
639 v4l2_scan_controls_enumerate_menu(capture);
642 if(capture->queryctrl.type != V4L2_CTRL_TYPE_INTEGER &&
643 capture->queryctrl.type != V4L2_CTRL_TYPE_BOOLEAN &&
644 capture->queryctrl.type != V4L2_CTRL_TYPE_MENU) {
650 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &c) == 0) {
651 v4l2_add_ctrl_range(capture, &c);
660 static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName)
664 capture->deviceName = strdup(deviceName);
666 detect_v4l2 = try_init_v4l2(capture, deviceName);
668 if (detect_v4l2 != 1) {
669 /* init of the v4l2 device is not OK */
673 /* starting from here, we assume we are in V4L2 mode */
674 capture->is_v4l2_device = 1;
676 capture->v4l2_ctrl_ranges = NULL;
677 capture->v4l2_ctrl_count = 0;
679 /* Scan V4L2 controls */
680 v4l2_scan_controls(capture);
682 if ((capture->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
684 fprintf( stderr, "HIGHGUI ERROR: V4L2: device %s is unable to capture video memory.\n",deviceName);
685 icvCloseCAM_V4L(capture);
689 /* The following code sets the CHANNEL_NUMBER of the video input. Some video sources
690 have sub "Channel Numbers". For a typical V4L TV capture card, this is usually 1.
691 I myself am using a simple NTSC video input capture card that uses the value of 1.
692 If you are not in North America or have a different video standard, you WILL have to change
693 the following settings and recompile/reinstall. This set of settings is based on
694 the most commonly encountered input video source types (like my bttv card) */
696 if(capture->inp.index > 0) {
697 CLEAR (capture->inp);
698 capture->inp.index = CHANNEL_NUMBER;
699 /* Set only channel number to CHANNEL_NUMBER */
700 /* V4L2 have a status field from selected video mode */
701 if (-1 == xioctl (capture->deviceHandle, VIDIOC_ENUMINPUT, &capture->inp))
703 fprintf (stderr, "HIGHGUI ERROR: V4L2: Aren't able to set channel number\n");
704 icvCloseCAM_V4L (capture);
709 /* Find Window info */
710 CLEAR (capture->form);
711 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
713 if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
714 fprintf( stderr, "HIGHGUI ERROR: V4L2: Could not obtain specifics of capture window.\n\n");
715 icvCloseCAM_V4L(capture);
719 /* libv4l will convert from any format to V4L2_PIX_FMT_BGR24 */
720 CLEAR (capture->form);
721 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
722 capture->form.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
723 capture->form.fmt.pix.field = V4L2_FIELD_ANY;
724 capture->form.fmt.pix.width = capture->width;
725 capture->form.fmt.pix.height = capture->height;
727 if (-1 == xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form)) {
728 fprintf(stderr, "HIGHGUI ERROR: libv4l unable to ioctl S_FMT\n");
732 if (V4L2_PIX_FMT_BGR24 != capture->form.fmt.pix.pixelformat) {
733 fprintf( stderr, "HIGHGUI ERROR: libv4l unable convert to requested pixfmt\n");
737 /* icvSetVideoSize(capture, DEFAULT_V4L_WIDTH, DEFAULT_V4L_HEIGHT); */
741 /* Buggy driver paranoia. */
742 min = capture->form.fmt.pix.width * 2;
744 if (capture->form.fmt.pix.bytesperline < min)
745 capture->form.fmt.pix.bytesperline = min;
747 min = capture->form.fmt.pix.bytesperline * capture->form.fmt.pix.height;
749 if (capture->form.fmt.pix.sizeimage < min)
750 capture->form.fmt.pix.sizeimage = min;
752 CLEAR (capture->req);
754 unsigned int buffer_number = DEFAULT_V4L_BUFFERS;
758 capture->req.count = buffer_number;
759 capture->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
760 capture->req.memory = V4L2_MEMORY_MMAP;
762 if (-1 == xioctl (capture->deviceHandle, VIDIOC_REQBUFS, &capture->req))
766 fprintf (stderr, "%s does not support memory mapping\n", deviceName);
768 perror ("VIDIOC_REQBUFS");
770 /* free capture, and returns an error code */
771 icvCloseCAM_V4L (capture);
775 if (capture->req.count < buffer_number)
777 if (buffer_number == 1)
779 fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName);
781 /* free capture, and returns an error code */
782 icvCloseCAM_V4L (capture);
786 fprintf (stderr, "Insufficient buffer memory on %s -- decreaseing buffers\n", deviceName);
792 for (n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
794 struct v4l2_buffer buf;
798 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
799 buf.memory = V4L2_MEMORY_MMAP;
800 buf.index = n_buffers;
802 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYBUF, &buf)) {
803 perror ("VIDIOC_QUERYBUF");
805 /* free capture, and returns an error code */
806 icvCloseCAM_V4L (capture);
810 capture->buffers[n_buffers].length = buf.length;
811 capture->buffers[n_buffers].start =
812 v4l2_mmap (NULL /* start anywhere */,
814 PROT_READ | PROT_WRITE /* required */,
815 MAP_SHARED /* recommended */,
816 capture->deviceHandle, buf.m.offset);
818 if (MAP_FAILED == capture->buffers[n_buffers].start) {
821 /* free capture, and returns an error code */
822 icvCloseCAM_V4L (capture);
826 #ifdef USE_TEMP_BUFFER
827 if (n_buffers == 0) {
828 if (capture->buffers[MAX_V4L_BUFFERS].start) {
829 free(capture->buffers[MAX_V4L_BUFFERS].start);
830 capture->buffers[MAX_V4L_BUFFERS].start = NULL;
833 capture->buffers[MAX_V4L_BUFFERS].start = malloc(buf.length);
834 capture->buffers[MAX_V4L_BUFFERS].length = buf.length;
839 /* Set up Image data */
840 cvInitImageHeader( &capture->frame,
841 cvSize( capture->captureWindow.width,
842 capture->captureWindow.height ),
843 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
844 /* Allocate space for RGBA data */
845 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
848 }; /* End _capture_V4L2 */
851 static int _capture_V4L (CvCaptureCAM_V4L *capture, char *deviceName)
855 detect_v4l = try_init_v4l(capture, deviceName);
857 if ((detect_v4l == -1)
860 fprintf (stderr, "HIGHGUI ERROR: V4L"
861 ": device %s: Unable to open for READ ONLY\n", deviceName);
866 if ((detect_v4l <= 0)
869 fprintf (stderr, "HIGHGUI ERROR: V4L"
870 ": device %s: Unable to query number of channels\n", deviceName);
876 if ((capture->capability.type & VID_TYPE_CAPTURE) == 0) {
878 fprintf( stderr, "HIGHGUI ERROR: V4L: "
879 "device %s is unable to capture video memory.\n",deviceName);
880 icvCloseCAM_V4L(capture);
887 /* The following code sets the CHANNEL_NUMBER of the video input. Some video sources
888 have sub "Channel Numbers". For a typical V4L TV capture card, this is usually 1.
889 I myself am using a simple NTSC video input capture card that uses the value of 1.
890 If you are not in North America or have a different video standard, you WILL have to change
891 the following settings and recompile/reinstall. This set of settings is based on
892 the most commonly encountered input video source types (like my bttv card) */
896 if(capture->capability.channels>0) {
898 struct video_channel selectedChannel;
900 selectedChannel.channel=CHANNEL_NUMBER;
901 if (v4l1_ioctl(capture->deviceHandle, VIDIOCGCHAN , &selectedChannel) != -1) {
902 /* set the video mode to ( VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM) */
903 // selectedChannel.norm = VIDEO_MODE_NTSC;
904 if (v4l1_ioctl(capture->deviceHandle, VIDIOCSCHAN , &selectedChannel) == -1) {
905 /* Could not set selected channel - Oh well */
906 //printf("\n%d, %s not NTSC capable.\n",selectedChannel.channel, selectedChannel.name);
915 if(v4l1_ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) == -1) {
916 fprintf( stderr, "HIGHGUI ERROR: V4L: "
917 "Could not obtain specifics of capture window.\n\n");
918 icvCloseCAM_V4L(capture);
925 if(v4l1_ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) {
926 fprintf( stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n");
927 icvCloseCAM_V4L(capture);
931 capture->imageProperties.palette = VIDEO_PALETTE_RGB24;
932 capture->imageProperties.depth = 24;
933 if (v4l1_ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties) < 0) {
934 fprintf( stderr, "HIGHGUI ERROR: libv4l unable to ioctl VIDIOCSPICT\n\n");
935 icvCloseCAM_V4L(capture);
938 if (v4l1_ioctl(capture->deviceHandle, VIDIOCGPICT, &capture->imageProperties) < 0) {
939 fprintf( stderr, "HIGHGUI ERROR: libv4l unable to ioctl VIDIOCGPICT\n\n");
940 icvCloseCAM_V4L(capture);
943 if (capture->imageProperties.palette != VIDEO_PALETTE_RGB24) {
944 fprintf( stderr, "HIGHGUI ERROR: libv4l unable convert to requested pixfmt\n\n");
945 icvCloseCAM_V4L(capture);
953 v4l1_ioctl(capture->deviceHandle, VIDIOCGMBUF, &capture->memoryBuffer);
954 capture->memoryMap = (char *)v4l1_mmap(0,
955 capture->memoryBuffer.size,
956 PROT_READ | PROT_WRITE,
958 capture->deviceHandle,
960 if (capture->memoryMap == MAP_FAILED) {
961 fprintf( stderr, "HIGHGUI ERROR: V4L: Mapping Memmory from video source error: %s\n", strerror(errno));
962 icvCloseCAM_V4L(capture);
966 /* Set up video_mmap structure pointing to this memory mapped area so each image may be
967 retrieved from an index value */
968 capture->mmaps = (struct video_mmap *)
969 (malloc(capture->memoryBuffer.frames * sizeof(struct video_mmap)));
970 if (!capture->mmaps) {
971 fprintf( stderr, "HIGHGUI ERROR: V4L: Could not memory map video frames.\n");
972 icvCloseCAM_V4L(capture);
978 /* Set up Image data */
979 cvInitImageHeader( &capture->frame,
980 cvSize( capture->captureWindow.width,
981 capture->captureWindow.height ),
982 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
983 /* Allocate space for RGBA data */
984 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
987 }; /* End _capture_V4L */
989 static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index)
991 static int autoindex;
994 char deviceName[MAX_DEVICE_DRIVER_NAME];
997 icvInitCapture_V4L(); /* Havent called icvInitCapture yet - do it now! */
999 return NULL; /* Are there any /dev/video input sources? */
1001 //search index in indexList
1002 if ( (index>-1) && ! ((1 << index) & indexList) )
1004 fprintf( stderr, "HIGHGUI ERROR: V4L: index %d is not correct!\n",index);
1005 return NULL; /* Did someone ask for not correct video source number? */
1007 /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL
1008 the handles for V4L processing */
1009 CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L));
1011 fprintf( stderr, "HIGHGUI ERROR: V4L: Could not allocate memory for capture process.\n");
1015 #ifdef USE_TEMP_BUFFER
1016 capture->buffers[MAX_V4L_BUFFERS].start = NULL;
1019 /* Select camera, or rather, V4L video source */
1020 if (index<0) { // Asking for the first device available
1021 for (; autoindex<MAX_CAMERAS;autoindex++)
1022 if (indexList & (1<<autoindex))
1024 if (autoindex==MAX_CAMERAS)
1027 autoindex++;// i can recall icvOpenCAM_V4l with index=-1 for next camera
1029 /* Print the CameraNumber at the end of the string with a width of one character */
1030 sprintf(deviceName, "/dev/video%1d", index);
1032 /* w/o memset some parts arent initialized - AKA: Fill it with zeros so it is clean */
1033 memset(capture,0,sizeof(CvCaptureCAM_V4L));
1034 /* Present the routines needed for V4L funtionality. They are inserted as part of
1035 the standard set of cv calls promoting transparency. "Vector Table" insertion. */
1036 capture->FirstCapture = 1;
1038 /* set the default size */
1039 capture->width = DEFAULT_V4L_WIDTH;
1040 capture->height = DEFAULT_V4L_HEIGHT;
1042 if (_capture_V4L2 (capture, deviceName) == -1) {
1043 icvCloseCAM_V4L(capture);
1044 capture->is_v4l2_device = 0;
1045 if (_capture_V4L (capture, deviceName) == -1) {
1046 icvCloseCAM_V4L(capture);
1050 capture->is_v4l2_device = 1;
1054 }; /* End icvOpenCAM_V4L */
1058 static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
1059 struct v4l2_buffer buf;
1063 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1064 buf.memory = V4L2_MEMORY_MMAP;
1066 if (-1 == xioctl (capture->deviceHandle, VIDIOC_DQBUF, &buf)) {
1072 /* Could ignore EIO, see spec. */
1077 /* display the error and stop processing */
1078 perror ("VIDIOC_DQBUF");
1083 assert(buf.index < capture->req.count);
1085 #ifdef USE_TEMP_BUFFER
1086 memcpy(capture->buffers[MAX_V4L_BUFFERS].start,
1087 capture->buffers[buf.index].start,
1088 capture->buffers[MAX_V4L_BUFFERS].length );
1089 capture->bufferIndex = MAX_V4L_BUFFERS;
1090 //printf("got data in buff %d, len=%d, flags=0x%X, seq=%d, used=%d)\n",
1091 // buf.index, buf.length, buf.flags, buf.sequence, buf.bytesused);
1093 capture->bufferIndex = buf.index;
1096 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf))
1097 perror ("VIDIOC_QBUF");
1102 static void mainloop_v4l2(CvCaptureCAM_V4L* capture) {
1107 while (count-- > 0) {
1114 FD_SET (capture->deviceHandle, &fds);
1120 r = select (capture->deviceHandle+1, &fds, NULL, NULL, &tv);
1130 fprintf (stderr, "select timeout\n");
1132 /* end the infinite loop */
1136 if (read_frame_v4l2 (capture))
1142 static int icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) {
1144 if (capture->FirstCapture) {
1145 /* Some general initialization must take place the first time through */
1147 /* This is just a technicality, but all buffers must be filled up before any
1148 staggered SYNC is applied. SO, filler up. (see V4L HowTo) */
1150 if (capture->is_v4l2_device == 1)
1153 for (capture->bufferIndex = 0;
1154 capture->bufferIndex < ((int)capture->req.count);
1155 ++capture->bufferIndex)
1158 struct v4l2_buffer buf;
1162 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1163 buf.memory = V4L2_MEMORY_MMAP;
1164 buf.index = (unsigned long)capture->bufferIndex;
1166 if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) {
1167 perror ("VIDIOC_QBUF");
1172 /* enable the streaming */
1173 capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1174 if (-1 == xioctl (capture->deviceHandle, VIDIOC_STREAMON,
1176 /* error enabling the stream */
1177 perror ("VIDIOC_STREAMON");
1183 for (capture->bufferIndex = 0;
1184 capture->bufferIndex < (capture->memoryBuffer.frames-1);
1185 ++capture->bufferIndex) {
1187 capture->mmaps[capture->bufferIndex].frame = capture->bufferIndex;
1188 capture->mmaps[capture->bufferIndex].width = capture->captureWindow.width;
1189 capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1190 capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1192 if (v4l1_ioctl(capture->deviceHandle, VIDIOCMCAPTURE, &capture->mmaps[capture->bufferIndex]) == -1) {
1193 fprintf( stderr, "HIGHGUI ERROR: V4L: Initial Capture Error: Unable to load initial memory buffers.\n");
1200 /* preparation is ok */
1201 capture->FirstCapture = 0;
1204 if (capture->is_v4l2_device == 1)
1207 mainloop_v4l2(capture);
1212 capture->mmaps[capture->bufferIndex].frame = capture->bufferIndex;
1213 capture->mmaps[capture->bufferIndex].width = capture->captureWindow.width;
1214 capture->mmaps[capture->bufferIndex].height = capture->captureWindow.height;
1215 capture->mmaps[capture->bufferIndex].format = capture->imageProperties.palette;
1217 if (v4l1_ioctl (capture->deviceHandle, VIDIOCMCAPTURE,
1218 &capture->mmaps[capture->bufferIndex]) == -1) {
1219 /* capture is on the way, so just exit */
1223 ++capture->bufferIndex;
1224 if (capture->bufferIndex == capture->memoryBuffer.frames) {
1225 capture->bufferIndex = 0;
1233 static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int) {
1235 if (capture->is_v4l2_device == 0)
1238 /* [FD] this really belongs here */
1239 if (v4l1_ioctl(capture->deviceHandle, VIDIOCSYNC, &capture->mmaps[capture->bufferIndex].frame) == -1) {
1240 fprintf( stderr, "HIGHGUI ERROR: V4L: Could not SYNC to video stream. %s\n", strerror(errno));
1245 /* Now get what has already been captured as a IplImage return */
1247 /* First, reallocate imageData if the frame size changed */
1249 if (capture->is_v4l2_device == 1)
1252 if(((unsigned long)capture->frame.width != capture->form.fmt.pix.width)
1253 || ((unsigned long)capture->frame.height != capture->form.fmt.pix.height)) {
1254 cvFree(&capture->frame.imageData);
1255 cvInitImageHeader( &capture->frame,
1256 cvSize( capture->form.fmt.pix.width,
1257 capture->form.fmt.pix.height ),
1258 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
1259 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1265 if((capture->frame.width != capture->mmaps[capture->bufferIndex].width)
1266 || (capture->frame.height != capture->mmaps[capture->bufferIndex].height)) {
1267 cvFree(&capture->frame.imageData);
1268 cvInitImageHeader( &capture->frame,
1269 cvSize( capture->captureWindow.width,
1270 capture->captureWindow.height ),
1271 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
1272 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize);
1277 if (capture->is_v4l2_device == 1)
1280 if(capture->buffers[capture->bufferIndex].start){
1281 memcpy((char *)capture->frame.imageData,
1282 (char *)capture->buffers[capture->bufferIndex].start,
1283 capture->frame.imageSize);
1287 #endif /* HAVE_CAMV4L2 */
1290 switch(capture->imageProperties.palette) {
1291 case VIDEO_PALETTE_RGB24:
1292 memcpy((char *)capture->frame.imageData,
1293 (char *)(capture->memoryMap + capture->memoryBuffer.offsets[capture->bufferIndex]),
1294 capture->frame.imageSize);
1298 "HIGHGUI ERROR: V4L: Cannot convert from palette %d to RGB\n",
1299 capture->imageProperties.palette);
1305 return(&capture->frame);
1308 /* TODO: review this adaptation */
1309 static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture,
1312 int is_v4l2_device = 0;
1313 /* initialize the control structure */
1314 switch (property_id) {
1315 case CV_CAP_PROP_FRAME_WIDTH:
1316 case CV_CAP_PROP_FRAME_HEIGHT:
1317 CLEAR (capture->form);
1318 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1319 if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
1320 /* display an error message, and return an error code */
1321 perror ("VIDIOC_G_FMT");
1322 if (v4l1_ioctl (capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
1323 fprintf (stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n");
1324 icvCloseCAM_V4L(capture);
1327 int retval = (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->captureWindow.width:capture->captureWindow.height;
1328 return retval / 0xFFFF;
1331 return (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->form.fmt.pix.width:capture->form.fmt.pix.height;
1332 case CV_CAP_PROP_BRIGHTNESS:
1333 sprintf(name, "Brightness");
1334 capture->control.id = V4L2_CID_BRIGHTNESS;
1336 case CV_CAP_PROP_CONTRAST:
1337 sprintf(name, "Contrast");
1338 capture->control.id = V4L2_CID_CONTRAST;
1340 case CV_CAP_PROP_SATURATION:
1341 sprintf(name, "Saturation");
1342 capture->control.id = V4L2_CID_SATURATION;
1344 case CV_CAP_PROP_HUE:
1345 sprintf(name, "Hue");
1346 capture->control.id = V4L2_CID_HUE;
1348 case CV_CAP_PROP_GAIN:
1349 sprintf(name, "Gain");
1350 capture->control.id = V4L2_CID_GAIN;
1352 case CV_CAP_PROP_EXPOSURE:
1353 sprintf(name, "Exposure");
1354 capture->control.id = V4L2_CID_EXPOSURE;
1357 sprintf(name, "<unknown property string>");
1358 capture->control.id = property_id;
1361 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &capture->control) == 0) {
1365 fprintf(stderr, "HIGHGUI ERROR: V4L2: Unable to get property %s(%u) - %s\n", name, capture->control.id, strerror(errno));
1368 if (is_v4l2_device == 1) {
1369 /* get the min/max values */
1370 int v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
1371 int v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);
1373 if ((v4l2_min == -1) && (v4l2_max == -1)) {
1374 fprintf(stderr, "HIGHGUI ERROR: V4L2: Property %s(%u) not supported by device\n", name, property_id);
1378 /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
1379 return ((float)capture->control.value - v4l2_min) / (v4l2_max - v4l2_min);
1382 /* TODO: review this section */
1385 switch (property_id) {
1386 case CV_CAP_PROP_BRIGHTNESS:
1387 retval = capture->imageProperties.brightness;
1389 case CV_CAP_PROP_CONTRAST:
1390 retval = capture->imageProperties.contrast;
1392 case CV_CAP_PROP_SATURATION:
1393 retval = capture->imageProperties.colour;
1395 case CV_CAP_PROP_HUE:
1396 retval = capture->imageProperties.hue;
1398 case CV_CAP_PROP_GAIN:
1399 fprintf(stderr, "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
1402 case CV_CAP_PROP_EXPOSURE:
1403 fprintf(stderr, "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n");
1409 /* there was a problem */
1412 /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
1413 return float (retval) / 0xFFFF;
1417 static int icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h) {
1419 if (capture->is_v4l2_device == 1)
1421 char deviceName[MAX_DEVICE_DRIVER_NAME];
1422 sprintf(deviceName, "%s", capture->deviceName);
1423 icvCloseCAM_V4L(capture);
1424 _capture_V4L2(capture, deviceName);
1426 CLEAR (capture->crop);
1427 capture->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1428 capture->crop.c.left = 0;
1429 capture->crop.c.top = 0;
1430 capture->crop.c.height = h*24;
1431 capture->crop.c.width = w*24;
1433 /* set the crop area, but don't exit if the device don't support croping */
1434 xioctl (capture->deviceHandle, VIDIOC_S_CROP, &capture->crop);
1436 CLEAR (capture->form);
1437 capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1439 /* read the current setting, mainly to retreive the pixelformat information */
1440 xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form);
1442 /* set the values we want to change */
1443 capture->form.fmt.pix.width = w;
1444 capture->form.fmt.pix.height = h;
1445 capture->form.fmt.win.chromakey = 0;
1446 capture->form.fmt.win.field = V4L2_FIELD_ANY;
1447 capture->form.fmt.win.clips = 0;
1448 capture->form.fmt.win.clipcount = 0;
1449 capture->form.fmt.pix.field = V4L2_FIELD_ANY;
1451 /* ask the device to change the size
1452 * don't test if the set of the size is ok, because some device
1453 * don't allow changing the size, and we will get the real size
1455 xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form);
1457 /* try to set framerate to 30 fps */
1458 struct v4l2_streamparm setfps;
1459 memset (&setfps, 0, sizeof(struct v4l2_streamparm));
1460 setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1461 setfps.parm.capture.timeperframe.numerator = 1;
1462 setfps.parm.capture.timeperframe.denominator = 30;
1463 xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps);
1465 /* we need to re-initialize some things, like buffers, because the size has
1467 capture->FirstCapture = 1;
1469 /* Get window info again, to get the real value */
1470 if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form))
1472 fprintf(stderr, "HIGHGUI ERROR: V4L/V4L2: Could not obtain specifics of capture window.\n\n");
1474 icvCloseCAM_V4L(capture);
1484 if (capture==0) return 0;
1485 if (w>capture->capability.maxwidth) {
1486 w=capture->capability.maxwidth;
1488 if (h>capture->capability.maxheight) {
1489 h=capture->capability.maxheight;
1492 capture->captureWindow.width=w;
1493 capture->captureWindow.height=h;
1495 if (ioctl(capture->deviceHandle, VIDIOCSWIN, &capture->captureWindow) < 0) {
1496 icvCloseCAM_V4L(capture);
1500 if (ioctl(capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
1501 icvCloseCAM_V4L(capture);
1505 capture->FirstCapture = 1;
1513 static int icvSetControl (CvCaptureCAM_V4L* capture, int property_id, double value) {
1514 struct v4l2_control c;
1520 if (capture->v4l2_ctrl_ranges == NULL) {
1521 v4l2_scan_controls(capture);
1524 CLEAR (capture->control);
1525 CLEAR (capture->queryctrl);
1527 /* get current values */
1528 switch (property_id) {
1529 case CV_CAP_PROP_BRIGHTNESS:
1530 sprintf(name, "Brightness");
1531 capture->control.id = V4L2_CID_BRIGHTNESS;
1533 case CV_CAP_PROP_CONTRAST:
1534 sprintf(name, "Contrast");
1535 capture->control.id = V4L2_CID_CONTRAST;
1537 case CV_CAP_PROP_SATURATION:
1538 sprintf(name, "Saturation");
1539 capture->control.id = V4L2_CID_SATURATION;
1541 case CV_CAP_PROP_HUE:
1542 sprintf(name, "Hue");
1543 capture->control.id = V4L2_CID_HUE;
1545 case CV_CAP_PROP_GAIN:
1546 sprintf(name, "Gain");
1547 capture->control.id = V4L2_CID_GAIN;
1549 case CV_CAP_PROP_EXPOSURE:
1550 sprintf(name, "Exposure");
1551 capture->control.id = V4L2_CID_EXPOSURE;
1554 sprintf(name, "<unknown property string>");
1555 capture->control.id = property_id;
1558 v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
1559 v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);
1561 if ((v4l2_min == -1) && (v4l2_max == -1)) {
1562 fprintf(stderr, "HIGHGUI ERROR: V4L: Property %s(%u) not supported by device\n", name, property_id);
1566 if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &capture->control) == 0) {
1569 fprintf(stderr, "HIGHGUI ERROR: V4L2: Unable to get property %s(%u) - %s\n", name, capture->control.id, strerror(errno));
1572 if (v4l2_max != 0) {
1576 } else if (value > 1.0) {
1579 ctrl_value = val * (double)(v4l2_max - v4l2_min) + v4l2_min;
1581 ctrl_value = v4l2_get_ctrl_default(capture, capture->control.id) * (double)(v4l2_max - v4l2_min) + v4l2_min;
1584 /* try and set value as if it was a v4l2 device */
1585 c.id = capture->control.id;
1586 c.value = ctrl_value;
1587 if (v4l2_ioctl(capture->deviceHandle, VIDIOC_S_CTRL, &c) != 0) {
1588 /* The driver may clamp the value or return ERANGE, ignored here */
1589 if (errno != ERANGE) {
1590 fprintf(stderr, "HIGHGUI ERROR: V4L2: Failed to set control \"%d\": %s (value %d)\n", c.id, strerror(errno), c.value);
1599 if (is_v4l2 == 0) { /* use v4l1_ioctl */
1600 fprintf(stderr, "HIGHGUI WARNING: Setting property %u through v4l2 failed. Trying with v4l1.\n", c.id);
1602 /* scale the value to the wanted integer one */
1603 v4l_value = (int)(0xFFFF * value);
1605 switch (property_id) {
1606 case CV_CAP_PROP_BRIGHTNESS:
1607 capture->imageProperties.brightness = v4l_value;
1609 case CV_CAP_PROP_CONTRAST:
1610 capture->imageProperties.contrast = v4l_value;
1612 case CV_CAP_PROP_SATURATION:
1613 capture->imageProperties.colour = v4l_value;
1615 case CV_CAP_PROP_HUE:
1616 capture->imageProperties.hue = v4l_value;
1618 case CV_CAP_PROP_GAIN:
1619 fprintf(stderr, "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
1621 case CV_CAP_PROP_EXPOSURE:
1622 fprintf(stderr, "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n");
1625 fprintf(stderr, "HIGHGUI ERROR: V4L: property #%d is not supported\n", property_id);
1629 if (v4l1_ioctl(capture->deviceHandle, VIDIOCSPICT, &capture->imageProperties) < 0){
1630 fprintf(stderr, "HIGHGUI ERROR: V4L: Unable to set video informations\n");
1631 icvCloseCAM_V4L(capture);
1640 static int icvSetPropertyCAM_V4L(CvCaptureCAM_V4L* capture, int property_id, double value){
1641 static int width = 0, height = 0;
1644 /* initialization */
1647 /* two subsequent calls setting WIDTH and HEIGHT will change
1649 /* the first one will return an error, though. */
1651 switch (property_id) {
1652 case CV_CAP_PROP_FRAME_WIDTH:
1653 width = cvRound(value);
1654 capture->width = width;
1655 if(width !=0 && height != 0) {
1656 retval = icvSetVideoSize( capture, width, height);
1660 case CV_CAP_PROP_FRAME_HEIGHT:
1661 height = cvRound(value);
1662 capture->height = height;
1663 if(width !=0 && height != 0) {
1664 retval = icvSetVideoSize( capture, width, height);
1668 case CV_CAP_PROP_FPS:
1669 struct v4l2_streamparm setfps;
1670 memset (&setfps, 0, sizeof(struct v4l2_streamparm));
1671 setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1672 setfps.parm.capture.timeperframe.numerator = 1;
1673 setfps.parm.capture.timeperframe.denominator = value;
1674 if (xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps) < 0){
1675 fprintf(stderr, "HIGHGUI ERROR: V4L: Unable to set camera FPS\n");
1680 retval = icvSetControl(capture, property_id, value);
1683 /* return the the status */
1687 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ){
1688 /* Deallocate space - Hopefully, no leaks */
1690 v4l2_free_ranges(capture);
1691 if (capture->is_v4l2_device == 0) {
1692 if (capture->mmaps) {
1693 free(capture->mmaps);
1695 if (capture->memoryMap) {
1696 v4l1_munmap(capture->memoryMap, capture->memoryBuffer.size);
1698 if (capture->deviceHandle != -1) {
1699 v4l1_close(capture->deviceHandle);
1702 capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1703 if (xioctl(capture->deviceHandle, VIDIOC_STREAMOFF, &capture->type) < 0) {
1704 perror ("Unable to stop the stream.");
1706 for (unsigned int n_buffers2 = 0; n_buffers2 < capture->req.count; ++n_buffers2) {
1707 if (-1 == v4l2_munmap (capture->buffers[n_buffers2].start, capture->buffers[n_buffers2].length)) {
1712 if (capture->deviceHandle != -1) {
1713 v4l2_close(capture->deviceHandle);
1717 if (capture->frame.imageData)
1718 cvFree(&capture->frame.imageData);
1720 #ifdef USE_TEMP_BUFFER
1721 if (capture->buffers[MAX_V4L_BUFFERS].start) {
1722 free(capture->buffers[MAX_V4L_BUFFERS].start);
1723 capture->buffers[MAX_V4L_BUFFERS].start = NULL;
1727 free(capture->deviceName);
1728 capture->deviceName = NULL;
1729 //v4l2_free_ranges(capture);
1730 //cvFree((void **)capture);
1735 class CvCaptureCAM_V4L_CPP : CvCapture
1738 CvCaptureCAM_V4L_CPP() { captureV4L = 0; }
1739 virtual ~CvCaptureCAM_V4L_CPP() { close(); }
1741 virtual bool open( int index );
1742 virtual void close();
1744 virtual double getProperty(int);
1745 virtual bool setProperty(int, double);
1746 virtual bool grabFrame();
1747 virtual IplImage* retrieveFrame(int);
1750 CvCaptureCAM_V4L* captureV4L;
1753 bool CvCaptureCAM_V4L_CPP::open( int index )
1756 captureV4L = icvCaptureFromCAM_V4L(index);
1757 return captureV4L != 0;
1760 void CvCaptureCAM_V4L_CPP::close()
1764 icvCloseCAM_V4L( captureV4L );
1765 cvFree( &captureV4L );
1769 bool CvCaptureCAM_V4L_CPP::grabFrame()
1771 return captureV4L ? icvGrabFrameCAM_V4L( captureV4L ) != 0 : false;
1774 IplImage* CvCaptureCAM_V4L_CPP::retrieveFrame(int)
1776 return captureV4L ? icvRetrieveFrameCAM_V4L( captureV4L, 0 ) : 0;
1779 double CvCaptureCAM_V4L_CPP::getProperty( int propId )
1781 return captureV4L ? icvGetPropertyCAM_V4L( captureV4L, propId ) : 0.0;
1784 bool CvCaptureCAM_V4L_CPP::setProperty( int propId, double value )
1786 return captureV4L ? icvSetPropertyCAM_V4L( captureV4L, propId, value ) != 0 : false;
1789 CvCapture* cvCreateCameraCapture_V4L( int index )
1791 CvCaptureCAM_V4L_CPP* capture = new CvCaptureCAM_V4L_CPP;
1793 if( capture->open( index ))
1794 return (CvCapture*)capture;