Android APIs
public class

ImageWriter

extends Object
implements AutoCloseable
java.lang.Object
   ↳ android.media.ImageWriter

Class Overview

The ImageWriter class allows an application to produce Image data into a Surface, and have it be consumed by another component like CameraDevice.

Several Android API classes can provide input Surface objects for ImageWriter to produce data into, including MediaCodec (encoder), CameraCaptureSession (reprocessing input), ImageReader, etc.

The input Image data is encapsulated in Image objects. To produce Image data into a destination Surface, the application can get an input Image via dequeueInputImage() then write Image data into it. Multiple such Image objects can be dequeued at the same time and queued back in any order, up to the number specified by the maxImages constructor parameter.

If the application already has an Image from ImageReader, the application can directly queue this Image into ImageWriter (via queueInputImage(Image)), potentially with zero buffer copies. For the PRIVATE format Images produced by ImageReader, this is the only way to send Image data to ImageWriter, as the Image data aren't accessible by the application.

Once new input Images are queued into an ImageWriter, it's up to the downstream components (e.g. ImageReader or CameraDevice) to consume the Images. If the downstream components cannot consume the Images at least as fast as the ImageWriter production rate, the dequeueInputImage() call will eventually block and the application will have to drop input frames.

If the consumer component that provided the input Surface abandons the Surface, queueing or dequeueing an Image will throw an IllegalStateException.

Summary

Nested Classes
interface ImageWriter.OnImageReleasedListener ImageWriter callback interface, used to to asynchronously notify the application of various ImageWriter events. 
Public Methods
void close()
Free up all the resources associated with this ImageWriter.
Image dequeueInputImage()

Dequeue the next available input Image for the application to produce data into.

int getFormat()
Get the ImageWriter format.
int getMaxImages()

Maximum number of Images that can be dequeued from the ImageWriter simultaneously (for example, with dequeueInputImage()).

static ImageWriter newInstance(Surface surface, int maxImages)

Create a new ImageWriter.

void queueInputImage(Image image)

Queue an input Image back to ImageWriter for the downstream consumer to access.

void setOnImageReleasedListener(ImageWriter.OnImageReleasedListener listener, Handler handler)
Register a listener to be invoked when an input Image is returned to the ImageWriter.
Protected Methods
void finalize()
Invoked when the garbage collector has detected that this instance is no longer reachable.
[Expand]
Inherited Methods
From class java.lang.Object
From interface java.lang.AutoCloseable

Public Methods

public void close ()

Added in API level 23

Free up all the resources associated with this ImageWriter.

After calling this method, this ImageWriter cannot be used. Calling any methods on this ImageWriter and Images previously provided by dequeueInputImage() will result in an IllegalStateException, and attempting to write into ByteBuffers returned by an earlier Plane#getBuffer call will have undefined behavior.

public Image dequeueInputImage ()

Added in API level 23

Dequeue the next available input Image for the application to produce data into.

This method requests a new input Image from ImageWriter. The application owns this Image after this call. Once the application fills the Image data, it is expected to return this Image back to ImageWriter for downstream consumer components (e.g. CameraDevice) to consume. The Image can be returned to ImageWriter via queueInputImage(Image) or close().

This call will block if all available input images have been queued by the application and the downstream consumer has not yet consumed any. When an Image is consumed by the downstream consumer and released, an onImageReleased(ImageWriter) callback will be fired, which indicates that there is one input Image available. For non- PRIVATE formats ( getFormat() != PRIVATE), it is recommended to dequeue the next Image only after this callback is fired, in the steady state.

If the format of ImageWriter is PRIVATE ( getFormat() == PRIVATE), the image buffer is inaccessible to the application, and calling this method will result in an IllegalStateException. Instead, the application should acquire images from some other component (e.g. an ImageReader), and queue them directly to this ImageWriter via the queueInputImage() method.

Returns
  • The next available input Image from this ImageWriter.
Throws
IllegalStateException if maxImages Images are currently dequeued, or the ImageWriter format is PRIVATE, or the input Surface has been abandoned by the consumer component that provided the Surface.

public int getFormat ()

Added in API level 23

Get the ImageWriter format.

This format may be different than the Image format returned by getFormat(). However, if the ImageWriter format is PRIVATE, calling dequeueInputImage() will result in an IllegalStateException.

Returns
  • The ImageWriter format.

public int getMaxImages ()

Added in API level 23

