camera_android.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930
  1. /**************************************************************************/
  2. /* camera_android.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "camera_android.h"
  31. #include "core/os/os.h"
  32. #include "platform/android/display_server_android.h"
  33. #include "platform/android/java_godot_io_wrapper.h"
  34. #include "platform/android/os_android.h"
  35. // Scope guard to ensure AImage instances are always deleted.
  36. class ScopedAImage {
  37. AImage *image = nullptr;
  38. public:
  39. ScopedAImage() = default;
  40. ~ScopedAImage() {
  41. reset();
  42. }
  43. ScopedAImage(const ScopedAImage &) = delete;
  44. ScopedAImage &operator=(const ScopedAImage &) = delete;
  45. AImage **out() {
  46. return ℑ
  47. }
  48. AImage *get() const {
  49. return image;
  50. }
  51. void reset(AImage *p_image = nullptr) {
  52. if (image != nullptr) {
  53. AImage_delete(image);
  54. }
  55. image = p_image;
  56. }
  57. };
  58. //////////////////////////////////////////////////////////////////////////
  59. // Helper functions
  60. //
  61. // The following code enables you to view the contents of a media type while
  62. // debugging.
  63. #ifndef IF_EQUAL_RETURN
  64. #define MAKE_FORMAT_CONST(suffix) AIMAGE_FORMAT_##suffix
  65. #define IF_EQUAL_RETURN(param, val) \
  66. if (MAKE_FORMAT_CONST(val) == param) \
  67. return #val
  68. #endif
  69. String GetFormatName(const int32_t &format) {
  70. IF_EQUAL_RETURN(format, YUV_420_888);
  71. IF_EQUAL_RETURN(format, RGB_888);
  72. IF_EQUAL_RETURN(format, RGBA_8888);
  73. return "Unsupported";
  74. }
  75. //////////////////////////////////////////////////////////////////////////
  76. // CameraFeedAndroid - Subclass for our camera feed on Android
  77. CameraFeedAndroid::CameraFeedAndroid(ACameraManager *manager, ACameraMetadata *metadata, const char *id,
  78. CameraFeed::FeedPosition position, int32_t orientation) :
  79. CameraFeed() {
  80. this->manager = manager;
  81. this->metadata = metadata;
  82. this->orientation = orientation;
  83. _add_formats();
  84. camera_id = id;
  85. set_position(position);
  86. // Position
  87. switch (position) {
  88. case CameraFeed::FEED_BACK:
  89. name = vformat("%s | BACK", id);
  90. break;
  91. case CameraFeed::FEED_FRONT:
  92. name = vformat("%s | FRONT", id);
  93. break;
  94. default:
  95. name = vformat("%s", id);
  96. break;
  97. }
  98. image_y.instantiate();
  99. image_uv.instantiate();
  100. }
  101. CameraFeedAndroid::~CameraFeedAndroid() {
  102. if (is_active()) {
  103. deactivate_feed();
  104. }
  105. if (metadata != nullptr) {
  106. ACameraMetadata_free(metadata);
  107. }
  108. }
  109. void CameraFeedAndroid::refresh_camera_metadata() {
  110. ERR_FAIL_NULL_MSG(manager, vformat("Camera %s: Cannot refresh metadata, manager is null.", camera_id));
  111. if (metadata != nullptr) {
  112. ACameraMetadata_free(metadata);
  113. metadata = nullptr;
  114. }
  115. camera_status_t status = ACameraManager_getCameraCharacteristics(manager, camera_id.utf8().get_data(), &metadata);
  116. if (status != ACAMERA_OK || metadata == nullptr) {
  117. ERR_FAIL_MSG(vformat("Camera %s: Failed to refresh metadata (status: %d).", camera_id, status));
  118. }
  119. ACameraMetadata_const_entry orientation_entry;
  120. status = ACameraMetadata_getConstEntry(metadata, ACAMERA_SENSOR_ORIENTATION, &orientation_entry);
  121. if (status == ACAMERA_OK) {
  122. orientation = orientation_entry.data.i32[0];
  123. print_verbose(vformat("Camera %s: Orientation updated to %d.", camera_id, orientation));
  124. } else {
  125. ERR_PRINT(vformat("Camera %s: Failed to get sensor orientation after refresh (status: %d).", camera_id, status));
  126. }
  127. formats.clear();
  128. _add_formats();
  129. print_verbose(vformat("Camera %s: Metadata refreshed successfully.", camera_id));
  130. }
  131. void CameraFeedAndroid::_set_rotation() {
  132. if (!metadata) {
  133. print_verbose(vformat("Camera %s: Metadata is null in _set_rotation, attempting refresh.", camera_id));
  134. refresh_camera_metadata();
  135. }
  136. float image_rotation = 0.0f;
  137. std::optional<int> result;
  138. if (metadata) {
  139. CameraRotationParams params;
  140. params.sensor_orientation = orientation;
  141. params.camera_facing = (position == CameraFeed::FEED_FRONT) ? CameraFacing::FRONT : CameraFacing::BACK;
  142. params.display_rotation = get_app_orientation();
  143. result = calculate_rotation(params);
  144. } else {
  145. ERR_PRINT(vformat("Camera %s: Cannot update rotation, metadata unavailable after refresh, using fallback.", camera_id));
  146. }
  147. if (result.has_value()) {
  148. image_rotation = static_cast<float>(result.value());
  149. } else {
  150. int display_rotation = DisplayServerAndroid::get_singleton()->get_display_rotation();
  151. switch (display_rotation) {
  152. case 90:
  153. display_rotation = 270;
  154. break;
  155. case 270:
  156. display_rotation = 90;
  157. break;
  158. default:
  159. break;
  160. }
  161. int sign = position == CameraFeed::FEED_FRONT ? 1 : -1;
  162. image_rotation = (orientation - display_rotation * sign + 360) % 360;
  163. }
  164. transform = Transform2D();
  165. transform = transform.rotated(Math::deg_to_rad(image_rotation));
  166. }
  167. void CameraFeedAndroid::_add_formats() {
  168. // Get supported formats
  169. ACameraMetadata_const_entry formats;
  170. camera_status_t status = ACameraMetadata_getConstEntry(metadata, ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &formats);
  171. if (status == ACAMERA_OK) {
  172. for (uint32_t f = 0; f < formats.count; f += 4) {
  173. // Only support output streams
  174. int32_t input = formats.data.i32[f + 3];
  175. if (input) {
  176. continue;
  177. }
  178. // Get format and resolution
  179. int32_t format = formats.data.i32[f + 0];
  180. if (format == AIMAGE_FORMAT_YUV_420_888 ||
  181. format == AIMAGE_FORMAT_RGBA_8888 ||
  182. format == AIMAGE_FORMAT_RGB_888) {
  183. CameraFeed::FeedFormat feed_format;
  184. feed_format.width = formats.data.i32[f + 1];
  185. feed_format.height = formats.data.i32[f + 2];
  186. feed_format.format = GetFormatName(format);
  187. feed_format.pixel_format = format;
  188. this->formats.append(feed_format);
  189. }
  190. }
  191. }
  192. }
  193. bool CameraFeedAndroid::activate_feed() {
  194. ERR_FAIL_COND_V_MSG(formats.is_empty(), false, "No camera formats available.");
  195. ERR_FAIL_INDEX_V_MSG(selected_format, formats.size(), false,
  196. vformat("CameraFeed format needs to be set before activating. Selected format index: %d (formats size: %d)", selected_format, formats.size()));
  197. if (is_active()) {
  198. deactivate_feed();
  199. };
  200. // Clear deactivation and error flags before starting activation.
  201. is_deactivating.clear();
  202. device_error_occurred.clear();
  203. // Request permission
  204. if (!OS::get_singleton()->request_permission("CAMERA")) {
  205. return false;
  206. }
  207. // Open device
  208. device_callbacks = {
  209. .context = this,
  210. .onDisconnected = onDisconnected,
  211. .onError = onError,
  212. };
  213. camera_status_t c_status = ACameraManager_openCamera(manager, camera_id.utf8().get_data(), &device_callbacks, &device);
  214. if (c_status != ACAMERA_OK) {
  215. print_error(vformat("Camera %s: Failed to open camera (status: %d)", camera_id, c_status));
  216. deactivate_feed();
  217. return false;
  218. }
  219. // Create image reader
  220. const FeedFormat &feed_format = formats[selected_format];
  221. media_status_t m_status = AImageReader_new(feed_format.width, feed_format.height, feed_format.pixel_format, 1, &reader);
  222. if (m_status != AMEDIA_OK) {
  223. print_error(vformat("Camera %s: Failed to create image reader (status: %d)", camera_id, m_status));
  224. deactivate_feed();
  225. return false;
  226. }
  227. // Get image listener
  228. image_listener = {
  229. .context = this,
  230. .onImageAvailable = onImage,
  231. };
  232. m_status = AImageReader_setImageListener(reader, &image_listener);
  233. if (m_status != AMEDIA_OK) {
  234. print_error(vformat("Camera %s: Failed to set image listener (status: %d)", camera_id, m_status));
  235. deactivate_feed();
  236. return false;
  237. }
  238. // Get image surface
  239. ANativeWindow *surface;
  240. m_status = AImageReader_getWindow(reader, &surface);
  241. if (m_status != AMEDIA_OK) {
  242. print_error(vformat("Camera %s: Failed to get image surface (status: %d)", camera_id, m_status));
  243. deactivate_feed();
  244. return false;
  245. }
  246. // Prepare session outputs
  247. c_status = ACaptureSessionOutput_create(surface, &session_output);
  248. if (c_status != ACAMERA_OK) {
  249. print_error(vformat("Camera %s: Failed to create session output (status: %d)", camera_id, c_status));
  250. deactivate_feed();
  251. return false;
  252. }
  253. c_status = ACaptureSessionOutputContainer_create(&session_output_container);
  254. if (c_status != ACAMERA_OK) {
  255. print_error(vformat("Camera %s: Failed to create session output container (status: %d)", camera_id, c_status));
  256. deactivate_feed();
  257. return false;
  258. }
  259. c_status = ACaptureSessionOutputContainer_add(session_output_container, session_output);
  260. if (c_status != ACAMERA_OK) {
  261. print_error(vformat("Camera %s: Failed to add session output to container (status: %d)", camera_id, c_status));
  262. deactivate_feed();
  263. return false;
  264. }
  265. // Create capture session
  266. session_callbacks = {
  267. .context = this,
  268. .onClosed = onSessionClosed,
  269. .onReady = onSessionReady,
  270. .onActive = onSessionActive
  271. };
  272. c_status = ACameraDevice_createCaptureSession(device, session_output_container, &session_callbacks, &session);
  273. if (c_status != ACAMERA_OK) {
  274. print_error(vformat("Camera %s: Failed to create capture session (status: %d)", camera_id, c_status));
  275. deactivate_feed();
  276. return false;
  277. }
  278. // Create capture request
  279. c_status = ACameraDevice_createCaptureRequest(device, TEMPLATE_PREVIEW, &request);
  280. if (c_status != ACAMERA_OK) {
  281. print_error(vformat("Camera %s: Failed to create capture request (status: %d)", camera_id, c_status));
  282. deactivate_feed();
  283. return false;
  284. }
  285. // Set capture target
  286. c_status = ACameraOutputTarget_create(surface, &camera_output_target);
  287. if (c_status != ACAMERA_OK) {
  288. print_error(vformat("Camera %s: Failed to create camera output target (status: %d)", camera_id, c_status));
  289. deactivate_feed();
  290. return false;
  291. }
  292. c_status = ACaptureRequest_addTarget(request, camera_output_target);
  293. if (c_status != ACAMERA_OK) {
  294. print_error(vformat("Camera %s: Failed to add target to capture request (status: %d)", camera_id, c_status));
  295. deactivate_feed();
  296. return false;
  297. }
  298. // Start capture
  299. c_status = ACameraCaptureSession_setRepeatingRequest(session, nullptr, 1, &request, nullptr);
  300. if (c_status != ACAMERA_OK) {
  301. print_error(vformat("Camera %s: Failed to start repeating request (status: %d)", camera_id, c_status));
  302. deactivate_feed();
  303. return false;
  304. }
  305. return true;
  306. }
  307. bool CameraFeedAndroid::set_format(int p_index, const Dictionary &p_parameters) {
  308. ERR_FAIL_COND_V_MSG(active, false, "Feed is active.");
  309. ERR_FAIL_INDEX_V_MSG(p_index, formats.size(), false, "Invalid format index.");
  310. selected_format = p_index;
  311. // Reset base dimensions to force texture recreation on next frame.
  312. // This ensures proper handling when switching between different resolutions.
  313. base_width = 0;
  314. base_height = 0;
  315. return true;
  316. }
  317. Array CameraFeedAndroid::get_formats() const {
  318. Array result;
  319. for (const FeedFormat &feed_format : formats) {
  320. Dictionary dictionary;
  321. dictionary["width"] = feed_format.width;
  322. dictionary["height"] = feed_format.height;
  323. dictionary["format"] = feed_format.format;
  324. result.push_back(dictionary);
  325. }
  326. return result;
  327. }
  328. CameraFeed::FeedFormat CameraFeedAndroid::get_format() const {
  329. CameraFeed::FeedFormat feed_format = {};
  330. ERR_FAIL_INDEX_V_MSG(selected_format, formats.size(), feed_format,
  331. vformat("Invalid format index: %d (formats size: %d)", selected_format, formats.size()));
  332. return formats[selected_format];
  333. }
  334. void CameraFeedAndroid::handle_pause() {
  335. if (is_active()) {
  336. was_active_before_pause = true;
  337. print_verbose(vformat("Camera %s: Pausing (was active).", camera_id));
  338. deactivate_feed();
  339. } else {
  340. was_active_before_pause = false;
  341. }
  342. }
  343. void CameraFeedAndroid::handle_resume() {
  344. if (was_active_before_pause) {
  345. print_verbose(vformat("Camera %s: Resuming.", camera_id));
  346. activate_feed();
  347. was_active_before_pause = false;
  348. }
  349. }
  350. void CameraFeedAndroid::handle_rotation_change() {
  351. if (!is_active()) {
  352. return;
  353. }
  354. print_verbose(vformat("Camera %s: Handling rotation change.", camera_id));
  355. refresh_camera_metadata();
  356. _set_rotation();
  357. }
  358. // In-place stride compaction (handles row padding).
  359. void CameraFeedAndroid::compact_stride_inplace(uint8_t *data, size_t width, int height, size_t stride) {
  360. if (stride <= width) {
  361. return;
  362. }
  363. uint8_t *src_row = data + stride;
  364. uint8_t *dst_row = data + width;
  365. for (int y = 1; y < height; y++) {
  366. memmove(dst_row, src_row, width);
  367. src_row += stride;
  368. dst_row += width;
  369. }
  370. }
  371. void CameraFeedAndroid::onImage(void *context, AImageReader *p_reader) {
  372. CameraFeedAndroid *feed = static_cast<CameraFeedAndroid *>(context);
  373. // Check deactivation flag before acquiring mutex to avoid using resources
  374. // that may be deleted during deactivate_feed(). This is a racy check but
  375. // safe because we only transition is_deactivating from false->true during
  376. // deactivation, and back to false only at the start of activation.
  377. if (feed->is_deactivating.is_set()) {
  378. // Don't try to acquire images - the reader may be deleted.
  379. // Android will clean up pending images when the reader is deleted.
  380. return;
  381. }
  382. MutexLock lock(feed->callback_mutex);
  383. // Re-check after acquiring mutex in case deactivation started while waiting.
  384. if (feed->is_deactivating.is_set()) {
  385. return;
  386. }
  387. // If feed is not active, we must still acquire and discard the image to
  388. // free the buffer slot. Otherwise, with maxImages=1, the buffer stays full
  389. // and no new frames will arrive (onImage won't be called again).
  390. // This can happen when a frame arrives between activate_feed() returning
  391. // and active=true being set in the base class.
  392. if (!feed->is_active()) {
  393. AImage *pending_image = nullptr;
  394. if (AImageReader_acquireNextImage(p_reader, &pending_image) == AMEDIA_OK && pending_image != nullptr) {
  395. AImage_delete(pending_image);
  396. }
  397. return;
  398. }
  399. Vector<uint8_t> data_y;
  400. Vector<uint8_t> data_uv;
  401. // Get image
  402. ScopedAImage image_guard;
  403. media_status_t status = AImageReader_acquireNextImage(p_reader, image_guard.out());
  404. ERR_FAIL_COND(status != AMEDIA_OK);
  405. AImage *image = image_guard.get();
  406. // Get image data
  407. uint8_t *data = nullptr;
  408. int len = 0;
  409. int32_t pixel_stride, row_stride;
  410. FeedFormat format = feed->get_format();
  411. int width = format.width;
  412. int height = format.height;
  413. switch (format.pixel_format) {
  414. case AIMAGE_FORMAT_YUV_420_888: {
  415. int32_t y_row_stride;
  416. AImage_getPlaneRowStride(image, 0, &y_row_stride);
  417. AImage_getPlaneData(image, 0, &data, &len);
  418. if (len <= 0) {
  419. return;
  420. }
  421. int64_t y_size = Image::get_image_data_size(width, height, Image::FORMAT_R8, false);
  422. if (y_row_stride == width && len == y_size) {
  423. data_y.resize(y_size);
  424. memcpy(data_y.ptrw(), data, y_size);
  425. } else {
  426. // Validate buffer size before compaction to prevent out-of-bounds read.
  427. int64_t required_y_len = (int64_t)y_row_stride * (height - 1) + width;
  428. if (len < required_y_len) {
  429. return;
  430. }
  431. if (feed->scratch_y.size() < len) {
  432. feed->scratch_y.resize(len);
  433. }
  434. memcpy(feed->scratch_y.ptrw(), data, len);
  435. CameraFeedAndroid::compact_stride_inplace(feed->scratch_y.ptrw(), width, height, y_row_stride);
  436. data_y.resize(y_size);
  437. memcpy(data_y.ptrw(), feed->scratch_y.ptr(), y_size);
  438. }
  439. AImage_getPlanePixelStride(image, 1, &pixel_stride);
  440. AImage_getPlaneRowStride(image, 1, &row_stride);
  441. AImage_getPlaneData(image, 1, &data, &len);
  442. if (len <= 0) {
  443. return;
  444. }
  445. int64_t uv_size = Image::get_image_data_size(width / 2, height / 2, Image::FORMAT_RG8, false);
  446. int uv_width = width / 2;
  447. int uv_height = height / 2;
  448. uint8_t *data_v = nullptr;
  449. int32_t v_pixel_stride = 0;
  450. int32_t v_row_stride = 0;
  451. int len_v = 0;
  452. if (pixel_stride != 2) {
  453. AImage_getPlanePixelStride(image, 2, &v_pixel_stride);
  454. AImage_getPlaneRowStride(image, 2, &v_row_stride);
  455. AImage_getPlaneData(image, 2, &data_v, &len_v);
  456. if (len_v <= 0) {
  457. return;
  458. }
  459. }
  460. if (pixel_stride == 2 && row_stride == uv_width * 2 && len == uv_size) {
  461. data_uv.resize(uv_size);
  462. memcpy(data_uv.ptrw(), data, uv_size);
  463. } else if (pixel_stride == 2) {
  464. // Allow 1-2 byte tolerance for UV buffer (some devices omit final bytes).
  465. int64_t required_uv_len = (int64_t)row_stride * (uv_height - 1) + uv_width * 2;
  466. const int64_t UV_TOLERANCE = 2;
  467. if (len < required_uv_len - UV_TOLERANCE) {
  468. return;
  469. }
  470. if (feed->scratch_uv.size() < required_uv_len) {
  471. feed->scratch_uv.resize(required_uv_len);
  472. }
  473. if (len < required_uv_len) {
  474. memset(feed->scratch_uv.ptrw() + len, 128, required_uv_len - len);
  475. }
  476. memcpy(feed->scratch_uv.ptrw(), data, len);
  477. if (row_stride != uv_width * 2) {
  478. CameraFeedAndroid::compact_stride_inplace(feed->scratch_uv.ptrw(), uv_width * 2, uv_height, row_stride);
  479. }
  480. data_uv.resize(uv_size);
  481. memcpy(data_uv.ptrw(), feed->scratch_uv.ptr(), uv_size);
  482. } else {
  483. if (data_v && len_v > 0) {
  484. data_uv.resize(uv_size);
  485. uint8_t *dst = data_uv.ptrw();
  486. uint8_t *src_u = data;
  487. uint8_t *src_v = data_v;
  488. for (int row = 0; row < uv_height; row++) {
  489. for (int col = 0; col < uv_width; col++) {
  490. dst[col * 2] = src_u[col * pixel_stride];
  491. dst[col * 2 + 1] = src_v[col * v_pixel_stride];
  492. }
  493. dst += uv_width * 2;
  494. src_u += row_stride;
  495. src_v += v_row_stride;
  496. }
  497. } else {
  498. data_uv.resize(uv_size);
  499. memset(data_uv.ptrw(), 128, uv_size);
  500. }
  501. }
  502. // Defer to main thread to avoid race conditions with RenderingServer.
  503. feed->image_y.instantiate();
  504. feed->image_y->initialize_data(width, height, false, Image::FORMAT_R8, data_y);
  505. feed->image_uv.instantiate();
  506. feed->image_uv->initialize_data(width / 2, height / 2, false, Image::FORMAT_RG8, data_uv);
  507. feed->call_deferred("set_ycbcr_images", feed->image_y, feed->image_uv);
  508. break;
  509. }
  510. case AIMAGE_FORMAT_RGBA_8888: {
  511. AImage_getPlaneData(image, 0, &data, &len);
  512. if (len <= 0) {
  513. return;
  514. }
  515. int64_t size = Image::get_image_data_size(width, height, Image::FORMAT_RGBA8, false);
  516. data_y.resize(len > size ? len : size);
  517. memcpy(data_y.ptrw(), data, len);
  518. feed->image_y.instantiate();
  519. feed->image_y->initialize_data(width, height, false, Image::FORMAT_RGBA8, data_y);
  520. feed->call_deferred("set_rgb_image", feed->image_y);
  521. break;
  522. }
  523. case AIMAGE_FORMAT_RGB_888: {
  524. AImage_getPlaneData(image, 0, &data, &len);
  525. if (len <= 0) {
  526. return;
  527. }
  528. int64_t size = Image::get_image_data_size(width, height, Image::FORMAT_RGB8, false);
  529. data_y.resize(len > size ? len : size);
  530. memcpy(data_y.ptrw(), data, len);
  531. feed->image_y.instantiate();
  532. feed->image_y->initialize_data(width, height, false, Image::FORMAT_RGB8, data_y);
  533. feed->call_deferred("set_rgb_image", feed->image_y);
  534. break;
  535. }
  536. default:
  537. return;
  538. }
  539. if (!feed->formats.is_empty()) {
  540. if (feed->metadata != nullptr) {
  541. feed->_set_rotation();
  542. } else {
  543. print_verbose(vformat("Camera %s: Metadata invalidated in onImage, attempting refresh.", feed->camera_id));
  544. feed->refresh_camera_metadata();
  545. if (feed->metadata != nullptr && !feed->formats.is_empty()) {
  546. feed->_set_rotation();
  547. }
  548. }
  549. }
  550. // Release image happens automatically via ScopedAImage.
  551. }
  552. void CameraFeedAndroid::onSessionReady(void *context, ACameraCaptureSession *session) {
  553. print_verbose("Capture session ready");
  554. }
  555. void CameraFeedAndroid::onSessionActive(void *context, ACameraCaptureSession *session) {
  556. print_verbose("Capture session active");
  557. }
  558. void CameraFeedAndroid::onSessionClosed(void *context, ACameraCaptureSession *p_session) {
  559. CameraFeedAndroid *feed = static_cast<CameraFeedAndroid *>(context);
  560. // Only post if deactivate_feed() is waiting for us. This prevents
  561. // spurious posts from error-triggered session closes that could
  562. // desynchronize the semaphore count.
  563. if (feed->session_close_pending.is_set()) {
  564. feed->session_closed_semaphore.post();
  565. }
  566. }
  567. void CameraFeedAndroid::deactivate_feed() {
  568. // Signal that deactivation is in progress. This prevents onImage callbacks
  569. // from using resources that may be deleted during cleanup.
  570. is_deactivating.set();
  571. // First, remove image listener to prevent new callbacks.
  572. if (reader != nullptr) {
  573. AImageReader_setImageListener(reader, nullptr);
  574. }
  575. // Stop and close capture session.
  576. // Must wait for session to fully close before closing device.
  577. if (session != nullptr) {
  578. ACameraCaptureSession_stopRepeating(session);
  579. // If an error occurred, the session may have already been closed by
  580. // Android. In that case, ACameraCaptureSession_close() may not trigger
  581. // onSessionClosed, so we skip waiting to avoid a deadlock.
  582. bool skip_wait = device_error_occurred.is_set();
  583. if (!skip_wait) {
  584. // Set flag before closing to indicate we're waiting for the callback.
  585. // This ensures we only wait for the post from THIS close operation.
  586. session_close_pending.set();
  587. }
  588. ACameraCaptureSession_close(session);
  589. if (!skip_wait) {
  590. // Wait for onSessionClosed callback to ensure session is fully closed
  591. // before proceeding to close the device.
  592. session_closed_semaphore.wait();
  593. session_close_pending.clear();
  594. }
  595. session = nullptr;
  596. }
  597. // Now safe to acquire lock and clean up resources.
  598. // No new callbacks will be triggered after this point.
  599. MutexLock lock(callback_mutex);
  600. if (device != nullptr) {
  601. ACameraDevice_close(device);
  602. device = nullptr;
  603. }
  604. if (reader != nullptr) {
  605. AImageReader_delete(reader);
  606. reader = nullptr;
  607. }
  608. if (request != nullptr) {
  609. ACaptureRequest_free(request);
  610. request = nullptr;
  611. }
  612. if (camera_output_target != nullptr) {
  613. ACameraOutputTarget_free(camera_output_target);
  614. camera_output_target = nullptr;
  615. }
  616. if (session_output_container != nullptr) {
  617. ACaptureSessionOutputContainer_free(session_output_container);
  618. session_output_container = nullptr;
  619. }
  620. if (session_output != nullptr) {
  621. ACaptureSessionOutput_free(session_output);
  622. session_output = nullptr;
  623. }
  624. }
  625. void CameraFeedAndroid::onError(void *context, ACameraDevice *p_device, int error) {
  626. CameraFeedAndroid *feed = static_cast<CameraFeedAndroid *>(context);
  627. print_error(vformat("Camera %s error: %d", feed->camera_id, error));
  628. // Mark that an error occurred. This signals to deactivate_feed() that
  629. // the session may have been closed by Android, so we shouldn't wait
  630. // for onSessionClosed.
  631. feed->device_error_occurred.set();
  632. onDisconnected(context, p_device);
  633. }
  634. void CameraFeedAndroid::onDisconnected(void *context, ACameraDevice *p_device) {
  635. CameraFeedAndroid *feed = static_cast<CameraFeedAndroid *>(context);
  636. // Defer to main thread to avoid reentrancy issues when called from
  637. // ACameraDevice_close() during deactivate_feed().
  638. feed->call_deferred("set_active", false);
  639. }
  640. //////////////////////////////////////////////////////////////////////////
  641. // CameraAndroid - Subclass for our camera server on Android
  642. void CameraAndroid::update_feeds() {
  643. ACameraIdList *cameraIds = nullptr;
  644. camera_status_t c_status = ACameraManager_getCameraIdList(cameraManager, &cameraIds);
  645. ERR_FAIL_COND(c_status != ACAMERA_OK);
  646. // Deactivate all feeds before removing to ensure proper cleanup.
  647. for (int i = 0; i < feeds.size(); i++) {
  648. Ref<CameraFeedAndroid> feed = feeds[i];
  649. if (feed.is_valid() && feed->is_active()) {
  650. feed->deactivate_feed();
  651. }
  652. }
  653. // remove existing devices
  654. for (int i = feeds.size() - 1; i >= 0; i--) {
  655. remove_feed(feeds[i]);
  656. }
  657. for (int c = 0; c < cameraIds->numCameras; ++c) {
  658. const char *id = cameraIds->cameraIds[c];
  659. ACameraMetadata *metadata = nullptr;
  660. ACameraManager_getCameraCharacteristics(cameraManager, id, &metadata);
  661. if (!metadata) {
  662. continue;
  663. }
  664. // Get sensor orientation
  665. ACameraMetadata_const_entry orientation;
  666. c_status = ACameraMetadata_getConstEntry(metadata, ACAMERA_SENSOR_ORIENTATION, &orientation);
  667. int32_t cameraOrientation;
  668. if (c_status == ACAMERA_OK) {
  669. cameraOrientation = orientation.data.i32[0];
  670. } else {
  671. cameraOrientation = 0;
  672. print_error(vformat("Unable to get sensor orientation: %s", id));
  673. }
  674. // Get position
  675. ACameraMetadata_const_entry lensInfo;
  676. CameraFeed::FeedPosition position = CameraFeed::FEED_UNSPECIFIED;
  677. camera_status_t status;
  678. status = ACameraMetadata_getConstEntry(metadata, ACAMERA_LENS_FACING, &lensInfo);
  679. if (status != ACAMERA_OK) {
  680. ACameraMetadata_free(metadata);
  681. continue;
  682. }
  683. uint8_t lens_facing = static_cast<acamera_metadata_enum_android_lens_facing_t>(lensInfo.data.u8[0]);
  684. if (lens_facing == ACAMERA_LENS_FACING_FRONT) {
  685. position = CameraFeed::FEED_FRONT;
  686. } else if (lens_facing == ACAMERA_LENS_FACING_BACK) {
  687. position = CameraFeed::FEED_BACK;
  688. } else {
  689. ACameraMetadata_free(metadata);
  690. continue;
  691. }
  692. Ref<CameraFeedAndroid> feed = memnew(CameraFeedAndroid(cameraManager, metadata, id, position, cameraOrientation));
  693. add_feed(feed);
  694. }
  695. ACameraManager_deleteCameraIdList(cameraIds);
  696. emit_signal(SNAME(CameraServer::feeds_updated_signal_name));
  697. }
  698. void CameraAndroid::remove_all_feeds() {
  699. // Deactivate all feeds before removing to ensure proper cleanup.
  700. // This prevents "Device is closed but session is not notified" warnings
  701. // that can occur if feeds are destroyed while still active.
  702. for (int i = 0; i < feeds.size(); i++) {
  703. Ref<CameraFeedAndroid> feed = feeds[i];
  704. if (feed.is_valid() && feed->is_active()) {
  705. feed->deactivate_feed();
  706. }
  707. }
  708. // remove existing devices
  709. for (int i = feeds.size() - 1; i >= 0; i--) {
  710. remove_feed(feeds[i]);
  711. }
  712. if (cameraManager != nullptr) {
  713. ACameraManager_delete(cameraManager);
  714. cameraManager = nullptr;
  715. }
  716. }
  717. void CameraAndroid::set_monitoring_feeds(bool p_monitoring_feeds) {
  718. if (p_monitoring_feeds == monitoring_feeds) {
  719. return;
  720. }
  721. CameraServer::set_monitoring_feeds(p_monitoring_feeds);
  722. if (p_monitoring_feeds) {
  723. if (cameraManager == nullptr) {
  724. cameraManager = ACameraManager_create();
  725. }
  726. // Update feeds
  727. update_feeds();
  728. } else {
  729. remove_all_feeds();
  730. }
  731. }
  732. void CameraAndroid::handle_application_pause() {
  733. for (int i = 0; i < feeds.size(); i++) {
  734. Ref<CameraFeedAndroid> feed = feeds[i];
  735. if (feed.is_valid()) {
  736. feed->handle_pause();
  737. }
  738. }
  739. }
  740. void CameraAndroid::handle_application_resume() {
  741. for (int i = 0; i < feeds.size(); i++) {
  742. Ref<CameraFeedAndroid> feed = feeds[i];
  743. if (feed.is_valid()) {
  744. feed->handle_resume();
  745. }
  746. }
  747. }
  748. void CameraAndroid::handle_display_rotation_change(int) {
  749. for (int i = 0; i < feeds.size(); i++) {
  750. Ref<CameraFeedAndroid> feed = feeds[i];
  751. if (feed.is_valid()) {
  752. feed->handle_rotation_change();
  753. }
  754. }
  755. }
  756. CameraAndroid::~CameraAndroid() {
  757. remove_all_feeds();
  758. }
  759. std::optional<int> CameraFeedAndroid::calculate_rotation(const CameraRotationParams &p_params) {
  760. if (p_params.sensor_orientation < 0 || p_params.sensor_orientation > 270 || p_params.sensor_orientation % 90 != 0) {
  761. return std::nullopt;
  762. }
  763. int rotation_angle = p_params.sensor_orientation - p_params.display_rotation;
  764. return normalize_angle(rotation_angle);
  765. }
  766. int CameraFeedAndroid::normalize_angle(int p_angle) {
  767. while (p_angle < 0) {
  768. p_angle += 360;
  769. }
  770. return p_angle % 360;
  771. }
  772. int CameraFeedAndroid::get_display_rotation() {
  773. return DisplayServerAndroid::get_singleton()->get_display_rotation();
  774. }
  775. int CameraFeedAndroid::get_app_orientation() {
  776. GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
  777. ERR_FAIL_NULL_V(godot_io_java, 0);
  778. int orientation = godot_io_java->get_screen_orientation();
  779. switch (orientation) {
  780. case 0: // SCREEN_LANDSCAPE
  781. return 90;
  782. case 1: // SCREEN_PORTRAIT
  783. return 0;
  784. case 2: // SCREEN_REVERSE_LANDSCAPE
  785. return 270;
  786. case 3: // SCREEN_REVERSE_PORTRAIT
  787. return 180;
  788. case 4: // SCREEN_SENSOR_LANDSCAPE
  789. case 5: // SCREEN_SENSOR_PORTRAIT
  790. case 6: // SCREEN_SENSOR
  791. default:
  792. return get_display_rotation();
  793. }
  794. }