android_media_ImageReader.cpp revision 5e712064dfe48992f8f732208fa4fc13f3455b30
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 MaxImagesAcquiredException =
47    "android/media/ImageReader$MaxImagesAcquiredException";
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, MaxImagesAcquiredException,
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, MaxImagesAcquiredException,
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 width/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 ((buffer->format != HAL_PIXEL_FORMAT_BLOB) &&
752            (imageReaderWidth != outputWidth || imageReaderHeight > outputHeight)) {
753        /**
754         * For video decoder, the buffer height is actually the vertical stride,
755         * which is always >= actual image height. For future, decoder need provide
756         * right crop rectangle to CpuConsumer to indicate the actual image height,
757         * see bug 9563986. After this bug is fixed, we can enforce the height equal
758         * check. Right now, only make sure buffer height is no less than ImageReader
759         * height.
760         */
761        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
762                "Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
763                outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
764    }
765
766    if (ctx->getBufferFormat() != buffer->format) {
767        // Return the buffer to the queue.
768        consumer->unlockBuffer(*buffer);
769        ctx->returnLockedBuffer(buffer);
770
771        // Throw exception
772        ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
773              buffer->format, ctx->getBufferFormat());
774        String8 msg;
775        msg.appendFormat("The producer output buffer format 0x%x doesn't "
776                "match the ImageReader's configured buffer format 0x%x.",
777                buffer->format, ctx->getBufferFormat());
778        jniThrowException(env, "java/lang/UnsupportedOperationException",
779                msg.string());
780        return false;
781    }
782    // Set SurfaceImage instance member variables
783    Image_setBuffer(env, image, buffer);
784    env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
785            static_cast<jlong>(buffer->timestamp));
786
787    return true;
788}
789
790static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
791{
792    ALOGV("%s: ", __FUNCTION__);
793
794    BufferQueue* bq = ImageReader_getBufferQueue(env, thiz);
795    if (bq == NULL) {
796        jniThrowRuntimeException(env, "CpuConsumer is uninitialized");
797        return NULL;
798    }
799
800    // Wrap the IGBP in a Java-language Surface.
801    return android_view_Surface_createFromIGraphicBufferProducer(env, bq);
802}
803
804static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx)
805{
806    int rowStride, pixelStride;
807    ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
808
809    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
810
811    ALOG_ASSERT(buffer != NULL);
812    if (buffer == NULL) {
813        jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
814    }
815    rowStride = Image_imageGetRowStride(env, buffer, idx);
816    pixelStride = Image_imageGetPixelStride(env, buffer, idx);
817
818    jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz,
819            gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride);
820
821    return surfPlaneObj;
822}
823
824static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx)
825{
826    uint8_t *base = NULL;
827    uint32_t size = 0;
828    jobject byteBuffer;
829
830    ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
831
832    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
833
834    if (buffer == NULL) {
835        jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
836    }
837
838    // Create byteBuffer from native buffer
839    Image_getLockedBufferInfo(env, buffer, idx, &base, &size);
840    byteBuffer = env->NewDirectByteBuffer(base, size);
841    // TODO: throw dvm exOutOfMemoryError?
842    if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
843        jniThrowException(env, "java/lang/IllegalStateException", "Failed to allocate ByteBuffer");
844    }
845
846    return byteBuffer;
847}
848
849} // extern "C"
850
851// ----------------------------------------------------------------------------
852
853static JNINativeMethod gImageReaderMethods[] = {
854    {"nativeClassInit",        "()V",                        (void*)ImageReader_classInit },
855    {"nativeInit",             "(Ljava/lang/Object;IIII)V",  (void*)ImageReader_init },
856    {"nativeClose",            "()V",                        (void*)ImageReader_close },
857    {"nativeReleaseImage",     "(Landroid/media/Image;)V",   (void*)ImageReader_imageRelease },
858    {"nativeImageSetup",       "(Landroid/media/Image;)Z",    (void*)ImageReader_imageSetup },
859    {"nativeGetSurface",       "()Landroid/view/Surface;",   (void*)ImageReader_getSurface },
860};
861
862static JNINativeMethod gImageMethods[] = {
863    {"nativeImageGetBuffer",   "(I)Ljava/nio/ByteBuffer;",   (void*)Image_getByteBuffer },
864    {"nativeCreatePlane",      "(I)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
865                                                             (void*)Image_createSurfacePlane },
866};
867
868int register_android_media_ImageReader(JNIEnv *env) {
869
870    int ret1 = AndroidRuntime::registerNativeMethods(env,
871                   "android/media/ImageReader", gImageReaderMethods, NELEM(gImageReaderMethods));
872
873    int ret2 = AndroidRuntime::registerNativeMethods(env,
874                   "android/media/ImageReader$SurfaceImage", gImageMethods, NELEM(gImageMethods));
875
876    return (ret1 || ret2);
877}
878