Maximum number of Images that can be dequeued from the ImageWriter simultaneously (for example, with dequeueInputImage()).

An Image is considered dequeued after it's returned by dequeueInputImage() from ImageWriter, and until the Image is sent back to ImageWriter via queueInputImage(Image), or close().

Attempting to dequeue more than maxImages concurrently will result in the dequeueInputImage() function throwing an IllegalStateException.

Returns
  • Maximum number of Images that can be dequeued from this ImageWriter.

public static ImageWriter newInstance (Surface surface, int maxImages)

Added in API level 23

Create a new ImageWriter.

The maxImages parameter determines the maximum number of Image objects that can be be dequeued from the ImageWriter simultaneously. Requesting more buffers will use up more memory, so it is important to use only the minimum number necessary.

The input Image size and format depend on the Surface that is provided by the downstream consumer end-point.

Parameters
surface The destination Surface this writer produces Image data into.
maxImages The maximum number of Images the user will want to access simultaneously for producing Image data. This should be as small as possible to limit memory use. Once maxImages Images are dequeued by the user, one of them has to be queued back before a new Image can be dequeued for access via dequeueInputImage().
Returns
  • a new ImageWriter instance.

public void queueInputImage (Image image)

Added in API level 23

Queue an input Image back to ImageWriter for the downstream consumer to access.

The input Image could be from ImageReader (acquired via acquireNextImage() or acquireLatestImage()), or from this ImageWriter (acquired via dequeueInputImage()). In the former case, the Image data will be moved to this ImageWriter. Note that the Image properties (size, format, strides, etc.) must be the same as the properties of the images dequeued from this ImageWriter, or this method will throw an IllegalArgumentException. In the latter case, the application has filled the input image with data. This method then passes the filled buffer to the downstream consumer. In both cases, it's up to the caller to ensure that the Image timestamp (in nanoseconds) is correctly set, as the downstream component may want to use it to indicate the Image data capture time.

After this method is called and the downstream consumer consumes and releases the Image, an onImageReleased(ImageWriter) callback will fire. The application can use this callback to avoid sending Images faster than the downstream consumer processing rate in steady state.

Passing in an Image from some other component (e.g. an ImageReader) requires a free input Image from this ImageWriter as the destination. In this case, this call will block, as dequeueInputImage() does, if there are no free Images available. To avoid blocking, the application should ensure that there is at least one free Image available in this ImageWriter before calling this method.

After this call, the input Image is no longer valid for further access, as if the Image is closed. Attempting to access the ByteBuffers returned by an earlier Plane#getBuffer call will result in an IllegalStateException.

Parameters
image The Image to be queued back to ImageWriter for future consumption.
Throws
IllegalStateException if the image was already queued previously, or the image was aborted previously, or the input Surface has been abandoned by the consumer component that provided the Surface.

public void setOnImageReleasedListener (ImageWriter.OnImageReleasedListener listener, Handler handler)

Added in API level 23

Register a listener to be invoked when an input Image is returned to the ImageWriter.

Parameters
listener The listener that will be run.
handler The handler on which the listener should be invoked, or null if the listener should be invoked on the calling thread's looper.
Throws
IllegalArgumentException If no handler specified and the calling thread has no looper.

Protected Methods

protected void finalize ()

Added in API level 23

Invoked when the garbage collector has detected that this instance is no longer reachable. The default implementation does nothing, but this method can be overridden to free resources.

Note that objects that override finalize are significantly more expensive than objects that don't. Finalizers may be run a long time after the object is no longer reachable, depending on memory pressure, so it's a bad idea to rely on them for cleanup. Note also that finalizers are run on a single VM-wide finalizer thread, so doing blocking work in a finalizer is a bad idea. A finalizer is usually only necessary for a class that has a native peer and needs to call a native method to destroy that peer. Even then, it's better to provide an explicit close method (and implement Closeable), and insist that callers manually dispose of instances. This works well for something like files, but less well for something like a BigInteger where typical calling code would have to deal with lots of temporaries. Unfortunately, code that creates lots of temporaries is the worst kind of code from the point of view of the single finalizer thread.

If you must use finalizers, consider at least providing your own ReferenceQueue and having your own thread process that queue.

Unlike constructors, finalizers are not automatically chained. You are responsible for calling super.finalize() yourself.

Uncaught exceptions thrown by finalizers are ignored and do not terminate the finalizer thread. See Effective Java Item 7, "Avoid finalizers" for more.

Throws
Throwable