Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/camera/camera_android.cpp
10277 views
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
31
#include "camera_android.h"
32
33
#include "core/os/os.h"
34
#include "platform/android/display_server_android.h"
35
36
//////////////////////////////////////////////////////////////////////////
37
// Helper functions
38
//
39
// The following code enables you to view the contents of a media type while
40
// debugging.
41
42
#ifndef IF_EQUAL_RETURN
43
#define MAKE_FORMAT_CONST(suffix) AIMAGE_FORMAT_##suffix
44
#define IF_EQUAL_RETURN(param, val) \
45
if (MAKE_FORMAT_CONST(val) == param) \
46
return #val
47
#endif
48
49
String GetFormatName(const int32_t &format) {
50
IF_EQUAL_RETURN(format, YUV_420_888);
51
IF_EQUAL_RETURN(format, RGB_888);
52
IF_EQUAL_RETURN(format, RGBA_8888);
53
54
return "Unsupported";
55
}
56
57
//////////////////////////////////////////////////////////////////////////
58
// CameraFeedAndroid - Subclass for our camera feed on Android
59
60
CameraFeedAndroid::CameraFeedAndroid(ACameraManager *manager, ACameraMetadata *metadata, const char *id,
61
CameraFeed::FeedPosition position, int32_t orientation) :
62
CameraFeed() {
63
this->manager = manager;
64
this->metadata = metadata;
65
this->orientation = orientation;
66
_add_formats();
67
camera_id = id;
68
set_position(position);
69
70
// Position
71
switch (position) {
72
case CameraFeed::FEED_BACK:
73
name = vformat("%s | BACK", id);
74
break;
75
case CameraFeed::FEED_FRONT:
76
name = vformat("%s | FRONT", id);
77
break;
78
default:
79
name = vformat("%s", id);
80
break;
81
}
82
83
image_y.instantiate();
84
image_uv.instantiate();
85
}
86
87
CameraFeedAndroid::~CameraFeedAndroid() {
88
if (is_active()) {
89
deactivate_feed();
90
}
91
if (metadata != nullptr) {
92
ACameraMetadata_free(metadata);
93
}
94
}
95
96
void 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;
108
}
109
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)));
113
}
114
115
void CameraFeedAndroid::_add_formats() {
116
// Get supported formats
117
ACameraMetadata_const_entry formats;
118
camera_status_t status = ACameraMetadata_getConstEntry(metadata, ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &formats);
119
120
if (status == ACAMERA_OK) {
121
for (uint32_t f = 0; f < formats.count; f += 4) {
122
// Only support output streams
123
int32_t input = formats.data.i32[f + 3];
124
if (input) {
125
continue;
126
}
127
128
// Get format and resolution
129
int32_t format = formats.data.i32[f + 0];
130
if (format == AIMAGE_FORMAT_YUV_420_888 ||
131
format == AIMAGE_FORMAT_RGBA_8888 ||
132
format == AIMAGE_FORMAT_RGB_888) {
133
CameraFeed::FeedFormat feed_format;
134
feed_format.width = formats.data.i32[f + 1];
135
feed_format.height = formats.data.i32[f + 2];
136
feed_format.format = GetFormatName(format);
137
feed_format.pixel_format = format;
138
this->formats.append(feed_format);
139
}
140
}
141
}
142
}
143
144
bool CameraFeedAndroid::activate_feed() {
145
ERR_FAIL_COND_V_MSG(selected_format == -1, false, "CameraFeed format needs to be set before activating.");
146
if (is_active()) {
147
deactivate_feed();
148
};
149
150
// Request permission
151
if (!OS::get_singleton()->request_permission("CAMERA")) {
152
return false;
153
}
154
155
// Open device
156
static ACameraDevice_stateCallbacks deviceCallbacks = {
157
.context = this,
158
.onDisconnected = onDisconnected,
159
.onError = onError,
160
};
161
camera_status_t c_status = ACameraManager_openCamera(manager, camera_id.utf8().get_data(), &deviceCallbacks, &device);
162
if (c_status != ACAMERA_OK) {
163
onError(this, device, c_status);
164
return false;
165
}
166
167
// Create image reader
168
const FeedFormat &feed_format = formats[selected_format];
169
media_status_t m_status = AImageReader_new(feed_format.width, feed_format.height, feed_format.pixel_format, 1, &reader);
170
if (m_status != AMEDIA_OK) {
171
onError(this, device, m_status);
172
return false;
173
}
174
175
// Get image listener
176
static AImageReader_ImageListener listener{
177
.context = this,
178
.onImageAvailable = onImage,
179
};
180
m_status = AImageReader_setImageListener(reader, &listener);
181
if (m_status != AMEDIA_OK) {
182
onError(this, device, m_status);
183
return false;
184
}
185
186
// Get image surface
187
ANativeWindow *surface;
188
m_status = AImageReader_getWindow(reader, &surface);
189
if (m_status != AMEDIA_OK) {
190
onError(this, device, m_status);
191
return false;
192
}
193
194
// Prepare session outputs
195
ACaptureSessionOutput *output = nullptr;
196
c_status = ACaptureSessionOutput_create(surface, &output);
197
if (c_status != ACAMERA_OK) {
198
onError(this, device, c_status);
199
return false;
200
}
201
202
ACaptureSessionOutputContainer *outputs = nullptr;
203
c_status = ACaptureSessionOutputContainer_create(&outputs);
204
if (c_status != ACAMERA_OK) {
205
onError(this, device, c_status);
206
return false;
207
}
208
209
c_status = ACaptureSessionOutputContainer_add(outputs, output);
210
if (c_status != ACAMERA_OK) {
211
onError(this, device, c_status);
212
return false;
213
}
214
215
// Create capture session
216
static ACameraCaptureSession_stateCallbacks sessionStateCallbacks{
217
.context = this,
218
.onClosed = onSessionClosed,
219
.onReady = onSessionReady,
220
.onActive = onSessionActive
221
};
222
c_status = ACameraDevice_createCaptureSession(device, outputs, &sessionStateCallbacks, &session);
223
if (c_status != ACAMERA_OK) {
224
onError(this, device, c_status);
225
return false;
226
}
227
228
// Create capture request
229
c_status = ACameraDevice_createCaptureRequest(device, TEMPLATE_PREVIEW, &request);
230
if (c_status != ACAMERA_OK) {
231
onError(this, device, c_status);
232
return false;
233
}
234
235
// Set capture target
236
ACameraOutputTarget *imageTarget = nullptr;
237
c_status = ACameraOutputTarget_create(surface, &imageTarget);
238
if (c_status != ACAMERA_OK) {
239
onError(this, device, c_status);
240
return false;
241
}
242
243
c_status = ACaptureRequest_addTarget(request, imageTarget);
244
if (c_status != ACAMERA_OK) {
245
onError(this, device, c_status);
246
return false;
247
}
248
249
// Start capture
250
c_status = ACameraCaptureSession_setRepeatingRequest(session, nullptr, 1, &request, nullptr);
251
if (c_status != ACAMERA_OK) {
252
onError(this, device, c_status);
253
return false;
254
}
255
256
return true;
257
}
258
259
bool CameraFeedAndroid::set_format(int p_index, const Dictionary &p_parameters) {
260
ERR_FAIL_COND_V_MSG(active, false, "Feed is active.");
261
ERR_FAIL_INDEX_V_MSG(p_index, formats.size(), false, "Invalid format index.");
262
263
selected_format = p_index;
264
return true;
265
}
266
267
Array CameraFeedAndroid::get_formats() const {
268
Array result;
269
for (const FeedFormat &feed_format : formats) {
270
Dictionary dictionary;
271
dictionary["width"] = feed_format.width;
272
dictionary["height"] = feed_format.height;
273
dictionary["format"] = feed_format.format;
274
result.push_back(dictionary);
275
}
276
return result;
277
}
278
279
CameraFeed::FeedFormat CameraFeedAndroid::get_format() const {
280
CameraFeed::FeedFormat feed_format = {};
281
return selected_format == -1 ? feed_format : formats[selected_format];
282
}
283
284
void CameraFeedAndroid::onImage(void *context, AImageReader *p_reader) {
285
CameraFeedAndroid *feed = static_cast<CameraFeedAndroid *>(context);
286
Vector<uint8_t> data_y = feed->data_y;
287
Vector<uint8_t> data_uv = feed->data_uv;
288
Ref<Image> image_y = feed->image_y;
289
Ref<Image> image_uv = feed->image_uv;
290
291
// Get image
292
AImage *image = nullptr;
293
media_status_t status = AImageReader_acquireNextImage(p_reader, &image);
294
ERR_FAIL_COND(status != AMEDIA_OK);
295
296
// Get image data
297
uint8_t *data = nullptr;
298
int len = 0;
299
int32_t pixel_stride, row_stride;
300
FeedFormat format = feed->get_format();
301
int width = format.width;
302
int height = format.height;
303
switch (format.pixel_format) {
304
case AIMAGE_FORMAT_YUV_420_888:
305
AImage_getPlaneData(image, 0, &data, &len);
306
if (len <= 0) {
307
return;
308
}
309
if (len != data_y.size()) {
310
int64_t size = Image::get_image_data_size(width, height, Image::FORMAT_R8, false);
311
data_y.resize(len > size ? len : size);
312
}
313
memcpy(data_y.ptrw(), data, len);
314
315
AImage_getPlanePixelStride(image, 1, &pixel_stride);
316
AImage_getPlaneRowStride(image, 1, &row_stride);
317
AImage_getPlaneData(image, 1, &data, &len);
318
if (len <= 0) {
319
return;
320
}
321
if (len != data_uv.size()) {
322
int64_t size = Image::get_image_data_size(width / 2, height / 2, Image::FORMAT_RG8, false);
323
data_uv.resize(len > size ? len : size);
324
}
325
memcpy(data_uv.ptrw(), data, len);
326
327
image_y->initialize_data(width, height, false, Image::FORMAT_R8, data_y);
328
image_uv->initialize_data(width / 2, height / 2, false, Image::FORMAT_RG8, data_uv);
329
330
feed->set_ycbcr_images(image_y, image_uv);
331
break;
332
case AIMAGE_FORMAT_RGBA_8888:
333
AImage_getPlaneData(image, 0, &data, &len);
334
if (len <= 0) {
335
return;
336
}
337
if (len != data_y.size()) {
338
int64_t size = Image::get_image_data_size(width, height, Image::FORMAT_RGBA8, false);
339
data_y.resize(len > size ? len : size);
340
}
341
memcpy(data_y.ptrw(), data, len);
342
343
image_y->initialize_data(width, height, false, Image::FORMAT_RGBA8, data_y);
344
345
feed->set_rgb_image(image_y);
346
break;
347
case AIMAGE_FORMAT_RGB_888:
348
AImage_getPlaneData(image, 0, &data, &len);
349
if (len <= 0) {
350
return;
351
}
352
if (len != data_y.size()) {
353
int64_t size = Image::get_image_data_size(width, height, Image::FORMAT_RGB8, false);
354
data_y.resize(len > size ? len : size);
355
}
356
memcpy(data_y.ptrw(), data, len);
357
358
image_y->initialize_data(width, height, false, Image::FORMAT_RGB8, data_y);
359
360
feed->set_rgb_image(image_y);
361
break;
362
default:
363
return;
364
}
365
366
// Rotation
367
feed->_set_rotation();
368
369
// Release image
370
AImage_delete(image);
371
}
372
373
void CameraFeedAndroid::onSessionReady(void *context, ACameraCaptureSession *session) {
374
print_verbose("Capture session ready");
375
}
376
377
void CameraFeedAndroid::onSessionActive(void *context, ACameraCaptureSession *session) {
378
print_verbose("Capture session active");
379
}
380
381
void CameraFeedAndroid::onSessionClosed(void *context, ACameraCaptureSession *session) {
382
print_verbose("Capture session closed");
383
}
384
385
void CameraFeedAndroid::deactivate_feed() {
386
if (session != nullptr) {
387
ACameraCaptureSession_stopRepeating(session);
388
ACameraCaptureSession_close(session);
389
session = nullptr;
390
}
391
392
if (request != nullptr) {
393
ACaptureRequest_free(request);
394
request = nullptr;
395
}
396
397
if (reader != nullptr) {
398
AImageReader_delete(reader);
399
reader = nullptr;
400
}
401
402
if (device != nullptr) {
403
ACameraDevice_close(device);
404
device = nullptr;
405
}
406
}
407
408
void CameraFeedAndroid::onError(void *context, ACameraDevice *p_device, int error) {
409
print_error(vformat("Camera error: %d", error));
410
onDisconnected(context, p_device);
411
}
412
413
void CameraFeedAndroid::onDisconnected(void *context, ACameraDevice *p_device) {
414
print_verbose("Camera disconnected");
415
auto *feed = static_cast<CameraFeedAndroid *>(context);
416
feed->set_active(false);
417
}
418
419
//////////////////////////////////////////////////////////////////////////
420
// CameraAndroid - Subclass for our camera server on Android
421
422
void CameraAndroid::update_feeds() {
423
ACameraIdList *cameraIds = nullptr;
424
camera_status_t c_status = ACameraManager_getCameraIdList(cameraManager, &cameraIds);
425
ERR_FAIL_COND(c_status != ACAMERA_OK);
426
427
// remove existing devices
428
for (int i = feeds.size() - 1; i >= 0; i--) {
429
remove_feed(feeds[i]);
430
}
431
432
for (int c = 0; c < cameraIds->numCameras; ++c) {
433
const char *id = cameraIds->cameraIds[c];
434
ACameraMetadata *metadata = nullptr;
435
ACameraManager_getCameraCharacteristics(cameraManager, id, &metadata);
436
if (!metadata) {
437
continue;
438
}
439
440
// Get sensor orientation
441
ACameraMetadata_const_entry orientation;
442
c_status = ACameraMetadata_getConstEntry(metadata, ACAMERA_SENSOR_ORIENTATION, &orientation);
443
int32_t cameraOrientation;
444
if (c_status == ACAMERA_OK) {
445
cameraOrientation = orientation.data.i32[0];
446
} else {
447
cameraOrientation = 0;
448
print_error(vformat("Unable to get sensor orientation: %s", id));
449
}
450
451
// Get position
452
ACameraMetadata_const_entry lensInfo;
453
CameraFeed::FeedPosition position = CameraFeed::FEED_UNSPECIFIED;
454
camera_status_t status;
455
status = ACameraMetadata_getConstEntry(metadata, ACAMERA_LENS_FACING, &lensInfo);
456
if (status != ACAMERA_OK) {
457
ACameraMetadata_free(metadata);
458
continue;
459
}
460
uint8_t lens_facing = static_cast<acamera_metadata_enum_android_lens_facing_t>(lensInfo.data.u8[0]);
461
if (lens_facing == ACAMERA_LENS_FACING_FRONT) {
462
position = CameraFeed::FEED_FRONT;
463
} else if (lens_facing == ACAMERA_LENS_FACING_BACK) {
464
position = CameraFeed::FEED_BACK;
465
} else {
466
ACameraMetadata_free(metadata);
467
continue;
468
}
469
470
Ref<CameraFeedAndroid> feed = memnew(CameraFeedAndroid(cameraManager, metadata, id, position, cameraOrientation));
471
add_feed(feed);
472
}
473
474
ACameraManager_deleteCameraIdList(cameraIds);
475
emit_signal(SNAME(CameraServer::feeds_updated_signal_name));
476
}
477
478
void CameraAndroid::remove_all_feeds() {
479
// remove existing devices
480
for (int i = feeds.size() - 1; i >= 0; i--) {
481
remove_feed(feeds[i]);
482
}
483
484
if (cameraManager != nullptr) {
485
ACameraManager_delete(cameraManager);
486
cameraManager = nullptr;
487
}
488
}
489
490
void CameraAndroid::set_monitoring_feeds(bool p_monitoring_feeds) {
491
if (p_monitoring_feeds == monitoring_feeds) {
492
return;
493
}
494
495
CameraServer::set_monitoring_feeds(p_monitoring_feeds);
496
if (p_monitoring_feeds) {
497
if (cameraManager == nullptr) {
498
cameraManager = ACameraManager_create();
499
}
500
501
// Update feeds
502
update_feeds();
503
} else {
504
remove_all_feeds();
505
}
506
}
507
508
CameraAndroid::~CameraAndroid() {
509
remove_all_feeds();
510
}
511
512