/**
* \file
* Webcam library declarations.
*
* \ingroup libwebcam
*/
/*
* Copyright (c) 2006-2008 Logitech.
*
* This file is part of libwebcam.
*
* libwebcam is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libwebcam is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libwebcam. If not, see .
*/
#ifndef C_LIBWEBCAM_H
#define C_LIBWEBCAM_H
#include
/*
* Features
*/
/// Whether private controls of the Linux UVC driver should be used or not
#define USE_UVCVIDEO
#ifdef USE_UVCVIDEO
/// Whether to compile in support functions for the Linux UVC driver's dynamic
/// controls.
#define ENABLE_UVCVIDEO_DYNCTRL
#ifdef ENABLE_UVCVIDEO_DYNCTRL
/// Whether to include the automatically generated Logitech dynamic controls
/// header file.
#define USE_LOGITECH_DYNCTRL
/// Whether to include support for raw controls.
/// Note that this requires V4L2_CTRL_TYPE_STRING to be available (i.e. V4L2 >= 2.6.32).
/// This is disabled by default but CMake enables it if it finds V4L2_CTRL_TYPE_STRING.
//#define ENABLE_RAW_CONTROLS
#endif
#endif
/*
* Constants
*/
/// Whether to use the V4L2_CTRL_FLAG_NEXT_CTRL flag when enumerating V4L2 controls
#define ENABLE_V4L2_ADVANCED_CONTROL_ENUMERATION
/// Ignore EEXIST errors for the UVCIOC_CTRL_ADD and UVCIOC_CTRL_MAP ioctls for
/// all but the first device. This is required if the driver uses global controls
/// instead of per-device controls.
#define DYNCTRL_IGNORE_EEXIST_AFTER_PASS1
/// The maximum number (plus 1) of handles libwebcam supports
#define MAX_HANDLES 32
/// Debug option to disable locking
#define DISABLE_LOCKING 1
/// Debug option to add verbosity to locking and unlocking
#define DEBUG_LOCKING 1
/// The name used for controls whose name could not be retrieved.
#define UNKNOWN_CONTROL_NAME "Unknown control"
/// Number of retries for failed V4L2 ioctl requests.
/// This is a workaround for faulty devices.
#define CONTROL_IO_ERROR_RETRIES 2
/// Size of a GUID in bytes
#define GUID_SIZE 16
/*
* Macros
*/
/// Returns the given handle structure
#define GET_HANDLE(handle) (handle_list.handles[(handle)])
/// Returns true if the given handle is open (valid or invalid)
#define HANDLE_OPEN(handle) ((handle) < MAX_HANDLES && GET_HANDLE(handle).open)
/// Returns true if the given handle is open and valid
#define HANDLE_VALID(handle) (HANDLE_OPEN(handle) && GET_HANDLE(handle).device)
/// Returns the maximum number of characters that a menu-type control choice
/// can have in V4L2.
#define V4L2_MENU_CTRL_MAX_NAME_SIZE sizeof(((struct v4l2_querymenu *)NULL)->name)
/// Converts the given characters into a FourCC code
#define MAKE_FOURCC(c1,c2,c3,c4) \
(unsigned int)((long)c1 | (long)c2 << 8 | (long)c3 << 16 | (long)c4 << 24)
/// Format string to print a GUID byte array with printf
#define GUID_FORMAT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
/// Argument macro to print a GUID byte array with printf
#define GUID_ARGS(guid) \
(guid)[3], (guid)[2], (guid)[1], (guid)[0], \
(guid)[5], (guid)[4], \
(guid)[7], (guid)[6], \
(guid)[8], (guid)[9], \
(guid)[10], (guid)[11], (guid)[12], \
(guid)[13], (guid)[14], (guid)[15]
/*
* Structures
*/
/**
* An internal control description associated with a device.
*/
typedef struct _Control {
/// Control description
CControl control;
/// V4L2 ioctl mapping (non-0 for V4L2 controls)
int v4l2_control;
/// Pointer to the next control in the list
struct _Control * next;
} Control;
/**
* Base structure that contains a list of controls and associated data.
*/
typedef struct _ControlList {
/// The first control in the list
Control * first;
/// The last control in the list
Control * last;
/// The mutex used to serialize access to the control list
pthread_mutex_t mutex;
/// The number of controls contained in the list
int count;
} ControlList;
/**
* Internal device information.
*/
typedef struct _Device {
/// Device information
CDevice device;
/// Short V4L2 device name (e.g. 'video0')
char v4l2_name[NAME_MAX];
/// Number of handles associated with this device
int handles;
/// List of controls supported by this device
ControlList controls;
/// Boolean whether the device is still valid, i.e. exists in the system.
/// Devices marked as invalid will be cleared out by cleanup_device_list().
int valid;
/// File descriptor returned by open
int fd;
/// Next device in the global device list
struct _Device * next;
} Device;
/**
* Base structure that contains a list of devices and associated data.
*/
typedef struct _DeviceList {
/// The first device in the list
Device * first;
/// The mutex used to serialize access to the device list
pthread_mutex_t mutex;
/// The number of devices contained in the list
int count;
} DeviceList;
/**
* Information associated with a device handle.
*
* Note that a handle can have three different states:
* - Closed/free: The device handle is not being used by an application.
* - Valid: The device handle is open by an application and points to a valid device.
* - Invalid: The device handle is open by an application but does not point to a
* (valid) device anymore. This happens when a device is removed from the system
* but there are still open handles around.
* An "open" handle can be both valid or invalid.
*/
typedef struct _Handle {
/// Pointer to the device structure associated with this handle
Device * device;
/// True if the handle is open (valid or invalid)
int open;
/// The number of the last system error (e.g. a V4L2 return value)
int last_system_error;
} Handle;
/**
* Base structure that contains an array of device handles and associated data.
*/
typedef struct _HandleList {
/// The array of handles
Handle handles[MAX_HANDLES];
/// The mutex used to serialize access to the handle list
pthread_mutex_t mutex;
/// The index of the first free handle.
/// Zero if there are now free handles at this time.
int first_free;
} HandleList;
/*
* Globals
*/
extern int initialized;
extern HandleList handle_list;
extern void print_error (char *format, ...);
extern int open_v4l2_device(char *device_name);
/*
* Helper functions
*/
/**
* Acquire a mutex.
*
* This function is identical to pthread_mutex_lock except that it has different
* return values and supports some debug flags.
*
* @return
* C_SUCCESS if the mutex was successfully acquired
* C_SYNC_ERROR if an error occured while trying to acquire the mutex
*/
static inline CResult lock_mutex (pthread_mutex_t *mutex)
{
#ifndef DISABLE_LOCKING
#ifdef DEBUG_LOCKING
fprintf(stderr, "Acquiring mutex 0x%08x ...\n", (unsigned int)mutex);
#endif
int ret = pthread_mutex_lock(mutex);
#ifdef DEBUG_LOCKING
fprintf(stderr, "Acquisition of mutex 0x%08x %s.\n", (unsigned int)mutex,
ret ? "failed" : "successful");
#endif
assert(ret == 0);
return ret ? C_SYNC_ERROR : C_SUCCESS;
#else
return C_SUCCESS;
#endif
}
/**
* Release a mutex.
*
* This function is identical to pthread_mutex_unlock except that it has different
* return values and supports some debug flags.
*
* @return
* C_SUCCESS if the mutex was successfully released
* C_SYNC_ERROR if an error occured while trying to release the mutex
*/
static inline void unlock_mutex (pthread_mutex_t *mutex)
{
#ifndef DISABLE_LOCKING
#ifdef DEBUG_LOCKING
fprintf(stderr, "Releasing mutex 0x%08x ...\n", (unsigned int)mutex);
#endif
int ret = pthread_mutex_unlock(mutex);
#ifdef DEBUG_LOCKING
fprintf(stderr, "Release of mutex 0x%08x %s.\n", (unsigned int)mutex,
ret ? "failed" : "successful");
#endif
assert(ret == 0);
#endif
}
/**
* Copies a variable-length string to the part of an enumeration buffer that is
* reserved for dynamic data.
*
* This function is used by the enumeration functions.
*/
static inline void copy_string_to_buffer (char **target, char *source, void *buffer, unsigned int *offset)
{
unsigned int length = strlen(source);
*target = (char *)buffer + *offset;
memcpy(*target, source, length + 1);
*offset += length + 1;
}
#endif /* C_LIBWEBCAM_H */