3232
3333#include " core/os/os.h"
3434#include " platform/android/display_server_android.h"
35+ #include " platform/android/java_godot_io_wrapper.h"
36+ #include " platform/android/os_android.h"
3537
3638// ////////////////////////////////////////////////////////////////////////
3739// Helper functions
@@ -93,23 +95,75 @@ CameraFeedAndroid::~CameraFeedAndroid() {
9395 }
9496}
9597
98+ void CameraFeedAndroid::refresh_camera_metadata () {
99+ ERR_FAIL_NULL_MSG (manager, vformat (" Camera %s: Cannot refresh metadata, manager is null." , camera_id));
100+
101+ if (metadata != nullptr ) {
102+ ACameraMetadata_free (metadata);
103+ metadata = nullptr ;
104+ }
105+
106+ camera_status_t status = ACameraManager_getCameraCharacteristics (manager, camera_id.utf8 ().get_data (), &metadata);
107+ if (status != ACAMERA_OK || metadata == nullptr ) {
108+ ERR_FAIL_MSG (vformat (" Camera %s: Failed to refresh metadata (status: %d)." , camera_id, status));
109+ }
110+
111+ ACameraMetadata_const_entry orientation_entry;
112+ status = ACameraMetadata_getConstEntry (metadata, ACAMERA_SENSOR_ORIENTATION, &orientation_entry);
113+ if (status == ACAMERA_OK) {
114+ orientation = orientation_entry.data .i32 [0 ];
115+ print_verbose (vformat (" Camera %s: Orientation updated to %d." , camera_id, orientation));
116+ } else {
117+ ERR_PRINT (vformat (" Camera %s: Failed to get sensor orientation after refresh (status: %d)." , camera_id, status));
118+ }
119+
120+ formats.clear ();
121+ _add_formats ();
122+
123+ print_verbose (vformat (" Camera %s: Metadata refreshed successfully." , camera_id));
124+ }
125+
96126void CameraFeedAndroid::_set_rotation () {
97- int display_rotation = DisplayServerAndroid::get_singleton ()->get_display_rotation ();
98- // reverse rotation
99- switch (display_rotation) {
100- case 90 :
101- display_rotation = 270 ;
102- break ;
103- case 270 :
104- display_rotation = 90 ;
105- break ;
106- default :
107- break ;
127+ if (!metadata) {
128+ print_verbose (vformat (" Camera %s: Metadata is null in _set_rotation, attempting refresh." , camera_id));
129+ refresh_camera_metadata ();
108130 }
109131
110- int sign = position == CameraFeed::FEED_FRONT ? 1 : -1 ;
111- float imageRotation = (orientation - display_rotation * sign + 360 ) % 360 ;
112- transform.set_rotation (real_t (Math::deg_to_rad (imageRotation)));
132+ float image_rotation = 0 .0f ;
133+ std::optional<int > result;
134+
135+ if (metadata) {
136+ CameraRotationParams params;
137+ params.sensor_orientation = orientation;
138+ params.camera_facing = (position == CameraFeed::FEED_FRONT) ? CameraFacing::FRONT : CameraFacing::BACK;
139+ params.display_rotation = get_app_orientation ();
140+
141+ result = calculate_rotation (params);
142+ } else {
143+ ERR_PRINT (vformat (" Camera %s: Cannot update rotation, metadata unavailable after refresh, using fallback." , camera_id));
144+ }
145+
146+ if (result.has_value ()) {
147+ image_rotation = static_cast <float >(result.value ());
148+ } else {
149+ int display_rotation = DisplayServerAndroid::get_singleton ()->get_display_rotation ();
150+ switch (display_rotation) {
151+ case 90 :
152+ display_rotation = 270 ;
153+ break ;
154+ case 270 :
155+ display_rotation = 90 ;
156+ break ;
157+ default :
158+ break ;
159+ }
160+
161+ int sign = position == CameraFeed::FEED_FRONT ? 1 : -1 ;
162+ image_rotation = (orientation - display_rotation * sign + 360 ) % 360 ;
163+ }
164+
165+ transform = Transform2D ();
166+ transform = transform.rotated (Math::deg_to_rad (image_rotation));
113167}
114168
115169void CameraFeedAndroid::_add_formats () {
@@ -142,7 +196,9 @@ void CameraFeedAndroid::_add_formats() {
142196}
143197
144198bool CameraFeedAndroid::activate_feed () {
145- ERR_FAIL_COND_V_MSG (selected_format == -1 , false , " CameraFeed format needs to be set before activating." );
199+ ERR_FAIL_COND_V_MSG (formats.is_empty (), false , " No camera formats available." );
200+ ERR_FAIL_INDEX_V_MSG (selected_format, formats.size (), false ,
201+ vformat (" CameraFeed format needs to be set before activating. Selected format index: %d (formats size: %d)" , selected_format, formats.size ()));
146202 if (is_active ()) {
147203 deactivate_feed ();
148204 };
@@ -278,11 +334,52 @@ Array CameraFeedAndroid::get_formats() const {
278334
279335CameraFeed::FeedFormat CameraFeedAndroid::get_format () const {
280336 CameraFeed::FeedFormat feed_format = {};
281- return selected_format == -1 ? feed_format : formats[selected_format];
337+ ERR_FAIL_INDEX_V_MSG (selected_format, formats.size (), feed_format,
338+ vformat (" Invalid format index: %d (formats size: %d)" , selected_format, formats.size ()));
339+ return formats[selected_format];
340+ }
341+
342+ void CameraFeedAndroid::handle_pause () {
343+ if (is_active ()) {
344+ was_active_before_pause = true ;
345+ print_verbose (vformat (" Camera %s: Pausing (was active)." , camera_id));
346+ deactivate_feed ();
347+ } else {
348+ was_active_before_pause = false ;
349+ }
350+ }
351+
352+ void CameraFeedAndroid::handle_resume () {
353+ if (was_active_before_pause) {
354+ print_verbose (vformat (" Camera %s: Resuming." , camera_id));
355+ activate_feed ();
356+ was_active_before_pause = false ;
357+ }
358+ }
359+
360+ void CameraFeedAndroid::handle_rotation_change () {
361+ if (!is_active ()) {
362+ return ;
363+ }
364+
365+ print_verbose (vformat (" Camera %s: Handling rotation change." , camera_id));
366+ refresh_camera_metadata ();
367+ _set_rotation ();
282368}
283369
284370void CameraFeedAndroid::onImage (void *context, AImageReader *p_reader) {
285371 CameraFeedAndroid *feed = static_cast <CameraFeedAndroid *>(context);
372+
373+ MutexLock lock (feed->callback_mutex );
374+
375+ if (!feed->is_active ()) {
376+ AImage *pending_image = nullptr ;
377+ if (AImageReader_acquireNextImage (p_reader, &pending_image) == AMEDIA_OK) {
378+ AImage_delete (pending_image);
379+ }
380+ return ;
381+ }
382+
286383 Vector<uint8_t > data_y = feed->data_y ;
287384 Vector<uint8_t > data_uv = feed->data_uv ;
288385 Ref<Image> image_y = feed->image_y ;
@@ -363,8 +460,17 @@ void CameraFeedAndroid::onImage(void *context, AImageReader *p_reader) {
363460 return ;
364461 }
365462
366- // Rotation
367- feed->_set_rotation ();
463+ if (!feed->formats .is_empty ()) {
464+ if (feed->metadata != nullptr ) {
465+ feed->_set_rotation ();
466+ } else {
467+ print_verbose (vformat (" Camera %s: Metadata invalidated in onImage, attempting refresh." , feed->camera_id ));
468+ feed->refresh_camera_metadata ();
469+ if (feed->metadata != nullptr && !feed->formats .is_empty ()) {
470+ feed->_set_rotation ();
471+ }
472+ }
473+ }
368474
369475 // Release image
370476 AImage_delete (image);
@@ -389,19 +495,27 @@ void CameraFeedAndroid::deactivate_feed() {
389495 session = nullptr ;
390496 }
391497
392- if (request != nullptr ) {
393- ACaptureRequest_free (request);
394- request = nullptr ;
395- }
396-
397498 if (reader != nullptr ) {
398- AImageReader_delete (reader);
399- reader = nullptr ;
499+ AImageReader_setImageListener (reader, nullptr );
400500 }
401501
402- if (device != nullptr ) {
403- ACameraDevice_close (device);
404- device = nullptr ;
502+ {
503+ MutexLock lock (callback_mutex);
504+
505+ if (device != nullptr ) {
506+ ACameraDevice_close (device);
507+ device = nullptr ;
508+ }
509+
510+ if (reader != nullptr ) {
511+ AImageReader_delete (reader);
512+ reader = nullptr ;
513+ }
514+
515+ if (request != nullptr ) {
516+ ACaptureRequest_free (request);
517+ request = nullptr ;
518+ }
405519 }
406520}
407521
@@ -505,6 +619,75 @@ void CameraAndroid::set_monitoring_feeds(bool p_monitoring_feeds) {
505619 }
506620}
507621
622+ void CameraAndroid::handle_pause () {
623+ for (int i = 0 ; i < feeds.size (); i++) {
624+ Ref<CameraFeedAndroid> feed = feeds[i];
625+ if (feed.is_valid ()) {
626+ feed->handle_pause ();
627+ }
628+ }
629+ }
630+
631+ void CameraAndroid::handle_resume () {
632+ for (int i = 0 ; i < feeds.size (); i++) {
633+ Ref<CameraFeedAndroid> feed = feeds[i];
634+ if (feed.is_valid ()) {
635+ feed->handle_resume ();
636+ }
637+ }
638+ }
639+
640+ void CameraAndroid::handle_rotation_change () {
641+ for (int i = 0 ; i < feeds.size (); i++) {
642+ Ref<CameraFeedAndroid> feed = feeds[i];
643+ if (feed.is_valid ()) {
644+ feed->handle_rotation_change ();
645+ }
646+ }
647+ }
648+
508649CameraAndroid::~CameraAndroid () {
509650 remove_all_feeds ();
510651}
652+
653+ std::optional<int > CameraFeedAndroid::calculate_rotation (const CameraRotationParams &p_params) {
654+ if (p_params.sensor_orientation < 0 || p_params.sensor_orientation > 270 || p_params.sensor_orientation % 90 != 0 ) {
655+ return std::nullopt ;
656+ }
657+
658+ int rotation_angle = p_params.sensor_orientation - p_params.display_rotation ;
659+ return normalize_angle (rotation_angle);
660+ }
661+
662+ int CameraFeedAndroid::normalize_angle (int p_angle) {
663+ while (p_angle < 0 ) {
664+ p_angle += 360 ;
665+ }
666+ return p_angle % 360 ;
667+ }
668+
669+ int CameraFeedAndroid::get_display_rotation () {
670+ return DisplayServerAndroid::get_singleton ()->get_display_rotation ();
671+ }
672+
673+ int CameraFeedAndroid::get_app_orientation () {
674+ GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton ()->get_godot_io_java ();
675+ ERR_FAIL_NULL_V (godot_io_java, 0 );
676+
677+ int orientation = godot_io_java->get_screen_orientation ();
678+ switch (orientation) {
679+ case 0 : // SCREEN_LANDSCAPE
680+ return 90 ;
681+ case 1 : // SCREEN_PORTRAIT
682+ return 0 ;
683+ case 2 : // SCREEN_REVERSE_LANDSCAPE
684+ return 270 ;
685+ case 3 : // SCREEN_REVERSE_PORTRAIT
686+ return 180 ;
687+ case 4 : // SCREEN_SENSOR_LANDSCAPE
688+ case 5 : // SCREEN_SENSOR_PORTRAIT
689+ case 6 : // SCREEN_SENSOR
690+ default :
691+ return get_display_rotation ();
692+ }
693+ }
0 commit comments