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.os.Handler;
21import android.os.Looper;
22import android.os.Message;
23import android.util.Log;
24import android.view.Surface;
25
26import dalvik.system.VMRuntime;
27
28import java.lang.ref.WeakReference;
29import java.nio.ByteBuffer;
30import java.nio.ByteOrder;
31import java.nio.NioUtils;
32import java.util.List;
33import java.util.concurrent.CopyOnWriteArrayList;
34import java.util.concurrent.atomic.AtomicBoolean;
35
36/**
37 * <p>The ImageReader class allows direct application access to image data
38 * rendered into a {@link android.view.Surface}</p>
39 *
40 * <p>Several Android media API classes accept Surface objects as targets to
41 * render to, including {@link MediaPlayer}, {@link MediaCodec},
42 * {@link android.hardware.camera2.CameraDevice}, {@link ImageWriter} and
43 * {@link android.renderscript.Allocation RenderScript Allocations}. The image
44 * sizes and formats that can be used with each source vary, and should be
45 * checked in the documentation for the specific API.</p>
46 *
47 * <p>The image data is encapsulated in {@link Image} objects, and multiple such
48 * objects can be accessed at the same time, up to the number specified by the
49 * {@code maxImages} constructor parameter. New images sent to an ImageReader
50 * through its {@link Surface} are queued until accessed through the {@link #acquireLatestImage}
51 * or {@link #acquireNextImage} call. Due to memory limits, an image source will
52 * eventually stall or drop Images in trying to render to the Surface if the
53 * ImageReader does not obtain and release Images at a rate equal to the
54 * production rate.</p>
55 */
56public class ImageReader implements AutoCloseable {
57
58    /**
59     * Returned by nativeImageSetup when acquiring the image was successful.
60     */
61    private static final int ACQUIRE_SUCCESS = 0;
62    /**
63     * Returned by nativeImageSetup when we couldn't acquire the buffer,
64     * because there were no buffers available to acquire.
65     */
66    private static final int ACQUIRE_NO_BUFS = 1;
67    /**
68     * Returned by nativeImageSetup when we couldn't acquire the buffer
69     * because the consumer has already acquired {@maxImages} and cannot
70     * acquire more than that.
71     */
72    private static final int ACQUIRE_MAX_IMAGES = 2;
73
74    /**
75     * <p>
76     * Create a new reader for images of the desired size and format.
77     * </p>
78     * <p>
79     * The {@code maxImages} parameter determines the maximum number of
80     * {@link Image} objects that can be be acquired from the
81     * {@code ImageReader} simultaneously. Requesting more buffers will use up
82     * more memory, so it is important to use only the minimum number necessary
83     * for the use case.
84     * </p>
85     * <p>
86     * The valid sizes and formats depend on the source of the image data.
87     * </p>
88     * <p>
89     * If the {@code format} is {@link ImageFormat#PRIVATE PRIVATE}, the created
90     * {@link ImageReader} will produce images that are not directly accessible
91     * by the application. The application can still acquire images from this
92     * {@link ImageReader}, and send them to the
93     * {@link android.hardware.camera2.CameraDevice camera} for reprocessing via
94     * {@link ImageWriter} interface. However, the {@link Image#getPlanes()
95     * getPlanes()} will return an empty array for {@link ImageFormat#PRIVATE
96     * PRIVATE} format images. The application can check if an existing reader's
97     * format by calling {@link #getImageFormat()}.
98     * </p>
99     * <p>
100     * {@link ImageFormat#PRIVATE PRIVATE} format {@link ImageReader
101     * ImageReaders} are more efficient to use when application access to image
102     * data is not necessary, compared to ImageReaders using other format such
103     * as {@link ImageFormat#YUV_420_888 YUV_420_888}.
104     * </p>
105     *
106     * @param width The default width in pixels of the Images that this reader
107     *            will produce.
108     * @param height The default height in pixels of the Images that this reader
109     *            will produce.
110     * @param format The format of the Image that this reader will produce. This
111     *            must be one of the {@link android.graphics.ImageFormat} or
112     *            {@link android.graphics.PixelFormat} constants. Note that not
113     *            all formats are supported, like ImageFormat.NV21.
114     * @param maxImages The maximum number of images the user will want to
115     *            access simultaneously. This should be as small as possible to
116     *            limit memory use. Once maxImages Images are obtained by the
117     *            user, one of them has to be released before a new Image will
118     *            become available for access through
119     *            {@link #acquireLatestImage()} or {@link #acquireNextImage()}.
120     *            Must be greater than 0.
121     * @see Image
122     */
123    public static ImageReader newInstance(int width, int height, int format, int maxImages) {
124        return new ImageReader(width, height, format, maxImages);
125    }
126
127    /**
128     * @hide
129     */
130    protected ImageReader(int width, int height, int format, int maxImages) {
131        mWidth = width;
132        mHeight = height;
133        mFormat = format;
134        mMaxImages = maxImages;
135
136        if (width < 1 || height < 1) {
137            throw new IllegalArgumentException(
138                "The image dimensions must be positive");
139        }
140        if (mMaxImages < 1) {
141            throw new IllegalArgumentException(
142                "Maximum outstanding image count must be at least 1");
143        }
144
145        if (format == ImageFormat.NV21) {
146            throw new IllegalArgumentException(
147                    "NV21 format is not supported");
148        }
149
150        mNumPlanes = ImageUtils.getNumPlanesForFormat(mFormat);
151
152        nativeInit(new WeakReference<ImageReader>(this), width, height, format, maxImages);
153
154        mSurface = nativeGetSurface();
155
156        mIsReaderValid = true;
157        // Estimate the native buffer allocation size and register it so it gets accounted for
158        // during GC. Note that this doesn't include the buffers required by the buffer queue
159        // itself and the buffers requested by the producer.
160        // Only include memory for 1 buffer, since actually accounting for the memory used is
161        // complex, and 1 buffer is enough for the VM to treat the ImageReader as being of some
162        // size.
163        mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
164                width, height, format, /*buffer count*/ 1);
165        VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
166    }
167
168    /**
169     * The default width of {@link Image Images}, in pixels.
170     *
171     * <p>The width may be overridden by the producer sending buffers to this
172     * ImageReader's Surface. If so, the actual width of the images can be
173     * found using {@link Image#getWidth}.</p>
174     *
175     * @return the expected width of an Image
176     */
177    public int getWidth() {
178        return mWidth;
179    }
180
181    /**
182     * The default height of {@link Image Images}, in pixels.
183     *
184     * <p>The height may be overridden by the producer sending buffers to this
185     * ImageReader's Surface. If so, the actual height of the images can be
186     * found using {@link Image#getHeight}.</p>
187     *
188     * @return the expected height of an Image
189     */
190    public int getHeight() {
191        return mHeight;
192    }
193
194    /**
195     * The default {@link ImageFormat image format} of {@link Image Images}.
196     *
197     * <p>Some color formats may be overridden by the producer sending buffers to
198     * this ImageReader's Surface if the default color format allows. ImageReader
199     * guarantees that all {@link Image Images} acquired from ImageReader
200     * (for example, with {@link #acquireNextImage}) will have a "compatible"
201     * format to what was specified in {@link #newInstance}.
202     * As of now, each format is only compatible to itself.
203     * The actual format of the images can be found using {@link Image#getFormat}.</p>
204     *
205     * @return the expected format of an Image
206     *
207     * @see ImageFormat
208     */
209    public int getImageFormat() {
210        return mFormat;
211    }
212
213    /**
214     * Maximum number of images that can be acquired from the ImageReader by any time (for example,
215     * with {@link #acquireNextImage}).
216     *
217     * <p>An image is considered acquired after it's returned by a function from ImageReader, and
218     * until the Image is {@link Image#close closed} to release the image back to the ImageReader.
219     * </p>
220     *
221     * <p>Attempting to acquire more than {@code maxImages} concurrently will result in the
222     * acquire function throwing a {@link IllegalStateException}. Furthermore,
223     * while the max number of images have been acquired by the ImageReader user, the producer
224     * enqueueing additional images may stall until at least one image has been released. </p>
225     *
226     * @return Maximum number of images for this ImageReader.
227     *
228     * @see Image#close
229     */
230    public int getMaxImages() {
231        return mMaxImages;
232    }
233
234    /**
235     * <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
236     * {@code ImageReader}.</p>
237     *
238     * <p>Until valid image data is rendered into this {@link Surface}, the
239     * {@link #acquireNextImage} method will return {@code null}. Only one source
240     * can be producing data into this Surface at the same time, although the
241     * same {@link Surface} can be reused with a different API once the first source is
242     * disconnected from the {@link Surface}.</p>
243     *
244     * @return A {@link Surface} to use for a drawing target for various APIs.
245     */
246    public Surface getSurface() {
247        return mSurface;
248    }
249
250    /**
251     * <p>
252     * Acquire the latest {@link Image} from the ImageReader's queue, dropping older
253     * {@link Image images}. Returns {@code null} if no new image is available.
254     * </p>
255     * <p>
256     * This operation will acquire all the images possible from the ImageReader,
257     * but {@link #close} all images that aren't the latest. This function is
258     * recommended to use over {@link #acquireNextImage} for most use-cases, as it's
259     * more suited for real-time processing.
260     * </p>
261     * <p>
262     * Note that {@link #getMaxImages maxImages} should be at least 2 for
263     * {@link #acquireLatestImage} to be any different than {@link #acquireNextImage} -
264     * discarding all-but-the-newest {@link Image} requires temporarily acquiring two
265     * {@link Image Images} at once. Or more generally, calling {@link #acquireLatestImage}
266     * with less than two images of margin, that is
267     * {@code (maxImages - currentAcquiredImages < 2)} will not discard as expected.
268     * </p>
269     * <p>
270     * This operation will fail by throwing an {@link IllegalStateException} if
271     * {@code maxImages} have been acquired with {@link #acquireLatestImage} or
272     * {@link #acquireNextImage}. In particular a sequence of {@link #acquireLatestImage}
273     * calls greater than {@link #getMaxImages} without calling {@link Image#close} in-between
274     * will exhaust the underlying queue. At such a time, {@link IllegalStateException}
275     * will be thrown until more images are
276     * released with {@link Image#close}.
277     * </p>
278     *
279     * @return latest frame of image data, or {@code null} if no image data is available.
280     * @throws IllegalStateException if too many images are currently acquired
281     */
282    public Image acquireLatestImage() {
283        Image image = acquireNextImage();
284        if (image == null) {
285            return null;
286        }
287        try {
288            for (;;) {
289                Image next = acquireNextImageNoThrowISE();
290                if (next == null) {
291                    Image result = image;
292                    image = null;
293                    return result;
294                }
295                image.close();
296                image = next;
297            }
298        } finally {
299            if (image != null) {
300                image.close();
301            }
302        }
303    }
304
305    /**
306     * Don't throw IllegalStateException if there are too many images acquired.
307     *
308     * @return Image if acquiring succeeded, or null otherwise.
309     *
310     * @hide
311     */
312    public Image acquireNextImageNoThrowISE() {
313        SurfaceImage si = new SurfaceImage(mFormat);
314        return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
315    }
316
317    /**
318     * Attempts to acquire the next image from the underlying native implementation.
319     *
320     * <p>
321     * Note that unexpected failures will throw at the JNI level.
322     * </p>
323     *
324     * @param si A blank SurfaceImage.
325     * @return One of the {@code ACQUIRE_*} codes that determine success or failure.
326     *
327     * @see #ACQUIRE_MAX_IMAGES
328     * @see #ACQUIRE_NO_BUFS
329     * @see #ACQUIRE_SUCCESS
330     */
331    private int acquireNextSurfaceImage(SurfaceImage si) {
332        synchronized (mCloseLock) {
333            // A null image will eventually be returned if ImageReader is already closed.
334            int status = ACQUIRE_NO_BUFS;
335            if (mIsReaderValid) {
336                status = nativeImageSetup(si);
337            }
338
339            switch (status) {
340                case ACQUIRE_SUCCESS:
341                    si.mIsImageValid = true;
342                case ACQUIRE_NO_BUFS:
343                case ACQUIRE_MAX_IMAGES:
344                    break;
345                default:
346                    throw new AssertionError("Unknown nativeImageSetup return code " + status);
347            }
348
349            // Only keep track the successfully acquired image, as the native buffer is only mapped
350            // for such case.
351            if (status == ACQUIRE_SUCCESS) {
352                mAcquiredImages.add(si);
353            }
354            return status;
355        }
356    }
357
358    /**
359     * <p>
360     * Acquire the next Image from the ImageReader's queue. Returns {@code null} if
361     * no new image is available.
362     * </p>
363     *
364     * <p><i>Warning:</i> Consider using {@link #acquireLatestImage()} instead, as it will
365     * automatically release older images, and allow slower-running processing routines to catch
366     * up to the newest frame. Usage of {@link #acquireNextImage} is recommended for
367     * batch/background processing. Incorrectly using this function can cause images to appear
368     * with an ever-increasing delay, followed by a complete stall where no new images seem to
369     * appear.
370     * </p>
371     *
372     * <p>
373     * This operation will fail by throwing an {@link IllegalStateException} if
374     * {@code maxImages} have been acquired with {@link #acquireNextImage} or
375     * {@link #acquireLatestImage}. In particular a sequence of {@link #acquireNextImage} or
376     * {@link #acquireLatestImage} calls greater than {@link #getMaxImages maxImages} without
377     * calling {@link Image#close} in-between will exhaust the underlying queue. At such a time,
378     * {@link IllegalStateException} will be thrown until more images are released with
379     * {@link Image#close}.
380     * </p>
381     *
382     * @return a new frame of image data, or {@code null} if no image data is available.
383     * @throws IllegalStateException if {@code maxImages} images are currently acquired
384     * @see #acquireLatestImage
385     */
386    public Image acquireNextImage() {
387        // Initialize with reader format, but can be overwritten by native if the image
388        // format is different from the reader format.
389        SurfaceImage si = new SurfaceImage(mFormat);
390        int status = acquireNextSurfaceImage(si);
391
392        switch (status) {
393            case ACQUIRE_SUCCESS:
394                return si;
395            case ACQUIRE_NO_BUFS:
396                return null;
397            case ACQUIRE_MAX_IMAGES:
398                throw new IllegalStateException(
399                        String.format(
400                                "maxImages (%d) has already been acquired, " +
401                                "call #close before acquiring more.", mMaxImages));
402            default:
403                throw new AssertionError("Unknown nativeImageSetup return code " + status);
404        }
405    }
406
407    /**
408     * <p>Return the frame to the ImageReader for reuse.</p>
409     */
410    private void releaseImage(Image i) {
411        if (! (i instanceof SurfaceImage) ) {
412            throw new IllegalArgumentException(
413                "This image was not produced by an ImageReader");
414        }
415        SurfaceImage si = (SurfaceImage) i;
416        if (si.mIsImageValid == false) {
417            return;
418        }
419
420        if (si.getReader() != this || !mAcquiredImages.contains(i)) {
421            throw new IllegalArgumentException(
422                "This image was not produced by this ImageReader");
423        }
424
425        si.clearSurfacePlanes();
426        nativeReleaseImage(i);
427        si.mIsImageValid = false;
428        mAcquiredImages.remove(i);
429    }
430
431    /**
432     * Register a listener to be invoked when a new image becomes available
433     * from the ImageReader.
434     *
435     * @param listener
436     *            The listener that will be run.
437     * @param handler
438     *            The handler on which the listener should be invoked, or null
439     *            if the listener should be invoked on the calling thread's looper.
440     * @throws IllegalArgumentException
441     *            If no handler specified and the calling thread has no looper.
442     */
443    public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
444        synchronized (mListenerLock) {
445            if (listener != null) {
446                Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
447                if (looper == null) {
448                    throw new IllegalArgumentException(
449                            "handler is null but the current thread is not a looper");
450                }
451                if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
452                    mListenerHandler = new ListenerHandler(looper);
453                }
454                mListener = listener;
455            } else {
456                mListener = null;
457                mListenerHandler = null;
458            }
459        }
460    }
461
462    /**
463     * Callback interface for being notified that a new image is available.
464     *
465     * <p>
466     * The onImageAvailable is called per image basis, that is, callback fires for every new frame
467     * available from ImageReader.
468     * </p>
469     */
470    public interface OnImageAvailableListener {
471        /**
472         * Callback that is called when a new image is available from ImageReader.
473         *
474         * @param reader the ImageReader the callback is associated with.
475         * @see ImageReader
476         * @see Image
477         */
478        void onImageAvailable(ImageReader reader);
479    }
480
481    /**
482     * Free up all the resources associated with this ImageReader.
483     *
484     * <p>
485     * After calling this method, this ImageReader can not be used. Calling
486     * any methods on this ImageReader and Images previously provided by
487     * {@link #acquireNextImage} or {@link #acquireLatestImage}
488     * will result in an {@link IllegalStateException}, and attempting to read from
489     * {@link ByteBuffer ByteBuffers} returned by an earlier
490     * {@link Image.Plane#getBuffer Plane#getBuffer} call will
491     * have undefined behavior.
492     * </p>
493     */
494    @Override
495    public void close() {
496        setOnImageAvailableListener(null, null);
497        if (mSurface != null) mSurface.release();
498
499        /**
500         * Close all outstanding acquired images before closing the ImageReader. It is a good
501         * practice to close all the images as soon as it is not used to reduce system instantaneous
502         * memory pressure. CopyOnWrite list will use a copy of current list content. For the images
503         * being closed by other thread (e.g., GC thread), doubling the close call is harmless. For
504         * the image being acquired by other threads, mCloseLock is used to synchronize close and
505         * acquire operations.
506         */
507        synchronized (mCloseLock) {
508            mIsReaderValid = false;
509            for (Image image : mAcquiredImages) {
510                image.close();
511            }
512            mAcquiredImages.clear();
513
514            nativeClose();
515        }
516
517        if (mEstimatedNativeAllocBytes > 0) {
518            VMRuntime.getRuntime().registerNativeFree(mEstimatedNativeAllocBytes);
519            mEstimatedNativeAllocBytes = 0;
520        }
521    }
522
523    @Override
524    protected void finalize() throws Throwable {
525        try {
526            close();
527        } finally {
528            super.finalize();
529        }
530    }
531
532    /**
533     * <p>
534     * Remove the ownership of this image from the ImageReader.
535     * </p>
536     * <p>
537     * After this call, the ImageReader no longer owns this image, and the image
538     * ownership can be transfered to another entity like {@link ImageWriter}
539     * via {@link ImageWriter#queueInputImage}. It's up to the new owner to
540     * release the resources held by this image. For example, if the ownership
541     * of this image is transfered to an {@link ImageWriter}, the image will be
542     * freed by the ImageWriter after the image data consumption is done.
543     * </p>
544     * <p>
545     * This method can be used to achieve zero buffer copy for use cases like
546     * {@link android.hardware.camera2.CameraDevice Camera2 API} PRIVATE and YUV
547     * reprocessing, where the application can select an output image from
548     * {@link ImageReader} and transfer this image directly to
549     * {@link ImageWriter}, where this image can be consumed by camera directly.
550     * For PRIVATE reprocessing, this is the only way to send input buffers to
551     * the {@link android.hardware.camera2.CameraDevice camera} for
552     * reprocessing.
553     * </p>
554     * <p>
555     * This is a package private method that is only used internally.
556     * </p>
557     *
558     * @param image The image to be detached from this ImageReader.
559     * @throws IllegalStateException If the ImageReader or image have been
560     *             closed, or the has been detached, or has not yet been
561     *             acquired.
562     */
563     void detachImage(Image image) {
564       if (image == null) {
565           throw new IllegalArgumentException("input image must not be null");
566       }
567       if (!isImageOwnedbyMe(image)) {
568           throw new IllegalArgumentException("Trying to detach an image that is not owned by"
569                   + " this ImageReader");
570       }
571
572        SurfaceImage si = (SurfaceImage) image;
573        si.throwISEIfImageIsInvalid();
574
575        if (si.isAttachable()) {
576            throw new IllegalStateException("Image was already detached from this ImageReader");
577        }
578
579        nativeDetachImage(image);
580        si.setDetached(true);
581    }
582
583    private boolean isImageOwnedbyMe(Image image) {
584        if (!(image instanceof SurfaceImage)) {
585            return false;
586        }
587        SurfaceImage si = (SurfaceImage) image;
588        return si.getReader() == this;
589    }
590
591    /**
592     * Called from Native code when an Event happens.
593     *
594     * This may be called from an arbitrary Binder thread, so access to the ImageReader must be
595     * synchronized appropriately.
596     */
597    private static void postEventFromNative(Object selfRef) {
598        @SuppressWarnings("unchecked")
599        WeakReference<ImageReader> weakSelf = (WeakReference<ImageReader>)selfRef;
600        final ImageReader ir = weakSelf.get();
601        if (ir == null) {
602            return;
603        }
604
605        final Handler handler;
606        synchronized (ir.mListenerLock) {
607            handler = ir.mListenerHandler;
608        }
609        if (handler != null) {
610            handler.sendEmptyMessage(0);
611        }
612    }
613
614    private final int mWidth;
615    private final int mHeight;
616    private final int mFormat;
617    private final int mMaxImages;
618    private final int mNumPlanes;
619    private final Surface mSurface;
620    private int mEstimatedNativeAllocBytes;
621
622    private final Object mListenerLock = new Object();
623    private final Object mCloseLock = new Object();
624    private boolean mIsReaderValid = false;
625    private OnImageAvailableListener mListener;
626    private ListenerHandler mListenerHandler;
627    // Keep track of the successfully acquired Images. This need to be thread safe as the images
628    // could be closed by different threads (e.g., application thread and GC thread).
629    private List<Image> mAcquiredImages = new CopyOnWriteArrayList<Image>();
630
631    /**
632     * This field is used by native code, do not access or modify.
633     */
634    private long mNativeContext;
635
636    /**
637     * This custom handler runs asynchronously so callbacks don't get queued behind UI messages.
638     */
639    private final class ListenerHandler extends Handler {
640        public ListenerHandler(Looper looper) {
641            super(looper, null, true /*async*/);
642        }
643
644        @Override
645        public void handleMessage(Message msg) {
646            OnImageAvailableListener listener;
647            synchronized (mListenerLock) {
648                listener = mListener;
649            }
650
651            // It's dangerous to fire onImageAvailable() callback when the ImageReader is being
652            // closed, as application could acquire next image in the onImageAvailable() callback.
653            boolean isReaderValid = false;
654            synchronized (mCloseLock) {
655                isReaderValid = mIsReaderValid;
656            }
657            if (listener != null && isReaderValid) {
658                listener.onImageAvailable(ImageReader.this);
659            }
660        }
661    }
662
663    private class SurfaceImage extends android.media.Image {
664        public SurfaceImage(int format) {
665            mFormat = format;
666        }
667
668        @Override
669        public void close() {
670            ImageReader.this.releaseImage(this);
671        }
672
673        public ImageReader getReader() {
674            return ImageReader.this;
675        }
676
677        @Override
678        public int getFormat() {
679            throwISEIfImageIsInvalid();
680            int readerFormat = ImageReader.this.getImageFormat();
681            // Assume opaque reader always produce opaque images.
682            mFormat = (readerFormat == ImageFormat.PRIVATE) ? readerFormat :
683                nativeGetFormat(readerFormat);
684            return mFormat;
685        }
686
687        @Override
688        public int getWidth() {
689            throwISEIfImageIsInvalid();
690            int width;
691            switch(getFormat()) {
692                case ImageFormat.JPEG:
693                case ImageFormat.DEPTH_POINT_CLOUD:
694                case ImageFormat.RAW_PRIVATE:
695                    width = ImageReader.this.getWidth();
696                    break;
697                default:
698                    width = nativeGetWidth();
699            }
700            return width;
701        }
702
703        @Override
704        public int getHeight() {
705            throwISEIfImageIsInvalid();
706            int height;
707            switch(getFormat()) {
708                case ImageFormat.JPEG:
709                case ImageFormat.DEPTH_POINT_CLOUD:
710                case ImageFormat.RAW_PRIVATE:
711                    height = ImageReader.this.getHeight();
712                    break;
713                default:
714                    height = nativeGetHeight();
715            }
716            return height;
717        }
718
719        @Override
720        public long getTimestamp() {
721            throwISEIfImageIsInvalid();
722            return mTimestamp;
723        }
724
725        @Override
726        public void setTimestamp(long timestampNs) {
727            throwISEIfImageIsInvalid();
728            mTimestamp = timestampNs;
729        }
730
731        @Override
732        public Plane[] getPlanes() {
733            throwISEIfImageIsInvalid();
734
735            if (mPlanes == null) {
736                mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat);
737            }
738            // Shallow copy is fine.
739            return mPlanes.clone();
740        }
741
742        @Override
743        protected final void finalize() throws Throwable {
744            try {
745                close();
746            } finally {
747                super.finalize();
748            }
749        }
750
751        @Override
752        boolean isAttachable() {
753            throwISEIfImageIsInvalid();
754            return mIsDetached.get();
755        }
756
757        @Override
758        ImageReader getOwner() {
759            throwISEIfImageIsInvalid();
760            return ImageReader.this;
761        }
762
763        @Override
764        long getNativeContext() {
765            throwISEIfImageIsInvalid();
766            return mNativeBuffer;
767        }
768
769        private void setDetached(boolean detached) {
770            throwISEIfImageIsInvalid();
771            mIsDetached.getAndSet(detached);
772        }
773
774        private void clearSurfacePlanes() {
775            // Image#getPlanes may not be called before the image is closed.
776            if (mIsImageValid && mPlanes != null) {
777                for (int i = 0; i < mPlanes.length; i++) {
778                    if (mPlanes[i] != null) {
779                        mPlanes[i].clearBuffer();
780                        mPlanes[i] = null;
781                    }
782                }
783            }
784        }
785
786        private class SurfacePlane extends android.media.Image.Plane {
787            // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
788            // called
789            private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
790                mRowStride = rowStride;
791                mPixelStride = pixelStride;
792                mBuffer = buffer;
793                /**
794                 * Set the byteBuffer order according to host endianness (native
795                 * order), otherwise, the byteBuffer order defaults to
796                 * ByteOrder.BIG_ENDIAN.
797                 */
798                mBuffer.order(ByteOrder.nativeOrder());
799            }
800
801            @Override
802            public ByteBuffer getBuffer() {
803                throwISEIfImageIsInvalid();
804                return mBuffer;
805            }
806
807            @Override
808            public int getPixelStride() {
809                SurfaceImage.this.throwISEIfImageIsInvalid();
810                if (ImageReader.this.mFormat == ImageFormat.RAW_PRIVATE) {
811                    throw new UnsupportedOperationException(
812                            "getPixelStride is not supported for RAW_PRIVATE plane");
813                }
814                return mPixelStride;
815            }
816
817            @Override
818            public int getRowStride() {
819                SurfaceImage.this.throwISEIfImageIsInvalid();
820                if (ImageReader.this.mFormat == ImageFormat.RAW_PRIVATE) {
821                    throw new UnsupportedOperationException(
822                            "getRowStride is not supported for RAW_PRIVATE plane");
823                }
824                return mRowStride;
825            }
826
827            private void clearBuffer() {
828                // Need null check first, as the getBuffer() may not be called before an image
829                // is closed.
830                if (mBuffer == null) {
831                    return;
832                }
833
834                if (mBuffer.isDirect()) {
835                    NioUtils.freeDirectBuffer(mBuffer);
836                }
837                mBuffer = null;
838            }
839
840            final private int mPixelStride;
841            final private int mRowStride;
842
843            private ByteBuffer mBuffer;
844        }
845
846        /**
847         * This field is used to keep track of native object and used by native code only.
848         * Don't modify.
849         */
850        private long mNativeBuffer;
851
852        /**
853         * This field is set by native code during nativeImageSetup().
854         */
855        private long mTimestamp;
856
857        private SurfacePlane[] mPlanes;
858        private int mFormat = ImageFormat.UNKNOWN;
859        // If this image is detached from the ImageReader.
860        private AtomicBoolean mIsDetached = new AtomicBoolean(false);
861
862        private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes,
863                int readerFormat);
864        private synchronized native int nativeGetWidth();
865        private synchronized native int nativeGetHeight();
866        private synchronized native int nativeGetFormat(int readerFormat);
867    }
868
869    private synchronized native void nativeInit(Object weakSelf, int w, int h,
870                                                    int fmt, int maxImgs);
871    private synchronized native void nativeClose();
872    private synchronized native void nativeReleaseImage(Image i);
873    private synchronized native Surface nativeGetSurface();
874    private synchronized native int nativeDetachImage(Image i);
875
876    /**
877     * @return A return code {@code ACQUIRE_*}
878     *
879     * @see #ACQUIRE_SUCCESS
880     * @see #ACQUIRE_NO_BUFS
881     * @see #ACQUIRE_MAX_IMAGES
882     */
883    private synchronized native int nativeImageSetup(Image i);
884
885    /**
886     * We use a class initializer to allow the native code to cache some
887     * field offsets.
888     */
889    private static native void nativeClassInit();
890    static {
891        System.loadLibrary("media_jni");
892        nativeClassInit();
893    }
894}
895