1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "../SDL_internal.h"
22
23#ifndef SDL_syscamera_h_
24#define SDL_syscamera_h_
25
26#include "../video/SDL_surface_c.h"
27
28#define DEBUG_CAMERA 0
29
30/* Backends should call this as devices are added to the system (such as
31 a USB camera being plugged in), and should also be called for
32 for every device found during DetectDevices(). */
33extern SDL_Camera *SDL_AddCamera(const char *name, SDL_CameraPosition position, int num_specs, const SDL_CameraSpec *specs, void *handle);
34
35/* Backends should call this if an opened camera device is lost.
36 This can happen due to i/o errors, or a device being unplugged, etc. */
37extern void SDL_CameraDisconnected(SDL_Camera *device);
38
39// Find an SDL_Camera, selected by a callback. NULL if not found. DOES NOT LOCK THE DEVICE.
40extern SDL_Camera *SDL_FindPhysicalCameraByCallback(bool (*callback)(SDL_Camera *device, void *userdata), void *userdata);
41
42// Backends should call this when the user has approved/denied access to a camera.
43extern void SDL_CameraPermissionOutcome(SDL_Camera *device, bool approved);
44
45// Backends can call this to get a standardized name for a thread to power a specific camera device.
46extern char *SDL_GetCameraThreadName(SDL_Camera *device, char *buf, size_t buflen);
47
48// Backends can call these to change a device's refcount.
49extern void RefPhysicalCamera(SDL_Camera *device);
50extern void UnrefPhysicalCamera(SDL_Camera *device);
51
52// These functions are the heart of the camera threads. Backends can call them directly if they aren't using the SDL-provided thread.
53extern void SDL_CameraThreadSetup(SDL_Camera *device);
54extern bool SDL_CameraThreadIterate(SDL_Camera *device);
55extern void SDL_CameraThreadShutdown(SDL_Camera *device);
56
57// Backends can call this if they have to finish initializing later, like Emscripten. Most backends should _not_ call this directly!
58extern bool SDL_PrepareCameraSurfaces(SDL_Camera *device);
59
60
61// common utility functionality to gather up camera specs. Not required!
62typedef struct CameraFormatAddData
63{
64 SDL_CameraSpec *specs;
65 int num_specs;
66 int allocated_specs;
67} CameraFormatAddData;
68
69bool SDL_AddCameraFormat(CameraFormatAddData *data, SDL_PixelFormat format, SDL_Colorspace colorspace, int w, int h, int framerate_numerator, int framerate_denominator);
70
71typedef enum SDL_CameraFrameResult
72{
73 SDL_CAMERA_FRAME_ERROR,
74 SDL_CAMERA_FRAME_SKIP,
75 SDL_CAMERA_FRAME_READY
76} SDL_CameraFrameResult;
77
78typedef struct SurfaceList
79{
80 SDL_Surface *surface;
81 Uint64 timestampNS;
82 struct SurfaceList *next;
83} SurfaceList;
84
85// Define the SDL camera driver structure
86struct SDL_Camera
87{
88 // A mutex for locking
89 SDL_Mutex *lock;
90
91 // Human-readable device name.
92 char *name;
93
94 // Position of camera (front-facing, back-facing, etc).
95 SDL_CameraPosition position;
96
97 // When refcount hits zero, we destroy the device object.
98 SDL_AtomicInt refcount;
99
100 // These are, initially, set from camera_driver, but we might swap them out with Zombie versions on disconnect/failure.
101 bool (*WaitDevice)(SDL_Camera *device);
102 SDL_CameraFrameResult (*AcquireFrame)(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS);
103 void (*ReleaseFrame)(SDL_Camera *device, SDL_Surface *frame);
104
105 // All supported formats/dimensions for this device.
106 SDL_CameraSpec *all_specs;
107
108 // Elements in all_specs.
109 int num_specs;
110
111 // The device's actual specification that the camera is outputting, before conversion.
112 SDL_CameraSpec actual_spec;
113
114 // The device's current camera specification, after conversions.
115 SDL_CameraSpec spec;
116
117 // Unique value assigned at creation time.
118 SDL_CameraID instance_id;
119
120 // Driver-specific hardware data on how to open device (`hidden` is driver-specific data _when opened_).
121 void *handle;
122
123 // Dropping the first frame(s) after open seems to help timing on some platforms.
124 int drop_frames;
125
126 // Backend timestamp of first acquired frame, so we can keep these meaningful regardless of epoch.
127 Uint64 base_timestamp;
128
129 // SDL timestamp of first acquired frame, so we can roughly convert to SDL ticks.
130 Uint64 adjust_timestamp;
131
132 // Pixel data flows from the driver into these, then gets converted for the app if necessary.
133 SDL_Surface *acquire_surface;
134
135 // acquire_surface converts or scales to this surface before landing in output_surfaces, if necessary.
136 SDL_Surface *conversion_surface;
137
138 // A queue of surfaces that buffer converted/scaled frames of video until the app claims them.
139 SurfaceList output_surfaces[8];
140 SurfaceList filled_output_surfaces; // this is FIFO
141 SurfaceList empty_output_surfaces; // this is LIFO
142 SurfaceList app_held_output_surfaces;
143
144 // A fake video frame we allocate if the camera fails/disconnects.
145 Uint8 *zombie_pixels;
146
147 // non-zero if acquire_surface needs to be scaled for final output.
148 int needs_scaling; // -1: downscale, 0: no scaling, 1: upscale
149
150 // true if acquire_surface needs to be converted for final output.
151 bool needs_conversion;
152
153 // Current state flags
154 SDL_AtomicInt shutdown;
155 SDL_AtomicInt zombie;
156
157 // A thread to feed the camera device
158 SDL_Thread *thread;
159
160 // Optional properties.
161 SDL_PropertiesID props;
162
163 // -1: user denied permission, 0: waiting for user response, 1: user approved permission.
164 int permission;
165
166 // Data private to this driver, used when device is opened and running.
167 struct SDL_PrivateCameraData *hidden;
168};
169
170typedef struct SDL_CameraDriverImpl
171{
172 void (*DetectDevices)(void);
173 bool (*OpenDevice)(SDL_Camera *device, const SDL_CameraSpec *spec);
174 void (*CloseDevice)(SDL_Camera *device);
175 bool (*WaitDevice)(SDL_Camera *device);
176 SDL_CameraFrameResult (*AcquireFrame)(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS); // set frame->pixels, frame->pitch, and *timestampNS!
177 void (*ReleaseFrame)(SDL_Camera *device, SDL_Surface *frame); // Reclaim frame->pixels and frame->pitch!
178 void (*FreeDeviceHandle)(SDL_Camera *device); // SDL is done with this device; free the handle from SDL_AddCamera()
179 void (*Deinitialize)(void);
180
181 bool ProvidesOwnCallbackThread;
182} SDL_CameraDriverImpl;
183
184typedef struct SDL_PendingCameraEvent
185{
186 Uint32 type;
187 SDL_CameraID devid;
188 struct SDL_PendingCameraEvent *next;
189} SDL_PendingCameraEvent;
190
191typedef struct SDL_CameraDriver
192{
193 const char *name; // The name of this camera driver
194 const char *desc; // The description of this camera driver
195 SDL_CameraDriverImpl impl; // the backend's interface
196
197 SDL_RWLock *device_hash_lock; // A rwlock that protects `device_hash` // !!! FIXME: device_hash _also_ has a rwlock, see if we still need this one.
198 SDL_HashTable *device_hash; // the collection of currently-available camera devices
199 SDL_PendingCameraEvent pending_events;
200 SDL_PendingCameraEvent *pending_events_tail;
201
202 SDL_AtomicInt device_count;
203 SDL_AtomicInt shutting_down; // non-zero during SDL_Quit, so we known not to accept any last-minute device hotplugs.
204} SDL_CameraDriver;
205
206typedef struct CameraBootStrap
207{
208 const char *name;
209 const char *desc;
210 bool (*init)(SDL_CameraDriverImpl *impl);
211 bool demand_only; // if true: request explicitly, or it won't be available.
212} CameraBootStrap;
213
214// Not all of these are available in a given build. Use #ifdefs, etc.
215extern CameraBootStrap DUMMYCAMERA_bootstrap;
216extern CameraBootStrap PIPEWIRECAMERA_bootstrap;
217extern CameraBootStrap V4L2_bootstrap;
218extern CameraBootStrap COREMEDIA_bootstrap;
219extern CameraBootStrap ANDROIDCAMERA_bootstrap;
220extern CameraBootStrap EMSCRIPTENCAMERA_bootstrap;
221extern CameraBootStrap MEDIAFOUNDATION_bootstrap;
222extern CameraBootStrap VITACAMERA_bootstrap;
223
224#endif // SDL_syscamera_h_
225