• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.media;
18 
19 import android.graphics.ImageFormat;
20 import android.os.Handler;
21 import android.os.Looper;
22 import android.os.Message;
23 import android.util.Log;
24 import android.view.Surface;
25 
26 import dalvik.system.VMRuntime;
27 
28 import java.lang.ref.WeakReference;
29 import java.nio.ByteBuffer;
30 import java.nio.ByteOrder;
31 import java.nio.NioUtils;
32 import java.util.List;
33 import java.util.concurrent.CopyOnWriteArrayList;
34 import 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  */
56 public 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      */
newInstance(int width, int height, int format, int maxImages)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      */
ImageReader(int width, int height, int format, int maxImages)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      */
getWidth()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      */
getHeight()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      */
getImageFormat()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      */
getMaxImages()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      */
getSurface()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      */
acquireLatestImage()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      */
acquireNextImageNoThrowISE()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      */
acquireNextSurfaceImage(SurfaceImage si)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      */
acquireNextImage()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      */
releaseImage(Image i)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      */
setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler)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          */
onImageAvailable(ImageReader reader)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
close()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             if (mEstimatedNativeAllocBytes > 0) {
517                 VMRuntime.getRuntime().registerNativeFree(mEstimatedNativeAllocBytes);
518                 mEstimatedNativeAllocBytes = 0;
519             }
520         }
521     }
522 
523     /**
524      * Discard any free buffers owned by this ImageReader.
525      *
526      * <p>
527      * Generally, the ImageReader caches buffers for reuse once they have been
528      * allocated, for best performance. However, sometimes it may be important to
529      * release all the cached, unused buffers to save on memory.
530      * </p>
531      * <p>
532      * Calling this method will discard all free cached buffers. This does not include any buffers
533      * associated with Images acquired from the ImageReader, any filled buffers waiting to be
534      * acquired, and any buffers currently in use by the source rendering buffers into the
535      * ImageReader's Surface.
536      * <p>
537      * The ImageReader continues to be usable after this call, but may need to reallocate buffers
538      * when more buffers are needed for rendering.
539      * </p>
540      * @hide
541      */
discardFreeBuffers()542     public void discardFreeBuffers() {
543         synchronized (mCloseLock) {
544             nativeDiscardFreeBuffers();
545         }
546     }
547 
548     @Override
finalize()549     protected void finalize() throws Throwable {
550         try {
551             close();
552         } finally {
553             super.finalize();
554         }
555     }
556 
557     /**
558      * <p>
559      * Remove the ownership of this image from the ImageReader.
560      * </p>
561      * <p>
562      * After this call, the ImageReader no longer owns this image, and the image
563      * ownership can be transfered to another entity like {@link ImageWriter}
564      * via {@link ImageWriter#queueInputImage}. It's up to the new owner to
565      * release the resources held by this image. For example, if the ownership
566      * of this image is transfered to an {@link ImageWriter}, the image will be
567      * freed by the ImageWriter after the image data consumption is done.
568      * </p>
569      * <p>
570      * This method can be used to achieve zero buffer copy for use cases like
571      * {@link android.hardware.camera2.CameraDevice Camera2 API} PRIVATE and YUV
572      * reprocessing, where the application can select an output image from
573      * {@link ImageReader} and transfer this image directly to
574      * {@link ImageWriter}, where this image can be consumed by camera directly.
575      * For PRIVATE reprocessing, this is the only way to send input buffers to
576      * the {@link android.hardware.camera2.CameraDevice camera} for
577      * reprocessing.
578      * </p>
579      * <p>
580      * This is a package private method that is only used internally.
581      * </p>
582      *
583      * @param image The image to be detached from this ImageReader.
584      * @throws IllegalStateException If the ImageReader or image have been
585      *             closed, or the has been detached, or has not yet been
586      *             acquired.
587      */
detachImage(Image image)588      void detachImage(Image image) {
589        if (image == null) {
590            throw new IllegalArgumentException("input image must not be null");
591        }
592        if (!isImageOwnedbyMe(image)) {
593            throw new IllegalArgumentException("Trying to detach an image that is not owned by"
594                    + " this ImageReader");
595        }
596 
597         SurfaceImage si = (SurfaceImage) image;
598         si.throwISEIfImageIsInvalid();
599 
600         if (si.isAttachable()) {
601             throw new IllegalStateException("Image was already detached from this ImageReader");
602         }
603 
604         nativeDetachImage(image);
605         si.setDetached(true);
606     }
607 
isImageOwnedbyMe(Image image)608     private boolean isImageOwnedbyMe(Image image) {
609         if (!(image instanceof SurfaceImage)) {
610             return false;
611         }
612         SurfaceImage si = (SurfaceImage) image;
613         return si.getReader() == this;
614     }
615 
616     /**
617      * Called from Native code when an Event happens.
618      *
619      * This may be called from an arbitrary Binder thread, so access to the ImageReader must be
620      * synchronized appropriately.
621      */
postEventFromNative(Object selfRef)622     private static void postEventFromNative(Object selfRef) {
623         @SuppressWarnings("unchecked")
624         WeakReference<ImageReader> weakSelf = (WeakReference<ImageReader>)selfRef;
625         final ImageReader ir = weakSelf.get();
626         if (ir == null) {
627             return;
628         }
629 
630         final Handler handler;
631         synchronized (ir.mListenerLock) {
632             handler = ir.mListenerHandler;
633         }
634         if (handler != null) {
635             handler.sendEmptyMessage(0);
636         }
637     }
638 
639     private final int mWidth;
640     private final int mHeight;
641     private final int mFormat;
642     private final int mMaxImages;
643     private final int mNumPlanes;
644     private final Surface mSurface;
645     private int mEstimatedNativeAllocBytes;
646 
647     private final Object mListenerLock = new Object();
648     private final Object mCloseLock = new Object();
649     private boolean mIsReaderValid = false;
650     private OnImageAvailableListener mListener;
651     private ListenerHandler mListenerHandler;
652     // Keep track of the successfully acquired Images. This need to be thread safe as the images
653     // could be closed by different threads (e.g., application thread and GC thread).
654     private List<Image> mAcquiredImages = new CopyOnWriteArrayList<Image>();
655 
656     /**
657      * This field is used by native code, do not access or modify.
658      */
659     private long mNativeContext;
660 
661     /**
662      * This custom handler runs asynchronously so callbacks don't get queued behind UI messages.
663      */
664     private final class ListenerHandler extends Handler {
ListenerHandler(Looper looper)665         public ListenerHandler(Looper looper) {
666             super(looper, null, true /*async*/);
667         }
668 
669         @Override
handleMessage(Message msg)670         public void handleMessage(Message msg) {
671             OnImageAvailableListener listener;
672             synchronized (mListenerLock) {
673                 listener = mListener;
674             }
675 
676             // It's dangerous to fire onImageAvailable() callback when the ImageReader is being
677             // closed, as application could acquire next image in the onImageAvailable() callback.
678             boolean isReaderValid = false;
679             synchronized (mCloseLock) {
680                 isReaderValid = mIsReaderValid;
681             }
682             if (listener != null && isReaderValid) {
683                 listener.onImageAvailable(ImageReader.this);
684             }
685         }
686     }
687 
688     private class SurfaceImage extends android.media.Image {
SurfaceImage(int format)689         public SurfaceImage(int format) {
690             mFormat = format;
691         }
692 
693         @Override
close()694         public void close() {
695             ImageReader.this.releaseImage(this);
696         }
697 
getReader()698         public ImageReader getReader() {
699             return ImageReader.this;
700         }
701 
702         @Override
getFormat()703         public int getFormat() {
704             throwISEIfImageIsInvalid();
705             int readerFormat = ImageReader.this.getImageFormat();
706             // Assume opaque reader always produce opaque images.
707             mFormat = (readerFormat == ImageFormat.PRIVATE) ? readerFormat :
708                 nativeGetFormat(readerFormat);
709             return mFormat;
710         }
711 
712         @Override
getWidth()713         public int getWidth() {
714             throwISEIfImageIsInvalid();
715             int width;
716             switch(getFormat()) {
717                 case ImageFormat.JPEG:
718                 case ImageFormat.DEPTH_POINT_CLOUD:
719                 case ImageFormat.RAW_PRIVATE:
720                     width = ImageReader.this.getWidth();
721                     break;
722                 default:
723                     width = nativeGetWidth();
724             }
725             return width;
726         }
727 
728         @Override
getHeight()729         public int getHeight() {
730             throwISEIfImageIsInvalid();
731             int height;
732             switch(getFormat()) {
733                 case ImageFormat.JPEG:
734                 case ImageFormat.DEPTH_POINT_CLOUD:
735                 case ImageFormat.RAW_PRIVATE:
736                     height = ImageReader.this.getHeight();
737                     break;
738                 default:
739                     height = nativeGetHeight();
740             }
741             return height;
742         }
743 
744         @Override
getTimestamp()745         public long getTimestamp() {
746             throwISEIfImageIsInvalid();
747             return mTimestamp;
748         }
749 
750         @Override
setTimestamp(long timestampNs)751         public void setTimestamp(long timestampNs) {
752             throwISEIfImageIsInvalid();
753             mTimestamp = timestampNs;
754         }
755 
756         @Override
getPlanes()757         public Plane[] getPlanes() {
758             throwISEIfImageIsInvalid();
759 
760             if (mPlanes == null) {
761                 mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat);
762             }
763             // Shallow copy is fine.
764             return mPlanes.clone();
765         }
766 
767         @Override
finalize()768         protected final void finalize() throws Throwable {
769             try {
770                 close();
771             } finally {
772                 super.finalize();
773             }
774         }
775 
776         @Override
isAttachable()777         boolean isAttachable() {
778             throwISEIfImageIsInvalid();
779             return mIsDetached.get();
780         }
781 
782         @Override
getOwner()783         ImageReader getOwner() {
784             throwISEIfImageIsInvalid();
785             return ImageReader.this;
786         }
787 
788         @Override
getNativeContext()789         long getNativeContext() {
790             throwISEIfImageIsInvalid();
791             return mNativeBuffer;
792         }
793 
setDetached(boolean detached)794         private void setDetached(boolean detached) {
795             throwISEIfImageIsInvalid();
796             mIsDetached.getAndSet(detached);
797         }
798 
clearSurfacePlanes()799         private void clearSurfacePlanes() {
800             // Image#getPlanes may not be called before the image is closed.
801             if (mIsImageValid && mPlanes != null) {
802                 for (int i = 0; i < mPlanes.length; i++) {
803                     if (mPlanes[i] != null) {
804                         mPlanes[i].clearBuffer();
805                         mPlanes[i] = null;
806                     }
807                 }
808             }
809         }
810 
811         private class SurfacePlane extends android.media.Image.Plane {
812             // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
813             // called
SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer)814             private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
815                 mRowStride = rowStride;
816                 mPixelStride = pixelStride;
817                 mBuffer = buffer;
818                 /**
819                  * Set the byteBuffer order according to host endianness (native
820                  * order), otherwise, the byteBuffer order defaults to
821                  * ByteOrder.BIG_ENDIAN.
822                  */
823                 mBuffer.order(ByteOrder.nativeOrder());
824             }
825 
826             @Override
getBuffer()827             public ByteBuffer getBuffer() {
828                 throwISEIfImageIsInvalid();
829                 return mBuffer;
830             }
831 
832             @Override
getPixelStride()833             public int getPixelStride() {
834                 SurfaceImage.this.throwISEIfImageIsInvalid();
835                 if (ImageReader.this.mFormat == ImageFormat.RAW_PRIVATE) {
836                     throw new UnsupportedOperationException(
837                             "getPixelStride is not supported for RAW_PRIVATE plane");
838                 }
839                 return mPixelStride;
840             }
841 
842             @Override
getRowStride()843             public int getRowStride() {
844                 SurfaceImage.this.throwISEIfImageIsInvalid();
845                 if (ImageReader.this.mFormat == ImageFormat.RAW_PRIVATE) {
846                     throw new UnsupportedOperationException(
847                             "getRowStride is not supported for RAW_PRIVATE plane");
848                 }
849                 return mRowStride;
850             }
851 
clearBuffer()852             private void clearBuffer() {
853                 // Need null check first, as the getBuffer() may not be called before an image
854                 // is closed.
855                 if (mBuffer == null) {
856                     return;
857                 }
858 
859                 if (mBuffer.isDirect()) {
860                     NioUtils.freeDirectBuffer(mBuffer);
861                 }
862                 mBuffer = null;
863             }
864 
865             final private int mPixelStride;
866             final private int mRowStride;
867 
868             private ByteBuffer mBuffer;
869         }
870 
871         /**
872          * This field is used to keep track of native object and used by native code only.
873          * Don't modify.
874          */
875         private long mNativeBuffer;
876 
877         /**
878          * This field is set by native code during nativeImageSetup().
879          */
880         private long mTimestamp;
881 
882         private SurfacePlane[] mPlanes;
883         private int mFormat = ImageFormat.UNKNOWN;
884         // If this image is detached from the ImageReader.
885         private AtomicBoolean mIsDetached = new AtomicBoolean(false);
886 
nativeCreatePlanes(int numPlanes, int readerFormat)887         private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes,
888                 int readerFormat);
nativeGetWidth()889         private synchronized native int nativeGetWidth();
nativeGetHeight()890         private synchronized native int nativeGetHeight();
nativeGetFormat(int readerFormat)891         private synchronized native int nativeGetFormat(int readerFormat);
892     }
893 
nativeInit(Object weakSelf, int w, int h, int fmt, int maxImgs)894     private synchronized native void nativeInit(Object weakSelf, int w, int h,
895                                                     int fmt, int maxImgs);
nativeClose()896     private synchronized native void nativeClose();
nativeReleaseImage(Image i)897     private synchronized native void nativeReleaseImage(Image i);
nativeGetSurface()898     private synchronized native Surface nativeGetSurface();
nativeDetachImage(Image i)899     private synchronized native int nativeDetachImage(Image i);
nativeDiscardFreeBuffers()900     private synchronized native void nativeDiscardFreeBuffers();
901 
902     /**
903      * @return A return code {@code ACQUIRE_*}
904      *
905      * @see #ACQUIRE_SUCCESS
906      * @see #ACQUIRE_NO_BUFS
907      * @see #ACQUIRE_MAX_IMAGES
908      */
nativeImageSetup(Image i)909     private synchronized native int nativeImageSetup(Image i);
910 
911     /**
912      * We use a class initializer to allow the native code to cache some
913      * field offsets.
914      */
nativeClassInit()915     private static native void nativeClassInit();
916     static {
917         System.loadLibrary("media_jni");
nativeClassInit()918         nativeClassInit();
919     }
920 }
921