SDL_VideoCapture: allow add/remove device at runtime on linux
parent
f0e47f8ee0
commit
6bb40f1d8d
|
@ -53,6 +53,7 @@ typedef enum
|
||||||
SDL_UDEV_DEVICE_ACCELEROMETER = 0x0020,
|
SDL_UDEV_DEVICE_ACCELEROMETER = 0x0020,
|
||||||
SDL_UDEV_DEVICE_TOUCHPAD = 0x0040,
|
SDL_UDEV_DEVICE_TOUCHPAD = 0x0040,
|
||||||
SDL_UDEV_DEVICE_HAS_KEYS = 0x0080,
|
SDL_UDEV_DEVICE_HAS_KEYS = 0x0080,
|
||||||
|
SDL_UDEV_DEVICE_VIDEO_CAPTURE = 0x0100,
|
||||||
} SDL_UDEV_deviceclass;
|
} SDL_UDEV_deviceclass;
|
||||||
|
|
||||||
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
||||||
|
|
|
@ -139,6 +139,7 @@ int SDL_UDEV_Init(void)
|
||||||
|
|
||||||
_this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL);
|
_this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL);
|
||||||
_this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL);
|
_this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL);
|
||||||
|
_this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "video4linux", NULL);
|
||||||
_this->syms.udev_monitor_enable_receiving(_this->udev_mon);
|
_this->syms.udev_monitor_enable_receiving(_this->udev_mon);
|
||||||
|
|
||||||
/* Do an initial scan of existing devices */
|
/* Do an initial scan of existing devices */
|
||||||
|
@ -200,6 +201,7 @@ int SDL_UDEV_Scan(void)
|
||||||
|
|
||||||
_this->syms.udev_enumerate_add_match_subsystem(enumerate, "input");
|
_this->syms.udev_enumerate_add_match_subsystem(enumerate, "input");
|
||||||
_this->syms.udev_enumerate_add_match_subsystem(enumerate, "sound");
|
_this->syms.udev_enumerate_add_match_subsystem(enumerate, "sound");
|
||||||
|
_this->syms.udev_enumerate_add_match_subsystem(enumerate, "video4linux");
|
||||||
|
|
||||||
_this->syms.udev_enumerate_scan_devices(enumerate);
|
_this->syms.udev_enumerate_scan_devices(enumerate);
|
||||||
devs = _this->syms.udev_enumerate_get_list_entry(enumerate);
|
devs = _this->syms.udev_enumerate_get_list_entry(enumerate);
|
||||||
|
@ -405,8 +407,16 @@ static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
subsystem = _this->syms.udev_device_get_subsystem(dev);
|
subsystem = _this->syms.udev_device_get_subsystem(dev);
|
||||||
|
|
||||||
if (SDL_strcmp(subsystem, "sound") == 0) {
|
if (SDL_strcmp(subsystem, "sound") == 0) {
|
||||||
devclass = SDL_UDEV_DEVICE_SOUND;
|
devclass = SDL_UDEV_DEVICE_SOUND;
|
||||||
|
} else if (SDL_strcmp(subsystem, "video4linux") == 0) {
|
||||||
|
devclass = SDL_UDEV_DEVICE_VIDEO_CAPTURE;
|
||||||
|
|
||||||
|
val = _this->syms.udev_device_get_property_value(dev, "ID_V4L_CAPABILITIES");
|
||||||
|
if (!val || !SDL_strcasestr(val, "capture")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else if (SDL_strcmp(subsystem, "input") == 0) {
|
} else if (SDL_strcmp(subsystem, "input") == 0) {
|
||||||
/* udev rules reference: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c */
|
/* udev rules reference: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c */
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,9 @@ struct SDL_VideoCaptureDevice
|
||||||
struct SDL_PrivateVideoCaptureData *hidden;
|
struct SDL_PrivateVideoCaptureData *hidden;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern int SDL_SYS_VideoCaptureInit(void);
|
||||||
|
extern int SDL_SYS_VideoCaptureQuit(void);
|
||||||
|
|
||||||
extern int OpenDevice(SDL_VideoCaptureDevice *_this);
|
extern int OpenDevice(SDL_VideoCaptureDevice *_this);
|
||||||
extern void CloseDevice(SDL_VideoCaptureDevice *_this);
|
extern void CloseDevice(SDL_VideoCaptureDevice *_this);
|
||||||
|
|
||||||
|
@ -80,9 +83,8 @@ extern int GetFormat(SDL_VideoCaptureDevice *_this, int index, Uint32 *format);
|
||||||
extern int GetNumFrameSizes(SDL_VideoCaptureDevice *_this, Uint32 format);
|
extern int GetNumFrameSizes(SDL_VideoCaptureDevice *_this, Uint32 format);
|
||||||
extern int GetFrameSize(SDL_VideoCaptureDevice *_this, Uint32 format, int index, int *width, int *height);
|
extern int GetFrameSize(SDL_VideoCaptureDevice *_this, Uint32 format, int index, int *width, int *height);
|
||||||
|
|
||||||
extern int GetDeviceName(int index, char *buf, int size);
|
extern int GetDeviceName(SDL_VideoCaptureDeviceID instance_id, char *buf, int size);
|
||||||
extern int GetNumDevices(void);
|
extern SDL_VideoCaptureDeviceID *GetVideoCaptureDevices(int *count);
|
||||||
|
|
||||||
|
|
||||||
extern SDL_bool check_all_device_closed(void);
|
extern SDL_bool check_all_device_closed(void);
|
||||||
extern SDL_bool check_device_playing(void);
|
extern SDL_bool check_device_playing(void);
|
||||||
|
|
|
@ -311,7 +311,6 @@ const char *
|
||||||
SDL_GetVideoCaptureDeviceName(SDL_VideoCaptureDeviceID instance_id)
|
SDL_GetVideoCaptureDeviceName(SDL_VideoCaptureDeviceID instance_id)
|
||||||
{
|
{
|
||||||
#ifdef SDL_VIDEO_CAPTURE
|
#ifdef SDL_VIDEO_CAPTURE
|
||||||
int index = instance_id - 1;
|
|
||||||
static char buf[256];
|
static char buf[256];
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
buf[255] = 0;
|
buf[255] = 0;
|
||||||
|
@ -321,7 +320,7 @@ SDL_GetVideoCaptureDeviceName(SDL_VideoCaptureDeviceID instance_id)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetDeviceName(index, buf, sizeof (buf)) < 0) {
|
if (GetDeviceName(instance_id, buf, sizeof (buf)) < 0) {
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
|
@ -336,14 +335,21 @@ SDL_VideoCaptureDeviceID *
|
||||||
SDL_GetVideoCaptureDevices(int *count)
|
SDL_GetVideoCaptureDevices(int *count)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i;
|
|
||||||
#ifdef SDL_VIDEO_CAPTURE
|
|
||||||
int num = GetNumDevices();
|
|
||||||
#else
|
|
||||||
int num = 0;
|
int num = 0;
|
||||||
|
SDL_VideoCaptureDeviceID *ret = NULL;
|
||||||
|
#ifdef SDL_VIDEO_CAPTURE
|
||||||
|
ret = GetVideoCaptureDevices(&num);
|
||||||
#endif
|
#endif
|
||||||
SDL_VideoCaptureDeviceID *ret;
|
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
if (count) {
|
||||||
|
*count = num;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return list of 0 ID, null terminated */
|
||||||
|
num = 0;
|
||||||
ret = (SDL_VideoCaptureDeviceID *)SDL_malloc((num + 1) * sizeof(*ret));
|
ret = (SDL_VideoCaptureDeviceID *)SDL_malloc((num + 1) * sizeof(*ret));
|
||||||
|
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
|
@ -354,11 +360,7 @@ SDL_GetVideoCaptureDevices(int *count)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
ret[i] = i + 1;
|
|
||||||
}
|
|
||||||
ret[num] = 0;
|
ret[num] = 0;
|
||||||
|
|
||||||
if (count) {
|
if (count) {
|
||||||
*count = num;
|
*count = num;
|
||||||
}
|
}
|
||||||
|
@ -501,6 +503,8 @@ SDL_OpenVideoCapture(SDL_VideoCaptureDeviceID instance_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// FIXME do we need this ?
|
||||||
/* Let the user override. */
|
/* Let the user override. */
|
||||||
{
|
{
|
||||||
const char *dev = SDL_getenv("SDL_VIDEO_CAPTURE_DEVICE_NAME");
|
const char *dev = SDL_getenv("SDL_VIDEO_CAPTURE_DEVICE_NAME");
|
||||||
|
@ -508,6 +512,7 @@ SDL_OpenVideoCapture(SDL_VideoCaptureDeviceID instance_id)
|
||||||
device_name = dev;
|
device_name = dev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (device_name == NULL) {
|
if (device_name == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -823,6 +828,8 @@ SDL_VideoCaptureInit(void)
|
||||||
{
|
{
|
||||||
#ifdef SDL_VIDEO_CAPTURE
|
#ifdef SDL_VIDEO_CAPTURE
|
||||||
SDL_zeroa(open_devices);
|
SDL_zeroa(open_devices);
|
||||||
|
|
||||||
|
SDL_SYS_VideoCaptureInit();
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -839,6 +846,8 @@ SDL_QuitVideoCapture(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_zeroa(open_devices);
|
SDL_zeroa(open_devices);
|
||||||
|
|
||||||
|
SDL_SYS_VideoCaptureQuit();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,6 +866,16 @@ SDL_QuitVideoCapture(void)
|
||||||
/* See SDL_video_capture_apple.m */
|
/* See SDL_video_capture_apple.m */
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
int SDL_SYS_VideoCaptureInit(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_SYS_VideoCaptureQuit(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
OpenDevice(SDL_VideoCaptureDevice *_this)
|
OpenDevice(SDL_VideoCaptureDevice *_this)
|
||||||
{
|
{
|
||||||
|
@ -933,16 +952,17 @@ GetFrameSize(SDL_VideoCaptureDevice *_this, Uint32 format, int index, int *width
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
GetDeviceName(int index, char *buf, int size)
|
GetDeviceName(SDL_VideoCaptureDeviceID instance_id, char *buf, int size)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
SDL_VideoCaptureDeviceID *
|
||||||
GetNumDevices(void)
|
GetVideoCaptureDevices(int *count)
|
||||||
{
|
{
|
||||||
return -1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* SDL_VIDEO_CAPTURE */
|
#endif /* SDL_VIDEO_CAPTURE */
|
||||||
|
|
|
@ -49,7 +49,7 @@ int AcquireFrame(SDL_VideoCaptureDevice *_this, SDL_VideoCaptureFrame *frame) {
|
||||||
}
|
}
|
||||||
void CloseDevice(SDL_VideoCaptureDevice *_this) {
|
void CloseDevice(SDL_VideoCaptureDevice *_this) {
|
||||||
}
|
}
|
||||||
int GetDeviceName(int index, char *buf, int size) {
|
int GetDeviceName(SDL_VideoCaptureDeviceID instance_id, char *buf, int size) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int GetDeviceSpec(SDL_VideoCaptureDevice *_this, SDL_VideoCaptureSpec *spec) {
|
int GetDeviceSpec(SDL_VideoCaptureDevice *_this, SDL_VideoCaptureSpec *spec) {
|
||||||
|
@ -61,8 +61,8 @@ int GetFormat(SDL_VideoCaptureDevice *_this, int index, Uint32 *format) {
|
||||||
int GetFrameSize(SDL_VideoCaptureDevice *_this, Uint32 format, int index, int *width, int *height) {
|
int GetFrameSize(SDL_VideoCaptureDevice *_this, Uint32 format, int index, int *width, int *height) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int GetNumDevices(void) {
|
SDL_VideoCaptureDeviceID *GetVideoCaptureDevices(int *count) {
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
int GetNumFormats(SDL_VideoCaptureDevice *_this) {
|
int GetNumFormats(SDL_VideoCaptureDevice *_this) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -79,6 +79,13 @@ int StartCapture(SDL_VideoCaptureDevice *_this) {
|
||||||
int StopCapture(SDL_VideoCaptureDevice *_this) {
|
int StopCapture(SDL_VideoCaptureDevice *_this) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int SDL_SYS_VideoCaptureInit(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int SDL_SYS_VideoCaptureQuit(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -589,8 +596,9 @@ GetFrameSize(SDL_VideoCaptureDevice *_this, Uint32 format, int index, int *width
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
GetDeviceName(int index, char *buf, int size)
|
GetDeviceName(SDL_VideoCaptureDeviceID instance_id, char *buf, int size)
|
||||||
{
|
{
|
||||||
|
int index = instance_id - 1;
|
||||||
NSArray<AVCaptureDevice *> *devices = discover_devices();
|
NSArray<AVCaptureDevice *> *devices = discover_devices();
|
||||||
if (index < [devices count]) {
|
if (index < [devices count]) {
|
||||||
AVCaptureDevice *device = devices[index];
|
AVCaptureDevice *device = devices[index];
|
||||||
|
@ -602,13 +610,49 @@ GetDeviceName(int index, char *buf, int size)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
GetNumDevices(void)
|
GetNumDevices(void)
|
||||||
{
|
{
|
||||||
NSArray<AVCaptureDevice *> *devices = discover_devices();
|
NSArray<AVCaptureDevice *> *devices = discover_devices();
|
||||||
return [devices count];
|
return [devices count];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_VideoCaptureDeviceID *GetVideoCaptureDevices(int *count)
|
||||||
|
{
|
||||||
|
/* hard-coded list of ID */
|
||||||
|
int i;
|
||||||
|
int num = GetNumDevices();
|
||||||
|
SDL_VideoCaptureDeviceID *ret;
|
||||||
|
|
||||||
|
ret = (SDL_VideoCaptureDeviceID *)SDL_malloc((num + 1) * sizeof(*ret));
|
||||||
|
|
||||||
|
if (ret == NULL) {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
*count = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
ret[i] = i + 1;
|
||||||
|
}
|
||||||
|
ret[num] = 0;
|
||||||
|
*count = num;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_SYS_VideoCaptureInit(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_SYS_VideoCaptureQuit(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* HAVE_COREMEDIA */
|
#endif /* HAVE_COREMEDIA */
|
||||||
|
|
||||||
#endif /* SDL_VIDEO_CAPTURE */
|
#endif /* SDL_VIDEO_CAPTURE */
|
||||||
|
|
|
@ -28,11 +28,41 @@
|
||||||
#include "SDL_video_capture_c.h"
|
#include "SDL_video_capture_c.h"
|
||||||
#include "SDL_pixels_c.h"
|
#include "SDL_pixels_c.h"
|
||||||
#include "../thread/SDL_systhread.h"
|
#include "../thread/SDL_systhread.h"
|
||||||
|
#include "../../core/linux/SDL_evdev_capabilities.h"
|
||||||
|
#include "../../core/linux/SDL_udev.h"
|
||||||
|
#include <limits.h> /* INT_MAX */
|
||||||
|
|
||||||
#define DEBUG_VIDEO_CAPTURE_CAPTURE 1
|
#define DEBUG_VIDEO_CAPTURE_CAPTURE 1
|
||||||
|
|
||||||
#if defined(__linux__) && !defined(__ANDROID__)
|
#if defined(__linux__) && !defined(__ANDROID__)
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_CAPTURE_DEVICES 128 /* It's doubtful someone has more than that */
|
||||||
|
|
||||||
|
static int MaybeAddDevice(const char *path);
|
||||||
|
#ifdef SDL_USE_LIBUDEV
|
||||||
|
static int MaybeRemoveDevice(const char *path);
|
||||||
|
static void capture_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
|
||||||
|
#endif /* SDL_USE_LIBUDEV */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List of available capture devices.
|
||||||
|
*/
|
||||||
|
typedef struct SDL_capturelist_item
|
||||||
|
{
|
||||||
|
char *fname; /* Dev path name (like /dev/video0) */
|
||||||
|
char *bus_info; /* don't add two paths with same bus_info (eg /dev/video0 and /dev/video1 */
|
||||||
|
SDL_VideoCaptureDeviceID instance_id;
|
||||||
|
SDL_VideoCaptureDevice *device; /* Associated device */
|
||||||
|
struct SDL_capturelist_item *next;
|
||||||
|
} SDL_capturelist_item;
|
||||||
|
|
||||||
|
static SDL_capturelist_item *SDL_capturelist = NULL;
|
||||||
|
static SDL_capturelist_item *SDL_capturelist_tail = NULL;
|
||||||
|
static int num_video_captures = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum io_method {
|
enum io_method {
|
||||||
IO_METHOD_READ,
|
IO_METHOD_READ,
|
||||||
IO_METHOD_MMAP,
|
IO_METHOD_MMAP,
|
||||||
|
@ -933,33 +963,253 @@ OpenDevice(SDL_VideoCaptureDevice *_this)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
GetDeviceName(int index, char *buf, int size) {
|
GetDeviceName(SDL_VideoCaptureDeviceID instance_id, char *buf, int size)
|
||||||
SDL_snprintf(buf, size, "/dev/video%d", index);
|
{
|
||||||
|
SDL_capturelist_item *item;
|
||||||
|
for (item = SDL_capturelist; item; item = item->next) {
|
||||||
|
if (item->instance_id == instance_id) {
|
||||||
|
SDL_snprintf(buf, size, "%s", item->fname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unknown instance_id */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SDL_VideoCaptureDeviceID *GetVideoCaptureDevices(int *count)
|
||||||
|
{
|
||||||
|
/* real list of ID */
|
||||||
|
int i = 0;
|
||||||
|
int num = num_video_captures;
|
||||||
|
SDL_VideoCaptureDeviceID *ret;
|
||||||
|
SDL_capturelist_item *item;
|
||||||
|
|
||||||
|
ret = (SDL_VideoCaptureDeviceID *)SDL_malloc((num + 1) * sizeof(*ret));
|
||||||
|
|
||||||
|
if (ret == NULL) {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
*count = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (item = SDL_capturelist; item; item = item->next) {
|
||||||
|
ret[i] = item->instance_id;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[num] = 0;
|
||||||
|
*count = num;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes the subsystem by finding available devices.
|
||||||
|
*/
|
||||||
|
int SDL_SYS_VideoCaptureInit(void)
|
||||||
|
{
|
||||||
|
const char pattern[] = "/dev/video%d";
|
||||||
|
char path[PATH_MAX];
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limit amount of checks to MAX_CAPTURE_DEVICES since we may or may not have
|
||||||
|
* permission to some or all devices.
|
||||||
|
*/
|
||||||
|
i = 0;
|
||||||
|
for (j = 0; j < MAX_CAPTURE_DEVICES; ++j) {
|
||||||
|
(void)SDL_snprintf(path, PATH_MAX, pattern, i++);
|
||||||
|
if (MaybeAddDevice(path) == -2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SDL_USE_LIBUDEV
|
||||||
|
if (SDL_UDEV_Init() < 0) {
|
||||||
|
return SDL_SetError("Could not initialize UDEV");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_UDEV_AddCallback(capture_udev_callback) < 0) {
|
||||||
|
SDL_UDEV_Quit();
|
||||||
|
return SDL_SetError("Could not setup Video Capture <-> udev callback");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force a scan to build the initial device list */
|
||||||
|
SDL_UDEV_Scan();
|
||||||
|
#endif /* SDL_USE_LIBUDEV */
|
||||||
|
|
||||||
|
return num_video_captures;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int SDL_SYS_VideoCaptureQuit(void)
|
||||||
|
{
|
||||||
|
SDL_capturelist_item *item;
|
||||||
|
for (item = SDL_capturelist; item; ) {
|
||||||
|
SDL_capturelist_item *tmp = item->next;
|
||||||
|
|
||||||
|
SDL_free(item->fname);
|
||||||
|
SDL_free(item->bus_info);
|
||||||
|
SDL_free(item);
|
||||||
|
item = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_video_captures = 0;
|
||||||
|
SDL_capturelist = NULL;
|
||||||
|
SDL_capturelist_tail = NULL;
|
||||||
|
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SDL_USE_LIBUDEV
|
||||||
|
static void capture_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
|
||||||
|
{
|
||||||
|
if (!devpath || !(udev_class & SDL_UDEV_DEVICE_VIDEO_CAPTURE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (udev_type) {
|
||||||
|
case SDL_UDEV_DEVICEADDED:
|
||||||
|
MaybeAddDevice(devpath);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_UDEV_DEVICEREMOVED:
|
||||||
|
MaybeRemoveDevice(devpath);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* SDL_USE_LIBUDEV */
|
||||||
|
|
||||||
|
static SDL_bool DeviceExists(const char *path, const char *bus_info) {
|
||||||
|
SDL_capturelist_item *item;
|
||||||
|
|
||||||
|
for (item = SDL_capturelist; item; item = item->next) {
|
||||||
|
/* found same dev name */
|
||||||
|
if (SDL_strcmp(path, item->fname) == 0) {
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
/* found same bus_info */
|
||||||
|
if (SDL_strcmp(bus_info, item->bus_info) == 0) {
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int MaybeAddDevice(const char *path)
|
||||||
|
{
|
||||||
|
char *bus_info = NULL;
|
||||||
|
struct v4l2_capability vcap;
|
||||||
|
int err;
|
||||||
|
int fd;
|
||||||
|
SDL_capturelist_item *item;
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(path, O_RDWR);
|
||||||
|
if (fd < 0) {
|
||||||
|
return -2; /* stop iterating /dev/video%d */
|
||||||
|
}
|
||||||
|
err = ioctl(fd, VIDIOC_QUERYCAP, &vcap);
|
||||||
|
close(fd);
|
||||||
|
if (err) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bus_info = SDL_strdup((char *)vcap.bus_info);
|
||||||
|
|
||||||
|
if (DeviceExists(path, bus_info)) {
|
||||||
|
SDL_free(bus_info);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
GetNumDevices(void) {
|
/* Add new item */
|
||||||
int num;
|
item = (SDL_capturelist_item *)SDL_calloc(1, sizeof(SDL_capturelist_item));
|
||||||
for (num = 0; num < 128; num++) {
|
if (!item) {
|
||||||
static char buf[256];
|
SDL_free(bus_info);
|
||||||
buf[0] = 0;
|
return -1;
|
||||||
buf[255] = 0;
|
|
||||||
GetDeviceName(num, buf, sizeof (buf));
|
|
||||||
SDL_RWops *src = SDL_RWFromFile(buf, "rb");
|
|
||||||
if (src == NULL) {
|
|
||||||
// When file does not exist, an error is set. Clear it.
|
|
||||||
SDL_ClearError();
|
|
||||||
return num;
|
|
||||||
}
|
}
|
||||||
SDL_RWclose(src);
|
|
||||||
|
item->fname = SDL_strdup(path);
|
||||||
|
if (!item->fname) {
|
||||||
|
SDL_free(item);
|
||||||
|
SDL_free(bus_info);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
return num;
|
|
||||||
|
item->fname = SDL_strdup(path);
|
||||||
|
item->bus_info = bus_info;
|
||||||
|
item->instance_id = SDL_GetNextObjectID();
|
||||||
|
|
||||||
|
|
||||||
|
if (!SDL_capturelist_tail) {
|
||||||
|
SDL_capturelist = SDL_capturelist_tail = item;
|
||||||
|
} else {
|
||||||
|
SDL_capturelist_tail->next = item;
|
||||||
|
SDL_capturelist_tail = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++num_video_captures;
|
||||||
|
|
||||||
|
/* !!! TODO: Send a add event? */
|
||||||
|
#if DEBUG_VIDEO_CAPTURE_CAPTURE
|
||||||
|
SDL_Log("Added video capture ID: %d %s (%s) (total: %d)", item->instance_id, path, bus_info, num_video_captures);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SDL_USE_LIBUDEV
|
||||||
|
static int MaybeRemoveDevice(const char *path)
|
||||||
|
{
|
||||||
|
|
||||||
|
SDL_capturelist_item *item;
|
||||||
|
SDL_capturelist_item *prev = NULL;
|
||||||
|
#if DEBUG_VIDEO_CAPTURE_CAPTURE
|
||||||
|
SDL_Log("Remove video capture %s", path);
|
||||||
|
#endif
|
||||||
|
if (!path) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (item = SDL_capturelist; item; item = item->next) {
|
||||||
|
/* found it, remove it. */
|
||||||
|
if (SDL_strcmp(path, item->fname) == 0) {
|
||||||
|
if (prev) {
|
||||||
|
prev->next = item->next;
|
||||||
|
} else {
|
||||||
|
SDL_assert(SDL_capturelist == item);
|
||||||
|
SDL_capturelist = item->next;
|
||||||
|
}
|
||||||
|
if (item == SDL_capturelist_tail) {
|
||||||
|
SDL_capturelist_tail = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to decrement the count */
|
||||||
|
--num_video_captures;
|
||||||
|
/* !!! TODO: Send a remove event? */
|
||||||
|
|
||||||
|
SDL_free(item->fname);
|
||||||
|
SDL_free(item->bus_info);
|
||||||
|
SDL_free(item);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
prev = item;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* SDL_USE_LIBUDEV */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* SDL_VIDEO_CAPTURE */
|
#endif /* SDL_VIDEO_CAPTURE */
|
||||||
|
|
|
@ -633,9 +633,12 @@ GetFrameSize(SDL_VideoCaptureDevice *_this, Uint32 format, int index, int *width
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int GetNumDevices(void);
|
||||||
|
|
||||||
int
|
int
|
||||||
GetDeviceName(int index, char *buf, int size)
|
GetDeviceName(SDL_VideoCaptureDeviceID instance_id, char *buf, int size)
|
||||||
{
|
{
|
||||||
|
int index = instance_id - 1;
|
||||||
create_cameraMgr();
|
create_cameraMgr();
|
||||||
|
|
||||||
if (cameraIdList == NULL) {
|
if (cameraIdList == NULL) {
|
||||||
|
@ -652,7 +655,7 @@ GetDeviceName(int index, char *buf, int size)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
GetNumDevices(void)
|
GetNumDevices(void)
|
||||||
{
|
{
|
||||||
camera_status_t res;
|
camera_status_t res;
|
||||||
|
@ -673,6 +676,38 @@ GetNumDevices(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_VideoCaptureDeviceID *GetVideoCaptureDevices(int *count)
|
||||||
|
{
|
||||||
|
/* hard-coded list of ID */
|
||||||
|
int i;
|
||||||
|
int num = GetNumDevices();
|
||||||
|
SDL_VideoCaptureDeviceID *ret;
|
||||||
|
|
||||||
|
ret = (SDL_VideoCaptureDeviceID *)SDL_malloc((num + 1) * sizeof(*ret));
|
||||||
|
|
||||||
|
if (ret == NULL) {
|
||||||
|
SDL_OutOfMemory();
|
||||||
|
*count = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
ret[i] = i + 1;
|
||||||
|
}
|
||||||
|
ret[num] = 0;
|
||||||
|
*count = num;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_SYS_VideoCaptureInit(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_SYS_VideoCaptureQuit(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,7 @@ static SDL_VideoCaptureDeviceID get_instance_id(int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
SDL_Log("invalid index");
|
/* SDL_Log("invalid index"); */
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -212,7 +212,7 @@ int main(int argc, char **argv)
|
||||||
SDL_Log("%s", usage);
|
SDL_Log("%s", usage);
|
||||||
|
|
||||||
/* Load the SDL library */
|
/* Load the SDL library */
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { /* FIXME: SDL_INIT_JOYSTICK needed for add/removing devices at runtime */
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -439,7 +439,7 @@ int main(int argc, char **argv)
|
||||||
SAVE_CAPTURE_STATE(current_dev);
|
SAVE_CAPTURE_STATE(current_dev);
|
||||||
|
|
||||||
current_dev += 1;
|
current_dev += 1;
|
||||||
if (current_dev == num || current_dev >= (int) SDL_arraysize(data_capture_tab)) {
|
if (current_dev >= num || current_dev >= (int) SDL_arraysize(data_capture_tab)) {
|
||||||
current_dev = 0;
|
current_dev = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ int main(int argc, char **argv)
|
||||||
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
|
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
|
||||||
|
|
||||||
/* Load the SDL library */
|
/* Load the SDL library */
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { /* FIXME: SDL_INIT_JOYSTICK needed for add/removing devices at runtime */
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue