android_hardware_camera2_legacy_LegacyCameraDevice.cpp revision 3c8fa3b356fa8f24b55d3dc42d4313297542e9f2
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 23#include "jni.h" 24#include "JNIHelp.h" 25#include "android_runtime/AndroidRuntime.h" 26#include "android_runtime/android_view_Surface.h" 27 28#include <gui/Surface.h> 29#include <gui/IGraphicBufferProducer.h> 30#include <ui/GraphicBuffer.h> 31#include <system/window.h> 32#include <hardware/camera3.h> 33 34#include <stdint.h> 35#include <inttypes.h> 36 37using namespace android; 38 39// fully-qualified class name 40#define CAMERA_DEVICE_CLASS_NAME "android/hardware/camera2/legacy/LegacyCameraDevice" 41#define CAMERA_DEVICE_BUFFER_SLACK 3 42#define DONT_CARE 0 43 44#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) 45 46#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) 47 48/** 49 * Convert from RGB 888 to Y'CbCr using the conversion specified in ITU-R BT.601 for 50 * digital RGB with K_b = 0.114, and K_r = 0.299. 51 */ 52static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, uint8_t* yPlane, 53 uint8_t* uPlane, uint8_t* vPlane, size_t chromaStep, size_t yStride, size_t chromaStride) { 54 uint8_t R, G, B; 55 size_t index = 0; 56 57 int32_t cStrideDiff = chromaStride - width; 58 59 for (int32_t j = 0; j < height; j++) { 60 for (int32_t i = 0; i < width; i++) { 61 R = rgbBuf[index++]; 62 G = rgbBuf[index++]; 63 B = rgbBuf[index++]; 64 *(yPlane + i) = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; 65 66 if (j % 2 == 0 && i % 2 == 0){ 67 *uPlane = (( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128; 68 *vPlane = (( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128; 69 uPlane += chromaStep; 70 vPlane += chromaStep; 71 } 72 // Skip alpha 73 index++; 74 } 75 yPlane += yStride; 76 if (j % 2 == 0) { 77 uPlane += cStrideDiff; 78 vPlane += cStrideDiff; 79 } 80 } 81} 82 83static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, android_ycbcr* ycbcr) { 84 size_t cStep = ycbcr->chroma_step; 85 size_t cStride = ycbcr->cstride; 86 size_t yStride = ycbcr->ystride; 87 rgbToYuv420(rgbBuf, width, height, reinterpret_cast<uint8_t*>(ycbcr->y), 88 reinterpret_cast<uint8_t*>(ycbcr->cb), reinterpret_cast<uint8_t*>(ycbcr->cr), 89 cStep, yStride, cStride); 90} 91 92static status_t configureSurface(const sp<ANativeWindow>& anw, 93 int32_t width, 94 int32_t height, 95 int32_t pixelFmt, 96 int32_t maxBufferSlack) { 97 status_t err = NO_ERROR; 98 err = native_window_set_buffers_dimensions(anw.get(), width, height); 99 if (err != NO_ERROR) { 100 ALOGE("%s: Failed to set native window buffer dimensions, error %s (%d).", __FUNCTION__, 101 strerror(-err), err); 102 return err; 103 } 104 105 err = native_window_set_buffers_format(anw.get(), pixelFmt); 106 if (err != NO_ERROR) { 107 ALOGE("%s: Failed to set native window buffer format, error %s (%d).", __FUNCTION__, 108 strerror(-err), err); 109 return err; 110 } 111 112 err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN); 113 if (err != NO_ERROR) { 114 ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__, 115 strerror(-err), err); 116 return err; 117 } 118 119 int minUndequeuedBuffers; 120 err = anw.get()->query(anw.get(), 121 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, 122 &minUndequeuedBuffers); 123 if (err != NO_ERROR) { 124 ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).", 125 __FUNCTION__, strerror(-err), err); 126 return err; 127 } 128 129 ALOGV("%s: Setting buffer count to %d, size to (%dx%d), fmt (0x%x)", __FUNCTION__, 130 maxBufferSlack + 1 + minUndequeuedBuffers, 131 width, height, pixelFmt); 132 err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers); 133 if (err != NO_ERROR) { 134 ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__, 135 strerror(-err), err); 136 return err; 137 } 138 return NO_ERROR; 139} 140 141/** 142 * Produce a frame in the given surface. 143 * 144 * Args: 145 * anw - a surface to produce a frame in. 146 * pixelBuffer - image buffer to generate a frame from. 147 * width - width of the pixelBuffer in pixels. 148 * height - height of the pixelBuffer in pixels. 149 * pixelFmt - format of the pixelBuffer, one of: 150 * HAL_PIXEL_FORMAT_YCrCb_420_SP, 151 * HAL_PIXEL_FORMAT_YCbCr_420_888, 152 * HAL_PIXEL_FORMAT_BLOB 153 * bufSize - the size of the pixelBuffer in bytes. 154 */ 155static status_t produceFrame(const sp<ANativeWindow>& anw, 156 uint8_t* pixelBuffer, 157 int32_t width, // Width of the pixelBuffer 158 int32_t height, // Height of the pixelBuffer 159 int32_t pixelFmt, // Format of the pixelBuffer 160 int32_t bufSize) { 161 ATRACE_CALL(); 162 status_t err = NO_ERROR; 163 ANativeWindowBuffer* anb; 164 ALOGV("%s: Dequeue buffer from %p %dx%d (fmt=%x, size=%x)", 165 __FUNCTION__, anw.get(), width, height, pixelFmt, bufSize); 166 167 if (anw == 0) { 168 ALOGE("%s: anw must not be NULL", __FUNCTION__); 169 return BAD_VALUE; 170 } else if (pixelBuffer == NULL) { 171 ALOGE("%s: pixelBuffer must not be NULL", __FUNCTION__); 172 return BAD_VALUE; 173 } else if (width < 0) { 174 ALOGE("%s: width must be non-negative", __FUNCTION__); 175 return BAD_VALUE; 176 } else if (height < 0) { 177 ALOGE("%s: height must be non-negative", __FUNCTION__); 178 return BAD_VALUE; 179 } else if (bufSize < 0) { 180 ALOGE("%s: bufSize must be non-negative", __FUNCTION__); 181 return BAD_VALUE; 182 } 183 184 if (width < 0 || height < 0 || bufSize < 0) { 185 ALOGE("%s: Illegal argument, negative dimension passed to produceFrame", __FUNCTION__); 186 return BAD_VALUE; 187 } 188 189 // TODO: Switch to using Surface::lock and Surface::unlockAndPost 190 err = native_window_dequeue_buffer_and_wait(anw.get(), &anb); 191 if (err != NO_ERROR) return err; 192 193 // TODO: check anb is large enough to store the results 194 195 sp<GraphicBuffer> buf(new GraphicBuffer(anb, /*keepOwnership*/false)); 196 197 switch(pixelFmt) { 198 case HAL_PIXEL_FORMAT_YCrCb_420_SP: { 199 if (bufSize < width * height * 4) { 200 ALOGE("%s: PixelBuffer size %" PRId32 " to small for given dimensions", 201 __FUNCTION__, bufSize); 202 return BAD_VALUE; 203 } 204 uint8_t* img = NULL; 205 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); 206 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 207 if (err != NO_ERROR) return err; 208 209 uint8_t* yPlane = img; 210 uint8_t* uPlane = img + height * width; 211 uint8_t* vPlane = uPlane + 1; 212 size_t chromaStep = 2; 213 size_t yStride = width; 214 size_t chromaStride = width; 215 216 rgbToYuv420(pixelBuffer, width, height, yPlane, 217 uPlane, vPlane, chromaStep, yStride, chromaStride); 218 break; 219 } 220 case HAL_PIXEL_FORMAT_YV12: { 221 if (bufSize < width * height * 4) { 222 ALOGE("%s: PixelBuffer size %" PRId32 " to small for given dimensions", 223 __FUNCTION__, bufSize); 224 return BAD_VALUE; 225 } 226 227 if ((width & 1) || (height & 1)) { 228 ALOGE("%s: Dimens %dx%d are not divisible by 2.", __FUNCTION__, width, height); 229 return BAD_VALUE; 230 } 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) { 236 ALOGE("%s: Error %s (%d) while locking gralloc buffer for write.", __FUNCTION__, 237 strerror(-err), err); 238 return err; 239 } 240 241 uint32_t stride = buf->getStride(); 242 LOG_ALWAYS_FATAL_IF(stride % 16, "Stride is not 16 pixel aligned %d", stride); 243 244 uint32_t cStride = ALIGN(stride / 2, 16); 245 size_t chromaStep = 1; 246 247 uint8_t* yPlane = img; 248 uint8_t* crPlane = img + static_cast<uint32_t>(height) * stride; 249 uint8_t* cbPlane = crPlane + cStride * static_cast<uint32_t>(height) / 2; 250 251 rgbToYuv420(pixelBuffer, width, height, yPlane, 252 crPlane, cbPlane, chromaStep, stride, cStride); 253 break; 254 } 255 case HAL_PIXEL_FORMAT_YCbCr_420_888: { 256 // Software writes with YCbCr_420_888 format are unsupported 257 // by the gralloc module for now 258 if (bufSize < width * height * 4) { 259 ALOGE("%s: PixelBuffer size %" PRId32 " to small for given dimensions", 260 __FUNCTION__, bufSize); 261 return BAD_VALUE; 262 } 263 android_ycbcr ycbcr = android_ycbcr(); 264 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); 265 266 err = buf->lockYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr); 267 if (err != NO_ERROR) { 268 ALOGE("%s: Failed to lock ycbcr buffer, error %s (%d).", __FUNCTION__, 269 strerror(-err), err); 270 return err; 271 } 272 rgbToYuv420(pixelBuffer, width, height, &ycbcr); 273 break; 274 } 275 case HAL_PIXEL_FORMAT_BLOB: { 276 if (bufSize != width || height != 1) { 277 ALOGE("%s: Incorrect pixelBuffer size: %" PRId32, __FUNCTION__, bufSize); 278 return BAD_VALUE; 279 } 280 int8_t* img = NULL; 281 282 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); 283 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 284 if (err != NO_ERROR) { 285 ALOGE("%s: Failed to lock buffer, error %s (%d).", __FUNCTION__, strerror(-err), 286 err); 287 return err; 288 } 289 struct camera3_jpeg_blob footer = { 290 jpeg_blob_id: CAMERA3_JPEG_BLOB_ID, 291 jpeg_size: (uint32_t)width 292 }; 293 memcpy(img, pixelBuffer, width); 294 memcpy(img + anb->width - sizeof(footer), &footer, sizeof(footer)); 295 break; 296 } 297 default: { 298 ALOGE("%s: Invalid pixel format in produceFrame: %x", __FUNCTION__, pixelFmt); 299 return BAD_VALUE; 300 } 301 } 302 303 ALOGV("%s: Unlock buffer from %p", __FUNCTION__, anw.get()); 304 err = buf->unlock(); 305 if (err != NO_ERROR) { 306 ALOGE("%s: Failed to unlock buffer, error %s (%d).", __FUNCTION__, strerror(-err), err); 307 return err; 308 } 309 310 ALOGV("%s: Queue buffer to %p", __FUNCTION__, anw.get()); 311 err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), /*fenceFd*/-1); 312 if (err != NO_ERROR) { 313 ALOGE("%s: Failed to queue buffer, error %s (%d).", __FUNCTION__, strerror(-err), err); 314 return err; 315 } 316 return NO_ERROR; 317} 318 319static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) { 320 sp<ANativeWindow> anw; 321 if (surface) { 322 anw = android_view_Surface_getNativeWindow(env, surface); 323 if (env->ExceptionCheck()) { 324 return NULL; 325 } 326 } else { 327 jniThrowNullPointerException(env, "surface"); 328 return NULL; 329 } 330 if (anw == NULL) { 331 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 332 "Surface had no valid native window."); 333 return NULL; 334 } 335 return anw; 336} 337 338static sp<Surface> getSurface(JNIEnv* env, jobject surface) { 339 sp<Surface> s; 340 if (surface) { 341 s = android_view_Surface_getSurface(env, surface); 342 if (env->ExceptionCheck()) { 343 return NULL; 344 } 345 } else { 346 jniThrowNullPointerException(env, "surface"); 347 return NULL; 348 } 349 if (s == NULL) { 350 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 351 "Surface had no valid native Surface."); 352 return NULL; 353 } 354 return s; 355} 356 357extern "C" { 358 359static jint LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) { 360 ALOGV("nativeDetectSurfaceType"); 361 sp<ANativeWindow> anw; 362 if ((anw = getNativeWindow(env, surface)) == NULL) { 363 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 364 return BAD_VALUE; 365 } 366 int32_t fmt = 0; 367 status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt); 368 if(err != NO_ERROR) { 369 ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__, strerror(-err), 370 err); 371 return err; 372 } 373 return fmt; 374} 375 376static jint LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz, 377 jobject surface, jintArray dimens) { 378 ALOGV("nativeGetSurfaceDimens"); 379 sp<ANativeWindow> anw; 380 if ((anw = getNativeWindow(env, surface)) == NULL) { 381 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 382 return BAD_VALUE; 383 } 384 int32_t dimenBuf[2]; 385 status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf); 386 if(err != NO_ERROR) { 387 ALOGE("%s: Error while querying surface width %s (%d).", __FUNCTION__, strerror(-err), 388 err); 389 return err; 390 } 391 err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1); 392 if(err != NO_ERROR) { 393 ALOGE("%s: Error while querying surface height %s (%d).", __FUNCTION__, strerror(-err), 394 err); 395 return err; 396 } 397 env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf); 398 return NO_ERROR; 399} 400 401static jint LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface, 402 jint width, jint height, jint pixelFormat) { 403 ALOGV("nativeConfigureSurface"); 404 sp<ANativeWindow> anw; 405 if ((anw = getNativeWindow(env, surface)) == NULL) { 406 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 407 return BAD_VALUE; 408 } 409 status_t err = configureSurface(anw, width, height, pixelFormat, CAMERA_DEVICE_BUFFER_SLACK); 410 if (err != NO_ERROR) { 411 ALOGE("%s: Error while configuring surface %s (%d).", __FUNCTION__, strerror(-err), err); 412 return err; 413 } 414 return NO_ERROR; 415} 416 417static jint LegacyCameraDevice_nativeProduceFrame(JNIEnv* env, jobject thiz, jobject surface, 418 jbyteArray pixelBuffer, jint width, jint height, jint pixelFormat) { 419 ALOGV("nativeProduceFrame"); 420 sp<ANativeWindow> anw; 421 422 if ((anw = getNativeWindow(env, surface)) == NULL) { 423 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 424 return BAD_VALUE; 425 } 426 427 if (pixelBuffer == NULL) { 428 jniThrowNullPointerException(env, "pixelBuffer"); 429 return DONT_CARE; 430 } 431 432 int32_t bufSize = static_cast<int32_t>(env->GetArrayLength(pixelBuffer)); 433 jbyte* pixels = env->GetByteArrayElements(pixelBuffer, /*is_copy*/NULL); 434 435 if (pixels == NULL) { 436 jniThrowNullPointerException(env, "pixels"); 437 return DONT_CARE; 438 } 439 440 status_t err = produceFrame(anw, reinterpret_cast<uint8_t*>(pixels), width, height, 441 pixelFormat, bufSize); 442 env->ReleaseByteArrayElements(pixelBuffer, pixels, JNI_ABORT); 443 444 if (err != NO_ERROR) { 445 ALOGE("%s: Error while producing frame %s (%d).", __FUNCTION__, strerror(-err), err); 446 return err; 447 } 448 return NO_ERROR; 449} 450 451static jint LegacyCameraDevice_nativeSetSurfaceFormat(JNIEnv* env, jobject thiz, jobject surface, 452 jint pixelFormat) { 453 ALOGV("nativeSetSurfaceType"); 454 sp<ANativeWindow> anw; 455 if ((anw = getNativeWindow(env, surface)) == NULL) { 456 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 457 return BAD_VALUE; 458 } 459 status_t err = native_window_set_buffers_format(anw.get(), pixelFormat); 460 if (err != NO_ERROR) { 461 ALOGE("%s: Error while setting surface format %s (%d).", __FUNCTION__, strerror(-err), err); 462 return err; 463 } 464 return NO_ERROR; 465} 466 467static jint LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface, 468 jint width, jint height) { 469 ALOGV("nativeSetSurfaceDimens"); 470 sp<ANativeWindow> anw; 471 if ((anw = getNativeWindow(env, surface)) == NULL) { 472 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 473 return BAD_VALUE; 474 } 475 status_t err = native_window_set_buffers_dimensions(anw.get(), width, height); 476 if (err != NO_ERROR) { 477 ALOGE("%s: Error while setting surface dimens %s (%d).", __FUNCTION__, strerror(-err), err); 478 return err; 479 } 480 return NO_ERROR; 481} 482 483static jlong LegacyCameraDevice_nativeGetSurfaceId(JNIEnv* env, jobject thiz, jobject surface) { 484 ALOGV("nativeGetSurfaceId"); 485 sp<Surface> s; 486 if ((s = getSurface(env, surface)) == NULL) { 487 ALOGE("%s: Could not retrieve native Surface from surface.", __FUNCTION__); 488 return 0; 489 } 490 sp<IGraphicBufferProducer> gbp = s->getIGraphicBufferProducer(); 491 if (gbp == NULL) { 492 ALOGE("%s: Could not retrieve IGraphicBufferProducer from surface.", __FUNCTION__); 493 return 0; 494 } 495 sp<IBinder> b = gbp->asBinder(); 496 if (b == NULL) { 497 ALOGE("%s: Could not retrieve IBinder from surface.", __FUNCTION__); 498 return 0; 499 } 500 /* 501 * FIXME: Use better unique ID for surfaces than native IBinder pointer. Fix also in the camera 502 * service (CameraDeviceClient.h). 503 */ 504 return reinterpret_cast<jlong>(b.get()); 505} 506 507} // extern "C" 508 509static JNINativeMethod gCameraDeviceMethods[] = { 510 { "nativeDetectSurfaceType", 511 "(Landroid/view/Surface;)I", 512 (void *)LegacyCameraDevice_nativeDetectSurfaceType }, 513 { "nativeDetectSurfaceDimens", 514 "(Landroid/view/Surface;[I)I", 515 (void *)LegacyCameraDevice_nativeDetectSurfaceDimens }, 516 { "nativeConfigureSurface", 517 "(Landroid/view/Surface;III)I", 518 (void *)LegacyCameraDevice_nativeConfigureSurface }, 519 { "nativeProduceFrame", 520 "(Landroid/view/Surface;[BIII)I", 521 (void *)LegacyCameraDevice_nativeProduceFrame }, 522 { "nativeSetSurfaceFormat", 523 "(Landroid/view/Surface;I)I", 524 (void *)LegacyCameraDevice_nativeSetSurfaceFormat }, 525 { "nativeSetSurfaceDimens", 526 "(Landroid/view/Surface;II)I", 527 (void *)LegacyCameraDevice_nativeSetSurfaceDimens }, 528 { "nativeGetSurfaceId", 529 "(Landroid/view/Surface;)J", 530 (void *)LegacyCameraDevice_nativeGetSurfaceId }, 531}; 532 533// Get all the required offsets in java class and register native functions 534int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv* env) 535{ 536 // Register native functions 537 return AndroidRuntime::registerNativeMethods(env, 538 CAMERA_DEVICE_CLASS_NAME, 539 gCameraDeviceMethods, 540 NELEM(gCameraDeviceMethods)); 541} 542 543