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