* commit 'ff7042481a08a9b109be72982c9e38220c1262f5': Image/Reader/Writer: address API review comments
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user