diff options
author | Zhijun He <zhijunhe@google.com> | 2015-03-29 16:33:59 -0700 |
---|---|---|
committer | Zhijun He <zhijunhe@google.com> | 2015-04-08 10:39:29 -0700 |
commit | ce9d6f9c75e2254f3704996e232e57e0c8f686d8 (patch) | |
tree | 01ccb7d2c423969e58011a73f581f6f5da0ebada /media/jni/android_media_ImageWriter.cpp | |
parent | 30b89849032eb57d1da93de40a6a9bd2a5f55a2e (diff) | |
download | frameworks_base-ce9d6f9c75e2254f3704996e232e57e0c8f686d8.zip frameworks_base-ce9d6f9c75e2254f3704996e232e57e0c8f686d8.tar.gz frameworks_base-ce9d6f9c75e2254f3704996e232e57e0c8f686d8.tar.bz2 |
ImageReader/Writer: implement opaque format operations
Implement attach/detach for image reader and writer.
Bug: 19872821
Change-Id: Ib45a054c6be0b56b370fa8d709b47b0298ba5ea7
Diffstat (limited to 'media/jni/android_media_ImageWriter.cpp')
-rw-r--r-- | media/jni/android_media_ImageWriter.cpp | 125 |
1 files changed, 97 insertions, 28 deletions
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp index d10df3e9..d2c614e 100644 --- a/media/jni/android_media_ImageWriter.cpp +++ b/media/jni/android_media_ImageWriter.cpp @@ -74,8 +74,8 @@ public: // has returned a buffer and it is ready for ImageWriter to dequeue. virtual void onBufferReleased(); - void setProducer(const sp<ANativeWindow>& producer) { mProducer = producer; } - ANativeWindow* getProducer() { return mProducer.get(); } + void setProducer(const sp<Surface>& producer) { mProducer = producer; } + Surface* getProducer() { return mProducer.get(); } void setBufferFormat(int format) { mFormat = format; } int getBufferFormat() { return mFormat; } @@ -90,7 +90,7 @@ private: static JNIEnv* getJNIEnv(bool* needsDetach); static void detachJNI(); - sp<ANativeWindow> mProducer; + sp<Surface> mProducer; jobject mWeakThiz; jclass mClazz; int mFormat; @@ -155,10 +155,21 @@ void JNIImageWriterContext::onBufferReleased() { bool needsDetach = false; JNIEnv* env = getJNIEnv(&needsDetach); if (env != NULL) { + // Detach the buffer every time when a buffer consumption is done, + // need let this callback give a BufferItem, then only detach if it was attached to this + // Writer. Do the detach unconditionally for opaque format now. see b/19977520 + if (mFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { + sp<Fence> fence; + ANativeWindowBuffer* buffer; + ALOGV("%s: One buffer is detached", __FUNCTION__); + mProducer->detachNextBuffer(&buffer, &fence); + } + env->CallStaticVoidMethod(mClazz, gImageWriterClassInfo.postEventFromNative, mWeakThiz); } else { ALOGW("onBufferReleased event will not posted"); } + if (needsDetach) { detachJNI(); } @@ -170,13 +181,13 @@ extern "C" { // -------------------------------Private method declarations-------------- -static bool isWritable(int format); static bool isPossiblyYUV(PixelFormat format); static void Image_setNativeContext(JNIEnv* env, jobject thiz, sp<GraphicBuffer> buffer, int fenceFd); static void Image_getNativeContext(JNIEnv* env, jobject thiz, GraphicBuffer** buffer, int* fenceFd); static void Image_unlockIfLocked(JNIEnv* env, jobject thiz); +static bool isFormatOpaque(int format); // --------------------------ImageWriter methods--------------------------------------- @@ -278,7 +289,7 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje env->SetIntField(thiz, gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(format)); - if (isWritable(format)) { + if (!isFormatOpaque(format)) { res = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN); if (res != OK) { ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)", @@ -461,31 +472,87 @@ static void ImageWriter_queueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, j return; } + // Clear the image native context: end of this image's lifecycle in public API. Image_setNativeContext(env, image, NULL, -1); } -static void ImageWriter_attachImage(JNIEnv* env, jobject thiz, jlong nativeCtx, jobject image) { +static jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, + jlong nativeBuffer, jint imageFormat, jlong timestampNs, jint left, jint top, + jint right, jint bottom) { ALOGV("%s", __FUNCTION__); JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx); if (ctx == NULL || thiz == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "ImageWriterContext is not initialized"); - return; + return -1; } - sp<ANativeWindow> anw = ctx->getProducer(); + sp<Surface> surface = ctx->getProducer(); + status_t res = OK; + if (!isFormatOpaque(imageFormat)) { + // TODO: need implement, see b/19962027 + jniThrowRuntimeException(env, + "nativeAttachImage for non-opaque image is not implement yet!!!"); + return -1; + } - GraphicBuffer *buffer = NULL; - int fenceFd = -1; - Image_getNativeContext(env, image, &buffer, &fenceFd); - if (buffer == NULL) { + if (!isFormatOpaque(ctx->getBufferFormat())) { jniThrowException(env, "java/lang/IllegalStateException", - "Image is not initialized"); - return; + "Trying to attach an opaque image into a non-opaque ImageWriter"); + return -1; + } + + // Image is guaranteed to be from ImageReader at this point, so it is safe to + // cast to BufferItem pointer. + BufferItem* opaqueBuffer = reinterpret_cast<BufferItem*>(nativeBuffer); + if (opaqueBuffer == NULL) { + jniThrowException(env, "java/lang/IllegalStateException", + "Image is not initialized or already closed"); + return -1; + } + + // Step 1. Attach Image + res = surface->attachBuffer(opaqueBuffer->mGraphicBuffer.get()); + if (res != OK) { + // TODO: handle different error case separately. + ALOGE("Attach image failed: %s (%d)", strerror(-res), res); + jniThrowRuntimeException(env, "nativeAttachImage failed!!!"); + return res; } + sp < ANativeWindow > anw = surface; - // TODO: need implement - jniThrowRuntimeException(env, "nativeAttachImage is not implement yet!!!"); + // Step 2. Set timestamp and crop. Note that we do not need unlock the image because + // it was not locked. + ALOGV("timestamp to be queued: %" PRId64, timestampNs); + res = native_window_set_buffers_timestamp(anw.get(), timestampNs); + if (res != OK) { + jniThrowRuntimeException(env, "Set timestamp failed"); + return res; + } + + android_native_rect_t cropRect; + cropRect.left = left; + cropRect.top = top; + cropRect.right = right; + cropRect.bottom = bottom; + res = native_window_set_crop(anw.get(), &cropRect); + if (res != OK) { + jniThrowRuntimeException(env, "Set crop rect failed"); + return res; + } + + // Step 3. Queue Image. + res = anw->queueBuffer(anw.get(), opaqueBuffer->mGraphicBuffer.get(), /*fenceFd*/ + -1); + if (res != OK) { + jniThrowRuntimeException(env, "Queue input buffer failed"); + return res; + } + + // Do not set the image native context. Since it would overwrite the existing native context + // of the image that is from ImageReader, the subsequent image close will run into issues. + + return res; } // --------------------------Image methods--------------------------------------- @@ -534,10 +601,13 @@ static void Image_unlockIfLocked(JNIEnv* env, jobject thiz) { // Is locked? bool isLocked = false; - jobject planes = env->GetObjectField(thiz, gSurfaceImageClassInfo.mPlanes); + jobject planes = NULL; + if (!isFormatOpaque(buffer->getPixelFormat())) { + planes = env->GetObjectField(thiz, gSurfaceImageClassInfo.mPlanes); + } isLocked = (planes != NULL); if (isLocked) { - // no need to use fence here, as we it will be consumed by either concel or queue buffer. + // no need to use fence here, as we it will be consumed by either cancel or queue buffer. status_t res = buffer->unlock(); if (res != OK) { jniThrowRuntimeException(env, "unlock buffer failed"); @@ -900,7 +970,7 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz, jobject byteBuffer; int format = Image_getFormat(env, thiz); - if (!isWritable(format) && numPlanes > 0) { + if (isFormatOpaque(format) && numPlanes > 0) { String8 msg; msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)" " must be 0", format, numPlanes); @@ -915,6 +985,9 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz, " probably out of memory"); return NULL; } + if (isFormatOpaque(format)) { + return surfacePlanes; + } // Buildup buffer info: rowStride, pixelStride and byteBuffers. LockedImage lockedImg = LockedImage(); @@ -943,13 +1016,9 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz, // -------------------------------Private convenience methods-------------------- -// Check if buffer with this format is writable. Generally speaking, the opaque formats -// like IMPLEMENTATION_DEFINED is not writable, as the actual buffer formats and layouts -// are unknown to frameworks. -static bool isWritable(int format) { - // Assume all other formats are writable. - return !(format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED || - format == HAL_PIXEL_FORMAT_RAW_OPAQUE); +static bool isFormatOpaque(int format) { + // Only treat IMPLEMENTATION_DEFINED as an opaque format for now. + return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; } static bool isPossiblyYUV(PixelFormat format) { @@ -986,8 +1055,8 @@ static JNINativeMethod gImageWriterMethods[] = { {"nativeClassInit", "()V", (void*)ImageWriter_classInit }, {"nativeInit", "(Ljava/lang/Object;Landroid/view/Surface;I)J", (void*)ImageWriter_init }, - {"nativeClose", "(J)V", (void*)ImageWriter_close }, - {"nativeAttachImage", "(JLandroid/media/Image;)V", (void*)ImageWriter_attachImage }, + {"nativeClose", "(J)V", (void*)ImageWriter_close }, + {"nativeAttachAndQueueImage", "(JJIJIIII)I", (void*)ImageWriter_attachAndQueueImage }, {"nativeDequeueInputImage", "(JLandroid/media/Image;)V", (void*)ImageWriter_dequeueImage }, {"nativeQueueInputImage", "(JLandroid/media/Image;JIIII)V", (void*)ImageWriter_queueImage }, {"cancelImage", "(JLandroid/media/Image;)V", (void*)ImageWriter_cancelImage }, |