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;
}
/**
- * <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();
* @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;
* 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;
}
using namespace android;
+static const char* const OutOfResourcesException =
+ "android/view/Surface$OutOfResourcesException";
+
enum {
IMAGE_READER_MAX_NUM_PLANES = 3,
};
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");
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;
}
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.