Skip to content

Commit f9e80bf

Browse files
penninghlhdshiena
authored andcommitted
Squash godotengine#98416 and split Android camera
1 parent 32eafc1 commit f9e80bf

File tree

7 files changed

+477
-6
lines changed

7 files changed

+477
-6
lines changed

modules/camera/SCsub

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Import("env_modules")
66

77
env_camera = env_modules.Clone()
88

9-
if env["platform"] in ["windows", "macos", "linuxbsd"]:
9+
if env["platform"] in ["windows", "macos", "linuxbsd", "android"]:
1010
env_camera.add_source_files(env.modules_sources, "register_types.cpp")
1111

1212
if env["platform"] == "windows":
@@ -15,6 +15,10 @@ if env["platform"] == "windows":
1515
elif env["platform"] == "macos":
1616
env_camera.add_source_files(env.modules_sources, "camera_macos.mm")
1717

18+
elif env["platform"] == "android":
19+
env_camera.add_source_files(env.modules_sources, "camera_android.cpp")
20+
env.Append(LIBS=["camera2ndk", "mediandk"])
21+
1822
elif env["platform"] == "linuxbsd":
1923
env_camera.add_source_files(env.modules_sources, "camera_linux.cpp")
2024
env_camera.add_source_files(env.modules_sources, "camera_feed_linux.cpp")

modules/camera/camera_android.cpp

