summaryrefslogtreecommitdiff
path: root/media/jni/android_media_ImageWriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/jni/android_media_ImageWriter.cpp')
-rw-r--r--media/jni/android_media_ImageWriter.cpp62
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",