1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
19import android.graphics.ImageFormat;
20import android.graphics.PixelFormat;
21import android.os.Handler;
22import android.os.Looper;
23import android.os.Message;
24import android.view.Surface;
25
26import java.lang.ref.WeakReference;
27import java.nio.ByteBuffer;
28import java.nio.ByteOrder;
29
30/**
31 * <p>The ImageReader class allows direct application access to image data
32 * rendered into a {@link android.view.Surface}</p>
33 *
34 * <p>Several Android media API classes accept Surface objects as targets to
35 * render to, including {@link MediaPlayer}, {@link MediaCodec}, and
36 * {@link android.renderscript.Allocation RenderScript Allocations}. The image
37 * sizes and formats that can be used with each source vary, and should be
38 * checked in the documentation for the specific API.</p>
39 *
40 * <p>The image data is encapsulated in {@link Image} objects, and multiple such
41 * objects can be accessed at the same time, up to the number specified by the
42 * {@code maxImages} constructor parameter. New images sent to an ImageReader
43 * through its {@link Surface} are queued until accessed through the {@link #acquireLatestImage}
44 * or {@link #acquireNextImage} call. Due to memory limits, an image source will
45 * eventually stall or drop Images in trying to render to the Surface if the
46 * ImageReader does not obtain and release Images at a rate equal to the
47 * production rate.</p>
48 */
49public class ImageReader implements AutoCloseable {
50
51    /**
52     * Returned by nativeImageSetup when acquiring the image was successful.
53     */
54    private static final int ACQUIRE_SUCCESS = 0;
55    /**
56     * Returned by nativeImageSetup when we couldn't acquire the buffer,
57     * because there were no buffers available to acquire.
58     */
59    private static final int ACQUIRE_NO_BUFS = 1;
60    /**
61     * Returned by nativeImageSetup when we couldn't acquire the buffer
62     * because the consumer has already acquired {@maxImages} and cannot
63     * acquire more than that.
64     */
65    private static final int ACQUIRE_MAX_IMAGES = 2;
66
67    /**
68     * <p>Create a new reader for images of the desired size and format.</p>
69     *
70     * <p>The {@code maxImages} parameter determines the maximum number of {@link Image}
71     * objects that can be be acquired from the {@code ImageReader}
72     * simultaneously. Requesting more buffers will use up more memory, so it is
73     * important to use only the minimum number necessary for the use case.</p>
74     *
75     * <p>The valid sizes and formats depend on the source of the image
76     * data.</p>
77     *
78     * @param width
79     *            The width in pixels of the Images that this reader will produce.
80     * @param height
81     *            The height in pixels of the Images that this reader will produce.
82     * @param format
83     *            The format of the Image that this reader will produce. This
84     *            must be one of the {@link android.graphics.ImageFormat} or
85     *            {@link android.graphics.PixelFormat} constants. Note that
86     *            not all formats is supported, like ImageFormat.NV21.
87     * @param maxImages
88     *            The maximum number of images the user will want to
89     *            access simultaneously. This should be as small as possible to limit
90     *            memory use. Once maxImages Images are obtained by the user, one of them
91     *            has to be released before a new Image will become available for access
92     *            through {@link #acquireLatestImage()} or {@link #acquireNextImage()}.
93     *            Must be greater than 0.
94     *
95     * @see Image
96     */
97    public static ImageReader newInstance(int width, int height, int format, int maxImages) {
98        return new ImageReader(width, height, format, maxImages);
99    }
100
101    /**
102     * @hide
103     */
104    protected ImageReader(int width, int height, int format, int maxImages) {
105        mWidth = width;
106        mHeight = height;
107        mFormat = format;
108        mMaxImages = maxImages;
109
110        if (width < 1 || height < 1) {
111            throw new IllegalArgumentException(
112                "The image dimensions must be positive");
113        }
114        if (mMaxImages < 1) {
115            throw new IllegalArgumentException(
116                "Maximum outstanding image count must be at least 1");
117        }
118
119        if (format == ImageFormat.NV21) {
120            throw new IllegalArgumentException(
121                    "NV21 format is not supported");
122        }
123
124        mNumPlanes = getNumPlanesFromFormat();
125
126        nativeInit(new WeakReference<ImageReader>(this), width, height, format, maxImages);
127
128        mSurface = nativeGetSurface();
129    }
130
131    /**
132     * The width of each {@link Image}, in pixels.
133     *
134     * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
135     * {@link #acquireNextImage}) will have the same dimensions as specified in
136     * {@link #newInstance}.</p>
137     *
138     * @return the width of an Image
139     */
140    public int getWidth() {
141        return mWidth;
142    }
143
144    /**
145     * The height of each {@link Image}, in pixels.
146     *
147     * <p>ImageReader guarantees that all Images acquired from ImageReader (for example, with
148     * {@link #acquireNextImage}) will have the same dimensions as specified in
149     * {@link #newInstance}.</p>
150     *
151     * @return the height of an Image
152     */
153    public int getHeight() {
154        return mHeight;
155    }
156
157    /**
158     * The {@link ImageFormat image format} of each Image.
159     *
160     * <p>ImageReader guarantees that all {@link Image Images} acquired from ImageReader
161     *  (for example, with {@link #acquireNextImage}) will have the same format as specified in
162     * {@link #newInstance}.</p>
163     *
164     * @return the format of an Image
165     *
166     * @see ImageFormat
167     */
168    public int getImageFormat() {
169        return mFormat;
170    }
171
172    /**
173     * Maximum number of images that can be acquired from the ImageReader by any time (for example,
174     * with {@link #acquireNextImage}).
175     *
176     * <p>An image is considered acquired after it's returned by a function from ImageReader, and
177     * until the Image is {@link Image#close closed} to release the image back to the ImageReader.
178     * </p>
179     *
180     * <p>Attempting to acquire more than {@code maxImages} concurrently will result in the
181     * acquire function throwing a {@link IllegalStateException}. Furthermore,
182     * while the max number of images have been acquired by the ImageReader user, the producer
183     * enqueueing additional images may stall until at least one image has been released. </p>
184     *
185     * @return Maximum number of images for this ImageReader.
186     *
187     * @see Image#close
188     */
189    public int getMaxImages() {
190        return mMaxImages;
191    }
192
193    /**
194     * <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
195     * {@code ImageReader}.</p>
196     *
197     * <p>Until valid image data is rendered into this {@link Surface}, the
198     * {@link #acquireNextImage} method will return {@code null}. Only one source
199     * can be producing data into this Surface at the same time, although the
200     * same {@link Surface} can be reused with a different API once the first source is
201     * disconnected from the {@link Surface}.</p>
202     *
203     * @return A {@link Surface} to use for a drawing target for various APIs.
204     */
205    public Surface getSurface() {
206        return mSurface;
207    }
208
209    /**
210     * <p>
211     * Acquire the latest {@link Image} from the ImageReader's queue, dropping older
212     * {@link Image images}. Returns {@code null} if no new image is available.
213     * </p>
214     * <p>
215     * This operation will acquire all the images possible from the ImageReader,
216     * but {@link #close} all images that aren't the latest. This function is
217     * recommended to use over {@link #acquireNextImage} for most use-cases, as it's
218     * more suited for real-time processing.
219     * </p>
220     * <p>
221     * Note that {@link #getMaxImages maxImages} should be at least 2 for
222     * {@link #acquireLatestImage} to be any different than {@link #acquireNextImage} -
223     * discarding all-but-the-newest {@link Image} requires temporarily acquiring two
224     * {@link Image Images} at once. Or more generally, calling {@link #acquireLatestImage}
225     * with less than two images of margin, that is
226     * {@code (maxImages - currentAcquiredImages < 2)} will not discard as expected.
227     * </p>
228     * <p>
229     * This operation will fail by throwing an {@link IllegalStateException} if
230     * {@code maxImages} have been acquired with {@link #acquireLatestImage} or
231     * {@link #acquireNextImage}. In particular a sequence of {@link #acquireLatestImage}
232     * calls greater than {@link #getMaxImages} without calling {@link Image#close} in-between
233     * will exhaust the underlying queue. At such a time, {@link IllegalStateException}
234     * will be thrown until more images are
235     * released with {@link Image#close}.
236     * </p>
237     *
238     * @return latest frame of image data, or {@code null} if no image data is available.
239     * @throws IllegalStateException if too many images are currently acquired
240     */
241    public Image acquireLatestImage() {
242        Image image = acquireNextImage();
243        if (image == null) {
244            return null;
245        }
246        try {
247            for (;;) {
248                Image next = acquireNextImageNoThrowISE();
249                if (next == null) {
250                    Image result = image;
251                    image = null;
252                    return result;
253                }
254                image.close();
255                image = next;
256            }
257        } finally {
258            if (image != null) {
259                image.close();
260            }
261        }
262    }
263
264    /**
265     * Don't throw IllegalStateException if there are too many images acquired.
266     *
267     * @return Image if acquiring succeeded, or null otherwise.
268     *
269     * @hide
270     */
271    public Image acquireNextImageNoThrowISE() {
272        SurfaceImage si = new SurfaceImage();
273        return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
274    }
275
276    /**
277     * Attempts to acquire the next image from the underlying native implementation.
278     *
279     * <p>
280     * Note that unexpected failures will throw at the JNI level.
281     * </p>
282     *
283     * @param si A blank SurfaceImage.
284     * @return One of the {@code ACQUIRE_*} codes that determine success or failure.
285     *
286     * @see #ACQUIRE_MAX_IMAGES
287     * @see #ACQUIRE_NO_BUFS
288     * @see #ACQUIRE_SUCCESS
289     */
290    private int acquireNextSurfaceImage(SurfaceImage si) {
291
292        int status = nativeImageSetup(si);
293
294        switch (status) {
295            case ACQUIRE_SUCCESS:
296                si.createSurfacePlanes();
297                si.setImageValid(true);
298            case ACQUIRE_NO_BUFS:
299            case ACQUIRE_MAX_IMAGES:
300                break;
301            default:
302                throw new AssertionError("Unknown nativeImageSetup return code " + status);
303        }
304
305        return status;
306    }
307
308    /**
309     * <p>
310     * Acquire the next Image from the ImageReader's queue. Returns {@code null} if
311     * no new image is available.
312     * </p>
313     *
314     * <p><i>Warning:</i> Consider using {@link #acquireLatestImage()} instead, as it will
315     * automatically release older images, and allow slower-running processing routines to catch
316     * up to the newest frame. Usage of {@link #acquireNextImage} is recommended for
317     * batch/background processing. Incorrectly using this function can cause images to appear
318     * with an ever-increasing delay, followed by a complete stall where no new images seem to
319     * appear.
320     * </p>
321     *
322     * <p>
323     * This operation will fail by throwing an {@link IllegalStateException} if
324     * {@code maxImages} have been acquired with {@link #acquireNextImage} or
325     * {@link #acquireLatestImage}. In particular a sequence of {@link #acquireNextImage} or
326     * {@link #acquireLatestImage} calls greater than {@link #getMaxImages maxImages} without
327     * calling {@link Image#close} in-between will exhaust the underlying queue. At such a time,
328     * {@link IllegalStateException} will be thrown until more images are released with
329     * {@link Image#close}.
330     * </p>
331     *
332     * @return a new frame of image data, or {@code null} if no image data is available.
333     * @throws IllegalStateException if {@code maxImages} images are currently acquired
334     * @see #acquireLatestImage
335     */
336    public Image acquireNextImage() {
337        SurfaceImage si = new SurfaceImage();
338        int status = acquireNextSurfaceImage(si);
339
340        switch (status) {
341            case ACQUIRE_SUCCESS:
342                return si;
343            case ACQUIRE_NO_BUFS:
344                return null;
345            case ACQUIRE_MAX_IMAGES:
346                throw new IllegalStateException(
347                        String.format(
348                                "maxImages (%d) has already been acquired, " +
349                                "call #close before acquiring more.", mMaxImages));
350            default:
351                throw new AssertionError("Unknown nativeImageSetup return code " + status);
352        }
353    }
354
355    /**
356     * <p>Return the frame to the ImageReader for reuse.</p>
357     */
358    private void releaseImage(Image i) {
359        if (! (i instanceof SurfaceImage) ) {
360            throw new IllegalArgumentException(
361                "This image was not produced by an ImageReader");
362        }
363        SurfaceImage si = (SurfaceImage) i;
364        if (si.getReader() != this) {
365            throw new IllegalArgumentException(
366                "This image was not produced by this ImageReader");
367        }
368
369        si.clearSurfacePlanes();
370        nativeReleaseImage(i);
371        si.setImageValid(false);
372    }
373
374    /**
375     * Register a listener to be invoked when a new image becomes available
376     * from the ImageReader.
377     *
378     * @param listener
379     *            The listener that will be run.
380     * @param handler
381     *            The handler on which the listener should be invoked, or null
382     *            if the listener should be invoked on the calling thread's looper.
383     * @throws IllegalArgumentException
384     *            If no handler specified and the calling thread has no looper.
385     */
386    public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
387        synchronized (mListenerLock) {
388            if (listener != null) {
389                Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
390                if (looper == null) {
391                    throw new IllegalArgumentException(
392                            "handler is null but the current thread is not a looper");
393                }
394                if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
395                    mListenerHandler = new ListenerHandler(looper);
396                }
397                mListener = listener;
398            } else {
399                mListener = null;
400                mListenerHandler = null;
401            }
402        }
403    }
404
405    /**
406     * Callback interface for being notified that a new image is available.
407     *
408     * <p>
409     * The onImageAvailable is called per image basis, that is, callback fires for every new frame
410     * available from ImageReader.
411     * </p>
412     */
413    public interface OnImageAvailableListener {
414        /**
415         * Callback that is called when a new image is available from ImageReader.
416         *
417         * @param reader the ImageReader the callback is associated with.
418         * @see ImageReader
419         * @see Image
420         */
421        void onImageAvailable(ImageReader reader);
422    }
423
424    /**
425     * Free up all the resources associated with this ImageReader.
426     *
427     * <p>
428     * After calling this method, this ImageReader can not be used. Calling
429     * any methods on this ImageReader and Images previously provided by
430     * {@link #acquireNextImage} or {@link #acquireLatestImage}
431     * will result in an {@link IllegalStateException}, and attempting to read from
432     * {@link ByteBuffer ByteBuffers} returned by an earlier
433     * {@link Image.Plane#getBuffer Plane#getBuffer} call will
434     * have undefined behavior.
435     * </p>
436     */
437    @Override
438    public void close() {
439        setOnImageAvailableListener(null, null);
440        nativeClose();
441    }
442
443    @Override
444    protected void finalize() throws Throwable {
445        try {
446            close();
447        } finally {
448            super.finalize();
449        }
450    }
451
452    /**
453     * Only a subset of the formats defined in
454     * {@link android.graphics.ImageFormat ImageFormat} and
455     * {@link android.graphics.PixelFormat PixelFormat} are supported by
456     * ImageReader. When reading RGB data from a surface, the formats defined in
457     * {@link android.graphics.PixelFormat PixelFormat} can be used, when
458     * reading YUV, JPEG or raw sensor data (for example, from camera or video
459     * decoder), formats from {@link android.graphics.ImageFormat ImageFormat}
460     * are used.
461     */
462    private int getNumPlanesFromFormat() {
463        switch (mFormat) {
464            case ImageFormat.YV12:
465            case ImageFormat.YUV_420_888:
466            case ImageFormat.NV21:
467                return 3;
468            case ImageFormat.NV16:
469                return 2;
470            case PixelFormat.RGB_565:
471            case PixelFormat.RGBA_8888:
472            case PixelFormat.RGBX_8888:
473            case PixelFormat.RGB_888:
474            case ImageFormat.JPEG:
475            case ImageFormat.YUY2:
476            case ImageFormat.Y8:
477            case ImageFormat.Y16:
478            case ImageFormat.RAW_SENSOR:
479                return 1;
480            default:
481                throw new UnsupportedOperationException(
482                        String.format("Invalid format specified %d", mFormat));
483        }
484    }
485
486    /**
487     * Called from Native code when an Event happens.
488     *
489     * This may be called from an arbitrary Binder thread, so access to the ImageReader must be
490     * synchronized appropriately.
491     */
492    private static void postEventFromNative(Object selfRef) {
493        @SuppressWarnings("unchecked")
494        WeakReference<ImageReader> weakSelf = (WeakReference<ImageReader>)selfRef;
495        final ImageReader ir = weakSelf.get();
496        if (ir == null) {
497            return;
498        }
499
500        final Handler handler;
501        synchronized (ir.mListenerLock) {
502            handler = ir.mListenerHandler;
503        }
504        if (handler != null) {
505            handler.sendEmptyMessage(0);
506        }
507    }
508
509
510    private final int mWidth;
511    private final int mHeight;
512    private final int mFormat;
513    private final int mMaxImages;
514    private final int mNumPlanes;
515    private final Surface mSurface;
516
517    private final Object mListenerLock = new Object();
518    private OnImageAvailableListener mListener;
519    private ListenerHandler mListenerHandler;
520
521    /**
522     * This field is used by native code, do not access or modify.
523     */
524    private long mNativeContext;
525
526    /**
527     * This custom handler runs asynchronously so callbacks don't get queued behind UI messages.
528     */
529    private final class ListenerHandler extends Handler {
530        public ListenerHandler(Looper looper) {
531            super(looper, null, true /*async*/);
532        }
533
534        @Override
535        public void handleMessage(Message msg) {
536            OnImageAvailableListener listener;
537            synchronized (mListenerLock) {
538                listener = mListener;
539            }
540            if (listener != null) {
541                listener.onImageAvailable(ImageReader.this);
542            }
543        }
544    }
545
546    private class SurfaceImage extends android.media.Image {
547        public SurfaceImage() {
548            mIsImageValid = false;
549        }
550
551        @Override
552        public void close() {
553            if (mIsImageValid) {
554                ImageReader.this.releaseImage(this);
555            }
556        }
557
558        public ImageReader getReader() {
559            return ImageReader.this;
560        }
561
562        @Override
563        public int getFormat() {
564            if (mIsImageValid) {
565                return ImageReader.this.mFormat;
566            } else {
567                throw new IllegalStateException("Image is already released");
568            }
569        }
570
571        @Override
572        public int getWidth() {
573            if (mIsImageValid) {
574                return ImageReader.this.mWidth;
575            } else {
576                throw new IllegalStateException("Image is already released");
577            }
578        }
579
580        @Override
581        public int getHeight() {
582            if (mIsImageValid) {
583                return ImageReader.this.mHeight;
584            } else {
585                throw new IllegalStateException("Image is already released");
586            }
587        }
588
589        @Override
590        public long getTimestamp() {
591            if (mIsImageValid) {
592                return mTimestamp;
593            } else {
594                throw new IllegalStateException("Image is already released");
595            }
596        }
597
598        @Override
599        public Plane[] getPlanes() {
600            if (mIsImageValid) {
601                // Shallow copy is fine.
602                return mPlanes.clone();
603            } else {
604                throw new IllegalStateException("Image is already released");
605            }
606        }
607
608        @Override
609        protected final void finalize() throws Throwable {
610            try {
611                close();
612            } finally {
613                super.finalize();
614            }
615        }
616
617        private void setImageValid(boolean isValid) {
618            mIsImageValid = isValid;
619        }
620
621        private boolean isImageValid() {
622            return mIsImageValid;
623        }
624
625        private void clearSurfacePlanes() {
626            if (mIsImageValid) {
627                for (int i = 0; i < mPlanes.length; i++) {
628                    if (mPlanes[i] != null) {
629                        mPlanes[i].clearBuffer();
630                        mPlanes[i] = null;
631                    }
632                }
633            }
634        }
635
636        private void createSurfacePlanes() {
637            mPlanes = new SurfacePlane[ImageReader.this.mNumPlanes];
638            for (int i = 0; i < ImageReader.this.mNumPlanes; i++) {
639                mPlanes[i] = nativeCreatePlane(i);
640            }
641        }
642        private class SurfacePlane extends android.media.Image.Plane {
643            // SurfacePlane instance is created by native code when a new SurfaceImage is created
644            private SurfacePlane(int index, int rowStride, int pixelStride) {
645                mIndex = index;
646                mRowStride = rowStride;
647                mPixelStride = pixelStride;
648            }
649
650            @Override
651            public ByteBuffer getBuffer() {
652                if (SurfaceImage.this.isImageValid() == false) {
653                    throw new IllegalStateException("Image is already released");
654                }
655                if (mBuffer != null) {
656                    return mBuffer;
657                } else {
658                    mBuffer = SurfaceImage.this.nativeImageGetBuffer(mIndex);
659                    // Set the byteBuffer order according to host endianness (native order),
660                    // otherwise, the byteBuffer order defaults to ByteOrder.BIG_ENDIAN.
661                    return mBuffer.order(ByteOrder.nativeOrder());
662                }
663            }
664
665            @Override
666            public int getPixelStride() {
667                if (SurfaceImage.this.isImageValid()) {
668                    return mPixelStride;
669                } else {
670                    throw new IllegalStateException("Image is already released");
671                }
672            }
673
674            @Override
675            public int getRowStride() {
676                if (SurfaceImage.this.isImageValid()) {
677                    return mRowStride;
678                } else {
679                    throw new IllegalStateException("Image is already released");
680                }
681            }
682
683            private void clearBuffer() {
684                mBuffer = null;
685            }
686
687            final private int mIndex;
688            final private int mPixelStride;
689            final private int mRowStride;
690
691            private ByteBuffer mBuffer;
692        }
693
694        /**
695         * This field is used to keep track of native object and used by native code only.
696         * Don't modify.
697         */
698        private long mLockedBuffer;
699
700        /**
701         * This field is set by native code during nativeImageSetup().
702         */
703        private long mTimestamp;
704
705        private SurfacePlane[] mPlanes;
706        private boolean mIsImageValid;
707
708        private synchronized native ByteBuffer nativeImageGetBuffer(int idx);
709        private synchronized native SurfacePlane nativeCreatePlane(int idx);
710    }
711
712    private synchronized native void nativeInit(Object weakSelf, int w, int h,
713                                                    int fmt, int maxImgs);
714    private synchronized native void nativeClose();
715    private synchronized native void nativeReleaseImage(Image i);
716    private synchronized native Surface nativeGetSurface();
717
718    /**
719     * @return A return code {@code ACQUIRE_*}
720     *
721     * @see #ACQUIRE_SUCCESS
722     * @see #ACQUIRE_NO_BUFS
723     * @see #ACQUIRE_MAX_IMAGES
724     */
725    private synchronized native int nativeImageSetup(Image i);
726
727    /**
728     * We use a class initializer to allow the native code to cache some
729     * field offsets.
730     */
731    private static native void nativeClassInit();
732    static {
733        System.loadLibrary("media_jni");
734        nativeClassInit();
735    }
736}
737