+370
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
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+
//////////////////////////////////////////////////////////////////////////
34+
// Helper functions
35+
//
36+
// The following code enables you to view the contents of a media type while
37+
// debugging.
38+
39+
#ifndef IF_EQUAL_RETURN
40+
#define IF_EQUAL_RETURN(param, val) \
41+
if (val == param) \
42+
return #val
43+
#endif
44+
45+
String GetFormatName(const int32_t &format) {
46+
IF_EQUAL_RETURN(format, AIMAGE_FORMAT_YUV_420_888);
47+
IF_EQUAL_RETURN(format, AIMAGE_FORMAT_RGB_888);
48+
IF_EQUAL_RETURN(format, AIMAGE_FORMAT_RGBA_8888);
49+
50+
return "Unsupported";
51+
}
52+
53+
//////////////////////////////////////////////////////////////////////////
54+
// CameraFeedAndroid - Subclass for our camera feed on Android
55+
56+
CameraFeedAndroid::CameraFeedAndroid(ACameraManager *manager, const char *id, int32_t position, int32_t width,
57+
int32_t height, int32_t format, int32_t orientation) {
58+
this->manager = manager;
59+
this->camera_id = id;
60+
this->width = width;
61+
this->height = height;
62+
63+
// Name
64+
name = vformat("%s | %d x %d", id, width, height);
65+
66+
// Data type
67+
this->format = format;
68+
if (format == AIMAGE_FORMAT_RGB_888) {
69+
this->datatype = FEED_RGB;
70+
name += " | RGB";
71+
}
72+
if (format == AIMAGE_FORMAT_RGBA_8888) {
73+
this->datatype = FEED_RGBA;
74+
name += " | RGBA";
75+
}
76+
if (format == AIMAGE_FORMAT_YUV_420_888) {
77+
this->datatype = FEED_YCBCR;
78+
name += " | YCBCR";
79+
}
80+
81+
// Position
82+
if (position == ACAMERA_LENS_FACING_BACK) {
83+
this->position = CameraFeed::FEED_BACK;
84+
name += " | BACK";
85+
}
86+
if (position == ACAMERA_LENS_FACING_FRONT) {
87+
this->position = CameraFeed::FEED_FRONT;
88+
name += " | FRONT";
89+
}
90+
91+
// Orientation
92+
int32_t imageRotation = 0;
93+
if (position == ACAMERA_LENS_FACING_FRONT) {
94+
imageRotation = orientation % 360;
95+
imageRotation = (360 - imageRotation) % 360;
96+
} else {
97+
imageRotation = (orientation + 360) % 360;
98+
}
99+
transform.rotate(real_t(imageRotation) * 0.015707963267949F);
100+
}
101+
102+
CameraFeedAndroid::~CameraFeedAndroid() {
103+
if (is_active()) {
104+
deactivate_feed();
105+
};
106+
}
107+
108+
bool CameraFeedAndroid::activate_feed() {
109+
if (is_active()) {
110+
deactivate_feed();
111+
};
112+
113+
// Request permission
114+
if (!OS::get_singleton()->request_permission("CAMERA")) {
115+
return false;
116+
}
117+
118+
// Open device
119+
static ACameraDevice_stateCallbacks deviceCallbacks = {
120+
.context = this,
121+
.onDisconnected = onDisconnected,
122+
.onError = onError,
123+
};
124+
camera_status_t c_status = ACameraManager_openCamera(manager, camera_id.utf8(), &deviceCallbacks, &device);
125+
if (c_status != ACAMERA_OK) {
126+
onError(this, device, c_status);
127+
return false;
128+
}
129+
130+
// Create image reader
131+
media_status_t m_status = AImageReader_new(width, height, format, 1, &reader);
132+
if (m_status != AMEDIA_OK) {
133+
onError(this, device, m_status);
134+
return false;
135+
}
136+
137+
// Create image buffers
138+
set_image(RenderingServer::CANVAS_TEXTURE_CHANNEL_DIFFUSE,
139+
Image::create_empty(width, height, false, Image::FORMAT_R8));
140+
set_image(RenderingServer::CANVAS_TEXTURE_CHANNEL_NORMAL,
141+
Image::create_empty(width / 2, height / 2, false, Image::FORMAT_RG8));
142+
// set_image(RenderingServer::CANVAS_TEXTURE_CHANNEL_SPECULAR,
143+
// Image::create_empty(width, height, false, Image::FORMAT_R8));
144+
145+
// Get image listener
146+
static AImageReader_ImageListener listener{
147+
.context = this,
148+
.onImageAvailable = onImage,
149+
};
150+
m_status = AImageReader_setImageListener(reader, &listener);
151+
if (m_status != AMEDIA_OK) {
152+
onError(this, device, m_status);
153+
return false;
154+
}
155+
156+
// Get image surface
157+
ANativeWindow *surface;
158+
m_status = AImageReader_getWindow(reader, &surface);
159+
if (m_status != AMEDIA_OK) {
160+
onError(this, device, m_status);
161+
return false;
162+
}
163+
164+
// Prepare session outputs
165+
ACaptureSessionOutput *output = nullptr;
166+
c_status = ACaptureSessionOutput_create(surface, &output);
167+
if (c_status != ACAMERA_OK) {
168+
onError(this, device, c_status);
169+
return false;
170+
}
171+
172+
ACaptureSessionOutputContainer *outputs = nullptr;
173+
c_status = ACaptureSessionOutputContainer_create(&outputs);
174+
if (c_status != ACAMERA_OK) {
175+
onError(this, device, c_status);
176+
return false;
177+
}
178+
179+
c_status = ACaptureSessionOutputContainer_add(outputs, output);
180+
if (c_status != ACAMERA_OK) {
181+
onError(this, device, c_status);
182+
return false;
183+
}
184+
185+
// Create capture session
186+
static ACameraCaptureSession_stateCallbacks sessionStateCallbacks{
187+
.context = this,
188+
.onClosed = onSessionClosed,
189+
.onReady = onSessionReady,
190+
.onActive = onSessionActive
191+
};
192+
c_status = ACameraDevice_createCaptureSession(device, outputs, &sessionStateCallbacks, &session);
193+
if (c_status != ACAMERA_OK) {
194+
onError(this, device, c_status);
195+
return false;
196+
}
197+
198+
// Create capture request
199+
c_status = ACameraDevice_createCaptureRequest(device, TEMPLATE_PREVIEW, &request);
200+
if (c_status != ACAMERA_OK) {
201+
onError(this, device, c_status);
202+
return false;
203+
}
204+
205+
// Set capture target
206+
ACameraOutputTarget *imageTarget = nullptr;
207+
c_status = ACameraOutputTarget_create(surface, &imageTarget);
208+
if (c_status != ACAMERA_OK) {
209+
onError(this, device, c_status);
210+
return false;
211+
}
212+
213+
c_status = ACaptureRequest_addTarget(request, imageTarget);
214+
if (c_status != ACAMERA_OK) {
215+
onError(this, device, c_status);
216+
return false;
217+
}
218+
219+
// Start capture
220+
c_status = ACameraCaptureSession_setRepeatingRequest(session, nullptr, 1, &request, nullptr);
221+
if (c_status != ACAMERA_OK) {
222+
onError(this, device, c_status);
223+
return false;
224+
}
225+
226+
return true;
227+
}
228+
229+
void CameraFeedAndroid::onImage(void *context, AImageReader *p_reader) {
230+
auto *feed = static_cast<CameraFeedAndroid *>(context);
231+
232+
// Get image
233+
AImage *image = nullptr;
234+
media_status_t status = AImageReader_acquireNextImage(p_reader, &image);
235+
ERR_FAIL_COND(status != AMEDIA_OK);
236+
237+
// Get image data
238+
uint8_t *data = nullptr;
239+
int len = 0;
240+
int32_t pixel_stride, row_stride;
241+
AImage_getPlaneData(image, 0, &data, &len);
242+
feed->set_image(RenderingServer::CANVAS_TEXTURE_CHANNEL_DIFFUSE, data, 0, len);
243+
AImage_getPlanePixelStride(image, 1, &pixel_stride);
244+
AImage_getPlaneRowStride(image, 1, &row_stride);
245+
AImage_getPlaneData(image, 1, &data, &len);
246+
feed->set_image(RenderingServer::CANVAS_TEXTURE_CHANNEL_NORMAL, data, 0, len);
247+
// AImage_getPlaneData(image, 2, &data, &len);
248+
// feed->set_image(RenderingServer::CANVAS_TEXTURE_CHANNEL_SPECULAR, data, 0, len);
249+
250+
// Release image
251+
AImage_delete(image);
252+
}
253+
254+
void CameraFeedAndroid::onSessionReady(void *context, ACameraCaptureSession *session) {
255+
print_verbose("Capture session ready");
256+
}
257+
258+
void CameraFeedAndroid::onSessionActive(void *context, ACameraCaptureSession *session) {
259+
print_verbose("Capture session active");
260+
}
261+
262+
void CameraFeedAndroid::onSessionClosed(void *context, ACameraCaptureSession *session) {
263+
print_verbose("Capture session active");
264+
}
265+
266+
void CameraFeedAndroid::deactivate_feed() {
267+
if (session != nullptr) {
268+
ACameraCaptureSession_stopRepeating(session);
269+
ACameraCaptureSession_close(session);
270+
session = nullptr;
271+
}
272+
273+
if (request != nullptr) {
274+
ACaptureRequest_free(request);
275+
request = nullptr;
276+
}
277+
278+
if (reader != nullptr) {
279+
AImageReader_delete(reader);
280+
reader = nullptr;
281+
}
282+
283+
if (device != nullptr) {
284+
ACameraDevice_close(device);
285+
device = nullptr;
286+
}
287+
}
288+
289+
void CameraFeedAndroid::onError(void *context, ACameraDevice *p_device, int error) {
290+
print_error(vformat("Camera error: %d", error));
291+
onDisconnected(context, p_device);
292+
}
293+
294+
void CameraFeedAndroid::onDisconnected(void *context, ACameraDevice *p_device) {
295+
print_verbose("Camera disconnected");
296+
auto *feed = static_cast<CameraFeedAndroid *>(context);
297+
feed->set_active(false);
298+
}
299+
300+
//////////////////////////////////////////////////////////////////////////
301+
// CameraAndroid - Subclass for our camera server on Android
302+
303+
void CameraAndroid::update_feeds() {
304+
ACameraIdList *cameraIds = nullptr;
305+
camera_status_t c_status = ACameraManager_getCameraIdList(cameraManager, &cameraIds);
306+
if (c_status != ACAMERA_OK) {
307+
ERR_PRINT("Unable to retrieve supported cameras");
308+
return;
309+
}
310+
311+
for (int c = 0; c < cameraIds->numCameras; ++c) {
312+
const char *id = cameraIds->cameraIds[c];
313+
ACameraMetadata *metadata;
314+
ACameraManager_getCameraCharacteristics(cameraManager, id, &metadata);
315+
316+
// Get position
317+
ACameraMetadata_const_entry lensInfo;
318+
ACameraMetadata_getConstEntry(metadata, ACAMERA_LENS_FACING, &lensInfo);
319+
uint8_t position = static_cast<acamera_metadata_enum_android_lens_facing_t>(lensInfo.data.u8[0]);
320+
321+
// Get sensor orientation
322+
ACameraMetadata_const_entry orientation;
323+
ACameraMetadata_getConstEntry(metadata, ACAMERA_SENSOR_ORIENTATION, &orientation);
324+
int32_t cameraOrientation = orientation.data.i32[0];
325+
326+
// Get supported formats
327+
ACameraMetadata_const_entry formats;
328+
ACameraMetadata_getConstEntry(metadata, ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &formats);
329+
for (uint32_t f = 0; f < formats.count; f += 4) {
330+
// Only support output streams
331+
int32_t input = formats.data.i32[f + 3];
332+
if (input) {
333+
continue;
334+
}
335+
336+
// Get format and resolution
337+
int32_t format = formats.data.i32[f + 0];
338+
if (format == AIMAGE_FORMAT_YUV_420_888 || format == AIMAGE_FORMAT_RGB_888 ||
339+
format == AIMAGE_FORMAT_RGBA_8888) {
340+
int32_t width = formats.data.i32[f + 1];
341+
int32_t height = formats.data.i32[f + 2];
342+
Ref<CameraFeedAndroid> feed = new CameraFeedAndroid(cameraManager, id,
343+
position,
344+
width,
345+
height,
346+
format,
347+
cameraOrientation);
348+
add_feed(feed);
349+
print_line("Added camera feed: ", feed->get_name());
350+
}
351+
}
352+
353+
ACameraMetadata_free(metadata);
354+
}
355+
356+
ACameraManager_deleteCameraIdList(cameraIds);
357+
}
358+
359+
CameraAndroid::CameraAndroid() {
360+
cameraManager = ACameraManager_create();
361+
362+
// Update feeds
363+
update_feeds();
364+
}
365+
366+
CameraAndroid::~CameraAndroid() {
367+
if (cameraManager != nullptr) {
368+
ACameraManager_delete(cameraManager);
369+
}
370+
}

0 commit comments

Comments
 (0)