1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "Legacy-CameraDevice-JNI"
18 // #define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 #include <utils/Errors.h>
21 #include <utils/Trace.h>
22 #include <camera/CameraUtils.h>
23
24 #include "jni.h"
25 #include "JNIHelp.h"
26 #include "core_jni_helpers.h"
27 #include "android_runtime/android_view_Surface.h"
28 #include "android_runtime/android_graphics_SurfaceTexture.h"
29
30 #include <gui/Surface.h>
31 #include <gui/IGraphicBufferProducer.h>
32 #include <gui/IProducerListener.h>
33 #include <ui/GraphicBuffer.h>
34 #include <system/window.h>
35 #include <hardware/camera3.h>
36 #include <system/camera_metadata.h>
37
38 #include <stdint.h>
39 #include <inttypes.h>
40
41 using namespace android;
42
43 // fully-qualified class name
44 #define CAMERA_DEVICE_CLASS_NAME "android/hardware/camera2/legacy/LegacyCameraDevice"
45 #define CAMERA_DEVICE_BUFFER_SLACK 3
46 #define DONT_CARE 0
47
48 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
49
50 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
51
52 /**
53 * Convert from RGB 888 to Y'CbCr using the conversion specified in JFIF v1.02
54 */
rgbToYuv420(uint8_t * rgbBuf,size_t width,size_t height,uint8_t * yPlane,uint8_t * crPlane,uint8_t * cbPlane,size_t chromaStep,size_t yStride,size_t chromaStride)55 static void rgbToYuv420(uint8_t* rgbBuf, size_t width, size_t height, uint8_t* yPlane,
56 uint8_t* crPlane, uint8_t* cbPlane, size_t chromaStep, size_t yStride, size_t chromaStride) {
57 uint8_t R, G, B;
58 size_t index = 0;
59 for (size_t j = 0; j < height; j++) {
60 uint8_t* cr = crPlane;
61 uint8_t* cb = cbPlane;
62 uint8_t* y = yPlane;
63 bool jEven = (j & 1) == 0;
64 for (size_t i = 0; i < width; i++) {
65 R = rgbBuf[index++];
66 G = rgbBuf[index++];
67 B = rgbBuf[index++];
68 *y++ = (77 * R + 150 * G + 29 * B) >> 8;
69 if (jEven && (i & 1) == 0) {
70 *cb = (( -43 * R - 85 * G + 128 * B) >> 8) + 128;
71 *cr = (( 128 * R - 107 * G - 21 * B) >> 8) + 128;
72 cr += chromaStep;
73 cb += chromaStep;
74 }
75 // Skip alpha
76 index++;
77 }
78 yPlane += yStride;
79 if (jEven) {
80 crPlane += chromaStride;
81 cbPlane += chromaStride;
82 }
83 }
84 }
85
rgbToYuv420(uint8_t * rgbBuf,size_t width,size_t height,android_ycbcr * ycbcr)86 static void rgbToYuv420(uint8_t* rgbBuf, size_t width, size_t height, android_ycbcr* ycbcr) {
87 size_t cStep = ycbcr->chroma_step;
88 size_t cStride = ycbcr->cstride;
89 size_t yStride = ycbcr->ystride;
90 ALOGV("%s: yStride is: %zu, cStride is: %zu, cStep is: %zu", __FUNCTION__, yStride, cStride,
91 cStep);
92 rgbToYuv420(rgbBuf, width, height, reinterpret_cast<uint8_t*>(ycbcr->y),
93 reinterpret_cast<uint8_t*>(ycbcr->cr), reinterpret_cast<uint8_t*>(ycbcr->cb),
94 cStep, yStride, cStride);
95 }
96
connectSurface(const sp<Surface> & surface,int32_t maxBufferSlack)97 static status_t connectSurface(const sp<Surface>& surface, int32_t maxBufferSlack) {
98 status_t err = NO_ERROR;
99
100 err = surface->connect(NATIVE_WINDOW_API_CAMERA, /*listener*/NULL);
101 if (err != OK) {
102 ALOGE("%s: Unable to connect to surface, error %s (%d).", __FUNCTION__,
103 strerror(-err), err);
104 return err;
105 }
106
107 err = native_window_set_usage(surface.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
108 if (err != NO_ERROR) {
109 ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__,
110 strerror(-err), err);
111 return err;
112 }
113
114 int minUndequeuedBuffers;
115 err = static_cast<ANativeWindow*>(surface.get())->query(surface.get(),
116 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
117 if (err != NO_ERROR) {
118 ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).",
119 __FUNCTION__, strerror(-err), err);
120 return err;
121 }
122
123 ALOGV("%s: Setting buffer count to %d", __FUNCTION__,
124 maxBufferSlack + 1 + minUndequeuedBuffers);
125 err = native_window_set_buffer_count(surface.get(), maxBufferSlack + 1 + minUndequeuedBuffers);
126 if (err != NO_ERROR) {
127 ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__,
128 strerror(-err), err);
129 return err;
130 }
131 return NO_ERROR;
132 }
133
134 /**
135 * Produce a frame in the given surface.
136 *
137 * Args:
138 * anw - a surface to produce a frame in.
139 * pixelBuffer - image buffer to generate a frame from.
140 * width - width of the pixelBuffer in pixels.
141 * height - height of the pixelBuffer in pixels.
142 * pixelFmt - format of the pixelBuffer, one of:
143 * HAL_PIXEL_FORMAT_YCrCb_420_SP,
144 * HAL_PIXEL_FORMAT_YCbCr_420_888,
145 * HAL_PIXEL_FORMAT_BLOB
146 * bufSize - the size of the pixelBuffer in bytes.
147 */
produceFrame(const sp<ANativeWindow> & anw,uint8_t * pixelBuffer,int32_t bufWidth,int32_t bufHeight,int32_t pixelFmt,int32_t bufSize)148 static status_t produceFrame(const sp<ANativeWindow>& anw,
149 uint8_t* pixelBuffer,
150 int32_t bufWidth, // Width of the pixelBuffer
151 int32_t bufHeight, // Height of the pixelBuffer
152 int32_t pixelFmt, // Format of the pixelBuffer
153 int32_t bufSize) {
154 ATRACE_CALL();
155 status_t err = NO_ERROR;
156 ANativeWindowBuffer* anb;
157 ALOGV("%s: Dequeue buffer from %p %dx%d (fmt=%x, size=%x)",
158 __FUNCTION__, anw.get(), bufWidth, bufHeight, pixelFmt, bufSize);
159
160 if (anw == 0) {
161 ALOGE("%s: anw must not be NULL", __FUNCTION__);
162 return BAD_VALUE;
163 } else if (pixelBuffer == NULL) {
164 ALOGE("%s: pixelBuffer must not be NULL", __FUNCTION__);
165 return BAD_VALUE;
166 } else if (bufWidth < 0) {
167 ALOGE("%s: width must be non-negative", __FUNCTION__);
168 return BAD_VALUE;
169 } else if (bufHeight < 0) {
170 ALOGE("%s: height must be non-negative", __FUNCTION__);
171 return BAD_VALUE;
172 } else if (bufSize < 0) {
173 ALOGE("%s: bufSize must be non-negative", __FUNCTION__);
174 return BAD_VALUE;
175 }
176
177 size_t width = static_cast<size_t>(bufWidth);
178 size_t height = static_cast<size_t>(bufHeight);
179 size_t bufferLength = static_cast<size_t>(bufSize);
180
181 // TODO: Switch to using Surface::lock and Surface::unlockAndPost
182 err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
183 if (err != NO_ERROR) return err;
184
185 sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
186 uint32_t grallocBufWidth = buf->getWidth();
187 uint32_t grallocBufHeight = buf->getHeight();
188 uint32_t grallocBufStride = buf->getStride();
189 if (grallocBufWidth != width || grallocBufHeight != height) {
190 ALOGE("%s: Received gralloc buffer with bad dimensions %" PRIu32 "x%" PRIu32
191 ", expecting dimensions %zu x %zu", __FUNCTION__, grallocBufWidth,
192 grallocBufHeight, width, height);
193 return BAD_VALUE;
194 }
195
196 int32_t bufFmt = 0;
197 err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &bufFmt);
198 if (err != NO_ERROR) {
199 ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__,
200 strerror(-err), err);
201 return err;
202 }
203
204 uint64_t tmpSize = (pixelFmt == HAL_PIXEL_FORMAT_BLOB) ? grallocBufWidth :
205 4 * grallocBufHeight * grallocBufWidth;
206 if (bufFmt != pixelFmt) {
207 if (bufFmt == HAL_PIXEL_FORMAT_RGBA_8888 && pixelFmt == HAL_PIXEL_FORMAT_BLOB) {
208 ALOGV("%s: Using BLOB to RGBA format override.", __FUNCTION__);
209 tmpSize = 4 * (grallocBufWidth + grallocBufStride * (grallocBufHeight - 1));
210 } else {
211 ALOGW("%s: Format mismatch in produceFrame: expecting format %#" PRIx32
212 ", but received buffer with format %#" PRIx32, __FUNCTION__, pixelFmt, bufFmt);
213 }
214 }
215
216 if (tmpSize > SIZE_MAX) {
217 ALOGE("%s: Overflow calculating size, buffer with dimens %zu x %zu is absurdly large...",
218 __FUNCTION__, width, height);
219 return BAD_VALUE;
220 }
221
222 size_t totalSizeBytes = tmpSize;
223
224 ALOGV("%s: Pixel format chosen: %x", __FUNCTION__, pixelFmt);
225 switch(pixelFmt) {
226 case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
227 if (bufferLength < totalSizeBytes) {
228 ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
229 __FUNCTION__, bufferLength);
230 return BAD_VALUE;
231 }
232 uint8_t* img = NULL;
233 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
234 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
235 if (err != NO_ERROR) return err;
236
237 uint8_t* yPlane = img;
238 uint8_t* uPlane = img + height * width;
239 uint8_t* vPlane = uPlane + 1;
240 size_t chromaStep = 2;
241 size_t yStride = width;
242 size_t chromaStride = width;
243
244 rgbToYuv420(pixelBuffer, width, height, yPlane,
245 uPlane, vPlane, chromaStep, yStride, chromaStride);
246 break;
247 }
248 case HAL_PIXEL_FORMAT_YV12: {
249 if (bufferLength < totalSizeBytes) {
250 ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
251 __FUNCTION__, bufferLength);
252 return BAD_VALUE;
253 }
254
255 if ((width & 1) || (height & 1)) {
256 ALOGE("%s: Dimens %zu x %zu are not divisible by 2.", __FUNCTION__, width, height);
257 return BAD_VALUE;
258 }
259
260 uint8_t* img = NULL;
261 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
262 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
263 if (err != NO_ERROR) {
264 ALOGE("%s: Error %s (%d) while locking gralloc buffer for write.", __FUNCTION__,
265 strerror(-err), err);
266 return err;
267 }
268
269 uint32_t stride = buf->getStride();
270 ALOGV("%s: stride is: %" PRIu32, __FUNCTION__, stride);
271 LOG_ALWAYS_FATAL_IF(stride % 16, "Stride is not 16 pixel aligned %d", stride);
272
273 uint32_t cStride = ALIGN(stride / 2, 16);
274 size_t chromaStep = 1;
275
276 uint8_t* yPlane = img;
277 uint8_t* crPlane = img + static_cast<uint32_t>(height) * stride;
278 uint8_t* cbPlane = crPlane + cStride * static_cast<uint32_t>(height) / 2;
279
280 rgbToYuv420(pixelBuffer, width, height, yPlane,
281 crPlane, cbPlane, chromaStep, stride, cStride);
282 break;
283 }
284 case HAL_PIXEL_FORMAT_YCbCr_420_888: {
285 // Software writes with YCbCr_420_888 format are unsupported
286 // by the gralloc module for now
287 if (bufferLength < totalSizeBytes) {
288 ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
289 __FUNCTION__, bufferLength);
290 return BAD_VALUE;
291 }
292 android_ycbcr ycbcr = android_ycbcr();
293 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
294
295 err = buf->lockYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr);
296 if (err != NO_ERROR) {
297 ALOGE("%s: Failed to lock ycbcr buffer, error %s (%d).", __FUNCTION__,
298 strerror(-err), err);
299 return err;
300 }
301 rgbToYuv420(pixelBuffer, width, height, &ycbcr);
302 break;
303 }
304 case HAL_PIXEL_FORMAT_BLOB: {
305 int8_t* img = NULL;
306 struct camera3_jpeg_blob footer = {
307 .jpeg_blob_id = CAMERA3_JPEG_BLOB_ID,
308 .jpeg_size = (uint32_t)bufferLength
309 };
310
311 size_t totalJpegSize = bufferLength + sizeof(footer);
312 totalJpegSize = (totalJpegSize + 3) & ~0x3; // round up to nearest octonibble
313
314 if (totalJpegSize > totalSizeBytes) {
315 ALOGE("%s: Pixel buffer needs size %zu, cannot fit in gralloc buffer of size %zu",
316 __FUNCTION__, totalJpegSize, totalSizeBytes);
317 return BAD_VALUE;
318 }
319
320 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
321 if (err != NO_ERROR) {
322 ALOGE("%s: Failed to lock buffer, error %s (%d).", __FUNCTION__, strerror(-err),
323 err);
324 return err;
325 }
326
327 memcpy(img, pixelBuffer, bufferLength);
328 memcpy(img + totalSizeBytes - sizeof(footer), &footer, sizeof(footer));
329 break;
330 }
331 default: {
332 ALOGE("%s: Invalid pixel format in produceFrame: %x", __FUNCTION__, pixelFmt);
333 return BAD_VALUE;
334 }
335 }
336
337 ALOGV("%s: Unlock buffer from %p", __FUNCTION__, anw.get());
338 err = buf->unlock();
339 if (err != NO_ERROR) {
340 ALOGE("%s: Failed to unlock buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
341 return err;
342 }
343
344 ALOGV("%s: Queue buffer to %p", __FUNCTION__, anw.get());
345 err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), /*fenceFd*/-1);
346 if (err != NO_ERROR) {
347 ALOGE("%s: Failed to queue buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
348 return err;
349 }
350 return NO_ERROR;
351 }
352
getNativeWindow(JNIEnv * env,jobject surface)353 static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) {
354 sp<ANativeWindow> anw;
355 if (surface) {
356 anw = android_view_Surface_getNativeWindow(env, surface);
357 if (env->ExceptionCheck()) {
358 return NULL;
359 }
360 } else {
361 jniThrowNullPointerException(env, "surface");
362 return NULL;
363 }
364 if (anw == NULL) {
365 ALOGE("%s: Surface had no valid native window.", __FUNCTION__);
366 return NULL;
367 }
368 return anw;
369 }
370
getNativeWindowFromTexture(JNIEnv * env,jobject surfaceTexture)371 static sp<ANativeWindow> getNativeWindowFromTexture(JNIEnv* env, jobject surfaceTexture) {
372 sp<ANativeWindow> anw;
373 if (surfaceTexture) {
374 anw = android_SurfaceTexture_getNativeWindow(env, surfaceTexture);
375 if (env->ExceptionCheck()) {
376 return NULL;
377 }
378 } else {
379 jniThrowNullPointerException(env, "surfaceTexture");
380 return NULL;
381 }
382 if (anw == NULL) {
383 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
384 "SurfaceTexture had no valid native window.");
385 return NULL;
386 }
387 return anw;
388 }
389
getSurface(JNIEnv * env,jobject surface)390 static sp<Surface> getSurface(JNIEnv* env, jobject surface) {
391 sp<Surface> s;
392 if (surface) {
393 s = android_view_Surface_getSurface(env, surface);
394 if (env->ExceptionCheck()) {
395 return NULL;
396 }
397 } else {
398 jniThrowNullPointerException(env, "surface");
399 return NULL;
400 }
401 if (s == NULL) {
402 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
403 "Surface had no valid native Surface.");
404 return NULL;
405 }
406 return s;
407 }
408
409 extern "C" {
410
LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv * env,jobject thiz,jobject surface)411 static jint LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) {
412 ALOGV("nativeDetectSurfaceType");
413 sp<ANativeWindow> anw;
414 if ((anw = getNativeWindow(env, surface)) == NULL) {
415 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
416 return BAD_VALUE;
417 }
418 int32_t fmt = 0;
419 status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt);
420 if(err != NO_ERROR) {
421 ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__, strerror(-err),
422 err);
423 return err;
424 }
425 return fmt;
426 }
427
LegacyCameraDevice_nativeDetectSurfaceDataspace(JNIEnv * env,jobject thiz,jobject surface)428 static jint LegacyCameraDevice_nativeDetectSurfaceDataspace(JNIEnv* env, jobject thiz, jobject surface) {
429 ALOGV("nativeDetectSurfaceDataspace");
430 sp<ANativeWindow> anw;
431 if ((anw = getNativeWindow(env, surface)) == NULL) {
432 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
433 return BAD_VALUE;
434 }
435 int32_t fmt = 0;
436 status_t err = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, &fmt);
437 if(err != NO_ERROR) {
438 ALOGE("%s: Error while querying surface dataspace %s (%d).", __FUNCTION__, strerror(-err),
439 err);
440 return err;
441 }
442 return fmt;
443 }
444
LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv * env,jobject thiz,jobject surface,jintArray dimens)445 static jint LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz,
446 jobject surface, jintArray dimens) {
447 ALOGV("nativeGetSurfaceDimens");
448
449 if (dimens == NULL) {
450 ALOGE("%s: Null dimens argument passed to nativeDetectSurfaceDimens", __FUNCTION__);
451 return BAD_VALUE;
452 }
453
454 if (env->GetArrayLength(dimens) < 2) {
455 ALOGE("%s: Invalid length of dimens argument in nativeDetectSurfaceDimens", __FUNCTION__);
456 return BAD_VALUE;
457 }
458
459 sp<ANativeWindow> anw;
460 if ((anw = getNativeWindow(env, surface)) == NULL) {
461 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
462 return BAD_VALUE;
463 }
464 int32_t dimenBuf[2];
465 status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
466 if(err != NO_ERROR) {
467 ALOGE("%s: Error while querying surface width %s (%d).", __FUNCTION__, strerror(-err),
468 err);
469 return err;
470 }
471 err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
472 if(err != NO_ERROR) {
473 ALOGE("%s: Error while querying surface height %s (%d).", __FUNCTION__, strerror(-err),
474 err);
475 return err;
476 }
477 env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
478 return NO_ERROR;
479 }
480
LegacyCameraDevice_nativeDetectSurfaceUsageFlags(JNIEnv * env,jobject thiz,jobject surface)481 static jint LegacyCameraDevice_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobject thiz,
482 jobject surface) {
483 ALOGV("nativeDetectSurfaceUsageFlags");
484
485 sp<ANativeWindow> anw;
486 if ((anw = getNativeWindow(env, surface)) == NULL) {
487 jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
488 "Could not retrieve native window from surface.");
489 return BAD_VALUE;
490 }
491 int32_t usage = 0;
492 status_t err = anw->query(anw.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage);
493 if(err != NO_ERROR) {
494 jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
495 "Error while querying surface usage bits");
496 return err;
497 }
498 return usage;
499 }
500
LegacyCameraDevice_nativeDisconnectSurface(JNIEnv * env,jobject thiz,jobject surface)501 static jint LegacyCameraDevice_nativeDisconnectSurface(JNIEnv* env, jobject thiz,
502 jobject surface) {
503 ALOGV("nativeDisconnectSurface");
504 if (surface == nullptr) return NO_ERROR;
505
506 sp<ANativeWindow> anw;
507 if ((anw = getNativeWindow(env, surface)) == NULL) {
508 ALOGV("Buffer queue has already been abandoned.");
509 return NO_ERROR;
510 }
511
512 status_t err = native_window_api_disconnect(anw.get(), NATIVE_WINDOW_API_CAMERA);
513 if(err != NO_ERROR) {
514 jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
515 "Error while disconnecting surface");
516 return err;
517 }
518 return NO_ERROR;
519 }
520
LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv * env,jobject thiz,jobject surfaceTexture,jintArray dimens)521 static jint LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv* env, jobject thiz,
522 jobject surfaceTexture, jintArray dimens) {
523 ALOGV("nativeDetectTextureDimens");
524 sp<ANativeWindow> anw;
525 if ((anw = getNativeWindowFromTexture(env, surfaceTexture)) == NULL) {
526 ALOGE("%s: Could not retrieve native window from SurfaceTexture.", __FUNCTION__);
527 return BAD_VALUE;
528 }
529
530 int32_t dimenBuf[2];
531 status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
532 if(err != NO_ERROR) {
533 ALOGE("%s: Error while querying SurfaceTexture width %s (%d)", __FUNCTION__,
534 strerror(-err), err);
535 return err;
536 }
537
538 err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
539 if(err != NO_ERROR) {
540 ALOGE("%s: Error while querying SurfaceTexture height %s (%d)", __FUNCTION__,
541 strerror(-err), err);
542 return err;
543 }
544
545 env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
546 if (env->ExceptionCheck()) {
547 return BAD_VALUE;
548 }
549 return NO_ERROR;
550 }
551
LegacyCameraDevice_nativeConnectSurface(JNIEnv * env,jobject thiz,jobject surface)552 static jint LegacyCameraDevice_nativeConnectSurface(JNIEnv* env, jobject thiz, jobject surface) {
553 ALOGV("nativeConnectSurface");
554 sp<Surface> s;
555 if ((s = getSurface(env, surface)) == NULL) {
556 ALOGE("%s: Could not retrieve surface.", __FUNCTION__);
557 return BAD_VALUE;
558 }
559 status_t err = connectSurface(s, CAMERA_DEVICE_BUFFER_SLACK);
560 if (err != NO_ERROR) {
561 ALOGE("%s: Error while configuring surface %s (%d).", __FUNCTION__, strerror(-err), err);
562 return err;
563 }
564 return NO_ERROR;
565 }
566
LegacyCameraDevice_nativeProduceFrame(JNIEnv * env,jobject thiz,jobject surface,jbyteArray pixelBuffer,jint width,jint height,jint pixelFormat)567 static jint LegacyCameraDevice_nativeProduceFrame(JNIEnv* env, jobject thiz, jobject surface,
568 jbyteArray pixelBuffer, jint width, jint height, jint pixelFormat) {
569 ALOGV("nativeProduceFrame");
570 sp<ANativeWindow> anw;
571
572 if ((anw = getNativeWindow(env, surface)) == NULL) {
573 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
574 return BAD_VALUE;
575 }
576
577 if (pixelBuffer == NULL) {
578 jniThrowNullPointerException(env, "pixelBuffer");
579 return DONT_CARE;
580 }
581
582 int32_t bufSize = static_cast<int32_t>(env->GetArrayLength(pixelBuffer));
583 jbyte* pixels = env->GetByteArrayElements(pixelBuffer, /*is_copy*/NULL);
584
585 if (pixels == NULL) {
586 jniThrowNullPointerException(env, "pixels");
587 return DONT_CARE;
588 }
589
590 status_t err = produceFrame(anw, reinterpret_cast<uint8_t*>(pixels), width, height,
591 pixelFormat, bufSize);
592 env->ReleaseByteArrayElements(pixelBuffer, pixels, JNI_ABORT);
593
594 if (err != NO_ERROR) {
595 ALOGE("%s: Error while producing frame %s (%d).", __FUNCTION__, strerror(-err), err);
596 return err;
597 }
598 return NO_ERROR;
599 }
600
LegacyCameraDevice_nativeSetSurfaceFormat(JNIEnv * env,jobject thiz,jobject surface,jint pixelFormat)601 static jint LegacyCameraDevice_nativeSetSurfaceFormat(JNIEnv* env, jobject thiz, jobject surface,
602 jint pixelFormat) {
603 ALOGV("nativeSetSurfaceType");
604 sp<ANativeWindow> anw;
605 if ((anw = getNativeWindow(env, surface)) == NULL) {
606 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
607 return BAD_VALUE;
608 }
609 status_t err = native_window_set_buffers_format(anw.get(), pixelFormat);
610 if (err != NO_ERROR) {
611 ALOGE("%s: Error while setting surface format %s (%d).", __FUNCTION__, strerror(-err), err);
612 return err;
613 }
614 return NO_ERROR;
615 }
616
LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv * env,jobject thiz,jobject surface,jint width,jint height)617 static jint LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface,
618 jint width, jint height) {
619 ALOGV("nativeSetSurfaceDimens");
620 sp<ANativeWindow> anw;
621 if ((anw = getNativeWindow(env, surface)) == NULL) {
622 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
623 return BAD_VALUE;
624 }
625
626 // Set user dimensions only
627 // The producer dimensions are owned by GL
628 status_t err = native_window_set_buffers_user_dimensions(anw.get(), width, height);
629 if (err != NO_ERROR) {
630 ALOGE("%s: Error while setting surface user dimens %s (%d).", __FUNCTION__, strerror(-err),
631 err);
632 return err;
633 }
634 return NO_ERROR;
635 }
636
LegacyCameraDevice_nativeGetSurfaceId(JNIEnv * env,jobject thiz,jobject surface)637 static jlong LegacyCameraDevice_nativeGetSurfaceId(JNIEnv* env, jobject thiz, jobject surface) {
638 ALOGV("nativeGetSurfaceId");
639 sp<Surface> s;
640 if ((s = getSurface(env, surface)) == NULL) {
641 ALOGE("%s: Could not retrieve native Surface from surface.", __FUNCTION__);
642 return 0;
643 }
644 sp<IGraphicBufferProducer> gbp = s->getIGraphicBufferProducer();
645 if (gbp == NULL) {
646 ALOGE("%s: Could not retrieve IGraphicBufferProducer from surface.", __FUNCTION__);
647 return 0;
648 }
649 sp<IBinder> b = IInterface::asBinder(gbp);
650 if (b == NULL) {
651 ALOGE("%s: Could not retrieve IBinder from surface.", __FUNCTION__);
652 return 0;
653 }
654 /*
655 * FIXME: Use better unique ID for surfaces than native IBinder pointer. Fix also in the camera
656 * service (CameraDeviceClient.h).
657 */
658 return reinterpret_cast<jlong>(b.get());
659 }
660
LegacyCameraDevice_nativeSetSurfaceOrientation(JNIEnv * env,jobject thiz,jobject surface,jint facing,jint orientation)661 static jint LegacyCameraDevice_nativeSetSurfaceOrientation(JNIEnv* env, jobject thiz,
662 jobject surface, jint facing, jint orientation) {
663 ALOGV("nativeSetSurfaceOrientation");
664 sp<ANativeWindow> anw;
665 if ((anw = getNativeWindow(env, surface)) == NULL) {
666 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
667 return BAD_VALUE;
668 }
669
670 status_t err = NO_ERROR;
671 CameraMetadata staticMetadata;
672
673 int32_t orientVal = static_cast<int32_t>(orientation);
674 uint8_t facingVal = static_cast<uint8_t>(facing);
675 staticMetadata.update(ANDROID_SENSOR_ORIENTATION, &orientVal, 1);
676 staticMetadata.update(ANDROID_LENS_FACING, &facingVal, 1);
677
678 int32_t transform = 0;
679
680 if ((err = CameraUtils::getRotationTransform(staticMetadata, /*out*/&transform)) != NO_ERROR) {
681 ALOGE("%s: Invalid rotation transform %s (%d)", __FUNCTION__, strerror(-err),
682 err);
683 return err;
684 }
685
686 ALOGV("%s: Setting buffer sticky transform to %d", __FUNCTION__, transform);
687
688 if ((err = native_window_set_buffers_sticky_transform(anw.get(), transform)) != NO_ERROR) {
689 ALOGE("%s: Unable to configure surface transform, error %s (%d)", __FUNCTION__,
690 strerror(-err), err);
691 return err;
692 }
693
694 return NO_ERROR;
695 }
696
LegacyCameraDevice_nativeSetNextTimestamp(JNIEnv * env,jobject thiz,jobject surface,jlong timestamp)697 static jint LegacyCameraDevice_nativeSetNextTimestamp(JNIEnv* env, jobject thiz, jobject surface,
698 jlong timestamp) {
699 ALOGV("nativeSetNextTimestamp");
700 sp<ANativeWindow> anw;
701 if ((anw = getNativeWindow(env, surface)) == NULL) {
702 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
703 return BAD_VALUE;
704 }
705
706 status_t err = NO_ERROR;
707
708 if ((err = native_window_set_buffers_timestamp(anw.get(), static_cast<int64_t>(timestamp))) !=
709 NO_ERROR) {
710 ALOGE("%s: Unable to set surface timestamp, error %s (%d)", __FUNCTION__, strerror(-err),
711 err);
712 return err;
713 }
714 return NO_ERROR;
715 }
716
LegacyCameraDevice_nativeSetScalingMode(JNIEnv * env,jobject thiz,jobject surface,jint mode)717 static jint LegacyCameraDevice_nativeSetScalingMode(JNIEnv* env, jobject thiz, jobject surface,
718 jint mode) {
719 ALOGV("nativeSetScalingMode");
720 sp<ANativeWindow> anw;
721 if ((anw = getNativeWindow(env, surface)) == NULL) {
722 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
723 return BAD_VALUE;
724 }
725 status_t err = NO_ERROR;
726 if ((err = native_window_set_scaling_mode(anw.get(), static_cast<int>(mode))) != NO_ERROR) {
727 ALOGE("%s: Unable to set surface scaling mode, error %s (%d)", __FUNCTION__,
728 strerror(-err), err);
729 return err;
730 }
731 return NO_ERROR;
732 }
733
LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv * env,jobject thiz)734 static jint LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv* env, jobject thiz) {
735 ALOGV("nativeGetJpegFooterSize");
736 return static_cast<jint>(sizeof(struct camera3_jpeg_blob));
737 }
738
739 } // extern "C"
740
741 static const JNINativeMethod gCameraDeviceMethods[] = {
742 { "nativeDetectSurfaceType",
743 "(Landroid/view/Surface;)I",
744 (void *)LegacyCameraDevice_nativeDetectSurfaceType },
745 { "nativeDetectSurfaceDataspace",
746 "(Landroid/view/Surface;)I",
747 (void *)LegacyCameraDevice_nativeDetectSurfaceDataspace },
748 { "nativeDetectSurfaceDimens",
749 "(Landroid/view/Surface;[I)I",
750 (void *)LegacyCameraDevice_nativeDetectSurfaceDimens },
751 { "nativeConnectSurface",
752 "(Landroid/view/Surface;)I",
753 (void *)LegacyCameraDevice_nativeConnectSurface },
754 { "nativeProduceFrame",
755 "(Landroid/view/Surface;[BIII)I",
756 (void *)LegacyCameraDevice_nativeProduceFrame },
757 { "nativeSetSurfaceFormat",
758 "(Landroid/view/Surface;I)I",
759 (void *)LegacyCameraDevice_nativeSetSurfaceFormat },
760 { "nativeSetSurfaceDimens",
761 "(Landroid/view/Surface;II)I",
762 (void *)LegacyCameraDevice_nativeSetSurfaceDimens },
763 { "nativeGetSurfaceId",
764 "(Landroid/view/Surface;)J",
765 (void *)LegacyCameraDevice_nativeGetSurfaceId },
766 { "nativeDetectTextureDimens",
767 "(Landroid/graphics/SurfaceTexture;[I)I",
768 (void *)LegacyCameraDevice_nativeDetectTextureDimens },
769 { "nativeSetSurfaceOrientation",
770 "(Landroid/view/Surface;II)I",
771 (void *)LegacyCameraDevice_nativeSetSurfaceOrientation },
772 { "nativeSetNextTimestamp",
773 "(Landroid/view/Surface;J)I",
774 (void *)LegacyCameraDevice_nativeSetNextTimestamp },
775 { "nativeGetJpegFooterSize",
776 "()I",
777 (void *)LegacyCameraDevice_nativeGetJpegFooterSize },
778 { "nativeDetectSurfaceUsageFlags",
779 "(Landroid/view/Surface;)I",
780 (void *)LegacyCameraDevice_nativeDetectSurfaceUsageFlags },
781 { "nativeSetScalingMode",
782 "(Landroid/view/Surface;I)I",
783 (void *)LegacyCameraDevice_nativeSetScalingMode },
784 { "nativeDisconnectSurface",
785 "(Landroid/view/Surface;)I",
786 (void *)LegacyCameraDevice_nativeDisconnectSurface },
787 };
788
789 // Get all the required offsets in java class and register native functions
register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv * env)790 int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv* env)
791 {
792 // Register native functions
793 return RegisterMethodsOrDie(env,
794 CAMERA_DEVICE_CLASS_NAME,
795 gCameraDeviceMethods,
796 NELEM(gCameraDeviceMethods));
797 }
798