SDL_camera.c 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "SDL_internal.h"
  19. #include "SDL_syscamera.h"
  20. #include "SDL_camera_c.h"
  21. #include "../video/SDL_pixels_c.h"
  22. #include "../thread/SDL_systhread.h"
  23. // A lot of this is a simplified version of SDL_audio.c; if fixing stuff here,
  24. // maybe check that file, too.
  25. // Available camera drivers
  26. static const CameraBootStrap *const bootstrap[] = {
  27. #ifdef SDL_CAMERA_DRIVER_PIPEWIRE
  28. &PIPEWIRECAMERA_bootstrap,
  29. #endif
  30. #ifdef SDL_CAMERA_DRIVER_V4L2
  31. &V4L2_bootstrap,
  32. #endif
  33. #ifdef SDL_CAMERA_DRIVER_COREMEDIA
  34. &COREMEDIA_bootstrap,
  35. #endif
  36. #ifdef SDL_CAMERA_DRIVER_ANDROID
  37. &ANDROIDCAMERA_bootstrap,
  38. #endif
  39. #ifdef SDL_CAMERA_DRIVER_EMSCRIPTEN
  40. &EMSCRIPTENCAMERA_bootstrap,
  41. #endif
  42. #ifdef SDL_CAMERA_DRIVER_MEDIAFOUNDATION
  43. &MEDIAFOUNDATION_bootstrap,
  44. #endif
  45. #ifdef SDL_CAMERA_DRIVER_DUMMY
  46. &DUMMYCAMERA_bootstrap,
  47. #endif
  48. NULL
  49. };
  50. static SDL_CameraDriver camera_driver;
  51. int SDL_GetNumCameraDrivers(void)
  52. {
  53. return SDL_arraysize(bootstrap) - 1;
  54. }
  55. const char *SDL_GetCameraDriver(int index)
  56. {
  57. if (index >= 0 && index < SDL_GetNumCameraDrivers()) {
  58. return SDL_CreateTemporaryString(bootstrap[index]->name);
  59. }
  60. return NULL;
  61. }
  62. const char *SDL_GetCurrentCameraDriver(void)
  63. {
  64. return SDL_CreateTemporaryString(camera_driver.name);
  65. }
  66. char *SDL_GetCameraThreadName(SDL_Camera *device, char *buf, size_t buflen)
  67. {
  68. (void)SDL_snprintf(buf, buflen, "SDLCamera%d", (int) device->instance_id);
  69. return buf;
  70. }
  71. int SDL_AddCameraFormat(CameraFormatAddData *data, SDL_PixelFormat format, SDL_Colorspace colorspace, int w, int h, int framerate_numerator, int framerate_denominator)
  72. {
  73. SDL_assert(data != NULL);
  74. if (data->allocated_specs <= data->num_specs) {
  75. const int newalloc = data->allocated_specs ? (data->allocated_specs * 2) : 16;
  76. void *ptr = SDL_realloc(data->specs, sizeof (SDL_CameraSpec) * newalloc);
  77. if (!ptr) {
  78. return -1;
  79. }
  80. data->specs = (SDL_CameraSpec *) ptr;
  81. data->allocated_specs = newalloc;
  82. }
  83. SDL_CameraSpec *spec = &data->specs[data->num_specs];
  84. spec->format = format;
  85. spec->colorspace = colorspace;
  86. spec->width = w;
  87. spec->height = h;
  88. spec->framerate_numerator = framerate_numerator;
  89. spec->framerate_denominator = framerate_denominator;
  90. data->num_specs++;
  91. return 0;
  92. }
  93. // Zombie device implementation...
  94. // These get used when a device is disconnected or fails. Apps that ignore the
  95. // loss notifications will get black frames but otherwise keep functioning.
  96. static int ZombieWaitDevice(SDL_Camera *device)
  97. {
  98. if (!SDL_AtomicGet(&device->shutdown)) {
  99. // !!! FIXME: this is bad for several reasons (uses double, could be precalculated, doesn't track elasped time).
  100. const double duration = ((double) device->actual_spec.framerate_denominator / ((double) device->actual_spec.framerate_numerator));
  101. SDL_Delay((Uint32) (duration * 1000.0));
  102. }
  103. return 0;
  104. }
  105. static size_t GetFrameBufLen(const SDL_CameraSpec *spec)
  106. {
  107. const size_t w = (const size_t) spec->width;
  108. const size_t h = (const size_t) spec->height;
  109. const size_t wxh = w * h;
  110. const SDL_PixelFormat fmt = spec->format;
  111. switch (fmt) {
  112. // Some YUV formats have a larger Y plane than their U or V planes.
  113. case SDL_PIXELFORMAT_YV12:
  114. case SDL_PIXELFORMAT_IYUV:
  115. case SDL_PIXELFORMAT_NV12:
  116. case SDL_PIXELFORMAT_NV21:
  117. return wxh + (wxh / 2);
  118. default: break;
  119. }
  120. // this is correct for most things.
  121. return wxh * SDL_BYTESPERPIXEL(fmt);
  122. }
  123. static int ZombieAcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS)
  124. {
  125. const SDL_CameraSpec *spec = &device->actual_spec;
  126. if (!device->zombie_pixels) {
  127. // attempt to allocate and initialize a fake frame of pixels.
  128. const size_t buflen = GetFrameBufLen(&device->actual_spec);
  129. device->zombie_pixels = (Uint8 *)SDL_aligned_alloc(SDL_GetSIMDAlignment(), buflen);
  130. if (!device->zombie_pixels) {
  131. *timestampNS = 0;
  132. return 0; // oh well, say there isn't a frame yet, so we'll go back to waiting. Maybe allocation will succeed later...?
  133. }
  134. Uint8 *dst = device->zombie_pixels;
  135. switch (spec->format) {
  136. // in YUV formats, the U and V values must be 128 to get a black frame. If set to zero, it'll be bright green.
  137. case SDL_PIXELFORMAT_YV12:
  138. case SDL_PIXELFORMAT_IYUV:
  139. case SDL_PIXELFORMAT_NV12:
  140. case SDL_PIXELFORMAT_NV21:
  141. SDL_memset(dst, 0, spec->width * spec->height); // set Y to zero.
  142. SDL_memset(dst + (spec->width * spec->height), 128, (spec->width * spec->height) / 2); // set U and V to 128.
  143. break;
  144. case SDL_PIXELFORMAT_YUY2:
  145. case SDL_PIXELFORMAT_YVYU:
  146. // Interleaved Y1[U1|V1]Y2[U2|V2].
  147. for (size_t i = 0; i < buflen; i += 4) {
  148. dst[i] = 0;
  149. dst[i+1] = 128;
  150. dst[i+2] = 0;
  151. dst[i+3] = 128;
  152. }
  153. break;
  154. case SDL_PIXELFORMAT_UYVY:
  155. // Interleaved [U1|V1]Y1[U2|V2]Y2.
  156. for (size_t i = 0; i < buflen; i += 4) {
  157. dst[i] = 128;
  158. dst[i+1] = 0;
  159. dst[i+2] = 128;
  160. dst[i+3] = 0;
  161. }
  162. break;
  163. default:
  164. // just zero everything else, it'll _probably_ be okay.
  165. SDL_memset(dst, 0, buflen);
  166. break;
  167. }
  168. }
  169. *timestampNS = SDL_GetTicksNS();
  170. frame->pixels = device->zombie_pixels;
  171. // SDL (currently) wants the pitch of YUV formats to be the pitch of the (1-byte-per-pixel) Y plane.
  172. frame->pitch = spec->width;
  173. if (!SDL_ISPIXELFORMAT_FOURCC(spec->format)) { // checking if it's not FOURCC to only do this for non-YUV data is good enough for now.
  174. frame->pitch *= SDL_BYTESPERPIXEL(spec->format);
  175. }
  176. #if DEBUG_CAMERA
  177. SDL_Log("CAMERA: dev[%p] Acquired Zombie frame, timestamp %llu", device, (unsigned long long) *timestampNS);
  178. #endif
  179. return 1; // frame is available.
  180. }
  181. static void ZombieReleaseFrame(SDL_Camera *device, SDL_Surface *frame) // Reclaim frame->pixels and frame->pitch!
  182. {
  183. if (frame->pixels != device->zombie_pixels) {
  184. // this was a frame from before the disconnect event; let the backend make an attempt to free it.
  185. camera_driver.impl.ReleaseFrame(device, frame);
  186. }
  187. // we just leave zombie_pixels alone, as we'll reuse it for every new frame until the camera is closed.
  188. }
  189. static void ClosePhysicalCamera(SDL_Camera *device)
  190. {
  191. if (!device) {
  192. return;
  193. }
  194. SDL_AtomicSet(&device->shutdown, 1);
  195. // !!! FIXME: the close_cond stuff from audio might help the race condition here.
  196. if (device->thread != NULL) {
  197. SDL_WaitThread(device->thread, NULL);
  198. device->thread = NULL;
  199. }
  200. // release frames that are queued up somewhere...
  201. if (!device->needs_conversion && !device->needs_scaling) {
  202. for (SurfaceList *i = device->filled_output_surfaces.next; i != NULL; i = i->next) {
  203. device->ReleaseFrame(device, i->surface);
  204. }
  205. for (SurfaceList *i = device->app_held_output_surfaces.next; i != NULL; i = i->next) {
  206. device->ReleaseFrame(device, i->surface);
  207. }
  208. }
  209. camera_driver.impl.CloseDevice(device);
  210. SDL_DestroyProperties(device->props);
  211. SDL_DestroySurface(device->acquire_surface);
  212. device->acquire_surface = NULL;
  213. SDL_DestroySurface(device->conversion_surface);
  214. device->conversion_surface = NULL;
  215. for (int i = 0; i < SDL_arraysize(device->output_surfaces); i++) {
  216. SDL_DestroySurface(device->output_surfaces[i].surface);
  217. }
  218. SDL_zeroa(device->output_surfaces);
  219. SDL_aligned_free(device->zombie_pixels);
  220. device->permission = 0;
  221. device->zombie_pixels = NULL;
  222. device->filled_output_surfaces.next = NULL;
  223. device->empty_output_surfaces.next = NULL;
  224. device->app_held_output_surfaces.next = NULL;
  225. device->base_timestamp = 0;
  226. device->adjust_timestamp = 0;
  227. }
  228. // this must not be called while `device` is still in a device list, or while a device's camera thread is still running.
  229. static void DestroyPhysicalCamera(SDL_Camera *device)
  230. {
  231. if (device) {
  232. // Destroy any logical devices that still exist...
  233. ClosePhysicalCamera(device);
  234. camera_driver.impl.FreeDeviceHandle(device);
  235. SDL_DestroyMutex(device->lock);
  236. SDL_free(device->all_specs);
  237. SDL_free(device->name);
  238. SDL_free(device);
  239. }
  240. }
  241. // Don't hold the device lock when calling this, as we may destroy the device!
  242. void UnrefPhysicalCamera(SDL_Camera *device)
  243. {
  244. if (SDL_AtomicDecRef(&device->refcount)) {
  245. // take it out of the device list.
  246. SDL_LockRWLockForWriting(camera_driver.device_hash_lock);
  247. if (SDL_RemoveFromHashTable(camera_driver.device_hash, (const void *) (uintptr_t) device->instance_id)) {
  248. SDL_AtomicAdd(&camera_driver.device_count, -1);
  249. }
  250. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  251. DestroyPhysicalCamera(device); // ...and nuke it.
  252. }
  253. }
  254. void RefPhysicalCamera(SDL_Camera *device)
  255. {
  256. SDL_AtomicIncRef(&device->refcount);
  257. }
  258. static void ObtainPhysicalCameraObj(SDL_Camera *device) SDL_NO_THREAD_SAFETY_ANALYSIS // !!! FIXMEL SDL_ACQUIRE
  259. {
  260. if (device) {
  261. RefPhysicalCamera(device);
  262. SDL_LockMutex(device->lock);
  263. }
  264. }
  265. static SDL_Camera *ObtainPhysicalCamera(SDL_CameraID devid) // !!! FIXME: SDL_ACQUIRE
  266. {
  267. if (!SDL_GetCurrentCameraDriver()) {
  268. SDL_SetError("Camera subsystem is not initialized");
  269. return NULL;
  270. }
  271. SDL_Camera *device = NULL;
  272. SDL_LockRWLockForReading(camera_driver.device_hash_lock);
  273. SDL_FindInHashTable(camera_driver.device_hash, (const void *) (uintptr_t) devid, (const void **) &device);
  274. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  275. if (!device) {
  276. SDL_SetError("Invalid camera device instance ID");
  277. } else {
  278. ObtainPhysicalCameraObj(device);
  279. }
  280. return device;
  281. }
  282. static void ReleaseCamera(SDL_Camera *device) SDL_NO_THREAD_SAFETY_ANALYSIS // !!! FIXME: SDL_RELEASE
  283. {
  284. if (device) {
  285. SDL_UnlockMutex(device->lock);
  286. UnrefPhysicalCamera(device);
  287. }
  288. }
  289. // we want these sorted by format first, so you can find a block of all
  290. // resolutions that are supported for a format. The formats are sorted in
  291. // "best" order, but that's subjective: right now, we prefer planar
  292. // formats, since they're likely what the cameras prefer to produce
  293. // anyhow, and they basically send the same information in less space
  294. // than an RGB-style format. After that, sort by bits-per-pixel.
  295. // we want specs sorted largest to smallest dimensions, larger width taking precedence over larger height.
  296. static int SDLCALL CameraSpecCmp(const void *vpa, const void *vpb)
  297. {
  298. const SDL_CameraSpec *a = (const SDL_CameraSpec *) vpa;
  299. const SDL_CameraSpec *b = (const SDL_CameraSpec *) vpb;
  300. // driver shouldn't send specs like this, check here since we're eventually going to sniff the whole array anyhow.
  301. SDL_assert(a->format != SDL_PIXELFORMAT_UNKNOWN);
  302. SDL_assert(a->width > 0);
  303. SDL_assert(a->height > 0);
  304. SDL_assert(b->format != SDL_PIXELFORMAT_UNKNOWN);
  305. SDL_assert(b->width > 0);
  306. SDL_assert(b->height > 0);
  307. const SDL_PixelFormat afmt = a->format;
  308. const SDL_PixelFormat bfmt = b->format;
  309. if (SDL_ISPIXELFORMAT_FOURCC(afmt) && !SDL_ISPIXELFORMAT_FOURCC(bfmt)) {
  310. return -1;
  311. } else if (!SDL_ISPIXELFORMAT_FOURCC(afmt) && SDL_ISPIXELFORMAT_FOURCC(bfmt)) {
  312. return 1;
  313. } else if (SDL_BITSPERPIXEL(afmt) > SDL_BITSPERPIXEL(bfmt)) {
  314. return -1;
  315. } else if (SDL_BITSPERPIXEL(bfmt) > SDL_BITSPERPIXEL(afmt)) {
  316. return 1;
  317. } else if (a->width > b->width) {
  318. return -1;
  319. } else if (b->width > a->width) {
  320. return 1;
  321. } else if (a->height > b->height) {
  322. return -1;
  323. } else if (b->height > a->height) {
  324. return 1;
  325. }
  326. // still here? We care about framerate less than format or size, but faster is better than slow.
  327. if (a->framerate_numerator && !b->framerate_numerator) {
  328. return -1;
  329. } else if (!a->framerate_numerator && b->framerate_numerator) {
  330. return 1;
  331. }
  332. const float fpsa = ((float)a->framerate_numerator / a->framerate_denominator);
  333. const float fpsb = ((float)b->framerate_numerator / b->framerate_denominator);
  334. if (fpsa > fpsb) {
  335. return -1;
  336. } else if (fpsb > fpsa) {
  337. return 1;
  338. }
  339. if (SDL_COLORSPACERANGE(a->colorspace) == SDL_COLOR_RANGE_FULL &&
  340. SDL_COLORSPACERANGE(b->colorspace) != SDL_COLOR_RANGE_FULL) {
  341. return -1;
  342. }
  343. if (SDL_COLORSPACERANGE(a->colorspace) != SDL_COLOR_RANGE_FULL &&
  344. SDL_COLORSPACERANGE(b->colorspace) == SDL_COLOR_RANGE_FULL) {
  345. return 1;
  346. }
  347. return 0; // apparently, they're equal.
  348. }
  349. // The camera backends call this when a new device is plugged in.
  350. SDL_Camera *SDL_AddCamera(const char *name, SDL_CameraPosition position, int num_specs, const SDL_CameraSpec *specs, void *handle)
  351. {
  352. SDL_assert(name != NULL);
  353. SDL_assert(num_specs >= 0);
  354. SDL_assert((specs != NULL) == (num_specs > 0));
  355. SDL_assert(handle != NULL);
  356. SDL_LockRWLockForReading(camera_driver.device_hash_lock);
  357. const int shutting_down = SDL_AtomicGet(&camera_driver.shutting_down);
  358. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  359. if (shutting_down) {
  360. return NULL; // we're shutting down, don't add any devices that are hotplugged at the last possible moment.
  361. }
  362. SDL_Camera *device = (SDL_Camera *)SDL_calloc(1, sizeof(SDL_Camera));
  363. if (!device) {
  364. return NULL;
  365. }
  366. device->name = SDL_strdup(name);
  367. if (!device->name) {
  368. SDL_free(device);
  369. return NULL;
  370. }
  371. device->position = position;
  372. device->lock = SDL_CreateMutex();
  373. if (!device->lock) {
  374. SDL_free(device->name);
  375. SDL_free(device);
  376. return NULL;
  377. }
  378. device->all_specs = (SDL_CameraSpec *)SDL_calloc(num_specs + 1, sizeof (*specs));
  379. if (!device->all_specs) {
  380. SDL_DestroyMutex(device->lock);
  381. SDL_free(device->name);
  382. SDL_free(device);
  383. return NULL;
  384. }
  385. if (num_specs > 0) {
  386. SDL_memcpy(device->all_specs, specs, sizeof (*specs) * num_specs);
  387. SDL_qsort(device->all_specs, num_specs, sizeof (*specs), CameraSpecCmp);
  388. // weed out duplicates, just in case.
  389. for (int i = 0; i < num_specs; i++) {
  390. SDL_CameraSpec *a = &device->all_specs[i];
  391. SDL_CameraSpec *b = &device->all_specs[i + 1];
  392. if (SDL_memcmp(a, b, sizeof (*a)) == 0) {
  393. SDL_memmove(a, b, sizeof (*specs) * (num_specs - i));
  394. i--;
  395. num_specs--;
  396. }
  397. }
  398. }
  399. #if DEBUG_CAMERA
  400. const char *posstr = "unknown position";
  401. if (position == SDL_CAMERA_POSITION_FRONT_FACING) {
  402. posstr = "front-facing";
  403. } else if (position == SDL_CAMERA_POSITION_BACK_FACING) {
  404. posstr = "back-facing";
  405. }
  406. SDL_Log("CAMERA: Adding device '%s' (%s) with %d spec%s%s", name, posstr, num_specs, (num_specs == 1) ? "" : "s", (num_specs == 0) ? "" : ":");
  407. for (int i = 0; i < num_specs; i++) {
  408. const SDL_CameraSpec *spec = &device->all_specs[i];
  409. SDL_Log("CAMERA: - fmt=%s, w=%d, h=%d, numerator=%d, denominator=%d", SDL_GetPixelFormatName(spec->format), spec->width, spec->height, spec->framerate_numerator, spec->framerate_denominator);
  410. }
  411. #endif
  412. device->num_specs = num_specs;
  413. device->handle = handle;
  414. device->instance_id = SDL_GetNextObjectID();
  415. SDL_AtomicSet(&device->shutdown, 0);
  416. SDL_AtomicSet(&device->zombie, 0);
  417. RefPhysicalCamera(device);
  418. SDL_LockRWLockForWriting(camera_driver.device_hash_lock);
  419. if (SDL_InsertIntoHashTable(camera_driver.device_hash, (const void *) (uintptr_t) device->instance_id, device)) {
  420. SDL_AtomicAdd(&camera_driver.device_count, 1);
  421. } else {
  422. SDL_DestroyMutex(device->lock);
  423. SDL_free(device->all_specs);
  424. SDL_free(device->name);
  425. SDL_free(device);
  426. device = NULL;
  427. }
  428. // Add a device add event to the pending list, to be pushed when the event queue is pumped (away from any of our internal threads).
  429. if (device) {
  430. SDL_PendingCameraEvent *p = (SDL_PendingCameraEvent *) SDL_malloc(sizeof (SDL_PendingCameraEvent));
  431. if (p) { // if allocation fails, you won't get an event, but we can't help that.
  432. p->type = SDL_EVENT_CAMERA_DEVICE_ADDED;
  433. p->devid = device->instance_id;
  434. p->next = NULL;
  435. SDL_assert(camera_driver.pending_events_tail != NULL);
  436. SDL_assert(camera_driver.pending_events_tail->next == NULL);
  437. camera_driver.pending_events_tail->next = p;
  438. camera_driver.pending_events_tail = p;
  439. }
  440. }
  441. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  442. return device;
  443. }
  444. // Called when a device is removed from the system, or it fails unexpectedly, from any thread, possibly even the camera device's thread.
  445. void SDL_CameraDisconnected(SDL_Camera *device)
  446. {
  447. if (!device) {
  448. return;
  449. }
  450. #if DEBUG_CAMERA
  451. SDL_Log("CAMERA: DISCONNECTED! dev[%p]", device);
  452. #endif
  453. // Save off removal info in a list so we can send events for each, next
  454. // time the event queue pumps, in case something tries to close a device
  455. // from an event filter, as this would risk deadlocks and other disasters
  456. // if done from the device thread.
  457. SDL_PendingCameraEvent pending;
  458. pending.next = NULL;
  459. SDL_PendingCameraEvent *pending_tail = &pending;
  460. ObtainPhysicalCameraObj(device);
  461. const SDL_bool first_disconnect = SDL_AtomicCompareAndSwap(&device->zombie, 0, 1);
  462. if (first_disconnect) { // if already disconnected this device, don't do it twice.
  463. // Swap in "Zombie" versions of the usual platform interfaces, so the device will keep
  464. // making progress until the app closes it. Otherwise, streams might continue to
  465. // accumulate waste data that never drains, apps that depend on audio callbacks to
  466. // progress will freeze, etc.
  467. device->WaitDevice = ZombieWaitDevice;
  468. device->AcquireFrame = ZombieAcquireFrame;
  469. device->ReleaseFrame = ZombieReleaseFrame;
  470. // Zombie functions will just report the timestamp as SDL_GetTicksNS(), so we don't need to adjust anymore to get it to match.
  471. device->adjust_timestamp = 0;
  472. device->base_timestamp = 0;
  473. SDL_PendingCameraEvent *p = (SDL_PendingCameraEvent *) SDL_malloc(sizeof (SDL_PendingCameraEvent));
  474. if (p) { // if this failed, no event for you, but you have deeper problems anyhow.
  475. p->type = SDL_EVENT_CAMERA_DEVICE_REMOVED;
  476. p->devid = device->instance_id;
  477. p->next = NULL;
  478. pending_tail->next = p;
  479. pending_tail = p;
  480. }
  481. }
  482. ReleaseCamera(device);
  483. if (first_disconnect) {
  484. if (pending.next) { // NULL if event is disabled or disaster struck.
  485. SDL_LockRWLockForWriting(camera_driver.device_hash_lock);
  486. SDL_assert(camera_driver.pending_events_tail != NULL);
  487. SDL_assert(camera_driver.pending_events_tail->next == NULL);
  488. camera_driver.pending_events_tail->next = pending.next;
  489. camera_driver.pending_events_tail = pending_tail;
  490. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  491. }
  492. }
  493. }
  494. void SDL_CameraPermissionOutcome(SDL_Camera *device, SDL_bool approved)
  495. {
  496. if (!device) {
  497. return;
  498. }
  499. SDL_PendingCameraEvent pending;
  500. pending.next = NULL;
  501. SDL_PendingCameraEvent *pending_tail = &pending;
  502. const int permission = approved ? 1 : -1;
  503. ObtainPhysicalCameraObj(device);
  504. if (device->permission != permission) {
  505. device->permission = permission;
  506. SDL_PendingCameraEvent *p = (SDL_PendingCameraEvent *) SDL_malloc(sizeof (SDL_PendingCameraEvent));
  507. if (p) { // if this failed, no event for you, but you have deeper problems anyhow.
  508. p->type = approved ? SDL_EVENT_CAMERA_DEVICE_APPROVED : SDL_EVENT_CAMERA_DEVICE_DENIED;
  509. p->devid = device->instance_id;
  510. p->next = NULL;
  511. pending_tail->next = p;
  512. pending_tail = p;
  513. }
  514. }
  515. ReleaseCamera(device);
  516. if (pending.next) { // NULL if event is disabled or disaster struck.
  517. SDL_LockRWLockForWriting(camera_driver.device_hash_lock);
  518. SDL_assert(camera_driver.pending_events_tail != NULL);
  519. SDL_assert(camera_driver.pending_events_tail->next == NULL);
  520. camera_driver.pending_events_tail->next = pending.next;
  521. camera_driver.pending_events_tail = pending_tail;
  522. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  523. }
  524. }
  525. SDL_Camera *SDL_FindPhysicalCameraByCallback(SDL_bool (*callback)(SDL_Camera *device, void *userdata), void *userdata)
  526. {
  527. if (!SDL_GetCurrentCameraDriver()) {
  528. SDL_SetError("Camera subsystem is not initialized");
  529. return NULL;
  530. }
  531. const void *key;
  532. const void *value;
  533. void *iter = NULL;
  534. SDL_LockRWLockForReading(camera_driver.device_hash_lock);
  535. while (SDL_IterateHashTable(camera_driver.device_hash, &key, &value, &iter)) {
  536. SDL_Camera *device = (SDL_Camera *) value;
  537. if (callback(device, userdata)) { // found it?
  538. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  539. return device;
  540. }
  541. }
  542. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  543. SDL_SetError("Device not found");
  544. return NULL;
  545. }
  546. void SDL_CloseCamera(SDL_Camera *camera)
  547. {
  548. SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
  549. ClosePhysicalCamera(device);
  550. }
  551. int SDL_GetCameraFormat(SDL_Camera *camera, SDL_CameraSpec *spec)
  552. {
  553. if (!camera) {
  554. return SDL_InvalidParamError("camera");
  555. } else if (!spec) {
  556. return SDL_InvalidParamError("spec");
  557. }
  558. SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
  559. ObtainPhysicalCameraObj(device);
  560. const int retval = (device->permission > 0) ? 0 : SDL_SetError("Camera permission has not been granted");
  561. if (retval == 0) {
  562. SDL_copyp(spec, &device->spec);
  563. } else {
  564. SDL_zerop(spec);
  565. }
  566. ReleaseCamera(device);
  567. return 0;
  568. }
  569. const char *SDL_GetCameraName(SDL_CameraID instance_id)
  570. {
  571. const char *retval = NULL;
  572. SDL_Camera *device = ObtainPhysicalCamera(instance_id);
  573. if (device) {
  574. retval = SDL_CreateTemporaryString(device->name);
  575. ReleaseCamera(device);
  576. }
  577. return retval;
  578. }
  579. SDL_CameraPosition SDL_GetCameraPosition(SDL_CameraID instance_id)
  580. {
  581. SDL_CameraPosition retval = SDL_CAMERA_POSITION_UNKNOWN;
  582. SDL_Camera *device = ObtainPhysicalCamera(instance_id);
  583. if (device) {
  584. retval = device->position;
  585. ReleaseCamera(device);
  586. }
  587. return retval;
  588. }
  589. const SDL_CameraID *SDL_GetCameras(int *count)
  590. {
  591. int dummy_count;
  592. if (!count) {
  593. count = &dummy_count;
  594. }
  595. if (!SDL_GetCurrentCameraDriver()) {
  596. *count = 0;
  597. SDL_SetError("Camera subsystem is not initialized");
  598. return NULL;
  599. }
  600. SDL_CameraID *retval = NULL;
  601. SDL_LockRWLockForReading(camera_driver.device_hash_lock);
  602. int num_devices = SDL_AtomicGet(&camera_driver.device_count);
  603. retval = (SDL_CameraID *) SDL_malloc((num_devices + 1) * sizeof (SDL_CameraID));
  604. if (!retval) {
  605. num_devices = 0;
  606. } else {
  607. int devs_seen = 0;
  608. const void *key;
  609. const void *value;
  610. void *iter = NULL;
  611. while (SDL_IterateHashTable(camera_driver.device_hash, &key, &value, &iter)) {
  612. retval[devs_seen++] = (SDL_CameraID) (uintptr_t) key;
  613. }
  614. SDL_assert(devs_seen == num_devices);
  615. retval[devs_seen] = 0; // null-terminated.
  616. }
  617. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  618. *count = num_devices;
  619. return SDL_FreeLater(retval);
  620. }
  621. const SDL_CameraSpec * const *SDL_GetCameraSupportedFormats(SDL_CameraID instance_id, int *count)
  622. {
  623. if (count) {
  624. *count = 0;
  625. }
  626. SDL_Camera *device = ObtainPhysicalCamera(instance_id);
  627. if (!device) {
  628. return NULL;
  629. }
  630. int i;
  631. int num_specs = device->num_specs;
  632. const SDL_CameraSpec **retval = (const SDL_CameraSpec **) SDL_malloc(((num_specs + 1) * sizeof(*retval)) + (num_specs * sizeof (**retval)));
  633. if (retval) {
  634. SDL_CameraSpec *specs = (SDL_CameraSpec *)((Uint8 *)retval + ((num_specs + 1) * sizeof(*retval)));
  635. SDL_memcpy(specs, device->all_specs, num_specs * sizeof(*specs));
  636. for (i = 0; i < num_specs; ++i) {
  637. retval[i] = specs++;
  638. }
  639. retval[i] = NULL;
  640. if (count) {
  641. *count = num_specs;
  642. }
  643. }
  644. ReleaseCamera(device);
  645. return SDL_FreeLater(retval);
  646. }
  647. // Camera device thread. This is split into chunks, so drivers that need to control this directly can use the pieces they need without duplicating effort.
  648. void SDL_CameraThreadSetup(SDL_Camera *device)
  649. {
  650. //camera_driver.impl.ThreadInit(device);
  651. #ifdef SDL_VIDEO_DRIVER_ANDROID
  652. // TODO
  653. /*
  654. {
  655. // Set thread priority to THREAD_PRIORITY_VIDEO
  656. extern void Android_JNI_CameraSetThreadPriority(int, int);
  657. Android_JNI_CameraSetThreadPriority(device->recording, device);
  658. }*/
  659. #else
  660. // The camera capture is always a high priority thread
  661. SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
  662. #endif
  663. }
  664. SDL_bool SDL_CameraThreadIterate(SDL_Camera *device)
  665. {
  666. SDL_LockMutex(device->lock);
  667. if (SDL_AtomicGet(&device->shutdown)) {
  668. SDL_UnlockMutex(device->lock);
  669. return SDL_FALSE; // we're done, shut it down.
  670. }
  671. const int permission = device->permission;
  672. if (permission <= 0) {
  673. SDL_UnlockMutex(device->lock);
  674. return (permission < 0) ? SDL_FALSE : SDL_TRUE; // if permission was denied, shut it down. if undecided, we're done for now.
  675. }
  676. SDL_bool failed = SDL_FALSE; // set to true if disaster worthy of treating the device as lost has happened.
  677. SDL_Surface *acquired = NULL;
  678. SDL_Surface *output_surface = NULL;
  679. SurfaceList *slist = NULL;
  680. Uint64 timestampNS = 0;
  681. // AcquireFrame SHOULD NOT BLOCK, as we are holding a lock right now. Block in WaitDevice instead!
  682. const int rc = device->AcquireFrame(device, device->acquire_surface, &timestampNS);
  683. if (rc == 1) { // new frame acquired!
  684. #if DEBUG_CAMERA
  685. SDL_Log("CAMERA: New frame available! pixels=%p pitch=%d", device->acquire_surface->pixels, device->acquire_surface->pitch);
  686. #endif
  687. if (device->drop_frames > 0) {
  688. #if DEBUG_CAMERA
  689. SDL_Log("CAMERA: Dropping an initial frame");
  690. #endif
  691. device->drop_frames--;
  692. device->ReleaseFrame(device, device->acquire_surface);
  693. device->acquire_surface->pixels = NULL;
  694. device->acquire_surface->pitch = 0;
  695. } else if (device->empty_output_surfaces.next == NULL) {
  696. // uhoh, no output frames available! Either the app is slow, or it forgot to release frames when done with them. Drop this new frame.
  697. #if DEBUG_CAMERA
  698. SDL_Log("CAMERA: No empty output surfaces! Dropping frame!");
  699. #endif
  700. device->ReleaseFrame(device, device->acquire_surface);
  701. device->acquire_surface->pixels = NULL;
  702. device->acquire_surface->pitch = 0;
  703. } else {
  704. if (!device->adjust_timestamp) {
  705. device->adjust_timestamp = SDL_GetTicksNS();
  706. device->base_timestamp = timestampNS;
  707. }
  708. timestampNS = (timestampNS - device->base_timestamp) + device->adjust_timestamp;
  709. slist = device->empty_output_surfaces.next;
  710. output_surface = slist->surface;
  711. device->empty_output_surfaces.next = slist->next;
  712. acquired = device->acquire_surface;
  713. slist->timestampNS = timestampNS;
  714. }
  715. } else if (rc == 0) { // no frame available yet; not an error.
  716. #if 0 //DEBUG_CAMERA
  717. SDL_Log("CAMERA: No frame available yet.");
  718. #endif
  719. } else { // fatal error!
  720. SDL_assert(rc == -1);
  721. #if DEBUG_CAMERA
  722. SDL_Log("CAMERA: dev[%p] error AcquireFrame: %s", device, SDL_GetError());
  723. #endif
  724. failed = SDL_TRUE;
  725. }
  726. // we can let go of the lock once we've tried to grab a frame of video and maybe moved the output frame off the empty list.
  727. // this lets us chew up the CPU for conversion and scaling without blocking other threads.
  728. SDL_UnlockMutex(device->lock);
  729. if (failed) {
  730. SDL_assert(slist == NULL);
  731. SDL_assert(acquired == NULL);
  732. SDL_CameraDisconnected(device); // doh.
  733. } else if (acquired) { // we have a new frame, scale/convert if necessary and queue it for the app!
  734. SDL_assert(slist != NULL);
  735. if (!device->needs_scaling && !device->needs_conversion) { // no conversion needed? Just move the pointer/pitch into the output surface.
  736. #if DEBUG_CAMERA
  737. SDL_Log("CAMERA: Frame is going through without conversion!");
  738. #endif
  739. output_surface->w = acquired->w;
  740. output_surface->h = acquired->h;
  741. output_surface->pixels = acquired->pixels;
  742. output_surface->pitch = acquired->pitch;
  743. } else { // convert/scale into a different surface.
  744. #if DEBUG_CAMERA
  745. SDL_Log("CAMERA: Frame is getting converted!");
  746. #endif
  747. SDL_Surface *srcsurf = acquired;
  748. if (device->needs_scaling == -1) { // downscaling? Do it first. -1: downscale, 0: no scaling, 1: upscale
  749. SDL_Surface *dstsurf = device->needs_conversion ? device->conversion_surface : output_surface;
  750. SDL_SoftStretch(srcsurf, NULL, dstsurf, NULL, SDL_SCALEMODE_NEAREST); // !!! FIXME: linear scale? letterboxing?
  751. srcsurf = dstsurf;
  752. }
  753. if (device->needs_conversion) {
  754. SDL_Surface *dstsurf = (device->needs_scaling == 1) ? device->conversion_surface : output_surface;
  755. SDL_ConvertPixels(srcsurf->w, srcsurf->h,
  756. srcsurf->format, srcsurf->pixels, srcsurf->pitch,
  757. dstsurf->format, dstsurf->pixels, dstsurf->pitch);
  758. srcsurf = dstsurf;
  759. }
  760. if (device->needs_scaling == 1) { // upscaling? Do it last. -1: downscale, 0: no scaling, 1: upscale
  761. SDL_SoftStretch(srcsurf, NULL, output_surface, NULL, SDL_SCALEMODE_NEAREST); // !!! FIXME: linear scale? letterboxing?
  762. }
  763. // we made a copy, so we can give the driver back its resources.
  764. device->ReleaseFrame(device, acquired);
  765. }
  766. // we either released these already after we copied the data, or the pointer was migrated to output_surface.
  767. acquired->pixels = NULL;
  768. acquired->pitch = 0;
  769. // make the filled output surface available to the app.
  770. SDL_LockMutex(device->lock);
  771. slist->next = device->filled_output_surfaces.next;
  772. device->filled_output_surfaces.next = slist;
  773. SDL_UnlockMutex(device->lock);
  774. }
  775. return SDL_TRUE; // always go on if not shutting down, even if device failed.
  776. }
  777. void SDL_CameraThreadShutdown(SDL_Camera *device)
  778. {
  779. //device->FlushRecording(device);
  780. //camera_driver.impl.ThreadDeinit(device);
  781. //SDL_CameraThreadFinalize(device);
  782. }
  783. // Actual thread entry point, if driver didn't handle this itself.
  784. static int SDLCALL CameraThread(void *devicep)
  785. {
  786. SDL_Camera *device = (SDL_Camera *) devicep;
  787. #if DEBUG_CAMERA
  788. SDL_Log("CAMERA: dev[%p] Start thread 'CameraThread'", devicep);
  789. #endif
  790. SDL_assert(device != NULL);
  791. SDL_CameraThreadSetup(device);
  792. do {
  793. if (device->WaitDevice(device) < 0) {
  794. SDL_CameraDisconnected(device); // doh. (but don't break out of the loop, just be a zombie for now!)
  795. }
  796. } while (SDL_CameraThreadIterate(device));
  797. SDL_CameraThreadShutdown(device);
  798. #if DEBUG_CAMERA
  799. SDL_Log("CAMERA: dev[%p] End thread 'CameraThread'", devicep);
  800. #endif
  801. return 0;
  802. }
  803. static void ChooseBestCameraSpec(SDL_Camera *device, const SDL_CameraSpec *spec, SDL_CameraSpec *closest)
  804. {
  805. // Find the closest available native format/size...
  806. //
  807. // We want the exact size if possible, even if we have
  808. // to convert formats, because we can _probably_ do that
  809. // conversion losslessly at less expense verses scaling.
  810. //
  811. // Failing that, we want the size that's closest to the
  812. // requested aspect ratio, then the closest size within
  813. // that.
  814. SDL_zerop(closest);
  815. SDL_assert(((Uint32) SDL_PIXELFORMAT_UNKNOWN) == 0); // since we SDL_zerop'd to this value.
  816. if (device->num_specs == 0) { // device listed no specs! You get whatever you want!
  817. if (spec) {
  818. SDL_copyp(closest, spec);
  819. }
  820. return;
  821. } else if (!spec) { // nothing specifically requested, get the best format we can...
  822. // we sorted this into the "best" format order when adding the camera.
  823. SDL_copyp(closest, &device->all_specs[0]);
  824. } else { // specific thing requested, try to get as close to that as possible...
  825. const int num_specs = device->num_specs;
  826. int wantw = spec->width;
  827. int wanth = spec->height;
  828. if (wantw > 0 && wanth > 0) {
  829. // Find the sizes with the closest aspect ratio and then find the best fit of those.
  830. const float wantaspect = ((float)wantw) / ((float)wanth);
  831. const float epsilon = 1e-6f;
  832. float closestaspect = -9999999.0f;
  833. float closestdiff = 999999.0f;
  834. int closestdiffw = 9999999;
  835. for (int i = 0; i < num_specs; i++) {
  836. const SDL_CameraSpec *thisspec = &device->all_specs[i];
  837. const int thisw = thisspec->width;
  838. const int thish = thisspec->height;
  839. const float thisaspect = ((float)thisw) / ((float)thish);
  840. const float aspectdiff = SDL_fabsf(wantaspect - thisaspect);
  841. const float diff = SDL_fabsf(closestaspect - thisaspect);
  842. const int diffw = SDL_abs(thisw - wantw);
  843. if (diff < epsilon) { // matches current closestaspect? See if resolution is closer in size.
  844. if (diffw < closestdiffw) {
  845. closestdiffw = diffw;
  846. closest->width = thisw;
  847. closest->height = thish;
  848. }
  849. } else if (aspectdiff < closestdiff) { // this is a closer aspect ratio? Take it, reset resolution checks.
  850. closestdiff = aspectdiff;
  851. closestaspect = thisaspect;
  852. closestdiffw = diffw;
  853. closest->width = thisw;
  854. closest->height = thish;
  855. }
  856. }
  857. } else {
  858. SDL_copyp(closest, &device->all_specs[0]);
  859. }
  860. SDL_assert(closest->width > 0);
  861. SDL_assert(closest->height > 0);
  862. // okay, we have what we think is the best resolution, now we just need the best format that supports it...
  863. const SDL_PixelFormat wantfmt = spec->format;
  864. SDL_PixelFormat best_format = SDL_PIXELFORMAT_UNKNOWN;
  865. SDL_Colorspace best_colorspace = SDL_COLORSPACE_UNKNOWN;
  866. for (int i = 0; i < num_specs; i++) {
  867. const SDL_CameraSpec *thisspec = &device->all_specs[i];
  868. if ((thisspec->width == closest->width) && (thisspec->height == closest->height)) {
  869. if (best_format == SDL_PIXELFORMAT_UNKNOWN) {
  870. best_format = thisspec->format; // spec list is sorted by what we consider "best" format, so unless we find an exact match later, first size match is the one!
  871. best_colorspace = thisspec->colorspace;
  872. }
  873. if (thisspec->format == wantfmt) {
  874. best_format = thisspec->format;
  875. best_colorspace = thisspec->colorspace;
  876. break; // exact match, stop looking.
  877. }
  878. }
  879. }
  880. SDL_assert(best_format != SDL_PIXELFORMAT_UNKNOWN);
  881. SDL_assert(best_colorspace != SDL_COLORSPACE_UNKNOWN);
  882. closest->format = best_format;
  883. closest->colorspace = best_colorspace;
  884. // We have a resolution and a format, find the closest framerate...
  885. const float wantfps = spec->framerate_denominator ? ((float)spec->framerate_numerator / spec->framerate_denominator) : 0.0f;
  886. float closestfps = 9999999.0f;
  887. for (int i = 0; i < num_specs; i++) {
  888. const SDL_CameraSpec *thisspec = &device->all_specs[i];
  889. if ((thisspec->format == closest->format) && (thisspec->width == closest->width) && (thisspec->height == closest->height)) {
  890. if ((thisspec->framerate_numerator == spec->framerate_numerator) && (thisspec->framerate_denominator == spec->framerate_denominator)) {
  891. closest->framerate_numerator = thisspec->framerate_numerator;
  892. closest->framerate_denominator = thisspec->framerate_denominator;
  893. break; // exact match, stop looking.
  894. }
  895. const float thisfps = thisspec->framerate_denominator ? ((float)thisspec->framerate_numerator / thisspec->framerate_denominator) : 0.0f;
  896. const float fpsdiff = SDL_fabsf(wantfps - thisfps);
  897. if (fpsdiff < closestfps) { // this is a closest FPS? Take it until something closer arrives.
  898. closestfps = fpsdiff;
  899. closest->framerate_numerator = thisspec->framerate_numerator;
  900. closest->framerate_denominator = thisspec->framerate_denominator;
  901. }
  902. }
  903. }
  904. }
  905. SDL_assert(closest->width > 0);
  906. SDL_assert(closest->height > 0);
  907. SDL_assert(closest->format != SDL_PIXELFORMAT_UNKNOWN);
  908. }
  909. SDL_Camera *SDL_OpenCamera(SDL_CameraID instance_id, const SDL_CameraSpec *spec)
  910. {
  911. SDL_Camera *device = ObtainPhysicalCamera(instance_id);
  912. if (!device) {
  913. return NULL;
  914. }
  915. if (device->hidden != NULL) {
  916. ReleaseCamera(device);
  917. SDL_SetError("Camera already opened"); // we may remove this limitation at some point.
  918. return NULL;
  919. }
  920. SDL_AtomicSet(&device->shutdown, 0);
  921. // These start with the backend's implementation, but we might swap them out with zombie versions later.
  922. device->WaitDevice = camera_driver.impl.WaitDevice;
  923. device->AcquireFrame = camera_driver.impl.AcquireFrame;
  924. device->ReleaseFrame = camera_driver.impl.ReleaseFrame;
  925. SDL_CameraSpec closest;
  926. ChooseBestCameraSpec(device, spec, &closest);
  927. #if DEBUG_CAMERA
  928. SDL_Log("CAMERA: App wanted [(%dx%d) fmt=%s framerate=%d/%d], chose [(%dx%d) fmt=%s framerate=%d/%d]",
  929. spec ? spec->width : -1, spec ? spec->height : -1, spec ? SDL_GetPixelFormatName(spec->format) : "(null)", spec ? spec->framerate_numerator : -1, spec ? spec->framerate_denominator : -1,
  930. closest.width, closest.height, SDL_GetPixelFormatName(closest.format), closest.framerate_numerator, closest.framerate_denominator);
  931. #endif
  932. if (camera_driver.impl.OpenDevice(device, &closest) < 0) {
  933. ClosePhysicalCamera(device); // in case anything is half-initialized.
  934. ReleaseCamera(device);
  935. return NULL;
  936. }
  937. if (spec) {
  938. SDL_copyp(&device->spec, spec);
  939. if (spec->width <= 0 || spec->height <= 0) {
  940. device->spec.width = closest.width;
  941. device->spec.height = closest.height;
  942. }
  943. if (spec->format == SDL_PIXELFORMAT_UNKNOWN) {
  944. device->spec.format = closest.format;
  945. }
  946. if (spec->framerate_denominator == 0) {
  947. device->spec.framerate_numerator = closest.framerate_numerator;
  948. device->spec.framerate_denominator = closest.framerate_denominator;
  949. }
  950. } else {
  951. SDL_copyp(&device->spec, &closest);
  952. }
  953. SDL_copyp(&device->actual_spec, &closest);
  954. if ((closest.width == device->spec.width) && (closest.height == device->spec.height)) {
  955. device->needs_scaling = 0;
  956. } else {
  957. const Uint64 srcarea = ((Uint64) closest.width) * ((Uint64) closest.height);
  958. const Uint64 dstarea = ((Uint64) device->spec.width) * ((Uint64) device->spec.height);
  959. if (dstarea <= srcarea) {
  960. device->needs_scaling = -1; // downscaling (or changing to new aspect ratio with same area)
  961. } else {
  962. device->needs_scaling = 1; // upscaling
  963. }
  964. }
  965. device->needs_conversion = (closest.format != device->spec.format);
  966. device->acquire_surface = SDL_CreateSurfaceFrom(closest.width, closest.height, closest.format, NULL, 0);
  967. if (!device->acquire_surface) {
  968. ClosePhysicalCamera(device);
  969. ReleaseCamera(device);
  970. return NULL;
  971. }
  972. SDL_SetSurfaceColorspace(device->acquire_surface, closest.colorspace);
  973. // if we have to scale _and_ convert, we need a middleman surface, since we can't do both changes at once.
  974. if (device->needs_scaling && device->needs_conversion) {
  975. const SDL_bool downsampling_first = (device->needs_scaling < 0);
  976. const SDL_CameraSpec *s = downsampling_first ? &device->spec : &closest;
  977. const SDL_PixelFormat fmt = downsampling_first ? closest.format : device->spec.format;
  978. device->conversion_surface = SDL_CreateSurface(s->width, s->height, fmt);
  979. if (!device->conversion_surface) {
  980. ClosePhysicalCamera(device);
  981. ReleaseCamera(device);
  982. return NULL;
  983. }
  984. SDL_SetSurfaceColorspace(device->conversion_surface, closest.colorspace);
  985. }
  986. // output surfaces are in the app-requested format. If no conversion is necessary, we'll just use the pointers
  987. // the backend fills into acquired_surface, and you can get all the way from DMA access in the camera hardware
  988. // to the app without a single copy. Otherwise, these will be full surfaces that hold converted/scaled copies.
  989. for (int i = 0; i < (SDL_arraysize(device->output_surfaces) - 1); i++) {
  990. device->output_surfaces[i].next = &device->output_surfaces[i + 1];
  991. }
  992. device->empty_output_surfaces.next = device->output_surfaces;
  993. for (int i = 0; i < SDL_arraysize(device->output_surfaces); i++) {
  994. SDL_Surface *surf;
  995. if (device->needs_scaling || device->needs_conversion) {
  996. surf = SDL_CreateSurface(device->spec.width, device->spec.height, device->spec.format);
  997. } else {
  998. surf = SDL_CreateSurfaceFrom(device->spec.width, device->spec.height, device->spec.format, NULL, 0);
  999. }
  1000. if (!surf) {
  1001. ClosePhysicalCamera(device);
  1002. ReleaseCamera(device);
  1003. return NULL;
  1004. }
  1005. SDL_SetSurfaceColorspace(surf, closest.colorspace);
  1006. device->output_surfaces[i].surface = surf;
  1007. }
  1008. device->drop_frames = 1;
  1009. // Start the camera thread if necessary
  1010. if (!camera_driver.impl.ProvidesOwnCallbackThread) {
  1011. char threadname[64];
  1012. SDL_GetCameraThreadName(device, threadname, sizeof (threadname));
  1013. device->thread = SDL_CreateThread(CameraThread, threadname, device);
  1014. if (!device->thread) {
  1015. ClosePhysicalCamera(device);
  1016. ReleaseCamera(device);
  1017. SDL_SetError("Couldn't create camera thread");
  1018. return NULL;
  1019. }
  1020. }
  1021. ReleaseCamera(device); // unlock, we're good to go!
  1022. return (SDL_Camera *) device; // currently there's no separation between physical and logical device.
  1023. }
  1024. SDL_Surface *SDL_AcquireCameraFrame(SDL_Camera *camera, Uint64 *timestampNS)
  1025. {
  1026. if (timestampNS) {
  1027. *timestampNS = 0;
  1028. }
  1029. if (!camera) {
  1030. SDL_InvalidParamError("camera");
  1031. return NULL;
  1032. }
  1033. SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
  1034. ObtainPhysicalCameraObj(device);
  1035. if (device->permission <= 0) {
  1036. ReleaseCamera(device);
  1037. SDL_SetError("Camera permission has not been granted");
  1038. return NULL;
  1039. }
  1040. SDL_Surface *retval = NULL;
  1041. // frames are in this list from newest to oldest, so find the end of the list...
  1042. SurfaceList *slistprev = &device->filled_output_surfaces;
  1043. SurfaceList *slist = slistprev;
  1044. while (slist->next) {
  1045. slistprev = slist;
  1046. slist = slist->next;
  1047. }
  1048. const SDL_bool list_is_empty = (slist == slistprev);
  1049. if (!list_is_empty) { // report the oldest frame.
  1050. if (timestampNS) {
  1051. *timestampNS = slist->timestampNS;
  1052. }
  1053. retval = slist->surface;
  1054. slistprev->next = slist->next; // remove from filled list.
  1055. slist->next = device->app_held_output_surfaces.next; // add to app_held list.
  1056. device->app_held_output_surfaces.next = slist;
  1057. }
  1058. ReleaseCamera(device);
  1059. return retval;
  1060. }
  1061. int SDL_ReleaseCameraFrame(SDL_Camera *camera, SDL_Surface *frame)
  1062. {
  1063. if (!camera) {
  1064. return SDL_InvalidParamError("camera");
  1065. } else if (frame == NULL) {
  1066. return SDL_InvalidParamError("frame");
  1067. }
  1068. SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
  1069. ObtainPhysicalCameraObj(device);
  1070. SurfaceList *slistprev = &device->app_held_output_surfaces;
  1071. SurfaceList *slist;
  1072. for (slist = slistprev->next; slist != NULL; slist = slist->next) {
  1073. if (slist->surface == frame) {
  1074. break;
  1075. }
  1076. slistprev = slist;
  1077. }
  1078. if (!slist) {
  1079. ReleaseCamera(device);
  1080. return SDL_SetError("Surface was not acquired from this camera, or was already released");
  1081. }
  1082. // this pointer was owned by the backend (DMA memory or whatever), clear it out.
  1083. if (!device->needs_conversion && !device->needs_scaling) {
  1084. device->ReleaseFrame(device, frame);
  1085. frame->pixels = NULL;
  1086. frame->pitch = 0;
  1087. }
  1088. slist->timestampNS = 0;
  1089. // remove from app_held list...
  1090. slistprev->next = slist->next;
  1091. // insert at front of empty list (and we'll use it first when we need to fill a new frame).
  1092. slist->next = device->empty_output_surfaces.next;
  1093. device->empty_output_surfaces.next = slist;
  1094. ReleaseCamera(device);
  1095. return 0;
  1096. }
  1097. SDL_CameraID SDL_GetCameraID(SDL_Camera *camera)
  1098. {
  1099. SDL_CameraID retval = 0;
  1100. if (!camera) {
  1101. SDL_InvalidParamError("camera");
  1102. } else {
  1103. SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
  1104. ObtainPhysicalCameraObj(device);
  1105. retval = device->instance_id;
  1106. ReleaseCamera(device);
  1107. }
  1108. return retval;
  1109. }
  1110. SDL_PropertiesID SDL_GetCameraProperties(SDL_Camera *camera)
  1111. {
  1112. SDL_PropertiesID retval = 0;
  1113. if (!camera) {
  1114. SDL_InvalidParamError("camera");
  1115. } else {
  1116. SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
  1117. ObtainPhysicalCameraObj(device);
  1118. if (device->props == 0) {
  1119. device->props = SDL_CreateProperties();
  1120. }
  1121. retval = device->props;
  1122. ReleaseCamera(device);
  1123. }
  1124. return retval;
  1125. }
  1126. int SDL_GetCameraPermissionState(SDL_Camera *camera)
  1127. {
  1128. int retval;
  1129. if (!camera) {
  1130. retval = SDL_InvalidParamError("camera");
  1131. } else {
  1132. SDL_Camera *device = (SDL_Camera *) camera; // currently there's no separation between physical and logical device.
  1133. ObtainPhysicalCameraObj(device);
  1134. retval = device->permission;
  1135. ReleaseCamera(device);
  1136. }
  1137. return retval;
  1138. }
  1139. static void CompleteCameraEntryPoints(void)
  1140. {
  1141. // this doesn't currently fill in stub implementations, it just asserts the backend filled them all in.
  1142. #define FILL_STUB(x) SDL_assert(camera_driver.impl.x != NULL)
  1143. FILL_STUB(DetectDevices);
  1144. FILL_STUB(OpenDevice);
  1145. FILL_STUB(CloseDevice);
  1146. FILL_STUB(AcquireFrame);
  1147. FILL_STUB(ReleaseFrame);
  1148. FILL_STUB(FreeDeviceHandle);
  1149. FILL_STUB(Deinitialize);
  1150. #undef FILL_STUB
  1151. }
  1152. void SDL_QuitCamera(void)
  1153. {
  1154. if (!camera_driver.name) { // not initialized?!
  1155. return;
  1156. }
  1157. SDL_LockRWLockForWriting(camera_driver.device_hash_lock);
  1158. SDL_AtomicSet(&camera_driver.shutting_down, 1);
  1159. SDL_HashTable *device_hash = camera_driver.device_hash;
  1160. camera_driver.device_hash = NULL;
  1161. SDL_PendingCameraEvent *pending_events = camera_driver.pending_events.next;
  1162. camera_driver.pending_events.next = NULL;
  1163. SDL_AtomicSet(&camera_driver.device_count, 0);
  1164. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  1165. SDL_PendingCameraEvent *pending_next = NULL;
  1166. for (SDL_PendingCameraEvent *i = pending_events; i; i = pending_next) {
  1167. pending_next = i->next;
  1168. SDL_free(i);
  1169. }
  1170. const void *key;
  1171. const void *value;
  1172. void *iter = NULL;
  1173. while (SDL_IterateHashTable(device_hash, &key, &value, &iter)) {
  1174. DestroyPhysicalCamera((SDL_Camera *) value);
  1175. }
  1176. // Free the driver data
  1177. camera_driver.impl.Deinitialize();
  1178. SDL_DestroyRWLock(camera_driver.device_hash_lock);
  1179. SDL_DestroyHashTable(device_hash);
  1180. SDL_zero(camera_driver);
  1181. }
  1182. static Uint32 HashCameraID(const void *key, void *data)
  1183. {
  1184. // The values are unique incrementing integers, starting at 1, so just return minus 1 to start with bucket zero.
  1185. return ((Uint32) ((uintptr_t) key)) - 1;
  1186. }
  1187. static SDL_bool MatchCameraID(const void *a, const void *b, void *data)
  1188. {
  1189. return (a == b); // simple integers, just compare them as pointer values.
  1190. }
  1191. static void NukeCameraHashItem(const void *key, const void *value, void *data)
  1192. {
  1193. // no-op, keys and values in this hashtable are treated as Plain Old Data and don't get freed here.
  1194. }
  1195. int SDL_CameraInit(const char *driver_name)
  1196. {
  1197. if (SDL_GetCurrentCameraDriver()) {
  1198. SDL_QuitCamera(); // shutdown driver if already running.
  1199. }
  1200. SDL_RWLock *device_hash_lock = SDL_CreateRWLock(); // create this early, so if it fails we don't have to tear down the whole camera subsystem.
  1201. if (!device_hash_lock) {
  1202. return -1;
  1203. }
  1204. SDL_HashTable *device_hash = SDL_CreateHashTable(NULL, 8, HashCameraID, MatchCameraID, NukeCameraHashItem, SDL_FALSE);
  1205. if (!device_hash) {
  1206. SDL_DestroyRWLock(device_hash_lock);
  1207. return -1;
  1208. }
  1209. // Select the proper camera driver
  1210. if (!driver_name) {
  1211. driver_name = SDL_GetHint(SDL_HINT_CAMERA_DRIVER);
  1212. }
  1213. SDL_bool initialized = SDL_FALSE;
  1214. SDL_bool tried_to_init = SDL_FALSE;
  1215. if (driver_name && (*driver_name != 0)) {
  1216. char *driver_name_copy = SDL_strdup(driver_name);
  1217. const char *driver_attempt = driver_name_copy;
  1218. if (!driver_name_copy) {
  1219. SDL_DestroyRWLock(device_hash_lock);
  1220. SDL_DestroyHashTable(device_hash);
  1221. return -1;
  1222. }
  1223. while (driver_attempt && (*driver_attempt != 0) && !initialized) {
  1224. char *driver_attempt_end = SDL_strchr(driver_attempt, ',');
  1225. if (driver_attempt_end) {
  1226. *driver_attempt_end = '\0';
  1227. }
  1228. for (int i = 0; bootstrap[i]; i++) {
  1229. if (SDL_strcasecmp(bootstrap[i]->name, driver_attempt) == 0) {
  1230. tried_to_init = SDL_TRUE;
  1231. SDL_zero(camera_driver);
  1232. camera_driver.pending_events_tail = &camera_driver.pending_events;
  1233. camera_driver.device_hash_lock = device_hash_lock;
  1234. camera_driver.device_hash = device_hash;
  1235. if (bootstrap[i]->init(&camera_driver.impl)) {
  1236. camera_driver.name = bootstrap[i]->name;
  1237. camera_driver.desc = bootstrap[i]->desc;
  1238. initialized = SDL_TRUE;
  1239. }
  1240. break;
  1241. }
  1242. }
  1243. driver_attempt = (driver_attempt_end) ? (driver_attempt_end + 1) : NULL;
  1244. }
  1245. SDL_free(driver_name_copy);
  1246. } else {
  1247. for (int i = 0; !initialized && bootstrap[i]; i++) {
  1248. if (bootstrap[i]->demand_only) {
  1249. continue;
  1250. }
  1251. tried_to_init = SDL_TRUE;
  1252. SDL_zero(camera_driver);
  1253. camera_driver.pending_events_tail = &camera_driver.pending_events;
  1254. camera_driver.device_hash_lock = device_hash_lock;
  1255. camera_driver.device_hash = device_hash;
  1256. if (bootstrap[i]->init(&camera_driver.impl)) {
  1257. camera_driver.name = bootstrap[i]->name;
  1258. camera_driver.desc = bootstrap[i]->desc;
  1259. initialized = SDL_TRUE;
  1260. }
  1261. }
  1262. }
  1263. if (!initialized) {
  1264. // specific drivers will set the error message if they fail, but otherwise we do it here.
  1265. if (!tried_to_init) {
  1266. if (driver_name) {
  1267. SDL_SetError("Camera driver '%s' not available", driver_name);
  1268. } else {
  1269. SDL_SetError("No available camera driver");
  1270. }
  1271. }
  1272. SDL_zero(camera_driver);
  1273. SDL_DestroyRWLock(device_hash_lock);
  1274. SDL_DestroyHashTable(device_hash);
  1275. return -1; // No driver was available, so fail.
  1276. }
  1277. CompleteCameraEntryPoints();
  1278. // Make sure we have a list of devices available at startup...
  1279. camera_driver.impl.DetectDevices();
  1280. return 0;
  1281. }
  1282. // This is an internal function, so SDL_PumpEvents() can check for pending camera device events.
  1283. // ("UpdateSubsystem" is the same naming that the other things that hook into PumpEvents use.)
  1284. void SDL_UpdateCamera(void)
  1285. {
  1286. SDL_LockRWLockForReading(camera_driver.device_hash_lock);
  1287. SDL_PendingCameraEvent *pending_events = camera_driver.pending_events.next;
  1288. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  1289. if (!pending_events) {
  1290. return; // nothing to do, check next time.
  1291. }
  1292. // okay, let's take this whole list of events so we can dump the lock, and new ones can queue up for a later update.
  1293. SDL_LockRWLockForWriting(camera_driver.device_hash_lock);
  1294. pending_events = camera_driver.pending_events.next; // in case this changed...
  1295. camera_driver.pending_events.next = NULL;
  1296. camera_driver.pending_events_tail = &camera_driver.pending_events;
  1297. SDL_UnlockRWLock(camera_driver.device_hash_lock);
  1298. SDL_PendingCameraEvent *pending_next = NULL;
  1299. for (SDL_PendingCameraEvent *i = pending_events; i; i = pending_next) {
  1300. pending_next = i->next;
  1301. if (SDL_EventEnabled(i->type)) {
  1302. SDL_Event event;
  1303. SDL_zero(event);
  1304. event.type = i->type;
  1305. event.adevice.which = (Uint32) i->devid;
  1306. SDL_PushEvent(&event);
  1307. }
  1308. SDL_free(i);
  1309. }
  1310. }