mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-23 11:38:28 +00:00
camera: Reworked to operate with a driver interface, like other subsystems.
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_CAMERA_V4L2
|
||||
#ifdef SDL_CAMERA_DRIVER_V4L2
|
||||
|
||||
#include "../SDL_syscamera.h"
|
||||
#include "../SDL_camera_c.h"
|
||||
@@ -30,8 +30,6 @@
|
||||
#include "../../core/linux/SDL_udev.h"
|
||||
#include <limits.h> // INT_MAX
|
||||
|
||||
#define DEBUG_CAMERA 1
|
||||
|
||||
#define MAX_CAMERA_DEVICES 128 // It's doubtful someone has more than that
|
||||
|
||||
static int MaybeAddDevice(const char *path);
|
||||
@@ -206,7 +204,7 @@ static int acquire_frame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||
}
|
||||
|
||||
|
||||
int ReleaseFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||
static int V4L2_ReleaseFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
const int fd = _this->hidden->fd;
|
||||
@@ -259,8 +257,7 @@ int ReleaseFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||
static int V4L2_AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
@@ -310,7 +307,7 @@ int AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||
}
|
||||
|
||||
|
||||
int StopCamera(SDL_CameraDevice *_this)
|
||||
static int V4L2_StopCamera(SDL_CameraDevice *_this)
|
||||
{
|
||||
enum v4l2_buf_type type;
|
||||
const int fd = _this->hidden->fd;
|
||||
@@ -428,7 +425,7 @@ static int PreEnqueueBuffers(SDL_CameraDevice *_this)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int StartCamera(SDL_CameraDevice *_this)
|
||||
static int V4L2_StartCamera(SDL_CameraDevice *_this)
|
||||
{
|
||||
enum v4l2_buf_type type;
|
||||
|
||||
@@ -476,15 +473,10 @@ static int AllocBufferRead(SDL_CameraDevice *_this, size_t buffer_size)
|
||||
{
|
||||
_this->hidden->buffers[0].length = buffer_size;
|
||||
_this->hidden->buffers[0].start = SDL_calloc(1, buffer_size);
|
||||
|
||||
if (!_this->hidden->buffers[0].start) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
return 0;
|
||||
return _this->hidden->buffers[0].start ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
AllocBufferMmap(SDL_CameraDevice *_this)
|
||||
static int AllocBufferMmap(SDL_CameraDevice *_this)
|
||||
{
|
||||
int fd = _this->hidden->fd;
|
||||
int i;
|
||||
@@ -516,8 +508,7 @@ AllocBufferMmap(SDL_CameraDevice *_this)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
AllocBufferUserPtr(SDL_CameraDevice *_this, size_t buffer_size)
|
||||
static int AllocBufferUserPtr(SDL_CameraDevice *_this, size_t buffer_size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < _this->hidden->nb_buffers; ++i) {
|
||||
@@ -525,41 +516,38 @@ AllocBufferUserPtr(SDL_CameraDevice *_this, size_t buffer_size)
|
||||
_this->hidden->buffers[i].start = SDL_calloc(1, buffer_size);
|
||||
|
||||
if (!_this->hidden->buffers[i].start) {
|
||||
return SDL_OutOfMemory();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint32
|
||||
format_v4l2_2_sdl(Uint32 fmt)
|
||||
static Uint32 format_v4l2_to_sdl(Uint32 fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
#define CASE(x, y) case x: return y
|
||||
#define CASE(x, y) case x: return y
|
||||
CASE(V4L2_PIX_FMT_YUYV, SDL_PIXELFORMAT_YUY2);
|
||||
CASE(V4L2_PIX_FMT_MJPEG, SDL_PIXELFORMAT_UNKNOWN);
|
||||
#undef CASE
|
||||
#undef CASE
|
||||
default:
|
||||
SDL_Log("Unknown format V4L2_PIX_FORMAT '%d'", fmt);
|
||||
return SDL_PIXELFORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static Uint32
|
||||
format_sdl_2_v4l2(Uint32 fmt)
|
||||
static Uint32 format_sdl_to_v4l2(Uint32 fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
#define CASE(y, x) case x: return y
|
||||
#define CASE(y, x) case x: return y
|
||||
CASE(V4L2_PIX_FMT_YUYV, SDL_PIXELFORMAT_YUY2);
|
||||
CASE(V4L2_PIX_FMT_MJPEG, SDL_PIXELFORMAT_UNKNOWN);
|
||||
#undef CASE
|
||||
#undef CASE
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
GetNumFormats(SDL_CameraDevice *_this)
|
||||
static int V4L2_GetNumFormats(SDL_CameraDevice *_this)
|
||||
{
|
||||
int fd = _this->hidden->fd;
|
||||
int i = 0;
|
||||
@@ -574,8 +562,7 @@ GetNumFormats(SDL_CameraDevice *_this)
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
GetFormat(SDL_CameraDevice *_this, int index, Uint32 *format)
|
||||
static int V4L2_GetFormat(SDL_CameraDevice *_this, int index, Uint32 *format)
|
||||
{
|
||||
int fd = _this->hidden->fd;
|
||||
struct v4l2_fmtdesc fmtdesc;
|
||||
@@ -584,7 +571,7 @@ GetFormat(SDL_CameraDevice *_this, int index, Uint32 *format)
|
||||
fmtdesc.index = index;
|
||||
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc) == 0) {
|
||||
*format = format_v4l2_2_sdl(fmtdesc.pixelformat);
|
||||
*format = format_v4l2_to_sdl(fmtdesc.pixelformat);
|
||||
|
||||
#if DEBUG_CAMERA
|
||||
if (fmtdesc.flags & V4L2_FMT_FLAG_EMULATED) {
|
||||
@@ -600,8 +587,7 @@ GetFormat(SDL_CameraDevice *_this, int index, Uint32 *format)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
GetNumFrameSizes(SDL_CameraDevice *_this, Uint32 format)
|
||||
static int V4L2_GetNumFrameSizes(SDL_CameraDevice *_this, Uint32 format)
|
||||
{
|
||||
int fd = _this->hidden->fd;
|
||||
int i = 0;
|
||||
@@ -609,7 +595,7 @@ GetNumFrameSizes(SDL_CameraDevice *_this, Uint32 format)
|
||||
|
||||
SDL_zero(frmsizeenum);
|
||||
frmsizeenum.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
frmsizeenum.pixel_format = format_sdl_2_v4l2(format);
|
||||
frmsizeenum.pixel_format = format_sdl_to_v4l2(format);
|
||||
while (ioctl(fd,VIDIOC_ENUM_FRAMESIZES, &frmsizeenum) == 0) {
|
||||
frmsizeenum.index++;
|
||||
if (frmsizeenum.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
|
||||
@@ -624,8 +610,7 @@ GetNumFrameSizes(SDL_CameraDevice *_this, Uint32 format)
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *width, int *height)
|
||||
static int V4L2_GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *width, int *height)
|
||||
{
|
||||
int fd = _this->hidden->fd;
|
||||
struct v4l2_frmsizeenum frmsizeenum;
|
||||
@@ -633,7 +618,7 @@ GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *width, int
|
||||
|
||||
SDL_zero(frmsizeenum);
|
||||
frmsizeenum.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
frmsizeenum.pixel_format = format_sdl_2_v4l2(format);
|
||||
frmsizeenum.pixel_format = format_sdl_to_v4l2(format);
|
||||
while (ioctl(fd,VIDIOC_ENUM_FRAMESIZES, &frmsizeenum) == 0) {
|
||||
frmsizeenum.index++;
|
||||
|
||||
@@ -663,12 +648,8 @@ GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *width, int
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if DEBUG_VIDEO_CAPTURE_CAPTURE
|
||||
static void
|
||||
dbg_v4l2_pixelformat(const char *str, int f) {
|
||||
static void dbg_v4l2_pixelformat(const char *str, int f)
|
||||
{
|
||||
SDL_Log("%s V4L2_format=%d %c%c%c%c", str, f,
|
||||
(f >> 0) & 0xff,
|
||||
(f >> 8) & 0xff,
|
||||
@@ -677,8 +658,7 @@ dbg_v4l2_pixelformat(const char *str, int f) {
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
GetDeviceSpec(SDL_CameraDevice *_this, SDL_CameraSpec *spec)
|
||||
static int V4L2_GetDeviceSpec(SDL_CameraDevice *_this, SDL_CameraSpec *spec)
|
||||
{
|
||||
struct v4l2_format fmt;
|
||||
int fd = _this->hidden->fd;
|
||||
@@ -705,13 +685,12 @@ GetDeviceSpec(SDL_CameraDevice *_this, SDL_CameraSpec *spec)
|
||||
//spec->width = fmt.fmt.pix.width;
|
||||
//spec->height = fmt.fmt.pix.height;
|
||||
_this->hidden->driver_pitch = fmt.fmt.pix.bytesperline;
|
||||
//spec->format = format_v4l2_2_sdl(fmt.fmt.pix.pixelformat);
|
||||
//spec->format = format_v4l2_to_sdl(fmt.fmt.pix.pixelformat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
InitDevice(SDL_CameraDevice *_this)
|
||||
static int V4L2_InitDevice(SDL_CameraDevice *_this)
|
||||
{
|
||||
struct v4l2_cropcap cropcap;
|
||||
struct v4l2_crop crop;
|
||||
@@ -753,7 +732,7 @@ InitDevice(SDL_CameraDevice *_this)
|
||||
fmt.fmt.pix.height = _this->spec.height;
|
||||
|
||||
|
||||
fmt.fmt.pix.pixelformat = format_sdl_2_v4l2(_this->spec.format);
|
||||
fmt.fmt.pix.pixelformat = format_sdl_to_v4l2(_this->spec.format);
|
||||
// fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||
fmt.fmt.pix.field = V4L2_FIELD_ANY;
|
||||
|
||||
@@ -767,7 +746,7 @@ InitDevice(SDL_CameraDevice *_this)
|
||||
}
|
||||
}
|
||||
|
||||
GetDeviceSpec(_this, &_this->spec);
|
||||
V4L2_GetDeviceSpec(_this, &_this->spec);
|
||||
|
||||
if (PreEnqueueBuffers(_this) < 0) {
|
||||
return -1;
|
||||
@@ -776,7 +755,7 @@ InitDevice(SDL_CameraDevice *_this)
|
||||
{
|
||||
_this->hidden->buffers = SDL_calloc(_this->hidden->nb_buffers, sizeof(*_this->hidden->buffers));
|
||||
if (!_this->hidden->buffers) {
|
||||
return SDL_OutOfMemory();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,7 +781,7 @@ InitDevice(SDL_CameraDevice *_this)
|
||||
return (retval < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
void CloseDevice(SDL_CameraDevice *_this)
|
||||
static void V4L2_CloseDevice(SDL_CameraDevice *_this)
|
||||
{
|
||||
if (!_this) {
|
||||
return;
|
||||
@@ -846,8 +825,7 @@ void CloseDevice(SDL_CameraDevice *_this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int OpenDevice(SDL_CameraDevice *_this)
|
||||
static int V4L2_OpenDevice(SDL_CameraDevice *_this)
|
||||
{
|
||||
struct stat st;
|
||||
struct v4l2_capability cap;
|
||||
@@ -856,7 +834,6 @@ int OpenDevice(SDL_CameraDevice *_this)
|
||||
|
||||
_this->hidden = (struct SDL_PrivateCameraData *) SDL_calloc(1, sizeof (struct SDL_PrivateCameraData));
|
||||
if (_this->hidden == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -921,7 +898,7 @@ int OpenDevice(SDL_CameraDevice *_this)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size)
|
||||
static int V4L2_GetDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size)
|
||||
{
|
||||
SDL_cameralist_item *item;
|
||||
for (item = SDL_cameralist; item; item = item->next) {
|
||||
@@ -935,15 +912,13 @@ int GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
SDL_CameraDeviceID *GetCameraDevices(int *count)
|
||||
static SDL_CameraDeviceID *V4L2_GetDevices(int *count)
|
||||
{
|
||||
// real list of ID
|
||||
const int num = num_cameras;
|
||||
SDL_CameraDeviceID *retval = (SDL_CameraDeviceID *)SDL_malloc((num + 1) * sizeof(*retval));
|
||||
|
||||
if (retval == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
*count = 0;
|
||||
return NULL;
|
||||
}
|
||||
@@ -959,55 +934,6 @@ SDL_CameraDeviceID *GetCameraDevices(int *count)
|
||||
}
|
||||
|
||||
|
||||
// Initializes the subsystem by finding available devices.
|
||||
int SDL_SYS_CameraInit(void)
|
||||
{
|
||||
const char pattern[] = "/dev/video%d";
|
||||
char path[PATH_MAX];
|
||||
|
||||
/*
|
||||
* Limit amount of checks to MAX_CAMERA_DEVICES since we may or may not have
|
||||
* permission to some or all devices.
|
||||
*/
|
||||
for (int i = 0; i < MAX_CAMERA_DEVICES; i++) {
|
||||
(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");
|
||||
} else if (SDL_UDEV_AddCallback(CameraUdevCallback) < 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_cameras;
|
||||
}
|
||||
|
||||
int SDL_SYS_CameraQuit(void)
|
||||
{
|
||||
for (SDL_cameralist_item *item = SDL_cameralist; item; ) {
|
||||
SDL_cameralist_item *tmp = item->next;
|
||||
SDL_free(item->fname);
|
||||
SDL_free(item->bus_info);
|
||||
SDL_free(item);
|
||||
item = tmp;
|
||||
}
|
||||
|
||||
num_cameras = 0;
|
||||
SDL_cameralist = NULL;
|
||||
SDL_cameralist_tail = NULL;
|
||||
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
#ifdef SDL_USE_LIBUDEV
|
||||
static void CameraUdevCallback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
|
||||
{
|
||||
@@ -1150,5 +1076,78 @@ static int MaybeRemoveDevice(const char *path)
|
||||
}
|
||||
#endif // SDL_USE_LIBUDEV
|
||||
|
||||
|
||||
static void V4L2_Deinitialize(void)
|
||||
{
|
||||
for (SDL_cameralist_item *item = SDL_cameralist; item; ) {
|
||||
SDL_cameralist_item *tmp = item->next;
|
||||
SDL_free(item->fname);
|
||||
SDL_free(item->bus_info);
|
||||
SDL_free(item);
|
||||
item = tmp;
|
||||
}
|
||||
|
||||
num_cameras = 0;
|
||||
SDL_cameralist = NULL;
|
||||
SDL_cameralist_tail = NULL;
|
||||
}
|
||||
|
||||
static void V4L2_DetectDevices(void)
|
||||
{
|
||||
}
|
||||
|
||||
static SDL_bool V4L2_Init(SDL_CameraDriverImpl *impl)
|
||||
{
|
||||
// !!! FIXME: move to DetectDevices
|
||||
const char pattern[] = "/dev/video%d";
|
||||
char path[PATH_MAX];
|
||||
|
||||
/*
|
||||
* Limit amount of checks to MAX_CAMERA_DEVICES since we may or may not have
|
||||
* permission to some or all devices.
|
||||
*/
|
||||
for (int i = 0; i < MAX_CAMERA_DEVICES; i++) {
|
||||
(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");
|
||||
} else if (SDL_UDEV_AddCallback(CameraUdevCallback) < 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
|
||||
|
||||
impl->DetectDevices = V4L2_DetectDevices;
|
||||
impl->OpenDevice = V4L2_OpenDevice;
|
||||
impl->CloseDevice = V4L2_CloseDevice;
|
||||
impl->InitDevice = V4L2_InitDevice;
|
||||
impl->GetDeviceSpec = V4L2_GetDeviceSpec;
|
||||
impl->StartCamera = V4L2_StartCamera;
|
||||
impl->StopCamera = V4L2_StopCamera;
|
||||
impl->AcquireFrame = V4L2_AcquireFrame;
|
||||
impl->ReleaseFrame = V4L2_ReleaseFrame;
|
||||
impl->GetNumFormats = V4L2_GetNumFormats;
|
||||
impl->GetFormat = V4L2_GetFormat;
|
||||
impl->GetNumFrameSizes = V4L2_GetNumFrameSizes;
|
||||
impl->GetFrameSize = V4L2_GetFrameSize;
|
||||
impl->GetDeviceName = V4L2_GetDeviceName;
|
||||
impl->GetDevices = V4L2_GetDevices;
|
||||
impl->Deinitialize = V4L2_Deinitialize;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
CameraBootStrap V4L2_bootstrap = {
|
||||
"v4l2", "SDL Video4Linux2 camera driver", V4L2_Init, SDL_FALSE
|
||||
};
|
||||
|
||||
#endif // SDL_CAMERA_V4L2
|
||||
|
||||
|
Reference in New Issue
Block a user