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