diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java index 8ddc094722fc5..f3356c9fba479 100644 --- a/media/java/android/media/ImageReader.java +++ b/media/java/android/media/ImageReader.java @@ -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 { } /** - *

Get the next Image from the ImageReader's queue. Returns {@code null} - * if no new image is available.

+ *

+ * Get the next Image from the ImageReader's queue. Returns {@code null} if + * no new image is available. + *

+ *

+ * 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}. + *

* * @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 weakSelf = (WeakReference)selfRef; + final ImageReader ir = weakSelf.get(); if (ir == null) { return; } diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index cd589ded22c2b..7d914d271c5f0 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -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 bq = new BufferQueue(); - sp consumer = new CpuConsumer(bq, true, maxImages); + sp 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.