camera: Made a pass over all the sources, cleaning up for SDL3 style, etc.
parent
7ae955ce68
commit
2ad44bd162
|
@ -20,8 +20,6 @@
|
||||||
*/
|
*/
|
||||||
#include "SDL_internal.h"
|
#include "SDL_internal.h"
|
||||||
|
|
||||||
#include "SDL3/SDL.h"
|
|
||||||
#include "SDL3/SDL_camera.h"
|
|
||||||
#include "SDL_syscamera.h"
|
#include "SDL_syscamera.h"
|
||||||
#include "SDL_camera_c.h"
|
#include "SDL_camera_c.h"
|
||||||
#include "../video/SDL_pixels_c.h"
|
#include "../video/SDL_pixels_c.h"
|
||||||
|
@ -29,16 +27,16 @@
|
||||||
|
|
||||||
#define DEBUG_CAMERA 1
|
#define DEBUG_CAMERA 1
|
||||||
|
|
||||||
/* list node entries to share frames between SDL and user app */
|
// list node entries to share frames between SDL and user app
|
||||||
|
// !!! FIXME: do we need this struct?
|
||||||
typedef struct entry_t
|
typedef struct entry_t
|
||||||
{
|
{
|
||||||
SDL_CameraFrame frame;
|
SDL_CameraFrame frame;
|
||||||
} entry_t;
|
} entry_t;
|
||||||
|
|
||||||
static SDL_CameraDevice *open_devices[16];
|
static SDL_CameraDevice *open_devices[16]; // !!! FIXME: remove limit
|
||||||
|
|
||||||
static void
|
static void CloseCameraDevice(SDL_CameraDevice *device)
|
||||||
close_device(SDL_CameraDevice *device)
|
|
||||||
{
|
{
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return;
|
return;
|
||||||
|
@ -57,27 +55,23 @@ close_device(SDL_CameraDevice *device)
|
||||||
SDL_DestroyMutex(device->acquiring_lock);
|
SDL_DestroyMutex(device->acquiring_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
const int n = SDL_arraysize(open_devices);
|
||||||
int i, n = SDL_arraysize(open_devices);
|
for (int i = 0; i < n; i++) {
|
||||||
for (i = 0; i < n; i++) {
|
if (open_devices[i] == device) {
|
||||||
if (open_devices[i] == device) {
|
open_devices[i] = NULL;
|
||||||
open_devices[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
entry_t *entry = NULL;
|
||||||
entry_t *entry = NULL;
|
while (device->buffer_queue != NULL) {
|
||||||
while (device->buffer_queue != NULL) {
|
SDL_ListPop(&device->buffer_queue, (void**)&entry);
|
||||||
SDL_ListPop(&device->buffer_queue, (void**)&entry);
|
if (entry) {
|
||||||
if (entry) {
|
SDL_CameraFrame f = entry->frame;
|
||||||
SDL_CameraFrame f = entry->frame;
|
// Release frames not acquired, if any
|
||||||
/* Release frames not acquired, if any */
|
if (f.timestampNS) {
|
||||||
if (f.timestampNS) {
|
ReleaseFrame(device, &f);
|
||||||
ReleaseFrame(device, &f);
|
|
||||||
}
|
|
||||||
SDL_free(entry);
|
|
||||||
}
|
}
|
||||||
|
SDL_free(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,12 +81,12 @@ close_device(SDL_CameraDevice *device)
|
||||||
SDL_free(device);
|
SDL_free(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tell if all device are closed */
|
// Tell if all devices are closed
|
||||||
SDL_bool check_all_device_closed(void)
|
SDL_bool CheckAllDeviceClosed(void)
|
||||||
{
|
{
|
||||||
int i, n = SDL_arraysize(open_devices);
|
const int n = SDL_arraysize(open_devices);
|
||||||
int all_closed = SDL_TRUE;
|
int all_closed = SDL_TRUE;
|
||||||
for (i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
if (open_devices[i]) {
|
if (open_devices[i]) {
|
||||||
all_closed = SDL_FALSE;
|
all_closed = SDL_FALSE;
|
||||||
break;
|
break;
|
||||||
|
@ -101,11 +95,11 @@ SDL_bool check_all_device_closed(void)
|
||||||
return all_closed;
|
return all_closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tell if at least one device is in playing state */
|
// Tell if at least one device is in playing state
|
||||||
SDL_bool check_device_playing(void)
|
SDL_bool CheckDevicePlaying(void)
|
||||||
{
|
{
|
||||||
int i, n = SDL_arraysize(open_devices);
|
const int n = SDL_arraysize(open_devices);
|
||||||
for (i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
if (open_devices[i]) {
|
if (open_devices[i]) {
|
||||||
if (SDL_GetCameraStatus(open_devices[i]) == SDL_CAMERA_PLAYING) {
|
if (SDL_GetCameraStatus(open_devices[i]) == SDL_CAMERA_PLAYING) {
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
|
@ -115,35 +109,26 @@ SDL_bool check_device_playing(void)
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void SDL_CloseCamera(SDL_CameraDevice *device)
|
||||||
SDL_CloseCamera(SDL_CameraDevice *device)
|
|
||||||
{
|
{
|
||||||
if (!device) {
|
if (!device) {
|
||||||
SDL_InvalidParamError("device");
|
SDL_InvalidParamError("device");
|
||||||
return;
|
} else {
|
||||||
|
CloseCameraDevice(device);
|
||||||
}
|
}
|
||||||
close_device(device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int SDL_StartCamera(SDL_CameraDevice *device)
|
||||||
SDL_StartCamera(SDL_CameraDevice *device)
|
|
||||||
{
|
{
|
||||||
SDL_CameraStatus status;
|
|
||||||
int result;
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return SDL_InvalidParamError("device");
|
return SDL_InvalidParamError("device");
|
||||||
}
|
} else if (device->is_spec_set == SDL_FALSE) {
|
||||||
|
|
||||||
if (device->is_spec_set == SDL_FALSE) {
|
|
||||||
return SDL_SetError("no spec set");
|
return SDL_SetError("no spec set");
|
||||||
}
|
} else if (SDL_GetCameraStatus(device) != SDL_CAMERA_INIT) {
|
||||||
|
|
||||||
status = SDL_GetCameraStatus(device);
|
|
||||||
if (status != SDL_CAMERA_INIT) {
|
|
||||||
return SDL_SetError("invalid state");
|
return SDL_SetError("invalid state");
|
||||||
}
|
}
|
||||||
|
|
||||||
result = StartCamera(device);
|
const int result = StartCamera(device);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -153,34 +138,23 @@ SDL_StartCamera(SDL_CameraDevice *device)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int SDL_GetCameraSpec(SDL_CameraDevice *device, SDL_CameraSpec *spec)
|
||||||
SDL_GetCameraSpec(SDL_CameraDevice *device, SDL_CameraSpec *spec)
|
|
||||||
{
|
{
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return SDL_InvalidParamError("device");
|
return SDL_InvalidParamError("device");
|
||||||
}
|
} else if (!spec) {
|
||||||
|
|
||||||
if (!spec) {
|
|
||||||
return SDL_InvalidParamError("spec");
|
return SDL_InvalidParamError("spec");
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_zerop(spec);
|
SDL_zerop(spec);
|
||||||
|
|
||||||
return GetDeviceSpec(device, spec);
|
return GetDeviceSpec(device, spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int SDL_StopCamera(SDL_CameraDevice *device)
|
||||||
SDL_StopCamera(SDL_CameraDevice *device)
|
|
||||||
{
|
{
|
||||||
SDL_CameraStatus status;
|
|
||||||
int ret;
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return SDL_InvalidParamError("device");
|
return SDL_InvalidParamError("device");
|
||||||
}
|
} else if (SDL_GetCameraStatus(device) != SDL_CAMERA_PLAYING) {
|
||||||
|
|
||||||
status = SDL_GetCameraStatus(device);
|
|
||||||
|
|
||||||
if (status != SDL_CAMERA_PLAYING) {
|
|
||||||
return SDL_SetError("invalid state");
|
return SDL_SetError("invalid state");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,104 +162,88 @@ SDL_StopCamera(SDL_CameraDevice *device)
|
||||||
SDL_AtomicSet(&device->shutdown, 1);
|
SDL_AtomicSet(&device->shutdown, 1);
|
||||||
|
|
||||||
SDL_LockMutex(device->acquiring_lock);
|
SDL_LockMutex(device->acquiring_lock);
|
||||||
ret = StopCamera(device);
|
const int retval = StopCamera(device);
|
||||||
SDL_UnlockMutex(device->acquiring_lock);
|
SDL_UnlockMutex(device->acquiring_lock);
|
||||||
|
|
||||||
if (ret < 0) {
|
return (retval < 0) ? -1 : 0;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check spec has valid format and frame size */
|
// Check spec has valid format and frame size
|
||||||
static int
|
static int prepare_cameraspec(SDL_CameraDevice *device, const SDL_CameraSpec *desired, SDL_CameraSpec *obtained, int allowed_changes)
|
||||||
prepare_cameraspec(SDL_CameraDevice *device, const SDL_CameraSpec *desired, SDL_CameraSpec *obtained, int allowed_changes)
|
|
||||||
{
|
{
|
||||||
/* Check format */
|
// Check format
|
||||||
{
|
const int numfmts = SDL_GetNumCameraFormats(device);
|
||||||
int i, num = SDL_GetNumCameraFormats(device);
|
SDL_bool is_format_valid = SDL_FALSE;
|
||||||
int is_format_valid = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
for (int i = 0; i < numfmts; i++) {
|
||||||
Uint32 format;
|
Uint32 format;
|
||||||
if (SDL_GetCameraFormat(device, i, &format) == 0) {
|
if (SDL_GetCameraFormat(device, i, &format) == 0) {
|
||||||
if (format == desired->format && format != SDL_PIXELFORMAT_UNKNOWN) {
|
if (format == desired->format && format != SDL_PIXELFORMAT_UNKNOWN) {
|
||||||
is_format_valid = 1;
|
is_format_valid = SDL_TRUE;
|
||||||
obtained->format = format;
|
obtained->format = format;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_format_valid) {
|
if (!is_format_valid) {
|
||||||
if (allowed_changes) {
|
if (allowed_changes) {
|
||||||
for (i = 0; i < num; i++) {
|
for (int i = 0; i < numfmts; i++) {
|
||||||
Uint32 format;
|
Uint32 format;
|
||||||
if (SDL_GetCameraFormat(device, i, &format) == 0) {
|
if (SDL_GetCameraFormat(device, i, &format) == 0) {
|
||||||
if (format != SDL_PIXELFORMAT_UNKNOWN) {
|
if (format != SDL_PIXELFORMAT_UNKNOWN) {
|
||||||
obtained->format = format;
|
obtained->format = format;
|
||||||
is_format_valid = 1;
|
is_format_valid = SDL_TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
SDL_SetError("Not allowed to change the format");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
return SDL_SetError("Not allowed to change the format");
|
||||||
if (!is_format_valid) {
|
|
||||||
SDL_SetError("Invalid format");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check frame size */
|
if (!is_format_valid) {
|
||||||
{
|
return SDL_SetError("Invalid format");
|
||||||
int i, num = SDL_GetNumCameraFrameSizes(device, obtained->format);
|
}
|
||||||
int is_framesize_valid = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
// Check frame size
|
||||||
|
const int numsizes = SDL_GetNumCameraFrameSizes(device, obtained->format);
|
||||||
|
SDL_bool is_framesize_valid = SDL_FALSE;
|
||||||
|
|
||||||
|
for (int i = 0; i < numsizes; i++) {
|
||||||
|
int w, h;
|
||||||
|
if (SDL_GetCameraFrameSize(device, obtained->format, i, &w, &h) == 0) {
|
||||||
|
if (desired->width == w && desired->height == h) {
|
||||||
|
is_framesize_valid = SDL_TRUE;
|
||||||
|
obtained->width = w;
|
||||||
|
obtained->height = h;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_framesize_valid) {
|
||||||
|
if (allowed_changes) {
|
||||||
int w, h;
|
int w, h;
|
||||||
if (SDL_GetCameraFrameSize(device, obtained->format, i, &w, &h) == 0) {
|
if (SDL_GetCameraFrameSize(device, obtained->format, 0, &w, &h) == 0) {
|
||||||
if (desired->width == w && desired->height == h) {
|
is_framesize_valid = SDL_TRUE;
|
||||||
is_framesize_valid = 1;
|
obtained->width = w;
|
||||||
obtained->width = w;
|
obtained->height = h;
|
||||||
obtained->height = h;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return SDL_SetError("Not allowed to change the frame size");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_framesize_valid) {
|
if (!is_framesize_valid) {
|
||||||
if (allowed_changes) {
|
return SDL_SetError("Invalid frame size");
|
||||||
int w, h;
|
|
||||||
if (SDL_GetCameraFrameSize(device, obtained->format, 0, &w, &h) == 0) {
|
|
||||||
is_framesize_valid = 1;
|
|
||||||
obtained->width = w;
|
|
||||||
obtained->height = h;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SDL_SetError("Not allowed to change the frame size");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_framesize_valid) {
|
|
||||||
SDL_SetError("Invalid frame size");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *SDL_GetCameraDeviceName(SDL_CameraDeviceID instance_id)
|
||||||
SDL_GetCameraDeviceName(SDL_CameraDeviceID instance_id)
|
|
||||||
{
|
{
|
||||||
static char buf[256];
|
static char buf[256];
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
|
@ -299,47 +257,41 @@ SDL_GetCameraDeviceName(SDL_CameraDeviceID instance_id)
|
||||||
if (GetCameraDeviceName(instance_id, buf, sizeof (buf)) < 0) {
|
if (GetCameraDeviceName(instance_id, buf, sizeof (buf)) < 0) {
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SDL_CameraDeviceID *
|
SDL_CameraDeviceID *SDL_GetCameraDevices(int *count)
|
||||||
SDL_GetCameraDevices(int *count)
|
|
||||||
{
|
{
|
||||||
|
int dummycount = 0;
|
||||||
int num = 0;
|
if (!count) {
|
||||||
SDL_CameraDeviceID *ret = GetCameraDevices(&num);
|
count = &dummycount;
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
if (count) {
|
|
||||||
*count = num;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return list of 0 ID, null terminated */
|
int num = 0;
|
||||||
num = 0;
|
SDL_CameraDeviceID *retval = GetCameraDevices(&num);
|
||||||
ret = (SDL_CameraDeviceID *)SDL_malloc((num + 1) * sizeof(*ret));
|
if (retval) {
|
||||||
|
*count = num;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret == NULL) {
|
// return list of 0 ID, null terminated
|
||||||
|
retval = (SDL_CameraDeviceID *)SDL_calloc(1, sizeof(*retval));
|
||||||
|
if (retval == NULL) {
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
if (count) {
|
*count = 0;
|
||||||
*count = 0;
|
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret[num] = 0;
|
retval[0] = 0;
|
||||||
if (count) {
|
*count = 0;
|
||||||
*count = num;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Camera thread function */
|
// Camera thread function
|
||||||
static int SDLCALL
|
static int SDLCALL SDL_CameraThread(void *devicep)
|
||||||
SDL_CameraThread(void *devicep)
|
|
||||||
{
|
{
|
||||||
const int delay = 20;
|
const int delay = 20;
|
||||||
SDL_CameraDevice *device = (SDL_CameraDevice *) devicep;
|
SDL_CameraDevice *device = (SDL_CameraDevice *) devicep;
|
||||||
|
@ -358,23 +310,23 @@ SDL_CameraThread(void *devicep)
|
||||||
Android_JNI_CameraSetThreadPriority(device->iscapture, device);
|
Android_JNI_CameraSetThreadPriority(device->iscapture, device);
|
||||||
}*/
|
}*/
|
||||||
#else
|
#else
|
||||||
/* The camera capture is always a high priority thread */
|
// The camera capture is always a high priority thread
|
||||||
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
|
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Perform any thread setup */
|
// Perform any thread setup
|
||||||
device->threadid = SDL_GetCurrentThreadID();
|
device->threadid = SDL_GetCurrentThreadID();
|
||||||
|
|
||||||
/* Init state */
|
// Init state
|
||||||
|
// !!! FIXME: use a semaphore or something
|
||||||
while (!SDL_AtomicGet(&device->enabled)) {
|
while (!SDL_AtomicGet(&device->enabled)) {
|
||||||
SDL_Delay(delay);
|
SDL_Delay(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop, filling the camera buffers */
|
// Loop, filling the camera buffers
|
||||||
while (!SDL_AtomicGet(&device->shutdown)) {
|
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||||
SDL_CameraFrame f;
|
SDL_CameraFrame f;
|
||||||
int ret;
|
int ret;
|
||||||
entry_t *entry;
|
|
||||||
|
|
||||||
SDL_zero(f);
|
SDL_zero(f);
|
||||||
|
|
||||||
|
@ -389,7 +341,7 @@ SDL_CameraThread(void *devicep)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/* Flag it as an error */
|
// Flag it as an error
|
||||||
#if DEBUG_CAMERA
|
#if DEBUG_CAMERA
|
||||||
SDL_Log("dev[%p] error AcquireFrame: %d %s", (void *)device, ret, SDL_GetError());
|
SDL_Log("dev[%p] error AcquireFrame: %d %s", (void *)device, ret, SDL_GetError());
|
||||||
#endif
|
#endif
|
||||||
|
@ -397,7 +349,7 @@ SDL_CameraThread(void *devicep)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
entry = SDL_malloc(sizeof (entry_t));
|
entry_t *entry = SDL_malloc(sizeof (entry_t));
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
goto error_mem;
|
goto error_mem;
|
||||||
}
|
}
|
||||||
|
@ -424,26 +376,25 @@ error_mem:
|
||||||
SDL_Log("dev[%p] End thread 'SDL_CameraThread' with error: %s", (void *)device, SDL_GetError());
|
SDL_Log("dev[%p] End thread 'SDL_CameraThread' with error: %s", (void *)device, SDL_GetError());
|
||||||
#endif
|
#endif
|
||||||
SDL_AtomicSet(&device->shutdown, 1);
|
SDL_AtomicSet(&device->shutdown, 1);
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory(); // !!! FIXME: this error isn't accessible since the thread is about to terminate
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_CameraDevice *
|
SDL_CameraDevice *SDL_OpenCamera(SDL_CameraDeviceID instance_id)
|
||||||
SDL_OpenCamera(SDL_CameraDeviceID instance_id)
|
|
||||||
{
|
{
|
||||||
int i, n = SDL_arraysize(open_devices);
|
const int n = SDL_arraysize(open_devices);
|
||||||
int id = -1;
|
|
||||||
SDL_CameraDevice *device = NULL;
|
SDL_CameraDevice *device = NULL;
|
||||||
const char *device_name = NULL;
|
const char *device_name = NULL;
|
||||||
|
int id = -1;
|
||||||
|
|
||||||
if (!SDL_WasInit(SDL_INIT_VIDEO)) {
|
if (!SDL_WasInit(SDL_INIT_VIDEO)) {
|
||||||
SDL_SetError("Video subsystem is not initialized");
|
SDL_SetError("Video subsystem is not initialized");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* !!! FIXME: there is a race condition here if two devices open from two threads at once. */
|
// !!! FIXME: there is a race condition here if two devices open from two threads at once.
|
||||||
/* Find an available device ID... */
|
// Find an available device ID...
|
||||||
for (i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
if (open_devices[i] == NULL) {
|
if (open_devices[i] == NULL) {
|
||||||
id = i;
|
id = i;
|
||||||
break;
|
break;
|
||||||
|
@ -470,7 +421,7 @@ SDL_OpenCamera(SDL_CameraDeviceID instance_id)
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// FIXME do we need this ?
|
// FIXME do we need this ?
|
||||||
/* Let the user override. */
|
// Let the user override.
|
||||||
{
|
{
|
||||||
const char *dev = SDL_getenv("SDL_CAMERA_DEVICE_NAME");
|
const char *dev = SDL_getenv("SDL_CAMERA_DEVICE_NAME");
|
||||||
if (dev && dev[0]) {
|
if (dev && dev[0]) {
|
||||||
|
@ -490,7 +441,6 @@ SDL_OpenCamera(SDL_CameraDeviceID instance_id)
|
||||||
}
|
}
|
||||||
device->dev_name = SDL_strdup(device_name);
|
device->dev_name = SDL_strdup(device_name);
|
||||||
|
|
||||||
|
|
||||||
SDL_AtomicSet(&device->shutdown, 0);
|
SDL_AtomicSet(&device->shutdown, 0);
|
||||||
SDL_AtomicSet(&device->enabled, 0);
|
SDL_AtomicSet(&device->enabled, 0);
|
||||||
|
|
||||||
|
@ -510,37 +460,28 @@ SDL_OpenCamera(SDL_CameraDeviceID instance_id)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* empty */
|
// empty
|
||||||
device->buffer_queue = NULL;
|
device->buffer_queue = NULL;
|
||||||
open_devices[id] = device; /* add it to our list of open devices. */
|
open_devices[id] = device; // add it to our list of open devices.
|
||||||
|
|
||||||
|
|
||||||
/* Start the camera thread */
|
// Start the camera thread
|
||||||
{
|
char threadname[64];
|
||||||
const size_t stacksize = 64 * 1024;
|
SDL_snprintf(threadname, sizeof (threadname), "SDLCamera%d", id);
|
||||||
char threadname[64];
|
device->thread = SDL_CreateThreadInternal(SDL_CameraThread, threadname, 0, device);
|
||||||
|
if (device->thread == NULL) {
|
||||||
SDL_snprintf(threadname, sizeof (threadname), "SDLCamera%d", id);
|
SDL_SetError("Couldn't create camera thread");
|
||||||
device->thread = SDL_CreateThreadInternal(SDL_CameraThread, threadname, stacksize, device);
|
goto error;
|
||||||
|
|
||||||
if (device->thread == NULL) {
|
|
||||||
SDL_SetError("Couldn't create camera thread");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return device;
|
return device;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
close_device(device);
|
CloseCameraDevice(device);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int SDL_SetCameraSpec(SDL_CameraDevice *device, const SDL_CameraSpec *desired, SDL_CameraSpec *obtained, int allowed_changes)
|
||||||
SDL_SetCameraSpec(SDL_CameraDevice *device,
|
|
||||||
const SDL_CameraSpec *desired,
|
|
||||||
SDL_CameraSpec *obtained,
|
|
||||||
int allowed_changes)
|
|
||||||
{
|
{
|
||||||
SDL_CameraSpec _obtained;
|
SDL_CameraSpec _obtained;
|
||||||
SDL_CameraSpec _desired;
|
SDL_CameraSpec _desired;
|
||||||
|
@ -548,9 +489,7 @@ SDL_SetCameraSpec(SDL_CameraDevice *device,
|
||||||
|
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return SDL_InvalidParamError("device");
|
return SDL_InvalidParamError("device");
|
||||||
}
|
} else if (device->is_spec_set == SDL_TRUE) {
|
||||||
|
|
||||||
if (device->is_spec_set == SDL_TRUE) {
|
|
||||||
return SDL_SetError("already configured");
|
return SDL_SetError("already configured");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,7 +498,7 @@ SDL_SetCameraSpec(SDL_CameraDevice *device,
|
||||||
desired = &_desired;
|
desired = &_desired;
|
||||||
allowed_changes = SDL_CAMERA_ALLOW_ANY_CHANGE;
|
allowed_changes = SDL_CAMERA_ALLOW_ANY_CHANGE;
|
||||||
} else {
|
} else {
|
||||||
/* in case desired == obtained */
|
// in case desired == obtained
|
||||||
_desired = *desired;
|
_desired = *desired;
|
||||||
desired = &_desired;
|
desired = &_desired;
|
||||||
}
|
}
|
||||||
|
@ -588,14 +527,11 @@ SDL_SetCameraSpec(SDL_CameraDevice *device,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int SDL_AcquireCameraFrame(SDL_CameraDevice *device, SDL_CameraFrame *frame)
|
||||||
SDL_AcquireCameraFrame(SDL_CameraDevice *device, SDL_CameraFrame *frame)
|
|
||||||
{
|
{
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return SDL_InvalidParamError("device");
|
return SDL_InvalidParamError("device");
|
||||||
}
|
} else if (!frame) {
|
||||||
|
|
||||||
if (!frame) {
|
|
||||||
return SDL_InvalidParamError("frame");
|
return SDL_InvalidParamError("frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,7 +540,7 @@ SDL_AcquireCameraFrame(SDL_CameraDevice *device, SDL_CameraFrame *frame)
|
||||||
if (device->thread == NULL) {
|
if (device->thread == NULL) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Wait for a frame */
|
// Wait for a frame
|
||||||
while ((ret = AcquireFrame(device, frame)) == 0) {
|
while ((ret = AcquireFrame(device, frame)) == 0) {
|
||||||
if (frame->num_planes) {
|
if (frame->num_planes) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -622,42 +558,33 @@ SDL_AcquireCameraFrame(SDL_CameraDevice *device, SDL_CameraFrame *frame)
|
||||||
*frame = entry->frame;
|
*frame = entry->frame;
|
||||||
SDL_free(entry);
|
SDL_free(entry);
|
||||||
|
|
||||||
/* Error from thread */
|
// Error from thread
|
||||||
if (frame->num_planes == 0 && frame->timestampNS == 0) {
|
if (frame->num_planes == 0 && frame->timestampNS == 0) {
|
||||||
return SDL_SetError("error from acquisition thread");
|
return SDL_SetError("error from acquisition thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Queue is empty. Not an error. */
|
// Queue is empty. Not an error.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int SDL_ReleaseCameraFrame(SDL_CameraDevice *device, SDL_CameraFrame *frame)
|
||||||
SDL_ReleaseCameraFrame(SDL_CameraDevice *device, SDL_CameraFrame *frame)
|
|
||||||
{
|
{
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return SDL_InvalidParamError("device");
|
return SDL_InvalidParamError("device");
|
||||||
}
|
} else if (frame == NULL) {
|
||||||
|
|
||||||
if (frame == NULL) {
|
|
||||||
return SDL_InvalidParamError("frame");
|
return SDL_InvalidParamError("frame");
|
||||||
}
|
} else if (ReleaseFrame(device, frame) < 0) {
|
||||||
|
|
||||||
if (ReleaseFrame(device, frame) < 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_zerop(frame);
|
SDL_zerop(frame);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int SDL_GetNumCameraFormats(SDL_CameraDevice *device)
|
||||||
SDL_GetNumCameraFormats(SDL_CameraDevice *device)
|
|
||||||
{
|
{
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return SDL_InvalidParamError("device");
|
return SDL_InvalidParamError("device");
|
||||||
|
@ -665,21 +592,18 @@ SDL_GetNumCameraFormats(SDL_CameraDevice *device)
|
||||||
return GetNumFormats(device);
|
return GetNumFormats(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int SDL_GetCameraFormat(SDL_CameraDevice *device, int index, Uint32 *format)
|
||||||
SDL_GetCameraFormat(SDL_CameraDevice *device, int index, Uint32 *format)
|
|
||||||
{
|
{
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return SDL_InvalidParamError("device");
|
return SDL_InvalidParamError("device");
|
||||||
}
|
} else if (!format) {
|
||||||
if (!format) {
|
|
||||||
return SDL_InvalidParamError("format");
|
return SDL_InvalidParamError("format");
|
||||||
}
|
}
|
||||||
*format = 0;
|
*format = 0;
|
||||||
return GetFormat(device, index, format);
|
return GetFormat(device, index, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int SDL_GetNumCameraFrameSizes(SDL_CameraDevice *device, Uint32 format)
|
||||||
SDL_GetNumCameraFrameSizes(SDL_CameraDevice *device, Uint32 format)
|
|
||||||
{
|
{
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return SDL_InvalidParamError("device");
|
return SDL_InvalidParamError("device");
|
||||||
|
@ -687,29 +611,20 @@ SDL_GetNumCameraFrameSizes(SDL_CameraDevice *device, Uint32 format)
|
||||||
return GetNumFrameSizes(device, format);
|
return GetNumFrameSizes(device, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int SDL_GetCameraFrameSize(SDL_CameraDevice *device, Uint32 format, int index, int *width, int *height)
|
||||||
SDL_GetCameraFrameSize(SDL_CameraDevice *device, Uint32 format, int index, int *width, int *height)
|
|
||||||
{
|
{
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return SDL_InvalidParamError("device");
|
return SDL_InvalidParamError("device");
|
||||||
}
|
} else if (!width) {
|
||||||
if (!width) {
|
|
||||||
return SDL_InvalidParamError("width");
|
return SDL_InvalidParamError("width");
|
||||||
}
|
} else if (!height) {
|
||||||
if (!height) {
|
|
||||||
return SDL_InvalidParamError("height");
|
return SDL_InvalidParamError("height");
|
||||||
}
|
}
|
||||||
*width = 0;
|
*width = *height = 0;
|
||||||
*height = 0;
|
|
||||||
return GetFrameSize(device, format, index, width, height);
|
return GetFrameSize(device, format, index, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_CameraDevice *
|
SDL_CameraDevice *SDL_OpenCameraWithSpec(SDL_CameraDeviceID instance_id, const SDL_CameraSpec *desired, SDL_CameraSpec *obtained, int allowed_changes)
|
||||||
SDL_OpenCameraWithSpec(
|
|
||||||
SDL_CameraDeviceID instance_id,
|
|
||||||
const SDL_CameraSpec *desired,
|
|
||||||
SDL_CameraSpec *obtained,
|
|
||||||
int allowed_changes)
|
|
||||||
{
|
{
|
||||||
SDL_CameraDevice *device;
|
SDL_CameraDevice *device;
|
||||||
|
|
||||||
|
@ -724,42 +639,32 @@ SDL_OpenCameraWithSpec(
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_CameraStatus
|
SDL_CameraStatus SDL_GetCameraStatus(SDL_CameraDevice *device)
|
||||||
SDL_GetCameraStatus(SDL_CameraDevice *device)
|
|
||||||
{
|
{
|
||||||
if (device == NULL) {
|
if (device == NULL) {
|
||||||
return SDL_CAMERA_INIT;
|
return SDL_CAMERA_INIT;
|
||||||
}
|
} else if (device->is_spec_set == SDL_FALSE) {
|
||||||
|
|
||||||
if (device->is_spec_set == SDL_FALSE) {
|
|
||||||
return SDL_CAMERA_INIT;
|
return SDL_CAMERA_INIT;
|
||||||
}
|
} else if (SDL_AtomicGet(&device->shutdown)) {
|
||||||
|
|
||||||
if (SDL_AtomicGet(&device->shutdown)) {
|
|
||||||
return SDL_CAMERA_STOPPED;
|
return SDL_CAMERA_STOPPED;
|
||||||
}
|
} else if (SDL_AtomicGet(&device->enabled)) {
|
||||||
|
|
||||||
if (SDL_AtomicGet(&device->enabled)) {
|
|
||||||
return SDL_CAMERA_PLAYING;
|
return SDL_CAMERA_PLAYING;
|
||||||
}
|
}
|
||||||
return SDL_CAMERA_INIT;
|
return SDL_CAMERA_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int SDL_CameraInit(void)
|
||||||
SDL_CameraInit(void)
|
|
||||||
{
|
{
|
||||||
SDL_zeroa(open_devices);
|
SDL_zeroa(open_devices);
|
||||||
|
|
||||||
SDL_SYS_CameraInit();
|
SDL_SYS_CameraInit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void SDL_QuitCamera(void)
|
||||||
SDL_QuitCamera(void)
|
|
||||||
{
|
{
|
||||||
int i, n = SDL_arraysize(open_devices);
|
const int n = SDL_arraysize(open_devices);
|
||||||
for (i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
close_device(open_devices[i]);
|
CloseCameraDevice(open_devices[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_zeroa(open_devices);
|
SDL_zeroa(open_devices);
|
||||||
|
|
|
@ -23,10 +23,10 @@
|
||||||
#ifndef SDL_camera_c_h_
|
#ifndef SDL_camera_c_h_
|
||||||
#define SDL_camera_c_h_
|
#define SDL_camera_c_h_
|
||||||
|
|
||||||
/* Initialize the camera subsystem */
|
// Initialize the camera subsystem
|
||||||
int SDL_CameraInit(void);
|
int SDL_CameraInit(void);
|
||||||
|
|
||||||
/* Shutdown the camera subsystem */
|
// Shutdown the camera subsystem
|
||||||
void SDL_QuitCamera(void);
|
void SDL_QuitCamera(void);
|
||||||
|
|
||||||
#endif /* SDL_camera_c_h_ */
|
#endif // SDL_camera_c_h_
|
||||||
|
|
|
@ -25,45 +25,43 @@
|
||||||
|
|
||||||
#include "../SDL_list.h"
|
#include "../SDL_list.h"
|
||||||
|
|
||||||
/* The SDL camera driver */
|
// The SDL camera driver
|
||||||
typedef struct SDL_CameraDevice SDL_CameraDevice;
|
typedef struct SDL_CameraDevice SDL_CameraDevice;
|
||||||
|
|
||||||
/* Define the SDL camera driver structure */
|
// Define the SDL camera driver structure
|
||||||
struct SDL_CameraDevice
|
struct SDL_CameraDevice
|
||||||
{
|
{
|
||||||
/* * * */
|
// The device's current camera specification
|
||||||
/* Data common to all devices */
|
|
||||||
|
|
||||||
/* The device's current camera specification */
|
|
||||||
SDL_CameraSpec spec;
|
SDL_CameraSpec spec;
|
||||||
|
|
||||||
/* Device name */
|
// Device name
|
||||||
char *dev_name;
|
char *dev_name;
|
||||||
|
|
||||||
/* Current state flags */
|
// Current state flags
|
||||||
SDL_AtomicInt shutdown;
|
SDL_AtomicInt shutdown;
|
||||||
SDL_AtomicInt enabled;
|
SDL_AtomicInt enabled;
|
||||||
SDL_bool is_spec_set;
|
SDL_bool is_spec_set;
|
||||||
|
|
||||||
/* A mutex for locking the queue buffers */
|
// A mutex for locking the queue buffers
|
||||||
SDL_Mutex *device_lock;
|
SDL_Mutex *device_lock;
|
||||||
SDL_Mutex *acquiring_lock;
|
SDL_Mutex *acquiring_lock;
|
||||||
|
|
||||||
/* A thread to feed the camera device */
|
// A thread to feed the camera device
|
||||||
SDL_Thread *thread;
|
SDL_Thread *thread;
|
||||||
SDL_ThreadID threadid;
|
SDL_ThreadID threadid;
|
||||||
|
|
||||||
/* Queued buffers (if app not using callback). */
|
// Queued buffers (if app not using callback).
|
||||||
SDL_ListNode *buffer_queue;
|
SDL_ListNode *buffer_queue;
|
||||||
|
|
||||||
/* * * */
|
// Data private to this driver
|
||||||
/* Data private to this driver */
|
|
||||||
struct SDL_PrivateCameraData *hidden;
|
struct SDL_PrivateCameraData *hidden;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int SDL_SYS_CameraInit(void);
|
extern int SDL_SYS_CameraInit(void);
|
||||||
extern int SDL_SYS_CameraQuit(void);
|
extern int SDL_SYS_CameraQuit(void);
|
||||||
|
|
||||||
|
// !!! FIXME: These names need to be made camera-specific.
|
||||||
|
|
||||||
extern int OpenDevice(SDL_CameraDevice *_this);
|
extern int OpenDevice(SDL_CameraDevice *_this);
|
||||||
extern void CloseDevice(SDL_CameraDevice *_this);
|
extern void CloseDevice(SDL_CameraDevice *_this);
|
||||||
|
|
||||||
|
@ -86,7 +84,7 @@ extern int GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *
|
||||||
extern int GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size);
|
extern int GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size);
|
||||||
extern SDL_CameraDeviceID *GetCameraDevices(int *count);
|
extern SDL_CameraDeviceID *GetCameraDevices(int *count);
|
||||||
|
|
||||||
extern SDL_bool check_all_device_closed(void);
|
extern SDL_bool CheckAllDeviceClosed(void);
|
||||||
extern SDL_bool check_device_playing(void);
|
extern SDL_bool CheckDevicePlaying(void);
|
||||||
|
|
||||||
#endif /* SDL_syscamera_h_ */
|
#endif // SDL_syscamera_h_
|
||||||
|
|
|
@ -62,8 +62,7 @@
|
||||||
static ACameraManager *cameraMgr = NULL;
|
static ACameraManager *cameraMgr = NULL;
|
||||||
static ACameraIdList *cameraIdList = NULL;
|
static ACameraIdList *cameraIdList = NULL;
|
||||||
|
|
||||||
static void
|
static void create_cameraMgr(void)
|
||||||
create_cameraMgr(void)
|
|
||||||
{
|
{
|
||||||
if (cameraMgr == NULL) {
|
if (cameraMgr == NULL) {
|
||||||
#if 0 // !!! FIXME: this is getting replaced in a different branch.
|
#if 0 // !!! FIXME: this is getting replaced in a different branch.
|
||||||
|
@ -81,8 +80,7 @@ create_cameraMgr(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void delete_cameraMgr(void)
|
||||||
delete_cameraMgr(void)
|
|
||||||
{
|
{
|
||||||
if (cameraIdList) {
|
if (cameraIdList) {
|
||||||
ACameraManager_deleteCameraIdList(cameraIdList);
|
ACameraManager_deleteCameraIdList(cameraIdList);
|
||||||
|
@ -104,50 +102,46 @@ struct SDL_PrivateCameraData
|
||||||
ACaptureSessionOutputContainer *sessionOutputContainer;
|
ACaptureSessionOutputContainer *sessionOutputContainer;
|
||||||
AImageReader *reader;
|
AImageReader *reader;
|
||||||
int num_formats;
|
int num_formats;
|
||||||
int count_formats[6]; // see format_2_id
|
int count_formats[6]; // see format_to_id
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**/
|
|
||||||
#define FORMAT_SDL SDL_PIXELFORMAT_NV12
|
#define FORMAT_SDL SDL_PIXELFORMAT_NV12
|
||||||
|
|
||||||
static int
|
static int format_to_id(int fmt) {
|
||||||
format_2_id(int fmt) {
|
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
#define CASE(x, y) case x: return y
|
#define CASE(x, y) case x: return y
|
||||||
CASE(FORMAT_SDL, 0);
|
CASE(FORMAT_SDL, 0);
|
||||||
CASE(SDL_PIXELFORMAT_RGB565, 1);
|
CASE(SDL_PIXELFORMAT_RGB565, 1);
|
||||||
CASE(SDL_PIXELFORMAT_XRGB8888, 2);
|
CASE(SDL_PIXELFORMAT_XRGB8888, 2);
|
||||||
CASE(SDL_PIXELFORMAT_RGBA8888, 3);
|
CASE(SDL_PIXELFORMAT_RGBA8888, 3);
|
||||||
CASE(SDL_PIXELFORMAT_RGBX8888, 4);
|
CASE(SDL_PIXELFORMAT_RGBX8888, 4);
|
||||||
CASE(SDL_PIXELFORMAT_UNKNOWN, 5);
|
CASE(SDL_PIXELFORMAT_UNKNOWN, 5);
|
||||||
#undef CASE
|
#undef CASE
|
||||||
default:
|
default:
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int id_to_format(int fmt) {
|
||||||
id_2_format(int fmt) {
|
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
#define CASE(x, y) case y: return x
|
#define CASE(x, y) case y: return x
|
||||||
CASE(FORMAT_SDL, 0);
|
CASE(FORMAT_SDL, 0);
|
||||||
CASE(SDL_PIXELFORMAT_RGB565, 1);
|
CASE(SDL_PIXELFORMAT_RGB565, 1);
|
||||||
CASE(SDL_PIXELFORMAT_XRGB8888, 2);
|
CASE(SDL_PIXELFORMAT_XRGB8888, 2);
|
||||||
CASE(SDL_PIXELFORMAT_RGBA8888, 3);
|
CASE(SDL_PIXELFORMAT_RGBA8888, 3);
|
||||||
CASE(SDL_PIXELFORMAT_RGBX8888, 4);
|
CASE(SDL_PIXELFORMAT_RGBX8888, 4);
|
||||||
CASE(SDL_PIXELFORMAT_UNKNOWN, 5);
|
CASE(SDL_PIXELFORMAT_UNKNOWN, 5);
|
||||||
#undef CASE
|
#undef CASE
|
||||||
default:
|
default:
|
||||||
return SDL_PIXELFORMAT_UNKNOWN;
|
return SDL_PIXELFORMAT_UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint32
|
static Uint32 format_android_to_sdl(Uint32 fmt)
|
||||||
format_android_2_sdl(Uint32 fmt)
|
|
||||||
{
|
{
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
#define CASE(x, y) case x: return y
|
#define CASE(x, y) case x: return y
|
||||||
CASE(AIMAGE_FORMAT_YUV_420_888, FORMAT_SDL);
|
CASE(AIMAGE_FORMAT_YUV_420_888, FORMAT_SDL);
|
||||||
CASE(AIMAGE_FORMAT_RGB_565, SDL_PIXELFORMAT_RGB565);
|
CASE(AIMAGE_FORMAT_RGB_565, SDL_PIXELFORMAT_RGB565);
|
||||||
CASE(AIMAGE_FORMAT_RGB_888, SDL_PIXELFORMAT_XRGB8888);
|
CASE(AIMAGE_FORMAT_RGB_888, SDL_PIXELFORMAT_XRGB8888);
|
||||||
|
@ -157,71 +151,72 @@ format_android_2_sdl(Uint32 fmt)
|
||||||
CASE(AIMAGE_FORMAT_RGBA_FP16, SDL_PIXELFORMAT_UNKNOWN); // 64bits
|
CASE(AIMAGE_FORMAT_RGBA_FP16, SDL_PIXELFORMAT_UNKNOWN); // 64bits
|
||||||
CASE(AIMAGE_FORMAT_RAW_PRIVATE, SDL_PIXELFORMAT_UNKNOWN);
|
CASE(AIMAGE_FORMAT_RAW_PRIVATE, SDL_PIXELFORMAT_UNKNOWN);
|
||||||
CASE(AIMAGE_FORMAT_JPEG, SDL_PIXELFORMAT_UNKNOWN);
|
CASE(AIMAGE_FORMAT_JPEG, SDL_PIXELFORMAT_UNKNOWN);
|
||||||
#undef CASE
|
#undef CASE
|
||||||
default:
|
default:
|
||||||
SDL_Log("Unknown format AIMAGE_FORMAT '%d'", fmt);
|
SDL_Log("Unknown format AIMAGE_FORMAT '%d'", fmt);
|
||||||
return SDL_PIXELFORMAT_UNKNOWN;
|
return SDL_PIXELFORMAT_UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint32
|
static Uint32 format_sdl_to_android(Uint32 fmt)
|
||||||
format_sdl_2_android(Uint32 fmt)
|
|
||||||
{
|
{
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
#define CASE(x, y) case y: return x
|
#define CASE(x, y) case y: return x
|
||||||
CASE(AIMAGE_FORMAT_YUV_420_888, FORMAT_SDL);
|
CASE(AIMAGE_FORMAT_YUV_420_888, FORMAT_SDL);
|
||||||
CASE(AIMAGE_FORMAT_RGB_565, SDL_PIXELFORMAT_RGB565);
|
CASE(AIMAGE_FORMAT_RGB_565, SDL_PIXELFORMAT_RGB565);
|
||||||
CASE(AIMAGE_FORMAT_RGB_888, SDL_PIXELFORMAT_XRGB8888);
|
CASE(AIMAGE_FORMAT_RGB_888, SDL_PIXELFORMAT_XRGB8888);
|
||||||
CASE(AIMAGE_FORMAT_RGBA_8888, SDL_PIXELFORMAT_RGBA8888);
|
CASE(AIMAGE_FORMAT_RGBA_8888, SDL_PIXELFORMAT_RGBA8888);
|
||||||
CASE(AIMAGE_FORMAT_RGBX_8888, SDL_PIXELFORMAT_RGBX8888);
|
CASE(AIMAGE_FORMAT_RGBX_8888, SDL_PIXELFORMAT_RGBX8888);
|
||||||
#undef CASE
|
#undef CASE
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void onDisconnected(void *context, ACameraDevice *device)
|
||||||
onDisconnected(void *context, ACameraDevice *device)
|
|
||||||
{
|
{
|
||||||
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
|
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
|
||||||
|
#if DEBUG_CAMERA
|
||||||
SDL_Log("CB onDisconnected");
|
SDL_Log("CB onDisconnected");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void onError(void *context, ACameraDevice *device, int error)
|
||||||
onError(void *context, ACameraDevice *device, int error)
|
|
||||||
{
|
{
|
||||||
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
|
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
|
||||||
|
#if DEBUG_CAMERA
|
||||||
SDL_Log("CB onError");
|
SDL_Log("CB onError");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void onClosed(void* context, ACameraCaptureSession *session)
|
||||||
onClosed(void* context, ACameraCaptureSession *session)
|
|
||||||
{
|
{
|
||||||
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
|
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
|
||||||
|
#if DEBUG_CAMERA
|
||||||
SDL_Log("CB onClosed");
|
SDL_Log("CB onClosed");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void onReady(void* context, ACameraCaptureSession *session)
|
||||||
onReady(void* context, ACameraCaptureSession *session)
|
|
||||||
{
|
{
|
||||||
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
|
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
|
||||||
|
#if DEBUG_CAMERA
|
||||||
SDL_Log("CB onReady");
|
SDL_Log("CB onReady");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void onActive(void* context, ACameraCaptureSession *session)
|
||||||
onActive(void* context, ACameraCaptureSession *session)
|
|
||||||
{
|
{
|
||||||
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
|
// SDL_CameraDevice *_this = (SDL_CameraDevice *) context;
|
||||||
|
#if DEBUG_CAMERA
|
||||||
SDL_Log("CB onActive");
|
SDL_Log("CB onActive");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int OpenDevice(SDL_CameraDevice *_this)
|
||||||
OpenDevice(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
camera_status_t res;
|
|
||||||
|
|
||||||
/* Cannot open a second camera, while the first one is opened.
|
/* Cannot open a second camera, while the first one is opened.
|
||||||
* If you want to play several camera, they must all be opened first, then played.
|
* If you want to play several camera, they must all be opened first, then played.
|
||||||
*
|
*
|
||||||
|
@ -230,7 +225,7 @@ OpenDevice(SDL_CameraDevice *_this)
|
||||||
* before configuring sessions on any of the camera devices. * "
|
* before configuring sessions on any of the camera devices. * "
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
if (check_device_playing()) {
|
if (CheckDevicePlaying()) {
|
||||||
return SDL_SetError("A camera is already playing");
|
return SDL_SetError("A camera is already playing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +240,7 @@ OpenDevice(SDL_CameraDevice *_this)
|
||||||
_this->hidden->dev_callbacks.onDisconnected = onDisconnected;
|
_this->hidden->dev_callbacks.onDisconnected = onDisconnected;
|
||||||
_this->hidden->dev_callbacks.onError = onError;
|
_this->hidden->dev_callbacks.onError = onError;
|
||||||
|
|
||||||
res = ACameraManager_openCamera(cameraMgr, _this->dev_name, &_this->hidden->dev_callbacks, &_this->hidden->device);
|
camera_status_t res = ACameraManager_openCamera(cameraMgr, _this->dev_name, &_this->hidden->dev_callbacks, &_this->hidden->device);
|
||||||
if (res != ACAMERA_OK) {
|
if (res != ACAMERA_OK) {
|
||||||
return SDL_SetError("Failed to open camera");
|
return SDL_SetError("Failed to open camera");
|
||||||
}
|
}
|
||||||
|
@ -253,8 +248,7 @@ OpenDevice(SDL_CameraDevice *_this)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void CloseDevice(SDL_CameraDevice *_this)
|
||||||
CloseDevice(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
if (_this && _this->hidden) {
|
if (_this && _this->hidden) {
|
||||||
if (_this->hidden->session) {
|
if (_this->hidden->session) {
|
||||||
|
@ -278,13 +272,13 @@ CloseDevice(SDL_CameraDevice *_this)
|
||||||
_this->hidden = NULL;
|
_this->hidden = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_all_device_closed()) {
|
// !!! FIXME: just refcount this?
|
||||||
|
if (CheckAllDeviceClosed()) {
|
||||||
delete_cameraMgr();
|
delete_cameraMgr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int InitDevice(SDL_CameraDevice *_this)
|
||||||
InitDevice(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
size_t size, pitch;
|
size_t size, pitch;
|
||||||
SDL_CalculateSize(_this->spec.format, _this->spec.width, _this->spec.height, &size, &pitch, SDL_FALSE);
|
SDL_CalculateSize(_this->spec.format, _this->spec.width, _this->spec.height, &size, &pitch, SDL_FALSE);
|
||||||
|
@ -292,19 +286,19 @@ InitDevice(SDL_CameraDevice *_this)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int GetDeviceSpec(SDL_CameraDevice *_this, SDL_CameraSpec *spec)
|
||||||
GetDeviceSpec(SDL_CameraDevice *_this, SDL_CameraSpec *spec)
|
|
||||||
{
|
{
|
||||||
|
// !!! FIXME: catch NULLs at higher level
|
||||||
if (spec) {
|
if (spec) {
|
||||||
*spec = _this->spec;
|
SDL_copyp(spec, &_this->spec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int StartCamera(SDL_CameraDevice *_this)
|
||||||
StartCamera(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
|
// !!! FIXME: maybe log the error code in SDL_SetError
|
||||||
camera_status_t res;
|
camera_status_t res;
|
||||||
media_status_t res2;
|
media_status_t res2;
|
||||||
ANativeWindow *window = NULL;
|
ANativeWindow *window = NULL;
|
||||||
|
@ -312,7 +306,7 @@ StartCamera(SDL_CameraDevice *_this)
|
||||||
ACameraOutputTarget *outputTarget;
|
ACameraOutputTarget *outputTarget;
|
||||||
ACaptureRequest *request;
|
ACaptureRequest *request;
|
||||||
|
|
||||||
res2 = AImageReader_new(_this->spec.width, _this->spec.height, format_sdl_2_android(_this->spec.format), 10 /* nb buffers */, &_this->hidden->reader);
|
res2 = AImageReader_new(_this->spec.width, _this->spec.height, format_sdl_to_android(_this->spec.format), 10 /* nb buffers */, &_this->hidden->reader);
|
||||||
if (res2 != AMEDIA_OK) {
|
if (res2 != AMEDIA_OK) {
|
||||||
SDL_SetError("Error AImageReader_new");
|
SDL_SetError("Error AImageReader_new");
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -321,10 +315,8 @@ StartCamera(SDL_CameraDevice *_this)
|
||||||
if (res2 != AMEDIA_OK) {
|
if (res2 != AMEDIA_OK) {
|
||||||
SDL_SetError("Error AImageReader_new");
|
SDL_SetError("Error AImageReader_new");
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
res = ACaptureSessionOutput_create(window, &sessionOutput);
|
res = ACaptureSessionOutput_create(window, &sessionOutput);
|
||||||
if (res != ACAMERA_OK) {
|
if (res != ACAMERA_OK) {
|
||||||
SDL_SetError("Error ACaptureSessionOutput_create");
|
SDL_SetError("Error ACaptureSessionOutput_create");
|
||||||
|
@ -341,14 +333,12 @@ StartCamera(SDL_CameraDevice *_this)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
res = ACameraOutputTarget_create(window, &outputTarget);
|
res = ACameraOutputTarget_create(window, &outputTarget);
|
||||||
if (res != ACAMERA_OK) {
|
if (res != ACAMERA_OK) {
|
||||||
SDL_SetError("Error ACameraOutputTarget_create");
|
SDL_SetError("Error ACameraOutputTarget_create");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
res = ACameraDevice_createCaptureRequest(_this->hidden->device, TEMPLATE_RECORD, &request);
|
res = ACameraDevice_createCaptureRequest(_this->hidden->device, TEMPLATE_RECORD, &request);
|
||||||
if (res != ACAMERA_OK) {
|
if (res != ACAMERA_OK) {
|
||||||
SDL_SetError("Error ACameraDevice_createCaptureRequest");
|
SDL_SetError("Error ACameraDevice_createCaptureRequest");
|
||||||
|
@ -361,7 +351,6 @@ StartCamera(SDL_CameraDevice *_this)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_this->hidden->capture_callbacks.context = (void *) _this;
|
_this->hidden->capture_callbacks.context = (void *) _this;
|
||||||
_this->hidden->capture_callbacks.onClosed = onClosed;
|
_this->hidden->capture_callbacks.onClosed = onClosed;
|
||||||
_this->hidden->capture_callbacks.onReady = onReady;
|
_this->hidden->capture_callbacks.onReady = onReady;
|
||||||
|
@ -388,16 +377,14 @@ error:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int StopCamera(SDL_CameraDevice *_this)
|
||||||
StopCamera(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
ACameraCaptureSession_close(_this->hidden->session);
|
ACameraCaptureSession_close(_this->hidden->session);
|
||||||
_this->hidden->session = NULL;
|
_this->hidden->session = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
|
||||||
{
|
{
|
||||||
media_status_t res;
|
media_status_t res;
|
||||||
AImage *image;
|
AImage *image;
|
||||||
|
@ -406,20 +393,17 @@ AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
res = AImageReader_acquireLatestImage(_this->hidden->reader, &image);
|
res = AImageReader_acquireLatestImage(_this->hidden->reader, &image);
|
||||||
*/
|
*/
|
||||||
if (res == AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE ) {
|
if (res == AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE ) {
|
||||||
|
|
||||||
SDL_Delay(20); // TODO fix some delay
|
SDL_Delay(20); // TODO fix some delay
|
||||||
#if DEBUG_CAMERA
|
#if DEBUG_CAMERA
|
||||||
// SDL_Log("AImageReader_acquireNextImage: AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE");
|
//SDL_Log("AImageReader_acquireNextImage: AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE");
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
|
||||||
} else if (res == AMEDIA_OK ) {
|
} else if (res == AMEDIA_OK ) {
|
||||||
int i = 0;
|
|
||||||
int32_t numPlanes = 0;
|
int32_t numPlanes = 0;
|
||||||
AImage_getNumberOfPlanes(image, &numPlanes);
|
AImage_getNumberOfPlanes(image, &numPlanes);
|
||||||
|
|
||||||
frame->timestampNS = SDL_GetTicksNS();
|
frame->timestampNS = SDL_GetTicksNS();
|
||||||
|
|
||||||
for (i = 0; i < numPlanes && i < 3; i++) {
|
for (int i = 0; i < numPlanes && i < 3; i++) {
|
||||||
int dataLength = 0;
|
int dataLength = 0;
|
||||||
int rowStride = 0;
|
int rowStride = 0;
|
||||||
uint8_t *data = NULL;
|
uint8_t *data = NULL;
|
||||||
|
@ -442,18 +426,16 @@ AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->internal = (void*)image;
|
frame->internal = (void*)image;
|
||||||
return 0;
|
|
||||||
} else if (res == AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED) {
|
} else if (res == AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED) {
|
||||||
SDL_SetError("AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED");
|
return SDL_SetError("AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED");
|
||||||
} else {
|
} else {
|
||||||
SDL_SetError("AImageReader_acquireNextImage: %d", res);
|
return SDL_SetError("AImageReader_acquireNextImage: %d", res);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int ReleaseFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
ReleaseFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
|
||||||
{
|
{
|
||||||
if (frame->internal){
|
if (frame->internal){
|
||||||
AImage_delete((AImage *)frame->internal);
|
AImage_delete((AImage *)frame->internal);
|
||||||
|
@ -461,12 +443,10 @@ ReleaseFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int GetNumFormats(SDL_CameraDevice *_this)
|
||||||
GetNumFormats(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
camera_status_t res;
|
camera_status_t res;
|
||||||
int i;
|
SDL_bool unknown = SDL_FALSE;
|
||||||
int unknown = 0;
|
|
||||||
ACameraMetadata *metadata;
|
ACameraMetadata *metadata;
|
||||||
ACameraMetadata_const_entry entry;
|
ACameraMetadata_const_entry entry;
|
||||||
|
|
||||||
|
@ -486,34 +466,33 @@ GetNumFormats(SDL_CameraDevice *_this)
|
||||||
|
|
||||||
SDL_Log("got entry ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS");
|
SDL_Log("got entry ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS");
|
||||||
|
|
||||||
for (i = 0; i < entry.count; i += 4) {
|
for (int i = 0; i < entry.count; i += 4) {
|
||||||
int32_t format = entry.data.i32[i + 0];
|
const int32_t format = entry.data.i32[i + 0];
|
||||||
int32_t type = entry.data.i32[i + 3];
|
const int32_t type = entry.data.i32[i + 3];
|
||||||
Uint32 fmt;
|
|
||||||
|
|
||||||
if (type == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
|
if (type == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt = format_android_2_sdl(format);
|
const Uint32 fmt = format_android_to_sdl(format);
|
||||||
_this->hidden->count_formats[format_2_id(fmt)] += 1;
|
_this->hidden->count_formats[format_to_id(fmt)] += 1;
|
||||||
|
|
||||||
#if DEBUG_CAMERA
|
#if DEBUG_CAMERA
|
||||||
if (fmt != SDL_PIXELFORMAT_UNKNOWN) {
|
if (fmt != SDL_PIXELFORMAT_UNKNOWN) {
|
||||||
int w = entry.data.i32[i + 1];
|
int w = entry.data.i32[i + 1];
|
||||||
int h = entry.data.i32[i + 2];
|
int h = entry.data.i32[i + 2];
|
||||||
SDL_Log("Got format android 0x%08x -> %s %d x %d", format, SDL_GetPixelFormatName(fmt), w, h);
|
SDL_Log("Got format android 0x%08x -> %s %d x %d", format, SDL_GetPixelFormatName(fmt), w, h);
|
||||||
} else {
|
} else {
|
||||||
unknown += 1;
|
unknown = SDL_TRUE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_CAMERA
|
#if DEBUG_CAMERA
|
||||||
if (unknown) {
|
if (unknown) {
|
||||||
SDL_Log("Got unknown android");
|
SDL_Log("Got unknown android");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
if ( _this->hidden->count_formats[0]) _this->hidden->num_formats += 1;
|
if ( _this->hidden->count_formats[0]) _this->hidden->num_formats += 1;
|
||||||
|
@ -526,10 +505,8 @@ GetNumFormats(SDL_CameraDevice *_this)
|
||||||
return _this->hidden->num_formats;
|
return _this->hidden->num_formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int GetFormat(SDL_CameraDevice *_this, int index, Uint32 *format)
|
||||||
GetFormat(SDL_CameraDevice *_this, int index, Uint32 *format)
|
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int i2 = 0;
|
int i2 = 0;
|
||||||
|
|
||||||
if (_this->hidden->num_formats == 0) {
|
if (_this->hidden->num_formats == 0) {
|
||||||
|
@ -537,16 +514,17 @@ GetFormat(SDL_CameraDevice *_this, int index, Uint32 *format)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < 0 || index >= _this->hidden->num_formats) {
|
if (index < 0 || index >= _this->hidden->num_formats) {
|
||||||
|
// !!! FIXME: call SDL_SetError()?
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < SDL_arraysize(_this->hidden->count_formats); i++) {
|
for (int i = 0; i < SDL_arraysize(_this->hidden->count_formats); i++) {
|
||||||
if (_this->hidden->count_formats[i] == 0) {
|
if (_this->hidden->count_formats[i] == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2 == index) {
|
if (i2 == index) {
|
||||||
*format = id_2_format(i);
|
*format = id_to_format(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
i2++;
|
i2++;
|
||||||
|
@ -555,17 +533,17 @@ GetFormat(SDL_CameraDevice *_this, int index, Uint32 *format)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int GetNumFrameSizes(SDL_CameraDevice *_this, Uint32 format)
|
||||||
GetNumFrameSizes(SDL_CameraDevice *_this, Uint32 format)
|
|
||||||
{
|
{
|
||||||
int i, i2 = 0, index;
|
// !!! FIXME: call SDL_SetError()?
|
||||||
if (_this->hidden->num_formats == 0) {
|
if (_this->hidden->num_formats == 0) {
|
||||||
GetNumFormats(_this);
|
GetNumFormats(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
index = format_2_id(format);
|
const int index = format_to_id(format);
|
||||||
|
|
||||||
for (i = 0; i < SDL_arraysize(_this->hidden->count_formats); i++) {
|
int i2 = 0;
|
||||||
|
for (int i = 0; i < SDL_arraysize(_this->hidden->count_formats); i++) {
|
||||||
if (_this->hidden->count_formats[i] == 0) {
|
if (_this->hidden->count_formats[i] == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -581,11 +559,10 @@ GetNumFrameSizes(SDL_CameraDevice *_this, Uint32 format)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *width, int *height)
|
||||||
GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *width, int *height)
|
|
||||||
{
|
{
|
||||||
|
// !!! FIXME: call SDL_SetError()?
|
||||||
camera_status_t res;
|
camera_status_t res;
|
||||||
int i, i2 = 0;
|
|
||||||
ACameraMetadata *metadata;
|
ACameraMetadata *metadata;
|
||||||
ACameraMetadata_const_entry entry;
|
ACameraMetadata_const_entry entry;
|
||||||
|
|
||||||
|
@ -603,19 +580,18 @@ GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *width, int
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < entry.count; i += 4) {
|
int i2 = 0;
|
||||||
|
for (int i = 0; i < entry.count; i += 4) {
|
||||||
int32_t f = entry.data.i32[i + 0];
|
int32_t f = entry.data.i32[i + 0];
|
||||||
int w = entry.data.i32[i + 1];
|
const int w = entry.data.i32[i + 1];
|
||||||
int h = entry.data.i32[i + 2];
|
const int h = entry.data.i32[i + 2];
|
||||||
int32_t type = entry.data.i32[i + 3];
|
int32_t type = entry.data.i32[i + 3];
|
||||||
Uint32 fmt;
|
|
||||||
|
|
||||||
if (type == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
|
if (type == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Uint32 fmt = format_android_to_sdl(f);
|
||||||
fmt = format_android_2_sdl(f);
|
|
||||||
if (fmt != format) {
|
if (fmt != format) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -628,33 +604,11 @@ GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *width, int
|
||||||
|
|
||||||
i2++;
|
i2++;
|
||||||
}
|
}
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int GetNumDevices(void);
|
|
||||||
|
|
||||||
int
|
|
||||||
GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size)
|
|
||||||
{
|
|
||||||
int index = instance_id - 1;
|
|
||||||
create_cameraMgr();
|
|
||||||
|
|
||||||
if (cameraIdList == NULL) {
|
|
||||||
GetNumDevices();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cameraIdList) {
|
|
||||||
if (index >= 0 && index < cameraIdList->numCameras) {
|
|
||||||
SDL_snprintf(buf, size, "%s", cameraIdList->cameraIds[index]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int GetNumDevices(void)
|
||||||
GetNumDevices(void)
|
|
||||||
{
|
{
|
||||||
camera_status_t res;
|
camera_status_t res;
|
||||||
create_cameraMgr();
|
create_cameraMgr();
|
||||||
|
@ -674,37 +628,55 @@ GetNumDevices(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size)
|
||||||
|
{
|
||||||
|
// !!! FIXME: call SDL_SetError()?
|
||||||
|
int index = instance_id - 1;
|
||||||
|
create_cameraMgr();
|
||||||
|
|
||||||
|
if (cameraIdList == NULL) {
|
||||||
|
GetNumDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cameraIdList) {
|
||||||
|
if (index >= 0 && index < cameraIdList->numCameras) {
|
||||||
|
SDL_snprintf(buf, size, "%s", cameraIdList->cameraIds[index]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_CameraDeviceID *GetCameraDevices(int *count)
|
SDL_CameraDeviceID *GetCameraDevices(int *count)
|
||||||
{
|
{
|
||||||
/* hard-coded list of ID */
|
// hard-coded list of ID
|
||||||
int i;
|
const int num = GetNumDevices();
|
||||||
int num = GetNumDevices();
|
SDL_CameraDeviceID *retval = (SDL_CameraDeviceID *)SDL_malloc((num + 1) * sizeof(*ret));
|
||||||
SDL_CameraDeviceID *ret;
|
|
||||||
|
|
||||||
ret = (SDL_CameraDeviceID *)SDL_malloc((num + 1) * sizeof(*ret));
|
if (retval == NULL) {
|
||||||
|
|
||||||
if (ret == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
*count = 0;
|
*count = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
for (int i = 0; i < num; i++) {
|
||||||
ret[i] = i + 1;
|
retval[i] = i + 1;
|
||||||
}
|
}
|
||||||
ret[num] = 0;
|
retval[num] = 0;
|
||||||
*count = num;
|
*count = num;
|
||||||
return ret;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDL_SYS_CameraInit(void) {
|
int SDL_SYS_CameraInit(void)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SDL_SYS_CameraQuit(void) {
|
int SDL_SYS_CameraQuit(void)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Simple DirectMedia Layer
|
Simple DirectMedia Layer
|
||||||
Copyright (C) 2021 Valve Corporation
|
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
This software is provided 'as-is', without any express or implied
|
||||||
warranty. In no event will the authors be held liable for any damages
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
#include "../thread/SDL_systhread.h"
|
#include "../thread/SDL_systhread.h"
|
||||||
|
|
||||||
#if defined(HAVE_COREMEDIA) && defined(SDL_PLATFORM_MACOS) && (__MAC_OS_X_VERSION_MAX_ALLOWED < 101500)
|
#if defined(HAVE_COREMEDIA) && defined(SDL_PLATFORM_MACOS) && (__MAC_OS_X_VERSION_MAX_ALLOWED < 101500)
|
||||||
/* AVCaptureDeviceTypeBuiltInWideAngleCamera requires macOS SDK 10.15 */
|
// AVCaptureDeviceTypeBuiltInWideAngleCamera requires macOS SDK 10.15
|
||||||
#undef HAVE_COREMEDIA
|
#undef HAVE_COREMEDIA
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -35,7 +35,9 @@
|
||||||
#undef HAVE_COREMEDIA
|
#undef HAVE_COREMEDIA
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_COREMEDIA /* !!! FIXME: use the dummy driver. */
|
// !!! FIXME: use the dummy driver
|
||||||
|
// !!! FIXME: actually, move everything over to backend callbacks instead.
|
||||||
|
#ifndef HAVE_COREMEDIA
|
||||||
int InitDevice(SDL_CameraDevice *_this) {
|
int InitDevice(SDL_CameraDevice *_this) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -119,16 +121,14 @@ struct SDL_PrivateCameraData
|
||||||
CMSimpleQueueRef frame_queue;
|
CMSimpleQueueRef frame_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
static NSString *
|
static NSString *fourcc_to_nstring(Uint32 code)
|
||||||
fourcc_to_nstring(Uint32 code)
|
|
||||||
{
|
{
|
||||||
Uint8 buf[4];
|
Uint8 buf[4];
|
||||||
*(Uint32 *)buf = code;
|
*(Uint32 *)buf = code;
|
||||||
return [NSString stringWithFormat:@"%c%c%c%c", buf[3], buf[2], buf[1], buf[0]];
|
return [NSString stringWithFormat:@"%c%c%c%c", buf[3], buf[2], buf[1], buf[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
static NSArray<AVCaptureDevice *> *
|
static NSArray<AVCaptureDevice *> *DiscoverCameraDevices()
|
||||||
discover_devices()
|
|
||||||
{
|
{
|
||||||
NSArray *deviceType = @[AVCaptureDeviceTypeBuiltInWideAngleCamera];
|
NSArray *deviceType = @[AVCaptureDeviceTypeBuiltInWideAngleCamera];
|
||||||
|
|
||||||
|
@ -154,10 +154,9 @@ discover_devices()
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AVCaptureDevice *
|
static AVCaptureDevice *GetCameraDeviceByName(const char *dev_name)
|
||||||
get_device_by_name(const char *dev_name)
|
|
||||||
{
|
{
|
||||||
NSArray<AVCaptureDevice *> *devices = discover_devices();
|
NSArray<AVCaptureDevice *> *devices = DiscoverCameraDevices();
|
||||||
|
|
||||||
for (AVCaptureDevice *device in devices) {
|
for (AVCaptureDevice *device in devices) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
|
@ -171,45 +170,41 @@ get_device_by_name(const char *dev_name)
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint32
|
static Uint32 nsfourcc_to_sdlformat(NSString *nsfourcc)
|
||||||
nsfourcc_to_sdlformat(NSString *nsfourcc)
|
|
||||||
{
|
{
|
||||||
const char *str = [nsfourcc UTF8String];
|
const char *str = [nsfourcc UTF8String];
|
||||||
|
|
||||||
/* FIXME
|
/* FIXME
|
||||||
* on IOS this mode gives 2 planes, and it's NV12
|
* on IOS this mode gives 2 planes, and it's NV12
|
||||||
* on macos, 1 plane/ YVYU
|
* on macos, 1 plane/ YVYU
|
||||||
*
|
*/
|
||||||
*/
|
#ifdef SDL_PLATFORM_MACOS
|
||||||
#ifdef SDL_PLATFORM_MACOS
|
if (SDL_strcmp("420v", str) == 0) return SDL_PIXELFORMAT_YVYU;
|
||||||
if (SDL_strcmp("420v", str) == 0) return SDL_PIXELFORMAT_YVYU;
|
#else
|
||||||
#else
|
if (SDL_strcmp("420v", str) == 0) return SDL_PIXELFORMAT_NV12;
|
||||||
if (SDL_strcmp("420v", str) == 0) return SDL_PIXELFORMAT_NV12;
|
#endif
|
||||||
#endif
|
|
||||||
if (SDL_strcmp("yuvs", str) == 0) return SDL_PIXELFORMAT_UYVY;
|
|
||||||
if (SDL_strcmp("420f", str) == 0) return SDL_PIXELFORMAT_UNKNOWN;
|
|
||||||
|
|
||||||
SDL_Log("Unknown format '%s'", str);
|
if (SDL_strcmp("yuvs", str) == 0) return SDL_PIXELFORMAT_UYVY;
|
||||||
|
if (SDL_strcmp("420f", str) == 0) return SDL_PIXELFORMAT_UNKNOWN;
|
||||||
|
|
||||||
return SDL_PIXELFORMAT_UNKNOWN;
|
SDL_Log("Unknown format '%s'", str);
|
||||||
|
|
||||||
|
return SDL_PIXELFORMAT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NSString *
|
static NSString *sdlformat_to_nsfourcc(Uint32 fmt)
|
||||||
sdlformat_to_nsfourcc(Uint32 fmt)
|
|
||||||
{
|
{
|
||||||
const char *str = "";
|
const char *str = "";
|
||||||
NSString *result;
|
NSString *result;
|
||||||
|
|
||||||
#ifdef SDL_PLATFORM_MACOS
|
#ifdef SDL_PLATFORM_MACOS
|
||||||
if (fmt == SDL_PIXELFORMAT_YVYU) str = "420v";
|
if (fmt == SDL_PIXELFORMAT_YVYU) str = "420v";
|
||||||
#else
|
#else
|
||||||
if (fmt == SDL_PIXELFORMAT_NV12) str = "420v";
|
if (fmt == SDL_PIXELFORMAT_NV12) str = "420v";
|
||||||
#endif
|
#endif
|
||||||
if (fmt == SDL_PIXELFORMAT_UYVY) str = "yuvs";
|
if (fmt == SDL_PIXELFORMAT_UYVY) str = "yuvs";
|
||||||
|
|
||||||
result = [[NSString alloc] initWithUTF8String: str];
|
return [[NSString alloc] initWithUTF8String: str];
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -234,27 +229,21 @@ sdlformat_to_nsfourcc(Uint32 fmt)
|
||||||
- (void)captureOutput:(AVCaptureOutput *)output
|
- (void)captureOutput:(AVCaptureOutput *)output
|
||||||
didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
||||||
fromConnection:(AVCaptureConnection *)connection {
|
fromConnection:(AVCaptureConnection *)connection {
|
||||||
|
// !!! FIXME #if DEBUG_CAMERA
|
||||||
SDL_Log("Drop frame..");
|
SDL_Log("Drop frame..");
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
int
|
int OpenDevice(SDL_CameraDevice *_this)
|
||||||
OpenDevice(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
_this->hidden = (struct SDL_PrivateCameraData *) SDL_calloc(1, sizeof (struct SDL_PrivateCameraData));
|
_this->hidden = (struct SDL_PrivateCameraData *) SDL_calloc(1, sizeof (struct SDL_PrivateCameraData));
|
||||||
if (_this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void CloseDevice(SDL_CameraDevice *_this)
|
||||||
CloseDevice(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
if (!_this) {
|
if (!_this) {
|
||||||
return;
|
return;
|
||||||
|
@ -282,9 +271,9 @@ CloseDevice(SDL_CameraDevice *_this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int InitDevice(SDL_CameraDevice *_this)
|
||||||
InitDevice(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
|
// !!! FIXME: autorelease pool?
|
||||||
NSString *fmt = sdlformat_to_nsfourcc(_this->spec.format);
|
NSString *fmt = sdlformat_to_nsfourcc(_this->spec.format);
|
||||||
int w = _this->spec.width;
|
int w = _this->spec.width;
|
||||||
int h = _this->spec.height;
|
int h = _this->spec.height;
|
||||||
|
@ -298,13 +287,13 @@ InitDevice(SDL_CameraDevice *_this)
|
||||||
|
|
||||||
#ifdef SDL_PLATFORM_MACOS
|
#ifdef SDL_PLATFORM_MACOS
|
||||||
if (@available(macOS 10.15, *)) {
|
if (@available(macOS 10.15, *)) {
|
||||||
/* good. */
|
// good.
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
device = get_device_by_name(_this->dev_name);
|
device = GetCameraDeviceByName(_this->dev_name);
|
||||||
if (!device) {
|
if (!device) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -317,14 +306,13 @@ InitDevice(SDL_CameraDevice *_this)
|
||||||
[_this->hidden->session setSessionPreset:AVCaptureSessionPresetHigh];
|
[_this->hidden->session setSessionPreset:AVCaptureSessionPresetHigh];
|
||||||
|
|
||||||
// Pick format that matches the spec
|
// Pick format that matches the spec
|
||||||
{
|
NSArray<AVCaptureDeviceFormat *> *formats = [device formats];
|
||||||
NSArray<AVCaptureDeviceFormat *> *formats = [device formats];
|
for (AVCaptureDeviceFormat *format in formats) {
|
||||||
for (AVCaptureDeviceFormat *format in formats) {
|
CMFormatDescriptionRef formatDescription = [format formatDescription];
|
||||||
CMFormatDescriptionRef formatDescription = [format formatDescription];
|
FourCharCode mediaSubType = CMFormatDescriptionGetMediaSubType(formatDescription);
|
||||||
FourCharCode mediaSubType = CMFormatDescriptionGetMediaSubType(formatDescription);
|
NSString *str = fourcc_to_nstring(mediaSubType);
|
||||||
NSString *str = fourcc_to_nstring(mediaSubType);
|
if ([str isEqualToString:fmt]) {
|
||||||
if (str == fmt) {
|
CMVideoDimensions dim = CMVideoFormatDescriptionGetDimensions(formatDescription);
|
||||||
CMVideoDimensions dim = CMVideoFormatDescriptionGetDimensions(formatDescription);
|
|
||||||
if (dim.width == w && dim.height == h) {
|
if (dim.width == w && dim.height == h) {
|
||||||
spec_format = format;
|
spec_format = format;
|
||||||
break;
|
break;
|
||||||
|
@ -334,8 +322,7 @@ InitDevice(SDL_CameraDevice *_this)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spec_format == nil) {
|
if (spec_format == nil) {
|
||||||
SDL_SetError("format not found");
|
return SDL_SetError("format not found");
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set format
|
// Set format
|
||||||
|
@ -343,15 +330,13 @@ InitDevice(SDL_CameraDevice *_this)
|
||||||
device.activeFormat = spec_format;
|
device.activeFormat = spec_format;
|
||||||
[device unlockForConfiguration];
|
[device unlockForConfiguration];
|
||||||
} else {
|
} else {
|
||||||
SDL_SetError("Cannot lockForConfiguration");
|
return SDL_SetError("Cannot lockForConfiguration");
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
|
input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
|
||||||
if (!input) {
|
if (!input) {
|
||||||
SDL_SetError("Cannot create AVCaptureDeviceInput");
|
return SDL_SetError("Cannot create AVCaptureDeviceInput");
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output
|
// Output
|
||||||
|
@ -373,105 +358,85 @@ InitDevice(SDL_CameraDevice *_this)
|
||||||
|
|
||||||
CMSimpleQueueCreate(kCFAllocatorDefault, 30 /* buffers */, &_this->hidden->frame_queue);
|
CMSimpleQueueCreate(kCFAllocatorDefault, 30 /* buffers */, &_this->hidden->frame_queue);
|
||||||
if (_this->hidden->frame_queue == nil) {
|
if (_this->hidden->frame_queue == nil) {
|
||||||
goto error;
|
return SDL_SetError("CMSimpleQueueCreate() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
_this->hidden->queue = dispatch_queue_create("my_queue", NULL);
|
_this->hidden->queue = dispatch_queue_create("my_queue", NULL);
|
||||||
[output setSampleBufferDelegate:_this->hidden->delegate queue:_this->hidden->queue];
|
[output setSampleBufferDelegate:_this->hidden->delegate queue:_this->hidden->queue];
|
||||||
|
|
||||||
|
|
||||||
if ([_this->hidden->session canAddInput:input] ){
|
if ([_this->hidden->session canAddInput:input] ){
|
||||||
[_this->hidden->session addInput:input];
|
[_this->hidden->session addInput:input];
|
||||||
} else {
|
} else {
|
||||||
SDL_SetError("Cannot add AVCaptureDeviceInput");
|
return SDL_SetError("Cannot add AVCaptureDeviceInput");
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([_this->hidden->session canAddOutput:output] ){
|
if ([_this->hidden->session canAddOutput:output] ){
|
||||||
[_this->hidden->session addOutput:output];
|
[_this->hidden->session addOutput:output];
|
||||||
} else {
|
} else {
|
||||||
SDL_SetError("Cannot add AVCaptureVideoDataOutput");
|
return SDL_SetError("Cannot add AVCaptureVideoDataOutput");
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[_this->hidden->session commitConfiguration];
|
[_this->hidden->session commitConfiguration];
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int GetDeviceSpec(SDL_CameraDevice *_this, SDL_CameraSpec *spec)
|
||||||
GetDeviceSpec(SDL_CameraDevice *_this, SDL_CameraSpec *spec)
|
|
||||||
{
|
{
|
||||||
|
// !!! FIXME: make sure higher level checks spec != NULL
|
||||||
if (spec) {
|
if (spec) {
|
||||||
*spec = _this->spec;
|
SDL_copyp(spec, &_this->spec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int StartCamera(SDL_CameraDevice *_this)
|
||||||
StartCamera(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
[_this->hidden->session startRunning];
|
[_this->hidden->session startRunning];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int StopCamera(SDL_CameraDevice *_this)
|
||||||
StopCamera(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
[_this->hidden->session stopRunning];
|
[_this->hidden->session stopRunning];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
|
||||||
{
|
{
|
||||||
if (CMSimpleQueueGetCount(_this->hidden->frame_queue) > 0) {
|
if (CMSimpleQueueGetCount(_this->hidden->frame_queue) > 0) {
|
||||||
int i, numPlanes, planar;
|
CMSampleBufferRef sampleBuffer = (CMSampleBufferRef)CMSimpleQueueDequeue(_this->hidden->frame_queue);
|
||||||
CMSampleBufferRef sampleBuffer;
|
|
||||||
CVImageBufferRef image;
|
|
||||||
|
|
||||||
sampleBuffer = (CMSampleBufferRef)CMSimpleQueueDequeue(_this->hidden->frame_queue);
|
|
||||||
frame->internal = (void *) sampleBuffer;
|
frame->internal = (void *) sampleBuffer;
|
||||||
frame->timestampNS = SDL_GetTicksNS();
|
frame->timestampNS = SDL_GetTicksNS();
|
||||||
|
|
||||||
i = 0;
|
CVImageBufferRef image = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||||
image = CMSampleBufferGetImageBuffer(sampleBuffer);
|
const int numPlanes = CVPixelBufferGetPlaneCount(image);
|
||||||
numPlanes = CVPixelBufferGetPlaneCount(image);
|
const int planar = CVPixelBufferIsPlanar(image);
|
||||||
planar = CVPixelBufferIsPlanar(image);
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
int w = CVPixelBufferGetWidth(image);
|
const int w = CVPixelBufferGetWidth(image);
|
||||||
int h = CVPixelBufferGetHeight(image);
|
const int h = CVPixelBufferGetHeight(image);
|
||||||
int sz = CVPixelBufferGetDataSize(image);
|
const int sz = CVPixelBufferGetDataSize(image);
|
||||||
int pitch = CVPixelBufferGetBytesPerRow(image);
|
const int pitch = CVPixelBufferGetBytesPerRow(image);
|
||||||
SDL_Log("buffer planar=%d count:%d %d x %d sz=%d pitch=%d", planar, numPlanes, w, h, sz, pitch);
|
SDL_Log("buffer planar=%d count:%d %d x %d sz=%d pitch=%d", planar, numPlanes, w, h, sz, pitch);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CVPixelBufferLockBaseAddress(image, 0);
|
CVPixelBufferLockBaseAddress(image, 0);
|
||||||
|
|
||||||
if (planar == 0 && numPlanes == 0) {
|
if ((planar == 0) && (numPlanes == 0)) {
|
||||||
frame->pitch[0] = CVPixelBufferGetBytesPerRow(image);
|
frame->pitch[0] = CVPixelBufferGetBytesPerRow(image);
|
||||||
frame->data[0] = CVPixelBufferGetBaseAddress(image);
|
frame->data[0] = CVPixelBufferGetBaseAddress(image);
|
||||||
frame->num_planes = 1;
|
frame->num_planes = 1;
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < numPlanes && i < 3; i++) {
|
for (int i = 0; (i < numPlanes) && (i < 3); i++) {
|
||||||
int rowStride = 0;
|
|
||||||
uint8_t *data = NULL;
|
|
||||||
frame->num_planes += 1;
|
frame->num_planes += 1;
|
||||||
|
frame->data[i] = CVPixelBufferGetBaseAddressOfPlane(image, i);
|
||||||
rowStride = CVPixelBufferGetBytesPerRowOfPlane(image, i);
|
frame->pitch[i] = CVPixelBufferGetBytesPerRowOfPlane(image, i);
|
||||||
data = CVPixelBufferGetBaseAddressOfPlane(image, i);
|
|
||||||
frame->data[i] = data;
|
|
||||||
frame->pitch[i] = rowStride;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unlocked when frame is released */
|
// Unlocked when frame is released
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// no frame
|
// no frame
|
||||||
SDL_Delay(20); // TODO fix some delay
|
SDL_Delay(20); // TODO fix some delay
|
||||||
|
@ -479,24 +444,21 @@ AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int ReleaseFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
ReleaseFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
|
||||||
{
|
{
|
||||||
if (frame->internal){
|
if (frame->internal) {
|
||||||
CMSampleBufferRef sampleBuffer = (CMSampleBufferRef) frame->internal;
|
CMSampleBufferRef sampleBuffer = (CMSampleBufferRef) frame->internal;
|
||||||
|
|
||||||
CVImageBufferRef image = CMSampleBufferGetImageBuffer(sampleBuffer);
|
CVImageBufferRef image = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||||
CVPixelBufferUnlockBaseAddress(image, 0);
|
CVPixelBufferUnlockBaseAddress(image, 0);
|
||||||
|
|
||||||
CFRelease(sampleBuffer);
|
CFRelease(sampleBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int GetNumFormats(SDL_CameraDevice *_this)
|
||||||
GetNumFormats(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
AVCaptureDevice *device = get_device_by_name(_this->dev_name);
|
AVCaptureDevice *device = GetCameraDeviceByName(_this->dev_name);
|
||||||
if (device) {
|
if (device) {
|
||||||
// LIST FORMATS
|
// LIST FORMATS
|
||||||
NSMutableOrderedSet<NSString *> *array_formats = [NSMutableOrderedSet new];
|
NSMutableOrderedSet<NSString *> *array_formats = [NSMutableOrderedSet new];
|
||||||
|
@ -514,10 +476,9 @@ GetNumFormats(SDL_CameraDevice *_this)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int GetFormat(SDL_CameraDevice *_this, int index, Uint32 *format)
|
||||||
GetFormat(SDL_CameraDevice *_this, int index, Uint32 *format)
|
|
||||||
{
|
{
|
||||||
AVCaptureDevice *device = get_device_by_name(_this->dev_name);
|
AVCaptureDevice *device = GetCameraDeviceByName(_this->dev_name);
|
||||||
if (device) {
|
if (device) {
|
||||||
// LIST FORMATS
|
// LIST FORMATS
|
||||||
NSMutableOrderedSet<NSString *> *array_formats = [NSMutableOrderedSet new];
|
NSMutableOrderedSet<NSString *> *array_formats = [NSMutableOrderedSet new];
|
||||||
|
@ -542,10 +503,9 @@ GetFormat(SDL_CameraDevice *_this, int index, Uint32 *format)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int GetNumFrameSizes(SDL_CameraDevice *_this, Uint32 format)
|
||||||
GetNumFrameSizes(SDL_CameraDevice *_this, Uint32 format)
|
|
||||||
{
|
{
|
||||||
AVCaptureDevice *device = get_device_by_name(_this->dev_name);
|
AVCaptureDevice *device = GetCameraDeviceByName(_this->dev_name);
|
||||||
if (device) {
|
if (device) {
|
||||||
NSString *fmt = sdlformat_to_nsfourcc(format);
|
NSString *fmt = sdlformat_to_nsfourcc(format);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -556,8 +516,8 @@ GetNumFrameSizes(SDL_CameraDevice *_this, Uint32 format)
|
||||||
FourCharCode mediaSubType = CMFormatDescriptionGetMediaSubType(formatDescription);
|
FourCharCode mediaSubType = CMFormatDescriptionGetMediaSubType(formatDescription);
|
||||||
NSString *str = fourcc_to_nstring(mediaSubType);
|
NSString *str = fourcc_to_nstring(mediaSubType);
|
||||||
|
|
||||||
if (str == fmt) {
|
if ([str isEqualToString:fmt]) {
|
||||||
count += 1;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
|
@ -568,7 +528,7 @@ GetNumFrameSizes(SDL_CameraDevice *_this, Uint32 format)
|
||||||
int
|
int
|
||||||
GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *width, int *height)
|
GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *width, int *height)
|
||||||
{
|
{
|
||||||
AVCaptureDevice *device = get_device_by_name(_this->dev_name);
|
AVCaptureDevice *device = GetCameraDeviceByName(_this->dev_name);
|
||||||
if (device) {
|
if (device) {
|
||||||
NSString *fmt = sdlformat_to_nsfourcc(format);
|
NSString *fmt = sdlformat_to_nsfourcc(format);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -579,25 +539,24 @@ GetFrameSize(SDL_CameraDevice *_this, Uint32 format, int index, int *width, int
|
||||||
FourCharCode mediaSubType = CMFormatDescriptionGetMediaSubType(formatDescription);
|
FourCharCode mediaSubType = CMFormatDescriptionGetMediaSubType(formatDescription);
|
||||||
NSString *str = fourcc_to_nstring(mediaSubType);
|
NSString *str = fourcc_to_nstring(mediaSubType);
|
||||||
|
|
||||||
if (str == fmt) {
|
if ([str isEqualToString:fmt]) {
|
||||||
if (index == count) {
|
if (index == count) {
|
||||||
CMVideoDimensions dim = CMVideoFormatDescriptionGetDimensions(formatDescription);
|
CMVideoDimensions dim = CMVideoFormatDescriptionGetDimensions(formatDescription);
|
||||||
*width = dim.width;
|
*width = dim.width;
|
||||||
*height = dim.height;
|
*height = dim.height;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
count += 1;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size)
|
||||||
GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size)
|
|
||||||
{
|
{
|
||||||
int index = instance_id - 1;
|
int index = instance_id - 1;
|
||||||
NSArray<AVCaptureDevice *> *devices = discover_devices();
|
NSArray<AVCaptureDevice *> *devices = DiscoverCameraDevices();
|
||||||
if (index < [devices count]) {
|
if (index < [devices count]) {
|
||||||
AVCaptureDevice *device = devices[index];
|
AVCaptureDevice *device = devices[index];
|
||||||
NSString *cameraID = [device localizedName];
|
NSString *cameraID = [device localizedName];
|
||||||
|
@ -608,32 +567,28 @@ GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int GetNumDevices(void)
|
||||||
GetNumDevices(void)
|
|
||||||
{
|
{
|
||||||
NSArray<AVCaptureDevice *> *devices = discover_devices();
|
NSArray<AVCaptureDevice *> *devices = DiscoverCameraDevices();
|
||||||
return [devices count];
|
return [devices count];
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_CameraDeviceID *GetCameraDevices(int *count)
|
SDL_CameraDeviceID *GetCameraDevices(int *count)
|
||||||
{
|
{
|
||||||
/* hard-coded list of ID */
|
// hard-coded list of ID
|
||||||
int i;
|
const int num = GetNumDevices();
|
||||||
int num = GetNumDevices();
|
SDL_CameraDeviceID *retval = (SDL_CameraDeviceID *)SDL_calloc((num + 1), sizeof(*ret));
|
||||||
SDL_CameraDeviceID *ret;
|
|
||||||
|
|
||||||
ret = (SDL_CameraDeviceID *)SDL_malloc((num + 1) * sizeof(*ret));
|
if (retval == NULL) {
|
||||||
|
|
||||||
if (ret == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
*count = 0;
|
*count = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
for (int i = 0; i < num; i++) {
|
||||||
ret[i] = i + 1;
|
retval[i] = i + 1;
|
||||||
}
|
}
|
||||||
ret[num] = 0;
|
retval[num] = 0;
|
||||||
*count = num;
|
*count = num;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -648,7 +603,7 @@ int SDL_SYS_CameraQuit(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_COREMEDIA */
|
#endif // HAVE_COREMEDIA
|
||||||
|
|
||||||
#endif /* SDL_CAMERA_APPLE */
|
#endif // SDL_CAMERA_APPLE
|
||||||
|
|
||||||
|
|
|
@ -28,27 +28,25 @@
|
||||||
#include "../../thread/SDL_systhread.h"
|
#include "../../thread/SDL_systhread.h"
|
||||||
#include "../../core/linux/SDL_evdev_capabilities.h"
|
#include "../../core/linux/SDL_evdev_capabilities.h"
|
||||||
#include "../../core/linux/SDL_udev.h"
|
#include "../../core/linux/SDL_udev.h"
|
||||||
#include <limits.h> /* INT_MAX */
|
#include <limits.h> // INT_MAX
|
||||||
|
|
||||||
#define DEBUG_CAMERA 1
|
#define DEBUG_CAMERA 1
|
||||||
|
|
||||||
#define MAX_CAMERA_DEVICES 128 /* It's doubtful someone has more than that */
|
#define MAX_CAMERA_DEVICES 128 // It's doubtful someone has more than that
|
||||||
|
|
||||||
static int MaybeAddDevice(const char *path);
|
static int MaybeAddDevice(const char *path);
|
||||||
#ifdef SDL_USE_LIBUDEV
|
#ifdef SDL_USE_LIBUDEV
|
||||||
static int MaybeRemoveDevice(const char *path);
|
static int MaybeRemoveDevice(const char *path);
|
||||||
static void camera_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
|
static void CameraUdevCallback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
|
||||||
#endif /* SDL_USE_LIBUDEV */
|
#endif // SDL_USE_LIBUDEV
|
||||||
|
|
||||||
/*
|
// List of available camera devices.
|
||||||
* List of available camera devices.
|
|
||||||
*/
|
|
||||||
typedef struct SDL_cameralist_item
|
typedef struct SDL_cameralist_item
|
||||||
{
|
{
|
||||||
char *fname; /* Dev path name (like /dev/video0) */
|
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 */
|
char *bus_info; // don't add two paths with same bus_info (eg /dev/video0 and /dev/video1
|
||||||
SDL_CameraDeviceID instance_id;
|
SDL_CameraDeviceID instance_id;
|
||||||
SDL_CameraDevice *device; /* Associated device */
|
SDL_CameraDevice *device; // Associated device
|
||||||
struct SDL_cameralist_item *next;
|
struct SDL_cameralist_item *next;
|
||||||
} SDL_cameralist_item;
|
} SDL_cameralist_item;
|
||||||
|
|
||||||
|
@ -67,7 +65,7 @@ enum io_method {
|
||||||
struct buffer {
|
struct buffer {
|
||||||
void *start;
|
void *start;
|
||||||
size_t length;
|
size_t length;
|
||||||
int available; /* Is available in userspace */
|
int available; // Is available in userspace
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SDL_PrivateCameraData
|
struct SDL_PrivateCameraData
|
||||||
|
@ -82,34 +80,30 @@ struct SDL_PrivateCameraData
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <fcntl.h> /* low-level i/o */
|
#include <fcntl.h> // low-level i/o
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
static int
|
static int xioctl(int fh, int request, void *arg)
|
||||||
xioctl(int fh, int request, void *arg)
|
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
r = ioctl(fh, request, arg);
|
r = ioctl(fh, request, arg);
|
||||||
} while (r == -1 && errno == EINTR);
|
} while ((r == -1) && (errno == EINTR));
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -1:error 1:frame 0:no frame*/
|
// -1:error 1:frame 0:no frame
|
||||||
static int
|
static int acquire_frame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
acquire_frame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
|
||||||
{
|
{
|
||||||
struct v4l2_buffer buf;
|
const int fd = _this->hidden->fd;
|
||||||
int i;
|
|
||||||
|
|
||||||
int fd = _this->hidden->fd;
|
|
||||||
enum io_method io = _this->hidden->io;
|
enum io_method io = _this->hidden->io;
|
||||||
size_t size = _this->hidden->buffers[0].length;
|
size_t size = _this->hidden->buffers[0].length;
|
||||||
|
struct v4l2_buffer buf;
|
||||||
|
|
||||||
switch (io) {
|
switch (io) {
|
||||||
case IO_METHOD_READ:
|
case IO_METHOD_READ:
|
||||||
|
@ -119,9 +113,8 @@ acquire_frame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case EIO:
|
case EIO:
|
||||||
/* Could ignore EIO, see spec. */
|
// Could ignore EIO, see spec.
|
||||||
|
// fall through
|
||||||
/* fall through */
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return SDL_SetError("read");
|
return SDL_SetError("read");
|
||||||
|
@ -145,9 +138,8 @@ acquire_frame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case EIO:
|
case EIO:
|
||||||
/* Could ignore EIO, see spec. */
|
// Could ignore EIO, see spec.
|
||||||
|
// fall through
|
||||||
/* fall through */
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return SDL_SetError("VIDIOC_DQBUF: %d", errno);
|
return SDL_SetError("VIDIOC_DQBUF: %d", errno);
|
||||||
|
@ -180,15 +172,16 @@ acquire_frame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case EIO:
|
case EIO:
|
||||||
/* Could ignore EIO, see spec. */
|
// Could ignore EIO, see spec.
|
||||||
|
|
||||||
/* fall through */
|
// fall through
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return SDL_SetError("VIDIOC_DQBUF");
|
return SDL_SetError("VIDIOC_DQBUF");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
for (i = 0; i < _this->hidden->nb_buffers; ++i) {
|
for (i = 0; i < _this->hidden->nb_buffers; ++i) {
|
||||||
if (buf.m.userptr == (unsigned long)_this->hidden->buffers[i].start && buf.length == size) {
|
if (buf.m.userptr == (unsigned long)_this->hidden->buffers[i].start && buf.length == size) {
|
||||||
break;
|
break;
|
||||||
|
@ -213,13 +206,12 @@ acquire_frame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int ReleaseFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
ReleaseFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
|
||||||
{
|
{
|
||||||
struct v4l2_buffer buf;
|
struct v4l2_buffer buf;
|
||||||
int i;
|
const int fd = _this->hidden->fd;
|
||||||
int fd = _this->hidden->fd;
|
|
||||||
enum io_method io = _this->hidden->io;
|
enum io_method io = _this->hidden->io;
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < _this->hidden->nb_buffers; ++i) {
|
for (i = 0; i < _this->hidden->nb_buffers; ++i) {
|
||||||
if (frame->num_planes && frame->data[0] == _this->hidden->buffers[i].start) {
|
if (frame->num_planes && frame->data[0] == _this->hidden->buffers[i].start) {
|
||||||
|
@ -268,25 +260,23 @@ ReleaseFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
|
||||||
{
|
{
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
int ret;
|
|
||||||
|
|
||||||
int fd = _this->hidden->fd;
|
const int fd = _this->hidden->fd;
|
||||||
|
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(fd, &fds);
|
FD_SET(fd, &fds);
|
||||||
|
|
||||||
/* Timeout. */
|
// Timeout.
|
||||||
tv.tv_sec = 0;
|
tv.tv_sec = 0;
|
||||||
tv.tv_usec = 300 * 1000;
|
tv.tv_usec = 300 * 1000;
|
||||||
|
|
||||||
ret = select(fd + 1, &fds, NULL, NULL, &tv);
|
int retval = select(fd + 1, &fds, NULL, NULL, &tv);
|
||||||
|
|
||||||
if (ret == -1) {
|
if (retval == -1) {
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
#if DEBUG_CAMERA
|
#if DEBUG_CAMERA
|
||||||
SDL_Log("continue ..");
|
SDL_Log("continue ..");
|
||||||
|
@ -296,35 +286,34 @@ AcquireFrame(SDL_CameraDevice *_this, SDL_CameraFrame *frame)
|
||||||
return SDL_SetError("select");
|
return SDL_SetError("select");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0) {
|
if (retval == 0) {
|
||||||
/* Timeout. Not an error */
|
// Timeout. Not an error
|
||||||
SDL_SetError("timeout select");
|
SDL_SetError("timeout select");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = acquire_frame(_this, frame);
|
retval = acquire_frame(_this, frame);
|
||||||
if (ret < 0) {
|
if (retval < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 1){
|
if (retval == 1){
|
||||||
frame->timestampNS = SDL_GetTicksNS();
|
frame->timestampNS = SDL_GetTicksNS();
|
||||||
} else if (ret == 0) {
|
} else if (retval == 0) {
|
||||||
#if DEBUG_CAMERA
|
#if DEBUG_CAMERA
|
||||||
SDL_Log("No frame continue: %s", SDL_GetError());
|
SDL_Log("No frame continue: %s", SDL_GetError());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EAGAIN - continue select loop. */
|
// EAGAIN - continue select loop.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int StopCamera(SDL_CameraDevice *_this)
|
||||||
StopCamera(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
enum v4l2_buf_type type;
|
enum v4l2_buf_type type;
|
||||||
int fd = _this->hidden->fd;
|
const int fd = _this->hidden->fd;
|
||||||
enum io_method io = _this->hidden->io;
|
enum io_method io = _this->hidden->io;
|
||||||
|
|
||||||
switch (io) {
|
switch (io) {
|
||||||
|
@ -343,18 +332,16 @@ StopCamera(SDL_CameraDevice *_this)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int EnqueueBuffers(SDL_CameraDevice *_this)
|
||||||
enqueue_buffers(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
int i;
|
const int fd = _this->hidden->fd;
|
||||||
int fd = _this->hidden->fd;
|
|
||||||
enum io_method io = _this->hidden->io;
|
enum io_method io = _this->hidden->io;
|
||||||
switch (io) {
|
switch (io) {
|
||||||
case IO_METHOD_READ:
|
case IO_METHOD_READ:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IO_METHOD_MMAP:
|
case IO_METHOD_MMAP:
|
||||||
for (i = 0; i < _this->hidden->nb_buffers; ++i) {
|
for (int i = 0; i < _this->hidden->nb_buffers; ++i) {
|
||||||
if (_this->hidden->buffers[i].available == 0) {
|
if (_this->hidden->buffers[i].available == 0) {
|
||||||
struct v4l2_buffer buf;
|
struct v4l2_buffer buf;
|
||||||
|
|
||||||
|
@ -371,7 +358,7 @@ enqueue_buffers(SDL_CameraDevice *_this)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IO_METHOD_USERPTR:
|
case IO_METHOD_USERPTR:
|
||||||
for (i = 0; i < _this->hidden->nb_buffers; ++i) {
|
for (int i = 0; i < _this->hidden->nb_buffers; ++i) {
|
||||||
if (_this->hidden->buffers[i].available == 0) {
|
if (_this->hidden->buffers[i].available == 0) {
|
||||||
struct v4l2_buffer buf;
|
struct v4l2_buffer buf;
|
||||||
|
|
||||||
|
@ -392,11 +379,10 @@ enqueue_buffers(SDL_CameraDevice *_this)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int PreEnqueueBuffers(SDL_CameraDevice *_this)
|
||||||
pre_enqueue_buffers(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
struct v4l2_requestbuffers req;
|
struct v4l2_requestbuffers req;
|
||||||
int fd = _this->hidden->fd;
|
const int fd = _this->hidden->fd;
|
||||||
enum io_method io = _this->hidden->io;
|
enum io_method io = _this->hidden->io;
|
||||||
|
|
||||||
switch (io) {
|
switch (io) {
|
||||||
|
@ -404,41 +390,37 @@ pre_enqueue_buffers(SDL_CameraDevice *_this)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IO_METHOD_MMAP:
|
case IO_METHOD_MMAP:
|
||||||
{
|
SDL_zero(req);
|
||||||
SDL_zero(req);
|
req.count = _this->hidden->nb_buffers;
|
||||||
req.count = _this->hidden->nb_buffers;
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
req.memory = V4L2_MEMORY_MMAP;
|
||||||
req.memory = V4L2_MEMORY_MMAP;
|
|
||||||
|
|
||||||
if (xioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
|
if (xioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
|
||||||
if (errno == EINVAL) {
|
if (errno == EINVAL) {
|
||||||
return SDL_SetError("Does not support memory mapping");
|
return SDL_SetError("Does not support memory mapping");
|
||||||
} else {
|
} else {
|
||||||
return SDL_SetError("VIDIOC_REQBUFS");
|
return SDL_SetError("VIDIOC_REQBUFS");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.count < 2) {
|
|
||||||
return SDL_SetError("Insufficient buffer memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
_this->hidden->nb_buffers = req.count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req.count < 2) {
|
||||||
|
return SDL_SetError("Insufficient buffer memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
_this->hidden->nb_buffers = req.count;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IO_METHOD_USERPTR:
|
case IO_METHOD_USERPTR:
|
||||||
{
|
SDL_zero(req);
|
||||||
SDL_zero(req);
|
req.count = _this->hidden->nb_buffers;
|
||||||
req.count = _this->hidden->nb_buffers;
|
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
req.memory = V4L2_MEMORY_USERPTR;
|
||||||
req.memory = V4L2_MEMORY_USERPTR;
|
|
||||||
|
|
||||||
if (xioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
|
if (xioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
|
||||||
if (errno == EINVAL) {
|
if (errno == EINVAL) {
|
||||||
return SDL_SetError("Does not support user pointer i/o");
|
return SDL_SetError("Does not support user pointer i/o");
|
||||||
} else {
|
} else {
|
||||||
return SDL_SetError("VIDIOC_REQBUFS");
|
return SDL_SetError("VIDIOC_REQBUFS");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -446,34 +428,31 @@ pre_enqueue_buffers(SDL_CameraDevice *_this)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int StartCamera(SDL_CameraDevice *_this)
|
||||||
StartCamera(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
enum v4l2_buf_type type;
|
enum v4l2_buf_type type;
|
||||||
|
|
||||||
int fd = _this->hidden->fd;
|
const int fd = _this->hidden->fd;
|
||||||
enum io_method io = _this->hidden->io;
|
enum io_method io = _this->hidden->io;
|
||||||
|
|
||||||
|
|
||||||
if (_this->hidden->first_start == 0) {
|
if (_this->hidden->first_start == 0) {
|
||||||
_this->hidden->first_start = 1;
|
_this->hidden->first_start = 1;
|
||||||
} else {
|
} else {
|
||||||
int old = _this->hidden->nb_buffers;
|
const int old = _this->hidden->nb_buffers;
|
||||||
// TODO mmap; doesn't work with stop->start
|
// TODO mmap; doesn't work with stop->start
|
||||||
#if 1
|
#if 1
|
||||||
/* Can change nb_buffers for mmap */
|
// Can change nb_buffers for mmap
|
||||||
if (pre_enqueue_buffers(_this) < 0) {
|
if (PreEnqueueBuffers(_this) < 0) {
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (old != _this->hidden->nb_buffers) {
|
|
||||||
SDL_SetError("different nb of buffers requested");
|
|
||||||
return -1;
|
return -1;
|
||||||
|
} else if (old != _this->hidden->nb_buffers) {
|
||||||
|
return SDL_SetError("different nb of buffers requested");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
_this->hidden->first_start = 1;
|
_this->hidden->first_start = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enqueue_buffers(_this) < 0) {
|
if (EnqueueBuffers(_this) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,7 +472,7 @@ StartCamera(SDL_CameraDevice *_this)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alloc_buffer_read(SDL_CameraDevice *_this, size_t buffer_size)
|
static int AllocBufferRead(SDL_CameraDevice *_this, size_t buffer_size)
|
||||||
{
|
{
|
||||||
_this->hidden->buffers[0].length = buffer_size;
|
_this->hidden->buffers[0].length = buffer_size;
|
||||||
_this->hidden->buffers[0].start = SDL_calloc(1, buffer_size);
|
_this->hidden->buffers[0].start = SDL_calloc(1, buffer_size);
|
||||||
|
@ -505,7 +484,7 @@ static int alloc_buffer_read(SDL_CameraDevice *_this, size_t buffer_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
alloc_buffer_mmap(SDL_CameraDevice *_this)
|
AllocBufferMmap(SDL_CameraDevice *_this)
|
||||||
{
|
{
|
||||||
int fd = _this->hidden->fd;
|
int fd = _this->hidden->fd;
|
||||||
int i;
|
int i;
|
||||||
|
@ -538,7 +517,7 @@ alloc_buffer_mmap(SDL_CameraDevice *_this)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
alloc_buffer_userp(SDL_CameraDevice *_this, size_t buffer_size)
|
AllocBufferUserPtr(SDL_CameraDevice *_this, size_t buffer_size)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < _this->hidden->nb_buffers; ++i) {
|
for (i = 0; i < _this->hidden->nb_buffers; ++i) {
|
||||||
|
@ -708,12 +687,12 @@ GetDeviceSpec(SDL_CameraDevice *_this, SDL_CameraSpec *spec)
|
||||||
SDL_zero(fmt);
|
SDL_zero(fmt);
|
||||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
|
||||||
/* Preserve original settings as set by v4l2-ctl for example */
|
// Preserve original settings as set by v4l2-ctl for example
|
||||||
if (xioctl(fd, VIDIOC_G_FMT, &fmt) == -1) {
|
if (xioctl(fd, VIDIOC_G_FMT, &fmt) == -1) {
|
||||||
return SDL_SetError("Error VIDIOC_G_FMT");
|
return SDL_SetError("Error VIDIOC_G_FMT");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Buggy driver paranoia. */
|
// Buggy driver paranoia.
|
||||||
min = fmt.fmt.pix.width * 2;
|
min = fmt.fmt.pix.width * 2;
|
||||||
if (fmt.fmt.pix.bytesperline < min) {
|
if (fmt.fmt.pix.bytesperline < min) {
|
||||||
fmt.fmt.pix.bytesperline = min;
|
fmt.fmt.pix.bytesperline = min;
|
||||||
|
@ -739,29 +718,29 @@ InitDevice(SDL_CameraDevice *_this)
|
||||||
|
|
||||||
int fd = _this->hidden->fd;
|
int fd = _this->hidden->fd;
|
||||||
enum io_method io = _this->hidden->io;
|
enum io_method io = _this->hidden->io;
|
||||||
int ret = -1;
|
int retval = -1;
|
||||||
|
|
||||||
/* Select video input, video standard and tune here. */
|
// Select video input, video standard and tune here.
|
||||||
SDL_zero(cropcap);
|
SDL_zero(cropcap);
|
||||||
|
|
||||||
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
|
|
||||||
if (xioctl(fd, VIDIOC_CROPCAP, &cropcap) == 0) {
|
if (xioctl(fd, VIDIOC_CROPCAP, &cropcap) == 0) {
|
||||||
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
crop.c = cropcap.defrect; /* reset to default */
|
crop.c = cropcap.defrect; // reset to default
|
||||||
|
|
||||||
if (xioctl(fd, VIDIOC_S_CROP, &crop) == -1) {
|
if (xioctl(fd, VIDIOC_S_CROP, &crop) == -1) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case EINVAL:
|
case EINVAL:
|
||||||
/* Cropping not supported. */
|
// Cropping not supported.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Errors ignored. */
|
// Errors ignored.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Errors ignored. */
|
// Errors ignored.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -790,7 +769,7 @@ InitDevice(SDL_CameraDevice *_this)
|
||||||
|
|
||||||
GetDeviceSpec(_this, &_this->spec);
|
GetDeviceSpec(_this, &_this->spec);
|
||||||
|
|
||||||
if (pre_enqueue_buffers(_this) < 0) {
|
if (PreEnqueueBuffers(_this) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,28 +786,23 @@ InitDevice(SDL_CameraDevice *_this)
|
||||||
|
|
||||||
switch (io) {
|
switch (io) {
|
||||||
case IO_METHOD_READ:
|
case IO_METHOD_READ:
|
||||||
ret = alloc_buffer_read(_this, size);
|
retval = AllocBufferRead(_this, size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IO_METHOD_MMAP:
|
case IO_METHOD_MMAP:
|
||||||
ret = alloc_buffer_mmap(_this);
|
retval = AllocBufferMmap(_this);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IO_METHOD_USERPTR:
|
case IO_METHOD_USERPTR:
|
||||||
ret = alloc_buffer_userp(_this, size);
|
retval = AllocBufferUserPtr(_this, size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0) {
|
return (retval < 0) ? -1 : 0;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void CloseDevice(SDL_CameraDevice *_this)
|
||||||
CloseDevice(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
if (!_this) {
|
if (!_this) {
|
||||||
return;
|
return;
|
||||||
|
@ -836,7 +810,6 @@ CloseDevice(SDL_CameraDevice *_this)
|
||||||
|
|
||||||
if (_this->hidden) {
|
if (_this->hidden) {
|
||||||
if (_this->hidden->buffers) {
|
if (_this->hidden->buffers) {
|
||||||
int i;
|
|
||||||
enum io_method io = _this->hidden->io;
|
enum io_method io = _this->hidden->io;
|
||||||
|
|
||||||
switch (io) {
|
switch (io) {
|
||||||
|
@ -845,7 +818,7 @@ CloseDevice(SDL_CameraDevice *_this)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IO_METHOD_MMAP:
|
case IO_METHOD_MMAP:
|
||||||
for (i = 0; i < _this->hidden->nb_buffers; ++i) {
|
for (int i = 0; i < _this->hidden->nb_buffers; ++i) {
|
||||||
if (munmap(_this->hidden->buffers[i].start, _this->hidden->buffers[i].length) == -1) {
|
if (munmap(_this->hidden->buffers[i].start, _this->hidden->buffers[i].length) == -1) {
|
||||||
SDL_SetError("munmap");
|
SDL_SetError("munmap");
|
||||||
}
|
}
|
||||||
|
@ -853,7 +826,7 @@ CloseDevice(SDL_CameraDevice *_this)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IO_METHOD_USERPTR:
|
case IO_METHOD_USERPTR:
|
||||||
for (i = 0; i < _this->hidden->nb_buffers; ++i) {
|
for (int i = 0; i < _this->hidden->nb_buffers; ++i) {
|
||||||
SDL_free(_this->hidden->buffers[i].start);
|
SDL_free(_this->hidden->buffers[i].start);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -864,7 +837,7 @@ CloseDevice(SDL_CameraDevice *_this)
|
||||||
|
|
||||||
if (_this->hidden->fd != -1) {
|
if (_this->hidden->fd != -1) {
|
||||||
if (close(_this->hidden->fd)) {
|
if (close(_this->hidden->fd)) {
|
||||||
SDL_SetError("close camera device");
|
SDL_SetError("close camera device"); // !!! FIXME: we probably won't ever see this error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SDL_free(_this->hidden);
|
SDL_free(_this->hidden);
|
||||||
|
@ -874,13 +847,12 @@ CloseDevice(SDL_CameraDevice *_this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int OpenDevice(SDL_CameraDevice *_this)
|
||||||
OpenDevice(SDL_CameraDevice *_this)
|
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct v4l2_capability cap;
|
struct v4l2_capability cap;
|
||||||
int fd;
|
|
||||||
enum io_method io;
|
enum io_method io;
|
||||||
|
int fd;
|
||||||
|
|
||||||
_this->hidden = (struct SDL_PrivateCameraData *) SDL_calloc(1, sizeof (struct SDL_PrivateCameraData));
|
_this->hidden = (struct SDL_PrivateCameraData *) SDL_calloc(1, sizeof (struct SDL_PrivateCameraData));
|
||||||
if (_this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
|
@ -891,19 +863,11 @@ OpenDevice(SDL_CameraDevice *_this)
|
||||||
_this->hidden->fd = -1;
|
_this->hidden->fd = -1;
|
||||||
|
|
||||||
if (stat(_this->dev_name, &st) == -1) {
|
if (stat(_this->dev_name, &st) == -1) {
|
||||||
SDL_SetError("Cannot identify '%s': %d, %s", _this->dev_name, errno, strerror(errno));
|
return SDL_SetError("Cannot identify '%s': %d, %s", _this->dev_name, errno, strerror(errno));
|
||||||
return -1;
|
} else if (!S_ISCHR(st.st_mode)) {
|
||||||
}
|
return SDL_SetError("%s is no device", _this->dev_name);
|
||||||
|
} else if ((fd = open(_this->dev_name, O_RDWR /* required */ | O_NONBLOCK, 0)) == -1) {
|
||||||
if (!S_ISCHR(st.st_mode)) {
|
return SDL_SetError("Cannot open '%s': %d, %s", _this->dev_name, errno, strerror(errno));
|
||||||
SDL_SetError("%s is no device", _this->dev_name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = open(_this->dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
|
|
||||||
if (fd == -1) {
|
|
||||||
SDL_SetError("Cannot open '%s': %d, %s", _this->dev_name, errno, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_this->hidden->fd = fd;
|
_this->hidden->fd = fd;
|
||||||
|
@ -914,7 +878,7 @@ OpenDevice(SDL_CameraDevice *_this)
|
||||||
if (_this->hidden->io == IO_METHOD_READ) {
|
if (_this->hidden->io == IO_METHOD_READ) {
|
||||||
_this->hidden->nb_buffers = 1;
|
_this->hidden->nb_buffers = 1;
|
||||||
} else {
|
} else {
|
||||||
_this->hidden->nb_buffers = 8; /* Number of image as internal buffer, */
|
_this->hidden->nb_buffers = 8; // Number of image as internal buffer,
|
||||||
}
|
}
|
||||||
io = _this->hidden->io;
|
io = _this->hidden->io;
|
||||||
|
|
||||||
|
@ -954,14 +918,10 @@ OpenDevice(SDL_CameraDevice *_this)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size)
|
||||||
GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size)
|
|
||||||
{
|
{
|
||||||
SDL_cameralist_item *item;
|
SDL_cameralist_item *item;
|
||||||
for (item = SDL_cameralist; item; item = item->next) {
|
for (item = SDL_cameralist; item; item = item->next) {
|
||||||
|
@ -971,54 +931,46 @@ GetCameraDeviceName(SDL_CameraDeviceID instance_id, char *buf, int size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unknown instance_id */
|
// unknown instance_id
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SDL_CameraDeviceID *GetCameraDevices(int *count)
|
SDL_CameraDeviceID *GetCameraDevices(int *count)
|
||||||
{
|
{
|
||||||
/* real list of ID */
|
// real list of ID
|
||||||
int i = 0;
|
const int num = num_cameras;
|
||||||
int num = num_cameras;
|
SDL_CameraDeviceID *retval = (SDL_CameraDeviceID *)SDL_malloc((num + 1) * sizeof(*retval));
|
||||||
SDL_CameraDeviceID *ret;
|
|
||||||
SDL_cameralist_item *item;
|
|
||||||
|
|
||||||
ret = (SDL_CameraDeviceID *)SDL_malloc((num + 1) * sizeof(*ret));
|
if (retval == NULL) {
|
||||||
|
|
||||||
if (ret == NULL) {
|
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
*count = 0;
|
*count = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (item = SDL_cameralist; item; item = item->next) {
|
int i = 0;
|
||||||
ret[i] = item->instance_id;
|
for (SDL_cameralist_item *item = SDL_cameralist; item; item = item->next) {
|
||||||
i++;
|
retval[i++] = item->instance_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret[num] = 0;
|
retval[num] = 0;
|
||||||
*count = num;
|
*count = num;
|
||||||
return ret;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
// Initializes the subsystem by finding available devices.
|
||||||
* Initializes the subsystem by finding available devices.
|
|
||||||
*/
|
|
||||||
int SDL_SYS_CameraInit(void)
|
int SDL_SYS_CameraInit(void)
|
||||||
{
|
{
|
||||||
const char pattern[] = "/dev/video%d";
|
const char pattern[] = "/dev/video%d";
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
int i, j;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Limit amount of checks to MAX_CAMERA_DEVICES since we may or may not have
|
* Limit amount of checks to MAX_CAMERA_DEVICES since we may or may not have
|
||||||
* permission to some or all devices.
|
* permission to some or all devices.
|
||||||
*/
|
*/
|
||||||
i = 0;
|
for (int i = 0; i < MAX_CAMERA_DEVICES; i++) {
|
||||||
for (j = 0; j < MAX_CAMERA_DEVICES; ++j) {
|
(void)SDL_snprintf(path, PATH_MAX, pattern, i);
|
||||||
(void)SDL_snprintf(path, PATH_MAX, pattern, i++);
|
|
||||||
if (MaybeAddDevice(path) == -2) {
|
if (MaybeAddDevice(path) == -2) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1027,27 +979,22 @@ int SDL_SYS_CameraInit(void)
|
||||||
#ifdef SDL_USE_LIBUDEV
|
#ifdef SDL_USE_LIBUDEV
|
||||||
if (SDL_UDEV_Init() < 0) {
|
if (SDL_UDEV_Init() < 0) {
|
||||||
return SDL_SetError("Could not initialize UDEV");
|
return SDL_SetError("Could not initialize UDEV");
|
||||||
}
|
} else if (SDL_UDEV_AddCallback(CameraUdevCallback) < 0) {
|
||||||
|
|
||||||
if (SDL_UDEV_AddCallback(camera_udev_callback) < 0) {
|
|
||||||
SDL_UDEV_Quit();
|
SDL_UDEV_Quit();
|
||||||
return SDL_SetError("Could not setup Video Capture <-> udev callback");
|
return SDL_SetError("Could not setup Video Capture <-> udev callback");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force a scan to build the initial device list */
|
// Force a scan to build the initial device list
|
||||||
SDL_UDEV_Scan();
|
SDL_UDEV_Scan();
|
||||||
#endif /* SDL_USE_LIBUDEV */
|
#endif // SDL_USE_LIBUDEV
|
||||||
|
|
||||||
return num_cameras;
|
return num_cameras;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SDL_SYS_CameraQuit(void)
|
int SDL_SYS_CameraQuit(void)
|
||||||
{
|
{
|
||||||
SDL_cameralist_item *item;
|
for (SDL_cameralist_item *item = SDL_cameralist; item; ) {
|
||||||
for (item = SDL_cameralist; item; ) {
|
|
||||||
SDL_cameralist_item *tmp = item->next;
|
SDL_cameralist_item *tmp = item->next;
|
||||||
|
|
||||||
SDL_free(item->fname);
|
SDL_free(item->fname);
|
||||||
SDL_free(item->bus_info);
|
SDL_free(item->bus_info);
|
||||||
SDL_free(item);
|
SDL_free(item);
|
||||||
|
@ -1062,7 +1009,7 @@ int SDL_SYS_CameraQuit(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SDL_USE_LIBUDEV
|
#ifdef SDL_USE_LIBUDEV
|
||||||
static void camera_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
|
static void CameraUdevCallback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
|
||||||
{
|
{
|
||||||
if (!devpath || !(udev_class & SDL_UDEV_DEVICE_VIDEO_CAPTURE)) {
|
if (!devpath || !(udev_class & SDL_UDEV_DEVICE_VIDEO_CAPTURE)) {
|
||||||
return;
|
return;
|
||||||
|
@ -1081,17 +1028,15 @@ static void camera_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* SDL_USE_LIBUDEV */
|
#endif // SDL_USE_LIBUDEV
|
||||||
|
|
||||||
static SDL_bool DeviceExists(const char *path, const char *bus_info) {
|
static SDL_bool DeviceExists(const char *path, const char *bus_info) {
|
||||||
SDL_cameralist_item *item;
|
for (SDL_cameralist_item *item = SDL_cameralist; item; item = item->next) {
|
||||||
|
// found same dev name
|
||||||
for (item = SDL_cameralist; item; item = item->next) {
|
|
||||||
/* found same dev name */
|
|
||||||
if (SDL_strcmp(path, item->fname) == 0) {
|
if (SDL_strcmp(path, item->fname) == 0) {
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
/* found same bus_info */
|
// found same bus_info
|
||||||
if (SDL_strcmp(bus_info, item->bus_info) == 0) {
|
if (SDL_strcmp(bus_info, item->bus_info) == 0) {
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1113,7 +1058,7 @@ static int MaybeAddDevice(const char *path)
|
||||||
|
|
||||||
fd = open(path, O_RDWR);
|
fd = open(path, O_RDWR);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
return -2; /* stop iterating /dev/video%d */
|
return -2; // stop iterating /dev/video%d
|
||||||
}
|
}
|
||||||
err = ioctl(fd, VIDIOC_QUERYCAP, &vcap);
|
err = ioctl(fd, VIDIOC_QUERYCAP, &vcap);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@ -1129,7 +1074,7 @@ static int MaybeAddDevice(const char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Add new item */
|
// Add new item
|
||||||
item = (SDL_cameralist_item *)SDL_calloc(1, sizeof(SDL_cameralist_item));
|
item = (SDL_cameralist_item *)SDL_calloc(1, sizeof(SDL_cameralist_item));
|
||||||
if (!item) {
|
if (!item) {
|
||||||
SDL_free(bus_info);
|
SDL_free(bus_info);
|
||||||
|
@ -1157,7 +1102,7 @@ static int MaybeAddDevice(const char *path)
|
||||||
|
|
||||||
++num_cameras;
|
++num_cameras;
|
||||||
|
|
||||||
/* !!! TODO: Send a add event? */
|
// !!! TODO: Send a add event?
|
||||||
#if DEBUG_CAMERA
|
#if DEBUG_CAMERA
|
||||||
SDL_Log("Added video camera ID: %d %s (%s) (total: %d)", item->instance_id, path, bus_info, num_cameras);
|
SDL_Log("Added video camera ID: %d %s (%s) (total: %d)", item->instance_id, path, bus_info, num_cameras);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1178,7 +1123,7 @@ static int MaybeRemoveDevice(const char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (item = SDL_cameralist; item; item = item->next) {
|
for (item = SDL_cameralist; item; item = item->next) {
|
||||||
/* found it, remove it. */
|
// found it, remove it.
|
||||||
if (SDL_strcmp(path, item->fname) == 0) {
|
if (SDL_strcmp(path, item->fname) == 0) {
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev->next = item->next;
|
prev->next = item->next;
|
||||||
|
@ -1190,9 +1135,9 @@ static int MaybeRemoveDevice(const char *path)
|
||||||
SDL_cameralist_tail = prev;
|
SDL_cameralist_tail = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Need to decrement the count */
|
// Need to decrement the count
|
||||||
--num_cameras;
|
--num_cameras;
|
||||||
/* !!! TODO: Send a remove event? */
|
// !!! TODO: Send a remove event?
|
||||||
|
|
||||||
SDL_free(item->fname);
|
SDL_free(item->fname);
|
||||||
SDL_free(item->bus_info);
|
SDL_free(item->bus_info);
|
||||||
|
@ -1203,6 +1148,7 @@ static int MaybeRemoveDevice(const char *path)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* SDL_USE_LIBUDEV */
|
#endif // SDL_USE_LIBUDEV
|
||||||
|
|
||||||
|
#endif // SDL_CAMERA_V4L2
|
||||||
|
|
||||||
#endif /* SDL_CAMERA_V4L2 */
|
|
||||||
|
|
Loading…
Reference in New Issue