blob: fcc975c0975a3ccf768e5b04479cd136387ec9ae [file] [log] [blame]
Zhijun He212e78d2013-06-07 11:36:23 -07001/*
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"
Zhijun He0ab41622016-02-25 16:00:38 -080019#include "android_media_Utils.h"
Zhijun He212e78d2013-06-07 11:36:23 -070020#include <utils/Log.h>
21#include <utils/misc.h>
22#include <utils/List.h>
Jeff Brownef961212013-08-05 20:39:29 -070023#include <utils/String8.h>
Zhijun He212e78d2013-06-07 11:36:23 -070024
25#include <cstdio>
26
Zhijun Hece9d6f92015-03-29 16:33:59 -070027#include <gui/BufferItemConsumer.h>
Zhijun He212e78d2013-06-07 11:36:23 -070028#include <gui/Surface.h>
29
30#include <android_runtime/AndroidRuntime.h>
31#include <android_runtime/android_view_Surface.h>
32
33#include <jni.h>
Steven Moreland2279b252017-07-19 09:50:45 -070034#include <nativehelper/JNIHelp.h>
Zhijun He212e78d2013-06-07 11:36:23 -070035
Igor Murashkin5096def2014-06-24 10:49:11 -070036#include <stdint.h>
37#include <inttypes.h>
38
Zhijun He212e78d2013-06-07 11:36:23 -070039#define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID "mNativeContext"
Zhijun Hece9d6f92015-03-29 16:33:59 -070040#define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID "mNativeBuffer"
Zhijun He212e78d2013-06-07 11:36:23 -070041#define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID "mTimestamp"
42
43// ----------------------------------------------------------------------------
44
45using namespace android;
46
Zhijun He212e78d2013-06-07 11:36:23 -070047
Igor Murashkine3351f12013-09-13 13:08:04 -070048enum {
49 ACQUIRE_SUCCESS = 0,
50 ACQUIRE_NO_BUFFERS = 1,
51 ACQUIRE_MAX_IMAGES = 2,
52};
53
Jeff Brownef961212013-08-05 20:39:29 -070054static struct {
55 jfieldID mNativeContext;
56 jmethodID postEventFromNative;
57} gImageReaderClassInfo;
Zhijun He212e78d2013-06-07 11:36:23 -070058
Jeff Brownef961212013-08-05 20:39:29 -070059static struct {
Zhijun Hece9d6f92015-03-29 16:33:59 -070060 jfieldID mNativeBuffer;
Jeff Brownef961212013-08-05 20:39:29 -070061 jfieldID mTimestamp;
Zhijun He0ab41622016-02-25 16:00:38 -080062 jfieldID mPlanes;
Jeff Brownef961212013-08-05 20:39:29 -070063} gSurfaceImageClassInfo;
64
65static struct {
Zhijun He212e78d2013-06-07 11:36:23 -070066 jclass clazz;
67 jmethodID ctor;
Jeff Brownef961212013-08-05 20:39:29 -070068} gSurfacePlaneClassInfo;
Zhijun He212e78d2013-06-07 11:36:23 -070069
Eino-Ville Talvalaef9db7d2015-06-09 14:15:15 -070070// Get an ID that's unique within this process.
71static int32_t createProcessUniqueId() {
72 static volatile int32_t globalCounter = 0;
73 return android_atomic_inc(&globalCounter);
74}
75
Zhijun He212e78d2013-06-07 11:36:23 -070076// ----------------------------------------------------------------------------
77
Zhijun Hece9d6f92015-03-29 16:33:59 -070078class JNIImageReaderContext : public ConsumerBase::FrameAvailableListener
Zhijun He212e78d2013-06-07 11:36:23 -070079{
80public:
81 JNIImageReaderContext(JNIEnv* env, jobject weakThiz, jclass clazz, int maxImages);
82
83 virtual ~JNIImageReaderContext();
84
Dan Stoza2c34b5e2014-11-04 11:36:33 -080085 virtual void onFrameAvailable(const BufferItem& item);
Zhijun He212e78d2013-06-07 11:36:23 -070086
Zhijun He0ab41622016-02-25 16:00:38 -080087 BufferItem* getBufferItem();
88 void returnBufferItem(BufferItem* buffer);
Zhijun He212e78d2013-06-07 11:36:23 -070089
Zhijun Hece9d6f92015-03-29 16:33:59 -070090
Zhijun He0ab41622016-02-25 16:00:38 -080091 void setBufferConsumer(const sp<BufferItemConsumer>& consumer) { mConsumer = consumer; }
92 BufferItemConsumer* getBufferConsumer() { return mConsumer.get(); }
Zhijun Hece9d6f92015-03-29 16:33:59 -070093
Dan Stoza5b3c7c12014-03-12 16:44:45 -070094 void setProducer(const sp<IGraphicBufferProducer>& producer) { mProducer = producer; }
95 IGraphicBufferProducer* getProducer() { return mProducer.get(); }
Zhijun He212e78d2013-06-07 11:36:23 -070096
97 void setBufferFormat(int format) { mFormat = format; }
98 int getBufferFormat() { return mFormat; }
99
Eino-Ville Talvala805f3c92015-02-26 10:57:55 -0800100 void setBufferDataspace(android_dataspace dataSpace) { mDataSpace = dataSpace; }
101 android_dataspace getBufferDataspace() { return mDataSpace; }
102
Zhijun He212e78d2013-06-07 11:36:23 -0700103 void setBufferWidth(int width) { mWidth = width; }
104 int getBufferWidth() { return mWidth; }
105
106 void setBufferHeight(int height) { mHeight = height; }
107 int getBufferHeight() { return mHeight; }
108
109private:
110 static JNIEnv* getJNIEnv(bool* needsDetach);
111 static void detachJNI();
112
Zhijun He0ab41622016-02-25 16:00:38 -0800113 List<BufferItem*> mBuffers;
114 sp<BufferItemConsumer> mConsumer;
Dan Stoza5b3c7c12014-03-12 16:44:45 -0700115 sp<IGraphicBufferProducer> mProducer;
Zhijun He212e78d2013-06-07 11:36:23 -0700116 jobject mWeakThiz;
117 jclass mClazz;
118 int mFormat;
Eino-Ville Talvala805f3c92015-02-26 10:57:55 -0800119 android_dataspace mDataSpace;
Zhijun He212e78d2013-06-07 11:36:23 -0700120 int mWidth;
121 int mHeight;
122};
123
124JNIImageReaderContext::JNIImageReaderContext(JNIEnv* env,
125 jobject weakThiz, jclass clazz, int maxImages) :
126 mWeakThiz(env->NewGlobalRef(weakThiz)),
Zhijun He0ab41622016-02-25 16:00:38 -0800127 mClazz((jclass)env->NewGlobalRef(clazz)),
128 mFormat(0),
129 mDataSpace(HAL_DATASPACE_UNKNOWN),
130 mWidth(-1),
131 mHeight(-1) {
Zhijun He212e78d2013-06-07 11:36:23 -0700132 for (int i = 0; i < maxImages; i++) {
Zhijun He0ab41622016-02-25 16:00:38 -0800133 BufferItem* buffer = new BufferItem;
Zhijun He212e78d2013-06-07 11:36:23 -0700134 mBuffers.push_back(buffer);
135 }
136}
137
138JNIEnv* JNIImageReaderContext::getJNIEnv(bool* needsDetach) {
139 LOG_ALWAYS_FATAL_IF(needsDetach == NULL, "needsDetach is null!!!");
140 *needsDetach = false;
141 JNIEnv* env = AndroidRuntime::getJNIEnv();
142 if (env == NULL) {
143 JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
144 JavaVM* vm = AndroidRuntime::getJavaVM();
145 int result = vm->AttachCurrentThread(&env, (void*) &args);
146 if (result != JNI_OK) {
147 ALOGE("thread attach failed: %#x", result);
148 return NULL;
149 }
150 *needsDetach = true;
151 }
152 return env;
153}
154
155void JNIImageReaderContext::detachJNI() {
156 JavaVM* vm = AndroidRuntime::getJavaVM();
157 int result = vm->DetachCurrentThread();
158 if (result != JNI_OK) {
159 ALOGE("thread detach failed: %#x", result);
160 }
161}
162
Zhijun He0ab41622016-02-25 16:00:38 -0800163BufferItem* JNIImageReaderContext::getBufferItem() {
Zhijun He212e78d2013-06-07 11:36:23 -0700164 if (mBuffers.empty()) {
165 return NULL;
166 }
Zhijun He0ab41622016-02-25 16:00:38 -0800167 // Return a BufferItem pointer and remove it from the list
168 List<BufferItem*>::iterator it = mBuffers.begin();
169 BufferItem* buffer = *it;
Zhijun He212e78d2013-06-07 11:36:23 -0700170 mBuffers.erase(it);
171 return buffer;
172}
173
Zhijun He0ab41622016-02-25 16:00:38 -0800174void JNIImageReaderContext::returnBufferItem(BufferItem* buffer) {
Zhijun He212e78d2013-06-07 11:36:23 -0700175 mBuffers.push_back(buffer);
176}
177
178JNIImageReaderContext::~JNIImageReaderContext() {
179 bool needsDetach = false;
180 JNIEnv* env = getJNIEnv(&needsDetach);
181 if (env != NULL) {
182 env->DeleteGlobalRef(mWeakThiz);
183 env->DeleteGlobalRef(mClazz);
184 } else {
185 ALOGW("leaking JNI object references");
186 }
187 if (needsDetach) {
188 detachJNI();
189 }
190
Zhijun He0ab41622016-02-25 16:00:38 -0800191 // Delete buffer items.
192 for (List<BufferItem *>::iterator it = mBuffers.begin();
Zhijun He212e78d2013-06-07 11:36:23 -0700193 it != mBuffers.end(); it++) {
194 delete *it;
195 }
Zhijun Hece9d6f92015-03-29 16:33:59 -0700196
Zhijun Hece9d6f92015-03-29 16:33:59 -0700197 if (mConsumer != 0) {
198 mConsumer.clear();
199 }
Zhijun He212e78d2013-06-07 11:36:23 -0700200}
201
Dan Stoza2c34b5e2014-11-04 11:36:33 -0800202void JNIImageReaderContext::onFrameAvailable(const BufferItem& /*item*/)
Zhijun He212e78d2013-06-07 11:36:23 -0700203{
204 ALOGV("%s: frame available", __FUNCTION__);
205 bool needsDetach = false;
206 JNIEnv* env = getJNIEnv(&needsDetach);
207 if (env != NULL) {
Jeff Brownef961212013-08-05 20:39:29 -0700208 env->CallStaticVoidMethod(mClazz, gImageReaderClassInfo.postEventFromNative, mWeakThiz);
Zhijun He212e78d2013-06-07 11:36:23 -0700209 } else {
210 ALOGW("onFrameAvailable event will not posted");
211 }
212 if (needsDetach) {
213 detachJNI();
214 }
215}
216
217// ----------------------------------------------------------------------------
218
219extern "C" {
220
221static JNIImageReaderContext* ImageReader_getContext(JNIEnv* env, jobject thiz)
222{
223 JNIImageReaderContext *ctx;
224 ctx = reinterpret_cast<JNIImageReaderContext *>
Jeff Brownef961212013-08-05 20:39:29 -0700225 (env->GetLongField(thiz, gImageReaderClassInfo.mNativeContext));
Zhijun He212e78d2013-06-07 11:36:23 -0700226 return ctx;
227}
228
Dan Stoza5b3c7c12014-03-12 16:44:45 -0700229static IGraphicBufferProducer* ImageReader_getProducer(JNIEnv* env, jobject thiz)
Mathias Agopian52a9a102013-08-02 01:38:38 -0700230{
231 ALOGV("%s:", __FUNCTION__);
232 JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
233 if (ctx == NULL) {
234 jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
235 return NULL;
236 }
Zhijun Hece9d6f92015-03-29 16:33:59 -0700237
Dan Stoza5b3c7c12014-03-12 16:44:45 -0700238 return ctx->getProducer();
Mathias Agopian52a9a102013-08-02 01:38:38 -0700239}
240
Zhijun He212e78d2013-06-07 11:36:23 -0700241static void ImageReader_setNativeContext(JNIEnv* env,
242 jobject thiz, sp<JNIImageReaderContext> ctx)
243{
244 ALOGV("%s:", __FUNCTION__);
245 JNIImageReaderContext* const p = ImageReader_getContext(env, thiz);
246 if (ctx != 0) {
247 ctx->incStrong((void*)ImageReader_setNativeContext);
248 }
249 if (p) {
250 p->decStrong((void*)ImageReader_setNativeContext);
251 }
Jeff Brownef961212013-08-05 20:39:29 -0700252 env->SetLongField(thiz, gImageReaderClassInfo.mNativeContext,
253 reinterpret_cast<jlong>(ctx.get()));
Zhijun He212e78d2013-06-07 11:36:23 -0700254}
255
Zhijun He0ab41622016-02-25 16:00:38 -0800256static BufferItemConsumer* ImageReader_getBufferConsumer(JNIEnv* env, jobject thiz)
Zhijun Hece9d6f92015-03-29 16:33:59 -0700257{
258 ALOGV("%s:", __FUNCTION__);
259 JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
260 if (ctx == NULL) {
261 jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
262 return NULL;
263 }
264
Zhijun He0ab41622016-02-25 16:00:38 -0800265 return ctx->getBufferConsumer();
Zhijun Hece9d6f92015-03-29 16:33:59 -0700266}
267
Zhijun He0ab41622016-02-25 16:00:38 -0800268static void Image_setBufferItem(JNIEnv* env, jobject thiz,
269 const BufferItem* buffer)
270{
271 env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
272}
273
274static BufferItem* Image_getBufferItem(JNIEnv* env, jobject image)
Zhijun Hece9d6f92015-03-29 16:33:59 -0700275{
276 return reinterpret_cast<BufferItem*>(
277 env->GetLongField(image, gSurfaceImageClassInfo.mNativeBuffer));
278}
279
Zhijun Hece9d6f92015-03-29 16:33:59 -0700280
Zhijun He212e78d2013-06-07 11:36:23 -0700281// ----------------------------------------------------------------------------
282
283static void ImageReader_classInit(JNIEnv* env, jclass clazz)
284{
285 ALOGV("%s:", __FUNCTION__);
286
287 jclass imageClazz = env->FindClass("android/media/ImageReader$SurfaceImage");
288 LOG_ALWAYS_FATAL_IF(imageClazz == NULL,
289 "can't find android/graphics/ImageReader$SurfaceImage");
Zhijun Hece9d6f92015-03-29 16:33:59 -0700290 gSurfaceImageClassInfo.mNativeBuffer = env->GetFieldID(
Jeff Brownef961212013-08-05 20:39:29 -0700291 imageClazz, ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID, "J");
Zhijun Hece9d6f92015-03-29 16:33:59 -0700292 LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mNativeBuffer == NULL,
Zhijun He212e78d2013-06-07 11:36:23 -0700293 "can't find android/graphics/ImageReader.%s",
294 ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID);
295
Jeff Brownef961212013-08-05 20:39:29 -0700296 gSurfaceImageClassInfo.mTimestamp = env->GetFieldID(
297 imageClazz, ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID, "J");
298 LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mTimestamp == NULL,
Zhijun He212e78d2013-06-07 11:36:23 -0700299 "can't find android/graphics/ImageReader.%s",
300 ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID);
301
Zhijun He0ab41622016-02-25 16:00:38 -0800302 gSurfaceImageClassInfo.mPlanes = env->GetFieldID(
303 imageClazz, "mPlanes", "[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;");
304 LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mPlanes == NULL,
305 "can't find android/media/ImageReader$ReaderSurfaceImage.mPlanes");
306
Jeff Brownef961212013-08-05 20:39:29 -0700307 gImageReaderClassInfo.mNativeContext = env->GetFieldID(
308 clazz, ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID, "J");
309 LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.mNativeContext == NULL,
Zhijun He212e78d2013-06-07 11:36:23 -0700310 "can't find android/graphics/ImageReader.%s",
311 ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID);
312
Jeff Brownef961212013-08-05 20:39:29 -0700313 gImageReaderClassInfo.postEventFromNative = env->GetStaticMethodID(
314 clazz, "postEventFromNative", "(Ljava/lang/Object;)V");
315 LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.postEventFromNative == NULL,
Zhijun He212e78d2013-06-07 11:36:23 -0700316 "can't find android/graphics/ImageReader.postEventFromNative");
317
318 jclass planeClazz = env->FindClass("android/media/ImageReader$SurfaceImage$SurfacePlane");
319 LOG_ALWAYS_FATAL_IF(planeClazz == NULL, "Can not find SurfacePlane class");
320 // FindClass only gives a local reference of jclass object.
Jeff Brownef961212013-08-05 20:39:29 -0700321 gSurfacePlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz);
322 gSurfacePlaneClassInfo.ctor = env->GetMethodID(gSurfacePlaneClassInfo.clazz, "<init>",
Zhijun He0ab41622016-02-25 16:00:38 -0800323 "(Landroid/media/ImageReader$SurfaceImage;IILjava/nio/ByteBuffer;)V");
Jeff Brownef961212013-08-05 20:39:29 -0700324 LOG_ALWAYS_FATAL_IF(gSurfacePlaneClassInfo.ctor == NULL,
325 "Can not find SurfacePlane constructor");
Zhijun He212e78d2013-06-07 11:36:23 -0700326}
327
328static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz,
329 jint width, jint height, jint format, jint maxImages)
330{
331 status_t res;
332 int nativeFormat;
Eino-Ville Talvala805f3c92015-02-26 10:57:55 -0800333 android_dataspace nativeDataspace;
Zhijun He212e78d2013-06-07 11:36:23 -0700334
335 ALOGV("%s: width:%d, height: %d, format: 0x%x, maxImages:%d",
336 __FUNCTION__, width, height, format, maxImages);
337
Eino-Ville Talvala805f3c92015-02-26 10:57:55 -0800338 PublicFormat publicFormat = static_cast<PublicFormat>(format);
339 nativeFormat = android_view_Surface_mapPublicFormatToHalFormat(
340 publicFormat);
341 nativeDataspace = android_view_Surface_mapPublicFormatToHalDataspace(
342 publicFormat);
Zhijun He212e78d2013-06-07 11:36:23 -0700343
Zhijun He212e78d2013-06-07 11:36:23 -0700344 jclass clazz = env->GetObjectClass(thiz);
345 if (clazz == NULL) {
346 jniThrowRuntimeException(env, "Can't find android/graphics/ImageReader");
347 return;
348 }
349 sp<JNIImageReaderContext> ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages));
Zhijun Hece9d6f92015-03-29 16:33:59 -0700350
351 sp<IGraphicBufferProducer> gbProducer;
352 sp<IGraphicBufferConsumer> gbConsumer;
353 BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
Zhijun He0ab41622016-02-25 16:00:38 -0800354 sp<BufferItemConsumer> bufferConsumer;
Eino-Ville Talvalaef9db7d2015-06-09 14:15:15 -0700355 String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
356 width, height, format, maxImages, getpid(),
357 createProcessUniqueId());
Zhijun He0ab41622016-02-25 16:00:38 -0800358 uint32_t consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
359
Zhijun Hece9d6f92015-03-29 16:33:59 -0700360 if (isFormatOpaque(nativeFormat)) {
361 // Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
362 // encoding. The only possibility will be ZSL output.
Zhijun He0ab41622016-02-25 16:00:38 -0800363 consumerUsage = GRALLOC_USAGE_SW_READ_NEVER;
Zhijun Hece9d6f92015-03-29 16:33:59 -0700364 }
Zhijun He0ab41622016-02-25 16:00:38 -0800365 bufferConsumer = new BufferItemConsumer(gbConsumer, consumerUsage, maxImages,
366 /*controlledByApp*/true);
367 if (bufferConsumer == nullptr) {
368 jniThrowExceptionFmt(env, "java/lang/RuntimeException",
369 "Failed to allocate native buffer consumer for format 0x%x", nativeFormat);
370 return;
371 }
372 ctx->setBufferConsumer(bufferConsumer);
373 bufferConsumer->setName(consumerName);
Zhijun Hece9d6f92015-03-29 16:33:59 -0700374
Dan Stoza5b3c7c12014-03-12 16:44:45 -0700375 ctx->setProducer(gbProducer);
Zhijun He0ab41622016-02-25 16:00:38 -0800376 bufferConsumer->setFrameAvailableListener(ctx);
Zhijun He212e78d2013-06-07 11:36:23 -0700377 ImageReader_setNativeContext(env, thiz, ctx);
378 ctx->setBufferFormat(nativeFormat);
Eino-Ville Talvala805f3c92015-02-26 10:57:55 -0800379 ctx->setBufferDataspace(nativeDataspace);
Zhijun He212e78d2013-06-07 11:36:23 -0700380 ctx->setBufferWidth(width);
381 ctx->setBufferHeight(height);
382
Zhijun He0ab41622016-02-25 16:00:38 -0800383 // Set the width/height/format/dataspace to the bufferConsumer.
384 res = bufferConsumer->setDefaultBufferSize(width, height);
385 if (res != OK) {
386 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
387 "Failed to set buffer consumer default size (%dx%d) for format 0x%x",
388 width, height, nativeFormat);
389 return;
390 }
391 res = bufferConsumer->setDefaultBufferFormat(nativeFormat);
392 if (res != OK) {
393 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
394 "Failed to set buffer consumer default format 0x%x", nativeFormat);
395 }
396 res = bufferConsumer->setDefaultBufferDataSpace(nativeDataspace);
397 if (res != OK) {
398 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
399 "Failed to set buffer consumer default dataSpace 0x%x", nativeDataspace);
Zhijun He212e78d2013-06-07 11:36:23 -0700400 }
Zhijun He212e78d2013-06-07 11:36:23 -0700401}
402
403static void ImageReader_close(JNIEnv* env, jobject thiz)
404{
405 ALOGV("%s:", __FUNCTION__);
406
407 JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
408 if (ctx == NULL) {
409 // ImageReader is already closed.
410 return;
411 }
412
Zhijun He0ab41622016-02-25 16:00:38 -0800413 BufferItemConsumer* consumer = NULL;
414 consumer = ImageReader_getBufferConsumer(env, thiz);
Zhijun Hece9d6f92015-03-29 16:33:59 -0700415
Zhijun He212e78d2013-06-07 11:36:23 -0700416 if (consumer != NULL) {
417 consumer->abandon();
418 consumer->setFrameAvailableListener(NULL);
419 }
420 ImageReader_setNativeContext(env, thiz, NULL);
421}
422
Zhijun He0ab41622016-02-25 16:00:38 -0800423static sp<Fence> Image_unlockIfLocked(JNIEnv* env, jobject image) {
424 ALOGV("%s", __FUNCTION__);
425 BufferItem* buffer = Image_getBufferItem(env, image);
426 if (buffer == NULL) {
427 jniThrowException(env, "java/lang/IllegalStateException",
428 "Image is not initialized");
429 return Fence::NO_FENCE;
430 }
431
432 // Is locked?
433 bool wasBufferLocked = false;
434 jobject planes = NULL;
435 if (!isFormatOpaque(buffer->mGraphicBuffer->getPixelFormat())) {
436 planes = env->GetObjectField(image, gSurfaceImageClassInfo.mPlanes);
437 }
438 wasBufferLocked = (planes != NULL);
439 if (wasBufferLocked) {
440 status_t res = OK;
441 int fenceFd = -1;
442 if (wasBufferLocked) {
443 res = buffer->mGraphicBuffer->unlockAsync(&fenceFd);
444 if (res != OK) {
445 jniThrowRuntimeException(env, "unlock buffer failed");
446 return Fence::NO_FENCE;
447 }
448 }
449 sp<Fence> releaseFence = new Fence(fenceFd);
450 return releaseFence;
451 ALOGV("Successfully unlocked the image");
452 }
453 return Fence::NO_FENCE;
454}
455
Zhijun He212e78d2013-06-07 11:36:23 -0700456static void ImageReader_imageRelease(JNIEnv* env, jobject thiz, jobject image)
457{
458 ALOGV("%s:", __FUNCTION__);
459 JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
460 if (ctx == NULL) {
461 ALOGW("ImageReader#close called before Image#close, consider calling Image#close first");
462 return;
463 }
464
Zhijun He0ab41622016-02-25 16:00:38 -0800465 BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer();
466 BufferItem* buffer = Image_getBufferItem(env, image);
467 if (buffer == nullptr) {
468 // Release an already closed image is harmless.
469 return;
Zhijun He212e78d2013-06-07 11:36:23 -0700470 }
471
Zhijun He0ab41622016-02-25 16:00:38 -0800472 sp<Fence> releaseFence = Image_unlockIfLocked(env, image);
473 bufferConsumer->releaseBuffer(*buffer, releaseFence);
474 Image_setBufferItem(env, image, NULL);
475 ctx->returnBufferItem(buffer);
476 ALOGV("%s: Image (format: 0x%x) has been released", __FUNCTION__, ctx->getBufferFormat());
Zhijun He212e78d2013-06-07 11:36:23 -0700477}
478
Zhijun Hece9d6f92015-03-29 16:33:59 -0700479static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) {
480 ALOGV("%s:", __FUNCTION__);
481 JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
482 if (ctx == NULL) {
Zhijun Hedc6bb242015-12-03 15:34:34 -0800483 jniThrowException(env, "java/lang/IllegalStateException",
484 "ImageReader is not initialized or was already closed");
Zhijun Hece9d6f92015-03-29 16:33:59 -0700485 return -1;
486 }
487
Zhijun He0ab41622016-02-25 16:00:38 -0800488 BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer();
489 BufferItem* buffer = ctx->getBufferItem();
490 if (buffer == NULL) {
491 ALOGW("Unable to acquire a buffer item, very likely client tried to acquire more than"
492 " maxImages buffers");
493 return ACQUIRE_MAX_IMAGES;
Zhijun Hece9d6f92015-03-29 16:33:59 -0700494 }
Zhijun He0ab41622016-02-25 16:00:38 -0800495
496 status_t res = bufferConsumer->acquireBuffer(buffer, 0);
497 if (res != OK) {
498 ctx->returnBufferItem(buffer);
499 if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
500 if (res == INVALID_OPERATION) {
501 // Max number of images were already acquired.
502 ALOGE("%s: Max number of buffers allowed are already acquired : %s (%d)",
503 __FUNCTION__, strerror(-res), res);
504 return ACQUIRE_MAX_IMAGES;
505 } else {
506 ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
507 __FUNCTION__, strerror(-res), res);
508 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
509 "Unknown error (%d) when we tried to acquire an image.",
510 res);
511 return ACQUIRE_NO_BUFFERS;
512 }
513 }
514 // This isn't really an error case, as the application may acquire buffer at any time.
515 return ACQUIRE_NO_BUFFERS;
516 }
517
518 // Add some extra checks for non-opaque formats.
519 if (!isFormatOpaque(ctx->getBufferFormat())) {
520 // Check if the left-top corner of the crop rect is origin, we currently assume this point is
521 // zero, will revisit this once this assumption turns out problematic.
522 Point lt = buffer->mCrop.leftTop();
523 if (lt.x != 0 || lt.y != 0) {
524 jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
525 "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
526 return -1;
527 }
528
529 // Check if the producer buffer configurations match what ImageReader configured.
530 int outputWidth = getBufferWidth(buffer);
531 int outputHeight = getBufferHeight(buffer);
532
533 int imgReaderFmt = ctx->getBufferFormat();
534 int imageReaderWidth = ctx->getBufferWidth();
535 int imageReaderHeight = ctx->getBufferHeight();
536 int bufferFormat = buffer->mGraphicBuffer->getPixelFormat();
537 if ((bufferFormat != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != HAL_PIXEL_FORMAT_BLOB) &&
538 (imageReaderWidth != outputWidth || imageReaderHeight != outputHeight)) {
539 ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
540 __FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
541 }
542 if (imgReaderFmt != bufferFormat) {
543 if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 &&
544 isPossiblyYUV(bufferFormat)) {
545 // Treat formats that are compatible with flexible YUV
546 // (HAL_PIXEL_FORMAT_YCbCr_420_888) as HAL_PIXEL_FORMAT_YCbCr_420_888.
547 ALOGV("%s: Treat buffer format to 0x%x as HAL_PIXEL_FORMAT_YCbCr_420_888",
548 __FUNCTION__, bufferFormat);
549 } else if (imgReaderFmt == HAL_PIXEL_FORMAT_BLOB &&
550 bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888) {
551 // Using HAL_PIXEL_FORMAT_RGBA_8888 Gralloc buffers containing JPEGs to get around
552 // SW write limitations for (b/17379185).
553 ALOGV("%s: Receiving JPEG in HAL_PIXEL_FORMAT_RGBA_8888 buffer.", __FUNCTION__);
554 } else {
555 // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
556 // used anywhere yet.
557 bufferConsumer->releaseBuffer(*buffer);
558 ctx->returnBufferItem(buffer);
559
560 // Throw exception
561 ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
562 bufferFormat, ctx->getBufferFormat());
563 String8 msg;
564 msg.appendFormat("The producer output buffer format 0x%x doesn't "
565 "match the ImageReader's configured buffer format 0x%x.",
566 bufferFormat, ctx->getBufferFormat());
567 jniThrowException(env, "java/lang/UnsupportedOperationException",
568 msg.string());
569 return -1;
570 }
571 }
572
573 }
574
575 // Set SurfaceImage instance member variables
576 Image_setBufferItem(env, image, buffer);
577 env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
578 static_cast<jlong>(buffer->mTimestamp));
579
580 return ACQUIRE_SUCCESS;
Zhijun Hece9d6f92015-03-29 16:33:59 -0700581}
582
583static jint ImageReader_detachImage(JNIEnv* env, jobject thiz, jobject image) {
Zhijun Hef6a09e52015-02-24 18:12:23 -0800584 ALOGV("%s:", __FUNCTION__);
585 JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
586 if (ctx == NULL) {
587 jniThrowException(env, "java/lang/IllegalStateException", "ImageReader was already closed");
Zhijun Hece9d6f92015-03-29 16:33:59 -0700588 return -1;
Zhijun Hef6a09e52015-02-24 18:12:23 -0800589 }
590
Zhijun He0ab41622016-02-25 16:00:38 -0800591 BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer();
592 BufferItem* buffer = Image_getBufferItem(env, image);
593 if (!buffer) {
Zhijun Hece9d6f92015-03-29 16:33:59 -0700594 ALOGE(
Zhijun He0ab41622016-02-25 16:00:38 -0800595 "Image already released and can not be detached from ImageReader!!!");
Zhijun Hece9d6f92015-03-29 16:33:59 -0700596 jniThrowException(env, "java/lang/IllegalStateException",
Zhijun He0ab41622016-02-25 16:00:38 -0800597 "Image detach from ImageReader failed: buffer was already released");
Zhijun Hece9d6f92015-03-29 16:33:59 -0700598 return -1;
599 }
600
Zhijun He0ab41622016-02-25 16:00:38 -0800601 status_t res = OK;
602 Image_unlockIfLocked(env, image);
603 res = bufferConsumer->detachBuffer(buffer->mSlot);
Zhijun Hece9d6f92015-03-29 16:33:59 -0700604 if (res != OK) {
Zhijun He0ab41622016-02-25 16:00:38 -0800605 ALOGE("Image detach failed: %s (%d)!!!", strerror(-res), res);
Zhijun Hece9d6f92015-03-29 16:33:59 -0700606 jniThrowRuntimeException(env,
Zhijun He0ab41622016-02-25 16:00:38 -0800607 "nativeDetachImage failed for image!!!");
Zhijun Hece9d6f92015-03-29 16:33:59 -0700608 return res;
609 }
610 return OK;
Zhijun Hef6a09e52015-02-24 18:12:23 -0800611}
612
Eino-Ville Talvala2e2aaf62016-07-21 17:04:19 -0700613static void ImageReader_discardFreeBuffers(JNIEnv* env, jobject thiz) {
614 ALOGV("%s:", __FUNCTION__);
615 JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
616 if (ctx == NULL) {
617 jniThrowException(env, "java/lang/IllegalStateException", "ImageReader was already closed");
618 return;
619 }
620
621 BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer();
622 status_t res = bufferConsumer->discardFreeBuffers();
623 if (res != OK) {
624 ALOGE("Buffer discard failed: %s (%d)", strerror(-res), res);
625 jniThrowRuntimeException(env,
626 "nativeDicardFreebuffers failed");
627 }
628}
629
Zhijun He212e78d2013-06-07 11:36:23 -0700630static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
631{
632 ALOGV("%s: ", __FUNCTION__);
633
Dan Stoza5b3c7c12014-03-12 16:44:45 -0700634 IGraphicBufferProducer* gbp = ImageReader_getProducer(env, thiz);
635 if (gbp == NULL) {
Zhijun He0ab41622016-02-25 16:00:38 -0800636 jniThrowRuntimeException(env, "Buffer consumer is uninitialized");
Zhijun He212e78d2013-06-07 11:36:23 -0700637 return NULL;
638 }
639
640 // Wrap the IGBP in a Java-language Surface.
Dan Stoza5b3c7c12014-03-12 16:44:45 -0700641 return android_view_Surface_createFromIGraphicBufferProducer(env, gbp);
Zhijun He212e78d2013-06-07 11:36:23 -0700642}
643
Zhijun He0ab41622016-02-25 16:00:38 -0800644static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image) {
645 ALOGV("%s", __FUNCTION__);
646 BufferItem* buffer = Image_getBufferItem(env, thiz);
647 if (buffer == NULL) {
648 jniThrowException(env, "java/lang/IllegalStateException",
649 "Image is not initialized");
650 return;
651 }
652
653 status_t res = lockImageFromBuffer(buffer,
654 GRALLOC_USAGE_SW_READ_OFTEN, buffer->mFence->dup(), image);
655 if (res != OK) {
656 jniThrowExceptionFmt(env, "java/lang/RuntimeException",
657 "lock buffer failed for format 0x%x",
658 buffer->mGraphicBuffer->getPixelFormat());
659 return;
660 }
661
662 // Carry over some fields from BufferItem.
663 image->crop = buffer->mCrop;
664 image->transform = buffer->mTransform;
665 image->scalingMode = buffer->mScalingMode;
666 image->timestamp = buffer->mTimestamp;
667 image->dataSpace = buffer->mDataSpace;
668 image->frameNumber = buffer->mFrameNumber;
669
670 ALOGV("%s: Successfully locked the image", __FUNCTION__);
671 // crop, transform, scalingMode, timestamp, and frameNumber should be set by producer,
672 // and we don't set them here.
673}
674
675static void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
676 int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
677 ALOGV("%s", __FUNCTION__);
678
679 status_t res = getLockedImageInfo(buffer, idx, writerFormat, base, size,
680 pixelStride, rowStride);
681 if (res != OK) {
682 jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
683 "Pixel format: 0x%x is unsupported", buffer->flexFormat);
684 }
685}
686
687static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
688 int numPlanes, int readerFormat)
Zhijun He212e78d2013-06-07 11:36:23 -0700689{
Zhijun He0ab41622016-02-25 16:00:38 -0800690 ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes);
691 int rowStride = 0;
692 int pixelStride = 0;
693 uint8_t *pData = NULL;
694 uint32_t dataSize = 0;
695 jobject byteBuffer = NULL;
696
Eino-Ville Talvala805f3c92015-02-26 10:57:55 -0800697 PublicFormat publicReaderFormat = static_cast<PublicFormat>(readerFormat);
Zhijun Hece9d6f92015-03-29 16:33:59 -0700698 int halReaderFormat = android_view_Surface_mapPublicFormatToHalFormat(
699 publicReaderFormat);
Eino-Ville Talvala805f3c92015-02-26 10:57:55 -0800700
Zhijun He0ab41622016-02-25 16:00:38 -0800701 if (isFormatOpaque(halReaderFormat) && numPlanes > 0) {
702 String8 msg;
703 msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
704 " must be 0", halReaderFormat, numPlanes);
705 jniThrowException(env, "java/lang/IllegalArgumentException", msg.string());
706 return NULL;
707 }
708
709 jobjectArray surfacePlanes = env->NewObjectArray(numPlanes, gSurfacePlaneClassInfo.clazz,
710 /*initial_element*/NULL);
711 if (surfacePlanes == NULL) {
712 jniThrowRuntimeException(env, "Failed to create SurfacePlane arrays,"
713 " probably out of memory");
714 return NULL;
715 }
Zhijun Hece9d6f92015-03-29 16:33:59 -0700716 if (isFormatOpaque(halReaderFormat)) {
Zhijun He0ab41622016-02-25 16:00:38 -0800717 // Return 0 element surface array.
718 return surfacePlanes;
Zhijun Hece9d6f92015-03-29 16:33:59 -0700719 }
Zhijun He212e78d2013-06-07 11:36:23 -0700720
Zhijun He0ab41622016-02-25 16:00:38 -0800721 LockedImage lockedImg = LockedImage();
722 Image_getLockedImage(env, thiz, &lockedImg);
723 // Create all SurfacePlanes
724 for (int i = 0; i < numPlanes; i++) {
725 Image_getLockedImageInfo(env, &lockedImg, i, halReaderFormat,
726 &pData, &dataSize, &pixelStride, &rowStride);
727 byteBuffer = env->NewDirectByteBuffer(pData, dataSize);
728 if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
729 jniThrowException(env, "java/lang/IllegalStateException",
730 "Failed to allocate ByteBuffer");
731 return NULL;
732 }
Zhijun He212e78d2013-06-07 11:36:23 -0700733
Zhijun He0ab41622016-02-25 16:00:38 -0800734 // Finally, create this SurfacePlane.
735 jobject surfacePlane = env->NewObject(gSurfacePlaneClassInfo.clazz,
736 gSurfacePlaneClassInfo.ctor, thiz, rowStride, pixelStride, byteBuffer);
737 env->SetObjectArrayElement(surfacePlanes, i, surfacePlane);
Zhijun He212e78d2013-06-07 11:36:23 -0700738 }
Ruben Brunk0fd198a2014-09-23 23:35:43 -0700739
Zhijun He0ab41622016-02-25 16:00:38 -0800740 return surfacePlanes;
Zhijun He212e78d2013-06-07 11:36:23 -0700741}
742
Zhijun He0ab41622016-02-25 16:00:38 -0800743static jint Image_getWidth(JNIEnv* env, jobject thiz)
Zhijun He212e78d2013-06-07 11:36:23 -0700744{
Zhijun He0ab41622016-02-25 16:00:38 -0800745 BufferItem* buffer = Image_getBufferItem(env, thiz);
746 return getBufferWidth(buffer);
Zhijun He212e78d2013-06-07 11:36:23 -0700747}
748
Zhijun He0ab41622016-02-25 16:00:38 -0800749static jint Image_getHeight(JNIEnv* env, jobject thiz)
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800750{
Zhijun He0ab41622016-02-25 16:00:38 -0800751 BufferItem* buffer = Image_getBufferItem(env, thiz);
752 return getBufferHeight(buffer);
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800753}
754
Zhijun He7c3997d2015-05-06 10:08:37 -0700755static jint Image_getFormat(JNIEnv* env, jobject thiz, jint readerFormat)
756{
757 if (isFormatOpaque(readerFormat)) {
758 // Assuming opaque reader produce opaque images.
759 return static_cast<jint>(PublicFormat::PRIVATE);
760 } else {
Zhijun He0ab41622016-02-25 16:00:38 -0800761 BufferItem* buffer = Image_getBufferItem(env, thiz);
Chien-Yu Chen0782aab2015-06-11 16:48:13 -0700762 int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
763 static_cast<PublicFormat>(readerFormat));
Zhijun He0ab41622016-02-25 16:00:38 -0800764 int32_t fmt = applyFormatOverrides(
765 buffer->mGraphicBuffer->getPixelFormat(), readerHalFormat);
Zhijun He9cc3f882016-02-17 17:24:04 -0800766 // Override the image format to HAL_PIXEL_FORMAT_YCbCr_420_888 if the actual format is
767 // NV21 or YV12. This could only happen when the Gralloc HAL version is v0.1 thus doesn't
768 // support lockycbcr(), the CpuConsumer need to use the lock() method in the
769 // lockNextBuffer() call. For Gralloc HAL v0.2 or newer, this format should already be
770 // overridden to HAL_PIXEL_FORMAT_YCbCr_420_888 for the flexible YUV compatible formats.
Zhijun He0ab41622016-02-25 16:00:38 -0800771 if (isPossiblyYUV(fmt)) {
Zhijun He9cc3f882016-02-17 17:24:04 -0800772 fmt = HAL_PIXEL_FORMAT_YCbCr_420_888;
773 }
Zhijun He7c3997d2015-05-06 10:08:37 -0700774 PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
Zhijun He0ab41622016-02-25 16:00:38 -0800775 fmt, buffer->mDataSpace);
Zhijun He7c3997d2015-05-06 10:08:37 -0700776 return static_cast<jint>(publicFmt);
777 }
778}
779
Zhijun He212e78d2013-06-07 11:36:23 -0700780} // extern "C"
781
782// ----------------------------------------------------------------------------
783
Daniel Micay76f6a862015-09-19 17:31:01 -0400784static const JNINativeMethod gImageReaderMethods[] = {
Zhijun He212e78d2013-06-07 11:36:23 -0700785 {"nativeClassInit", "()V", (void*)ImageReader_classInit },
786 {"nativeInit", "(Ljava/lang/Object;IIII)V", (void*)ImageReader_init },
787 {"nativeClose", "()V", (void*)ImageReader_close },
788 {"nativeReleaseImage", "(Landroid/media/Image;)V", (void*)ImageReader_imageRelease },
Ruben Brunkf4a637d2014-11-20 18:01:36 -0800789 {"nativeImageSetup", "(Landroid/media/Image;)I", (void*)ImageReader_imageSetup },
Zhijun He212e78d2013-06-07 11:36:23 -0700790 {"nativeGetSurface", "()Landroid/view/Surface;", (void*)ImageReader_getSurface },
Zhijun Hece9d6f92015-03-29 16:33:59 -0700791 {"nativeDetachImage", "(Landroid/media/Image;)I", (void*)ImageReader_detachImage },
Eino-Ville Talvala2e2aaf62016-07-21 17:04:19 -0700792 {"nativeDiscardFreeBuffers", "()V", (void*)ImageReader_discardFreeBuffers }
Zhijun He212e78d2013-06-07 11:36:23 -0700793};
794
Daniel Micay76f6a862015-09-19 17:31:01 -0400795static const JNINativeMethod gImageMethods[] = {
Zhijun He0ab41622016-02-25 16:00:38 -0800796 {"nativeCreatePlanes", "(II)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
797 (void*)Image_createSurfacePlanes },
798 {"nativeGetWidth", "()I", (void*)Image_getWidth },
799 {"nativeGetHeight", "()I", (void*)Image_getHeight },
Zhijun He7c3997d2015-05-06 10:08:37 -0700800 {"nativeGetFormat", "(I)I", (void*)Image_getFormat },
Zhijun He212e78d2013-06-07 11:36:23 -0700801};
802
803int register_android_media_ImageReader(JNIEnv *env) {
804
805 int ret1 = AndroidRuntime::registerNativeMethods(env,
806 "android/media/ImageReader", gImageReaderMethods, NELEM(gImageReaderMethods));
807
808 int ret2 = AndroidRuntime::registerNativeMethods(env,
809 "android/media/ImageReader$SurfaceImage", gImageMethods, NELEM(gImageMethods));
810
811 return (ret1 || ret2);
812}