static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) { ALOGV("%s:", __FUNCTION__); JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz); if (ctx == NULL) { jniThrowRuntimeException(env, "ImageReaderContext is not initialized"); return -1; } CpuConsumer* consumer = ctx->getCpuConsumer(); CpuConsumer::LockedBuffer* buffer = ctx->getLockedBuffer(); if (buffer == NULL) { ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than" " maxImages buffers"); return ACQUIRE_MAX_IMAGES; } status_t res = consumer->lockNextBuffer(buffer); if (res != NO_ERROR) { ctx->returnLockedBuffer(buffer); if (res != BAD_VALUE /*no buffers*/) { if (res == NOT_ENOUGH_DATA) { return ACQUIRE_MAX_IMAGES; } else { ALOGE("%s Fail to lockNextBuffer with error: %d ", __FUNCTION__, res); jniThrowExceptionFmt(env, "java/lang/AssertionError", "Unknown error (%d) when we tried to lock buffer.", res); } } return ACQUIRE_NO_BUFFERS; } if (buffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) { jniThrowException(env, "java/lang/UnsupportedOperationException", "NV21 format is not supported by ImageReader"); return -1; } // Check if the left-top corner of the crop rect is origin, we currently assume this point is // zero, will revist this once this assumption turns out problematic. Point lt = buffer->crop.leftTop(); if (lt.x != 0 || lt.y != 0) { jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException", "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y); return -1; } // Check if the producer buffer configurations match what ImageReader configured. // We want to fail for the very first image because this case is too bad. int outputWidth = buffer->width; int outputHeight = buffer->height; // Correct width/height when crop is set. if (!buffer->crop.isEmpty()) { outputWidth = buffer->crop.getWidth(); outputHeight = buffer->crop.getHeight(); } int imgReaderFmt = ctx->getBufferFormat(); int imageReaderWidth = ctx->getBufferWidth(); int imageReaderHeight = ctx->getBufferHeight(); if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != HAL_PIXEL_FORMAT_BLOB) && (imageReaderWidth != outputWidth || imageReaderHeight > outputHeight)) { /** * For video decoder, the buffer height is actually the vertical stride, * which is always >= actual image height. For future, decoder need provide * right crop rectangle to CpuConsumer to indicate the actual image height, * see bug 9563986. After this bug is fixed, we can enforce the height equal * check. Right now, only make sure buffer height is no less than ImageReader * height. */ jniThrowExceptionFmt(env, "java/lang/IllegalStateException", "Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d", outputWidth, outputHeight, imageReaderWidth, imageReaderHeight); return -1; } int bufFmt = buffer->format; if (imgReaderFmt != bufFmt) { if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt == HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) { // Special casing for when producer switches to a format compatible with flexible YUV // (HAL_PIXEL_FORMAT_YCbCr_420_888). ctx->setBufferFormat(bufFmt); ALOGD("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt); } else if (imgReaderFmt == HAL_PIXEL_FORMAT_BLOB && bufFmt == HAL_PIXEL_FORMAT_RGBA_8888) { // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW // write limitations for (b/17379185). ALOGD("%s: Receiving JPEG in HAL_PIXEL_FORMAT_RGBA_8888 buffer.", __FUNCTION__); } else { // Return the buffer to the queue. consumer->unlockBuffer(*buffer); ctx->returnLockedBuffer(buffer); // Throw exception ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x", buffer->format, ctx->getBufferFormat()); String8 msg; msg.appendFormat("The producer output buffer format 0x%x doesn't " "match the ImageReader's configured buffer format 0x%x.", buffer->format, ctx->getBufferFormat()); jniThrowException(env, "java/lang/UnsupportedOperationException", msg.string()); return -1; } } // Set SurfaceImage instance member variables Image_setBuffer(env, image, buffer); env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp, static_cast<jlong>(buffer->timestamp)); return ACQUIRE_SUCCESS; }
static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) { ALOGV("%s:", __FUNCTION__); JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz); if (ctx == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "ImageReader is not initialized or was already closed"); return -1; } BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer(); BufferItem* buffer = ctx->getBufferItem(); if (buffer == NULL) { ALOGW("Unable to acquire a buffer item, very likely client tried to acquire more than" " maxImages buffers"); return ACQUIRE_MAX_IMAGES; } status_t res = bufferConsumer->acquireBuffer(buffer, 0); if (res != OK) { ctx->returnBufferItem(buffer); if (res != BufferQueue::NO_BUFFER_AVAILABLE) { if (res == INVALID_OPERATION) { // Max number of images were already acquired. ALOGE("%s: Max number of buffers allowed are already acquired : %s (%d)", __FUNCTION__, strerror(-res), res); return ACQUIRE_MAX_IMAGES; } else { ALOGE("%s: Acquire image failed with some unknown error: %s (%d)", __FUNCTION__, strerror(-res), res); jniThrowExceptionFmt(env, "java/lang/IllegalStateException", "Unknown error (%d) when we tried to acquire an image.", res); return ACQUIRE_NO_BUFFERS; } } // This isn't really an error case, as the application may acquire buffer at any time. return ACQUIRE_NO_BUFFERS; } // Add some extra checks for non-opaque formats. if (!isFormatOpaque(ctx->getBufferFormat())) { // Check if the left-top corner of the crop rect is origin, we currently assume this point is // zero, will revisit this once this assumption turns out problematic. Point lt = buffer->mCrop.leftTop(); if (lt.x != 0 || lt.y != 0) { jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException", "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y); return -1; } // Check if the producer buffer configurations match what ImageReader configured. int outputWidth = getBufferWidth(buffer); int outputHeight = getBufferHeight(buffer); int imgReaderFmt = ctx->getBufferFormat(); int imageReaderWidth = ctx->getBufferWidth(); int imageReaderHeight = ctx->getBufferHeight(); int bufferFormat = buffer->mGraphicBuffer->getPixelFormat(); if ((bufferFormat != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != HAL_PIXEL_FORMAT_BLOB) && (imageReaderWidth != outputWidth || imageReaderHeight != outputHeight)) { ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d", __FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight); } if (imgReaderFmt != bufferFormat) { if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFormat)) { // Treat formats that are compatible with flexible YUV // (HAL_PIXEL_FORMAT_YCbCr_420_888) as HAL_PIXEL_FORMAT_YCbCr_420_888. ALOGV("%s: Treat buffer format to 0x%x as HAL_PIXEL_FORMAT_YCbCr_420_888", __FUNCTION__, bufferFormat); } else if (imgReaderFmt == HAL_PIXEL_FORMAT_BLOB && bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888) { // Using HAL_PIXEL_FORMAT_RGBA_8888 Gralloc buffers containing JPEGs to get around // SW write limitations for (b/17379185). ALOGV("%s: Receiving JPEG in HAL_PIXEL_FORMAT_RGBA_8888 buffer.", __FUNCTION__); } else { // Return the buffer to the queue. No need to provide fence, as this buffer wasn't // used anywhere yet. bufferConsumer->releaseBuffer(*buffer); ctx->returnBufferItem(buffer); // Throw exception ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x", bufferFormat, ctx->getBufferFormat()); String8 msg; msg.appendFormat("The producer output buffer format 0x%x doesn't " "match the ImageReader's configured buffer format 0x%x.", bufferFormat, ctx->getBufferFormat()); jniThrowException(env, "java/lang/UnsupportedOperationException", msg.string()); return -1; } } } // Set SurfaceImage instance member variables Image_setBufferItem(env, image, buffer); env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp, static_cast<jlong>(buffer->mTimestamp)); return ACQUIRE_SUCCESS; }