1 /*
2  * Copyright 2015 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.annotation.IntRange;
20 import android.annotation.NonNull;
21 import android.graphics.ImageFormat;
22 import android.graphics.ImageFormat.Format;
23 import android.graphics.PixelFormat;
24 import android.graphics.Rect;
25 import android.hardware.camera2.utils.SurfaceUtils;
26 import android.hardware.HardwareBuffer;
27 import android.os.Handler;
28 import android.os.Looper;
29 import android.os.Message;
30 import android.util.Size;
31 import android.view.Surface;
32 
33 import dalvik.system.VMRuntime;
34 
35 import java.lang.ref.WeakReference;
36 import java.nio.ByteBuffer;
37 import java.nio.ByteOrder;
38 import java.nio.NioUtils;
39 import java.util.List;
40 import java.util.concurrent.CopyOnWriteArrayList;
41 
42 /**
43  * <p>
44  * The ImageWriter class allows an application to produce Image data into a
45  * {@link android.view.Surface}, and have it be consumed by another component
46  * like {@link android.hardware.camera2.CameraDevice CameraDevice}.
47  * </p>
48  * <p>
49  * Several Android API classes can provide input {@link android.view.Surface
50  * Surface} objects for ImageWriter to produce data into, including
51  * {@link MediaCodec MediaCodec} (encoder),
52  * {@link android.hardware.camera2.CameraCaptureSession CameraCaptureSession}
53  * (reprocessing input), {@link ImageReader}, etc.
54  * </p>
55  * <p>
56  * The input Image data is encapsulated in {@link Image} objects. To produce
57  * Image data into a destination {@link android.view.Surface Surface}, the
58  * application can get an input Image via {@link #dequeueInputImage} then write
59  * Image data into it. Multiple such {@link Image} objects can be dequeued at
60  * the same time and queued back in any order, up to the number specified by the
61  * {@code maxImages} constructor parameter.
62  * </p>
63  * <p>
64  * If the application already has an Image from {@link ImageReader}, the
65  * application can directly queue this Image into the ImageWriter (via
66  * {@link #queueInputImage}), potentially with zero buffer copies. This
67  * even works if the image format of the ImageWriter is
68  * {@link ImageFormat#PRIVATE PRIVATE}, and prior to Android P is the only
69  * way to enqueue images into such an ImageWriter. Starting in Android P
70  * private images may also be accessed through their hardware buffers
71  * (when available) through the {@link Image#getHardwareBuffer()} method.
72  * Attempting to access the planes of a private image, will return an
73  * empty array.
74  * </p>
75  * <p>
76  * Once new input Images are queued into an ImageWriter, it's up to the
77  * downstream components (e.g. {@link ImageReader} or
78  * {@link android.hardware.camera2.CameraDevice}) to consume the Images. If the
79  * downstream components cannot consume the Images at least as fast as the
80  * ImageWriter production rate, the {@link #dequeueInputImage} call will
81  * eventually block and the application will have to drop input frames.
82  * </p>
83  * <p>
84  * If the consumer component that provided the input {@link android.view.Surface Surface}
85  * abandons the {@link android.view.Surface Surface}, {@link #queueInputImage queueing}
86  * or {@link #dequeueInputImage dequeueing} an {@link Image} will throw an
87  * {@link IllegalStateException}.
88  * </p>
89  */
90 public class ImageWriter implements AutoCloseable {
91     private final Object mListenerLock = new Object();
92     private OnImageReleasedListener mListener;
93     private ListenerHandler mListenerHandler;
94     private long mNativeContext;
95 
96     // Field below is used by native code, do not access or modify.
97     private int mWriterFormat;
98 
99     private final int mMaxImages;
100     // Keep track of the currently dequeued Image. This need to be thread safe as the images
101     // could be closed by different threads (e.g., application thread and GC thread).
102     private List<Image> mDequeuedImages = new CopyOnWriteArrayList<>();
103     private int mEstimatedNativeAllocBytes;
104 
105     /**
106      * <p>
107      * Create a new ImageWriter.
108      * </p>
109      * <p>
110      * The {@code maxImages} parameter determines the maximum number of
111      * {@link Image} objects that can be be dequeued from the
112      * {@code ImageWriter} simultaneously. Requesting more buffers will use up
113      * more memory, so it is important to use only the minimum number necessary.
114      * </p>
115      * <p>
116      * The input Image size and format depend on the Surface that is provided by
117      * the downstream consumer end-point.
118      * </p>
119      *
120      * @param surface The destination Surface this writer produces Image data
121      *            into.
122      * @param maxImages The maximum number of Images the user will want to
123      *            access simultaneously for producing Image data. This should be
124      *            as small as possible to limit memory use. Once maxImages
125      *            Images are dequeued by the user, one of them has to be queued
126      *            back before a new Image can be dequeued for access via
127      *            {@link #dequeueInputImage()}.
128      * @return a new ImageWriter instance.
129      */
newInstance(@onNull Surface surface, @IntRange(from = 1) int maxImages)130     public static @NonNull ImageWriter newInstance(@NonNull Surface surface,
131             @IntRange(from = 1) int maxImages) {
132         return new ImageWriter(surface, maxImages, ImageFormat.UNKNOWN);
133     }
134 
135     /**
136      * <p>
137      * Create a new ImageWriter with given number of max Images and format.
138      * </p>
139      * <p>
140      * The {@code maxImages} parameter determines the maximum number of
141      * {@link Image} objects that can be be dequeued from the
142      * {@code ImageWriter} simultaneously. Requesting more buffers will use up
143      * more memory, so it is important to use only the minimum number necessary.
144      * </p>
145      * <p>
146      * The format specifies the image format of this ImageWriter. The format
147      * from the {@code surface} will be overridden with this format. For example,
148      * if the surface is obtained from a {@link android.graphics.SurfaceTexture}, the default
149      * format may be {@link PixelFormat#RGBA_8888}. If the application creates an ImageWriter
150      * with this surface and {@link ImageFormat#PRIVATE}, this ImageWriter will be able to operate
151      * with {@link ImageFormat#PRIVATE} Images.
152      * </p>
153      * <p>
154      * Note that the consumer end-point may or may not be able to support Images with different
155      * format, for such case, the application should only use this method if the consumer is able
156      * to consume such images.
157      * </p>
158      * <p>
159      * The input Image size depends on the Surface that is provided by
160      * the downstream consumer end-point.
161      * </p>
162      *
163      * @param surface The destination Surface this writer produces Image data
164      *            into.
165      * @param maxImages The maximum number of Images the user will want to
166      *            access simultaneously for producing Image data. This should be
167      *            as small as possible to limit memory use. Once maxImages
168      *            Images are dequeued by the user, one of them has to be queued
169      *            back before a new Image can be dequeued for access via
170      *            {@link #dequeueInputImage()}.
171      * @param format The format of this ImageWriter. It can be any valid format specified by
172      *            {@link ImageFormat} or {@link PixelFormat}.
173      *
174      * @return a new ImageWriter instance.
175      */
newInstance(@onNull Surface surface, @IntRange(from = 1) int maxImages, @Format int format)176     public static @NonNull ImageWriter newInstance(@NonNull Surface surface,
177             @IntRange(from = 1) int maxImages, @Format int format) {
178         if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
179             throw new IllegalArgumentException("Invalid format is specified: " + format);
180         }
181         return new ImageWriter(surface, maxImages, format);
182     }
183 
184     /**
185      * @hide
186      */
ImageWriter(Surface surface, int maxImages, int format)187     protected ImageWriter(Surface surface, int maxImages, int format) {
188         if (surface == null || maxImages < 1) {
189             throw new IllegalArgumentException("Illegal input argument: surface " + surface
190                     + ", maxImages: " + maxImages);
191         }
192 
193         mMaxImages = maxImages;
194 
195         // Note that the underlying BufferQueue is working in synchronous mode
196         // to avoid dropping any buffers.
197         mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, format);
198 
199         // nativeInit internally overrides UNKNOWN format. So does surface format query after
200         // nativeInit and before getEstimatedNativeAllocBytes().
201         if (format == ImageFormat.UNKNOWN) {
202             format = SurfaceUtils.getSurfaceFormat(surface);
203         }
204         // Estimate the native buffer allocation size and register it so it gets accounted for
205         // during GC. Note that this doesn't include the buffers required by the buffer queue
206         // itself and the buffers requested by the producer.
207         // Only include memory for 1 buffer, since actually accounting for the memory used is
208         // complex, and 1 buffer is enough for the VM to treat the ImageWriter as being of some
209         // size.
210         Size surfSize = SurfaceUtils.getSurfaceSize(surface);
211         mEstimatedNativeAllocBytes =
212                 ImageUtils.getEstimatedNativeAllocBytes(surfSize.getWidth(),surfSize.getHeight(),
213                         format, /*buffer count*/ 1);
214         VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
215     }
216 
217     /**
218      * <p>
219      * Maximum number of Images that can be dequeued from the ImageWriter
220      * simultaneously (for example, with {@link #dequeueInputImage()}).
221      * </p>
222      * <p>
223      * An Image is considered dequeued after it's returned by
224      * {@link #dequeueInputImage()} from ImageWriter, and until the Image is
225      * sent back to ImageWriter via {@link #queueInputImage}, or
226      * {@link Image#close()}.
227      * </p>
228      * <p>
229      * Attempting to dequeue more than {@code maxImages} concurrently will
230      * result in the {@link #dequeueInputImage()} function throwing an
231      * {@link IllegalStateException}.
232      * </p>
233      *
234      * @return Maximum number of Images that can be dequeued from this
235      *         ImageWriter.
236      * @see #dequeueInputImage
237      * @see #queueInputImage
238      * @see Image#close
239      */
getMaxImages()240     public int getMaxImages() {
241         return mMaxImages;
242     }
243 
244     /**
245      * <p>
246      * Dequeue the next available input Image for the application to produce
247      * data into.
248      * </p>
249      * <p>
250      * This method requests a new input Image from ImageWriter. The application
251      * owns this Image after this call. Once the application fills the Image
252      * data, it is expected to return this Image back to ImageWriter for
253      * downstream consumer components (e.g.
254      * {@link android.hardware.camera2.CameraDevice}) to consume. The Image can
255      * be returned to ImageWriter via {@link #queueInputImage} or
256      * {@link Image#close()}.
257      * </p>
258      * <p>
259      * This call will block if all available input images have been queued by
260      * the application and the downstream consumer has not yet consumed any.
261      * When an Image is consumed by the downstream consumer and released, an
262      * {@link OnImageReleasedListener#onImageReleased} callback will be fired,
263      * which indicates that there is one input Image available. For non-
264      * {@link ImageFormat#PRIVATE PRIVATE} formats (
265      * {@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE}), it is
266      * recommended to dequeue the next Image only after this callback is fired,
267      * in the steady state.
268      * </p>
269      * <p>
270      * If the format of ImageWriter is {@link ImageFormat#PRIVATE PRIVATE} (
271      * {@link ImageWriter#getFormat()} == {@link ImageFormat#PRIVATE}), the
272      * image buffer is accessible to the application only through the hardware
273      * buffer obtained through {@link Image#getHardwareBuffer()}. (On Android
274      * versions prior to P, dequeueing private buffers will cause an
275      * {@link IllegalStateException} to be thrown). Alternatively,
276      * the application can acquire images from some other component (e.g. an
277      * {@link ImageReader}), and queue them directly to this ImageWriter via the
278      * {@link ImageWriter#queueInputImage queueInputImage()} method.
279      * </p>
280      *
281      * @return The next available input Image from this ImageWriter.
282      * @throws IllegalStateException if {@code maxImages} Images are currently
283      *             dequeued, or the input {@link android.view.Surface Surface}
284      *             has been abandoned by the consumer component that provided
285      *             the {@link android.view.Surface Surface}. Prior to Android
286      *             P, throws if the ImageWriter format is
287      *             {@link ImageFormat#PRIVATE PRIVATE}.
288      * @see #queueInputImage
289      * @see Image#close
290      */
dequeueInputImage()291     public Image dequeueInputImage() {
292         if (mDequeuedImages.size() >= mMaxImages) {
293             throw new IllegalStateException("Already dequeued max number of Images " + mMaxImages);
294         }
295         WriterSurfaceImage newImage = new WriterSurfaceImage(this);
296         nativeDequeueInputImage(mNativeContext, newImage);
297         mDequeuedImages.add(newImage);
298         newImage.mIsImageValid = true;
299         return newImage;
300     }
301 
302     /**
303      * <p>
304      * Queue an input {@link Image} back to ImageWriter for the downstream
305      * consumer to access.
306      * </p>
307      * <p>
308      * The input {@link Image} could be from ImageReader (acquired via
309      * {@link ImageReader#acquireNextImage} or
310      * {@link ImageReader#acquireLatestImage}), or from this ImageWriter
311      * (acquired via {@link #dequeueInputImage}). In the former case, the Image
312      * data will be moved to this ImageWriter. Note that the Image properties
313      * (size, format, strides, etc.) must be the same as the properties of the
314      * images dequeued from this ImageWriter, or this method will throw an
315      * {@link IllegalArgumentException}. In the latter case, the application has
316      * filled the input image with data. This method then passes the filled
317      * buffer to the downstream consumer. In both cases, it's up to the caller
318      * to ensure that the Image timestamp (in nanoseconds) is correctly set, as
319      * the downstream component may want to use it to indicate the Image data
320      * capture time.
321      * </p>
322      * <p>
323      * After this method is called and the downstream consumer consumes and
324      * releases the Image, an {@link OnImageReleasedListener#onImageReleased}
325      * callback will fire. The application can use this callback to avoid
326      * sending Images faster than the downstream consumer processing rate in
327      * steady state.
328      * </p>
329      * <p>
330      * Passing in an Image from some other component (e.g. an
331      * {@link ImageReader}) requires a free input Image from this ImageWriter as
332      * the destination. In this case, this call will block, as
333      * {@link #dequeueInputImage} does, if there are no free Images available.
334      * To avoid blocking, the application should ensure that there is at least
335      * one free Image available in this ImageWriter before calling this method.
336      * </p>
337      * <p>
338      * After this call, the input Image is no longer valid for further access,
339      * as if the Image is {@link Image#close closed}. Attempting to access the
340      * {@link ByteBuffer ByteBuffers} returned by an earlier
341      * {@link Image.Plane#getBuffer Plane#getBuffer} call will result in an
342      * {@link IllegalStateException}.
343      * </p>
344      *
345      * @param image The Image to be queued back to ImageWriter for future
346      *            consumption.
347      * @throws IllegalStateException if the image was already queued previously,
348      *            or the image was aborted previously, or the input
349      *            {@link android.view.Surface Surface} has been abandoned by the
350      *            consumer component that provided the
351      *            {@link android.view.Surface Surface}.
352      * @see #dequeueInputImage()
353      */
queueInputImage(Image image)354     public void queueInputImage(Image image) {
355         if (image == null) {
356             throw new IllegalArgumentException("image shouldn't be null");
357         }
358         boolean ownedByMe = isImageOwnedByMe(image);
359         if (ownedByMe && !(((WriterSurfaceImage) image).mIsImageValid)) {
360             throw new IllegalStateException("Image from ImageWriter is invalid");
361         }
362 
363         // For images from other components, need to detach first, then attach.
364         if (!ownedByMe) {
365             if (!(image.getOwner() instanceof ImageReader)) {
366                 throw new IllegalArgumentException("Only images from ImageReader can be queued to"
367                         + " ImageWriter, other image source is not supported yet!");
368             }
369 
370             ImageReader prevOwner = (ImageReader) image.getOwner();
371 
372             prevOwner.detachImage(image);
373             attachAndQueueInputImage(image);
374             // This clears the native reference held by the original owner.
375             // When this Image is detached later by this ImageWriter, the
376             // native memory won't be leaked.
377             image.close();
378             return;
379         }
380 
381         Rect crop = image.getCropRect();
382         nativeQueueInputImage(mNativeContext, image, image.getTimestamp(), crop.left, crop.top,
383                 crop.right, crop.bottom, image.getTransform(), image.getScalingMode());
384 
385         /**
386          * Only remove and cleanup the Images that are owned by this
387          * ImageWriter. Images detached from other owners are only temporarily
388          * owned by this ImageWriter and will be detached immediately after they
389          * are released by downstream consumers, so there is no need to keep
390          * track of them in mDequeuedImages.
391          */
392         if (ownedByMe) {
393             mDequeuedImages.remove(image);
394             // Do not call close here, as close is essentially cancel image.
395             WriterSurfaceImage wi = (WriterSurfaceImage) image;
396             wi.clearSurfacePlanes();
397             wi.mIsImageValid = false;
398         }
399     }
400 
401     /**
402      * Get the ImageWriter format.
403      * <p>
404      * This format may be different than the Image format returned by
405      * {@link Image#getFormat()}. However, if the ImageWriter format is
406      * {@link ImageFormat#PRIVATE PRIVATE}, calling {@link #dequeueInputImage()}
407      * will result in an {@link IllegalStateException}.
408      * </p>
409      *
410      * @return The ImageWriter format.
411      */
getFormat()412     public int getFormat() {
413         return mWriterFormat;
414     }
415 
416     /**
417      * ImageWriter callback interface, used to to asynchronously notify the
418      * application of various ImageWriter events.
419      */
420     public interface OnImageReleasedListener {
421         /**
422          * <p>
423          * Callback that is called when an input Image is released back to
424          * ImageWriter after the data consumption.
425          * </p>
426          * <p>
427          * The client can use this callback to be notified that an input Image
428          * has been consumed and released by the downstream consumer. More
429          * specifically, this callback will be fired for below cases:
430          * <li>The application dequeues an input Image via the
431          * {@link ImageWriter#dequeueInputImage dequeueInputImage()} method,
432          * uses it, and then queues it back to this ImageWriter via the
433          * {@link ImageWriter#queueInputImage queueInputImage()} method. After
434          * the downstream consumer uses and releases this image to this
435          * ImageWriter, this callback will be fired. This image will be
436          * available to be dequeued after this callback.</li>
437          * <li>The application obtains an Image from some other component (e.g.
438          * an {@link ImageReader}), uses it, and then queues it to this
439          * ImageWriter via {@link ImageWriter#queueInputImage queueInputImage()}.
440          * After the downstream consumer uses and releases this image to this
441          * ImageWriter, this callback will be fired.</li>
442          * </p>
443          *
444          * @param writer the ImageWriter the callback is associated with.
445          * @see ImageWriter
446          * @see Image
447          */
onImageReleased(ImageWriter writer)448         void onImageReleased(ImageWriter writer);
449     }
450 
451     /**
452      * Register a listener to be invoked when an input Image is returned to the
453      * ImageWriter.
454      *
455      * @param listener The listener that will be run.
456      * @param handler The handler on which the listener should be invoked, or
457      *            null if the listener should be invoked on the calling thread's
458      *            looper.
459      * @throws IllegalArgumentException If no handler specified and the calling
460      *             thread has no looper.
461      */
setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler)462     public void setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler) {
463         synchronized (mListenerLock) {
464             if (listener != null) {
465                 Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
466                 if (looper == null) {
467                     throw new IllegalArgumentException(
468                             "handler is null but the current thread is not a looper");
469                 }
470                 if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
471                     mListenerHandler = new ListenerHandler(looper);
472                 }
473                 mListener = listener;
474             } else {
475                 mListener = null;
476                 mListenerHandler = null;
477             }
478         }
479     }
480 
481     /**
482      * Free up all the resources associated with this ImageWriter.
483      * <p>
484      * After calling this method, this ImageWriter cannot be used. Calling any
485      * methods on this ImageWriter and Images previously provided by
486      * {@link #dequeueInputImage()} will result in an
487      * {@link IllegalStateException}, and attempting to write into
488      * {@link ByteBuffer ByteBuffers} returned by an earlier
489      * {@link Image.Plane#getBuffer Plane#getBuffer} call will have undefined
490      * behavior.
491      * </p>
492      */
493     @Override
close()494     public void close() {
495         setOnImageReleasedListener(null, null);
496         for (Image image : mDequeuedImages) {
497             image.close();
498         }
499         mDequeuedImages.clear();
500         nativeClose(mNativeContext);
501         mNativeContext = 0;
502 
503         if (mEstimatedNativeAllocBytes > 0) {
504             VMRuntime.getRuntime().registerNativeFree(mEstimatedNativeAllocBytes);
505             mEstimatedNativeAllocBytes = 0;
506         }
507     }
508 
509     @Override
finalize()510     protected void finalize() throws Throwable {
511         try {
512             close();
513         } finally {
514             super.finalize();
515         }
516     }
517 
518     /**
519      * <p>
520      * Attach and queue input Image to this ImageWriter.
521      * </p>
522      * <p>
523      * When the format of an Image is {@link ImageFormat#PRIVATE PRIVATE}, or
524      * the source Image is so large that copying its data is too expensive, this
525      * method can be used to migrate the source Image into ImageWriter without a
526      * data copy, and then queue it to this ImageWriter. The source Image must
527      * be detached from its previous owner already, or this call will throw an
528      * {@link IllegalStateException}.
529      * </p>
530      * <p>
531      * After this call, the ImageWriter takes ownership of this Image. This
532      * ownership will automatically be removed from this writer after the
533      * consumer releases this Image, that is, after
534      * {@link OnImageReleasedListener#onImageReleased}. The caller is responsible for
535      * closing this Image through {@link Image#close()} to free up the resources
536      * held by this Image.
537      * </p>
538      *
539      * @param image The source Image to be attached and queued into this
540      *            ImageWriter for downstream consumer to use.
541      * @throws IllegalStateException if the Image is not detached from its
542      *             previous owner, or the Image is already attached to this
543      *             ImageWriter, or the source Image is invalid.
544      */
attachAndQueueInputImage(Image image)545     private void attachAndQueueInputImage(Image image) {
546         if (image == null) {
547             throw new IllegalArgumentException("image shouldn't be null");
548         }
549         if (isImageOwnedByMe(image)) {
550             throw new IllegalArgumentException(
551                     "Can not attach an image that is owned ImageWriter already");
552         }
553         /**
554          * Throw ISE if the image is not attachable, which means that it is
555          * either owned by other entity now, or completely non-attachable (some
556          * stand-alone images are not backed by native gralloc buffer, thus not
557          * attachable).
558          */
559         if (!image.isAttachable()) {
560             throw new IllegalStateException("Image was not detached from last owner, or image "
561                     + " is not detachable");
562         }
563 
564         // TODO: what if attach failed, throw RTE or detach a slot then attach?
565         // need do some cleanup to make sure no orphaned
566         // buffer caused leak.
567         Rect crop = image.getCropRect();
568         nativeAttachAndQueueImage(mNativeContext, image.getNativeContext(), image.getFormat(),
569                 image.getTimestamp(), crop.left, crop.top, crop.right, crop.bottom,
570                 image.getTransform(), image.getScalingMode());
571     }
572 
573     /**
574      * This custom handler runs asynchronously so callbacks don't get queued
575      * behind UI messages.
576      */
577     private final class ListenerHandler extends Handler {
ListenerHandler(Looper looper)578         public ListenerHandler(Looper looper) {
579             super(looper, null, true /* async */);
580         }
581 
582         @Override
handleMessage(Message msg)583         public void handleMessage(Message msg) {
584             OnImageReleasedListener listener;
585             synchronized (mListenerLock) {
586                 listener = mListener;
587             }
588             if (listener != null) {
589                 listener.onImageReleased(ImageWriter.this);
590             }
591         }
592     }
593 
594     /**
595      * Called from Native code when an Event happens. This may be called from an
596      * arbitrary Binder thread, so access to the ImageWriter must be
597      * synchronized appropriately.
598      */
postEventFromNative(Object selfRef)599     private static void postEventFromNative(Object selfRef) {
600         @SuppressWarnings("unchecked")
601         WeakReference<ImageWriter> weakSelf = (WeakReference<ImageWriter>) selfRef;
602         final ImageWriter iw = weakSelf.get();
603         if (iw == null) {
604             return;
605         }
606 
607         final Handler handler;
608         synchronized (iw.mListenerLock) {
609             handler = iw.mListenerHandler;
610         }
611         if (handler != null) {
612             handler.sendEmptyMessage(0);
613         }
614     }
615 
616     /**
617      * <p>
618      * Abort the Images that were dequeued from this ImageWriter, and return
619      * them to this writer for reuse.
620      * </p>
621      * <p>
622      * This method is used for the cases where the application dequeued the
623      * Image, may have filled the data, but does not want the downstream
624      * component to consume it. The Image will be returned to this ImageWriter
625      * for reuse after this call, and the ImageWriter will immediately have an
626      * Image available to be dequeued. This aborted Image will be invisible to
627      * the downstream consumer, as if nothing happened.
628      * </p>
629      *
630      * @param image The Image to be aborted.
631      * @see #dequeueInputImage()
632      * @see Image#close()
633      */
abortImage(Image image)634     private void abortImage(Image image) {
635         if (image == null) {
636             throw new IllegalArgumentException("image shouldn't be null");
637         }
638 
639         if (!mDequeuedImages.contains(image)) {
640             throw new IllegalStateException("It is illegal to abort some image that is not"
641                     + " dequeued yet");
642         }
643 
644         WriterSurfaceImage wi = (WriterSurfaceImage) image;
645         if (!wi.mIsImageValid) {
646             return;
647         }
648 
649         /**
650          * We only need abort Images that are owned and dequeued by ImageWriter.
651          * For attached Images, no need to abort, as there are only two cases:
652          * attached + queued successfully, and attach failed. Neither of the
653          * cases need abort.
654          */
655         cancelImage(mNativeContext, image);
656         mDequeuedImages.remove(image);
657         wi.clearSurfacePlanes();
658         wi.mIsImageValid = false;
659     }
660 
isImageOwnedByMe(Image image)661     private boolean isImageOwnedByMe(Image image) {
662         if (!(image instanceof WriterSurfaceImage)) {
663             return false;
664         }
665         WriterSurfaceImage wi = (WriterSurfaceImage) image;
666         if (wi.getOwner() != this) {
667             return false;
668         }
669 
670         return true;
671     }
672 
673     private static class WriterSurfaceImage extends android.media.Image {
674         private ImageWriter mOwner;
675         // This field is used by native code, do not access or modify.
676         private long mNativeBuffer;
677         private int mNativeFenceFd = -1;
678         private SurfacePlane[] mPlanes;
679         private int mHeight = -1;
680         private int mWidth = -1;
681         private int mFormat = -1;
682         // When this default timestamp is used, timestamp for the input Image
683         // will be generated automatically when queueInputBuffer is called.
684         private final long DEFAULT_TIMESTAMP = Long.MIN_VALUE;
685         private long mTimestamp = DEFAULT_TIMESTAMP;
686 
687         private int mTransform = 0; //Default no transform
688         private int mScalingMode = 0; //Default frozen scaling mode
689 
WriterSurfaceImage(ImageWriter writer)690         public WriterSurfaceImage(ImageWriter writer) {
691             mOwner = writer;
692         }
693 
694         @Override
getFormat()695         public int getFormat() {
696             throwISEIfImageIsInvalid();
697 
698             if (mFormat == -1) {
699                 mFormat = nativeGetFormat();
700             }
701             return mFormat;
702         }
703 
704         @Override
getWidth()705         public int getWidth() {
706             throwISEIfImageIsInvalid();
707 
708             if (mWidth == -1) {
709                 mWidth = nativeGetWidth();
710             }
711 
712             return mWidth;
713         }
714 
715         @Override
getHeight()716         public int getHeight() {
717             throwISEIfImageIsInvalid();
718 
719             if (mHeight == -1) {
720                 mHeight = nativeGetHeight();
721             }
722 
723             return mHeight;
724         }
725 
726         @Override
getTransform()727         public int getTransform() {
728             throwISEIfImageIsInvalid();
729 
730             return mTransform;
731         }
732 
733         @Override
getScalingMode()734         public int getScalingMode() {
735             throwISEIfImageIsInvalid();
736 
737             return mScalingMode;
738         }
739 
740         @Override
getTimestamp()741         public long getTimestamp() {
742             throwISEIfImageIsInvalid();
743 
744             return mTimestamp;
745         }
746 
747         @Override
setTimestamp(long timestamp)748         public void setTimestamp(long timestamp) {
749             throwISEIfImageIsInvalid();
750 
751             mTimestamp = timestamp;
752         }
753 
754         @Override
getHardwareBuffer()755         public HardwareBuffer getHardwareBuffer() {
756             throwISEIfImageIsInvalid();
757 
758             return nativeGetHardwareBuffer();
759         }
760 
761         @Override
getPlanes()762         public Plane[] getPlanes() {
763             throwISEIfImageIsInvalid();
764 
765             if (mPlanes == null) {
766                 int numPlanes = ImageUtils.getNumPlanesForFormat(getFormat());
767                 mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat());
768             }
769 
770             return mPlanes.clone();
771         }
772 
773         @Override
isAttachable()774         boolean isAttachable() {
775             throwISEIfImageIsInvalid();
776             // Don't allow Image to be detached from ImageWriter for now, as no
777             // detach API is exposed.
778             return false;
779         }
780 
781         @Override
getOwner()782         ImageWriter getOwner() {
783             throwISEIfImageIsInvalid();
784 
785             return mOwner;
786         }
787 
788         @Override
getNativeContext()789         long getNativeContext() {
790             throwISEIfImageIsInvalid();
791 
792             return mNativeBuffer;
793         }
794 
795         @Override
close()796         public void close() {
797             if (mIsImageValid) {
798                 getOwner().abortImage(this);
799             }
800         }
801 
802         @Override
finalize()803         protected final void finalize() throws Throwable {
804             try {
805                 close();
806             } finally {
807                 super.finalize();
808             }
809         }
810 
clearSurfacePlanes()811         private void clearSurfacePlanes() {
812             if (mIsImageValid && mPlanes != null) {
813                 for (int i = 0; i < mPlanes.length; i++) {
814                     if (mPlanes[i] != null) {
815                         mPlanes[i].clearBuffer();
816                         mPlanes[i] = null;
817                     }
818                 }
819             }
820         }
821 
822         private class SurfacePlane extends android.media.Image.Plane {
823             private ByteBuffer mBuffer;
824             final private int mPixelStride;
825             final private int mRowStride;
826 
827             // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
828             // called
SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer)829             private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
830                 mRowStride = rowStride;
831                 mPixelStride = pixelStride;
832                 mBuffer = buffer;
833                 /**
834                  * Set the byteBuffer order according to host endianness (native
835                  * order), otherwise, the byteBuffer order defaults to
836                  * ByteOrder.BIG_ENDIAN.
837                  */
838                 mBuffer.order(ByteOrder.nativeOrder());
839             }
840 
841             @Override
getRowStride()842             public int getRowStride() {
843                 throwISEIfImageIsInvalid();
844                 return mRowStride;
845             }
846 
847             @Override
getPixelStride()848             public int getPixelStride() {
849                 throwISEIfImageIsInvalid();
850                 return mPixelStride;
851             }
852 
853             @Override
getBuffer()854             public ByteBuffer getBuffer() {
855                 throwISEIfImageIsInvalid();
856                 return mBuffer;
857             }
858 
clearBuffer()859             private void clearBuffer() {
860                 // Need null check first, as the getBuffer() may not be called
861                 // before an Image is closed.
862                 if (mBuffer == null) {
863                     return;
864                 }
865 
866                 if (mBuffer.isDirect()) {
867                     NioUtils.freeDirectBuffer(mBuffer);
868                 }
869                 mBuffer = null;
870             }
871 
872         }
873 
874         // Create the SurfacePlane object and fill the information
nativeCreatePlanes(int numPlanes, int writerFmt)875         private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt);
876 
nativeGetWidth()877         private synchronized native int nativeGetWidth();
878 
nativeGetHeight()879         private synchronized native int nativeGetHeight();
880 
nativeGetFormat()881         private synchronized native int nativeGetFormat();
882 
nativeGetHardwareBuffer()883         private synchronized native HardwareBuffer nativeGetHardwareBuffer();
884     }
885 
886     // Native implemented ImageWriter methods.
nativeInit(Object weakSelf, Surface surface, int maxImgs, int format)887     private synchronized native long nativeInit(Object weakSelf, Surface surface, int maxImgs,
888             int format);
889 
nativeClose(long nativeCtx)890     private synchronized native void nativeClose(long nativeCtx);
891 
nativeDequeueInputImage(long nativeCtx, Image wi)892     private synchronized native void nativeDequeueInputImage(long nativeCtx, Image wi);
893 
nativeQueueInputImage(long nativeCtx, Image image, long timestampNs, int left, int top, int right, int bottom, int transform, int scalingMode)894     private synchronized native void nativeQueueInputImage(long nativeCtx, Image image,
895             long timestampNs, int left, int top, int right, int bottom, int transform,
896             int scalingMode);
897 
nativeAttachAndQueueImage(long nativeCtx, long imageNativeBuffer, int imageFormat, long timestampNs, int left, int top, int right, int bottom, int transform, int scalingMode)898     private synchronized native int nativeAttachAndQueueImage(long nativeCtx,
899             long imageNativeBuffer, int imageFormat, long timestampNs, int left,
900             int top, int right, int bottom, int transform, int scalingMode);
901 
cancelImage(long nativeCtx, Image image)902     private synchronized native void cancelImage(long nativeCtx, Image image);
903 
904     /**
905      * We use a class initializer to allow the native code to cache some field
906      * offsets.
907      */
nativeClassInit()908     private static native void nativeClassInit();
909 
910     static {
911         System.loadLibrary("media_jni");
nativeClassInit()912         nativeClassInit();
913     }
914 }
915