2 * Copyright 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
26 #include <gui/CpuConsumer.h>
27 #include <gui/BufferItemConsumer.h>
28 #include <gui/Surface.h>
31 #include <android_runtime/AndroidRuntime.h>
32 #include <android_runtime/android_view_Surface.h>
40 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
42 #define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID "mNativeContext"
43 #define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID "mNativeBuffer"
44 #define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID "mTimestamp"
46 // ----------------------------------------------------------------------------
48 using namespace android;
51 IMAGE_READER_MAX_NUM_PLANES = 3,
56 ACQUIRE_NO_BUFFERS = 1,
57 ACQUIRE_MAX_IMAGES = 2,
61 jfieldID mNativeContext;
62 jmethodID postEventFromNative;
63 } gImageReaderClassInfo;
66 jfieldID mNativeBuffer;
68 } gSurfaceImageClassInfo;
73 } gSurfacePlaneClassInfo;
75 // Get an ID that's unique within this process.
76 static int32_t createProcessUniqueId() {
77 static volatile int32_t globalCounter = 0;
78 return android_atomic_inc(&globalCounter);
81 // ----------------------------------------------------------------------------
83 class JNIImageReaderContext : public ConsumerBase::FrameAvailableListener
86 JNIImageReaderContext(JNIEnv* env, jobject weakThiz, jclass clazz, int maxImages);
88 virtual ~JNIImageReaderContext();
90 virtual void onFrameAvailable(const BufferItem& item);
92 CpuConsumer::LockedBuffer* getLockedBuffer();
93 void returnLockedBuffer(CpuConsumer::LockedBuffer* buffer);
95 BufferItem* getOpaqueBuffer();
96 void returnOpaqueBuffer(BufferItem* buffer);
98 void setCpuConsumer(const sp<CpuConsumer>& consumer) { mConsumer = consumer; }
99 CpuConsumer* getCpuConsumer() { return mConsumer.get(); }
101 void setOpaqueConsumer(const sp<BufferItemConsumer>& consumer) { mOpaqueConsumer = consumer; }
102 BufferItemConsumer* getOpaqueConsumer() { return mOpaqueConsumer.get(); }
103 // This is the only opaque format exposed in the ImageFormat public API.
104 // Note that we do support CPU access for HAL_PIXEL_FORMAT_RAW_OPAQUE
105 // (ImageFormat#RAW_PRIVATE) so it doesn't count as opaque here.
106 bool isOpaque() { return mFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; }
108 void setProducer(const sp<IGraphicBufferProducer>& producer) { mProducer = producer; }
109 IGraphicBufferProducer* getProducer() { return mProducer.get(); }
111 void setBufferFormat(int format) { mFormat = format; }
112 int getBufferFormat() { return mFormat; }
114 void setBufferDataspace(android_dataspace dataSpace) { mDataSpace = dataSpace; }
115 android_dataspace getBufferDataspace() { return mDataSpace; }
117 void setBufferWidth(int width) { mWidth = width; }
118 int getBufferWidth() { return mWidth; }
120 void setBufferHeight(int height) { mHeight = height; }
121 int getBufferHeight() { return mHeight; }
124 static JNIEnv* getJNIEnv(bool* needsDetach);
125 static void detachJNI();
127 List<CpuConsumer::LockedBuffer*> mBuffers;
128 List<BufferItem*> mOpaqueBuffers;
129 sp<CpuConsumer> mConsumer;
130 sp<BufferItemConsumer> mOpaqueConsumer;
131 sp<IGraphicBufferProducer> mProducer;
135 android_dataspace mDataSpace;
140 JNIImageReaderContext::JNIImageReaderContext(JNIEnv* env,
141 jobject weakThiz, jclass clazz, int maxImages) :
142 mWeakThiz(env->NewGlobalRef(weakThiz)),
143 mClazz((jclass)env->NewGlobalRef(clazz)) {
144 for (int i = 0; i < maxImages; i++) {
145 CpuConsumer::LockedBuffer *buffer = new CpuConsumer::LockedBuffer;
146 BufferItem* opaqueBuffer = new BufferItem;
147 mBuffers.push_back(buffer);
148 mOpaqueBuffers.push_back(opaqueBuffer);
152 JNIEnv* JNIImageReaderContext::getJNIEnv(bool* needsDetach) {
153 LOG_ALWAYS_FATAL_IF(needsDetach == NULL, "needsDetach is null!!!");
154 *needsDetach = false;
155 JNIEnv* env = AndroidRuntime::getJNIEnv();
157 JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
158 JavaVM* vm = AndroidRuntime::getJavaVM();
159 int result = vm->AttachCurrentThread(&env, (void*) &args);
160 if (result != JNI_OK) {
161 ALOGE("thread attach failed: %#x", result);
169 void JNIImageReaderContext::detachJNI() {
170 JavaVM* vm = AndroidRuntime::getJavaVM();
171 int result = vm->DetachCurrentThread();
172 if (result != JNI_OK) {
173 ALOGE("thread detach failed: %#x", result);
177 CpuConsumer::LockedBuffer* JNIImageReaderContext::getLockedBuffer() {
178 if (mBuffers.empty()) {
181 // Return a LockedBuffer pointer and remove it from the list
182 List<CpuConsumer::LockedBuffer*>::iterator it = mBuffers.begin();
183 CpuConsumer::LockedBuffer* buffer = *it;
188 void JNIImageReaderContext::returnLockedBuffer(CpuConsumer::LockedBuffer* buffer) {
189 mBuffers.push_back(buffer);
192 BufferItem* JNIImageReaderContext::getOpaqueBuffer() {
193 if (mOpaqueBuffers.empty()) {
196 // Return an opaque buffer pointer and remove it from the list
197 List<BufferItem*>::iterator it = mOpaqueBuffers.begin();
198 BufferItem* buffer = *it;
199 mOpaqueBuffers.erase(it);
203 void JNIImageReaderContext::returnOpaqueBuffer(BufferItem* buffer) {
204 mOpaqueBuffers.push_back(buffer);
207 JNIImageReaderContext::~JNIImageReaderContext() {
208 bool needsDetach = false;
209 JNIEnv* env = getJNIEnv(&needsDetach);
211 env->DeleteGlobalRef(mWeakThiz);
212 env->DeleteGlobalRef(mClazz);
214 ALOGW("leaking JNI object references");
220 // Delete LockedBuffers
221 for (List<CpuConsumer::LockedBuffer *>::iterator it = mBuffers.begin();
222 it != mBuffers.end(); it++) {
226 // Delete opaque buffers
227 for (List<BufferItem *>::iterator it = mOpaqueBuffers.begin();
228 it != mOpaqueBuffers.end(); it++) {
233 if (mConsumer != 0) {
236 if (mOpaqueConsumer != 0) {
237 mOpaqueConsumer.clear();
241 void JNIImageReaderContext::onFrameAvailable(const BufferItem& /*item*/)
243 ALOGV("%s: frame available", __FUNCTION__);
244 bool needsDetach = false;
245 JNIEnv* env = getJNIEnv(&needsDetach);
247 env->CallStaticVoidMethod(mClazz, gImageReaderClassInfo.postEventFromNative, mWeakThiz);
249 ALOGW("onFrameAvailable event will not posted");
256 // ----------------------------------------------------------------------------
260 static bool isFormatOpaque(int format) {
261 // Only treat IMPLEMENTATION_DEFINED as an opaque format for now.
262 return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
265 static JNIImageReaderContext* ImageReader_getContext(JNIEnv* env, jobject thiz)
267 JNIImageReaderContext *ctx;
268 ctx = reinterpret_cast<JNIImageReaderContext *>
269 (env->GetLongField(thiz, gImageReaderClassInfo.mNativeContext));
273 static CpuConsumer* ImageReader_getCpuConsumer(JNIEnv* env, jobject thiz)
275 ALOGV("%s:", __FUNCTION__);
276 JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
278 jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
282 if (ctx->isOpaque()) {
283 jniThrowException(env, "java/lang/IllegalStateException",
284 "Opaque ImageReader doesn't support this method");
288 return ctx->getCpuConsumer();
291 static IGraphicBufferProducer* ImageReader_getProducer(JNIEnv* env, jobject thiz)
293 ALOGV("%s:", __FUNCTION__);
294 JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
296 jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
300 return ctx->getProducer();
303 static void ImageReader_setNativeContext(JNIEnv* env,
304 jobject thiz, sp<JNIImageReaderContext> ctx)
306 ALOGV("%s:", __FUNCTION__);
307 JNIImageReaderContext* const p = ImageReader_getContext(env, thiz);
309 ctx->incStrong((void*)ImageReader_setNativeContext);
312 p->decStrong((void*)ImageReader_setNativeContext);
314 env->SetLongField(thiz, gImageReaderClassInfo.mNativeContext,
315 reinterpret_cast<jlong>(ctx.get()));
318 static CpuConsumer::LockedBuffer* Image_getLockedBuffer(JNIEnv* env, jobject image)
320 return reinterpret_cast<CpuConsumer::LockedBuffer*>(
321 env->GetLongField(image, gSurfaceImageClassInfo.mNativeBuffer));
324 static void Image_setBuffer(JNIEnv* env, jobject thiz,
325 const CpuConsumer::LockedBuffer* buffer)
327 env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
330 static void Image_setOpaqueBuffer(JNIEnv* env, jobject thiz,
331 const BufferItem* buffer)
333 env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
336 static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer, bool usingRGBAOverride)
338 ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
340 uint32_t width = buffer->width;
341 uint8_t* jpegBuffer = buffer->data;
343 if (usingRGBAOverride) {
344 width = (buffer->width + buffer->stride * (buffer->height - 1)) * 4;
347 // First check for JPEG transport header at the end of the buffer
348 uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
349 struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
350 if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
351 size = blob->jpeg_size;
352 ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
355 // failed to find size, default to whole buffer
358 * This is a problem because not including the JPEG header
359 * means that in certain rare situations a regular JPEG blob
360 * will be misidentified as having a header, in which case
361 * we will get a garbage size value.
363 ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
364 __FUNCTION__, width);
371 static bool usingRGBAToJpegOverride(int32_t bufferFormat, int32_t readerCtxFormat) {
372 return readerCtxFormat == HAL_PIXEL_FORMAT_BLOB && bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888;
375 static int32_t applyFormatOverrides(int32_t bufferFormat, int32_t readerCtxFormat)
377 // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
378 // write limitations for some platforms (b/17379185).
379 if (usingRGBAToJpegOverride(bufferFormat, readerCtxFormat)) {
380 return HAL_PIXEL_FORMAT_BLOB;
385 static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
386 uint8_t **base, uint32_t *size, int32_t readerFormat)
388 ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
389 ALOG_ASSERT(base != NULL, "base is NULL!!!");
390 ALOG_ASSERT(size != NULL, "size is NULL!!!");
391 ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
393 ALOGV("%s: buffer: %p", __FUNCTION__, buffer);
395 uint32_t dataSize, ySize, cSize, cStride;
397 uint8_t *pData = NULL;
398 int bytesPerPixel = 0;
400 dataSize = ySize = cSize = cStride = 0;
401 int32_t fmt = buffer->flexFormat;
403 bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, readerFormat);
404 fmt = applyFormatOverrides(fmt, readerFormat);
406 case HAL_PIXEL_FORMAT_YCbCr_420_888:
413 // only map until last pixel
415 dataSize = buffer->stride * (buffer->height - 1) + buffer->width;
417 dataSize = buffer->chromaStride * (buffer->height / 2 - 1) +
418 buffer->chromaStep * (buffer->width / 2 - 1) + 1;
422 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
423 cr = buffer->data + (buffer->stride * buffer->height);
425 // only map until last pixel
426 ySize = buffer->width * (buffer->height - 1) + buffer->width;
427 cSize = buffer->width * (buffer->height / 2 - 1) + buffer->width - 1;
436 dataSize = (idx == 0) ? ySize : cSize;
438 case HAL_PIXEL_FORMAT_YV12:
439 // Y and C stride need to be 16 pixel aligned.
440 LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
441 "Stride is not 16 pixel aligned %d", buffer->stride);
443 ySize = buffer->stride * buffer->height;
444 cStride = ALIGN(buffer->stride / 2, 16);
445 cr = buffer->data + ySize;
446 cSize = cStride * buffer->height / 2;
455 dataSize = (idx == 0) ? ySize : cSize;
457 case HAL_PIXEL_FORMAT_Y8:
458 // Single plane, 8bpp.
459 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
461 pData = buffer->data;
462 dataSize = buffer->stride * buffer->height;
464 case HAL_PIXEL_FORMAT_Y16:
466 // Single plane, 16bpp, strides are specified in pixels, not in bytes
467 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
469 pData = buffer->data;
470 dataSize = buffer->stride * buffer->height * bytesPerPixel;
472 case HAL_PIXEL_FORMAT_BLOB:
473 // Used for JPEG data, height must be 1, width == size, single plane.
474 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
475 ALOG_ASSERT(buffer->height == 1,
476 "JPEG should has height value one but got %d", buffer->height);
478 pData = buffer->data;
479 dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
481 case HAL_PIXEL_FORMAT_RAW16:
482 // Single plane 16bpp bayer data.
484 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
485 pData = buffer->data;
486 dataSize = buffer->stride * buffer->height * bytesPerPixel;
488 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
489 // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
490 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
491 ALOG_ASSERT(buffer->height == 1,
492 "RAW_PRIVATE should has height value one but got %d", buffer->height);
493 pData = buffer->data;
494 dataSize = buffer->width;
496 case HAL_PIXEL_FORMAT_RAW10:
497 // Single plane 10bpp bayer data.
498 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
499 LOG_ALWAYS_FATAL_IF(buffer->width % 4,
500 "Width is not multiple of 4 %d", buffer->width);
501 LOG_ALWAYS_FATAL_IF(buffer->height % 2,
502 "Height is not even %d", buffer->height);
503 LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 10 / 8),
504 "stride (%d) should be at least %d",
505 buffer->stride, buffer->width * 10 / 8);
506 pData = buffer->data;
507 dataSize = buffer->stride * buffer->height;
509 case HAL_PIXEL_FORMAT_RAW12:
510 // Single plane 10bpp bayer data.
511 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
512 LOG_ALWAYS_FATAL_IF(buffer->width % 4,
513 "Width is not multiple of 4 %d", buffer->width);
514 LOG_ALWAYS_FATAL_IF(buffer->height % 2,
515 "Height is not even %d", buffer->height);
516 LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 12 / 8),
517 "stride (%d) should be at least %d",
518 buffer->stride, buffer->width * 12 / 8);
519 pData = buffer->data;
520 dataSize = buffer->stride * buffer->height;
522 case HAL_PIXEL_FORMAT_RGBA_8888:
523 case HAL_PIXEL_FORMAT_RGBX_8888:
524 // Single plane, 32bpp.
526 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
527 pData = buffer->data;
528 dataSize = buffer->stride * buffer->height * bytesPerPixel;
530 case HAL_PIXEL_FORMAT_RGB_565:
531 // Single plane, 16bpp.
533 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
534 pData = buffer->data;
535 dataSize = buffer->stride * buffer->height * bytesPerPixel;
537 case HAL_PIXEL_FORMAT_RGB_888:
538 // Single plane, 24bpp.
540 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
541 pData = buffer->data;
542 dataSize = buffer->stride * buffer->height * bytesPerPixel;
545 jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
546 "Pixel format: 0x%x is unsupported", fmt);
554 static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
555 int32_t halReaderFormat)
557 ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
558 ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0), "Index is out of range:%d", idx);
561 ALOG_ASSERT(buffer != NULL, "buffer is NULL");
563 int32_t fmt = buffer->flexFormat;
565 fmt = applyFormatOverrides(fmt, halReaderFormat);
568 case HAL_PIXEL_FORMAT_YCbCr_420_888:
569 pixelStride = (idx == 0) ? 1 : buffer->chromaStep;
571 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
572 pixelStride = (idx == 0) ? 1 : 2;
574 case HAL_PIXEL_FORMAT_Y8:
575 // Single plane 8bpp data.
576 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
579 case HAL_PIXEL_FORMAT_YV12:
582 case HAL_PIXEL_FORMAT_BLOB:
583 case HAL_PIXEL_FORMAT_RAW10:
584 case HAL_PIXEL_FORMAT_RAW12:
585 // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
586 // those are single plane data with pixel stride 0 since they don't really have a
587 // well defined pixel stride
588 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
591 case HAL_PIXEL_FORMAT_Y16:
592 case HAL_PIXEL_FORMAT_RAW16:
593 case HAL_PIXEL_FORMAT_RGB_565:
594 // Single plane 16bpp data.
595 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
598 case HAL_PIXEL_FORMAT_RGBA_8888:
599 case HAL_PIXEL_FORMAT_RGBX_8888:
600 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
603 case HAL_PIXEL_FORMAT_RGB_888:
604 // Single plane, 24bpp.
605 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
608 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
609 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
610 pixelStride = 0; // RAW OPAQUE doesn't have pixel stride
613 jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
614 "Pixel format: 0x%x is unsupported", fmt);
621 static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
622 int32_t halReaderFormat)
624 ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
625 ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
628 ALOG_ASSERT(buffer != NULL, "buffer is NULL");
630 int32_t fmt = buffer->flexFormat;
632 fmt = applyFormatOverrides(fmt, halReaderFormat);
635 case HAL_PIXEL_FORMAT_YCbCr_420_888:
636 rowStride = (idx == 0) ? buffer->stride : buffer->chromaStride;
638 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
639 rowStride = buffer->width;
641 case HAL_PIXEL_FORMAT_YV12:
642 LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
643 "Stride is not 16 pixel aligned %d", buffer->stride);
644 rowStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
646 case HAL_PIXEL_FORMAT_BLOB:
647 // Blob is used for JPEG data. It is single plane and has 0 row stride and
649 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
652 case HAL_PIXEL_FORMAT_RAW10:
653 case HAL_PIXEL_FORMAT_RAW12:
654 // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane
655 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
656 rowStride = buffer->stride;
658 case HAL_PIXEL_FORMAT_Y8:
659 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
660 LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
661 "Stride is not 16 pixel aligned %d", buffer->stride);
662 rowStride = buffer->stride;
664 case HAL_PIXEL_FORMAT_Y16:
665 case HAL_PIXEL_FORMAT_RAW16:
666 // In native side, strides are specified in pixels, not in bytes.
667 // Single plane 16bpp bayer data. even width/height,
668 // row stride multiple of 16 pixels (32 bytes)
669 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
670 LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
671 "Stride is not 16 pixel aligned %d", buffer->stride);
672 rowStride = buffer->stride * 2;
674 case HAL_PIXEL_FORMAT_RGB_565:
675 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
676 rowStride = buffer->stride * 2;
678 case HAL_PIXEL_FORMAT_RGBA_8888:
679 case HAL_PIXEL_FORMAT_RGBX_8888:
680 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
681 rowStride = buffer->stride * 4;
683 case HAL_PIXEL_FORMAT_RGB_888:
684 // Single plane, 24bpp.
685 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
686 rowStride = buffer->stride * 3;
688 case HAL_PIXEL_FORMAT_RAW_OPAQUE:
689 ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
690 rowStride = 0; // RAW OPAQUE doesn't have row stride
693 ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
694 jniThrowException(env, "java/lang/UnsupportedOperationException",
695 "unsupported buffer format");
702 static int Image_getBufferWidth(CpuConsumer::LockedBuffer* buffer) {
703 if (buffer == NULL) return -1;
705 if (!buffer->crop.isEmpty()) {
706 return buffer->crop.getWidth();
708 return buffer->width;
711 static int Image_getBufferHeight(CpuConsumer::LockedBuffer* buffer) {
712 if (buffer == NULL) return -1;
714 if (!buffer->crop.isEmpty()) {
715 return buffer->crop.getHeight();
717 return buffer->height;
720 // --------------------------Methods for opaque Image and ImageReader----------
722 static BufferItemConsumer* ImageReader_getOpaqueConsumer(JNIEnv* env, jobject thiz)
724 ALOGV("%s:", __FUNCTION__);
725 JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
727 jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
731 if (!ctx->isOpaque()) {
732 jniThrowException(env, "java/lang/IllegalStateException",
733 "Non-opaque ImageReader doesn't support this method");
736 return ctx->getOpaqueConsumer();
739 static BufferItem* Image_getOpaqueBuffer(JNIEnv* env, jobject image)
741 return reinterpret_cast<BufferItem*>(
742 env->GetLongField(image, gSurfaceImageClassInfo.mNativeBuffer));
745 static int Image_getOpaqueBufferWidth(BufferItem* buffer) {
746 if (buffer == NULL) return -1;
748 if (!buffer->mCrop.isEmpty()) {
749 return buffer->mCrop.getWidth();
751 return buffer->mGraphicBuffer->getWidth();
754 static int Image_getOpaqueBufferHeight(BufferItem* buffer) {
755 if (buffer == NULL) return -1;
757 if (!buffer->mCrop.isEmpty()) {
758 return buffer->mCrop.getHeight();
761 return buffer->mGraphicBuffer->getHeight();
766 // ----------------------------------------------------------------------------
768 static void ImageReader_classInit(JNIEnv* env, jclass clazz)
770 ALOGV("%s:", __FUNCTION__);
772 jclass imageClazz = env->FindClass("android/media/ImageReader$SurfaceImage");
773 LOG_ALWAYS_FATAL_IF(imageClazz == NULL,
774 "can't find android/graphics/ImageReader$SurfaceImage");
775 gSurfaceImageClassInfo.mNativeBuffer = env->GetFieldID(
776 imageClazz, ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID, "J");
777 LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mNativeBuffer == NULL,
778 "can't find android/graphics/ImageReader.%s",
779 ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID);
781 gSurfaceImageClassInfo.mTimestamp = env->GetFieldID(
782 imageClazz, ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID, "J");
783 LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mTimestamp == NULL,
784 "can't find android/graphics/ImageReader.%s",
785 ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID);
787 gImageReaderClassInfo.mNativeContext = env->GetFieldID(
788 clazz, ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID, "J");
789 LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.mNativeContext == NULL,
790 "can't find android/graphics/ImageReader.%s",
791 ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID);
793 gImageReaderClassInfo.postEventFromNative = env->GetStaticMethodID(
794 clazz, "postEventFromNative", "(Ljava/lang/Object;)V");
795 LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.postEventFromNative == NULL,
796 "can't find android/graphics/ImageReader.postEventFromNative");
798 jclass planeClazz = env->FindClass("android/media/ImageReader$SurfaceImage$SurfacePlane");
799 LOG_ALWAYS_FATAL_IF(planeClazz == NULL, "Can not find SurfacePlane class");
800 // FindClass only gives a local reference of jclass object.
801 gSurfacePlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz);
802 gSurfacePlaneClassInfo.ctor = env->GetMethodID(gSurfacePlaneClassInfo.clazz, "<init>",
803 "(Landroid/media/ImageReader$SurfaceImage;III)V");
804 LOG_ALWAYS_FATAL_IF(gSurfacePlaneClassInfo.ctor == NULL,
805 "Can not find SurfacePlane constructor");
808 static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz,
809 jint width, jint height, jint format, jint maxImages)
813 android_dataspace nativeDataspace;
815 ALOGV("%s: width:%d, height: %d, format: 0x%x, maxImages:%d",
816 __FUNCTION__, width, height, format, maxImages);
818 PublicFormat publicFormat = static_cast<PublicFormat>(format);
819 nativeFormat = android_view_Surface_mapPublicFormatToHalFormat(
821 nativeDataspace = android_view_Surface_mapPublicFormatToHalDataspace(
824 jclass clazz = env->GetObjectClass(thiz);
826 jniThrowRuntimeException(env, "Can't find android/graphics/ImageReader");
829 sp<JNIImageReaderContext> ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages));
831 sp<IGraphicBufferProducer> gbProducer;
832 sp<IGraphicBufferConsumer> gbConsumer;
833 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
834 sp<ConsumerBase> consumer;
835 sp<CpuConsumer> cpuConsumer;
836 sp<BufferItemConsumer> opaqueConsumer;
837 String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
838 width, height, format, maxImages, getpid(),
839 createProcessUniqueId());
840 if (isFormatOpaque(nativeFormat)) {
841 // Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
842 // encoding. The only possibility will be ZSL output.
844 new BufferItemConsumer(gbConsumer, GRALLOC_USAGE_SW_READ_NEVER, maxImages,
845 /*controlledByApp*/true);
846 if (opaqueConsumer == NULL) {
847 jniThrowRuntimeException(env, "Failed to allocate native opaque consumer");
850 ctx->setOpaqueConsumer(opaqueConsumer);
851 opaqueConsumer->setName(consumerName);
852 consumer = opaqueConsumer;
854 cpuConsumer = new CpuConsumer(gbConsumer, maxImages, /*controlledByApp*/true);
855 // TODO: throw dvm exOutOfMemoryError?
856 if (cpuConsumer == NULL) {
857 jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer");
860 ctx->setCpuConsumer(cpuConsumer);
861 cpuConsumer->setName(consumerName);
862 consumer = cpuConsumer;
865 ctx->setProducer(gbProducer);
866 consumer->setFrameAvailableListener(ctx);
867 ImageReader_setNativeContext(env, thiz, ctx);
868 ctx->setBufferFormat(nativeFormat);
869 ctx->setBufferDataspace(nativeDataspace);
870 ctx->setBufferWidth(width);
871 ctx->setBufferHeight(height);
873 // Set the width/height/format/dataspace to the CpuConsumer
874 // TODO: below code can be simplified once b/19977701 is fixed.
875 if (isFormatOpaque(nativeFormat)) {
876 res = opaqueConsumer->setDefaultBufferSize(width, height);
878 jniThrowException(env, "java/lang/IllegalStateException",
879 "Failed to set opaque consumer buffer size");
882 res = opaqueConsumer->setDefaultBufferFormat(nativeFormat);
884 jniThrowException(env, "java/lang/IllegalStateException",
885 "Failed to set opaque consumer buffer format");
887 res = opaqueConsumer->setDefaultBufferDataSpace(nativeDataspace);
889 jniThrowException(env, "java/lang/IllegalStateException",
890 "Failed to set opaque consumer buffer dataSpace");
893 res = cpuConsumer->setDefaultBufferSize(width, height);
895 jniThrowException(env, "java/lang/IllegalStateException",
896 "Failed to set CpuConsumer buffer size");
899 res = cpuConsumer->setDefaultBufferFormat(nativeFormat);
901 jniThrowException(env, "java/lang/IllegalStateException",
902 "Failed to set CpuConsumer buffer format");
904 res = cpuConsumer->setDefaultBufferDataSpace(nativeDataspace);
906 jniThrowException(env, "java/lang/IllegalStateException",
907 "Failed to set CpuConsumer buffer dataSpace");
912 static void ImageReader_close(JNIEnv* env, jobject thiz)
914 ALOGV("%s:", __FUNCTION__);
916 JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
918 // ImageReader is already closed.
922 ConsumerBase* consumer = NULL;
923 if (ctx->isOpaque()) {
924 consumer = ImageReader_getOpaqueConsumer(env, thiz);
926 consumer = ImageReader_getCpuConsumer(env, thiz);
929 if (consumer != NULL) {
931 consumer->setFrameAvailableListener(NULL);
933 ImageReader_setNativeContext(env, thiz, NULL);
936 static void ImageReader_imageRelease(JNIEnv* env, jobject thiz, jobject image)
938 ALOGV("%s:", __FUNCTION__);
939 JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
941 ALOGW("ImageReader#close called before Image#close, consider calling Image#close first");
945 if (ctx->isOpaque()) {
946 BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
947 BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, image);
948 opaqueConsumer->releaseBuffer(*opaqueBuffer); // Not using fence for now.
949 Image_setOpaqueBuffer(env, image, NULL);
950 ctx->returnOpaqueBuffer(opaqueBuffer);
951 ALOGV("%s: Opaque Image has been released", __FUNCTION__);
953 CpuConsumer* consumer = ctx->getCpuConsumer();
954 CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, image);
956 // Release an already closed image is harmless.
959 consumer->unlockBuffer(*buffer);
960 Image_setBuffer(env, image, NULL);
961 ctx->returnLockedBuffer(buffer);
962 ALOGV("%s: Image (format: 0x%x) has been released", __FUNCTION__, ctx->getBufferFormat());
966 static jint ImageReader_opaqueImageSetup(JNIEnv* env, JNIImageReaderContext* ctx, jobject image) {
967 ALOGV("%s:", __FUNCTION__);
968 if (ctx == NULL || !ctx->isOpaque()) {
969 jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
973 BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
974 BufferItem* buffer = ctx->getOpaqueBuffer();
975 if (buffer == NULL) {
976 ALOGW("Unable to acquire a buffer item, very likely client tried to acquire more than"
977 " maxImages buffers");
978 return ACQUIRE_MAX_IMAGES;
981 status_t res = opaqueConsumer->acquireBuffer(buffer, 0);
983 ctx->returnOpaqueBuffer(buffer);
984 if (res == INVALID_OPERATION) {
985 // Max number of images were already acquired.
986 ALOGE("%s: Max number of buffers allowed are already acquired : %s (%d)",
987 __FUNCTION__, strerror(-res), res);
988 return ACQUIRE_MAX_IMAGES;
990 ALOGE("%s: Acquire image failed with error: %s (%d)",
991 __FUNCTION__, strerror(-res), res);
992 return ACQUIRE_NO_BUFFERS;
996 // Set SurfaceImage instance member variables
997 Image_setOpaqueBuffer(env, image, buffer);
998 env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
999 static_cast<jlong>(buffer->mTimestamp));
1001 return ACQUIRE_SUCCESS;
1004 static jint ImageReader_lockedImageSetup(JNIEnv* env, JNIImageReaderContext* ctx, jobject image) {
1005 CpuConsumer* consumer = ctx->getCpuConsumer();
1006 CpuConsumer::LockedBuffer* buffer = ctx->getLockedBuffer();
1007 if (buffer == NULL) {
1008 ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
1009 " maxImages buffers");
1010 return ACQUIRE_MAX_IMAGES;
1012 status_t res = consumer->lockNextBuffer(buffer);
1013 if (res != NO_ERROR) {
1014 ctx->returnLockedBuffer(buffer);
1015 if (res != BAD_VALUE /*no buffers*/) {
1016 if (res == NOT_ENOUGH_DATA) {
1017 return ACQUIRE_MAX_IMAGES;
1019 ALOGE("%s Fail to lockNextBuffer with error: %d ",
1021 jniThrowExceptionFmt(env, "java/lang/AssertionError",
1022 "Unknown error (%d) when we tried to lock buffer.",
1026 return ACQUIRE_NO_BUFFERS;
1029 if (buffer->flexFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
1030 jniThrowException(env, "java/lang/UnsupportedOperationException",
1031 "NV21 format is not supported by ImageReader");
1035 // Check if the left-top corner of the crop rect is origin, we currently assume this point is
1036 // zero, will revist this once this assumption turns out problematic.
1037 Point lt = buffer->crop.leftTop();
1038 if (lt.x != 0 || lt.y != 0) {
1039 jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
1040 "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
1044 // Check if the producer buffer configurations match what ImageReader configured.
1045 int outputWidth = Image_getBufferWidth(buffer);
1046 int outputHeight = Image_getBufferHeight(buffer);
1048 int imgReaderFmt = ctx->getBufferFormat();
1049 int imageReaderWidth = ctx->getBufferWidth();
1050 int imageReaderHeight = ctx->getBufferHeight();
1051 if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != HAL_PIXEL_FORMAT_BLOB) &&
1052 (imageReaderWidth != outputWidth || imageReaderHeight != outputHeight)) {
1053 ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
1054 __FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
1057 int bufFmt = buffer->format;
1058 if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888) {
1059 bufFmt = buffer->flexFormat;
1061 if (imgReaderFmt != bufFmt) {
1062 if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
1063 HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
1064 // Special casing for when producer switches to a format compatible with flexible YUV
1065 // (HAL_PIXEL_FORMAT_YCbCr_420_888).
1066 ctx->setBufferFormat(bufFmt);
1067 ALOGD("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt);
1068 } else if (imgReaderFmt == HAL_PIXEL_FORMAT_BLOB && bufFmt == HAL_PIXEL_FORMAT_RGBA_8888) {
1069 // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
1070 // write limitations for (b/17379185).
1071 ALOGD("%s: Receiving JPEG in HAL_PIXEL_FORMAT_RGBA_8888 buffer.", __FUNCTION__);
1073 // Return the buffer to the queue.
1074 consumer->unlockBuffer(*buffer);
1075 ctx->returnLockedBuffer(buffer);
1078 ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
1079 buffer->format, ctx->getBufferFormat());
1081 msg.appendFormat("The producer output buffer format 0x%x doesn't "
1082 "match the ImageReader's configured buffer format 0x%x.",
1083 bufFmt, ctx->getBufferFormat());
1084 jniThrowException(env, "java/lang/UnsupportedOperationException",
1089 // Set SurfaceImage instance member variables
1090 Image_setBuffer(env, image, buffer);
1091 env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
1092 static_cast<jlong>(buffer->timestamp));
1094 return ACQUIRE_SUCCESS;
1097 static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) {
1098 ALOGV("%s:", __FUNCTION__);
1099 JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
1101 jniThrowException(env, "java/lang/IllegalStateException",
1102 "ImageReader is not initialized or was already closed");
1106 if (ctx->isOpaque()) {
1107 return ImageReader_opaqueImageSetup(env, ctx, image);
1109 return ImageReader_lockedImageSetup(env, ctx, image);
1113 static jint ImageReader_detachImage(JNIEnv* env, jobject thiz, jobject image) {
1114 ALOGV("%s:", __FUNCTION__);
1115 JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
1117 jniThrowException(env, "java/lang/IllegalStateException", "ImageReader was already closed");
1122 if (!ctx->isOpaque()) {
1123 // TODO: Non-Opaque format detach is not implemented yet.
1124 jniThrowRuntimeException(env,
1125 "nativeDetachImage is not implemented yet for non-opaque format !!!");
1129 BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
1130 BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, image);
1131 if (!opaqueBuffer) {
1133 "Opaque Image already released and can not be detached from ImageReader!!!");
1134 jniThrowException(env, "java/lang/IllegalStateException",
1135 "Opaque Image detach from ImageReader failed: buffer was already released");
1139 res = opaqueConsumer->detachBuffer(opaqueBuffer->mSlot);
1141 ALOGE("Opaque Image detach failed: %s (%d)!!!", strerror(-res), res);
1142 jniThrowRuntimeException(env,
1143 "nativeDetachImage failed for opaque image!!!");
1149 static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
1151 ALOGV("%s: ", __FUNCTION__);
1153 IGraphicBufferProducer* gbp = ImageReader_getProducer(env, thiz);
1155 jniThrowRuntimeException(env, "CpuConsumer is uninitialized");
1159 // Wrap the IGBP in a Java-language Surface.
1160 return android_view_Surface_createFromIGraphicBufferProducer(env, gbp);
1163 static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx, int readerFormat)
1165 int rowStride, pixelStride;
1166 PublicFormat publicReaderFormat = static_cast<PublicFormat>(readerFormat);
1167 int halReaderFormat = android_view_Surface_mapPublicFormatToHalFormat(
1168 publicReaderFormat);
1170 ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
1171 if (isFormatOpaque(halReaderFormat)) {
1172 jniThrowException(env, "java/lang/IllegalStateException",
1173 "Opaque images from Opaque ImageReader do not have any planes");
1177 CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
1179 ALOG_ASSERT(buffer != NULL);
1180 if (buffer == NULL) {
1181 jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
1184 rowStride = Image_imageGetRowStride(env, buffer, idx, halReaderFormat);
1185 pixelStride = Image_imageGetPixelStride(env, buffer, idx, halReaderFormat);
1187 jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz,
1188 gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride);
1190 return surfPlaneObj;
1193 static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx, int readerFormat)
1195 uint8_t *base = NULL;
1198 PublicFormat readerPublicFormat = static_cast<PublicFormat>(readerFormat);
1199 int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
1200 readerPublicFormat);
1202 ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
1204 if (isFormatOpaque(readerHalFormat)) {
1205 jniThrowException(env, "java/lang/IllegalStateException",
1206 "Opaque images from Opaque ImageReader do not have any plane");
1210 CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
1212 if (buffer == NULL) {
1213 jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
1216 // Create byteBuffer from native buffer
1217 Image_getLockedBufferInfo(env, buffer, idx, &base, &size, readerHalFormat);
1219 if (size > static_cast<uint32_t>(INT32_MAX)) {
1220 // Byte buffer have 'int capacity', so check the range
1221 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
1222 "Size too large for bytebuffer capacity %" PRIu32, size);
1226 byteBuffer = env->NewDirectByteBuffer(base, size);
1227 // TODO: throw dvm exOutOfMemoryError?
1228 if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
1229 jniThrowException(env, "java/lang/IllegalStateException", "Failed to allocate ByteBuffer");
1235 static jint Image_getWidth(JNIEnv* env, jobject thiz, jint format)
1237 if (isFormatOpaque(format)) {
1238 BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, thiz);
1239 return Image_getOpaqueBufferWidth(opaqueBuffer);
1241 CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
1242 return Image_getBufferWidth(buffer);
1246 static jint Image_getHeight(JNIEnv* env, jobject thiz, jint format)
1248 if (isFormatOpaque(format)) {
1249 BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, thiz);
1250 return Image_getOpaqueBufferHeight(opaqueBuffer);
1252 CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
1253 return Image_getBufferHeight(buffer);
1257 static jint Image_getFormat(JNIEnv* env, jobject thiz, jint readerFormat)
1259 if (isFormatOpaque(readerFormat)) {
1260 // Assuming opaque reader produce opaque images.
1261 return static_cast<jint>(PublicFormat::PRIVATE);
1263 CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
1264 int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
1265 static_cast<PublicFormat>(readerFormat));
1266 int32_t fmt = applyFormatOverrides(buffer->flexFormat, readerHalFormat);
1267 PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
1268 fmt, buffer->dataSpace);
1269 return static_cast<jint>(publicFmt);
1275 // ----------------------------------------------------------------------------
1277 static const JNINativeMethod gImageReaderMethods[] = {
1278 {"nativeClassInit", "()V", (void*)ImageReader_classInit },
1279 {"nativeInit", "(Ljava/lang/Object;IIII)V", (void*)ImageReader_init },
1280 {"nativeClose", "()V", (void*)ImageReader_close },
1281 {"nativeReleaseImage", "(Landroid/media/Image;)V", (void*)ImageReader_imageRelease },
1282 {"nativeImageSetup", "(Landroid/media/Image;)I", (void*)ImageReader_imageSetup },
1283 {"nativeGetSurface", "()Landroid/view/Surface;", (void*)ImageReader_getSurface },
1284 {"nativeDetachImage", "(Landroid/media/Image;)I", (void*)ImageReader_detachImage },
1287 static const JNINativeMethod gImageMethods[] = {
1288 {"nativeImageGetBuffer", "(II)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer },
1289 {"nativeCreatePlane", "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
1290 (void*)Image_createSurfacePlane },
1291 {"nativeGetWidth", "(I)I", (void*)Image_getWidth },
1292 {"nativeGetHeight", "(I)I", (void*)Image_getHeight },
1293 {"nativeGetFormat", "(I)I", (void*)Image_getFormat },
1296 int register_android_media_ImageReader(JNIEnv *env) {
1298 int ret1 = AndroidRuntime::registerNativeMethods(env,
1299 "android/media/ImageReader", gImageReaderMethods, NELEM(gImageReaderMethods));
1301 int ret2 = AndroidRuntime::registerNativeMethods(env,
1302 "android/media/ImageReader$SurfaceImage", gImageMethods, NELEM(gImageMethods));
1304 return (ret1 || ret2);