OSDN Git Service

media: Fix ImageReader only using maxImages=1 no matter what
authorIgor Murashkin <iam@google.com>
Thu, 15 Aug 2013 02:05:17 +0000 (19:05 -0700)
committerIgor Murashkin <iam@google.com>
Fri, 16 Aug 2013 19:20:09 +0000 (12:20 -0700)
- No longer return null when some bad error happens
- Throws OutOfResourcesException when images need to be closed
- Throws IllegalStateException when an unknown internal error happens

Bug: 10333400
Change-Id: Ia53a5dd33f9ce53abd036e080e6fcc4ded9b251d

media/java/android/media/ImageReader.java
media/jni/android_media_ImageReader.cpp

index 8ddc094..f3356c9 100644 (file)
@@ -20,7 +20,6 @@ import android.graphics.ImageFormat;
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.Message;
 import android.view.Surface;
 
 import java.lang.ref.WeakReference;
@@ -130,11 +129,26 @@ public final class ImageReader implements AutoCloseable {
     }
 
     /**
-     * <p>Get the next Image from the ImageReader's queue. Returns {@code null}
-     * if no new image is available.</p>
+     * <p>
+     * Get the next Image from the ImageReader's queue. Returns {@code null} if
+     * no new image is available.
+     * </p>
+     * <p>
+     * This operation will fail by throwing an
+     * {@link Surface.OutOfResourcesException OutOfResourcesException} if too
+     * many images have been acquired with {@link #getNextImage}. In particular
+     * a sequence of {@link #getNextImage} calls greater than {@link #getMaxImages}
+     * without calling {@link Image#close} or {@link #releaseImage} in-between
+     * will exhaust the underlying queue. At such a time,
+     * {@link Surface.OutOfResourcesException OutOfResourcesException} will be
+     * thrown until more images are released with {@link Image#close} or
+     * {@link #releaseImage}.
+     * </p>
      *
      * @return a new frame of image data, or {@code null} if no image data is
-     * available.
+     *         available.
+     * @throws Surface.OutOfResourcesException if too many images are currently
+     *         acquired
      */
     public Image getNextImage() {
         SurfaceImage si = new SurfaceImage();
@@ -172,6 +186,8 @@ public final class ImageReader implements AutoCloseable {
      * @param listener the listener that will be run
      * @param handler The handler on which the listener should be invoked, or null
      * if the listener should be invoked on the calling thread's looper.
+     *
+     * @throws IllegalArgumentException if no handler specified and the calling thread has no looper
      */
    public void setImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
         mImageListener = listener;
@@ -260,8 +276,9 @@ public final class ImageReader implements AutoCloseable {
      * Called from Native code when an Event happens.
      */
     private static void postEventFromNative(Object selfRef) {
-        WeakReference weakSelf = (WeakReference)selfRef;
-        final ImageReader ir = (ImageReader)weakSelf.get();
+        @SuppressWarnings("unchecked")
+        WeakReference<ImageReader> weakSelf = (WeakReference<ImageReader>)selfRef;
+        final ImageReader ir = weakSelf.get();
         if (ir == null) {
             return;
         }
index cd589de..7d914d2 100644 (file)
@@ -44,6 +44,9 @@
 
 using namespace android;
 
+static const char* const OutOfResourcesException =
+    "android/view/Surface$OutOfResourcesException";
+
 enum {
     IMAGE_READER_MAX_NUM_PLANES = 3,
 };
@@ -609,7 +612,8 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz,
     nativeFormat = Image_getPixelFormat(env, format);
 
     sp<BufferQueue> bq = new BufferQueue();
-    sp<CpuConsumer> consumer = new CpuConsumer(bq, true, maxImages);
+    sp<CpuConsumer> consumer = new CpuConsumer(bq, maxImages,
+                                               /*controlledByApp*/true);
     // TODO: throw dvm exOutOfMemoryError?
     if (consumer == NULL) {
         jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer");
@@ -702,7 +706,17 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz,
     status_t res = consumer->lockNextBuffer(buffer);
     if (res != NO_ERROR) {
         if (res != BAD_VALUE /*no buffers*/) {
-            ALOGE("%s Fail to lockNextBuffer with error: %d ", __FUNCTION__, res);
+            if (res == NOT_ENOUGH_DATA) {
+                jniThrowException(env, OutOfResourcesException,
+                          "Too many outstanding images, close existing images"
+                          " to be able to acquire more.");
+            } else {
+                ALOGE("%s Fail to lockNextBuffer with error: %d ",
+                      __FUNCTION__, res);
+                jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                          "Unknown error (%d) when we tried to lock buffer.",
+                          res);
+            }
         }
         return false;
     }
@@ -714,6 +728,7 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz,
         ALOGE("crop left: %d, top = %d", lt.x, lt.y);
         jniThrowException(env, "java/lang/UnsupportedOperationException",
                           "crop left top corner need to at origin");
+        return false;
     }
 
     // Check if the producer buffer configurations match what ImageReader configured.