source: eviacam/trunk/fuentes/creavision/libwebcam/libwebcam.c @ 567

Last change on this file since 567 was 567, checked in by mabarracus, 4 years ago

updated sources to version 2.0.3

File size: 87.5 KB
Line 
1/**
2 * \file
3 * Webcam library implementation.
4 *
5 * \ingroup libwebcam
6 */
7
8/*
9 * Copyright (c) 2006-2010 Logitech.
10 *
11 * This file is part of libwebcam.
12 *
13 * libwebcam is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as published
15 * by the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * libwebcam is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 * GNU Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with libwebcam.  If not, see <http://www.gnu.org/licenses/>.
25 */
26
27#ifndef _GNU_SOURCE
28        #define _GNU_SOURCE
29#endif
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <sys/types.h>
34#include <limits.h>
35#include <dirent.h>
36#include <pthread.h>
37#include <fcntl.h>
38#include <unistd.h>
39#include <stdarg.h>
40#include <sys/ioctl.h>
41#include <errno.h>
42
43#include "webcam.h"
44#include "libwebcam.h"
45
46#include "compat.h"
47
48#ifdef USE_LOGITECH_DYNCTRL
49#include <dynctrl-logitech.h>
50#endif
51
52
53/// A flag indicating whether the library was initialized.
54int initialized = 0;
55/// A list of webcam devices found in the system.
56static DeviceList device_list;
57/// The fixed size list of file handles.
58HandleList handle_list;
59
60
61/*
62 * Forward declarations
63 */
64
65void print_libwebcam_error (char *format, ...);
66static void print_libwebcam_c_error (CResult error, char *format, ...);
67
68static unsigned int get_control_dynamics_length(Device *device, unsigned int *names_length, unsigned int *choices_length);
69static Control *find_control_by_id (Device *dev, CControlId id);
70
71static CResult refresh_device_list (void);
72static Device *find_device_by_name (const char *name);
73static int get_device_dynamics_length (CDevice *device);
74static int get_devices_dynamics_length (void);
75
76int open_v4l2_device(char *device_name);
77static CResult read_v4l2_control(Device *device, Control *control, CControlValue *value, CHandle hDevice);
78static CResult write_v4l2_control(Device *device, Control *control, const CControlValue *value, CHandle hDevice);
79static CControlId get_control_id_from_v4l2 (int v4l2_id, Device *dev);
80
81static CResult get_device_usb_info (Device *device, CUSBInfo *usbinfo);
82static CResult get_mimetype_from_fourcc(char **mimetype, unsigned int fourcc);
83
84static CHandle create_handle(Device *device);
85static void close_handle(CHandle handle);
86static void set_last_error(CHandle hDevice, int error);
87
88
89/*
90 * Devices
91 */
92
93/**
94 * Opens a camera device.
95 *
96 * The function returns a handle that can be used for all functions that require
97 * a device handle.
98 *
99 * @param device_name   Name of the device to open.
100 *                                              Two different naming schemes are accepted: Full device names
101 *                                              (e.g. '/dev/video0') and short names (e.g. 'video0') as
102 *                                              returned by c_enum_devices().
103 * @return
104 *              - a device handle greater than zero on success
105 *              - 0 if an error has occurred
106 */
107CHandle c_open_device (const char *device_name)
108{
109        CHandle handle;
110        const char *v4l2_name;
111
112        if(device_name == NULL || !initialized) {
113                print_libwebcam_error("Unable to open device. No name given or library not initialized.");
114                return 0;
115        }
116
117        // Try to find the device with the given name.
118        // Note: If the given name is a device path (e.g. /dev/video0), the V4L2 name
119        // is simply generated by cutting off the '/dev/' part. If the given name
120        // starts with 'video', it is taken as is.
121        if(strstr(device_name, "/dev/video") == device_name)
122                v4l2_name = &device_name[5];
123        else if(strstr(device_name, "video") == device_name)
124                v4l2_name = device_name;
125        else if(strstr(device_name, "subdev") == device_name)
126                v4l2_name = device_name;
127        else {
128                print_libwebcam_error("Unable to open device '%s'. Unrecognized device name.", device_name);
129                return 0;
130        }
131        Device *device = find_device_by_name(v4l2_name);
132        if(device == NULL) {
133                print_libwebcam_error("Unable to open device '%s'. Device not found.", device_name);
134                return 0;
135        }
136
137        // Open device when needed
138        if (device->fd== 0) {
139                device->fd= open_v4l2_device(device->v4l2_name);
140                if (device->fd<= 0) {
141                        print_libwebcam_error("open sys call failed for %s'.", device_name);
142                        // Open error
143                        device->fd= 0;
144                        return 0;
145                }
146        }
147
148        // Create a handle for the given device
149        // TODO Race condition if delete_device is called here (via c_cleanup)
150        handle = create_handle(device);
151        if (handle== 0) {
152                close(device->fd);
153                device->fd= 0;
154        }
155        return handle;
156}
157
158
159/**
160 * Closes a device handle.
161 *
162 * @param       hDevice         a handle obtained from c_open_device()
163 */
164void c_close_device (CHandle hDevice)
165{
166        if(!initialized)
167                return;
168        close_handle(hDevice);
169}
170
171/**
172 * Given a handle returns the corresponding file descriptor.
173 *
174 * The function returns a file descriptor that can be used for low level operations outside
175 * this library.
176 *
177 * @param       hDevice         a handle obtained from c_open_device()
178 *
179 * @return
180 *              - a file descriptor greater than zero on success
181 *              - 0 if an error has occurred
182 */
183int c_get_file_descriptor (CHandle hDevice)
184{
185        // Check the given handle and arguments
186        if(!initialized)
187                return 0;
188        if(!HANDLE_OPEN(hDevice))
189                return 0;
190        if(!HANDLE_VALID(hDevice))
191                return 0;
192        Device *device = GET_HANDLE(hDevice).device;
193        if (!device) return 0;
194
195        return device->fd;
196}
197
198/**
199 * Enumerates all devices available in the system.
200 *
201 * Users must call c_init() prior to using this function.
202 *
203 * If the buffer is not large enough, #C_BUFFER_TOO_SMALL is returned and
204 * the \a size parameter is modified to contain the required buffer size.
205 *
206 * @param       devices         a pointer to a buffer that retrieves the list of devices
207 * @param       size            a pointer to an integer that contains or receives the size
208 *                                              of the @a devices buffer
209 * @param       count           a pointer to an integer that receives the number of devices
210 *                                              available. Can be NULL. If this argument is not NULL, the
211 *                                              device count is returned independent of whether or not the
212 *                                              buffer is large enough.
213 * @return
214 *              - #C_SUCCESS on success
215 *              - #C_INIT_ERROR if the library has not been initialized
216 *              - #C_SYNC_ERROR if the synchronization structures could not be initialized
217 *              - #C_INVALID_ARG if no size pointer was given or if a size pointer was given
218 *                but no @a devices buffer was given
219 *              - #C_BUFFER_TOO_SMALL if the supplied buffer is not large enough
220 */
221CResult c_enum_devices (CDevice *devices, unsigned int *size, unsigned int *count)
222{
223        CResult ret = C_SUCCESS;
224
225        if(!initialized)
226                return C_INIT_ERROR;
227        if(size == NULL)
228                return C_INVALID_ARG;
229
230        // Refresh the internal device list
231        ret = refresh_device_list();
232        if(ret) return ret;
233
234        if(lock_mutex(&device_list.mutex))
235                return C_SYNC_ERROR;
236
237        // Return the required size if the given size is not large enough
238        if(count)
239                *count = device_list.count;
240        int dynamics_length = get_devices_dynamics_length();
241        int req_size = device_list.count * sizeof(CDevice) + dynamics_length;
242        if(req_size > *size) {
243                *size = req_size;
244                ret = C_BUFFER_TOO_SMALL;
245                goto done;
246        }
247        if(device_list.count == 0)
248                goto done;
249        if(devices == NULL) {
250                ret = C_INVALID_ARG;
251                goto done;
252        }
253
254        // Loop through all devices and return a list of CDevice structs
255        CDevice *current = devices;
256        Device *elem = device_list.first;
257        unsigned int dynamics_offset = device_list.count * sizeof(CDevice);
258        while(elem) {
259                // Copy the simple attributes
260                memcpy(current, &elem->device, sizeof(elem->device));
261
262                // Copy the strings
263                copy_string_to_buffer(&current->shortName,      elem->device.shortName, devices, &dynamics_offset);
264                copy_string_to_buffer(&current->name,           elem->device.name,              devices, &dynamics_offset);
265                copy_string_to_buffer(&current->driver,         elem->device.driver,    devices, &dynamics_offset);
266                copy_string_to_buffer(&current->location,       elem->device.location,  devices, &dynamics_offset);
267
268                current++;
269                elem = elem->next;
270        }
271        assert(dynamics_offset == req_size);
272
273done:
274        unlock_mutex(&device_list.mutex);
275        return ret;
276}
277
278
279/**
280 * Returns information about a given camera device.
281 *
282 * The function returns information about a device specified using a device handle
283 * obtained from c_open_device() or a string that would be recognized by the same
284 * function. The @a hDevice and @a device_name arguments are mutually exclusive.
285 * If both are specified, the handle is used. If the device name should be used,
286 * @a hDevice should be set to zero.
287 *
288 * If the buffer is not large enough, #C_BUFFER_TOO_SMALL is returned and
289 * the \a size parameter is modified to contain the required buffer size.
290 *
291 * Specifying a size of sizeof(CDevice) + strlen(device_name) + 84 will usually
292 * be enough. This information can be used to try receiving device information in
293 * a statically allocated buffer first. The number comes from the field lengths
294 * that V4L2 uses internally. There is no guarantee, however, that this does not
295 * change in the future, so applications must be prepared to allocate more memory
296 * if indicated by a return value of #C_BUFFER_TOO_SMALL.
297 *
298 * @param hDevice               a handle obtained from c_open_device()
299 * @param device_name   a device name as accepted by c_open_device()
300 * @param info                  a pointer to a buffer to receive the device information
301 * @param size                  a pointer to an integer that contains or receives the size
302 *                                              of the @a info buffer
303 * @return
304 *              - #C_SUCCESS on success
305 *              - #C_INIT_ERROR if the library has not been initialized
306 *              - #C_SYNC_ERROR if the synchronization structures could not be initialized
307 *              - #C_INVALID_ARG if no size pointer was given or if a size pointer was given
308 *                but no @a info buffer was given
309 *              - #C_INVALID_HANDLE if a non-zero invalid handle was specified
310 *              - #C_BUFFER_TOO_SMALL if the supplied buffer is not large enough
311 */
312CResult c_get_device_info (CHandle hDevice, const char *device_name, CDevice *info, unsigned int *size)
313{
314        CDevice *info_src;
315
316        if(!initialized)
317                return C_INIT_ERROR;
318        if(size == NULL)
319                return C_INVALID_ARG;
320
321        // Look for the device
322        if(hDevice) {                           // By device handle
323                if(!HANDLE_OPEN(hDevice))
324                        return C_INVALID_HANDLE;
325                if(!HANDLE_VALID(hDevice))
326                        return C_NOT_EXIST;
327                info_src = &GET_HANDLE(hDevice).device->device;
328        }
329        else if(device_name) {          // By device name
330                Device *device = find_device_by_name(device_name);
331                if(device == NULL)
332                        return C_NOT_FOUND;
333                info_src = &device->device;
334        }
335        else {
336                return C_INVALID_ARG;
337        }
338
339        // Return the required size if the given size is not large enough
340        int dynamics_length = get_device_dynamics_length(info_src);
341        int req_size = sizeof(*info_src) + dynamics_length;
342        if(req_size > *size) {
343                *size = req_size;
344                return C_BUFFER_TOO_SMALL;
345        }
346        if(info == NULL)
347                return C_INVALID_ARG;
348
349        // Copy the simple values
350        memcpy(info, info_src, sizeof(*info_src));
351
352        // Copy the strings
353        unsigned int dynamics_offset = sizeof(*info_src);
354        copy_string_to_buffer(&info->shortName, info_src->shortName, info, &dynamics_offset);
355        copy_string_to_buffer(&info->name,              info_src->name,          info, &dynamics_offset);
356        copy_string_to_buffer(&info->driver,    info_src->driver,        info, &dynamics_offset);
357        copy_string_to_buffer(&info->location,  info_src->location,      info, &dynamics_offset);
358        assert(dynamics_offset == req_size);
359
360        return C_SUCCESS;
361}
362
363
364
365/*
366 * Frame format enumeration
367 */
368
369/**
370 * Enumerates all pixel formats supported by the given camera.
371 *
372 * If the buffer is not large enough, #C_BUFFER_TOO_SMALL is returned and
373 * the \a size parameter is modified to contain the required buffer size.
374 *
375 * @param       hDevice         a handle obtained from c_open_device()
376 * @param       formats         a pointer to a buffer that retrieves the list of pixel formats
377 * @param       size            a pointer to an integer that contains or receives the size
378 *                                              of the @a formats buffer
379 * @param       count           a pointer to an integer that receives the number of pixel
380 *                                              formats supported. Can be NULL. If this argument is not NULL,
381 *                                              the device count is returned independent of whether or not
382 *                                              the buffer is large enough.
383 * @return
384 *              - #C_SUCCESS on success
385 *              - #C_INIT_ERROR if the library has not been initialized
386 *              - #C_INVALID_HANDLE if the given device handle is invalid
387 *              - #C_INVALID_ARG if no size pointer was given or if a size pointer was given
388 *                but no @a formats buffer was given
389 *              - #C_INVALID_DEVICE if the device could not be opened
390 *              - #C_BUFFER_TOO_SMALL if the supplied buffer is not large enough
391 *              - #C_NO_MEMORY if no temporary memory could be allocated
392 *              - #C_V4L2_ERROR if a V4L2 error occurred during pixel format enumeration
393 */
394CResult c_enum_pixel_formats (CHandle hDevice, CPixelFormat *formats, unsigned int *size, unsigned int *count)
395{
396        CResult ret = C_SUCCESS;
397        int v4l2_dev;
398
399        // Check the given handle and arguments
400        if(!initialized)
401                return C_INIT_ERROR;
402        if(!HANDLE_OPEN(hDevice))
403                return C_INVALID_HANDLE;
404        if(!HANDLE_VALID(hDevice))
405                return C_NOT_EXIST;
406        Device *device = GET_HANDLE(hDevice).device;
407        if(size == NULL)
408                return C_INVALID_ARG;
409
410        // Open the corresponding V4L2 device
411        v4l2_dev = device->fd; //open_v4l2_device(device->v4l2_name);
412        if(!v4l2_dev)
413                return C_INVALID_DEVICE;
414
415        // Run V4L2 pixel format enumeration
416        typedef struct _PixelFormat {
417                CPixelFormat            format;
418                struct _PixelFormat     * next;
419        } PixelFormat;
420        PixelFormat *head = NULL, *tail = NULL;
421        unsigned int req_size = 0, format_count = 0;
422        struct v4l2_fmtdesc fmt;
423        memset(&fmt, 0, sizeof(fmt));
424        fmt.index = 0;
425        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
426        while(ioctl(v4l2_dev, VIDIOC_ENUM_FMT, &fmt) == 0) {
427                PixelFormat *format = (PixelFormat *)malloc(sizeof(PixelFormat));
428                if(!format) {
429                        ret = C_NO_MEMORY;
430                        goto done;
431                }
432                memset(format, 0, sizeof(PixelFormat));
433                fmt.index++;
434
435                // Copy the pixel format attributes
436                sprintf(format->format.fourcc, "%c%c%c%c",
437                                fmt.pixelformat & 0xFF, (fmt.pixelformat >> 8) & 0xFF,
438                                (fmt.pixelformat >> 16) & 0xFF, (fmt.pixelformat >> 24) & 0xFF);
439                format->format.name = strdup((char *)fmt.description);
440                req_size += sizeof(CPixelFormat) + strlen(format->format.name) + 1;
441                if(!get_mimetype_from_fourcc(&format->format.mimeType, fmt.pixelformat))
442                        req_size += strlen(format->format.mimeType) + 1;
443                else
444                        format->format.mimeType = NULL;
445                format_count++;
446
447                // Append the format to the list
448                if(head == NULL)
449                        head = tail = format;
450                else
451                        tail->next = format;
452                tail = format;
453        }
454        if(errno != EINVAL) {
455                ret = C_V4L2_ERROR;
456                set_last_error(hDevice, errno);
457                goto done;
458        }
459
460        // Return the required size if the given size is not large enough
461        if(count)
462                *count = format_count;
463        if(req_size > *size) {
464                *size = req_size;
465                ret = C_BUFFER_TOO_SMALL;
466                goto done;
467        }
468        if(format_count == 0)
469                goto done;
470        if(formats == NULL) {
471                ret = C_INVALID_ARG;
472                goto done;
473        }
474
475        // Loop through the formats and return a list of CPixelFormat structs
476        CPixelFormat *current = formats;
477        PixelFormat *elem = head;
478        unsigned int dynamics_offset = format_count * sizeof(CPixelFormat);
479        while(elem) {
480                // Copy the simple attributes
481                memcpy(current, &elem->format, sizeof(elem->format));
482
483                // Copy the strings
484                copy_string_to_buffer(&current->name, elem->format.name, formats, &dynamics_offset);
485                if(elem->format.mimeType)
486                        copy_string_to_buffer(&current->mimeType, elem->format.mimeType, formats, &dynamics_offset);
487
488                current++;
489                elem = elem->next;
490        }
491        assert(dynamics_offset == req_size);
492
493done:
494        // Free the list of pixel formats and close the V4L2 device
495        //close(v4l2_dev);
496        elem = head;
497        while(elem) {
498                PixelFormat *next = elem->next;
499                if(elem->format.mimeType) free(elem->format.mimeType);
500                if(elem->format.name) free(elem->format.name);
501                free(elem);
502                elem = next;
503        }
504        return ret;
505}
506
507
508/**
509 * Enumerates all frame sizes supported for the given pixel format.
510 *
511 * If the buffer is not large enough, #C_BUFFER_TOO_SMALL is returned and
512 * the \a size parameter is modified to contain the required buffer size.
513 *
514 * A list of pixel formats can be obtained from c_enum_pixel_formats().
515 *
516 * @param       hDevice         a handle obtained from c_open_device()
517 * @param       pixelformat     the pixel format for which the frame sizes should be
518 *                                              enumerated
519 * @param       sizes           a pointer to a buffer that retrieves the list of frame sizes
520 * @param       size            a pointer to an integer that contains or receives the size
521 *                                              of the @a sizes buffer
522 * @param       count           a pointer to an integer that receives the number of frame
523 *                                              sizes supported for the given pixel format. Can be NULL.
524 *                                              If this argument is not NULL, the frame size count is
525 *                                              returned independent of whether or not the buffer is large
526 *                                              enough.
527 * @return
528 *              - #C_SUCCESS on success
529 *              - #C_INIT_ERROR if the library has not been initialized
530 *              - #C_INVALID_HANDLE if the given device handle is invalid
531 *              - #C_INVALID_ARG if no size pointer was given; if a size pointer was given
532 *                but no @a sizes buffer was given; if no @a pixelformat was given
533 *              - #C_INVALID_DEVICE if the device could not be opened
534 *              - #C_BUFFER_TOO_SMALL if the supplied buffer is not large enough
535 *              - #C_NO_MEMORY if no temporary memory could be allocated
536 *              - #C_V4L2_ERROR if a V4L2 error occurred during frame size enumeration
537 */
538CResult c_enum_frame_sizes (CHandle hDevice, const CPixelFormat *pixelformat, CFrameSize *sizes, unsigned int *size, unsigned int *count)
539{
540        CResult ret = C_SUCCESS;
541        int v4l2_dev;
542
543        // Check the given handle and arguments
544        if(!initialized)
545                return C_INIT_ERROR;
546        if(!HANDLE_OPEN(hDevice))
547                return C_INVALID_HANDLE;
548        if(!HANDLE_VALID(hDevice))
549                return C_NOT_EXIST;
550        Device *device = GET_HANDLE(hDevice).device;
551        if(size == NULL || pixelformat == NULL)
552                return C_INVALID_ARG;
553
554        // Open the corresponding V4L2 device
555        v4l2_dev =  device->fd; //open_v4l2_device(device->v4l2_name);
556        if(!v4l2_dev)
557                return C_INVALID_DEVICE;
558
559        // Run V4L2 frame size enumeration
560        typedef struct _FrameSize {
561                CFrameSize                      size;
562                struct _FrameSize       * next;
563        } FrameSize;
564        FrameSize *head = NULL, *tail = NULL;
565        unsigned int req_size = 0, size_count = 0;
566        struct v4l2_frmsizeenum fsize;
567        memset(&fsize, 0, sizeof(fsize));
568        fsize.index = 0;
569        fsize.pixel_format = pixelformat->fourcc[0] |
570                        (unsigned long)pixelformat->fourcc[1] << 8 |
571                        (unsigned long)pixelformat->fourcc[2] << 16 |
572                        (unsigned long)pixelformat->fourcc[3] << 24;
573        fsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
574        while(ioctl(v4l2_dev, VIDIOC_ENUM_FRAMESIZES, &fsize) == 0) {
575                FrameSize *framesize = (FrameSize *)malloc(sizeof(FrameSize));
576                if(!framesize) {
577                        ret = C_NO_MEMORY;
578                        goto done;
579                }
580                memset(framesize, 0, sizeof(FrameSize));
581                fsize.index++;
582
583                // Copy the frame size attributes
584                if(fsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
585                        framesize->size.type = CF_SIZE_DISCRETE;
586                        framesize->size.width = fsize.discrete.width;
587                        framesize->size.height = fsize.discrete.height;
588                }
589                else if(fsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
590                        framesize->size.type = CF_SIZE_CONTINUOUS;
591                        framesize->size.min_width = fsize.stepwise.min_width;
592                        framesize->size.max_width = fsize.stepwise.max_width;
593                        framesize->size.step_width = 1;
594                        framesize->size.min_height = fsize.stepwise.min_height;
595                        framesize->size.max_height = fsize.stepwise.max_height;
596                        framesize->size.step_height = 1;
597                }
598                else if(fsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
599                        framesize->size.type = CF_SIZE_STEPWISE;
600                        framesize->size.min_width = fsize.stepwise.min_width;
601                        framesize->size.max_width = fsize.stepwise.max_width;
602                        framesize->size.step_width = fsize.stepwise.step_width;
603                        framesize->size.min_height = fsize.stepwise.min_height;
604                        framesize->size.max_height = fsize.stepwise.max_height;
605                        framesize->size.step_height = fsize.stepwise.step_height;
606                }
607                req_size += sizeof(CFrameSize);
608                size_count++;
609
610                // Append the frame size to the list
611                if(head == NULL)
612                        head = tail = framesize;
613                else
614                        tail->next = framesize;
615                tail = framesize;
616        }
617        if(errno != EINVAL) {
618                ret = C_V4L2_ERROR;
619                set_last_error(hDevice, errno);
620                goto done;
621        }
622
623        // Return the required size if the given size is not large enough
624        if(count)
625                *count = size_count;
626        if(req_size > *size) {
627                *size = req_size;
628                ret = C_BUFFER_TOO_SMALL;
629                goto done;
630        }
631        if(size_count == 0)
632                goto done;
633        if(sizes == NULL)
634                return C_INVALID_ARG;
635
636        // Loop through the formats and return a list of CFrameSize structs
637        CFrameSize *current = sizes;
638        FrameSize *elem = head;
639        while(elem) {
640                memcpy(current, &elem->size, sizeof(elem->size));
641                current++;
642                elem = elem->next;
643        }
644
645done:
646        // Free the list of frame sizes and close the V4L2 device
647        //close(v4l2_dev);
648        elem = head;
649        while(elem) {
650                FrameSize *next = elem->next;
651                free(elem);
652                elem = next;
653        }
654        return ret;
655}
656
657
658/**
659 * Enumerates all frame intervals supported for the given pixel format and frame size.
660 *
661 * If the buffer is not large enough, #C_BUFFER_TOO_SMALL is returned and
662 * the \a size parameter is modified to contain the required buffer size.
663 *
664 * A list of pixel formats can be obtained from c_enum_pixel_formats(). In a
665 * similar manner the list of supported frame sizes for each pixel format can be
666 * obtained from c_enum_frame_sizes().
667 *
668 * @param       hDevice         a handle obtained from c_open_device()
669 * @param       pixelformat     the pixel format for which the frame intervals should be
670 *                                              enumerated
671 * @param       framesize       the frame size for which the frame intervals should be
672 *                                              enumerated. Note that this frame size's type must be discrete.
673 * @param       intervals       a pointer to a buffer that retrieves the list of frame
674 *                                              intervals
675 * @param       size            a pointer to an integer that contains or receives the size
676 *                                              of the @a intervals buffer
677 * @param       count           a pointer to an integer that receives the number of frame
678 *                                              intervals supported for the given pixel format and frame
679 *                                              size. Can be NULL. If this argument is not NULL, the frame
680 *                                              size count is returned independent of whether or not the
681 *                                              buffer is large enough.
682 * @return
683 *              - #C_SUCCESS on success
684 *              - #C_INIT_ERROR if the library has not been initialized
685 *              - #C_INVALID_HANDLE if the given device handle is invalid
686 *              - #C_INVALID_ARG if no size pointer was given; if a size pointer was given
687 *                but no @a sizes buffer was given; if @a pixelformat or @a framesize were
688 *                not given; if a non-descrete frame size was given
689 *              - #C_INVALID_DEVICE if the device could not be opened
690 *              - #C_BUFFER_TOO_SMALL if the supplied buffer is not large enough
691 *              - #C_NO_MEMORY if no temporary memory could be allocated
692 *              - #C_V4L2_ERROR if a V4L2 error occurred during frame interval enumeration
693 */
694CResult c_enum_frame_intervals (CHandle hDevice, const CPixelFormat *pixelformat, const CFrameSize *framesize, CFrameInterval *intervals, unsigned int *size, unsigned int *count)
695{
696        CResult ret = C_SUCCESS;
697        int v4l2_dev;
698
699        // Check the given handle and arguments
700        if(!initialized)
701                return C_INIT_ERROR;
702        if(!HANDLE_OPEN(hDevice))
703                return C_INVALID_HANDLE;
704        if(!HANDLE_VALID(hDevice))
705                return C_NOT_EXIST;
706        Device *device = GET_HANDLE(hDevice).device;
707        if(size == NULL || pixelformat == NULL || framesize == NULL)
708                return C_INVALID_ARG;
709
710        // The frame size must be discrete because V4L2's VIDIOC_ENUM_FRAMEINTERVALS function
711        // only accepts a single width and height.
712        if(framesize->type != CF_SIZE_DISCRETE)
713                return C_INVALID_ARG;
714
715        // Open the corresponding V4L2 device
716        v4l2_dev = device->fd; //open_v4l2_device(device->v4l2_name);
717        if(!v4l2_dev)
718                return C_INVALID_DEVICE;
719
720        // Run V4L2 frame interval enumeration
721        typedef struct _FrameInterval {
722                CFrameInterval                  interval;
723                struct _FrameInterval   * next;
724        } FrameInterval;
725        FrameInterval *head = NULL, *tail = NULL;
726        unsigned int req_size = 0, interval_count = 0;
727        struct v4l2_frmivalenum fival;
728        memset(&fival, 0, sizeof(fival));
729        fival.index = 0;
730        fival.pixel_format = pixelformat->fourcc[0] |
731                        (unsigned long)pixelformat->fourcc[1] << 8 |
732                        (unsigned long)pixelformat->fourcc[2] << 16 |
733                        (unsigned long)pixelformat->fourcc[3] << 24;
734        fival.width = framesize->width;
735        fival.height = framesize->height;
736        fival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
737        while(ioctl(v4l2_dev, VIDIOC_ENUM_FRAMEINTERVALS, &fival) == 0) {
738                FrameInterval *frameinterval = (FrameInterval *)malloc(sizeof(FrameInterval));
739                if(!frameinterval) {
740                        ret = C_NO_MEMORY;
741                        goto done;
742                }
743                memset(frameinterval, 0, sizeof(FrameInterval));
744                fival.index++;
745
746                // Copy the frame interval attributes
747                if(fival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
748                        frameinterval->interval.type = CF_INTERVAL_DISCRETE;
749                        frameinterval->interval.n = fival.discrete.numerator;
750                        frameinterval->interval.d = fival.discrete.denominator;
751                }
752                else if(fival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) {
753                        frameinterval->interval.type = CF_INTERVAL_CONTINUOUS;
754                        frameinterval->interval.min_n = fival.stepwise.min.numerator;
755                        frameinterval->interval.min_d = fival.stepwise.min.denominator;
756                        frameinterval->interval.max_n = fival.stepwise.max.numerator;
757                        frameinterval->interval.max_d = fival.stepwise.max.denominator;
758                        frameinterval->interval.step_n = 1;
759                        frameinterval->interval.step_d = 1;
760                }
761                else if(fival.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
762                        frameinterval->interval.type = CF_INTERVAL_STEPWISE;
763                        frameinterval->interval.min_n = fival.stepwise.min.numerator;
764                        frameinterval->interval.min_d = fival.stepwise.min.denominator;
765                        frameinterval->interval.max_n = fival.stepwise.max.numerator;
766                        frameinterval->interval.max_d = fival.stepwise.max.denominator;
767                        frameinterval->interval.step_n = fival.stepwise.step.numerator;
768                        frameinterval->interval.step_d = fival.stepwise.step.denominator;
769                }
770                req_size += sizeof(CFrameInterval);
771                interval_count++;
772
773                // Append the frame interval to the list
774                if(head == NULL)
775                        head = tail = frameinterval;
776                else
777                        tail->next = frameinterval;
778                tail = frameinterval;
779        }
780        if(errno != EINVAL) {
781                ret = C_V4L2_ERROR;
782                set_last_error(hDevice, errno);
783                goto done;
784        }
785
786        // Return the required size if the given size is not large enough
787        if(count)
788                *count = interval_count;
789        if(req_size > *size) {
790                *size = req_size;
791                ret = C_BUFFER_TOO_SMALL;
792                goto done;
793        }
794        if(interval_count == 0)
795                goto done;
796        if(intervals == NULL)
797                return C_INVALID_ARG;
798
799        // Loop through the formats and return a list of CFrameInterval structs
800        CFrameInterval *current = intervals;
801        FrameInterval *elem = head;
802        while(elem) {
803                memcpy(current, &elem->interval, sizeof(elem->interval));
804                current++;
805                elem = elem->next;
806        }
807
808done:
809        // Free the list of frame sizes and close the V4L2 device
810        //close(v4l2_dev);
811        elem = head;
812        while(elem) {
813                FrameInterval *next = elem->next;
814                free(elem);
815                elem = next;
816        }
817        return ret;
818}
819
820
821
822/*
823 * Controls
824 */
825
826/**
827 * Enumerates all controls supported by the given device.
828 *
829 * If the buffer is not large enough, #C_BUFFER_TOO_SMALL is returned and
830 * the \a size parameter is modified to contain the required buffer size.
831 *
832 * @param hDevice       a device handle obtained from c_open_device()
833 * @param controls      a pointer to a buffer that retrieves the list of supported
834 *                                      controls.
835 * @param size          a pointer to an integer that contains or receives the size of
836 *                                      the \a controls buffer.
837 * @param count         a pointer to an integer that receives the number of controls
838 *                                      supported. Can be NULL. If this argument is not NULL, the control
839 *                                      count is returned independent of whether or not the buffer is
840 *                                      large enough.
841 * @return
842 *              - #C_SUCCESS on success
843 *              - #C_INIT_ERROR if the library has not been initialized
844 *              - #C_INVALID_HANDLE if the given device handle is invalid
845 *              - #C_SYNC_ERROR if the synchronization structures could not be initialized
846 *              - #C_INVALID_ARG if no size pointer was given or if a size pointer was given
847 *                but no @a controls buffer was given
848 *              - #C_BUFFER_TOO_SMALL if the supplied buffer is not large enough
849 */
850CResult c_enum_controls (CHandle hDevice, CControl *controls, unsigned int *size, unsigned int *count)
851{
852        CResult ret = C_SUCCESS;
853        unsigned int names_length, choices_length;
854
855        // Check the given handle and arguments
856        if(!initialized)
857                return C_INIT_ERROR;
858        if(!HANDLE_OPEN(hDevice))
859                return C_INVALID_HANDLE;
860        if(!HANDLE_VALID(hDevice))
861                return C_NOT_EXIST;
862        Device *device = GET_HANDLE(hDevice).device;
863        if(size == NULL)
864                return C_INVALID_ARG;
865
866        if(lock_mutex(&device->controls.mutex))
867                return C_SYNC_ERROR;
868
869        // Determine the buffer size needed to describe all controls
870        if(count)
871                *count = device->controls.count;
872        get_control_dynamics_length(device, &names_length, &choices_length);
873        int req_size = device->controls.count * sizeof(CControl) + names_length + choices_length;
874        if(req_size > *size) {
875                *size = req_size;
876                ret = C_BUFFER_TOO_SMALL;
877                goto done;
878        }
879        if(device->controls.count == 0)
880                goto done;
881        if(controls == NULL)
882                return C_INVALID_ARG;
883
884        // Loop through all the device's controls and return a list of CControl structs
885        CControl *current = controls;
886        Control *elem = device->controls.first;
887        unsigned int names_offset = device->controls.count * sizeof(CControl);
888        unsigned int choices_offset = names_offset + names_length;
889        while(elem) {
890                // Copy the simple attributes
891                memcpy(current, &elem->control, sizeof(elem->control));
892
893                // Copy the name
894                unsigned int name_length = strlen(elem->control.name);
895                current->name = (char *)controls + names_offset;
896                memcpy(current->name, elem->control.name, name_length + 1);
897                assert(names_offset + name_length < req_size);
898                names_offset += name_length + 1;
899
900                // Copy the choices
901                if(elem->control.type == CC_TYPE_CHOICE) {
902                        current->choices.count = elem->control.choices.count;
903                        current->choices.list = (CControlChoice *)((char *)controls + choices_offset);
904                        choices_offset += elem->control.choices.count * sizeof(CControlChoice);
905                        //current->choices.names = (char *)controls + choices_offset;
906
907                        int index;
908                        for(index = 0; index < elem->control.choices.count; index++) {
909                                int name_length = strlen(elem->control.choices.list[index].name);
910                                current->choices.list[index].index = elem->control.choices.list[index].index;
911                                memcpy(current->choices.list[index].name, elem->control.choices.list[index].name, name_length + 1);
912                                assert(choices_offset + name_length < req_size);
913                                choices_offset += name_length + 1;
914                        }
915                }
916
917                current++;
918                elem = elem->next;
919        }
920        assert(choices_offset == req_size);
921
922done:
923        unlock_mutex(&device->controls.mutex);
924        return ret;
925}
926
927
928/**
929 * Sets the value of a device control.
930 *
931 * @param hDevice               a device handle obtained from c_open_device()
932 * @param control_id    the ID of the control whose value shall be set
933 * @param value                 the value to which the control shall be set
934 * @return
935 *              - #C_SUCCESS on success
936 *              - #C_INIT_ERROR if the library has not been initialized
937 *              - #C_INVALID_HANDLE if the given device handle is invalid
938 *              - #C_INVALID_ARG if no value is given
939 *              - #C_NOT_FOUND if the device does not support the given control
940 *              - #C_CANNOT_WRITE if the given control is not writable
941 *              - #C_INVALID_DEVICE if the device could not be opened
942 *              - #C_V4L2_ERROR if a V4L2 error occurred during control access
943 */
944CResult c_set_control (CHandle hDevice, CControlId control_id, const CControlValue *value)
945{
946        CResult ret = C_SUCCESS;
947
948        // Check the given handle and arguments
949        if(!initialized)
950                return C_INIT_ERROR;
951        if(!HANDLE_OPEN(hDevice))
952                return C_INVALID_HANDLE;
953        if(!HANDLE_VALID(hDevice))
954                return C_NOT_EXIST;
955        Device *device = GET_HANDLE(hDevice).device;
956        if(value == NULL)
957                return C_INVALID_ARG;
958
959        // Look for the requested control within the given device
960        Control *control = find_control_by_id(device, control_id);
961        if(!control)
962                return C_NOT_FOUND;
963
964        // Check if the control is writable
965        if(!(control->control.flags & CC_CAN_WRITE))
966                return C_CANNOT_WRITE;
967
968        // Write the control in a way that depends on its source
969        if(control->v4l2_control) {             // V4L2
970                ret = write_v4l2_control(device, control, value, hDevice);
971        }
972        else {
973                assert(0);
974                return C_INVALID_ARG;
975        }
976
977        return ret;
978}
979
980
981/**
982 * Returns the value of a device control.
983 *
984 * @param hDevice               a device handle obtained from c_open_device()
985 * @param control_id    the ID of the control whose value shall be read
986 * @param value                 a pointer to receive the value read
987 * @return
988 *              - #C_SUCCESS on success
989 *              - #C_INIT_ERROR if the library has not been initialized
990 *              - #C_INVALID_HANDLE if the given device handle is invalid
991 *              - #C_INVALID_ARG if no value is given
992 *              - #C_NOT_FOUND if the device does not support the given control
993 *              - #C_CANNOT_READ if the given control is not readable
994 *              - #C_INVALID_DEVICE if the device could not be opened
995 *              - #C_V4L2_ERROR if a V4L2 error occurred during control access
996 */
997CResult c_get_control (CHandle hDevice, CControlId control_id, CControlValue *value)
998{
999        CResult ret = C_SUCCESS;
1000
1001        // Check the given handle and arguments
1002        if(!initialized)
1003                return C_INIT_ERROR;
1004        if(!HANDLE_OPEN(hDevice))
1005                return C_INVALID_HANDLE;
1006        if(!HANDLE_VALID(hDevice))
1007                return C_NOT_EXIST;
1008        Device *device = GET_HANDLE(hDevice).device;
1009        if(value == NULL)
1010                return C_INVALID_ARG;
1011
1012        // Look for the requested control within the given device
1013        Control *control = find_control_by_id(device, control_id);
1014        if(!control)
1015                return C_NOT_FOUND;
1016
1017        // Check if the control is readable
1018        if(!(control->control.flags & CC_CAN_READ))
1019                return C_CANNOT_READ;
1020
1021        // Read the control in a way that depends on its source
1022        if(control->v4l2_control) {                     // V4L2
1023                ret = read_v4l2_control(device, control, value, hDevice);
1024        }
1025        else {
1026                assert(0);
1027                return C_INVALID_ARG;
1028        }
1029
1030        return ret;
1031}
1032
1033/**
1034 * refreshes the values of all device controls.
1035 *
1036 * @param hDevice               a device handle obtained from c_open_device()
1037 * @return
1038 *              - #C_SUCCESS on success
1039 *              - #C_INIT_ERROR if the library has not been initialized
1040 *              - #C_INVALID_HANDLE if the given device handle is invalid
1041 */
1042static CResult refresh_control_values(CHandle hDevice)
1043{
1044        // Check the given handle and arguments
1045        if(!initialized)
1046                return C_INIT_ERROR;
1047        if(!HANDLE_OPEN(hDevice))
1048                return C_INVALID_HANDLE;
1049        if(!HANDLE_VALID(hDevice))
1050                return C_NOT_EXIST;
1051        Device *device = GET_HANDLE(hDevice).device;
1052    int ret = C_SUCCESS;
1053    //update control values
1054    Control *current = device->controls.first;
1055   
1056    while(current) 
1057    {
1058        ret = read_v4l2_control(device, current, &current->control.value, hDevice);
1059        if(ret != C_SUCCESS)
1060            print_libwebcam_error("Could not read control: 0x%08x.\n", current->v4l2_control);
1061       
1062        current = current->next;
1063    }
1064 
1065    return C_SUCCESS;
1066}
1067
1068/**
1069 * set special auto controls (higher id) before setting manual counterparts.
1070 *
1071 * @param hDevice               a device handle obtained from c_open_device()
1072 * @return
1073 *              - #C_SUCCESS on success
1074 *              - #C_INIT_ERROR if the library has not been initialized
1075 *              - #C_INVALID_HANDLE if the given device handle is invalid
1076 */
1077static CResult set_special_auto_controls(CHandle hDevice)
1078{
1079    // Check the given handle and arguments
1080    if(!initialized)
1081        return C_INIT_ERROR;
1082    if(!HANDLE_OPEN(hDevice))
1083        return C_INVALID_HANDLE;
1084    if(!HANDLE_VALID(hDevice))
1085        return C_NOT_EXIST;
1086    Device *device = GET_HANDLE(hDevice).device;
1087    int ret = C_SUCCESS;
1088    //update control values
1089    Control *current = device->controls.first;
1090   
1091    while(current) 
1092    {
1093        if( (current->v4l2_control == V4L2_CID_FOCUS_AUTO) || 
1094            (current->v4l2_control == V4L2_CID_HUE_AUTO) )
1095        {
1096            if(current->control.flags & CC_NEED_SET)
1097            {
1098                ret = write_v4l2_control(device, current, &current->control.value, hDevice);
1099                if(ret != C_SUCCESS)
1100                {
1101                    print_libwebcam_error("Could not set control: 0x%08x.\n", current->v4l2_control);
1102                    // update with the real value
1103                    read_v4l2_control(device, current, &current->control.value, hDevice);
1104                }
1105                current->control.flags &= ~(CC_NEED_SET); //reset flag
1106            }
1107        }
1108        current = current->next;
1109    }
1110    return C_SUCCESS;
1111}
1112
1113/**
1114 * set the values of all device controls.
1115 *
1116 * @param hDevice               a device handle obtained from c_open_device()
1117 * @return
1118 *              - #C_SUCCESS on success
1119 *              - #C_INIT_ERROR if the library has not been initialized
1120 *              - #C_INVALID_HANDLE if the given device handle is invalid
1121 */
1122static CResult set_control_values(CHandle hDevice)
1123{
1124    // Check the given handle and arguments
1125    if(!initialized)
1126        return C_INIT_ERROR;
1127    if(!HANDLE_OPEN(hDevice))
1128        return C_INVALID_HANDLE;
1129    if(!HANDLE_VALID(hDevice))
1130        return C_NOT_EXIST;
1131    Device *device = GET_HANDLE(hDevice).device;
1132   
1133    //make sure special auto controls have already been set
1134    int ret = set_special_auto_controls(hDevice);
1135   
1136    //update all other control values
1137    Control *current = device->controls.first;
1138   
1139    while(current) 
1140    {
1141        if(current->control.flags & CC_NEED_SET)
1142        {
1143            ret = write_v4l2_control(device, current, &current->control.value, hDevice);
1144            if(ret != C_SUCCESS)
1145            {
1146                print_libwebcam_error("Could not set control: 0x%08x.\n", current->v4l2_control);
1147                // update with the real value
1148                read_v4l2_control(device, current, &current->control.value, hDevice);
1149            }
1150            current->control.flags &= ~(CC_NEED_SET); //reset flag
1151        }
1152        current = current->next;
1153    }
1154
1155    return C_SUCCESS;
1156}
1157
1158/**
1159 * Looks up the control with the given V4L2 ID for the given device.
1160 *
1161 * @return
1162 *              - NULL if no corresponding control was found for the given device.
1163 *              - Pointer to the control if it was found.
1164 */
1165static Control *find_control_by_v4l2_id (Device *dev, int id)
1166{
1167    Control *elem = dev->controls.first;
1168    while(elem) {
1169        if(elem->v4l2_control == id)
1170            break;
1171        elem = elem->next;
1172    }
1173    return elem;
1174}
1175
1176/**
1177 * Stores the values of all device controls into a file.
1178 *
1179 * @param hDevice               a device handle obtained from c_open_device()
1180 * @param filename          file name for storing the controls data
1181 * @return
1182 *              - #C_SUCCESS on success
1183 *              - #C_INIT_ERROR if the library has not been initialized
1184 *              - #C_INVALID_HANDLE if the given device handle is invalid
1185 */
1186CResult c_save_controls (CHandle hDevice, const char *filename)
1187{
1188    // Check the given handle and arguments
1189    if(!initialized)
1190        return C_INIT_ERROR;
1191    if(!HANDLE_OPEN(hDevice))
1192        return C_INVALID_HANDLE;
1193    if(!HANDLE_VALID(hDevice))
1194        return C_NOT_EXIST;
1195    Device *device = GET_HANDLE(hDevice).device;
1196
1197    if(lock_mutex(&device->controls.mutex))
1198        return C_SYNC_ERROR;
1199   
1200    //printf("%i device controls\n",device->controls.count);   
1201    FILE *fp = fopen(filename, "w");
1202   
1203    if( fp == NULL )
1204    {
1205        print_libwebcam_error("Could not open control data file for write: %s.\n", filename);
1206        return (-1);
1207    } 
1208    else 
1209    {
1210        refresh_control_values(hDevice);
1211       
1212        //write header
1213        fprintf(fp, "#V4L2/CTRL/0.0.2\n");
1214        fprintf(fp, "APP{\"libwebcam\"}\n");
1215        //write control data
1216        fprintf(fp, "# control data\n");
1217       
1218        Control *current = device->controls.first;
1219        while(current) 
1220        {
1221            //printf("printing control id: 0x%08x\n", current->v4l2_control);
1222            if(!(current->control.flags & (CC_CAN_READ | CC_CAN_WRITE)))
1223            {
1224                current = current->next;
1225                printf("jumping\n");
1226                continue;
1227            }
1228           
1229            fprintf(fp, "#%s\n", current->control.name);
1230            switch(current->control.type)
1231            {
1232#ifdef ENABLE_RAW_CONTROLS
1233                case CC_TYPE_RAW :
1234                    fprintf(fp, "ID{0x%08x};CHK{%i:%i:1:0}=STR{\"%s\"}\n",
1235                            current->v4l2_control, 
1236                            current->control.min.raw.size, 
1237                            current->control.min.raw.size,
1238                            (char *) current->control.value.raw.data);
1239                    break;
1240#endif
1241                case CC_TYPE_CHOICE : 
1242                    //since we don't have real v4l2 maximum, minimum, step
1243                    //use 1 for step, 0 for minimum and calculate maximum from choices.count
1244                    //NOTE: although this should be valid for most cases, it's not necessarly true. 
1245                    fprintf(fp, "ID{0x%08x};CHK{0:%i:1:%i}=VAL{%i}\n",
1246                            current->v4l2_control,
1247                            current->control.choices.count - 1,
1248                            current->control.def.value,
1249                            current->control.value.value);
1250                    break;
1251               
1252                default :
1253                    fprintf(fp, "ID{0x%08x};CHK{%i:%i:%i:%i}=VAL{%i}\n",
1254                            current->v4l2_control, 
1255                            current->control.min.value, 
1256                            current->control.max.value,
1257                            current->control.step.value,
1258                            current->control.def.value,
1259                            current->control.value.value);
1260                    break;
1261            }
1262            current = current->next;
1263        }
1264    }
1265   
1266    fclose(fp);
1267    unlock_mutex(&device->controls.mutex);
1268    return C_SUCCESS;
1269}
1270
1271 /**
1272 * Loads the values of all device controls from a file.
1273 *
1274 * @param hDevice               a device handle obtained from c_open_device()
1275 * @param filename          file name for reading the controls data
1276 * @return
1277 *              - #C_SUCCESS on success
1278 *              - #C_INIT_ERROR if the library has not been initialized
1279 *              - #C_INVALID_HANDLE if the given device handle is invalid
1280 *              - #C_INVALID_ARG if no value is given
1281 *              - #C_NOT_FOUND if the device does not support the given control
1282 *              - #C_CANNOT_READ if the given control is not readable
1283 *              - #C_INVALID_DEVICE if the device could not be opened
1284 *              - #C_V4L2_ERROR if a V4L2 error occurred during control access
1285 */
1286
1287CResult c_load_controls (CHandle hDevice, const char *filename)
1288{
1289    // Check the given handle and arguments
1290    if(!initialized)
1291        return C_INIT_ERROR;
1292    if(!HANDLE_OPEN(hDevice))
1293        return C_INVALID_HANDLE;
1294    if(!HANDLE_VALID(hDevice))
1295        return C_NOT_EXIST;
1296    Device *device = GET_HANDLE(hDevice).device;
1297
1298    if(lock_mutex(&device->controls.mutex))
1299        return C_SYNC_ERROR;
1300       
1301    FILE *fp = fopen(filename, "r");
1302    if( fp == NULL )
1303    {
1304        print_libwebcam_error("Could not open control data file for read: %s.\n", filename);
1305        return (-1);
1306    } 
1307    else 
1308    {
1309        char line[200];
1310        if(fgets(line, sizeof(line), fp) != NULL)
1311        {
1312                        int major,minor,rev;
1313
1314            if(sscanf(line,"#V4L2/CTRL/%i.%i.%i", &major, &minor, &rev) == 3) 
1315            {
1316                //check standard version if needed
1317            }
1318            else
1319            {
1320                print_libwebcam_error("no valid control file header found\n");
1321                goto finish;
1322            }
1323        }
1324        else
1325        {
1326            print_libwebcam_error("no valid control file header found\n");
1327            goto finish;
1328        }
1329           
1330        while (fgets(line, sizeof(line), fp) != NULL) 
1331        {
1332            int id = 0; 
1333            int min = 0, max = 0, step = 0, def = 0;
1334            int32_t val = 0;
1335            //int64_t val64 = 0;
1336           
1337            if ((line[0]!='#') && (line[0]!='\n')) 
1338            {
1339                if(sscanf(line,"ID{0x%08x};CHK{%i:%i:%i:%i}=VAL{%i}",
1340                    &id, &min, &max, &step, &def, &val) == 6)
1341                {
1342                   
1343                    Control *current = find_control_by_v4l2_id(device, id);
1344                    if(current)
1345                    {
1346                        //check values
1347                        if((current->control.type != CC_TYPE_CHOICE && 
1348                                                    (current->control.min.value == min && 
1349                                                         current->control.max.value == max &&
1350                             current->control.step.value == step &&
1351                                                         current->control.def.value == def)) ||
1352                                                   (current->control.type == CC_TYPE_CHOICE &&                           
1353                                                        current->control.def.value == def))
1354                        {
1355                            current->control.value.value = val;
1356                            current->control.flags |= CC_NEED_SET; //set flag
1357                                                        //printf("setting 0x%08x to %i\n", id, val);
1358                        }
1359                                                else
1360                                                {
1361                                                        print_libwebcam_error("control (0x%08x) - doesn't match hardware\n", id);
1362                                                }
1363                    }
1364                }
1365                else if(sscanf(line,"ID{0x%08x};CHK{0:0:0:0}=VAL64{",
1366                    &id) == 1)
1367                {
1368                    print_libwebcam_error("control (0x%08x) - 64 bit controls not supported\n", id);
1369                }
1370                else if(sscanf(line,"ID{0x%08x};CHK{%i:%i:%i:0}=STR{\"%*s\"}",
1371                    &id, &min, &max, &step) == 5)
1372                {
1373#ifdef ENABLE_RAW_CONTROLS
1374                    Control *current = find_control_by_v4l2_id(device, id);
1375                    if(current)
1376                    {
1377                         //check values
1378                        if(current->control.min.raw.size == min &&
1379                           current->control.max.raw.size == max &&
1380                           1 == step)
1381                        {
1382                            char str[max+1];
1383                            sscanf(line, "ID{0x%*x};CHK{%*i:%*i:%*i:0}==STR{\"%s\"}", str);
1384                            if(strlen(str) > max) //FIXME: should also check (minimum +N*step)
1385                            {
1386                                print_libwebcam_error("string bigger than maximum buffer size");
1387                            }
1388                            else
1389                            {
1390                                strcpy(current->control.value.raw.data, str);
1391                                current->control.flags |= CC_NEED_SET; //set flag
1392                            }
1393                        }
1394                    }
1395#endif
1396                }
1397                                //else printf("skip line\n");
1398                                               
1399            }
1400        }
1401       
1402        set_control_values(hDevice);
1403    }
1404finish:   
1405    fclose(fp);
1406    unlock_mutex(&device->controls.mutex);
1407    return C_SUCCESS;
1408}
1409 
1410/*
1411 * Events
1412 */
1413
1414/**
1415 * Enumerates the events supported by the given device. @e [unimplemented]
1416 *
1417 * @return
1418 *              - #C_INIT_ERROR if the library has not been initialized
1419 *              - #C_NOT_IMPLEMENTED
1420 */
1421CResult c_enum_events (CHandle hDevice, CEvent *events, unsigned int *size, unsigned int *count)
1422{
1423        if(!initialized)
1424                return C_INIT_ERROR;
1425        return C_NOT_IMPLEMENTED;
1426}
1427
1428
1429/**
1430 * Subscribes the caller to receive the given event. @e [unimplemented]
1431 *
1432 * @return
1433 *              - #C_INIT_ERROR if the library has not been initialized
1434 *              - #C_NOT_IMPLEMENTED
1435 */
1436CResult c_subscribe_event (CHandle hDevice, CEventId event_id, CEventHandler handler, void *context)
1437{
1438        if(!initialized)
1439                return C_INIT_ERROR;
1440        return C_NOT_IMPLEMENTED;
1441}
1442
1443
1444/**
1445 * Unsubscribes the caller from the given event. @e [unimplemented]
1446 *
1447 * @return
1448 *              - #C_INIT_ERROR if the library has not been initialized
1449 *              - #C_NOT_IMPLEMENTED
1450 */
1451CResult c_unsubscribe_event (CHandle hDevice, CEventId event_id)
1452{
1453        if(!initialized)
1454                return C_INIT_ERROR;
1455        return C_NOT_IMPLEMENTED;
1456}
1457
1458
1459/**
1460 * Returns the error message associated with a given error code.
1461 *
1462 * Note that the caller must free the buffer returned by this function.
1463 *
1464 * @param error         error code for which the message should be retrieved
1465 * @return
1466 *              - a newly allocated string describing the given error code
1467 *              - NULL if not enough memory was available or if the error code is
1468 *                unknown
1469 */
1470char *c_get_error_text (CResult error)
1471{
1472        return c_get_handle_error_text(0, error);
1473}
1474
1475
1476/**
1477 * Returns the error message associated with a given error code and device handle.
1478 *
1479 * Note that the caller must free the buffer returned by this function. Compared to the
1480 * #c_get_error_text() function, this function can take the handle's last system error
1481 * into account.
1482 *
1483 * @param hDevice       an open device handle. If this parameter is 0, the function behaves
1484 *                                      exactly like #c_get_error_text().
1485 * @param error         error code for which the message should be retrieved
1486 * @return
1487 *              - a newly allocated string describing the given error code
1488 *              - NULL if not enough memory was available or if the error code is
1489 *                unknown
1490 */
1491char *c_get_handle_error_text (CHandle hDevice, CResult error)
1492{
1493        switch(error) {
1494                case C_SUCCESS:                         return strdup("Success");
1495                case C_NOT_IMPLEMENTED:         return strdup("The function is not implemented");
1496                case C_INIT_ERROR:                      return strdup("Error during initialization or library not initialized");
1497                case C_INVALID_ARG:                     return strdup("Invalid argument");
1498                case C_INVALID_HANDLE:          return strdup("Invalid handle");
1499                case C_INVALID_DEVICE:          return strdup("Invalid device or device cannot be opened");
1500                case C_NOT_FOUND:                       return strdup("Object not found");
1501                case C_BUFFER_TOO_SMALL:        return strdup("Buffer too small");
1502                case C_SYNC_ERROR:                      return strdup("Error during data synchronization");
1503                case C_NO_MEMORY:                       return strdup("Out of memory");
1504                case C_NO_HANDLES:                      return strdup("Out of handles");
1505                case C_V4L2_ERROR:
1506                {
1507                        char *text = NULL;
1508                        if(hDevice && HANDLE_OPEN(hDevice)) {
1509                                if(asprintf(&text, "A Video4Linux2 API call returned an unexpected error %d", GET_HANDLE(hDevice).last_system_error) == -1)
1510                                        text = NULL;;
1511                        }
1512                        if(!text)
1513                                return strdup("A Video4Linux2 API call returned an unexpected error");
1514                        return text;
1515                }
1516                case C_SYSFS_ERROR:                     return strdup("A sysfs file access returned an error");
1517                case C_PARSE_ERROR:                     return strdup("A control could not be parsed");
1518                case C_CANNOT_WRITE:            return strdup("Writing not possible (e.g. read-only control)");
1519                case C_CANNOT_READ:                     return strdup("Reading not possible (e.g. write-only control)");
1520                default:                                        return NULL;
1521        }
1522}
1523
1524
1525
1526/*
1527 * Helper functions
1528 */
1529
1530/**
1531 * Prints a generic error message to stderr.
1532 */
1533void print_libwebcam_error (char *format, ...)
1534{
1535        char *newformat;
1536        va_list ap;
1537
1538        if(asprintf(&newformat, "[libwebcam] %s\n", format) == -1)
1539                newformat = format;
1540
1541        va_start(ap, format);
1542        vfprintf(stderr, newformat, ap);
1543        va_end(ap);
1544
1545        if(newformat != format)
1546                free(newformat);
1547        else
1548                fprintf(stderr, "\n");
1549}
1550
1551
1552/**
1553 * Prints a libwebcam error message to stderr.
1554 *
1555 * @param error         a #CResult error code whose error text is appended
1556 * @param format        a @a printf compatible format
1557 */
1558static void print_libwebcam_c_error (CResult error, char *format, ...)
1559{
1560        char *unknown_text = "Unknown error";
1561        char *text, *newformat;
1562        va_list ap;
1563
1564        // Retrieve the libwebcam error text
1565        text = c_get_error_text(error);
1566        if(text == NULL)
1567                text = unknown_text;
1568
1569        if(asprintf(&newformat, "[libwebcam] %s (error %d: %s)\n", format, error, text) == -1)
1570                newformat = format;
1571
1572        if(text != unknown_text)
1573                free(text);
1574
1575        va_start(ap, format);
1576        vfprintf(stderr, newformat, ap);
1577        va_end(ap);
1578
1579        if(newformat != format)
1580                free(newformat);
1581        else
1582                fprintf(stderr, "\n");
1583}
1584
1585
1586
1587/*
1588 * Control management
1589 */
1590
1591/**
1592 * Queries the control choice values of the given V4L2 control and uses the results to
1593 * fill in the choice structures of a libwebcam control.
1594 *
1595 * @param ctrl          Internal control for which the choice data is requested.
1596 * @param v4l2_ctrl     Pointer to a structure obtained from VIDIOC_QUERYCTRL and containing
1597 *                                      the V4L2 control data.
1598 * @param v4l2_dev      Open V4L2 device handle.
1599 */
1600static CResult create_control_choices (Control *ctrl, struct v4l2_queryctrl *v4l2_ctrl, int v4l2_dev)
1601{
1602        CResult ret = C_SUCCESS;
1603
1604        //int choices_count = v4l2_ctrl->maximum - v4l2_ctrl->minimum + 1;
1605        ctrl->control.choices.count = 0;
1606        ctrl->control.choices.list = NULL;
1607        // Allocate memory for the choices.names and choices.list members
1608        //ctrl->control.choices.names = (char *)malloc(choices_count * V4L2_MENU_CTRL_MAX_NAME_SIZE);
1609       
1610        //if(ctrl->control.choices.names == NULL) {
1611        //      ret = C_NO_MEMORY;
1612        //      goto done;
1613        //}
1614        //ctrl->control.choices.list = (CControlChoice *)malloc(choices_count * sizeof(CControlChoice));
1615        //if(ctrl->control.choices.list == NULL) {
1616        //      ret = C_NO_MEMORY;
1617        //      goto done;
1618        //}
1619
1620        // Query the menu items of the given control and transform them
1621        // into CControlChoice.
1622        struct v4l2_querymenu v4l2_menu = {0};
1623       
1624        v4l2_menu.id = v4l2_ctrl->id;
1625
1626        for(v4l2_menu.index = v4l2_ctrl->minimum; v4l2_menu.index <= v4l2_ctrl->maximum; v4l2_menu.index++) {
1627                if(ioctl(v4l2_dev, VIDIOC_QUERYMENU, &v4l2_menu) < 0)
1628                continue;
1629               
1630                ctrl->control.choices.count++;
1631                       
1632                if(!ctrl->control.choices.list)
1633                        ctrl->control.choices.list = (CControlChoice *)malloc(sizeof(CControlChoice));
1634                else
1635                        ctrl->control.choices.list = (CControlChoice *)realloc(ctrl->control.choices.list, ctrl->control.choices.count * sizeof(CControlChoice));
1636
1637               
1638                ctrl->control.choices.list[ctrl->control.choices.count-1].index = v4l2_menu.index;
1639                ctrl->control.choices.list[ctrl->control.choices.count-1].id = v4l2_menu.id;
1640                if(strlen((char *)v4l2_menu.name))
1641                        memcpy(ctrl->control.choices.list[ctrl->control.choices.count-1].name, v4l2_menu.name, V4L2_MENU_CTRL_MAX_NAME_SIZE);
1642                else
1643                        snprintf(ctrl->control.choices.list[ctrl->control.choices.count-1].name, V4L2_MENU_CTRL_MAX_NAME_SIZE, "%d", v4l2_menu.index);
1644        }
1645
1646        if(ret != C_SUCCESS) {
1647                if(ctrl->control.choices.list)
1648                        free(ctrl->control.choices.list);
1649        }
1650        return ret;
1651}
1652
1653
1654/**
1655 * Create a libwebcam control from a V4L2 control.
1656 *
1657 * If necessary, further information is requested by this function, e.g. in the case
1658 * of a choice control.
1659 *
1660 * @param device        Device to which the control should be appended.
1661 * @param v4l2_ctrl     Pointer to a structure obtained from VIDIOC_QUERYCTRL and containing
1662 *                                      the V4L2 control data.
1663 * @param v4l2_dev      Open V4L2 device handle.
1664 * @param pret          Pointer to receive the error code in the case of an error.
1665 *                                      (Can be NULL.)
1666 *
1667 * @return
1668 *              - NULL if an error occurred. The associated error can be found in @a pret.
1669 *              - Pointer to the newly created control.
1670 */
1671static Control *create_v4l2_control (Device *device, struct v4l2_queryctrl *v4l2_ctrl, int v4l2_dev, CResult *pret)
1672{
1673        CResult ret = C_SUCCESS;
1674        Control *ctrl = NULL;
1675
1676        // Map V4L2 control types to libwebcam control types
1677        CControlType type;
1678        switch(v4l2_ctrl->type) {
1679                case V4L2_CTRL_TYPE_INTEGER:    type = CC_TYPE_DWORD;           break;
1680                case V4L2_CTRL_TYPE_BOOLEAN:    type = CC_TYPE_BOOLEAN;         break;
1681                case V4L2_CTRL_TYPE_MENU:               type = CC_TYPE_CHOICE;          break;
1682#ifdef ENABLE_RAW_CONTROLS
1683                case V4L2_CTRL_TYPE_STRING:             type = CC_TYPE_RAW;                     break;
1684#endif
1685                case V4L2_CTRL_TYPE_BUTTON:             type = CC_TYPE_BUTTON;          break;
1686                case V4L2_CTRL_TYPE_INTEGER64:  // TODO implement
1687                        ret = C_NOT_IMPLEMENTED;
1688                        print_libwebcam_error("Warning: Unsupported V4L2 control type encountered: ctrl_id = 0x%08X, "
1689                                        "name = '%s', type = %d",
1690                                        v4l2_ctrl->id, v4l2_ctrl->name, v4l2_ctrl->type);
1691                        goto done;
1692                default:
1693                        ret = C_PARSE_ERROR;
1694                        print_libwebcam_error("Invalid V4L2 control type encountered: ctrl_id = 0x%08X, "
1695                                        "name = '%s', type = %d",
1696                                        v4l2_ctrl->id, v4l2_ctrl->name, v4l2_ctrl->type);
1697                        goto done;
1698        }
1699
1700        // Map the V4L2 control ID to a libwebcam ID
1701        CControlId ctrl_id = get_control_id_from_v4l2(v4l2_ctrl->id, device);
1702        //printf("Mapping V4L2 control ID 0x%08X => 0x%08X\n", v4l2_ctrl->id, ctrl_id);
1703        if(ctrl_id == 0) {
1704                ret = C_NOT_IMPLEMENTED;
1705                goto done;
1706        }
1707
1708        // Create the internal control info structure
1709        ctrl = (Control *)malloc(sizeof(*ctrl));
1710        if(ctrl) {
1711                memset(ctrl, 0, sizeof(*ctrl));
1712                ctrl->control.id                = ctrl_id;
1713                ctrl->v4l2_control              = v4l2_ctrl->id;
1714                if(strlen((char *)v4l2_ctrl->name))
1715                        ctrl->control.name              = strdup((char *)v4l2_ctrl->name);
1716                else
1717                        ctrl->control.name              = strdup(UNKNOWN_CONTROL_NAME);
1718                ctrl->control.type              = type;
1719                ctrl->control.flags             = CC_CAN_READ;
1720                if(!(v4l2_ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
1721                        ctrl->control.flags     |= CC_CAN_WRITE;
1722                if(v4l2_ctrl->id >= V4L2_CID_PRIVATE_BASE)
1723                        ctrl->control.flags |= CC_IS_CUSTOM;
1724                ctrl->control.def.value = v4l2_ctrl->default_value;
1725
1726                // Process V4L2 menu-style and raw controls
1727                if(type == CC_TYPE_CHOICE) {
1728                        ret = create_control_choices(ctrl, v4l2_ctrl, v4l2_dev);
1729                        if(ret) goto done;
1730                }
1731#ifdef ENABLE_RAW_CONTROLS
1732                else if(type == CC_TYPE_RAW) {
1733                        if(v4l2_ctrl->minimum != v4l2_ctrl->maximum || v4l2_ctrl->step != 1) {
1734                                print_libwebcam_error("Unsupported V4L2 string control encountered: ctrl_id = 0x%08X, "
1735                                        "name = '%s', min = %u, max = %u, step = %u",
1736                                        v4l2_ctrl->id, v4l2_ctrl->name,
1737                                        v4l2_ctrl->minimum, v4l2_ctrl->maximum, v4l2_ctrl->step);
1738                                ret = C_NOT_IMPLEMENTED;
1739                                goto done;
1740                        }
1741                        ctrl->control.value.raw.size =
1742                        ctrl->control.min.raw.size =
1743                        ctrl->control.def.raw.size = v4l2_ctrl->maximum;
1744                        //allocate data buffer
1745            ctrl->control.value.raw.data = calloc(ctrl->control.def.raw.size, sizeof(char));
1746                }
1747#endif
1748                else {
1749                        ctrl->control.min.value         = v4l2_ctrl->minimum;
1750                        ctrl->control.max.value         = v4l2_ctrl->maximum;
1751                        ctrl->control.step.value        = v4l2_ctrl->step;
1752                }
1753       
1754        ctrl->next = NULL;
1755        // Add the new control to the end of the control list of the given device
1756        if(device->controls.last)
1757        {
1758            device->controls.last->next = ctrl;
1759            device->controls.last = device->controls.last->next;
1760        }
1761        else
1762        {
1763            // is the first control to be added
1764            device->controls.first = ctrl;
1765            device->controls.last = device->controls.first;     
1766        }
1767                device->controls.count++;
1768        }
1769        else {
1770                ret = C_NO_MEMORY;
1771        }
1772
1773done:
1774        if(ret != C_SUCCESS && ctrl) {
1775                if(ctrl->control.name) {
1776                        free(ctrl->control.name);
1777                        ctrl->control.name = NULL;
1778                }
1779                free(ctrl);
1780                ctrl = NULL;
1781        }
1782        if(pret)
1783                *pret = ret;
1784        return ctrl;
1785}
1786
1787
1788/**
1789 * Frees all resources associated with the given control, including choice data.
1790 *
1791 * Note that this functino does not remove the control from its device's control list.
1792 */
1793static void delete_control (Control *ctrl)
1794{
1795        if(ctrl->control.type == CC_TYPE_CHOICE) {
1796                if(ctrl->control.choices.list)
1797                        free(ctrl->control.choices.list);
1798                //if(ctrl->control.choices.names)
1799                //      free(ctrl->control.choices.names);
1800        }
1801#ifdef ENABLE_RAW_CONTROLS
1802    if(ctrl->control.type == CC_TYPE_RAW)
1803    {
1804        if(ctrl->control.value.raw.data)
1805            free(ctrl->control.value.raw.data);
1806    } 
1807#endif
1808        if(ctrl->control.name)
1809                free(ctrl->control.name);
1810        free(ctrl);
1811}
1812
1813
1814/**
1815 * Looks up the control with the given ID for the given device.
1816 *
1817 * @return
1818 *              - NULL if no corresponding control was found for the given device.
1819 *              - Pointer to the control if it was found.
1820 */
1821static Control *find_control_by_id (Device *dev, CControlId id)
1822{
1823        Control *elem = dev->controls.first;
1824        while(elem) {
1825                if(elem->control.id == id)
1826                        break;
1827                elem = elem->next;
1828        }
1829        return elem;
1830}
1831
1832
1833/**
1834 * Clears the control list of the given device and frees all associated resources.
1835 */
1836static void clear_control_list (Device *dev)
1837{
1838        lock_mutex(&dev->controls.mutex);
1839
1840        Control *elem = dev->controls.first;
1841        while(elem) {
1842                Control *next = elem->next;
1843                delete_control(elem);
1844                elem = next;
1845        }
1846        dev->controls.first = NULL;
1847        dev->controls.count = 0;
1848
1849        unlock_mutex(&dev->controls.mutex);
1850}
1851
1852
1853/**
1854 * Scans the given device for supported controls and adds them to the internal list.
1855 *
1856 * Note that this function clears all existing controls prior to reenumerating them.
1857 */
1858static CResult refresh_control_list (Device *dev)
1859{
1860        CResult ret = C_SUCCESS;
1861        int v4l2_dev;
1862        struct v4l2_queryctrl v4l2_ctrl = { 0 };
1863
1864        // Clear control list first
1865        clear_control_list(dev);
1866
1867        // Open the corresponding V4L2 device
1868        if (dev->fd) v4l2_dev = dev->fd;
1869        else v4l2_dev = open_v4l2_device(dev->v4l2_name);
1870        if(!v4l2_dev)
1871                return C_INVALID_DEVICE;
1872
1873        if(lock_mutex(&dev->controls.mutex)) {
1874                ret = C_SYNC_ERROR;
1875                goto done;
1876        }
1877
1878        // Test if the driver supports the V4L2_CTRL_FLAG_NEXT_CTRL flag
1879#ifdef ENABLE_V4L2_ADVANCED_CONTROL_ENUMERATION
1880        v4l2_ctrl.id = 0 | V4L2_CTRL_FLAG_NEXT_CTRL;
1881        if(ioctl(v4l2_dev, VIDIOC_QUERYCTRL, &v4l2_ctrl) == 0) {
1882                // The driver supports the V4L2_CTRL_FLAG_NEXT_CTRL flag, so go ahead with
1883                // the advanced enumeration way.
1884
1885                int r;
1886                v4l2_ctrl.id = 0;
1887                int current_ctrl = v4l2_ctrl.id;
1888                v4l2_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
1889                // Loop as long as ioctl does not return EINVAL
1890                while((r = ioctl(v4l2_dev, VIDIOC_QUERYCTRL, &v4l2_ctrl)), r ? errno != EINVAL : 1) {
1891#ifdef CONTROL_IO_ERROR_RETRIES
1892                        if(r && (errno == EIO || errno == EPIPE || errno == ETIMEDOUT)) {
1893                                // An I/O error occurred, so retry the query a few times.
1894                                // This part is a little tricky. On the one hand, we want to retrieve the ID
1895                                // of the next control in case the query succeeds or we give up on retrying.
1896                                // On the other hand we want to retry the erroneous control instead of just
1897                                // skipping to the next one, wo we needed to backup the ID of the failing
1898                                // control first (above in current_ctrl).
1899                                // Keep in mind that with the NEXT_CTRL flag VIDIO_QUERYCTRL returns the
1900                                // first control with a *higher* ID than the specified one.
1901                                int tries = CONTROL_IO_ERROR_RETRIES;
1902                                v4l2_ctrl.id = current_ctrl | V4L2_CTRL_FLAG_NEXT_CTRL;
1903                                while(tries-- &&
1904                                          (r = ioctl(v4l2_dev, VIDIOC_QUERYCTRL, &v4l2_ctrl)) &&
1905                                          (errno == EIO || errno == EPIPE || errno == ETIMEDOUT)) {
1906                                        v4l2_ctrl.id = current_ctrl | V4L2_CTRL_FLAG_NEXT_CTRL;
1907                                }
1908                        }
1909#endif
1910                        // Prevent infinite loops for buggy NEXT_CTRL implementations
1911                        if(r && v4l2_ctrl.id <= current_ctrl) {
1912                                // If there was an error but the driver failed to provide us with the ID
1913                                // of the next control, we have to manually increase the control ID,
1914                                // otherwise we risk getting stuck querying the erroneous control.
1915                                current_ctrl++;
1916                                print_libwebcam_error(
1917                                                "Warning: The driver behind device %s has a slightly buggy implementation\n"
1918                                                "  of the V4L2_CTRL_FLAG_NEXT_CTRL flag. It does not return the next higher\n"
1919                                                "  control ID if a control query fails. A workaround has been enabled.",
1920                                                dev->v4l2_name);
1921                                goto next_control;
1922                        }
1923                        else if(!r && v4l2_ctrl.id == current_ctrl) {
1924                                // If there was no error but the driver did not increase the control ID
1925                                // we simply cancel the enumeration.
1926                                print_libwebcam_error(
1927                                                "Error: The driver %s behind device %s has a buggy\n"
1928                                                "  implementation of the V4L2_CTRL_FLAG_NEXT_CTRL flag. It does not raise an\n"
1929                                                "  error or return the next control. Canceling control enumeration.",
1930                                                dev->device.driver, dev->v4l2_name);
1931                                goto done;
1932                        }
1933
1934                        current_ctrl = v4l2_ctrl.id;
1935
1936                        // Skip failed and disabled controls
1937                        if(r || v4l2_ctrl.flags & V4L2_CTRL_FLAG_DISABLED)
1938                                goto next_control;
1939
1940                        Control *ctrl = create_v4l2_control(dev, &v4l2_ctrl, v4l2_dev, &ret);
1941                        if(ctrl == NULL) {
1942                                if(ret == C_PARSE_ERROR || ret == C_NOT_IMPLEMENTED) {
1943                                        print_libwebcam_error("Invalid or unsupported V4L2 control encountered: "
1944                                                        "ctrl_id = 0x%08X, name = '%s'", v4l2_ctrl.id, v4l2_ctrl.name);
1945                                        ret = C_SUCCESS;
1946                                }
1947                                else {
1948                                        goto done;
1949                                }
1950                        }
1951
1952next_control:
1953                        v4l2_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
1954                }
1955        }
1956        else
1957#endif
1958        {
1959                // The driver does not support the V4L2_CTRL_FLAG_NEXT_CTRL flag, so we need
1960                // to fall back to the old way of enumerating controls, i.e. enumerating the
1961                // standard V4L2 controls first, followed by the driver's private controls.
1962                // It won't be possible to enumerate controls with non-contiguous IDs but in
1963                // this case the driver probably doesn't implement any.
1964
1965                // Enumerate default V4L2 controls.
1966                // We use a separate variable instead of v4l2_ctrl.id for the loop counter because
1967                // some drivers (bttv) simply return a fake control with ID 0 when the device
1968                // doesn't support a control in the [V4L2_CID_BASE, V4L2_CID_LASTP1) interval,
1969                // thereby overwriting our loop variable and causing us to restart from 0.
1970                int current_ctrl;
1971                for(current_ctrl = V4L2_CID_BASE; current_ctrl < V4L2_CID_LASTP1; current_ctrl++) {
1972                        v4l2_ctrl.id = current_ctrl;
1973#ifndef CONTROL_IO_ERROR_RETRIES
1974                        if(ioctl(v4l2_dev, VIDIOC_QUERYCTRL, &v4l2_ctrl) ||
1975                           v4l2_ctrl.flags & V4L2_CTRL_FLAG_DISABLED)
1976                                continue;
1977#else
1978                        int r = 0, tries = 1 + CONTROL_IO_ERROR_RETRIES;
1979                        while(tries-- &&
1980                                  (r = ioctl(v4l2_dev, VIDIOC_QUERYCTRL, &v4l2_ctrl)) &&
1981                                  (errno == EIO || errno == EPIPE || errno == ETIMEDOUT));
1982                        if(r || v4l2_ctrl.flags & V4L2_CTRL_FLAG_DISABLED)
1983                                continue;
1984#endif
1985
1986                        Control *ctrl = create_v4l2_control(dev, &v4l2_ctrl, v4l2_dev, &ret);
1987                        if(ctrl == NULL) {
1988                                if(ret == C_PARSE_ERROR || ret == C_NOT_IMPLEMENTED) {
1989                                        print_libwebcam_error("Invalid or unsupported V4L2 control encountered: "
1990                                                        "ctrl_id = 0x%08X, name = '%s'", v4l2_ctrl.id, v4l2_ctrl.name);
1991                                        ret = C_SUCCESS;
1992                                        continue;
1993                                }
1994                                goto done;
1995                        }
1996                }
1997
1998                // Enumerate custom controls
1999                for(v4l2_ctrl.id = V4L2_CID_PRIVATE_BASE;; v4l2_ctrl.id++) {
2000#ifndef CONTROL_IO_ERROR_RETRIES
2001                        if(ioctl(v4l2_dev, VIDIOC_QUERYCTRL, &v4l2_ctrl))
2002                                break;
2003#else
2004                        int r = 0, tries = 1 + CONTROL_IO_ERROR_RETRIES;
2005                        while(tries-- &&
2006                                  (r = ioctl(v4l2_dev, VIDIOC_QUERYCTRL, &v4l2_ctrl)) &&
2007                                  (errno == EIO || errno == EPIPE || errno == ETIMEDOUT));
2008                        if(r)
2009                                break;
2010#endif
2011                        if(v4l2_ctrl.flags & V4L2_CTRL_FLAG_DISABLED)
2012                                continue;
2013
2014                        Control *ctrl = create_v4l2_control(dev, &v4l2_ctrl, v4l2_dev, &ret);
2015                        if(ctrl == NULL) {
2016                                if(ret == C_PARSE_ERROR || ret == C_NOT_IMPLEMENTED) {
2017                                        print_libwebcam_error("Invalid or unsupported custom V4L2 control encountered: "
2018                                                        "ctrl_id = 0x%08X, name = '%s'", v4l2_ctrl.id, v4l2_ctrl.name);
2019                                        ret = C_SUCCESS;
2020                                        continue;
2021                                }
2022                                goto done;
2023                        }
2024                }
2025        }
2026
2027done:
2028        unlock_mutex(&dev->controls.mutex);
2029        if (!dev->fd) close(v4l2_dev);
2030
2031        return ret;
2032}
2033
2034
2035/**
2036 * Retrieve device information for the given device.
2037 */
2038static CResult refresh_device_details (Device *dev)
2039{
2040        CResult ret = C_SUCCESS;
2041        int v4l2_dev;
2042        struct v4l2_capability v4l2_cap;
2043
2044        // Open the corresponding V4L2 device
2045        if (dev->fd) v4l2_dev = dev->fd;
2046        else v4l2_dev = open_v4l2_device(dev->v4l2_name);
2047        if(!v4l2_dev)
2048                return C_INVALID_DEVICE;
2049
2050        // Query the device
2051        if(!ioctl(v4l2_dev, VIDIOC_QUERYCAP, &v4l2_cap)) {
2052                if(v4l2_cap.card[0])
2053                        dev->device.name = strdup((char *)v4l2_cap.card);
2054                else
2055                        dev->device.name = dev->v4l2_name;      // strdup?!
2056                dev->device.driver = strdup((char *)v4l2_cap.driver);
2057                if(v4l2_cap.bus_info[0])
2058                        dev->device.location = strdup((char *)v4l2_cap.bus_info);
2059                else
2060                        dev->device.location = dev->v4l2_name;  // strdup?!
2061        }
2062        else {
2063                //ret = C_V4L2_ERROR;
2064                dev->device.name = strdup(dev->v4l2_name);
2065                dev->device.driver = strdup("uvcvideo");
2066                dev->device.location = strdup(dev->v4l2_name);
2067        }
2068
2069        if (!dev->fd) close(v4l2_dev);
2070
2071        return ret;
2072}
2073
2074
2075/**
2076 * Returns the length required to store all the (null-terminated) names of the given
2077 * device's controls in a buffer.
2078 *
2079 * Note: The control list should be locked before calling this function.
2080 */
2081static unsigned int get_control_dynamics_length(Device *device, unsigned int *names_length, unsigned int *choices_length)
2082{
2083        unsigned int names = 0, choices = 0;
2084        Control *elem = device->controls.first;
2085        while(elem) {
2086                // Add length of the control name
2087                if(elem->control.name)
2088                        names += strlen(elem->control.name) + 1;
2089
2090                // Add length of the control choice names
2091                if(elem->control.type == CC_TYPE_CHOICE) {
2092                        int index;
2093                        for(index = 0; index < elem->control.choices.count; index++) {
2094                                choices += sizeof(CControlChoice);
2095                                choices += strlen(elem->control.choices.list[index].name) + 1;
2096                        }
2097                }
2098
2099                elem = elem->next;
2100        }
2101        if(names_length)
2102                *names_length = names;
2103        if(choices_length)
2104                *choices_length = choices;
2105        return names + choices;
2106}
2107
2108
2109/**
2110 * Converts a V4L2 control ID to a libwebcam control ID.
2111 *
2112 * @param v4l2_id       V4L2 ID that should be converted.
2113 * @param dev           Pointer to the device to which the control belongs.
2114 */
2115static CControlId get_control_id_from_v4l2 (int v4l2_id, Device *dev)
2116{
2117        switch(v4l2_id) {
2118                // Basic V4L2 controls
2119                case V4L2_CID_BRIGHTNESS:                       return CC_BRIGHTNESS;
2120                case V4L2_CID_CONTRAST:                         return CC_CONTRAST;
2121                case V4L2_CID_SATURATION:                       return CC_SATURATION;
2122                case V4L2_CID_HUE:                                      return CC_HUE;
2123                case V4L2_CID_AUDIO_VOLUME:                     break;  // not supported by libwebcam
2124                case V4L2_CID_AUDIO_BALANCE:            break;  // not supported by libwebcam
2125                case V4L2_CID_AUDIO_BASS:                       break;  // not supported by libwebcam
2126                case V4L2_CID_AUDIO_TREBLE:                     break;  // not supported by libwebcam
2127                case V4L2_CID_AUDIO_MUTE:                       break;  // not supported by libwebcam
2128                case V4L2_CID_AUDIO_LOUDNESS:           break;  // not supported by libwebcam
2129                case V4L2_CID_BLACK_LEVEL:                      break;  // deprecated
2130                case V4L2_CID_AUTO_WHITE_BALANCE:       return CC_AUTO_WHITE_BALANCE_TEMPERATURE;
2131                case V4L2_CID_DO_WHITE_BALANCE:         break;  // not supported by libwebcam
2132                case V4L2_CID_RED_BALANCE:                      break;  // not supported by libwebcam
2133                case V4L2_CID_BLUE_BALANCE:                     break;  // not supported by libwebcam
2134                case V4L2_CID_GAMMA:                            return CC_GAMMA;
2135                case V4L2_CID_EXPOSURE:                         return CC_EXPOSURE_TIME_ABSOLUTE;
2136                case V4L2_CID_AUTOGAIN:                         break;  // not supported by libwebcam
2137                case V4L2_CID_GAIN:                                     return CC_GAIN;
2138                case V4L2_CID_HFLIP:                            break;  // not supported by libwebcam
2139                case V4L2_CID_VFLIP:                            break;  // not supported by libwebcam
2140#ifdef V4L2_CID_POWER_LINE_FREQUENCY
2141                case V4L2_CID_POWER_LINE_FREQUENCY:             return CC_POWER_LINE_FREQUENCY;
2142#endif
2143#ifdef V4L2_CID_HUE_AUTO
2144                case V4L2_CID_HUE_AUTO:                                 return CC_AUTO_HUE;
2145#endif
2146#ifdef V4L2_CID_WHITE_BALANCE_TEMPERATURE
2147                case V4L2_CID_WHITE_BALANCE_TEMPERATURE:        return CC_WHITE_BALANCE_TEMPERATURE;
2148#endif
2149#ifdef V4L2_CID_SHARPNESS
2150                case V4L2_CID_SHARPNESS:                                return CC_SHARPNESS;
2151#endif
2152#ifdef V4L2_CID_BACKLIGHT_COMPENSATION
2153                case V4L2_CID_BACKLIGHT_COMPENSATION:   return CC_BACKLIGHT_COMPENSATION;
2154#endif
2155#ifdef V4L2_CID_CHROMA_AGC
2156                case V4L2_CID_CHROMA_AGC:                               break;  // not supported by libwebcam
2157#endif
2158#ifdef V4L2_CID_COLOR_KILLER
2159                case V4L2_CID_COLOR_KILLER:                             break;  // not supported by libwebcam
2160#endif
2161#ifdef V4L2_CID_COLORFX
2162                case V4L2_CID_COLORFX:                                  break;  // not supported by libwebcam
2163#endif
2164
2165                // Camera/UVC driver controls
2166#ifdef V4L2_CID_EXPOSURE_AUTO
2167                case V4L2_CID_EXPOSURE_AUTO:                    return CC_AUTO_EXPOSURE_MODE;
2168#endif
2169#ifdef V4L2_CID_EXPOSURE_ABSOLUTE
2170                case V4L2_CID_EXPOSURE_ABSOLUTE:                return CC_EXPOSURE_TIME_ABSOLUTE;
2171#endif
2172#ifdef V4L2_CID_EXPOSURE_AUTO_PRIORITY
2173                case V4L2_CID_EXPOSURE_AUTO_PRIORITY:   return CC_AUTO_EXPOSURE_PRIORITY;
2174#endif
2175#ifdef V4L2_CID_PAN_RELATIVE
2176                case V4L2_CID_PAN_RELATIVE:                             return CC_PAN_RELATIVE;
2177#endif
2178#ifdef V4L2_CID_TILT_RELATIVE
2179                case V4L2_CID_TILT_RELATIVE:                    return CC_TILT_RELATIVE;
2180#endif
2181#ifdef V4L2_CID_PAN_RESET
2182                case V4L2_CID_PAN_RESET:                                return CC_PAN_RESET;
2183#endif
2184#ifdef V4L2_CID_TILT_RESET
2185                case V4L2_CID_TILT_RESET:                               return CC_TILT_RESET;
2186#endif
2187#ifdef V4L2_CID_PAN_ABSOLUTE
2188                case V4L2_CID_PAN_ABSOLUTE:                             return CC_PAN_ABSOLUTE;
2189#endif
2190#ifdef V4L2_CID_TILT_ABSOLUTE
2191                case V4L2_CID_TILT_ABSOLUTE:                    return CC_TILT_ABSOLUTE;
2192#endif
2193#ifdef V4L2_CID_FOCUS_ABSOLUTE
2194                case V4L2_CID_FOCUS_ABSOLUTE:                   return CC_FOCUS_ABSOLUTE;
2195#endif
2196#ifdef V4L2_CID_FOCUS_RELATIVE
2197                case V4L2_CID_FOCUS_RELATIVE:                   return CC_FOCUS_RELATIVE;
2198#endif
2199#ifdef V4L2_CID_FOCUS_AUTO
2200                case V4L2_CID_FOCUS_AUTO:                               return CC_AUTO_FOCUS;
2201#endif
2202#ifdef V4L2_CID_ZOOM_ABSOLUTE
2203                case V4L2_CID_ZOOM_ABSOLUTE:                    return CC_ZOOM_ABSOLUTE;
2204#endif
2205#ifdef V4L2_CID_ZOOM_RELATIVE
2206                case V4L2_CID_ZOOM_RELATIVE:                    return CC_ZOOM_RELATIVE;
2207#endif
2208#ifdef V4L2_CID_ZOOM_CONTINUOUS
2209                case V4L2_CID_ZOOM_CONTINUOUS:                  break;  // not supported by libwebcam
2210#endif
2211#ifdef V4L2_CID_PRIVACY
2212                case V4L2_CID_PRIVACY:                                  return CC_PRIVACY;
2213#endif
2214#ifdef V4L2_CID_LED1_MODE
2215                case V4L2_CID_LED1_MODE:                                return CC_LOGITECH_LED1_MODE;
2216#endif
2217#ifdef V4L2_CID_LED1_FREQUENCY
2218                case V4L2_CID_LED1_FREQUENCY:                   return CC_LOGITECH_LED1_FREQUENCY;
2219#endif
2220#ifdef V4L2_CID_DISABLE_PROCESSING
2221                case V4L2_CID_DISABLE_PROCESSING:               return CC_LOGITECH_DISABLE_PROCESSING;
2222#endif
2223#ifdef V4L2_CID_RAW_BITS_PER_PIXEL
2224                case V4L2_CID_RAW_BITS_PER_PIXEL:               return CC_LOGITECH_RAW_BITS_PER_PIXEL;
2225#endif
2226        };
2227
2228#ifdef USE_UVCVIDEO
2229        // Controls contained only in older UVC drivers
2230        //printf("*** 0x%08X 0x%08X\n", v4l2_id, UVC_CID_EXPOSURE_AUTO);
2231        if(strcmp(dev->device.driver, "uvcvideo") == 0) {
2232                switch(v4l2_id) {
2233#ifdef UVC_CID_BACKLIGHT_COMPENSATION
2234                        case UVC_CID_BACKLIGHT_COMPENSATION:                    return CC_BACKLIGHT_COMPENSATION;
2235#endif
2236#ifdef UVC_CID_POWER_LINE_FREQUENCY
2237                        case UVC_CID_POWER_LINE_FREQUENCY:                              return CC_POWER_LINE_FREQUENCY;
2238#endif
2239#ifdef UVC_CID_SHARPNESS
2240                        case UVC_CID_SHARPNESS:                                                 return CC_SHARPNESS;
2241#endif
2242#ifdef UVC_CID_HUE_AUTO
2243                        case UVC_CID_HUE_AUTO:                                                  return CC_AUTO_HUE;
2244#endif
2245#ifdef UVC_CID_FOCUS_AUTO
2246                        case UVC_CID_FOCUS_AUTO:                                                return CC_AUTO_FOCUS;
2247#endif
2248#ifdef UVC_CID_FOCUS_ABSOLUTE
2249                        case UVC_CID_FOCUS_ABSOLUTE:                                    return CC_FOCUS_ABSOLUTE;
2250#endif
2251#ifdef UVC_CID_FOCUS_RELATIVE
2252                        case UVC_CID_FOCUS_RELATIVE:                                    return CC_FOCUS_RELATIVE;
2253#endif
2254#ifdef UVC_CID_PAN_RELATIVE
2255                        case UVC_CID_PAN_RELATIVE:                                              return CC_PAN_RELATIVE;
2256#endif
2257#ifdef UVC_CID_TILT_RELATIVE
2258                        case UVC_CID_TILT_RELATIVE:                                             return CC_TILT_RELATIVE;
2259#endif
2260#ifdef UVC_CID_PANTILT_RESET
2261                        case UVC_CID_PANTILT_RESET:                                             return CC_LOGITECH_PANTILT_RESET;
2262#endif
2263#ifdef UVC_CID_EXPOSURE_AUTO
2264                        case UVC_CID_EXPOSURE_AUTO:                                             return CC_AUTO_EXPOSURE_MODE;
2265#endif
2266#ifdef UVC_CID_EXPOSURE_ABSOLUTE
2267                        case UVC_CID_EXPOSURE_ABSOLUTE:                                 return CC_EXPOSURE_TIME_ABSOLUTE;
2268#endif
2269#ifdef UVC_CID_EXPOSURE_AUTO_PRIORITY
2270                        case UVC_CID_EXPOSURE_AUTO_PRIORITY:                    return CC_AUTO_EXPOSURE_PRIORITY;
2271#endif
2272#ifdef UVC_CID_WHITE_BALANCE_TEMPERATURE_AUTO
2273                        case UVC_CID_WHITE_BALANCE_TEMPERATURE_AUTO:    return CC_AUTO_WHITE_BALANCE_TEMPERATURE;
2274#endif
2275#ifdef UVC_CID_WHITE_BALANCE_TEMPERATURE
2276                        case UVC_CID_WHITE_BALANCE_TEMPERATURE:                 return CC_WHITE_BALANCE_TEMPERATURE;
2277#endif
2278#ifdef V4L2_CID_PANTILT_RELATIVE
2279                        case V4L2_CID_PANTILT_RELATIVE:                                 return CC_LOGITECH_PANTILT_RELATIVE;
2280#endif
2281                }
2282        }
2283#endif
2284
2285        // Unknown V4L2 controls
2286        // Note that there is a margin of 256 control values for controls that are added
2287        // after libwebcam compilation time.
2288        if(V4L2_CTRL_ID2CLASS(v4l2_id) == V4L2_CTRL_CLASS_USER) {
2289                // Unknown user control
2290                print_libwebcam_error(
2291                        "Unknown V4L2 user control ID encountered: 0x%08X (V4L2_CID_USER_BASE + %d)",
2292                        v4l2_id, v4l2_id - V4L2_CID_USER_BASE
2293                );
2294                return CC_V4L2_BASE + (v4l2_id - V4L2_CID_USER_BASE);
2295        }
2296        else if(V4L2_CTRL_ID2CLASS(v4l2_id) == V4L2_CTRL_CLASS_MPEG) {
2297                // Unknown MPEG control
2298                print_libwebcam_error(
2299                        "Unknown V4L2 MPEG control ID encountered: 0x%08X (V4L2_CID_MPEG_BASE + %d)",
2300                        v4l2_id, v4l2_id - V4L2_CID_MPEG_BASE
2301                );
2302                return CC_V4L2_MPEG_BASE + (v4l2_id - V4L2_CID_MPEG_BASE);
2303        }
2304        else if(V4L2_CTRL_ID2CLASS(v4l2_id) == V4L2_CTRL_CLASS_CAMERA) {
2305                // Unknown camera class (UVC) control
2306                print_libwebcam_error(
2307                        "Unknown V4L2 camera class (UVC) control ID encountered: 0x%08X (V4L2_CID_CAMERA_CLASS_BASE + %d)",
2308                        v4l2_id, v4l2_id - V4L2_CID_CAMERA_CLASS_BASE
2309                );
2310                return CC_V4L2_CAMERA_CLASS_BASE + (v4l2_id - V4L2_CID_CAMERA_CLASS_BASE);
2311        }
2312        else if(v4l2_id >= V4L2_CID_PRIVATE_BASE) {
2313                // Unknown private control
2314                print_libwebcam_error(
2315                        "Unknown V4L2 private control ID encountered: 0x%08X (V4L2_CID_PRIVATE_BASE + %d)",
2316                        v4l2_id, v4l2_id - V4L2_CID_PRIVATE_BASE
2317                );
2318                return CC_V4L2_CUSTOM_BASE + (v4l2_id - V4L2_CID_PRIVATE_BASE);
2319        }
2320
2321        print_libwebcam_error("Unknown V4L2 control ID encountered: 0x%08X", v4l2_id);
2322        return 0;
2323}
2324
2325
2326/*
2327 * Device management
2328 */
2329
2330/**
2331 * Allocate a new device with the given name and add it to the global device list.
2332 */
2333static Device *create_device (char *name)
2334{
2335        Device *dev = NULL;
2336
2337        dev = (Device *)malloc(sizeof(*dev));
2338        if(dev) {
2339                memset(dev, 0, sizeof(*dev));
2340                strcpy(dev->v4l2_name, name);
2341                dev->device.shortName = strdup(name);
2342                dev->valid = 1;
2343
2344                // Add the new device to the global device list
2345                dev->next = device_list.first;
2346                device_list.first = dev;
2347                device_list.count++;
2348        }
2349
2350        return dev;
2351}
2352
2353
2354/**
2355 * Free up the given device.
2356 *
2357 * Note that this function does not remove the device from the global device list.
2358 */
2359static void delete_device (Device *dev)
2360{
2361        // Free all the handles that point to this device
2362        lock_mutex(&handle_list.mutex);
2363        if(dev->handles > 0) {
2364                CHandle hDevice;
2365                for(hDevice = 1; hDevice < MAX_HANDLES; hDevice++) {
2366                        if(HANDLE_OPEN(hDevice) && GET_HANDLE(hDevice).device == dev) {
2367                                // Remove the device link from the handle but leave the handle around
2368                                dev->handles--;
2369                                GET_HANDLE(hDevice).device = NULL;
2370                        }
2371                }
2372        }
2373        unlock_mutex(&handle_list.mutex);
2374
2375        // Free all controls of this device
2376        clear_control_list(dev);
2377
2378        if(dev->device.shortName)
2379                free(dev->device.shortName);
2380        if(dev->device.name && dev->device.name != dev->v4l2_name)
2381                free(dev->device.name);
2382        if(dev->device.driver)
2383                free(dev->device.driver);
2384        if(dev->device.location && dev->device.location != dev->v4l2_name)
2385                free(dev->device.location);
2386        free(dev);
2387}
2388
2389
2390/**
2391 * Mark all entries in the device list as invalid. This allows the cleanup_device_list()
2392 * function to be used to clear the entire device list.
2393 *
2394 * Note: The device list should be locked before calling this function.
2395 */
2396static void invalidate_device_list (void)
2397{
2398        Device *elem = device_list.first;
2399        while(elem) {
2400                elem->valid = 0;
2401                elem = elem->next;
2402        }
2403}
2404
2405
2406/**
2407 * Remove all entries marked as invalid from the device list.
2408 *
2409 * Note: The device list should be locked before calling this function.
2410 */
2411static void cleanup_device_list (void)
2412{
2413        Device *elem = device_list.first;
2414        Device *prev = NULL, *next;
2415        while(elem) {
2416                next = elem->next;
2417                if(!elem->valid) {
2418                        if(prev)
2419                                prev->next = next;
2420                        else
2421                                device_list.first = next;
2422                        delete_device(elem);
2423                        device_list.count--;
2424                }
2425                else {
2426                        prev = elem;
2427                }
2428                elem = next;
2429        }
2430}
2431
2432
2433/**
2434 * Searches the device list for the device with the given name.
2435 */
2436static Device *find_device_by_name (const char *name)
2437{
2438        Device *elem = device_list.first;
2439        while(elem) {
2440                if(strcmp(name, elem->v4l2_name) == 0)
2441                        return elem;
2442                elem = elem->next;
2443        }
2444        return NULL;
2445}
2446
2447
2448/**
2449 * Returns the length required to store all the (null-terminated) strings of the
2450 * given device in a buffer.
2451 */
2452static int get_device_dynamics_length (CDevice *device)
2453{
2454        return strlen(device->shortName)        + 1 +
2455                   strlen(device->name)                 + 1 +
2456                   strlen(device->driver)               + 1 +
2457                   strlen(device->location)             + 1;
2458}
2459
2460
2461/**
2462 * Returns the length required to store all the (null-terminated) strings of the
2463 * current devices in a buffer.
2464 *
2465 * Note: The device list should be locked before calling this function.
2466 */
2467static int get_devices_dynamics_length (void)
2468{
2469        int size = 0;
2470        Device *elem = device_list.first;
2471        while(elem) {
2472                size += get_device_dynamics_length(&elem->device);
2473                elem = elem->next;
2474        }
2475        return size;
2476}
2477
2478
2479/**
2480 * Synchronizes the device list with the information available in sysfs.
2481 */
2482static CResult refresh_device_list (void)
2483{
2484        CResult ret = C_SUCCESS;
2485        DIR *v4l_dir = NULL;
2486        struct dirent *dir_entry;
2487
2488        if(lock_mutex(&device_list.mutex))
2489                return C_SYNC_ERROR;
2490
2491        // Invalidate all list entries
2492        invalidate_device_list();
2493
2494        // Go through all devices in sysfs and validate the list entries that have
2495        // correspondences in sysfs.
2496        v4l_dir = opendir("/sys/class/video4linux");
2497        if(v4l_dir) {
2498                while((dir_entry = readdir(v4l_dir))) {
2499                        // Ignore non-video devices
2500                        if(strstr(dir_entry->d_name, "video") != dir_entry->d_name &&
2501                                        strstr(dir_entry->d_name, "subdev") != dir_entry->d_name)
2502                                continue;
2503
2504                        Device *dev = find_device_by_name(dir_entry->d_name);
2505                        if(dev) {
2506                                dev->valid = 1;
2507                        }
2508                        else {
2509                                dev = create_device(dir_entry->d_name);
2510                                if(dev == NULL) {
2511                                        ret = C_NO_MEMORY;
2512                                        goto done;
2513                                }
2514
2515                                // Read detail information about the device
2516                                ret = refresh_device_details(dev);
2517                                if(ret) {
2518                                        // Invalidate the device immediately, so it gets deleted by the call
2519                                        // to cleanup_device_list() below.
2520                                        dev->valid = 0;
2521
2522                                        // If there was a V4L2 error reset the error code, so that device enumeration
2523                                        // continues. This is necessary because V4L1 devices will let
2524                                        // refresh_device_details fail as they don't understand VIDIOC_QUERYCAP.
2525                                        if(ret == C_V4L2_ERROR) {
2526                                                print_libwebcam_error(
2527                                                                "Warning: The driver behind device %s does not seem to support V4L2.",
2528                                                                dev->v4l2_name);
2529                                                ret = C_SUCCESS;
2530                                                continue;
2531                                        }
2532                                        break;
2533                                }
2534                                get_device_usb_info(dev, &dev->device.usb);
2535
2536                                // Create the control list for the given device
2537                                ret = refresh_control_list(dev);
2538                                if(ret) goto done;
2539                        }
2540                }
2541        }
2542
2543        // Clean out all invalid device list entries
2544        cleanup_device_list();
2545
2546done:
2547        if(v4l_dir)
2548                closedir(v4l_dir);
2549        unlock_mutex(&device_list.mutex);
2550        if(ret)
2551                print_libwebcam_c_error(ret, "Unable to refresh device list.");
2552        return ret;
2553}
2554
2555
2556/**
2557 * Open the V4L2 device node with the given name.
2558 *
2559 * @param device_name   A device name as accepted by c_open_device()
2560 *
2561 * @return
2562 *              - 0 if the device could not be opened
2563 *              - a device handle > 0 on success
2564 */
2565int open_v4l2_device(char *device_name)
2566{
2567        int v4l2_dev;
2568        char *dev_node;
2569
2570        if(device_name == NULL)
2571                return C_INVALID_ARG;
2572
2573        dev_node = (char *)malloc(5 + strlen(device_name) + 1);
2574        if(!dev_node)
2575                return 0;
2576        sprintf(dev_node, "/dev/%s", device_name);
2577        v4l2_dev = open(dev_node, O_RDWR);
2578        free(dev_node);
2579        return v4l2_dev;
2580}
2581
2582
2583/**
2584 * Retrieves the value of a given V4L2 control.
2585 */
2586static CResult read_v4l2_control(Device *device, Control *control, CControlValue *value, CHandle hDevice)
2587{
2588        CResult ret = C_SUCCESS;
2589
2590        if(device == NULL || control == NULL || value == NULL)
2591                return C_INVALID_ARG;
2592
2593        int v4l2_dev = device->fd; //open_v4l2_device(device->v4l2_name);
2594        if(!v4l2_dev)
2595                return C_INVALID_DEVICE;
2596
2597#ifdef ENABLE_RAW_CONTROLS
2598        if(control->control.type == CC_TYPE_RAW) {
2599                unsigned int ctrl_size = control->control.max.raw.size;
2600
2601                if(value->raw.data == NULL)
2602                        return C_INVALID_ARG;
2603                if(value->raw.size < ctrl_size)
2604                        return C_INVALID_ARG;
2605
2606                struct v4l2_ext_control v4l2_ext_ctrl = {
2607                        .id             = control->v4l2_control,
2608                        .size   = ctrl_size,
2609                };
2610                v4l2_ext_ctrl.string = value->raw.data;
2611                struct v4l2_ext_controls v4l2_ext_ctrls = {
2612                        .ctrl_class     = V4L2_CTRL_CLASS_USER,
2613                        .count          = 1,
2614                        .controls       = &v4l2_ext_ctrl
2615                };
2616                if(ioctl(v4l2_dev, VIDIOC_G_EXT_CTRLS, &v4l2_ext_ctrls)) {
2617                        ret = C_V4L2_ERROR;
2618                        set_last_error(hDevice, errno);
2619                        goto done;
2620                }
2621
2622                // Set the raw data size to the size of the control
2623                value->raw.size = ctrl_size;
2624        }
2625        else
2626#endif
2627        {
2628                struct v4l2_control v4l2_ctrl = { .id = control->v4l2_control };
2629                if(ioctl(v4l2_dev, VIDIOC_G_CTRL, &v4l2_ctrl)) {
2630                        ret = C_V4L2_ERROR;
2631                        set_last_error(hDevice, errno);
2632                        goto done;
2633                }
2634                value->value    = v4l2_ctrl.value;
2635        }
2636
2637        value->type             = control->control.type;
2638
2639done:
2640        //close(v4l2_dev);
2641        return ret;
2642}
2643
2644
2645/**
2646 * Changes the value of a given V4L2 control.
2647 */
2648static CResult write_v4l2_control(Device *device, Control *control, const CControlValue *value, CHandle hDevice)
2649{
2650        CResult ret = C_SUCCESS;
2651
2652        if(device == NULL || control == NULL || value == NULL)
2653                return C_INVALID_ARG;
2654
2655        int v4l2_dev = device->fd; //open_v4l2_device(device->v4l2_name);
2656        if(!v4l2_dev)
2657                return C_INVALID_DEVICE;
2658
2659#ifdef ENABLE_RAW_CONTROLS
2660        if(control->control.type == CC_TYPE_RAW) {
2661                unsigned int ctrl_size = control->control.max.raw.size;
2662
2663                if(value->raw.data == NULL)
2664                        return C_INVALID_ARG;
2665                if(value->raw.size < ctrl_size)
2666                        return C_INVALID_ARG;
2667
2668                struct v4l2_ext_control v4l2_ext_ctrl = {
2669                        .id             = control->v4l2_control,
2670                        .size   = ctrl_size,
2671                };
2672                v4l2_ext_ctrl.string = value->raw.data;
2673                struct v4l2_ext_controls v4l2_ext_ctrls = {
2674                        .ctrl_class     = V4L2_CTRL_CLASS_USER,
2675                        .count          = 1,
2676                        .controls       = &v4l2_ext_ctrl
2677                };
2678                if(ioctl(v4l2_dev, VIDIOC_S_EXT_CTRLS, &v4l2_ext_ctrls)) {
2679                        ret = C_V4L2_ERROR;
2680                        set_last_error(hDevice, errno);
2681                        goto done;
2682                }
2683        }
2684        else
2685#endif
2686        {
2687                struct v4l2_control v4l2_ctrl = {
2688                        .id             = control->v4l2_control,
2689                        .value  = value->value
2690                };
2691                if(ioctl(v4l2_dev, VIDIOC_S_CTRL, &v4l2_ctrl)) {
2692                        ret = C_V4L2_ERROR;
2693                        set_last_error(hDevice, errno);
2694                }
2695        }
2696
2697#ifdef ENABLE_RAW_CONTROLS
2698done:
2699#endif
2700        //close(v4l2_dev);
2701        return ret;
2702}
2703
2704
2705/**
2706 * Reads the USB information for the given device into the given #CUSBInfo structure.
2707 */
2708static CResult get_device_usb_info (Device *device, CUSBInfo *usbinfo)
2709{
2710        if(device == NULL || usbinfo == NULL)
2711                return C_INVALID_ARG;
2712
2713        // File names in the /sys/class/video4linux/video?/device directory and
2714        // corresponding pointers in the CUSBInfo structure.
2715        char *files[] = {
2716                "idVendor",
2717                "idProduct",
2718                "bcdDevice"
2719        };
2720        unsigned short *fields[] = {
2721                &usbinfo->vendor,
2722                &usbinfo->product,
2723                &usbinfo->release
2724        };
2725
2726        // Read USB information
2727        int i;
2728        for(i = 0; i < 3; i++) {
2729                char *filename = NULL;
2730                if(asprintf(&filename, "/sys/class/video4linux/%s/device/../%s",
2731                                        device->v4l2_name, files[i]) < 0)
2732                        return C_NO_MEMORY;
2733
2734                FILE *input = fopen(filename, "r");
2735                if(input) {
2736                        if(fscanf(input, "%hx", fields[i]) != 1)
2737                                *fields[i] = 0;
2738                        fclose(input);
2739                }
2740
2741                free(filename);
2742        }
2743
2744        return C_SUCCESS;
2745}
2746
2747
2748/*
2749 * Utility functions
2750 */
2751
2752/**
2753 * Converts a FourCC code into a MIME type string.
2754 */
2755static CResult get_mimetype_from_fourcc(char **mimetype, unsigned int fourcc)
2756{
2757        if(mimetype == NULL)
2758                return C_INVALID_ARG;
2759
2760        char *result;
2761        switch(fourcc) {
2762                case MAKE_FOURCC('Y','U','Y','2'):
2763                case MAKE_FOURCC('Y','U','Y','V'):
2764                        result = "video/x-raw-yuv";
2765                        break;
2766                case MAKE_FOURCC('M','J','P','G'):
2767                        result = "image/jpeg";
2768                        break;
2769                default:
2770                        return C_NOT_FOUND;
2771        };
2772
2773        *mimetype = strdup(result);
2774        return C_SUCCESS;
2775}
2776
2777
2778/*
2779 * Handle management
2780 */
2781
2782/**
2783 * Creates a new device handle for the given device.
2784 *
2785 * @return
2786 *              - 0 if there are no free handles left.
2787 *              - A libwebcam handle > 0 on success.
2788 */
2789static CHandle create_handle(Device *device)
2790{
2791        CHandle handle = handle_list.first_free;
2792        int first_free, next_free;
2793        if(device == NULL)
2794                return 0;
2795        if(handle == 0) {
2796                print_libwebcam_error("No free device handles left. Unable to create handle "
2797                                "for device '%s'.", device->v4l2_name);
2798                return 0;
2799        }
2800
2801        if(lock_mutex(&handle_list.mutex))
2802                return C_SYNC_ERROR;
2803
2804        GET_HANDLE(handle).device = device;
2805        GET_HANDLE(handle).open = 1;
2806        device->handles++;
2807
2808        // Look for the next free handle index
2809        first_free = handle_list.first_free;
2810        next_free = first_free;
2811        do {
2812                next_free = (next_free + 1) % MAX_HANDLES;
2813                if(next_free == 0) next_free = 1;
2814
2815                if(!HANDLE_OPEN(next_free)) {
2816                        handle_list.first_free = next_free;
2817                        break;
2818                }
2819        }
2820        while(next_free != first_free);
2821        if(next_free == first_free)
2822                handle_list.first_free = 0;             // No free handles left
2823
2824        unlock_mutex(&handle_list.mutex);
2825        return handle;
2826}
2827
2828
2829/**
2830 * Closes the given handle.
2831 */
2832static void close_handle(CHandle hDevice)
2833{
2834        if(!HANDLE_OPEN(hDevice))
2835                return;
2836
2837        // If the handle is open, close it. If it is also valid, remove the device reference.
2838        if(HANDLE_VALID(hDevice)) {
2839                lock_mutex(&handle_list.mutex);
2840                GET_HANDLE(hDevice).device->handles--;
2841                // Closes device when reference count reaches 0
2842                if (GET_HANDLE(hDevice).device->handles== 0) {
2843                        close (GET_HANDLE(hDevice).device->fd);
2844                        GET_HANDLE(hDevice).device->fd= 0;
2845                }
2846                GET_HANDLE(hDevice).device = NULL;
2847                GET_HANDLE(hDevice).open = 0;
2848                unlock_mutex(&handle_list.mutex);
2849        }
2850        else {
2851                GET_HANDLE(hDevice).open = 0;
2852        }
2853        GET_HANDLE(hDevice).last_system_error = 0;
2854}
2855
2856
2857/**
2858 * Sets the last system error for the given handle.
2859 */
2860static void set_last_error(CHandle hDevice, int error)
2861{
2862        if(HANDLE_OPEN(hDevice))
2863                GET_HANDLE(hDevice).last_system_error = error;
2864}
2865
2866
2867
2868/*
2869 * Initialization and cleanup
2870 */
2871
2872/**
2873 * Initializes libwebcam.
2874 * This method must be called prior to using most of the other methods.
2875 * To release resources allocated during initialization, users should make a call
2876 * to c_cleanup() when the library is no longer used.
2877 */
2878CResult c_init(void)
2879{
2880        CResult ret = C_SUCCESS;
2881
2882        // Don't reinitialize
2883        if(initialized)
2884                return C_SUCCESS;
2885
2886        // Initialize the handle list
2887        memset(&handle_list, 0, sizeof(handle_list));
2888        handle_list.first_free = 1;
2889        if(pthread_mutex_init(&handle_list.mutex, NULL))
2890                return C_INIT_ERROR;
2891
2892        // Initialize the device list
2893        device_list.first = NULL;
2894        if(pthread_mutex_init(&device_list.mutex, NULL))
2895                return C_INIT_ERROR;
2896        device_list.count = 0;
2897        ret = refresh_device_list();
2898
2899        if(ret == C_SUCCESS)
2900                initialized = 1;
2901        return ret;
2902}
2903
2904
2905/**
2906 * Clean up resources.
2907 * This method should be called when the library is no longer used.
2908 */
2909void c_cleanup(void)
2910{
2911        if(!initialized)
2912                return;
2913        initialized = 0;
2914
2915        // Clear the device list
2916        lock_mutex(&device_list.mutex);
2917        invalidate_device_list();
2918        cleanup_device_list();
2919        unlock_mutex(&device_list.mutex);
2920
2921        pthread_mutex_destroy(&device_list.mutex);
2922        pthread_mutex_destroy(&handle_list.mutex);
2923}
2924
2925
2926/**
2927 * Make sure the library resources are cleaned up when the library is unloaded.
2928 */
2929static void __attribute__ ((constructor)) c_unload(void)
2930{
2931        c_cleanup();
2932}
Note: See TracBrowser for help on using the repository browser.