Browse Source

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.
Ryan C. Gordon 1 year ago
parent
commit
8db2a3b27a

+ 12 - 0
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.
  *

+ 3 - 0
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

+ 22 - 6
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);
 }