From 8db2a3b27a98054e4ac5f0bd23bd5c3d336cd90c Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 7 Feb 2024 09:17:01 -0500 Subject: [PATCH] camera: Add an optional property that reports if a camera is back or front. This is useful for iOS and Android, so an app can find the camera it cares about in the list of devices. --- include/SDL3/SDL_camera.h | 12 +++++++++ include/SDL3/SDL_properties.h | 3 +++ src/camera/coremedia/SDL_camera_coremedia.m | 28 ++++++++++++++++----- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/include/SDL3/SDL_camera.h b/include/SDL3/SDL_camera.h index c07066627..57c41a130 100644 --- a/include/SDL3/SDL_camera.h +++ b/include/SDL3/SDL_camera.h @@ -305,6 +305,16 @@ extern DECLSPEC SDL_CameraDeviceID SDLCALL SDL_GetCameraInstanceID(SDL_Camera *c /** * Get the properties associated with an opened camera. * + * The following read-only properties are provided by SDL: + * + * - `SDL_PROP_CAMERA_POSITION_STRING`: the position of the camera in + * relation to the hardware it is connected to. This is currently either + * the string "front" or "back", to signify which side of the user's + * device a camera is on. Future versions of SDL may add other position + * strings. This property is only set if this information can be + * determined by SDL. Most platforms do not set this attribute at all, + * but mobile devices tend to. + * * \param camera the SDL_Camera obtained from SDL_OpenCameraDevice() * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. @@ -318,6 +328,8 @@ extern DECLSPEC SDL_CameraDeviceID SDLCALL SDL_GetCameraInstanceID(SDL_Camera *c */ extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetCameraProperties(SDL_Camera *camera); +#define SDL_PROP_CAMERA_POSITION_STRING "SDL.camera.position" + /** * Get the spec that a camera is using when generating images. * diff --git a/include/SDL3/SDL_properties.h b/include/SDL3/SDL_properties.h index 806197237..f2fda2810 100644 --- a/include/SDL3/SDL_properties.h +++ b/include/SDL3/SDL_properties.h @@ -183,6 +183,9 @@ extern DECLSPEC int SDLCALL SDL_SetProperty(SDL_PropertiesID props, const char * /** * Set a string property on a set of properties * + * This function makes a copy of the string; the caller does not have to + * preserve the data after this call completes. + * * \param props the properties to modify * \param name the name of the property to modify * \param value the new value of the property, or NULL to delete the property diff --git a/src/camera/coremedia/SDL_camera_coremedia.m b/src/camera/coremedia/SDL_camera_coremedia.m index cf07d47cc..4d2e40f35 100644 --- a/src/camera/coremedia/SDL_camera_coremedia.m +++ b/src/camera/coremedia/SDL_camera_coremedia.m @@ -386,20 +386,36 @@ static SDL_bool FindCoreMediaCameraDeviceByUniqueID(SDL_CameraDevice *device, vo return ([uniqueid isEqualToString:avdev.uniqueID]) ? SDL_TRUE : SDL_FALSE; } -static void MaybeAddDevice(AVCaptureDevice *device) +static void MaybeAddDevice(AVCaptureDevice *avdevice) { - if (!device.connected) { + if (!avdevice.connected) { return; // not connected. - } else if (![device hasMediaType:AVMediaTypeVideo]) { + } else if (![avdevice hasMediaType:AVMediaTypeVideo]) { return; // not a camera. - } else if (SDL_FindPhysicalCameraDeviceByCallback(FindCoreMediaCameraDeviceByUniqueID, (__bridge void *) device.uniqueID)) { + } else if (SDL_FindPhysicalCameraDeviceByCallback(FindCoreMediaCameraDeviceByUniqueID, (__bridge void *) avdevice.uniqueID)) { return; // already have this one. } CameraFormatAddData add_data; - GatherCameraSpecs(device, &add_data); + GatherCameraSpecs(avdevice, &add_data); if (add_data.num_specs > 0) { - SDL_AddCameraDevice(device.localizedName.UTF8String, add_data.num_specs, add_data.specs, (void *) CFBridgingRetain(device)); + 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_free(add_data.specs); }