am ff704248: am 492afe90: Merge "Image/Reader/Writer: address API review comments" into mnc-dev

* commit 'ff7042481a08a9b109be72982c9e38220c1262f5':
  Image/Reader/Writer: address API review comments
This commit is contained in:
Zhijun He
2015-05-14 22:11:12 +00:00
committed by Android Git Automerger
6 changed files with 101 additions and 171 deletions

View File

@@ -15230,7 +15230,6 @@ package android.media {
method public abstract android.media.Image.Plane[] getPlanes(); method public abstract android.media.Image.Plane[] getPlanes();
method public abstract long getTimestamp(); method public abstract long getTimestamp();
method public abstract int getWidth(); method public abstract int getWidth();
method public boolean isOpaque();
method public void setCropRect(android.graphics.Rect); method public void setCropRect(android.graphics.Rect);
method public void setTimestamp(long); method public void setTimestamp(long);
} }
@@ -15250,9 +15249,7 @@ package android.media {
method public int getMaxImages(); method public int getMaxImages();
method public android.view.Surface getSurface(); method public android.view.Surface getSurface();
method public int getWidth(); method public int getWidth();
method public boolean isOpaque();
method public static android.media.ImageReader newInstance(int, int, int, int); method public static android.media.ImageReader newInstance(int, int, int, int);
method public static android.media.ImageReader newOpaqueInstance(int, int, int);
method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler); method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
} }
@@ -15267,11 +15264,11 @@ package android.media {
method public int getMaxImages(); method public int getMaxImages();
method public static android.media.ImageWriter newInstance(android.view.Surface, int); method public static android.media.ImageWriter newInstance(android.view.Surface, int);
method public void queueInputImage(android.media.Image); method public void queueInputImage(android.media.Image);
method public void setImageListener(android.media.ImageWriter.ImageListener, android.os.Handler); method public void setOnImageReleasedListener(android.media.ImageWriter.OnImageReleasedListener, android.os.Handler);
} }
public static abstract interface ImageWriter.ImageListener { public static abstract interface ImageWriter.OnImageReleasedListener {
method public abstract void onInputImageReleased(android.media.ImageWriter); method public abstract void onImageReleased(android.media.ImageWriter);
} }
public class JetPlayer { public class JetPlayer {

View File

@@ -16467,7 +16467,6 @@ package android.media {
method public abstract android.media.Image.Plane[] getPlanes(); method public abstract android.media.Image.Plane[] getPlanes();
method public abstract long getTimestamp(); method public abstract long getTimestamp();
method public abstract int getWidth(); method public abstract int getWidth();
method public boolean isOpaque();
method public void setCropRect(android.graphics.Rect); method public void setCropRect(android.graphics.Rect);
method public void setTimestamp(long); method public void setTimestamp(long);
} }
@@ -16487,9 +16486,7 @@ package android.media {
method public int getMaxImages(); method public int getMaxImages();
method public android.view.Surface getSurface(); method public android.view.Surface getSurface();
method public int getWidth(); method public int getWidth();
method public boolean isOpaque();
method public static android.media.ImageReader newInstance(int, int, int, int); method public static android.media.ImageReader newInstance(int, int, int, int);
method public static android.media.ImageReader newOpaqueInstance(int, int, int);
method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler); method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
} }
@@ -16504,11 +16501,11 @@ package android.media {
method public int getMaxImages(); method public int getMaxImages();
method public static android.media.ImageWriter newInstance(android.view.Surface, int); method public static android.media.ImageWriter newInstance(android.view.Surface, int);
method public void queueInputImage(android.media.Image); method public void queueInputImage(android.media.Image);
method public void setImageListener(android.media.ImageWriter.ImageListener, android.os.Handler); method public void setOnImageReleasedListener(android.media.ImageWriter.OnImageReleasedListener, android.os.Handler);
} }
public static abstract interface ImageWriter.ImageListener { public static abstract interface ImageWriter.OnImageReleasedListener {
method public abstract void onInputImageReleased(android.media.ImageWriter); method public abstract void onImageReleased(android.media.ImageWriter);
} }
public class JetPlayer { public class JetPlayer {

View File

@@ -163,10 +163,12 @@ public abstract class Image implements AutoCloseable {
* Get the timestamp associated with this frame. * Get the timestamp associated with this frame.
* <p> * <p>
* The timestamp is measured in nanoseconds, and is normally monotonically * The timestamp is measured in nanoseconds, and is normally monotonically
* increasing. However, the behavior of the timestamp depends on the source * increasing. The timestamps for the images from different sources may have
* of this image. See {@link android.hardware.Camera Camera}, * different timebases therefore may not be comparable. The specific meaning and
* {@link android.hardware.camera2.CameraDevice CameraDevice}, {@link MediaPlayer} and * timebase of the timestamp depend on the source providing images. See
* {@link MediaCodec} for more details. * {@link android.hardware.Camera Camera},
* {@link android.hardware.camera2.CameraDevice CameraDevice},
* {@link MediaPlayer} and {@link MediaCodec} for more details.
* </p> * </p>
*/ */
public abstract long getTimestamp(); public abstract long getTimestamp();
@@ -175,9 +177,11 @@ public abstract class Image implements AutoCloseable {
* Set the timestamp associated with this frame. * Set the timestamp associated with this frame.
* <p> * <p>
* The timestamp is measured in nanoseconds, and is normally monotonically * The timestamp is measured in nanoseconds, and is normally monotonically
* increasing. However, the behavior of the timestamp depends on * increasing. The timestamps for the images from different sources may have
* the destination of this image. See {@link android.hardware.Camera Camera} * different timebases therefore may not be comparable. The specific meaning and
* , {@link android.hardware.camera2.CameraDevice CameraDevice}, * timebase of the timestamp depend on the source providing images. See
* {@link android.hardware.Camera Camera},
* {@link android.hardware.camera2.CameraDevice CameraDevice},
* {@link MediaPlayer} and {@link MediaCodec} for more details. * {@link MediaPlayer} and {@link MediaCodec} for more details.
* </p> * </p>
* <p> * <p>
@@ -195,18 +199,6 @@ public abstract class Image implements AutoCloseable {
return; return;
} }
/**
* <p>Check if the image is opaque.</p>
*
* <p>The pixel data of opaque images are not accessible to the application,
* and therefore {@link #getPlanes} will return an empty array for an opaque image.
* </p>
*/
public boolean isOpaque() {
throwISEIfImageIsInvalid();
return false;
}
private Rect mCropRect; private Rect mCropRect;
/** /**
@@ -243,10 +235,11 @@ public abstract class Image implements AutoCloseable {
/** /**
* Get the array of pixel planes for this Image. The number of planes is * Get the array of pixel planes for this Image. The number of planes is
* determined by the format of the Image. The application will get an * determined by the format of the Image. The application will get an empty
* empty array if the image is opaque because the opaque image pixel data * array if the image format is {@link android.graphics.ImageFormat#PRIVATE
* is not directly accessible. The application can check if an image is * PRIVATE}, because the image pixel data is not directly accessible. The
* opaque by calling {@link Image#isOpaque}. * application can check the image format by calling
* {@link Image#getFormat()}.
*/ */
public abstract Plane[] getPlanes(); public abstract Plane[] getPlanes();

View File

@@ -67,77 +67,46 @@ public class ImageReader implements AutoCloseable {
*/ */
private static final int ACQUIRE_MAX_IMAGES = 2; private static final int ACQUIRE_MAX_IMAGES = 2;
/**
* <p>Create a new reader for images of the desired size and format.</p>
*
* <p>The {@code maxImages} parameter determines the maximum number of {@link Image}
* objects that can be be acquired from the {@code ImageReader}
* simultaneously. Requesting more buffers will use up more memory, so it is
* important to use only the minimum number necessary for the use case.</p>
*
* <p>The valid sizes and formats depend on the source of the image
* data.</p>
*
* @param width
* The default width in pixels of the Images that this reader will produce.
* @param height
* The default height in pixels of the Images that this reader will produce.
* @param format
* The format of the Image that this reader will produce. This
* must be one of the {@link android.graphics.ImageFormat} or
* {@link android.graphics.PixelFormat} constants. Note that
* not all formats is supported, like ImageFormat.NV21.
* @param maxImages
* The maximum number of images the user will want to
* access simultaneously. This should be as small as possible to limit
* memory use. Once maxImages Images are obtained by the user, one of them
* has to be released before a new Image will become available for access
* through {@link #acquireLatestImage()} or {@link #acquireNextImage()}.
* Must be greater than 0.
*
* @see Image
*/
public static ImageReader newInstance(int width, int height, int format, int maxImages) {
if (format == ImageFormat.PRIVATE) {
throw new IllegalArgumentException("To obtain an opaque ImageReader, please use"
+ " newOpaqueInstance rather than newInstance");
}
return new ImageReader(width, height, format, maxImages);
}
/** /**
* <p> * <p>
* Create a new opaque reader for images of the desired size. * Create a new reader for images of the desired size and format.
* </p>
* <p>
* An opaque {@link ImageReader} produces images that are not directly
* accessible by the application. The application can still acquire images
* from an opaque image reader, and send them to the
* {@link android.hardware.camera2.CameraDevice camera} for reprocessing via
* {@link ImageWriter} interface. However, the {@link Image#getPlanes()
* getPlanes()} will return an empty array for opaque images. The
* application can check if an existing reader is an opaque reader by
* calling {@link #isOpaque()}.
* </p> * </p>
* <p> * <p>
* The {@code maxImages} parameter determines the maximum number of * The {@code maxImages} parameter determines the maximum number of
* {@link Image} objects that can be be acquired from the * {@link Image} objects that can be be acquired from the
* {@code ImageReader} simultaneously. Requesting more buffers will use up * {@code ImageReader} simultaneously. Requesting more buffers will use up
* more memory, so it is important to use only the minimum number necessary. * more memory, so it is important to use only the minimum number necessary
* for the use case.
* </p> * </p>
* <p> * <p>
* The valid sizes and formats depend on the source of the image data. * The valid sizes and formats depend on the source of the image data.
* </p> * </p>
* <p> * <p>
* Opaque ImageReaders are more efficient to use when application access to * If the {@code format} is {@link ImageFormat#PRIVATE PRIVATE}, the created
* image data is not necessary, compared to ImageReaders using a non-opaque * {@link ImageReader} will produce images that are not directly accessible
* format such as {@link ImageFormat#YUV_420_888 YUV_420_888}. * by the application. The application can still acquire images from this
* {@link ImageReader}, and send them to the
* {@link android.hardware.camera2.CameraDevice camera} for reprocessing via
* {@link ImageWriter} interface. However, the {@link Image#getPlanes()
* getPlanes()} will return an empty array for {@link ImageFormat#PRIVATE
* PRIVATE} format images. The application can check if an existing reader's
* format by calling {@link #getImageFormat()}.
* </p>
* <p>
* {@link ImageFormat#PRIVATE PRIVATE} format {@link ImageReader
* ImageReaders} are more efficient to use when application access to image
* data is not necessary, compared to ImageReaders using other format such
* as {@link ImageFormat#YUV_420_888 YUV_420_888}.
* </p> * </p>
* *
* @param width The default width in pixels of the Images that this reader * @param width The default width in pixels of the Images that this reader
* will produce. * will produce.
* @param height The default height in pixels of the Images that this reader * @param height The default height in pixels of the Images that this reader
* will produce. * will produce.
* @param format The format of the Image that this reader will produce. This
* must be one of the {@link android.graphics.ImageFormat} or
* {@link android.graphics.PixelFormat} constants. Note that not
* all formats are supported, like ImageFormat.NV21.
* @param maxImages The maximum number of images the user will want to * @param maxImages The maximum number of images the user will want to
* access simultaneously. This should be as small as possible to * access simultaneously. This should be as small as possible to
* limit memory use. Once maxImages Images are obtained by the * limit memory use. Once maxImages Images are obtained by the
@@ -147,8 +116,8 @@ public class ImageReader implements AutoCloseable {
* Must be greater than 0. * Must be greater than 0.
* @see Image * @see Image
*/ */
public static ImageReader newOpaqueInstance(int width, int height, int maxImages) { public static ImageReader newInstance(int width, int height, int format, int maxImages) {
return new ImageReader(width, height, ImageFormat.PRIVATE, maxImages); return new ImageReader(width, height, format, maxImages);
} }
/** /**
@@ -247,23 +216,6 @@ public class ImageReader implements AutoCloseable {
return mMaxImages; return mMaxImages;
} }
/**
* <p>
* Check if the {@link ImageReader} is an opaque reader.
* </p>
* <p>
* An opaque image reader produces opaque images, see {@link Image#isOpaque}
* for more details.
* </p>
*
* @return true if the ImageReader is opaque.
* @see Image#isOpaque
* @see ImageReader#newOpaqueInstance
*/
public boolean isOpaque() {
return mFormat == ImageFormat.PRIVATE;
}
/** /**
* <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this * <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
* {@code ImageReader}.</p> * {@code ImageReader}.</p>
@@ -540,11 +492,11 @@ public class ImageReader implements AutoCloseable {
* </p> * </p>
* <p> * <p>
* This method can be used to achieve zero buffer copy for use cases like * This method can be used to achieve zero buffer copy for use cases like
* {@link android.hardware.camera2.CameraDevice Camera2 API} OPAQUE and YUV * {@link android.hardware.camera2.CameraDevice Camera2 API} PRIVATE and YUV
* reprocessing, where the application can select an output image from * reprocessing, where the application can select an output image from
* {@link ImageReader} and transfer this image directly to * {@link ImageReader} and transfer this image directly to
* {@link ImageWriter}, where this image can be consumed by camera directly. * {@link ImageWriter}, where this image can be consumed by camera directly.
* For OPAQUE reprocessing, this is the only way to send input buffers to * For PRIVATE reprocessing, this is the only way to send input buffers to
* the {@link android.hardware.camera2.CameraDevice camera} for * the {@link android.hardware.camera2.CameraDevice camera} for
* reprocessing. * reprocessing.
* </p> * </p>
@@ -745,12 +697,6 @@ public class ImageReader implements AutoCloseable {
return mPlanes.clone(); return mPlanes.clone();
} }
@Override
public boolean isOpaque() {
throwISEIfImageIsInvalid();
return mFormat == ImageFormat.PRIVATE;
}
@Override @Override
protected final void finalize() throws Throwable { protected final void finalize() throws Throwable {
try { try {

View File

@@ -57,7 +57,7 @@ class ImageUtils {
case ImageFormat.RAW_SENSOR: case ImageFormat.RAW_SENSOR:
case ImageFormat.RAW10: case ImageFormat.RAW10:
return 1; return 1;
case PixelFormat.OPAQUE: case ImageFormat.PRIVATE:
return 0; return 0;
default: default:
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
@@ -70,10 +70,11 @@ class ImageUtils {
* Copy source image data to destination Image. * Copy source image data to destination Image.
* </p> * </p>
* <p> * <p>
* Only support the copy between two non-opaque images with same properties * Only support the copy between two non-{@link ImageFormat#PRIVATE PRIVATE} format
* (format, size, etc.). The data from the source image will be copied to * images with same properties (format, size, etc.). The data from the
* the byteBuffers from the destination Image starting from position zero, * source image will be copied to the byteBuffers from the destination Image
* and the destination image will be rewound to zero after copy is done. * starting from position zero, and the destination image will be rewound to
* zero after copy is done.
* </p> * </p>
* *
* @param src The source image to be copied from. * @param src The source image to be copied from.
@@ -88,8 +89,9 @@ class ImageUtils {
if (src.getFormat() != dst.getFormat()) { if (src.getFormat() != dst.getFormat()) {
throw new IllegalArgumentException("Src and dst images should have the same format"); throw new IllegalArgumentException("Src and dst images should have the same format");
} }
if (src.isOpaque() || dst.isOpaque()) { if (src.getFormat() == ImageFormat.PRIVATE ||
throw new IllegalArgumentException("Opaque image is not copyable"); dst.getFormat() == ImageFormat.PRIVATE) {
throw new IllegalArgumentException("PRIVATE format images are not copyable");
} }
if (!(dst.getOwner() instanceof ImageWriter)) { if (!(dst.getOwner() instanceof ImageWriter)) {
throw new IllegalArgumentException("Destination image is not from ImageWriter. Only" throw new IllegalArgumentException("Destination image is not from ImageWriter. Only"

View File

@@ -33,8 +33,8 @@ import java.util.List;
/** /**
* <p> * <p>
* The ImageWriter class allows an application to produce Image data into a * The ImageWriter class allows an application to produce Image data into a
* {@link android.view.Surface}, and have it be consumed by another component like * {@link android.view.Surface}, and have it be consumed by another component
* {@link android.hardware.camera2.CameraDevice CameraDevice}. * like {@link android.hardware.camera2.CameraDevice CameraDevice}.
* </p> * </p>
* <p> * <p>
* Several Android API classes can provide input {@link android.view.Surface * Several Android API classes can provide input {@link android.view.Surface
@@ -54,21 +54,21 @@ import java.util.List;
* <p> * <p>
* If the application already has an Image from {@link ImageReader}, the * If the application already has an Image from {@link ImageReader}, the
* application can directly queue this Image into ImageWriter (via * application can directly queue this Image into ImageWriter (via
* {@link #queueInputImage}), potentially with zero buffer copies. For the opaque * {@link #queueInputImage}), potentially with zero buffer copies. For the
* Images produced by an opaque ImageReader (created by * {@link ImageFormat#PRIVATE PRIVATE} format Images produced by
* {@link ImageReader#newOpaqueInstance}), this is the only way to send Image * {@link ImageReader}, this is the only way to send Image data to ImageWriter,
* data to ImageWriter, as the Image data aren't accessible by the application. * as the Image data aren't accessible by the application.
* </p> * </p>
* Once new input Images are queued into an ImageWriter, it's up to the downstream * Once new input Images are queued into an ImageWriter, it's up to the
* components (e.g. {@link ImageReader} or * downstream components (e.g. {@link ImageReader} or
* {@link android.hardware.camera2.CameraDevice}) to consume the Images. If the * {@link android.hardware.camera2.CameraDevice}) to consume the Images. If the
* downstream components cannot consume the Images at least as fast as the * downstream components cannot consume the Images at least as fast as the
* ImageWriter production rate, the {@link #dequeueInputImage} call will eventually * ImageWriter production rate, the {@link #dequeueInputImage} call will
* block and the application will have to drop input frames. </p> * eventually block and the application will have to drop input frames. </p>
*/ */
public class ImageWriter implements AutoCloseable { public class ImageWriter implements AutoCloseable {
private final Object mListenerLock = new Object(); private final Object mListenerLock = new Object();
private ImageListener mListener; private OnImageReleasedListener mListener;
private ListenerHandler mListenerHandler; private ListenerHandler mListenerHandler;
private long mNativeContext; private long mNativeContext;
@@ -168,32 +168,34 @@ public class ImageWriter implements AutoCloseable {
* This call will block if all available input images have been queued by * This call will block if all available input images have been queued by
* the application and the downstream consumer has not yet consumed any. * the application and the downstream consumer has not yet consumed any.
* When an Image is consumed by the downstream consumer and released, an * When an Image is consumed by the downstream consumer and released, an
* {@link ImageListener#onInputImageReleased} callback will be fired, which * {@link OnImageReleasedListener#onImageReleased} callback will be fired,
* indicates that there is one input Image available. For non-opaque formats * which indicates that there is one input Image available. For non-
* (({@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE})), it is * {@link ImageFormat#PRIVATE PRIVATE} formats (
* {@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE}), it is
* recommended to dequeue the next Image only after this callback is fired, * recommended to dequeue the next Image only after this callback is fired,
* in the steady state. * in the steady state.
* </p> * </p>
* <p> * <p>
* If the ImageWriter is opaque ({@link ImageWriter#getFormat()} == * If the format of ImageWriter is {@link ImageFormat#PRIVATE PRIVATE} (
* {@link ImageFormat#PRIVATE}), the image buffer is inaccessible to * {@link ImageWriter#getFormat()} == {@link ImageFormat#PRIVATE}), the
* the application, and calling this method will result in an * image buffer is inaccessible to the application, and calling this method
* {@link IllegalStateException}. Instead, the application should acquire * will result in an {@link IllegalStateException}. Instead, the application
* opaque images from some other component (e.g. an opaque * should acquire images from some other component (e.g. an
* {@link ImageReader}), and queue them directly to this ImageWriter via the * {@link ImageReader}), and queue them directly to this ImageWriter via the
* {@link ImageWriter#queueInputImage queueInputImage()} method. * {@link ImageWriter#queueInputImage queueInputImage()} method.
* </p> * </p>
* *
* @return The next available input Image from this ImageWriter. * @return The next available input Image from this ImageWriter.
* @throws IllegalStateException if {@code maxImages} Images are currently * @throws IllegalStateException if {@code maxImages} Images are currently
* dequeued, or the ImageWriter is opaque. * dequeued, or the ImageWriter format is
* {@link ImageFormat#PRIVATE PRIVATE}.
* @see #queueInputImage * @see #queueInputImage
* @see Image#close * @see Image#close
*/ */
public Image dequeueInputImage() { public Image dequeueInputImage() {
if (mWriterFormat == ImageFormat.PRIVATE) { if (mWriterFormat == ImageFormat.PRIVATE) {
throw new IllegalStateException( throw new IllegalStateException(
"Opaque ImageWriter doesn't support this operation since opaque images are" "PRIVATE format ImageWriter doesn't support this operation since the images are"
+ " inaccessible to the application!"); + " inaccessible to the application!");
} }
@@ -229,10 +231,10 @@ public class ImageWriter implements AutoCloseable {
* </p> * </p>
* <p> * <p>
* After this method is called and the downstream consumer consumes and * After this method is called and the downstream consumer consumes and
* releases the Image, an {@link ImageListener#onInputImageReleased * releases the Image, an {@link OnImageReleasedListener#onImageReleased}
* onInputImageReleased()} callback will fire. The application can use this * callback will fire. The application can use this callback to avoid
* callback to avoid sending Images faster than the downstream consumer * sending Images faster than the downstream consumer processing rate in
* processing rate in steady state. * steady state.
* </p> * </p>
* <p> * <p>
* Passing in an Image from some other component (e.g. an * Passing in an Image from some other component (e.g. an
@@ -271,12 +273,12 @@ public class ImageWriter implements AutoCloseable {
} }
ImageReader prevOwner = (ImageReader) image.getOwner(); ImageReader prevOwner = (ImageReader) image.getOwner();
// Only do the image attach for opaque images for now. Do the image // Only do the image attach for PRIVATE format images for now. Do the image
// copy for other formats. TODO: use attach for other formats to // copy for other formats. TODO: use attach for other formats to
// improve the performance, and fall back to copy when attach/detach // improve the performance, and fall back to copy when attach/detach
// fails. Right now, detach is guaranteed to fail as the buffer is // fails. Right now, detach is guaranteed to fail as the buffer is
// locked when ImageReader#acquireNextImage is called. See bug 19962027. // locked when ImageReader#acquireNextImage is called. See bug 19962027.
if (image.isOpaque()) { if (image.getFormat() == ImageFormat.PRIVATE) {
prevOwner.detachImage(image); prevOwner.detachImage(image);
attachAndQueueInputImage(image); attachAndQueueInputImage(image);
// This clears the native reference held by the original owner. // This clears the native reference held by the original owner.
@@ -319,8 +321,9 @@ public class ImageWriter implements AutoCloseable {
* Get the ImageWriter format. * Get the ImageWriter format.
* <p> * <p>
* This format may be different than the Image format returned by * This format may be different than the Image format returned by
* {@link Image#getFormat()}. However, if the ImageWriter is opaque (format * {@link Image#getFormat()}. However, if the ImageWriter format is
* == {@link ImageFormat#PRIVATE}) , the images from it will also be opaque. * {@link ImageFormat#PRIVATE PRIVATE}, calling {@link #dequeueInputImage()}
* will result in an {@link IllegalStateException}.
* </p> * </p>
* *
* @return The ImageWriter format. * @return The ImageWriter format.
@@ -333,7 +336,7 @@ public class ImageWriter implements AutoCloseable {
* ImageWriter callback interface, used to to asynchronously notify the * ImageWriter callback interface, used to to asynchronously notify the
* application of various ImageWriter events. * application of various ImageWriter events.
*/ */
public interface ImageListener { public interface OnImageReleasedListener {
/** /**
* <p> * <p>
* Callback that is called when an input Image is released back to * Callback that is called when an input Image is released back to
@@ -361,7 +364,7 @@ public class ImageWriter implements AutoCloseable {
* @see ImageWriter * @see ImageWriter
* @see Image * @see Image
*/ */
void onInputImageReleased(ImageWriter writer); void onImageReleased(ImageWriter writer);
} }
/** /**
@@ -375,7 +378,7 @@ public class ImageWriter implements AutoCloseable {
* @throws IllegalArgumentException If no handler specified and the calling * @throws IllegalArgumentException If no handler specified and the calling
* thread has no looper. * thread has no looper.
*/ */
public void setImageListener(ImageListener listener, Handler handler) { public void setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler) {
synchronized (mListenerLock) { synchronized (mListenerLock) {
if (listener != null) { if (listener != null) {
Looper looper = handler != null ? handler.getLooper() : Looper.myLooper(); Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
@@ -408,7 +411,7 @@ public class ImageWriter implements AutoCloseable {
*/ */
@Override @Override
public void close() { public void close() {
setImageListener(null, null); setOnImageReleasedListener(null, null);
for (Image image : mDequeuedImages) { for (Image image : mDequeuedImages) {
image.close(); image.close();
} }
@@ -431,19 +434,18 @@ public class ImageWriter implements AutoCloseable {
* Attach and queue input Image to this ImageWriter. * Attach and queue input Image to this ImageWriter.
* </p> * </p>
* <p> * <p>
* When an Image is from an opaque source (e.g. an opaque ImageReader * When the format of an Image is {@link ImageFormat#PRIVATE PRIVATE}, or
* created by {@link ImageReader#newOpaqueInstance}), or the source Image is * the source Image is so large that copying its data is too expensive, this
* so large that copying its data is too expensive, this method can be used * method can be used to migrate the source Image into ImageWriter without a
* to migrate the source Image into ImageWriter without a data copy, and * data copy, and then queue it to this ImageWriter. The source Image must
* then queue it to this ImageWriter. The source Image must be detached from * be detached from its previous owner already, or this call will throw an
* its previous owner already, or this call will throw an
* {@link IllegalStateException}. * {@link IllegalStateException}.
* </p> * </p>
* <p> * <p>
* After this call, the ImageWriter takes ownership of this Image. This * After this call, the ImageWriter takes ownership of this Image. This
* ownership will automatically be removed from this writer after the * ownership will automatically be removed from this writer after the
* consumer releases this Image, that is, after * consumer releases this Image, that is, after
* {@link ImageListener#onInputImageReleased}. The caller is responsible for * {@link OnImageReleasedListener#onImageReleased}. The caller is responsible for
* closing this Image through {@link Image#close()} to free up the resources * closing this Image through {@link Image#close()} to free up the resources
* held by this Image. * held by this Image.
* </p> * </p>
@@ -492,12 +494,12 @@ public class ImageWriter implements AutoCloseable {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
ImageListener listener; OnImageReleasedListener listener;
synchronized (mListenerLock) { synchronized (mListenerLock) {
listener = mListener; listener = mListener;
} }
if (listener != null) { if (listener != null) {
listener.onInputImageReleased(ImageWriter.this); listener.onImageReleased(ImageWriter.this);
} }
} }
} }
@@ -646,13 +648,6 @@ public class ImageWriter implements AutoCloseable {
mTimestamp = timestamp; mTimestamp = timestamp;
} }
@Override
public boolean isOpaque() {
throwISEIfImageIsInvalid();
return getFormat() == ImageFormat.PRIVATE;
}
@Override @Override
public Plane[] getPlanes() { public Plane[] getPlanes() {
throwISEIfImageIsInvalid(); throwISEIfImageIsInvalid();