• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.SuppressLint;
22 import android.graphics.GraphicBuffer;
23 import android.graphics.ImageFormat;
24 import android.graphics.ImageFormat.Format;
25 import android.graphics.PixelFormat;
26 import android.graphics.Rect;
27 import android.hardware.DataSpace;
28 import android.hardware.DataSpace.NamedDataSpace;
29 import android.hardware.HardwareBuffer;
30 import android.hardware.HardwareBuffer.Usage;
31 import android.hardware.SyncFence;
32 import android.hardware.camera2.params.StreamConfigurationMap;
33 import android.hardware.camera2.utils.SurfaceUtils;
34 import android.os.Handler;
35 import android.os.Looper;
36 import android.os.Message;
37 import android.os.ParcelFileDescriptor;
38 import android.util.Size;
39 import android.view.Surface;
40 
41 import dalvik.system.VMRuntime;
42 
43 import java.io.IOException;
44 import java.lang.ref.WeakReference;
45 import java.nio.ByteBuffer;
46 import java.nio.ByteOrder;
47 import java.nio.NioUtils;
48 import java.util.List;
49 import java.util.concurrent.CopyOnWriteArrayList;
50 
51 /**
52  * <p>
53  * The ImageWriter class allows an application to produce Image data into a
54  * {@link android.view.Surface}, and have it be consumed by another component
55  * like {@link android.hardware.camera2.CameraDevice CameraDevice}.
56  * </p>
57  * <p>
58  * Several Android API classes can provide input {@link android.view.Surface
59  * Surface} objects for ImageWriter to produce data into, including
60  * {@link MediaCodec MediaCodec} (encoder),
61  * {@link android.hardware.camera2.CameraCaptureSession CameraCaptureSession}
62  * (reprocessing input), {@link ImageReader}, etc.
63  * </p>
64  * <p>
65  * The input Image data is encapsulated in {@link Image} objects. To produce
66  * Image data into a destination {@link android.view.Surface Surface}, the
67  * application can get an input Image via {@link #dequeueInputImage} then write
68  * Image data into it. Multiple such {@link Image} objects can be dequeued at
69  * the same time and queued back in any order, up to the number specified by the
70  * {@code maxImages} constructor parameter.
71  * </p>
72  * <p>
73  * If the application already has an Image from {@link ImageReader}, the
74  * application can directly queue this Image into the ImageWriter (via
75  * {@link #queueInputImage}), potentially with zero buffer copies. This
76  * even works if the image format of the ImageWriter is
77  * {@link ImageFormat#PRIVATE PRIVATE}, and prior to Android P is the only
78  * way to enqueue images into such an ImageWriter. Starting in Android P
79  * private images may also be accessed through their hardware buffers
80  * (when available) through the {@link Image#getHardwareBuffer()} method.
81  * Attempting to access the planes of a private image, will return an
82  * empty array.
83  * </p>
84  * <p>
85  * Once new input Images are queued into an ImageWriter, it's up to the
86  * downstream components (e.g. {@link ImageReader} or
87  * {@link android.hardware.camera2.CameraDevice}) to consume the Images. If the
88  * downstream components cannot consume the Images at least as fast as the
89  * ImageWriter production rate, the {@link #dequeueInputImage} call will
90  * eventually block and the application will have to drop input frames.
91  * </p>
92  * <p>
93  * If the consumer component that provided the input {@link android.view.Surface Surface}
94  * abandons the {@link android.view.Surface Surface}, {@link #queueInputImage queueing}
95  * or {@link #dequeueInputImage dequeueing} an {@link Image} will throw an
96  * {@link IllegalStateException}.
97  * </p>
98  */
99 public class ImageWriter implements AutoCloseable {
100     private final Object mListenerLock = new Object();
101     private OnImageReleasedListener mListener;
102     private ListenerHandler mListenerHandler;
103     private final Object mCloseLock = new Object();
104     private boolean mIsWriterValid = false;
105     private long mNativeContext;
106 
107     private int mWidth;
108     private int mHeight;
109     private final int mMaxImages;
110     private long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN;
111     private @HardwareBuffer.Format int mHardwareBufferFormat;
112     private @NamedDataSpace int mDataSpace;
113 
114     // Field below is used by native code, do not access or modify.
115     private int mWriterFormat;
116 
117     // Keep track of the currently dequeued Image. This need to be thread safe as the images
118     // could be closed by different threads (e.g., application thread and GC thread).
119     private List<Image> mDequeuedImages = new CopyOnWriteArrayList<>();
120     private int mEstimatedNativeAllocBytes;
121 
122     /**
123      * <p>
124      * Create a new ImageWriter.
125      * </p>
126      * <p>
127      * The {@code maxImages} parameter determines the maximum number of
128      * {@link Image} objects that can be be dequeued from the
129      * {@code ImageWriter} simultaneously. Requesting more buffers will use up
130      * more memory, so it is important to use only the minimum number necessary.
131      * </p>
132      * <p>
133      * The input Image size and format depend on the Surface that is provided by
134      * the downstream consumer end-point.
135      * </p>
136      *
137      * @param surface The destination Surface this writer produces Image data
138      *            into.
139      * @param maxImages The maximum number of Images the user will want to
140      *            access simultaneously for producing Image data. This should be
141      *            as small as possible to limit memory use. Once maxImages
142      *            Images are dequeued by the user, one of them has to be queued
143      *            back before a new Image can be dequeued for access via
144      *            {@link #dequeueInputImage()}.
145      * @return a new ImageWriter instance.
146      */
newInstance(@onNull Surface surface, @IntRange(from = 1) int maxImages)147     public static @NonNull ImageWriter newInstance(@NonNull Surface surface,
148             @IntRange(from = 1) int maxImages) {
149         return new ImageWriter(surface, maxImages, true, ImageFormat.UNKNOWN, -1 /*width*/,
150                 -1 /*height*/);
151     }
152 
153     /**
154      * <p>
155      * Create a new ImageWriter with given number of max Images, format and producer dimension.
156      * </p>
157      * <p>
158      * The {@code maxImages} parameter determines the maximum number of
159      * {@link Image} objects that can be be dequeued from the
160      * {@code ImageWriter} simultaneously. Requesting more buffers will use up
161      * more memory, so it is important to use only the minimum number necessary.
162      * </p>
163      * <p>
164      * The format specifies the image format of this ImageWriter. The format
165      * from the {@code surface} will be overridden with this format. For example,
166      * if the surface is obtained from a {@link android.graphics.SurfaceTexture}, the default
167      * format may be {@link PixelFormat#RGBA_8888}. If the application creates an ImageWriter
168      * with this surface and {@link ImageFormat#PRIVATE}, this ImageWriter will be able to operate
169      * with {@link ImageFormat#PRIVATE} Images.
170      * </p>
171      * <p>
172      * Note that the consumer end-point may or may not be able to support Images with different
173      * format, for such case, the application should only use this method if the consumer is able
174      * to consume such images.
175      * </p>
176      * <p> The input Image size can also be set by the client. </p>
177      *
178      * @param surface The destination Surface this writer produces Image data
179      *            into.
180      * @param maxImages The maximum number of Images the user will want to
181      *            access simultaneously for producing Image data. This should be
182      *            as small as possible to limit memory use. Once maxImages
183      *            Images are dequeued by the user, one of them has to be queued
184      *            back before a new Image can be dequeued for access via
185      *            {@link #dequeueInputImage()}.
186      * @param format The format of this ImageWriter. It can be any valid format specified by
187      *            {@link ImageFormat} or {@link PixelFormat}.
188      *
189      * @param width Input size width.
190      * @param height Input size height.
191      *
192      * @return a new ImageWriter instance.
193      *
194      * @hide
195      */
newInstance(@onNull Surface surface, @IntRange(from = 1) int maxImages, @Format int format, int width, int height)196     public static @NonNull ImageWriter newInstance(@NonNull Surface surface,
197             @IntRange(from = 1) int maxImages, @Format int format, int width, int height) {
198         if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
199             throw new IllegalArgumentException("Invalid format is specified: " + format);
200         }
201         return new ImageWriter(surface, maxImages, false, format, width, height);
202     }
203 
204     /**
205      * <p>
206      * Create a new ImageWriter with given number of max Images and format.
207      * </p>
208      * <p>
209      * The {@code maxImages} parameter determines the maximum number of
210      * {@link Image} objects that can be be dequeued from the
211      * {@code ImageWriter} simultaneously. Requesting more buffers will use up
212      * more memory, so it is important to use only the minimum number necessary.
213      * </p>
214      * <p>
215      * The format specifies the image format of this ImageWriter. The format
216      * from the {@code surface} will be overridden with this format. For example,
217      * if the surface is obtained from a {@link android.graphics.SurfaceTexture}, the default
218      * format may be {@link PixelFormat#RGBA_8888}. If the application creates an ImageWriter
219      * with this surface and {@link ImageFormat#PRIVATE}, this ImageWriter will be able to operate
220      * with {@link ImageFormat#PRIVATE} Images.
221      * </p>
222      * <p>
223      * Note that the consumer end-point may or may not be able to support Images with different
224      * format, for such case, the application should only use this method if the consumer is able
225      * to consume such images.
226      * </p>
227      * <p>
228      * The input Image size depends on the Surface that is provided by
229      * the downstream consumer end-point.
230      * </p>
231      *
232      * @param surface The destination Surface this writer produces Image data
233      *            into.
234      * @param maxImages The maximum number of Images the user will want to
235      *            access simultaneously for producing Image data. This should be
236      *            as small as possible to limit memory use. Once maxImages
237      *            Images are dequeued by the user, one of them has to be queued
238      *            back before a new Image can be dequeued for access via
239      *            {@link #dequeueInputImage()}.
240      * @param format The format of this ImageWriter. It can be any valid format specified by
241      *            {@link ImageFormat} or {@link PixelFormat}.
242      *
243      * @return a new ImageWriter instance.
244      */
newInstance(@onNull Surface surface, @IntRange(from = 1) int maxImages, @Format int format)245     public static @NonNull ImageWriter newInstance(@NonNull Surface surface,
246             @IntRange(from = 1) int maxImages, @Format int format) {
247         if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
248             throw new IllegalArgumentException("Invalid format is specified: " + format);
249         }
250         return new ImageWriter(surface, maxImages, false, format, -1 /*width*/, -1 /*height*/);
251     }
252 
initializeImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, boolean useLegacyImageFormat, int imageFormat, int hardwareBufferFormat, int dataSpace, int width, int height, long usage)253     private void initializeImageWriter(Surface surface, int maxImages,
254             boolean useSurfaceImageFormatInfo, boolean useLegacyImageFormat, int imageFormat,
255             int hardwareBufferFormat, int dataSpace, int width, int height, long usage) {
256         if (surface == null || maxImages < 1) {
257             throw new IllegalArgumentException("Illegal input argument: surface " + surface
258                 + ", maxImages: " + maxImages);
259         }
260 
261         // Note that the underlying BufferQueue is working in synchronous mode
262         // to avoid dropping any buffers.
263         mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, width, height,
264             useSurfaceImageFormatInfo, hardwareBufferFormat, dataSpace, usage);
265 
266         // if useSurfaceImageFormatInfo is true, imageformat should be read from the surface.
267         if (useSurfaceImageFormatInfo) {
268             // nativeInit internally overrides UNKNOWN format. So does surface format query after
269             // nativeInit and before getEstimatedNativeAllocBytes().
270             imageFormat = SurfaceUtils.getSurfaceFormat(surface);
271             mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
272             mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
273         }
274 
275         // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native
276         // allocation estimation sequence depends on the public formats values. To avoid
277         // possible errors, convert where necessary.
278         if (imageFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) {
279             int surfaceDataspace = SurfaceUtils.getSurfaceDataspace(surface);
280             switch (surfaceDataspace) {
281                 case StreamConfigurationMap.HAL_DATASPACE_DEPTH:
282                     imageFormat = ImageFormat.DEPTH_POINT_CLOUD;
283                     break;
284                 case StreamConfigurationMap.HAL_DATASPACE_DYNAMIC_DEPTH:
285                     imageFormat = ImageFormat.DEPTH_JPEG;
286                     break;
287                 case StreamConfigurationMap.HAL_DATASPACE_HEIF:
288                     imageFormat = ImageFormat.HEIC;
289                     break;
290                 default:
291                     imageFormat = ImageFormat.JPEG;
292             }
293             mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
294             mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
295         }
296         // Estimate the native buffer allocation size and register it so it gets accounted for
297         // during GC. Note that this doesn't include the buffers required by the buffer queue
298         // itself and the buffers requested by the producer.
299         // Only include memory for 1 buffer, since actually accounting for the memory used is
300         // complex, and 1 buffer is enough for the VM to treat the ImageWriter as being of some
301         // size.
302         Size surfSize = SurfaceUtils.getSurfaceSize(surface);
303         mWidth = width == -1 ? surfSize.getWidth() : width;
304         mHeight = height == -1 ? surfSize.getHeight() : height;
305 
306         mEstimatedNativeAllocBytes =
307             ImageUtils.getEstimatedNativeAllocBytes(mWidth, mHeight,
308                 useLegacyImageFormat ? imageFormat : hardwareBufferFormat, /*buffer count*/ 1);
309         VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
310 
311         mIsWriterValid = true;
312     }
313 
ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, int imageFormat, int width, int height)314     private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo,
315             int imageFormat, int width, int height) {
316         mMaxImages = maxImages;
317         mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
318         mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
319 
320         initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true,
321                 imageFormat, mHardwareBufferFormat, mDataSpace, width, height, mUsage);
322     }
323 
ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, int imageFormat, int width, int height, long usage)324     private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo,
325             int imageFormat, int width, int height, long usage) {
326         mMaxImages = maxImages;
327         mUsage = usage;
328         mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
329         mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
330 
331         initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, true,
332                 imageFormat, mHardwareBufferFormat, mDataSpace, width, height, usage);
333     }
334 
ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, int hardwareBufferFormat, int dataSpace, int width, int height, long usage)335     private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo,
336             int hardwareBufferFormat, int dataSpace, int width, int height, long usage) {
337         mMaxImages = maxImages;
338         mUsage = usage;
339         int imageFormat;
340         // if useSurfaceImageFormatInfo is true, imageFormat will be set to UNKNOWN
341         // and retrieve corresponding hardwareBufferFormat and dataSpace here.
342         if (useSurfaceImageFormatInfo) {
343             imageFormat = ImageFormat.UNKNOWN;
344             mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
345             mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
346         } else {
347             imageFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
348             mHardwareBufferFormat = hardwareBufferFormat;
349             mDataSpace = dataSpace;
350         }
351 
352         initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, false,
353                 imageFormat, hardwareBufferFormat, dataSpace, width, height, usage);
354     }
355 
356     /**
357      * <p>
358      * Maximum number of Images that can be dequeued from the ImageWriter
359      * simultaneously (for example, with {@link #dequeueInputImage()}).
360      * </p>
361      * <p>
362      * An Image is considered dequeued after it's returned by
363      * {@link #dequeueInputImage()} from ImageWriter, and until the Image is
364      * sent back to ImageWriter via {@link #queueInputImage}, or
365      * {@link Image#close()}.
366      * </p>
367      * <p>
368      * Attempting to dequeue more than {@code maxImages} concurrently will
369      * result in the {@link #dequeueInputImage()} function throwing an
370      * {@link IllegalStateException}.
371      * </p>
372      *
373      * @return Maximum number of Images that can be dequeued from this
374      *         ImageWriter.
375      * @see #dequeueInputImage
376      * @see #queueInputImage
377      * @see Image#close
378      */
getMaxImages()379     public int getMaxImages() {
380         return mMaxImages;
381     }
382 
383     /**
384      * The width of {@link Image Images}, in pixels.
385      *
386      * <p>If {@link Builder#setWidthAndHeight} is not called, the default width of the Image
387      * depends on the Surface provided by customer end-point.</p>
388      *
389      * @return the expected actual width of an Image.
390      */
getWidth()391     public int getWidth() {
392         return mWidth;
393     }
394 
395     /**
396      * The height of {@link Image Images}, in pixels.
397      *
398      * <p>If {@link Builder#setWidthAndHeight} is not called, the default height of the Image
399      * depends on the Surface provided by customer end-point.</p>
400      *
401      * @return the expected height of an Image.
402      */
getHeight()403     public int getHeight() {
404         return mHeight;
405     }
406 
407     /**
408      * <p>
409      * Dequeue the next available input Image for the application to produce
410      * data into.
411      * </p>
412      * <p>
413      * This method requests a new input Image from ImageWriter. The application
414      * owns this Image after this call. Once the application fills the Image
415      * data, it is expected to return this Image back to ImageWriter for
416      * downstream consumer components (e.g.
417      * {@link android.hardware.camera2.CameraDevice}) to consume. The Image can
418      * be returned to ImageWriter via {@link #queueInputImage} or
419      * {@link Image#close()}.
420      * </p>
421      * <p>
422      * This call will block if all available input images have been queued by
423      * the application and the downstream consumer has not yet consumed any.
424      * When an Image is consumed by the downstream consumer and released, an
425      * {@link OnImageReleasedListener#onImageReleased} callback will be fired,
426      * which indicates that there is one input Image available. For non-
427      * {@link ImageFormat#PRIVATE PRIVATE} formats (
428      * {@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE}), it is
429      * recommended to dequeue the next Image only after this callback is fired,
430      * in the steady state.
431      * </p>
432      * <p>
433      * If the format of ImageWriter is {@link ImageFormat#PRIVATE PRIVATE} (
434      * {@link ImageWriter#getFormat()} == {@link ImageFormat#PRIVATE}), the
435      * image buffer is accessible to the application only through the hardware
436      * buffer obtained through {@link Image#getHardwareBuffer()}. (On Android
437      * versions prior to P, dequeueing private buffers will cause an
438      * {@link IllegalStateException} to be thrown). Alternatively,
439      * the application can acquire images from some other component (e.g. an
440      * {@link ImageReader}), and queue them directly to this ImageWriter via the
441      * {@link ImageWriter#queueInputImage queueInputImage()} method.
442      * </p>
443      *
444      * @return The next available input Image from this ImageWriter.
445      * @throws IllegalStateException if {@code maxImages} Images are currently
446      *             dequeued, or the input {@link android.view.Surface Surface}
447      *             has been abandoned by the consumer component that provided
448      *             the {@link android.view.Surface Surface}. Prior to Android
449      *             P, throws if the ImageWriter format is
450      *             {@link ImageFormat#PRIVATE PRIVATE}.
451      * @see #queueInputImage
452      * @see Image#close
453      */
dequeueInputImage()454     public Image dequeueInputImage() {
455         if (mDequeuedImages.size() >= mMaxImages) {
456             throw new IllegalStateException(
457                     "Already dequeued max number of Images " + mMaxImages);
458         }
459         WriterSurfaceImage newImage = new WriterSurfaceImage(this);
460         nativeDequeueInputImage(mNativeContext, newImage);
461         mDequeuedImages.add(newImage);
462         newImage.mIsImageValid = true;
463         return newImage;
464     }
465 
466     /**
467      * <p>
468      * Queue an input {@link Image} back to ImageWriter for the downstream
469      * consumer to access.
470      * </p>
471      * <p>
472      * The input {@link Image} could be from ImageReader (acquired via
473      * {@link ImageReader#acquireNextImage} or
474      * {@link ImageReader#acquireLatestImage}), or from this ImageWriter
475      * (acquired via {@link #dequeueInputImage}). In the former case, the Image
476      * data will be moved to this ImageWriter. Note that the Image properties
477      * (size, format, strides, etc.) must be the same as the properties of the
478      * images dequeued from this ImageWriter. In the latter case, the application has
479      * filled the input image with data. This method then passes the filled
480      * buffer to the downstream consumer. In both cases, it's up to the caller
481      * to ensure that the Image timestamp (in nanoseconds) is correctly set, as
482      * the downstream component may want to use it to indicate the Image data
483      * capture time.
484      * </p>
485      * <p>
486      * After this method is called and the downstream consumer consumes and
487      * releases the Image, an {@link OnImageReleasedListener#onImageReleased}
488      * callback will fire. The application can use this callback to avoid
489      * sending Images faster than the downstream consumer processing rate in
490      * steady state.
491      * </p>
492      * <p>
493      * Passing in an Image from some other component (e.g. an
494      * {@link ImageReader}) requires a free input Image from this ImageWriter as
495      * the destination. In this case, this call will block, as
496      * {@link #dequeueInputImage} does, if there are no free Images available.
497      * To avoid blocking, the application should ensure that there is at least
498      * one free Image available in this ImageWriter before calling this method.
499      * </p>
500      * <p>
501      * After this call, the input Image is no longer valid for further access,
502      * as if the Image is {@link Image#close closed}. Attempting to access the
503      * {@link ByteBuffer ByteBuffers} returned by an earlier
504      * {@link Image.Plane#getBuffer Plane#getBuffer} call will result in an
505      * {@link IllegalStateException}.
506      * </p>
507      *
508      * @param image The Image to be queued back to ImageWriter for future
509      *            consumption.
510      * @throws IllegalStateException if the image was already queued previously,
511      *            or the image was aborted previously, or the input
512      *            {@link android.view.Surface Surface} has been abandoned by the
513      *            consumer component that provided the
514      *            {@link android.view.Surface Surface}.
515      * @see #dequeueInputImage()
516      */
queueInputImage(Image image)517     public void queueInputImage(Image image) {
518         if (image == null) {
519             throw new IllegalArgumentException("image shouldn't be null");
520         }
521 
522         boolean ownedByMe = isImageOwnedByMe(image);
523         if (ownedByMe && !(((WriterSurfaceImage) image).mIsImageValid)) {
524             throw new IllegalStateException("Image from ImageWriter is invalid");
525         }
526 
527         // For images from other components that have non-null owner, need to detach first,
528         // then attach. Images without owners must already be attachable.
529         if (!ownedByMe) {
530             if ((image.getOwner() instanceof ImageReader)) {
531                 ImageReader prevOwner = (ImageReader) image.getOwner();
532 
533                 prevOwner.detachImage(image);
534             } else if (image.getOwner() != null) {
535                 throw new IllegalArgumentException(
536                         "Only images from ImageReader can be queued to"
537                                 + " ImageWriter, other image source is not supported yet!");
538             }
539 
540             attachAndQueueInputImage(image);
541             // This clears the native reference held by the original owner.
542             // When this Image is detached later by this ImageWriter, the
543             // native memory won't be leaked.
544             image.close();
545             return;
546         }
547 
548         Rect crop = image.getCropRect();
549         nativeQueueInputImage(mNativeContext, image, image.getTimestamp(), image.getDataSpace(),
550                 crop.left, crop.top, crop.right, crop.bottom, image.getTransform(),
551                 image.getScalingMode());
552 
553         /**
554          * Only remove and cleanup the Images that are owned by this
555          * ImageWriter. Images detached from other owners are only temporarily
556          * owned by this ImageWriter and will be detached immediately after they
557          * are released by downstream consumers, so there is no need to keep
558          * track of them in mDequeuedImages.
559          */
560         if (ownedByMe) {
561             mDequeuedImages.remove(image);
562             // Do not call close here, as close is essentially cancel image.
563             WriterSurfaceImage wi = (WriterSurfaceImage) image;
564             wi.clearSurfacePlanes();
565             wi.mIsImageValid = false;
566         }
567     }
568 
569     /**
570      * Get the ImageWriter format.
571      * <p>
572      * This format may be different than the Image format returned by
573      * {@link Image#getFormat()}. However, if the ImageWriter format is
574      * {@link ImageFormat#PRIVATE PRIVATE}, calling {@link #dequeueInputImage()}
575      * will result in an {@link IllegalStateException}.
576      * </p>
577      *
578      * @return The ImageWriter format.
579      */
getFormat()580     public int getFormat() {
581         return mWriterFormat;
582     }
583 
584     /**
585      * Get the ImageWriter usage flag.
586      *
587      * <p>It is not recommended to use this function if {@link Builder#setUsage} is not called.
588      * Invalid usage value will be returned if so.</p>
589      *
590      * @return The ImageWriter usage flag.
591      */
getUsage()592     public @Usage long getUsage() {
593         return mUsage;
594     }
595 
596     /**
597      * Get the ImageWriter hardwareBuffer format.
598      *
599      * <p>Use this function if the ImageWriter instance is created by builder pattern
600      * {@code ImageWriter.Builder} and using {@link Builder#setHardwareBufferFormat} and
601      * {@link Builder#setDataSpace}.</p>
602      *
603      * @return The ImageWriter hardwareBuffer format.
604      */
getHardwareBufferFormat()605     public @HardwareBuffer.Format int getHardwareBufferFormat() {
606         return mHardwareBufferFormat;
607     }
608 
609     /**
610      * Get the ImageWriter dataspace.
611      *
612      * <p>Use this function if the ImageWriter instance is created by builder pattern
613      * {@code ImageWriter.Builder} and {@link Builder#setDataSpace}.</p>
614      *
615      * @return The ImageWriter dataspace.
616      */
617     @SuppressLint("MethodNameUnits")
getDataSpace()618     public @NamedDataSpace int getDataSpace() {
619         return mDataSpace;
620     }
621 
622     /**
623      * ImageWriter callback interface, used to to asynchronously notify the
624      * application of various ImageWriter events.
625      */
626     public interface OnImageReleasedListener {
627         /**
628          * <p>
629          * Callback that is called when an input Image is released back to
630          * ImageWriter after the data consumption.
631          * </p>
632          * <p>
633          * The client can use this callback to be notified that an input Image
634          * has been consumed and released by the downstream consumer. More
635          * specifically, this callback will be fired for below cases:
636          * <li>The application dequeues an input Image via the
637          * {@link ImageWriter#dequeueInputImage dequeueInputImage()} method,
638          * uses it, and then queues it back to this ImageWriter via the
639          * {@link ImageWriter#queueInputImage queueInputImage()} method. After
640          * the downstream consumer uses and releases this image to this
641          * ImageWriter, this callback will be fired. This image will be
642          * available to be dequeued after this callback.</li>
643          * <li>The application obtains an Image from some other component (e.g.
644          * an {@link ImageReader}), uses it, and then queues it to this
645          * ImageWriter via {@link ImageWriter#queueInputImage queueInputImage()}.
646          * After the downstream consumer uses and releases this image to this
647          * ImageWriter, this callback will be fired.</li>
648          * </p>
649          *
650          * @param writer the ImageWriter the callback is associated with.
651          * @see ImageWriter
652          * @see Image
653          */
onImageReleased(ImageWriter writer)654         void onImageReleased(ImageWriter writer);
655     }
656 
657     /**
658      * Register a listener to be invoked when an input Image is returned to the
659      * ImageWriter.
660      *
661      * @param listener The listener that will be run.
662      * @param handler The handler on which the listener should be invoked, or
663      *            null if the listener should be invoked on the calling thread's
664      *            looper.
665      * @throws IllegalArgumentException If no handler specified and the calling
666      *             thread has no looper.
667      */
setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler)668     public void setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler) {
669         synchronized (mListenerLock) {
670             if (listener != null) {
671                 Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
672                 if (looper == null) {
673                     throw new IllegalArgumentException(
674                             "handler is null but the current thread is not a looper");
675                 }
676                 if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
677                     mListenerHandler = new ListenerHandler(looper);
678                 }
679                 mListener = listener;
680             } else {
681                 mListener = null;
682                 mListenerHandler = null;
683             }
684         }
685     }
686 
687     /**
688      * Free up all the resources associated with this ImageWriter.
689      * <p>
690      * After calling this method, this ImageWriter cannot be used. Calling any
691      * methods on this ImageWriter and Images previously provided by
692      * {@link #dequeueInputImage()} will result in an
693      * {@link IllegalStateException}, and attempting to write into
694      * {@link ByteBuffer ByteBuffers} returned by an earlier
695      * {@link Image.Plane#getBuffer Plane#getBuffer} call will have undefined
696      * behavior.
697      * </p>
698      */
699     @Override
close()700     public void close() {
701         setOnImageReleasedListener(null, null);
702         synchronized (mCloseLock) {
703             if (!mIsWriterValid) {
704                 return;
705             }
706             for (Image image : mDequeuedImages) {
707                 image.close();
708             }
709             mDequeuedImages.clear();
710             nativeClose(mNativeContext);
711             mNativeContext = 0;
712 
713             if (mEstimatedNativeAllocBytes > 0) {
714                 VMRuntime.getRuntime().registerNativeFree(mEstimatedNativeAllocBytes);
715                 mEstimatedNativeAllocBytes = 0;
716             }
717             mIsWriterValid = false;
718         }
719     }
720 
721     @Override
finalize()722     protected void finalize() throws Throwable {
723         try {
724             close();
725         } finally {
726             super.finalize();
727         }
728     }
729 
730     /**
731      * <p>
732      * Attach and queue input Image to this ImageWriter.
733      * </p>
734      * <p>
735      * When the format of an Image is {@link ImageFormat#PRIVATE PRIVATE}, or
736      * the source Image is so large that copying its data is too expensive, this
737      * method can be used to migrate the source Image into ImageWriter without a
738      * data copy, and then queue it to this ImageWriter. The source Image must
739      * be detached from its previous owner already, or this call will throw an
740      * {@link IllegalStateException}.
741      * </p>
742      * <p>
743      * After this call, the ImageWriter takes ownership of this Image. This
744      * ownership will automatically be removed from this writer after the
745      * consumer releases this Image, that is, after
746      * {@link OnImageReleasedListener#onImageReleased}. The caller is responsible for
747      * closing this Image through {@link Image#close()} to free up the resources
748      * held by this Image.
749      * </p>
750      *
751      * @param image The source Image to be attached and queued into this
752      *            ImageWriter for downstream consumer to use.
753      * @throws IllegalStateException if the Image is not detached from its
754      *             previous owner, or the Image is already attached to this
755      *             ImageWriter, or the source Image is invalid.
756      */
attachAndQueueInputImage(Image image)757     private void attachAndQueueInputImage(Image image) {
758         if (image == null) {
759             throw new IllegalArgumentException("image shouldn't be null");
760         }
761         if (isImageOwnedByMe(image)) {
762             throw new IllegalArgumentException(
763                     "Can not attach an image that is owned ImageWriter already");
764         }
765         /**
766          * Throw ISE if the image is not attachable, which means that it is
767          * either owned by other entity now, or completely non-attachable (some
768          * stand-alone images are not backed by native gralloc buffer, thus not
769          * attachable).
770          */
771         if (!image.isAttachable()) {
772             throw new IllegalStateException("Image was not detached from last owner, or image "
773                     + " is not detachable");
774         }
775 
776         // TODO: what if attach failed, throw RTE or detach a slot then attach?
777         // need do some cleanup to make sure no orphaned
778         // buffer caused leak.
779         Rect crop = image.getCropRect();
780         if (image.getNativeContext() != 0) {
781             nativeAttachAndQueueImage(mNativeContext, image.getNativeContext(), image.getFormat(),
782                     image.getTimestamp(), image.getDataSpace(), crop.left, crop.top, crop.right,
783                     crop.bottom, image.getTransform(), image.getScalingMode());
784         } else {
785             GraphicBuffer gb = GraphicBuffer.createFromHardwareBuffer(image.getHardwareBuffer());
786             nativeAttachAndQueueGraphicBuffer(mNativeContext, gb, image.getFormat(),
787                     image.getTimestamp(), image.getDataSpace(), crop.left, crop.top, crop.right,
788                     crop.bottom, image.getTransform(), image.getScalingMode());
789             gb.destroy();
790             image.close();
791         }
792     }
793 
794     /**
795      * This custom handler runs asynchronously so callbacks don't get queued
796      * behind UI messages.
797      */
798     private final class ListenerHandler extends Handler {
ListenerHandler(Looper looper)799         public ListenerHandler(Looper looper) {
800             super(looper, null, true /* async */);
801         }
802 
803         @Override
handleMessage(Message msg)804         public void handleMessage(Message msg) {
805             OnImageReleasedListener listener;
806             boolean isWriterValid;
807             synchronized (ImageWriter.this.mListenerLock) {
808                 listener = mListener;
809             }
810             // Check to make sure we don't accidentally queue images after the writer is
811             // closed or closing
812             synchronized (ImageWriter.this.mCloseLock) {
813                 isWriterValid = ImageWriter.this.mIsWriterValid;
814             }
815             if (listener != null && isWriterValid) {
816                 listener.onImageReleased(ImageWriter.this);
817             }
818         }
819     }
820 
821     /**
822      * Called from Native code when an Event happens. This may be called from an
823      * arbitrary Binder thread, so access to the ImageWriter must be
824      * synchronized appropriately.
825      */
postEventFromNative(Object selfRef)826     private static void postEventFromNative(Object selfRef) {
827         @SuppressWarnings("unchecked")
828         WeakReference<ImageWriter> weakSelf = (WeakReference<ImageWriter>) selfRef;
829         final ImageWriter iw = weakSelf.get();
830         if (iw == null) {
831             return;
832         }
833 
834         final Handler handler;
835         synchronized (iw.mListenerLock) {
836             handler = iw.mListenerHandler;
837         }
838 
839         if (handler != null) {
840             // The ListenerHandler will take care of ensuring that the parent ImageWriter is valid
841             handler.sendEmptyMessage(0);
842         }
843     }
844 
845     /**
846      * <p>
847      * Abort the Images that were dequeued from this ImageWriter, and return
848      * them to this writer for reuse.
849      * </p>
850      * <p>
851      * This method is used for the cases where the application dequeued the
852      * Image, may have filled the data, but does not want the downstream
853      * component to consume it. The Image will be returned to this ImageWriter
854      * for reuse after this call, and the ImageWriter will immediately have an
855      * Image available to be dequeued. This aborted Image will be invisible to
856      * the downstream consumer, as if nothing happened.
857      * </p>
858      *
859      * @param image The Image to be aborted.
860      * @see #dequeueInputImage()
861      * @see Image#close()
862      */
abortImage(Image image)863     private void abortImage(Image image) {
864         if (image == null) {
865             throw new IllegalArgumentException("image shouldn't be null");
866         }
867 
868         if (!mDequeuedImages.contains(image)) {
869             throw new IllegalStateException("It is illegal to abort some image that is not"
870                     + " dequeued yet");
871         }
872 
873         WriterSurfaceImage wi = (WriterSurfaceImage) image;
874         if (!wi.mIsImageValid) {
875             return;
876         }
877 
878         /**
879          * We only need abort Images that are owned and dequeued by ImageWriter.
880          * For attached Images, no need to abort, as there are only two cases:
881          * attached + queued successfully, and attach failed. Neither of the
882          * cases need abort.
883          */
884         cancelImage(mNativeContext, image);
885         mDequeuedImages.remove(image);
886         wi.clearSurfacePlanes();
887         wi.mIsImageValid = false;
888     }
889 
isImageOwnedByMe(Image image)890     private boolean isImageOwnedByMe(Image image) {
891         if (!(image instanceof WriterSurfaceImage)) {
892             return false;
893         }
894         WriterSurfaceImage wi = (WriterSurfaceImage) image;
895         if (wi.getOwner() != this) {
896             return false;
897         }
898 
899         return true;
900     }
901 
902     /**
903      * Builder class for {@link ImageWriter} objects.
904      */
905     public static final class Builder {
906         private Surface mSurface;
907         private int mWidth = -1;
908         private int mHeight = -1;
909         private int mMaxImages = 1;
910         private int mImageFormat = ImageFormat.UNKNOWN;
911         private long mUsage = -1;
912         private @HardwareBuffer.Format int mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
913         private @NamedDataSpace int mDataSpace = DataSpace.DATASPACE_UNKNOWN;
914         private boolean mUseSurfaceImageFormatInfo = true;
915         private boolean mUseLegacyImageFormat = false;
916 
917         /**
918          * Constructs a new builder for {@link ImageWriter}.
919          *
920          * @param surface The destination Surface this writer produces Image data into.
921          *
922          * @throws IllegalArgumentException if the surface is already abandoned.
923          */
Builder(@onNull Surface surface)924         public Builder(@NonNull Surface surface) {
925             mSurface = surface;
926         }
927 
928         /**
929          * Set the width and height of images. Default size is dependent on the Surface that is
930          * provided by the downstream end-point.
931          *
932          * @param width The width in pixels that will be passed to the producer.
933          * @param height The height in pixels that will be passed to the producer.
934          * @return the Builder instance with customized width and height.
935          */
936         @SuppressLint("MissingGetterMatchingBuilder")
setWidthAndHeight(@ntRangefrom = 1) int width, @IntRange(from = 1) int height)937         public @NonNull Builder setWidthAndHeight(@IntRange(from = 1) int width,
938                 @IntRange(from = 1) int height) {
939             mWidth = width;
940             mHeight = height;
941             return this;
942         }
943 
944         /**
945          * Set the maximum number of images. Default value is 1.
946          *
947          * @param maxImages The maximum number of Images the user will want to access simultaneously
948          *                  for producing Image data.
949          * @return the Builder instance with customized usage value.
950          */
setMaxImages(@ntRangefrom = 1) int maxImages)951         public @NonNull Builder setMaxImages(@IntRange(from = 1) int maxImages) {
952             mMaxImages = maxImages;
953             return this;
954         }
955 
956         /**
957          * Set the image format of this ImageWriter.
958          * Default format depends on the Surface provided.
959          *
960          * @param imageFormat The format of the {@link ImageWriter}. It can be any valid specified
961          *                    by {@link ImageFormat} or {@link PixelFormat}.
962          * @return the Builder instance with customized image format.
963          *
964          * @throws IllegalArgumentException if {@code imageFormat} is invalid.
965          */
966         @SuppressLint("MissingGetterMatchingBuilder")
setImageFormat(@ormat int imageFormat)967         public @NonNull Builder setImageFormat(@Format int imageFormat) {
968             if (!ImageFormat.isPublicFormat(imageFormat)
969                     && !PixelFormat.isPublicFormat(imageFormat)) {
970                 throw new IllegalArgumentException(
971                         "Invalid imageFormat is specified: " + imageFormat);
972             }
973             mImageFormat = imageFormat;
974             mUseLegacyImageFormat = true;
975             mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
976             mDataSpace = DataSpace.DATASPACE_UNKNOWN;
977             mUseSurfaceImageFormatInfo = false;
978             return this;
979         }
980 
981         /**
982          * Set the hardwareBuffer format of this ImageWriter. The default value is
983          * {@link HardwareBuffer#RGBA_8888 HardwareBuffer.RGBA_8888}.
984          *
985          * <p>This function works together with {@link #setDataSpace} for an
986          * {@link ImageWriter} instance. Setting at least one of these two replaces
987          * {@link #setImageFormat} function.</p>
988          *
989          * @param hardwareBufferFormat The HardwareBuffer format of the image that this writer
990          *                             will produce.
991          * @return the Builder instance with customized buffer format.
992          *
993          * @see #setDataSpace
994          * @see #setImageFormat
995          */
setHardwareBufferFormat( @ardwareBuffer.Format int hardwareBufferFormat)996         public @NonNull Builder setHardwareBufferFormat(
997                 @HardwareBuffer.Format int hardwareBufferFormat) {
998             mHardwareBufferFormat = hardwareBufferFormat;
999             mImageFormat = ImageFormat.UNKNOWN;
1000             mUseLegacyImageFormat = false;
1001             mUseSurfaceImageFormatInfo = false;
1002             return this;
1003         }
1004 
1005         /**
1006          * Set the dataspace of this ImageWriter.
1007          * The default value is {@link DataSpace#DATASPACE_UNKNOWN}.
1008          *
1009          * @param dataSpace The dataspace of the image that this writer will produce.
1010          * @return the builder instance with customized dataspace value.
1011          *
1012          * @see #setHardwareBufferFormat
1013          */
setDataSpace(@amedDataSpace int dataSpace)1014         public @NonNull Builder setDataSpace(@NamedDataSpace int dataSpace) {
1015             mDataSpace = dataSpace;
1016             mImageFormat = ImageFormat.UNKNOWN;
1017             mUseLegacyImageFormat = false;
1018             mUseSurfaceImageFormatInfo = false;
1019             return this;
1020         }
1021 
1022         /**
1023          * Set the usage flag of this ImageWriter.
1024          *
1025          * <p>If this function is not called, usage bit will be set
1026          * to {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN} if the image format is not
1027          * {@link ImageFormat#PRIVATE PRIVATE}.</p>
1028          *
1029          * @param usage The intended usage of the images produced by this ImageWriter.
1030          * @return the Builder instance with customized usage flag.
1031          *
1032          * @see HardwareBuffer
1033          * @see #getUsage
1034          */
setUsage(@sage long usage)1035         public @NonNull Builder setUsage(@Usage long usage) {
1036             mUsage = usage;
1037             return this;
1038         }
1039 
1040         /**
1041          * Builds a new ImageWriter object.
1042          *
1043          * @return The new ImageWriter object.
1044          */
build()1045         public @NonNull ImageWriter build() {
1046             if (mUseLegacyImageFormat) {
1047                 return new ImageWriter(mSurface, mMaxImages, mUseSurfaceImageFormatInfo,
1048                         mImageFormat, mWidth, mHeight, mUsage);
1049             } else {
1050                 return new ImageWriter(mSurface, mMaxImages, mUseSurfaceImageFormatInfo,
1051                         mHardwareBufferFormat, mDataSpace, mWidth, mHeight, mUsage);
1052             }
1053         }
1054     }
1055 
1056     private static class WriterSurfaceImage extends android.media.Image {
1057         private ImageWriter mOwner;
1058         // This field is used by native code, do not access or modify.
1059         private long mNativeBuffer;
1060         private int mNativeFenceFd = -1;
1061         private SurfacePlane[] mPlanes;
1062         private int mHeight = -1;
1063         private int mWidth = -1;
1064         private int mFormat = -1;
1065         private @NamedDataSpace int mDataSpace = DataSpace.DATASPACE_UNKNOWN;
1066         // When this default timestamp is used, timestamp for the input Image
1067         // will be generated automatically when queueInputBuffer is called.
1068         private final long DEFAULT_TIMESTAMP = Long.MIN_VALUE;
1069         private long mTimestamp = DEFAULT_TIMESTAMP;
1070 
1071         private int mTransform = 0; //Default no transform
1072         private int mScalingMode = 0; //Default frozen scaling mode
1073 
1074         private final Object mCloseLock = new Object(); // lock to protect against multiple
1075                                                         // simultaneous calls to close()
1076 
WriterSurfaceImage(ImageWriter writer)1077         public WriterSurfaceImage(ImageWriter writer) {
1078             mOwner = writer;
1079             mWidth = writer.mWidth;
1080             mHeight = writer.mHeight;
1081             mDataSpace = writer.mDataSpace;
1082         }
1083 
1084         @Override
getDataSpace()1085         public @NamedDataSpace int getDataSpace() {
1086             throwISEIfImageIsInvalid();
1087 
1088             return mDataSpace;
1089         }
1090 
1091         @Override
setDataSpace(@amedDataSpace int dataSpace)1092         public void setDataSpace(@NamedDataSpace int dataSpace) {
1093             throwISEIfImageIsInvalid();
1094 
1095             mDataSpace = dataSpace;
1096         }
1097 
1098         @Override
getFormat()1099         public int getFormat() {
1100             throwISEIfImageIsInvalid();
1101 
1102             if (mFormat == -1) {
1103                 mFormat = nativeGetFormat(mDataSpace);
1104             }
1105             return mFormat;
1106         }
1107 
1108         @Override
getWidth()1109         public int getWidth() {
1110             throwISEIfImageIsInvalid();
1111 
1112             if (mWidth == -1) {
1113                 mWidth = nativeGetWidth();
1114             }
1115 
1116             return mWidth;
1117         }
1118 
1119         @Override
getHeight()1120         public int getHeight() {
1121             throwISEIfImageIsInvalid();
1122 
1123             if (mHeight == -1) {
1124                 mHeight = nativeGetHeight();
1125             }
1126 
1127             return mHeight;
1128         }
1129 
1130         @Override
getTransform()1131         public int getTransform() {
1132             throwISEIfImageIsInvalid();
1133 
1134             return mTransform;
1135         }
1136 
1137         @Override
getScalingMode()1138         public int getScalingMode() {
1139             throwISEIfImageIsInvalid();
1140 
1141             return mScalingMode;
1142         }
1143 
1144         @Override
getTimestamp()1145         public long getTimestamp() {
1146             throwISEIfImageIsInvalid();
1147 
1148             return mTimestamp;
1149         }
1150 
1151         @Override
setTimestamp(long timestamp)1152         public void setTimestamp(long timestamp) {
1153             throwISEIfImageIsInvalid();
1154 
1155             mTimestamp = timestamp;
1156         }
1157 
1158         @Override
getHardwareBuffer()1159         public HardwareBuffer getHardwareBuffer() {
1160             throwISEIfImageIsInvalid();
1161 
1162             return nativeGetHardwareBuffer();
1163         }
1164 
1165         @Override
getFence()1166         public SyncFence getFence() throws IOException {
1167             throwISEIfImageIsInvalid();
1168             // if mNativeFenceFd is -1, the fence is closed
1169             if (mNativeFenceFd != -1) {
1170                 return SyncFence.create(ParcelFileDescriptor.fromFd(mNativeFenceFd));
1171             } else {
1172                 return SyncFence.createEmpty();
1173             }
1174         }
1175 
1176         @Override
setFence(@onNull SyncFence fence)1177         public void setFence(@NonNull SyncFence fence) throws IOException {
1178             throwISEIfImageIsInvalid();
1179             nativeSetFenceFd(fence.getFdDup().detachFd());
1180         }
1181 
1182         @Override
getPlanes()1183         public Plane[] getPlanes() {
1184             throwISEIfImageIsInvalid();
1185 
1186             if (mPlanes == null) {
1187                 int numPlanes = ImageUtils.getNumPlanesForFormat(getFormat());
1188                 mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat(),
1189                         getOwner().getDataSpace());
1190             }
1191 
1192             return mPlanes.clone();
1193         }
1194 
1195         @Override
isAttachable()1196         public boolean isAttachable() {
1197             throwISEIfImageIsInvalid();
1198             // Don't allow Image to be detached from ImageWriter for now, as no
1199             // detach API is exposed.
1200             return false;
1201         }
1202 
1203         @Override
getOwner()1204         ImageWriter getOwner() {
1205             throwISEIfImageIsInvalid();
1206 
1207             return mOwner;
1208         }
1209 
1210         @Override
getNativeContext()1211         long getNativeContext() {
1212             throwISEIfImageIsInvalid();
1213 
1214             return mNativeBuffer;
1215         }
1216 
1217         @Override
close()1218         public void close() {
1219             synchronized (mCloseLock) {
1220                 if (mIsImageValid) {
1221                     getOwner().abortImage(this);
1222                 }
1223             }
1224         }
1225 
1226         @Override
finalize()1227         protected final void finalize() throws Throwable {
1228             try {
1229                 close();
1230             } finally {
1231                 super.finalize();
1232             }
1233         }
1234 
clearSurfacePlanes()1235         private void clearSurfacePlanes() {
1236             if (mIsImageValid && mPlanes != null) {
1237                 for (int i = 0; i < mPlanes.length; i++) {
1238                     if (mPlanes[i] != null) {
1239                         mPlanes[i].clearBuffer();
1240                         mPlanes[i] = null;
1241                     }
1242                 }
1243             }
1244         }
1245 
1246         private class SurfacePlane extends android.media.Image.Plane {
1247             private ByteBuffer mBuffer;
1248             final private int mPixelStride;
1249             final private int mRowStride;
1250 
1251             // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
1252             // called
SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer)1253             private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
1254                 mRowStride = rowStride;
1255                 mPixelStride = pixelStride;
1256                 mBuffer = buffer;
1257                 /**
1258                  * Set the byteBuffer order according to host endianness (native
1259                  * order), otherwise, the byteBuffer order defaults to
1260                  * ByteOrder.BIG_ENDIAN.
1261                  */
1262                 mBuffer.order(ByteOrder.nativeOrder());
1263             }
1264 
1265             @Override
getRowStride()1266             public int getRowStride() {
1267                 throwISEIfImageIsInvalid();
1268                 return mRowStride;
1269             }
1270 
1271             @Override
getPixelStride()1272             public int getPixelStride() {
1273                 throwISEIfImageIsInvalid();
1274                 return mPixelStride;
1275             }
1276 
1277             @Override
getBuffer()1278             public ByteBuffer getBuffer() {
1279                 throwISEIfImageIsInvalid();
1280                 return mBuffer;
1281             }
1282 
clearBuffer()1283             private void clearBuffer() {
1284                 // Need null check first, as the getBuffer() may not be called
1285                 // before an Image is closed.
1286                 if (mBuffer == null) {
1287                     return;
1288                 }
1289 
1290                 if (mBuffer.isDirect()) {
1291                     NioUtils.freeDirectBuffer(mBuffer);
1292                 }
1293                 mBuffer = null;
1294             }
1295 
1296         }
1297 
1298         // Create the SurfacePlane object and fill the information
nativeCreatePlanes(int numPlanes, int writerFmt, int dataSpace)1299         private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt,
1300                 int dataSpace);
1301 
nativeGetWidth()1302         private synchronized native int nativeGetWidth();
1303 
nativeGetHeight()1304         private synchronized native int nativeGetHeight();
1305 
nativeGetFormat(int dataSpace)1306         private synchronized native int nativeGetFormat(int dataSpace);
1307 
nativeGetHardwareBuffer()1308         private synchronized native HardwareBuffer nativeGetHardwareBuffer();
1309 
nativeSetFenceFd(int fenceFd)1310         private synchronized native void nativeSetFenceFd(int fenceFd);
1311     }
1312 
1313     // Native implemented ImageWriter methods.
nativeInit(Object weakSelf, Surface surface, int maxImages, int width, int height, boolean useSurfaceImageFormatInfo, int hardwareBufferFormat, int dataSpace, long usage)1314     private synchronized native long nativeInit(Object weakSelf, Surface surface, int maxImages,
1315             int width, int height, boolean useSurfaceImageFormatInfo, int hardwareBufferFormat,
1316             int dataSpace, long usage);
1317 
nativeClose(long nativeCtx)1318     private synchronized native void nativeClose(long nativeCtx);
1319 
nativeDequeueInputImage(long nativeCtx, Image wi)1320     private synchronized native void nativeDequeueInputImage(long nativeCtx, Image wi);
1321 
nativeQueueInputImage(long nativeCtx, Image image, long timestampNs, int dataSpace, int left, int top, int right, int bottom, int transform, int scalingMode)1322     private synchronized native void nativeQueueInputImage(long nativeCtx, Image image,
1323             long timestampNs, int dataSpace, int left, int top, int right, int bottom,
1324             int transform, int scalingMode);
1325 
nativeAttachAndQueueImage(long nativeCtx, long imageNativeBuffer, int imageFormat, long timestampNs, int dataSpace, int left, int top, int right, int bottom, int transform, int scalingMode)1326     private synchronized native int nativeAttachAndQueueImage(long nativeCtx,
1327             long imageNativeBuffer, int imageFormat, long timestampNs, int dataSpace,
1328             int left, int top, int right, int bottom, int transform, int scalingMode);
nativeAttachAndQueueGraphicBuffer(long nativeCtx, GraphicBuffer graphicBuffer, int imageFormat, long timestampNs, int dataSpace, int left, int top, int right, int bottom, int transform, int scalingMode)1329     private synchronized native int nativeAttachAndQueueGraphicBuffer(long nativeCtx,
1330             GraphicBuffer graphicBuffer, int imageFormat, long timestampNs, int dataSpace,
1331             int left, int top, int right, int bottom, int transform, int scalingMode);
1332 
cancelImage(long nativeCtx, Image image)1333     private synchronized native void cancelImage(long nativeCtx, Image image);
1334 
1335     /**
1336      * We use a class initializer to allow the native code to cache some field
1337      * offsets.
1338      */
nativeClassInit()1339     private static native void nativeClassInit();
1340 
1341     static {
1342         System.loadLibrary("media_jni");
nativeClassInit()1343         nativeClassInit();
1344     }
1345 }
1346