camera: Added SDL_GetCameraDevicePosition.

Otherwise, as a property, you have to open each camera device to figure out
which ones are which.
This commit is contained in:
Ryan C. Gordon
2024-02-19 14:19:57 -05:00
parent b1ed49772c
commit 70b89ab70d
8 changed files with 75 additions and 49 deletions

View File

@@ -398,9 +398,8 @@ static int SDLCALL CameraSpecCmp(const void *vpa, const void *vpb)
return 0; // apparently, they're equal.
}
// The camera backends call this when a new device is plugged in.
SDL_CameraDevice *SDL_AddCameraDevice(const char *name, int num_specs, const SDL_CameraSpec *specs, void *handle)
SDL_CameraDevice *SDL_AddCameraDevice(const char *name, SDL_CameraPosition position, int num_specs, const SDL_CameraSpec *specs, void *handle)
{
SDL_assert(name != NULL);
SDL_assert(num_specs >= 0);
@@ -425,6 +424,8 @@ SDL_CameraDevice *SDL_AddCameraDevice(const char *name, int num_specs, const SDL
return NULL;
}
device->position = position;
device->lock = SDL_CreateMutex();
if (!device->lock) {
SDL_free(device->name);
@@ -457,7 +458,13 @@ SDL_CameraDevice *SDL_AddCameraDevice(const char *name, int num_specs, const SDL
}
#if DEBUG_CAMERA
SDL_Log("CAMERA: Adding device ('%s') with %d spec%s%s", name, num_specs, (num_specs == 1) ? "" : "s", (num_specs == 0) ? "" : ":");
const char *posstr = "unknown position";
if (position == SDL_CAMERA_POSITION_FRONT_FACING) {
posstr = "front-facing";
} else if (position == SDL_CAMERA_POSITION_BACK_FACING) {
posstr = "back-facing";
}
SDL_Log("CAMERA: Adding device '%s' (%s) with %d spec%s%s", name, posstr, num_specs, (num_specs == 1) ? "" : "s", (num_specs == 0) ? "" : ":");
for (int i = 0; i < num_specs; i++) {
const SDL_CameraSpec *spec = &device->all_specs[i];
SDL_Log("CAMERA: - fmt=%s, w=%d, h=%d, numerator=%d, denominator=%d", SDL_GetPixelFormatName(spec->format), spec->width, spec->height, spec->interval_numerator, spec->interval_denominator);
@@ -658,6 +665,18 @@ char *SDL_GetCameraDeviceName(SDL_CameraDeviceID instance_id)
return retval;
}
SDL_CameraPosition SDL_GetCameraDevicePosition(SDL_CameraDeviceID instance_id)
{
SDL_CameraPosition retval = SDL_CAMERA_POSITION_UNKNOWN;
SDL_CameraDevice *device = ObtainPhysicalCameraDevice(instance_id);
if (device) {
retval = device->position;
ReleaseCameraDevice(device);
}
return retval;
}
SDL_CameraDeviceID *SDL_GetCameraDevices(int *count)
{
int dummy_count;

View File

@@ -25,14 +25,14 @@
#include "../SDL_hashtable.h"
#define DEBUG_CAMERA 0
#define DEBUG_CAMERA 1
typedef struct SDL_CameraDevice SDL_CameraDevice;
/* Backends should call this as devices are added to the system (such as
a USB camera being plugged in), and should also be called for
for every device found during DetectDevices(). */
extern SDL_CameraDevice *SDL_AddCameraDevice(const char *name, int num_specs, const SDL_CameraSpec *specs, void *handle);
extern SDL_CameraDevice *SDL_AddCameraDevice(const char *name, SDL_CameraPosition position, int num_specs, const SDL_CameraSpec *specs, void *handle);
/* Backends should call this if an opened camera device is lost.
This can happen due to i/o errors, or a device being unplugged, etc. */
@@ -82,6 +82,9 @@ struct SDL_CameraDevice
// Human-readable device name.
char *name;
// Position of camera (front-facing, back-facing, etc).
SDL_CameraPosition position;
// When refcount hits zero, we destroy the device object.
SDL_AtomicInt refcount;

View File

@@ -575,7 +575,7 @@ static void ANDROIDCAMERA_FreeDeviceHandle(SDL_CameraDevice *device)
}
}
static void GatherCameraSpecs(const char *devid, CameraFormatAddData *add_data, char **fullname, const char **posstr)
static void GatherCameraSpecs(const char *devid, CameraFormatAddData *add_data, char **fullname, SDL_CameraPosition *position)
{
SDL_zerop(add_data);
@@ -608,16 +608,15 @@ static void GatherCameraSpecs(const char *devid, CameraFormatAddData *add_data,
}
}
*posstr = NULL;
ACameraMetadata_const_entry posentry;
if (pACameraMetadata_getConstEntry(metadata, ACAMERA_LENS_FACING, &posentry) == ACAMERA_OK) { // ignore this if it fails.
if (*posentry.data.u8 == ACAMERA_LENS_FACING_FRONT) {
*posstr = "front";
*position = SDL_CAMERA_POSITION_FRONT_FACING;
if (!*fullname) {
*fullname = SDL_strdup("Front-facing camera");
}
} else if (*posentry.data.u8 == ACAMERA_LENS_FACING_BACK) {
*posstr = "back";
*position = SDL_CAMERA_POSITION_BACK_FACING;
if (!*fullname) {
*fullname = SDL_strdup("Back-facing camera");
}
@@ -680,22 +679,16 @@ static void MaybeAddDevice(const char *devid)
return; // already have this one.
}
const char *posstr = NULL;
SDL_CameraPosition position = SDL_CAMERA_POSITION_UNKNOWN;
char *fullname = NULL;
CameraFormatAddData add_data;
GatherCameraSpecs(devid, &add_data, &fullname, &posstr);
GatherCameraSpecs(devid, &add_data, &fullname, &position);
if (add_data.num_specs > 0) {
char *namecpy = SDL_strdup(devid);
if (namecpy) {
SDL_CameraDevice *device = SDL_AddCameraDevice(fullname, add_data.num_specs, add_data.specs, namecpy);
SDL_CameraDevice *device = SDL_AddCameraDevice(fullname, position, add_data.num_specs, add_data.specs, namecpy);
if (!device) {
SDL_free(namecpy);
} else if (device && posstr) {
SDL_Camera *camera = (SDL_Camera *) device; // currently there's no separation between physical and logical device.
SDL_PropertiesID props = SDL_GetCameraProperties(camera);
if (props) {
SDL_SetStringProperty(props, SDL_PROP_CAMERA_POSITION_STRING, posstr);
}
}
}
}

View File

@@ -399,24 +399,15 @@ static void MaybeAddDevice(AVCaptureDevice *avdevice)
CameraFormatAddData add_data;
GatherCameraSpecs(avdevice, &add_data);
if (add_data.num_specs > 0) {
SDL_CameraDevice *device = SDL_AddCameraDevice(avdevice.localizedName.UTF8String, add_data.num_specs, add_data.specs, (void *) CFBridgingRetain(avdevice));
if (device) {
const char *posstr = NULL;
if (avdevice.position == AVCaptureDevicePositionFront) {
posstr = "front";
} else if (avdevice.position == AVCaptureDevicePositionBack) {
posstr = "back";
}
if (posstr) {
SDL_Camera *camera = (SDL_Camera *) device; // currently there's no separation between physical and logical device.
SDL_PropertiesID props = SDL_GetCameraProperties(camera);
if (props) {
SDL_SetStringProperty(props, SDL_PROP_CAMERA_POSITION_STRING, posstr);
}
}
SDL_CameraPosition position = SDL_CAMERA_POSITION_UNKNOWN;
if (avdevice.position == AVCaptureDevicePositionFront) {
position = SDL_CAMERA_POSITION_FRONT_FACING;
} else if (avdevice.position == AVCaptureDevicePositionBack) {
position = SDL_CAMERA_POSITION_BACK_FACING;
}
SDL_AddCameraDevice(avdevice.localizedName.UTF8String, position, add_data.num_specs, add_data.specs, (void *) CFBridgingRetain(avdevice));
}
SDL_free(add_data.specs);
}

View File

@@ -228,7 +228,7 @@ static void EMSCRIPTENCAMERA_DetectDevices(void)
// will pop up a user permission dialog warning them we're trying to access the camera, and we generally
// don't want that during SDL_Init().
if (supported) {
SDL_AddCameraDevice("Web browser's camera", 0, NULL, (void *) (size_t) 0x1);
SDL_AddCameraDevice("Web browser's camera", SDL_CAMERA_POSITION_UNKNOWN, 0, NULL, (void *) (size_t) 0x1);
}
}

View File

@@ -777,7 +777,7 @@ static void MaybeAddDevice(IMFActivate *activation)
CameraFormatAddData add_data;
GatherCameraSpecs(source, &add_data);
if (add_data.num_specs > 0) {
SDL_AddCameraDevice(name, add_data.num_specs, add_data.specs, symlink);
SDL_AddCameraDevice(name, SDL_CAMERA_POSITION_UNKNOWN, add_data.num_specs, add_data.specs, symlink);
}
SDL_free(add_data.specs);
IMFActivate_ShutdownObject(activation);

View File

@@ -778,7 +778,7 @@ static void MaybeAddDevice(const char *path)
if (handle->path) {
handle->bus_info = SDL_strdup((char *)vcap.bus_info);
if (handle->bus_info) {
if (SDL_AddCameraDevice((const char *) vcap.card, add_data.num_specs, add_data.specs, handle)) {
if (SDL_AddCameraDevice((const char *) vcap.card, SDL_CAMERA_POSITION_UNKNOWN, add_data.num_specs, add_data.specs, handle)) {
SDL_free(add_data.specs);
return; // good to go.
}