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 41using 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 */ 55static 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 86static 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 97static 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 */ 148static 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 353static 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 371static 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 390static 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 409extern "C" { 410 411static 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 428static 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 445static 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 481static 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 501static 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 521static 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 552static 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 567static 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 601static 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 617static 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 637static 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 661static 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 697static 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 717static 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 734static 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 741static 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 790int 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