camera: Added SDL_GetCameraDevicePosition.
Otherwise, as a property, you have to open each camera device to figure out which ones are which.main
parent
b1ed49772c
commit
70b89ab70d
|
@ -70,6 +70,19 @@ typedef struct SDL_CameraSpec
|
|||
int interval_denominator; /**< Frame rate demoninator ((dom / num) == fps, (num / dom) == duration) */
|
||||
} SDL_CameraSpec;
|
||||
|
||||
/**
|
||||
* The position of camera in relation to system device.
|
||||
*
|
||||
* \sa SDL_GetCameraDevicePosition
|
||||
*/
|
||||
typedef enum SDL_CameraPosition
|
||||
{
|
||||
SDL_CAMERA_POSITION_UNKNOWN,
|
||||
SDL_CAMERA_POSITION_FRONT_FACING,
|
||||
SDL_CAMERA_POSITION_BACK_FACING
|
||||
} SDL_CameraPosition;
|
||||
|
||||
|
||||
/**
|
||||
* Use this function to get the number of built-in camera drivers.
|
||||
*
|
||||
|
@ -210,6 +223,25 @@ extern DECLSPEC SDL_CameraSpec *SDLCALL SDL_GetCameraDeviceSupportedFormats(SDL_
|
|||
*/
|
||||
extern DECLSPEC char * SDLCALL SDL_GetCameraDeviceName(SDL_CameraDeviceID instance_id);
|
||||
|
||||
/**
|
||||
* Get the position of the camera in relation to the system.
|
||||
*
|
||||
* Most platforms will report UNKNOWN, but mobile devices, like phones, can
|
||||
* often make a distiction between cameras on the front of the device (that
|
||||
* points towards the user, for taking "selfies") and cameras on the back
|
||||
* (for filming in the direction the user is facing).
|
||||
*
|
||||
* \param instance_id the camera device instance ID
|
||||
* \returns The position of the camera on the system hardware.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.0.0.
|
||||
*
|
||||
* \sa SDL_GetCameraDevices
|
||||
*/
|
||||
extern DECLSPEC SDL_CameraPosition SDLCALL SDL_GetCameraDevicePosition(SDL_CameraDeviceID instance_id);
|
||||
|
||||
/**
|
||||
* Open a video capture device (a "camera").
|
||||
*
|
||||
|
@ -305,16 +337,6 @@ 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.
|
||||
|
@ -328,8 +350,6 @@ 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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue