From 916d8ac650865cd05808d48bad68b69bebbc95ab Mon Sep 17 00:00:00 2001
From: Zhijun He
* Create a new reader for images of the desired size and format.
@@ -121,13 +129,104 @@ public class ImageReader implements AutoCloseable {
* @see Image
*/
public static ImageReader newInstance(int width, int height, int format, int maxImages) {
- return new ImageReader(width, height, format, maxImages);
+ return new ImageReader(width, height, format, maxImages, BUFFER_USAGE_UNKNOWN);
+ }
+
+ /**
+ *
+ * Create a new reader for images of the desired size, format and consumer usage flag.
+ *
+ * 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.
+ *
+ * The valid sizes and formats depend on the source of the image data.
+ *
+ * The format and usage flag combination describes how the buffer will be used by
+ * consumer end-points. For example, if the application intends to send the images to
+ * {@link android.media.MediaCodec} or {@link android.media.MediaRecorder} for hardware video
+ * encoding, the format and usage flag combination needs to be
+ * {@link ImageFormat#PRIVATE PRIVATE} and {@link HardwareBuffer#USAGE0_VIDEO_ENCODE}. When an
+ * {@link ImageReader} object is created with a valid size and such format/usage flag
+ * combination, the application can send the {@link Image images} to an {@link ImageWriter} that
+ * is created with the input {@link android.view.Surface} provided by the
+ * {@link android.media.MediaCodec} or {@link android.media.MediaRecorder}.
+ *
+ * If the {@code format} is {@link ImageFormat#PRIVATE PRIVATE}, the created {@link ImageReader}
+ * will produce images that are not directly accessible 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, or to the
+ * {@link android.media.MediaCodec} / {@link android.media.MediaRecorder} for hardware video
+ * encoding 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()}.
+ *
+ * {@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}.
+ *
+ * Note that not all format and usage flag combination is supported by the
+ * {@link ImageReader}. Below are the supported combinations by the {@link ImageReader}
+ * (assuming the consumer end-points support the such image consumption, e.g., hardware video
+ * encoding).
+ *
+ *
+ * Using other combinations may result in {@link IllegalArgumentException}.
+ *
+ *
+ * Format
+ * Compatible usage flags
+ *
+ *
+ * non-{@link android.graphics.ImageFormat#PRIVATE PRIVATE} formats defined by
+ * {@link android.graphics.ImageFormat ImageFormat} or
+ * {@link android.graphics.PixelFormat PixelFormat}
+ * {@link HardwareBuffer#USAGE0_CPU_READ} or
+ * {@link HardwareBuffer#USAGE0_CPU_READ_OFTEN}
+ *
+ *
+ * {@link android.graphics.ImageFormat#PRIVATE}
+ * {@link HardwareBuffer#USAGE0_VIDEO_ENCODE} or
+ * {@link HardwareBuffer#USAGE0_GPU_SAMPLED_IMAGE}, or combined
+ *
+ * Create a new ImageWriter with given number of max Images and format. + *
+ *+ * The {@code maxImages} parameter determines the maximum number of + * {@link Image} objects that can be be dequeued from the + * {@code ImageWriter} simultaneously. Requesting more buffers will use up + * more memory, so it is important to use only the minimum number necessary. + *
+ *+ * The format specifies the image format of this ImageWriter. The format + * from the {@code surface} will be overridden with this format. For example, + * if the surface is obtained from a {@link android.graphics.SurfaceTexture}, the default + * format may be {@link PixelFormat#RGBA_8888}. If the application creates an ImageWriter + * with this surface and {@link ImageFormat#PRIVATE}, this ImageWriter will be able to operate + * with {@link ImageFormat#PRIVATE} Images. + *
+ *+ * Note that the consumer end-point may or may not be able to support Images with different + * format, for such case, the application should only use this method if the consumer is able + * to consume such images. + *
+ *+ * The input Image size depends on the Surface that is provided by + * the downstream consumer end-point. + *
+ * + * @param surface The destination Surface this writer produces Image data + * into. + * @param 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 + * {@link #dequeueInputImage()}. + * @param format The format of this ImageWriter. It can be any valid format specified by + * {@link ImageFormat} or {@link PixelFormat}. + * + * @return a new ImageWriter instance. + * @hide + */ + public static ImageWriter newInstance(Surface surface, int maxImages, int format) { + if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) { + throw new IllegalArgumentException("Invalid format is specified: " + format); + } + return new ImageWriter(surface, maxImages, format); } /** * @hide */ - protected ImageWriter(Surface surface, int maxImages) { + protected ImageWriter(Surface surface, int maxImages, int format) { if (surface == null || maxImages < 1) { throw new IllegalArgumentException("Illegal input argument: surface " + surface + ", maxImages: " + maxImages); } mMaxImages = maxImages; + + if (format == ImageFormat.UNKNOWN) { + format = SurfaceUtils.getSurfaceFormat(surface); + } // Note that the underlying BufferQueue is working in synchronous mode // to avoid dropping any buffers. - mNativeContext = nativeInit(new WeakReference