diff options
Diffstat (limited to 'media/jni/android_media_ImageWriter.cpp')
-rw-r--r-- | media/jni/android_media_ImageWriter.cpp | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp index 7a0eeee17b0d..936edb3fb005 100644 --- a/media/jni/android_media_ImageWriter.cpp +++ b/media/jni/android_media_ImageWriter.cpp @@ -86,6 +86,14 @@ public: void setBufferHeight(int height) { mHeight = height; } int getBufferHeight() { return mHeight; } + void queueAttachedFlag(bool isAttached) { + Mutex::Autolock l(mAttachedFlagQueueLock); + mAttachedFlagQueue.push_back(isAttached); + } + void dequeueAttachedFlag() { + Mutex::Autolock l(mAttachedFlagQueueLock); + mAttachedFlagQueue.pop_back(); + } private: static JNIEnv* getJNIEnv(bool* needsDetach); static void detachJNI(); @@ -136,6 +144,11 @@ private: }; static BufferDetacher sBufferDetacher; + + // Buffer queue guarantees both producer and consumer side buffer flows are + // in order. See b/19977520. As a result, we can use a queue here. + Mutex mAttachedFlagQueueLock; + std::deque<bool> mAttachedFlagQueue; }; JNIImageWriterContext::BufferDetacher JNIImageWriterContext::sBufferDetacher; @@ -265,11 +278,23 @@ void JNIImageWriterContext::onBufferReleased() { ALOGV("%s: buffer released", __FUNCTION__); bool needsDetach = false; JNIEnv* env = getJNIEnv(&needsDetach); + + bool bufferIsAttached = false; + { + Mutex::Autolock l(mAttachedFlagQueueLock); + if (!mAttachedFlagQueue.empty()) { + bufferIsAttached = mAttachedFlagQueue.front(); + mAttachedFlagQueue.pop_front(); + } else { + ALOGW("onBufferReleased called with no attached flag queued"); + } + } + 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) { + // Writer. see b/19977520 + if (mFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED || bufferIsAttached) { sBufferDetacher.detach(mProducer); } @@ -622,10 +647,16 @@ static void ImageWriter_queueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, j return; } - // Finally, queue input buffer + // Finally, queue input buffer. + // + // Because onBufferReleased may be called before queueBuffer() returns, + // queue the "attached" flag before calling queueBuffer. In case + // queueBuffer() fails, remove it from the queue. + ctx->queueAttachedFlag(false); res = anw->queueBuffer(anw.get(), buffer, fenceFd); if (res != OK) { ALOGE("%s: Queue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res); + ctx->dequeueAttachedFlag(); switch (res) { case NO_INIT: jniThrowException(env, "java/lang/IllegalStateException", @@ -720,10 +751,16 @@ static jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nat } // Step 3. Queue Image. + // + // Because onBufferReleased may be called before queueBuffer() returns, + // queue the "attached" flag before calling queueBuffer. In case + // queueBuffer() fails, remove it from the queue. + ctx->queueAttachedFlag(true); res = anw->queueBuffer(anw.get(), buffer->mGraphicBuffer.get(), /*fenceFd*/ -1); if (res != OK) { ALOGE("%s: Queue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res); + ctx->dequeueAttachedFlag(); switch (res) { case NO_INIT: jniThrowException(env, "java/lang/IllegalStateException", @@ -798,6 +835,7 @@ static void Image_unlockIfLocked(JNIEnv* env, jobject thiz) { status_t res = buffer->unlock(); if (res != OK) { jniThrowRuntimeException(env, "unlock buffer failed"); + return; } ALOGV("Successfully unlocked the image"); } @@ -840,8 +878,8 @@ static jint Image_getFormat(JNIEnv* env, jobject thiz) { } // ImageWriter doesn't support data space yet, assuming it is unknown. - PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat( - buffer->getPixelFormat(), HAL_DATASPACE_UNKNOWN); + PublicFormat publicFmt = mapHalFormatDataspaceToPublicFormat(buffer->getPixelFormat(), + HAL_DATASPACE_UNKNOWN); return static_cast<jint>(publicFmt); } @@ -893,7 +931,7 @@ static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image) // and we don't set them here. } -static void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx, +static bool Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx, int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) { ALOGV("%s", __FUNCTION__); @@ -901,8 +939,10 @@ static void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx, pixelStride, rowStride); if (res != OK) { jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException", - "Pixel format: 0x%x is unsupported", buffer->flexFormat); + "Pixel format: 0x%x is unsupported", writerFormat); + return false; } + return true; } static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz, @@ -939,10 +979,12 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz, // Create all SurfacePlanes PublicFormat publicWriterFormat = static_cast<PublicFormat>(writerFormat); - writerFormat = android_view_Surface_mapPublicFormatToHalFormat(publicWriterFormat); + writerFormat = mapPublicFormatToHalFormat(publicWriterFormat); for (int i = 0; i < numPlanes; i++) { - Image_getLockedImageInfo(env, &lockedImg, i, writerFormat, - &pData, &dataSize, &pixelStride, &rowStride); + if (!Image_getLockedImageInfo(env, &lockedImg, i, writerFormat, + &pData, &dataSize, &pixelStride, &rowStride)) { + return NULL; + } byteBuffer = env->NewDirectByteBuffer(pData, dataSize); if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) { jniThrowException(env, "java/lang/IllegalStateException", |