1 /* 2 * Copyright 2013 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_NDEBUG 0 18 #define LOG_TAG "ImageReader_JNI" 19 #include <utils/Log.h> 20 #include <utils/misc.h> 21 #include <utils/List.h> 22 #include <utils/String8.h> 23 24 #include <cstdio> 25 26 #include <gui/CpuConsumer.h> 27 #include <gui/Surface.h> 28 #include <camera3.h> 29 30 #include <android_runtime/AndroidRuntime.h> 31 #include <android_runtime/android_view_Surface.h> 32 33 #include <jni.h> 34 #include <JNIHelp.h> 35 36 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) 37 38 #define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID "mNativeContext" 39 #define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID "mLockedBuffer" 40 #define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID "mTimestamp" 41 42 // ---------------------------------------------------------------------------- 43 44 using namespace android; 45 46 enum { 47 IMAGE_READER_MAX_NUM_PLANES = 3, 48 }; 49 50 enum { 51 ACQUIRE_SUCCESS = 0, 52 ACQUIRE_NO_BUFFERS = 1, 53 ACQUIRE_MAX_IMAGES = 2, 54 }; 55 56 static struct { 57 jfieldID mNativeContext; 58 jmethodID postEventFromNative; 59 } gImageReaderClassInfo; 60 61 static struct { 62 jfieldID mLockedBuffer; 63 jfieldID mTimestamp; 64 } gSurfaceImageClassInfo; 65 66 static struct { 67 jclass clazz; 68 jmethodID ctor; 69 } gSurfacePlaneClassInfo; 70 71 // ---------------------------------------------------------------------------- 72 73 class JNIImageReaderContext : public CpuConsumer::FrameAvailableListener 74 { 75 public: 76 JNIImageReaderContext(JNIEnv* env, jobject weakThiz, jclass clazz, int maxImages); 77 78 virtual ~JNIImageReaderContext(); 79 80 virtual void onFrameAvailable(); 81 82 CpuConsumer::LockedBuffer* getLockedBuffer(); 83 84 void returnLockedBuffer(CpuConsumer::LockedBuffer* buffer); 85 86 void setCpuConsumer(const sp<CpuConsumer>& consumer) { mConsumer = consumer; } 87 CpuConsumer* getCpuConsumer() { return mConsumer.get(); } 88 89 void setBufferQueue(const sp<BufferQueue>& bq) { mBufferQueue = bq; } 90 BufferQueue* getBufferQueue() { return mBufferQueue.get(); } 91 92 void setBufferFormat(int format) { mFormat = format; } 93 int getBufferFormat() { return mFormat; } 94 95 void setBufferWidth(int width) { mWidth = width; } 96 int getBufferWidth() { return mWidth; } 97 98 void setBufferHeight(int height) { mHeight = height; } 99 int getBufferHeight() { return mHeight; } 100 101 private: 102 static JNIEnv* getJNIEnv(bool* needsDetach); 103 static void detachJNI(); 104 105 List<CpuConsumer::LockedBuffer*> mBuffers; 106 sp<CpuConsumer> mConsumer; 107 sp<BufferQueue> mBufferQueue; 108 jobject mWeakThiz; 109 jclass mClazz; 110 int mFormat; 111 int mWidth; 112 int mHeight; 113 }; 114 115 JNIImageReaderContext::JNIImageReaderContext(JNIEnv* env, 116 jobject weakThiz, jclass clazz, int maxImages) : 117 mWeakThiz(env->NewGlobalRef(weakThiz)), 118 mClazz((jclass)env->NewGlobalRef(clazz)) { 119 for (int i = 0; i < maxImages; i++) { 120 CpuConsumer::LockedBuffer *buffer = new CpuConsumer::LockedBuffer; 121 mBuffers.push_back(buffer); 122 } 123 } 124 125 JNIEnv* JNIImageReaderContext::getJNIEnv(bool* needsDetach) { 126 LOG_ALWAYS_FATAL_IF(needsDetach == NULL, "needsDetach is null!!!"); 127 *needsDetach = false; 128 JNIEnv* env = AndroidRuntime::getJNIEnv(); 129 if (env == NULL) { 130 JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL}; 131 JavaVM* vm = AndroidRuntime::getJavaVM(); 132 int result = vm->AttachCurrentThread(&env, (void*) &args); 133 if (result != JNI_OK) { 134 ALOGE("thread attach failed: %#x", result); 135 return NULL; 136 } 137 *needsDetach = true; 138 } 139 return env; 140 } 141 142 void JNIImageReaderContext::detachJNI() { 143 JavaVM* vm = AndroidRuntime::getJavaVM(); 144 int result = vm->DetachCurrentThread(); 145 if (result != JNI_OK) { 146 ALOGE("thread detach failed: %#x", result); 147 } 148 } 149 150 CpuConsumer::LockedBuffer* JNIImageReaderContext::getLockedBuffer() { 151 if (mBuffers.empty()) { 152 return NULL; 153 } 154 // Return a LockedBuffer pointer and remove it from the list 155 List<CpuConsumer::LockedBuffer*>::iterator it = mBuffers.begin(); 156 CpuConsumer::LockedBuffer* buffer = *it; 157 mBuffers.erase(it); 158 return buffer; 159 } 160 161 void JNIImageReaderContext::returnLockedBuffer(CpuConsumer::LockedBuffer* buffer) { 162 mBuffers.push_back(buffer); 163 } 164 165 JNIImageReaderContext::~JNIImageReaderContext() { 166 bool needsDetach = false; 167 JNIEnv* env = getJNIEnv(&needsDetach); 168 if (env != NULL) { 169 env->DeleteGlobalRef(mWeakThiz); 170 env->DeleteGlobalRef(mClazz); 171 } else { 172 ALOGW("leaking JNI object references"); 173 } 174 if (needsDetach) { 175 detachJNI(); 176 } 177 178 // Delete LockedBuffers 179 for (List<CpuConsumer::LockedBuffer *>::iterator it = mBuffers.begin(); 180 it != mBuffers.end(); it++) { 181 delete *it; 182 } 183 mBuffers.clear(); 184 mConsumer.clear(); 185 } 186 187 void JNIImageReaderContext::onFrameAvailable() 188 { 189 ALOGV("%s: frame available", __FUNCTION__); 190 bool needsDetach = false; 191 JNIEnv* env = getJNIEnv(&needsDetach); 192 if (env != NULL) { 193 env->CallStaticVoidMethod(mClazz, gImageReaderClassInfo.postEventFromNative, mWeakThiz); 194 } else { 195 ALOGW("onFrameAvailable event will not posted"); 196 } 197 if (needsDetach) { 198 detachJNI(); 199 } 200 } 201 202 // ---------------------------------------------------------------------------- 203 204 extern "C" { 205 206 static JNIImageReaderContext* ImageReader_getContext(JNIEnv* env, jobject thiz) 207 { 208 JNIImageReaderContext *ctx; 209 ctx = reinterpret_cast<JNIImageReaderContext *> 210 (env->GetLongField(thiz, gImageReaderClassInfo.mNativeContext)); 211 return ctx; 212 } 213 214 static CpuConsumer* ImageReader_getCpuConsumer(JNIEnv* env, jobject thiz) 215 { 216 ALOGV("%s:", __FUNCTION__); 217 JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz); 218 if (ctx == NULL) { 219 jniThrowRuntimeException(env, "ImageReaderContext is not initialized"); 220 return NULL; 221 } 222 return ctx->getCpuConsumer(); 223 } 224 225 static BufferQueue* ImageReader_getBufferQueue(JNIEnv* env, jobject thiz) 226 { 227 ALOGV("%s:", __FUNCTION__); 228 JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz); 229 if (ctx == NULL) { 230 jniThrowRuntimeException(env, "ImageReaderContext is not initialized"); 231 return NULL; 232 } 233 return ctx->getBufferQueue(); 234 } 235 236 static void ImageReader_setNativeContext(JNIEnv* env, 237 jobject thiz, sp<JNIImageReaderContext> ctx) 238 { 239 ALOGV("%s:", __FUNCTION__); 240 JNIImageReaderContext* const p = ImageReader_getContext(env, thiz); 241 if (ctx != 0) { 242 ctx->incStrong((void*)ImageReader_setNativeContext); 243 } 244 if (p) { 245 p->decStrong((void*)ImageReader_setNativeContext); 246 } 247 env->SetLongField(thiz, gImageReaderClassInfo.mNativeContext, 248 reinterpret_cast<jlong>(ctx.get())); 249 } 250 251 static CpuConsumer::LockedBuffer* Image_getLockedBuffer(JNIEnv* env, jobject image) 252 { 253 return reinterpret_cast<CpuConsumer::LockedBuffer*>( 254 env->GetLongField(image, gSurfaceImageClassInfo.mLockedBuffer)); 255 } 256 257 static void Image_setBuffer(JNIEnv* env, jobject thiz, 258 const CpuConsumer::LockedBuffer* buffer) 259 { 260 env->SetLongField(thiz, gSurfaceImageClassInfo.mLockedBuffer, reinterpret_cast<jlong>(buffer)); 261 } 262 263 // Some formats like JPEG defined with different values between android.graphics.ImageFormat and 264 // graphics.h, need convert to the one defined in graphics.h here. 265 static int Image_getPixelFormat(JNIEnv* env, int format) 266 { 267 int jpegFormat, rawSensorFormat; 268 jfieldID fid; 269 270 ALOGV("%s: format = 0x%x", __FUNCTION__, format); 271 272 jclass imageFormatClazz = env->FindClass("android/graphics/ImageFormat"); 273 ALOG_ASSERT(imageFormatClazz != NULL); 274 275 fid = env->GetStaticFieldID(imageFormatClazz, "JPEG", "I"); 276 jpegFormat = env->GetStaticIntField(imageFormatClazz, fid); 277 fid = env->GetStaticFieldID(imageFormatClazz, "RAW_SENSOR", "I"); 278 rawSensorFormat = env->GetStaticIntField(imageFormatClazz, fid); 279 280 // Translate the JPEG to BLOB for camera purpose, an add more if more mismatch is found. 281 if (format == jpegFormat) { 282 format = HAL_PIXEL_FORMAT_BLOB; 283 } 284 // Same thing for RAW_SENSOR format 285 if (format == rawSensorFormat) { 286 format = HAL_PIXEL_FORMAT_RAW_SENSOR; 287 } 288 289 return format; 290 } 291 292 static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer) 293 { 294 ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!"); 295 uint32_t size = 0; 296 uint32_t width = buffer->width; 297 uint8_t* jpegBuffer = buffer->data; 298 299 // First check for JPEG transport header at the end of the buffer 300 uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob)); 301 struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header); 302 if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) { 303 size = blob->jpeg_size; 304 ALOGV("%s: Jpeg size = %d", __FUNCTION__, size); 305 } 306 307 // failed to find size, default to whole buffer 308 if (size == 0) { 309 size = width; 310 } 311 312 return size; 313 } 314 315 static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx, 316 uint8_t **base, uint32_t *size) 317 { 318 ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!"); 319 ALOG_ASSERT(base != NULL, "base is NULL!!!"); 320 ALOG_ASSERT(size != NULL, "size is NULL!!!"); 321 ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0)); 322 323 ALOGV("%s: buffer: %p", __FUNCTION__, buffer); 324 325 uint32_t dataSize, ySize, cSize, cStride; 326 uint8_t *cb, *cr; 327 uint8_t *pData = NULL; 328 int bytesPerPixel = 0; 329 330 dataSize = ySize = cSize = cStride = 0; 331 int32_t fmt = buffer->format; 332 switch (fmt) { 333 case HAL_PIXEL_FORMAT_YCbCr_420_888: 334 pData = 335 (idx == 0) ? 336 buffer->data : 337 (idx == 1) ? 338 buffer->dataCb : 339 buffer->dataCr; 340 if (idx == 0) { 341 dataSize = buffer->stride * buffer->height; 342 } else { 343 dataSize = buffer->chromaStride * buffer->height / 2; 344 } 345 break; 346 // NV21 347 case HAL_PIXEL_FORMAT_YCrCb_420_SP: 348 cr = buffer->data + (buffer->stride * buffer->height); 349 cb = cr + 1; 350 ySize = buffer->width * buffer->height; 351 cSize = buffer->width * buffer->height / 2; 352 353 pData = 354 (idx == 0) ? 355 buffer->data : 356 (idx == 1) ? 357 cb: 358 cr; 359 360 dataSize = (idx == 0) ? ySize : cSize; 361 break; 362 case HAL_PIXEL_FORMAT_YV12: 363 // Y and C stride need to be 16 pixel aligned. 364 LOG_ALWAYS_FATAL_IF(buffer->stride % 16, 365 "Stride is not 16 pixel aligned %d", buffer->stride); 366 367 ySize = buffer->stride * buffer->height; 368 cStride = ALIGN(buffer->stride / 2, 16); 369 cr = buffer->data + ySize; 370 cSize = cStride * buffer->height / 2; 371 cb = cr + cSize; 372 373 pData = 374 (idx == 0) ? 375 buffer->data : 376 (idx == 1) ? 377 cb : 378 cr; 379 dataSize = (idx == 0) ? ySize : cSize; 380 break; 381 case HAL_PIXEL_FORMAT_Y8: 382 // Single plane, 8bpp. 383 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 384 385 pData = buffer->data; 386 dataSize = buffer->stride * buffer->height; 387 break; 388 case HAL_PIXEL_FORMAT_Y16: 389 // Single plane, 16bpp, strides are specified in pixels, not in bytes 390 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 391 392 pData = buffer->data; 393 dataSize = buffer->stride * buffer->height * 2; 394 break; 395 case HAL_PIXEL_FORMAT_BLOB: 396 // Used for JPEG data, height must be 1, width == size, single plane. 397 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 398 ALOG_ASSERT(buffer->height == 1, "JPEG should has height value %d", buffer->height); 399 400 pData = buffer->data; 401 dataSize = Image_getJpegSize(buffer); 402 break; 403 case HAL_PIXEL_FORMAT_RAW_SENSOR: 404 // Single plane 16bpp bayer data. 405 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 406 pData = buffer->data; 407 dataSize = buffer->width * 2 * buffer->height; 408 break; 409 case HAL_PIXEL_FORMAT_RGBA_8888: 410 case HAL_PIXEL_FORMAT_RGBX_8888: 411 // Single plane, 32bpp. 412 bytesPerPixel = 4; 413 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 414 pData = buffer->data; 415 dataSize = buffer->stride * buffer->height * bytesPerPixel; 416 break; 417 case HAL_PIXEL_FORMAT_RGB_565: 418 // Single plane, 16bpp. 419 bytesPerPixel = 2; 420 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 421 pData = buffer->data; 422 dataSize = buffer->stride * buffer->height * bytesPerPixel; 423 break; 424 case HAL_PIXEL_FORMAT_RGB_888: 425 // Single plane, 24bpp. 426 bytesPerPixel = 3; 427 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 428 pData = buffer->data; 429 dataSize = buffer->stride * buffer->height * bytesPerPixel; 430 break; 431 default: 432 jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException", 433 "Pixel format: 0x%x is unsupported", fmt); 434 break; 435 } 436 437 *base = pData; 438 *size = dataSize; 439 } 440 441 static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx) 442 { 443 ALOGV("%s: buffer index: %d", __FUNCTION__, idx); 444 ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0), "Index is out of range:%d", idx); 445 446 int pixelStride = 0; 447 ALOG_ASSERT(buffer != NULL, "buffer is NULL"); 448 449 int32_t fmt = buffer->format; 450 switch (fmt) { 451 case HAL_PIXEL_FORMAT_YCbCr_420_888: 452 pixelStride = (idx == 0) ? 1 : buffer->chromaStep; 453 break; 454 case HAL_PIXEL_FORMAT_YCrCb_420_SP: 455 pixelStride = (idx == 0) ? 1 : 2; 456 break; 457 case HAL_PIXEL_FORMAT_Y8: 458 // Single plane 8bpp data. 459 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 460 pixelStride; 461 break; 462 case HAL_PIXEL_FORMAT_YV12: 463 pixelStride = 1; 464 break; 465 case HAL_PIXEL_FORMAT_BLOB: 466 // Used for JPEG data, single plane, row and pixel strides are 0 467 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 468 pixelStride = 0; 469 break; 470 case HAL_PIXEL_FORMAT_Y16: 471 case HAL_PIXEL_FORMAT_RAW_SENSOR: 472 case HAL_PIXEL_FORMAT_RGB_565: 473 // Single plane 16bpp data. 474 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 475 pixelStride = 2; 476 break; 477 case HAL_PIXEL_FORMAT_RGBA_8888: 478 case HAL_PIXEL_FORMAT_RGBX_8888: 479 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 480 pixelStride = 4; 481 break; 482 case HAL_PIXEL_FORMAT_RGB_888: 483 // Single plane, 24bpp. 484 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 485 pixelStride = 3; 486 break; 487 default: 488 jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException", 489 "Pixel format: 0x%x is unsupported", fmt); 490 break; 491 } 492 493 return pixelStride; 494 } 495 496 static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx) 497 { 498 ALOGV("%s: buffer index: %d", __FUNCTION__, idx); 499 ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0)); 500 501 int rowStride = 0; 502 ALOG_ASSERT(buffer != NULL, "buffer is NULL"); 503 504 int32_t fmt = buffer->format; 505 506 switch (fmt) { 507 case HAL_PIXEL_FORMAT_YCbCr_420_888: 508 rowStride = (idx == 0) ? buffer->stride : buffer->chromaStride; 509 break; 510 case HAL_PIXEL_FORMAT_YCrCb_420_SP: 511 rowStride = buffer->width; 512 break; 513 case HAL_PIXEL_FORMAT_YV12: 514 LOG_ALWAYS_FATAL_IF(buffer->stride % 16, 515 "Stride is not 16 pixel aligned %d", buffer->stride); 516 rowStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16); 517 break; 518 case HAL_PIXEL_FORMAT_BLOB: 519 // Used for JPEG data, single plane, row and pixel strides are 0 520 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 521 rowStride = 0; 522 break; 523 case HAL_PIXEL_FORMAT_Y8: 524 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 525 LOG_ALWAYS_FATAL_IF(buffer->stride % 16, 526 "Stride is not 16 pixel aligned %d", buffer->stride); 527 rowStride = buffer->stride; 528 break; 529 case HAL_PIXEL_FORMAT_Y16: 530 case HAL_PIXEL_FORMAT_RAW_SENSOR: 531 // In native side, strides are specified in pixels, not in bytes. 532 // Single plane 16bpp bayer data. even width/height, 533 // row stride multiple of 16 pixels (32 bytes) 534 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 535 LOG_ALWAYS_FATAL_IF(buffer->stride % 16, 536 "Stride is not 16 pixel aligned %d", buffer->stride); 537 rowStride = buffer->stride * 2; 538 break; 539 case HAL_PIXEL_FORMAT_RGB_565: 540 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 541 rowStride = buffer->stride * 2; 542 break; 543 case HAL_PIXEL_FORMAT_RGBA_8888: 544 case HAL_PIXEL_FORMAT_RGBX_8888: 545 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 546 rowStride = buffer->stride * 4; 547 break; 548 case HAL_PIXEL_FORMAT_RGB_888: 549 // Single plane, 24bpp. 550 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); 551 rowStride = buffer->stride * 3; 552 break; 553 default: 554 ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt); 555 jniThrowException(env, "java/lang/UnsupportedOperationException", 556 "unsupported buffer format"); 557 break; 558 } 559 560 return rowStride; 561 } 562 563 // ---------------------------------------------------------------------------- 564 565 static void ImageReader_classInit(JNIEnv* env, jclass clazz) 566 { 567 ALOGV("%s:", __FUNCTION__); 568 569 jclass imageClazz = env->FindClass("android/media/ImageReader$SurfaceImage"); 570 LOG_ALWAYS_FATAL_IF(imageClazz == NULL, 571 "can't find android/graphics/ImageReader$SurfaceImage"); 572 gSurfaceImageClassInfo.mLockedBuffer = env->GetFieldID( 573 imageClazz, ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID, "J"); 574 LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mLockedBuffer == NULL, 575 "can't find android/graphics/ImageReader.%s", 576 ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID); 577 578 gSurfaceImageClassInfo.mTimestamp = env->GetFieldID( 579 imageClazz, ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID, "J"); 580 LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mTimestamp == NULL, 581 "can't find android/graphics/ImageReader.%s", 582 ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID); 583 584 gImageReaderClassInfo.mNativeContext = env->GetFieldID( 585 clazz, ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID, "J"); 586 LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.mNativeContext == NULL, 587 "can't find android/graphics/ImageReader.%s", 588 ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID); 589 590 gImageReaderClassInfo.postEventFromNative = env->GetStaticMethodID( 591 clazz, "postEventFromNative", "(Ljava/lang/Object;)V"); 592 LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.postEventFromNative == NULL, 593 "can't find android/graphics/ImageReader.postEventFromNative"); 594 595 jclass planeClazz = env->FindClass("android/media/ImageReader$SurfaceImage$SurfacePlane"); 596 LOG_ALWAYS_FATAL_IF(planeClazz == NULL, "Can not find SurfacePlane class"); 597 // FindClass only gives a local reference of jclass object. 598 gSurfacePlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz); 599 gSurfacePlaneClassInfo.ctor = env->GetMethodID(gSurfacePlaneClassInfo.clazz, "<init>", 600 "(Landroid/media/ImageReader$SurfaceImage;III)V"); 601 LOG_ALWAYS_FATAL_IF(gSurfacePlaneClassInfo.ctor == NULL, 602 "Can not find SurfacePlane constructor"); 603 } 604 605 static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, 606 jint width, jint height, jint format, jint maxImages) 607 { 608 status_t res; 609 int nativeFormat; 610 611 ALOGV("%s: width:%d, height: %d, format: 0x%x, maxImages:%d", 612 __FUNCTION__, width, height, format, maxImages); 613 614 nativeFormat = Image_getPixelFormat(env, format); 615 616 sp<BufferQueue> bq = new BufferQueue(); 617 sp<CpuConsumer> consumer = new CpuConsumer(bq, maxImages, 618 /*controlledByApp*/true); 619 // TODO: throw dvm exOutOfMemoryError? 620 if (consumer == NULL) { 621 jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer"); 622 return; 623 } 624 625 jclass clazz = env->GetObjectClass(thiz); 626 if (clazz == NULL) { 627 jniThrowRuntimeException(env, "Can't find android/graphics/ImageReader"); 628 return; 629 } 630 sp<JNIImageReaderContext> ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages)); 631 ctx->setCpuConsumer(consumer); 632 ctx->setBufferQueue(bq); 633 consumer->setFrameAvailableListener(ctx); 634 ImageReader_setNativeContext(env, thiz, ctx); 635 ctx->setBufferFormat(nativeFormat); 636 ctx->setBufferWidth(width); 637 ctx->setBufferHeight(height); 638 639 // Set the width/height/format to the CpuConsumer 640 res = consumer->setDefaultBufferSize(width, height); 641 if (res != OK) { 642 jniThrowException(env, "java/lang/IllegalStateException", 643 "Failed to set CpuConsumer buffer size"); 644 return; 645 } 646 res = consumer->setDefaultBufferFormat(nativeFormat); 647 if (res != OK) { 648 jniThrowException(env, "java/lang/IllegalStateException", 649 "Failed to set CpuConsumer buffer format"); 650 } 651 } 652 653 static void ImageReader_close(JNIEnv* env, jobject thiz) 654 { 655 ALOGV("%s:", __FUNCTION__); 656 657 JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz); 658 if (ctx == NULL) { 659 // ImageReader is already closed. 660 return; 661 } 662 663 CpuConsumer* consumer = ImageReader_getCpuConsumer(env, thiz); 664 if (consumer != NULL) { 665 consumer->abandon(); 666 consumer->setFrameAvailableListener(NULL); 667 } 668 ImageReader_setNativeContext(env, thiz, NULL); 669 } 670 671 static void ImageReader_imageRelease(JNIEnv* env, jobject thiz, jobject image) 672 { 673 ALOGV("%s:", __FUNCTION__); 674 JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz); 675 if (ctx == NULL) { 676 ALOGW("ImageReader#close called before Image#close, consider calling Image#close first"); 677 return; 678 } 679 680 CpuConsumer* consumer = ctx->getCpuConsumer(); 681 CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, image); 682 if (!buffer) { 683 ALOGW("Image already released!!!"); 684 return; 685 } 686 consumer->unlockBuffer(*buffer); 687 Image_setBuffer(env, image, NULL); 688 ctx->returnLockedBuffer(buffer); 689 } 690 691 static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, 692 jobject image) 693 { 694 ALOGV("%s:", __FUNCTION__); 695 JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz); 696 if (ctx == NULL) { 697 jniThrowRuntimeException(env, "ImageReaderContext is not initialized"); 698 return -1; 699 } 700 701 CpuConsumer* consumer = ctx->getCpuConsumer(); 702 CpuConsumer::LockedBuffer* buffer = ctx->getLockedBuffer(); 703 if (buffer == NULL) { 704 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than" 705 " maxImages buffers"); 706 return ACQUIRE_MAX_IMAGES; 707 } 708 status_t res = consumer->lockNextBuffer(buffer); 709 if (res != NO_ERROR) { 710 if (res != BAD_VALUE /*no buffers*/) { 711 if (res == NOT_ENOUGH_DATA) { 712 return ACQUIRE_MAX_IMAGES; 713 } else { 714 ALOGE("%s Fail to lockNextBuffer with error: %d ", 715 __FUNCTION__, res); 716 jniThrowExceptionFmt(env, "java/lang/AssertionError", 717 "Unknown error (%d) when we tried to lock buffer.", 718 res); 719 } 720 } 721 return ACQUIRE_NO_BUFFERS; 722 } 723 724 if (buffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) { 725 jniThrowException(env, "java/lang/UnsupportedOperationException", 726 "NV21 format is not supported by ImageReader"); 727 return -1; 728 } 729 730 // Check if the left-top corner of the crop rect is origin, we currently assume this point is 731 // zero, will revist this once this assumption turns out problematic. 732 Point lt = buffer->crop.leftTop(); 733 if (lt.x != 0 || lt.y != 0) { 734 jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException", 735 "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y); 736 return -1; 737 } 738 739 // Check if the producer buffer configurations match what ImageReader configured. 740 // We want to fail for the very first image because this case is too bad. 741 int outputWidth = buffer->width; 742 int outputHeight = buffer->height; 743 744 // Correct width/height when crop is set. 745 if (!buffer->crop.isEmpty()) { 746 outputWidth = buffer->crop.getWidth(); 747 outputHeight = buffer->crop.getHeight(); 748 } 749 750 int imageReaderWidth = ctx->getBufferWidth(); 751 int imageReaderHeight = ctx->getBufferHeight(); 752 if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && 753 (imageReaderWidth != outputWidth || imageReaderHeight > outputHeight)) { 754 /** 755 * For video decoder, the buffer height is actually the vertical stride, 756 * which is always >= actual image height. For future, decoder need provide 757 * right crop rectangle to CpuConsumer to indicate the actual image height, 758 * see bug 9563986. After this bug is fixed, we can enforce the height equal 759 * check. Right now, only make sure buffer height is no less than ImageReader 760 * height. 761 */ 762 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 763 "Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d", 764 outputWidth, outputHeight, imageReaderWidth, imageReaderHeight); 765 return -1; 766 } 767 768 if (ctx->getBufferFormat() != buffer->format) { 769 // Return the buffer to the queue. 770 consumer->unlockBuffer(*buffer); 771 ctx->returnLockedBuffer(buffer); 772 773 // Throw exception 774 ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x", 775 buffer->format, ctx->getBufferFormat()); 776 String8 msg; 777 msg.appendFormat("The producer output buffer format 0x%x doesn't " 778 "match the ImageReader's configured buffer format 0x%x.", 779 buffer->format, ctx->getBufferFormat()); 780 jniThrowException(env, "java/lang/UnsupportedOperationException", 781 msg.string()); 782 return -1; 783 } 784 // Set SurfaceImage instance member variables 785 Image_setBuffer(env, image, buffer); 786 env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp, 787 static_cast<jlong>(buffer->timestamp)); 788 789 return ACQUIRE_SUCCESS; 790 } 791 792 static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz) 793 { 794 ALOGV("%s: ", __FUNCTION__); 795 796 BufferQueue* bq = ImageReader_getBufferQueue(env, thiz); 797 if (bq == NULL) { 798 jniThrowRuntimeException(env, "CpuConsumer is uninitialized"); 799 return NULL; 800 } 801 802 // Wrap the IGBP in a Java-language Surface. 803 return android_view_Surface_createFromIGraphicBufferProducer(env, bq); 804 } 805 806 static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx) 807 { 808 int rowStride, pixelStride; 809 ALOGV("%s: buffer index: %d", __FUNCTION__, idx); 810 811 CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz); 812 813 ALOG_ASSERT(buffer != NULL); 814 if (buffer == NULL) { 815 jniThrowException(env, "java/lang/IllegalStateException", "Image was released"); 816 } 817 rowStride = Image_imageGetRowStride(env, buffer, idx); 818 pixelStride = Image_imageGetPixelStride(env, buffer, idx); 819 820 jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz, 821 gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride); 822 823 return surfPlaneObj; 824 } 825 826 static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx) 827 { 828 uint8_t *base = NULL; 829 uint32_t size = 0; 830 jobject byteBuffer; 831 832 ALOGV("%s: buffer index: %d", __FUNCTION__, idx); 833 834 CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz); 835 836 if (buffer == NULL) { 837 jniThrowException(env, "java/lang/IllegalStateException", "Image was released"); 838 } 839 840 // Create byteBuffer from native buffer 841 Image_getLockedBufferInfo(env, buffer, idx, &base, &size); 842 byteBuffer = env->NewDirectByteBuffer(base, size); 843 // TODO: throw dvm exOutOfMemoryError? 844 if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) { 845 jniThrowException(env, "java/lang/IllegalStateException", "Failed to allocate ByteBuffer"); 846 } 847 848 return byteBuffer; 849 } 850 851 } // extern "C" 852 853 // ---------------------------------------------------------------------------- 854 855 static JNINativeMethod gImageReaderMethods[] = { 856 {"nativeClassInit", "()V", (void*)ImageReader_classInit }, 857 {"nativeInit", "(Ljava/lang/Object;IIII)V", (void*)ImageReader_init }, 858 {"nativeClose", "()V", (void*)ImageReader_close }, 859 {"nativeReleaseImage", "(Landroid/media/Image;)V", (void*)ImageReader_imageRelease }, 860 {"nativeImageSetup", "(Landroid/media/Image;)I", (void*)ImageReader_imageSetup }, 861 {"nativeGetSurface", "()Landroid/view/Surface;", (void*)ImageReader_getSurface }, 862 }; 863 864 static JNINativeMethod gImageMethods[] = { 865 {"nativeImageGetBuffer", "(I)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer }, 866 {"nativeCreatePlane", "(I)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;", 867 (void*)Image_createSurfacePlane }, 868 }; 869 870 int register_android_media_ImageReader(JNIEnv *env) { 871 872 int ret1 = AndroidRuntime::registerNativeMethods(env, 873 "android/media/ImageReader", gImageReaderMethods, NELEM(gImageReaderMethods)); 874 875 int ret2 = AndroidRuntime::registerNativeMethods(env, 876 "android/media/ImageReader$SurfaceImage", gImageMethods, NELEM(gImageMethods)); 877 878 return (ret1 || ret2); 879 } 880