Merge "Introduce Builder in ImageReader class for setup and construct an ImageReader instance."
This commit is contained in:
@@ -21897,16 +21897,29 @@ package android.media {
|
||||
method public android.media.Image acquireNextImage();
|
||||
method public void close();
|
||||
method public void discardFreeBuffers();
|
||||
method public long getDataSpace();
|
||||
method public int getHardwareBufferFormat();
|
||||
method public int getHeight();
|
||||
method public int getImageFormat();
|
||||
method public int getMaxImages();
|
||||
method public android.view.Surface getSurface();
|
||||
method public long getUsage();
|
||||
method public int getWidth();
|
||||
method @NonNull public static android.media.ImageReader newInstance(@IntRange(from=1) int, @IntRange(from=1) int, int, @IntRange(from=1) int);
|
||||
method @NonNull public static android.media.ImageReader newInstance(@IntRange(from=1) int, @IntRange(from=1) int, int, @IntRange(from=1) int, long);
|
||||
method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
|
||||
}
|
||||
|
||||
public static final class ImageReader.Builder {
|
||||
ctor public ImageReader.Builder(@IntRange(from=1) int, @IntRange(from=1) int);
|
||||
method @NonNull public android.media.ImageReader build();
|
||||
method @NonNull public android.media.ImageReader.Builder setDefaultDataSpace(long);
|
||||
method @NonNull public android.media.ImageReader.Builder setDefaultHardwareBufferFormat(int);
|
||||
method @NonNull public android.media.ImageReader.Builder setImageFormat(int);
|
||||
method @NonNull public android.media.ImageReader.Builder setMaxImages(int);
|
||||
method @NonNull public android.media.ImageReader.Builder setUsage(long);
|
||||
}
|
||||
|
||||
public static interface ImageReader.OnImageAvailableListener {
|
||||
method public void onImageAvailable(android.media.ImageReader);
|
||||
}
|
||||
|
||||
@@ -18,10 +18,13 @@ package android.media;
|
||||
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.ImageFormat.Format;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.DataSpace;
|
||||
import android.hardware.DataSpace.NamedDataSpace;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.hardware.HardwareBuffer.Usage;
|
||||
import android.hardware.camera2.MultiResolutionImageReader;
|
||||
@@ -136,8 +139,7 @@ public class ImageReader implements AutoCloseable {
|
||||
// If the format is private don't default to USAGE_CPU_READ_OFTEN since it may not
|
||||
// work, and is inscrutable anyway
|
||||
return new ImageReader(width, height, format, maxImages,
|
||||
format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN,
|
||||
/*parent*/ null);
|
||||
format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,44 +270,32 @@ public class ImageReader implements AutoCloseable {
|
||||
// If the format is private don't default to USAGE_CPU_READ_OFTEN since it may not
|
||||
// work, and is inscrutable anyway
|
||||
return new ImageReader(width, height, format, maxImages,
|
||||
format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN,
|
||||
parent);
|
||||
format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN, parent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
protected ImageReader(int width, int height, int format, int maxImages, long usage,
|
||||
MultiResolutionImageReader parent) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mFormat = format;
|
||||
mUsage = usage;
|
||||
mMaxImages = maxImages;
|
||||
mParent = parent;
|
||||
|
||||
private void initializeImageReader(int width, int height, int imageFormat, int maxImages,
|
||||
long usage, int hardwareBufferFormat, long dataSpace, boolean useLegacyImageFormat) {
|
||||
if (width < 1 || height < 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"The image dimensions must be positive");
|
||||
}
|
||||
if (mMaxImages < 1) {
|
||||
|
||||
if (maxImages < 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"Maximum outstanding image count must be at least 1");
|
||||
}
|
||||
|
||||
if (format == ImageFormat.NV21) {
|
||||
if (imageFormat == ImageFormat.NV21) {
|
||||
throw new IllegalArgumentException(
|
||||
"NV21 format is not supported");
|
||||
"NV21 format is not supported");
|
||||
}
|
||||
|
||||
mNumPlanes = ImageUtils.getNumPlanesForFormat(mFormat);
|
||||
|
||||
nativeInit(new WeakReference<>(this), width, height, format, maxImages, usage);
|
||||
|
||||
mSurface = nativeGetSurface();
|
||||
nativeInit(new WeakReference<>(this), width, height, maxImages, usage,
|
||||
hardwareBufferFormat, dataSpace);
|
||||
|
||||
mIsReaderValid = true;
|
||||
|
||||
mSurface = nativeGetSurface();
|
||||
// Estimate the native buffer allocation size and register it so it gets accounted for
|
||||
// during GC. Note that this doesn't include the buffers required by the buffer queue
|
||||
// itself and the buffers requested by the producer.
|
||||
@@ -313,10 +303,46 @@ public class ImageReader implements AutoCloseable {
|
||||
// complex, and 1 buffer is enough for the VM to treat the ImageReader as being of some
|
||||
// size.
|
||||
mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
|
||||
width, height, format, /*buffer count*/ 1);
|
||||
width, height, useLegacyImageFormat ? imageFormat : hardwareBufferFormat,
|
||||
/*buffer count*/ 1);
|
||||
VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
|
||||
}
|
||||
|
||||
private ImageReader(int width, int height, int imageFormat, int maxImages, long usage,
|
||||
MultiResolutionImageReader parent) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mFormat = imageFormat;
|
||||
mUsage = usage;
|
||||
mMaxImages = maxImages;
|
||||
mParent = parent;
|
||||
// retrieve hal Format and hal dataspace from imageFormat
|
||||
mHardwareBufferFormat = PublicFormatUtils.getHalFormat(mFormat);
|
||||
mDataSpace = PublicFormatUtils.getHalDataspace(mFormat);
|
||||
mUseLegacyImageFormat = true;
|
||||
mNumPlanes = ImageUtils.getNumPlanesForFormat(mFormat);
|
||||
|
||||
initializeImageReader(width, height, imageFormat, maxImages, usage, mHardwareBufferFormat,
|
||||
mDataSpace, mUseLegacyImageFormat);
|
||||
}
|
||||
|
||||
private ImageReader(int width, int height, int maxImages, long usage,
|
||||
MultiResolutionImageReader parent, int hardwareBufferFormat, long dataSpace) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mFormat = ImageFormat.UNKNOWN; // set default image format value as UNKNOWN
|
||||
mUsage = usage;
|
||||
mMaxImages = maxImages;
|
||||
mParent = parent;
|
||||
mHardwareBufferFormat = hardwareBufferFormat;
|
||||
mDataSpace = dataSpace;
|
||||
mUseLegacyImageFormat = false;
|
||||
mNumPlanes = ImageUtils.getNumPlanesForHardwareBufferFormat(mHardwareBufferFormat);
|
||||
|
||||
initializeImageReader(width, height, mFormat, maxImages, usage, hardwareBufferFormat,
|
||||
dataSpace, mUseLegacyImageFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default width of {@link Image Images}, in pixels.
|
||||
*
|
||||
@@ -354,6 +380,10 @@ public class ImageReader implements AutoCloseable {
|
||||
* As of now, each format is only compatible to itself.
|
||||
* The actual format of the images can be found using {@link Image#getFormat}.</p>
|
||||
*
|
||||
* <p>Use this function if the ImageReader instance is created by factory method
|
||||
* {@code newInstance} function or by builder pattern {@code ImageReader.Builder} and using
|
||||
* {@link Builder#setImageFormat}.</p>
|
||||
*
|
||||
* @return the expected format of an Image
|
||||
*
|
||||
* @see ImageFormat
|
||||
@@ -362,6 +392,32 @@ public class ImageReader implements AutoCloseable {
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default {@link HardwareBuffer} format of {@link Image Images}.
|
||||
*
|
||||
* <p>Use this function if the ImageReader instance is created by builder pattern
|
||||
* {@code ImageReader.Builder} and using {@link Builder#setDefaultHardwareBufferFormat} and
|
||||
* {@link Builder#setDefaultDataSpace}.</p>
|
||||
*
|
||||
* @return the expected {@link HardwareBuffer} format of an Image.
|
||||
*/
|
||||
public @HardwareBuffer.Format int getHardwareBufferFormat() {
|
||||
return mHardwareBufferFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default dataspace of {@link Image Images}.
|
||||
*
|
||||
* <p>Use this function if the ImageReader instance is created by builder pattern
|
||||
* {@code ImageReader.Builder} and {@link Builder#setDefaultDataSpace}.</p>
|
||||
*
|
||||
* @return the expected dataspace of an Image.
|
||||
*/
|
||||
@SuppressLint("MethodNameUnits")
|
||||
public @NamedDataSpace long getDataSpace() {
|
||||
return mDataSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum number of images that can be acquired from the ImageReader by any time (for example,
|
||||
* with {@link #acquireNextImage}).
|
||||
@@ -383,6 +439,15 @@ public class ImageReader implements AutoCloseable {
|
||||
return mMaxImages;
|
||||
}
|
||||
|
||||
/**
|
||||
* The usage flag of images that can be produced by the ImageReader.
|
||||
*
|
||||
* @return The usage flag of the images for this ImageReader.
|
||||
*/
|
||||
public @Usage long getUsage() {
|
||||
return mUsage;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
|
||||
* {@code ImageReader}.</p>
|
||||
@@ -469,7 +534,12 @@ public class ImageReader implements AutoCloseable {
|
||||
* @hide
|
||||
*/
|
||||
public Image acquireNextImageNoThrowISE() {
|
||||
SurfaceImage si = new SurfaceImage(mFormat);
|
||||
SurfaceImage si;
|
||||
if (mUseLegacyImageFormat) {
|
||||
si = new SurfaceImage(mFormat);
|
||||
} else {
|
||||
si = new SurfaceImage(mHardwareBufferFormat, mDataSpace);
|
||||
}
|
||||
return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
|
||||
}
|
||||
|
||||
@@ -492,7 +562,7 @@ public class ImageReader implements AutoCloseable {
|
||||
// A null image will eventually be returned if ImageReader is already closed.
|
||||
int status = ACQUIRE_NO_BUFS;
|
||||
if (mIsReaderValid) {
|
||||
status = nativeImageSetup(si);
|
||||
status = nativeImageSetup(si, mUseLegacyImageFormat);
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
@@ -545,7 +615,12 @@ public class ImageReader implements AutoCloseable {
|
||||
public Image acquireNextImage() {
|
||||
// Initialize with reader format, but can be overwritten by native if the image
|
||||
// format is different from the reader format.
|
||||
SurfaceImage si = new SurfaceImage(mFormat);
|
||||
SurfaceImage si;
|
||||
if (mUseLegacyImageFormat) {
|
||||
si = new SurfaceImage(mFormat);
|
||||
} else {
|
||||
si = new SurfaceImage(mHardwareBufferFormat, mDataSpace);
|
||||
}
|
||||
int status = acquireNextSurfaceImage(si);
|
||||
|
||||
switch (status) {
|
||||
@@ -838,13 +913,161 @@ public class ImageReader implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for {@link ImageReader} objects.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private int mMaxImages = 1;
|
||||
private int mImageFormat = ImageFormat.UNKNOWN;
|
||||
private int mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
|
||||
private long mDataSpace = DataSpace.DATASPACE_UNKNOWN;
|
||||
private long mUsage = HardwareBuffer.USAGE_CPU_READ_OFTEN;
|
||||
private boolean mUseLegacyImageFormat = false;
|
||||
|
||||
/**
|
||||
* Constructs a new builder for {@link ImageReader}.
|
||||
*
|
||||
* @param width The default width in pixels that will be passed to the producer.
|
||||
* May be overridden by the producer.
|
||||
* @param height The default height in pixels that will be passed to the producer.
|
||||
* May be overridden by the producer.
|
||||
* @see Image
|
||||
*/
|
||||
public Builder(@IntRange(from = 1) int width, @IntRange(from = 1) int height) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximal number of images.
|
||||
*
|
||||
* @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. Default value is 1.
|
||||
* @return the Builder instance with customized usage value.
|
||||
*/
|
||||
public @NonNull Builder setMaxImages(int maxImages) {
|
||||
mMaxImages = maxImages;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the consumer usage flag.
|
||||
*
|
||||
* @param usage The intended usage of the images consumed by this ImageReader.
|
||||
* See the usages on {@link HardwareBuffer} for a list of valid usage bits.
|
||||
* Default value is {@link HardwareBuffer#USAGE_CPU_READ_OFTEN}.
|
||||
* @return the Builder instance with customized usage value.
|
||||
*
|
||||
* @see HardwareBuffer
|
||||
*/
|
||||
public @NonNull Builder setUsage(long usage) {
|
||||
mUsage = usage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default image format passed by the producer. May be overridden by the producer.
|
||||
*
|
||||
* <p>{@link #setImageFormat} function replaces the combination of
|
||||
* {@link #setDefaultHardwareBufferFormat} and {@link #setDefaultDataSpace} functions.
|
||||
* Either this or these two functions must be called to initialize an {@code ImageReader}
|
||||
* instance.</p>
|
||||
*
|
||||
* @param imageFormat 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. The default value is
|
||||
* {@link ImageFormat#UNKNOWN}.
|
||||
* @return the builder instance with customized image format value.
|
||||
*
|
||||
* @see #setDefaultHardwareBufferFormat
|
||||
* @see #setDefaultDataSpace
|
||||
*/
|
||||
public @NonNull Builder setImageFormat(@Format int imageFormat) {
|
||||
mImageFormat = imageFormat;
|
||||
mUseLegacyImageFormat = true;
|
||||
mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
|
||||
mDataSpace = DataSpace.DATASPACE_UNKNOWN;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default hardwareBuffer format passed by the producer.
|
||||
* May be overridden by the producer.
|
||||
*
|
||||
* <p>This function works together with {@link #setDefaultDataSpace} for an
|
||||
* {@link ImageReader} instance. Setting at least one of these two replaces
|
||||
* {@link #setImageFormat} function.</p>
|
||||
*
|
||||
* <p>The format of the Image can be overridden after {@link #setImageFormat} by calling
|
||||
* this function and then {@link #setDefaultDataSpace} functions.
|
||||
* <i>Warning:</i> Missing one of callings for initializing or overriding the format may
|
||||
* involve undefined behaviors.</p>
|
||||
*
|
||||
* @param hardwareBufferFormat The HardwareBuffer format of the image that this reader
|
||||
* will produce. The default value is
|
||||
* {@link HardwareBuffer#RGBA_8888 HardwareBuffer.RGBA_8888}.
|
||||
* @return the builder instance with customized hardwareBuffer value.
|
||||
*
|
||||
* @see #setDefaultDataSpace
|
||||
* @see #setImageFormat
|
||||
*/
|
||||
@SuppressLint("MissingGetterMatchingBuilder")
|
||||
public @NonNull Builder setDefaultHardwareBufferFormat(
|
||||
@HardwareBuffer.Format int hardwareBufferFormat) {
|
||||
mHardwareBufferFormat = hardwareBufferFormat;
|
||||
mUseLegacyImageFormat = false;
|
||||
mImageFormat = ImageFormat.UNKNOWN;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default dataspace passed by the producer.
|
||||
* May be overridden by the producer.
|
||||
*
|
||||
* <p>This function works together with {@link #setDefaultHardwareBufferFormat} for an
|
||||
* {@link ImageReader} instance. Setting at least one of these two replaces
|
||||
* {@link #setImageFormat} function.</p>
|
||||
*
|
||||
* @param dataSpace The dataspace of the image that this reader will produce.
|
||||
* The default value is {@link DataSpace#DATASPACE_UNKNOWN}.
|
||||
* @return the builder instance with customized dataspace value.
|
||||
*
|
||||
* @see #setDefaultHardwareBufferFormat
|
||||
*/
|
||||
@SuppressLint("MissingGetterMatchingBuilder")
|
||||
public @NonNull Builder setDefaultDataSpace(@NamedDataSpace long dataSpace) {
|
||||
mDataSpace = dataSpace;
|
||||
mUseLegacyImageFormat = false;
|
||||
mImageFormat = ImageFormat.UNKNOWN;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new ImageReader object.
|
||||
*
|
||||
* @return The new ImageReader object.
|
||||
*/
|
||||
public @NonNull ImageReader build() {
|
||||
if (mUseLegacyImageFormat) {
|
||||
return new ImageReader(mWidth, mHeight, mImageFormat, mMaxImages, mUsage, null);
|
||||
} else {
|
||||
return new ImageReader(mWidth, mHeight, mMaxImages, mUsage, null,
|
||||
mHardwareBufferFormat, mDataSpace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final int mWidth;
|
||||
private final int mHeight;
|
||||
private final int mFormat;
|
||||
private final long mUsage;
|
||||
private final int mMaxImages;
|
||||
private final int mNumPlanes;
|
||||
private final Surface mSurface;
|
||||
private Surface mSurface;
|
||||
private int mEstimatedNativeAllocBytes;
|
||||
|
||||
private final Object mListenerLock = new Object();
|
||||
@@ -861,6 +1084,12 @@ public class ImageReader implements AutoCloseable {
|
||||
// MultiResolutionImageReader.
|
||||
private final MultiResolutionImageReader mParent;
|
||||
|
||||
private final int mHardwareBufferFormat;
|
||||
|
||||
private final long mDataSpace;
|
||||
|
||||
private final boolean mUseLegacyImageFormat;
|
||||
|
||||
/**
|
||||
* This field is used by native code, do not access or modify.
|
||||
*/
|
||||
@@ -897,6 +1126,12 @@ public class ImageReader implements AutoCloseable {
|
||||
mFormat = format;
|
||||
}
|
||||
|
||||
SurfaceImage(int hardwareBufferFormat, long dataSpace) {
|
||||
mHardwareBufferFormat = hardwareBufferFormat;
|
||||
mDataSpace = dataSpace;
|
||||
mFormat = PublicFormatUtils.getPublicFormat(mHardwareBufferFormat, mDataSpace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
ImageReader.this.releaseImage(this);
|
||||
@@ -909,10 +1144,15 @@ public class ImageReader implements AutoCloseable {
|
||||
@Override
|
||||
public int getFormat() {
|
||||
throwISEIfImageIsInvalid();
|
||||
int readerFormat = ImageReader.this.getImageFormat();
|
||||
// Assume opaque reader always produce opaque images.
|
||||
mFormat = (readerFormat == ImageFormat.PRIVATE) ? readerFormat :
|
||||
nativeGetFormat(readerFormat);
|
||||
// update mFormat only if ImageReader is initialized by factory pattern.
|
||||
// if using builder pattern, mFormat has been updated upon initialization.
|
||||
// no need update here.
|
||||
if (ImageReader.this.mUseLegacyImageFormat) {
|
||||
int readerFormat = ImageReader.this.getImageFormat();
|
||||
// Assume opaque reader always produce opaque images.
|
||||
mFormat = (readerFormat == ImageFormat.PRIVATE) ? readerFormat :
|
||||
nativeGetFormat(readerFormat);
|
||||
}
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
@@ -1125,6 +1365,8 @@ public class ImageReader implements AutoCloseable {
|
||||
|
||||
private SurfacePlane[] mPlanes;
|
||||
private int mFormat = ImageFormat.UNKNOWN;
|
||||
private int mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
|
||||
private long mDataSpace = DataSpace.DATASPACE_UNKNOWN;
|
||||
// If this image is detached from the ImageReader.
|
||||
private AtomicBoolean mIsDetached = new AtomicBoolean(false);
|
||||
|
||||
@@ -1137,8 +1379,8 @@ public class ImageReader implements AutoCloseable {
|
||||
private synchronized native HardwareBuffer nativeGetHardwareBuffer();
|
||||
}
|
||||
|
||||
private synchronized native void nativeInit(Object weakSelf, int w, int h,
|
||||
int fmt, int maxImgs, long consumerUsage);
|
||||
private synchronized native void nativeInit(Object weakSelf, int w, int h, int maxImgs,
|
||||
long consumerUsage, int hardwareBufferFormat, long dataSpace);
|
||||
private synchronized native void nativeClose();
|
||||
private synchronized native void nativeReleaseImage(Image i);
|
||||
private synchronized native Surface nativeGetSurface();
|
||||
@@ -1152,7 +1394,7 @@ public class ImageReader implements AutoCloseable {
|
||||
* @see #ACQUIRE_NO_BUFS
|
||||
* @see #ACQUIRE_MAX_IMAGES
|
||||
*/
|
||||
private synchronized native int nativeImageSetup(Image i);
|
||||
private synchronized native int nativeImageSetup(Image i, boolean legacyValidateImageFormat);
|
||||
|
||||
/**
|
||||
* @hide
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.media;
|
||||
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.media.Image.Plane;
|
||||
import android.util.Size;
|
||||
|
||||
@@ -76,6 +77,34 @@ class ImageUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only a subset of the formats defined in
|
||||
* {@link android.graphics.HardwareBuffer.Format} constants are supported by ImageReader.
|
||||
*/
|
||||
public static int getNumPlanesForHardwareBufferFormat(int hardwareBufferFormat) {
|
||||
switch(hardwareBufferFormat) {
|
||||
case HardwareBuffer.YCBCR_420_888:
|
||||
return 3;
|
||||
case HardwareBuffer.RGBA_8888:
|
||||
case HardwareBuffer.RGBX_8888:
|
||||
case HardwareBuffer.RGB_888:
|
||||
case HardwareBuffer.RGB_565:
|
||||
case HardwareBuffer.RGBA_FP16:
|
||||
case HardwareBuffer.RGBA_1010102:
|
||||
case HardwareBuffer.BLOB:
|
||||
case HardwareBuffer.D_16:
|
||||
case HardwareBuffer.D_24:
|
||||
case HardwareBuffer.DS_24UI8:
|
||||
case HardwareBuffer.D_FP32:
|
||||
case HardwareBuffer.DS_FP32UI8:
|
||||
case HardwareBuffer.S_UI8:
|
||||
return 1;
|
||||
default:
|
||||
throw new UnsupportedOperationException(
|
||||
String.format("Invalid hardwareBuffer format specified %d",
|
||||
hardwareBufferFormat));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* <p>
|
||||
* Copy source image data to destination Image.
|
||||
|
||||
34
media/java/android/media/PublicFormatUtils.java
Normal file
34
media/java/android/media/PublicFormatUtils.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.media;
|
||||
|
||||
/**
|
||||
* Package private utility class for PublicFormat related methods.
|
||||
*/
|
||||
class PublicFormatUtils {
|
||||
public static int getHalFormat(int imageFormat) {
|
||||
return nativeGetHalFormat(imageFormat);
|
||||
}
|
||||
public static long getHalDataspace(int imageFormat) {
|
||||
return nativeGetHalDataspace(imageFormat);
|
||||
}
|
||||
public static int getPublicFormat(int imageFormat, long dataspace) {
|
||||
return nativeGetPublicFormat(imageFormat, dataspace);
|
||||
}
|
||||
private static native int nativeGetHalFormat(int imageFormat);
|
||||
private static native long nativeGetHalDataspace(int imageFormat);
|
||||
private static native int nativeGetPublicFormat(int imageFormat, long dataspace);
|
||||
}
|
||||
@@ -39,6 +39,7 @@ cc_library_shared {
|
||||
"android_media_MediaProfiles.cpp",
|
||||
"android_media_MediaRecorder.cpp",
|
||||
"android_media_MediaSync.cpp",
|
||||
"android_media_PublicFormatUtils.cpp",
|
||||
"android_media_ResampleInputStream.cpp",
|
||||
"android_media_Streams.cpp",
|
||||
"android_media_SyncParams.cpp",
|
||||
|
||||
@@ -375,18 +375,13 @@ static void ImageReader_classInit(JNIEnv* env, jclass clazz)
|
||||
}
|
||||
|
||||
static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint width, jint height,
|
||||
jint format, jint maxImages, jlong ndkUsage)
|
||||
{
|
||||
jint maxImages, jlong ndkUsage, jint nativeFormat, jlong dataSpace) {
|
||||
status_t res;
|
||||
int nativeFormat;
|
||||
android_dataspace nativeDataspace;
|
||||
|
||||
ALOGV("%s: width:%d, height: %d, format: 0x%x, maxImages:%d",
|
||||
__FUNCTION__, width, height, format, maxImages);
|
||||
ALOGV("%s: width:%d, height: %d, nativeFormat: %d, maxImages:%d",
|
||||
__FUNCTION__, width, height, nativeFormat, maxImages);
|
||||
|
||||
PublicFormat publicFormat = static_cast<PublicFormat>(format);
|
||||
nativeFormat = mapPublicFormatToHalFormat(publicFormat);
|
||||
nativeDataspace = mapPublicFormatToHalDataspace(publicFormat);
|
||||
android_dataspace nativeDataspace = static_cast<android_dataspace>(dataSpace);
|
||||
|
||||
jclass clazz = env->GetObjectClass(thiz);
|
||||
if (clazz == NULL) {
|
||||
@@ -400,7 +395,7 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint w
|
||||
BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
|
||||
sp<BufferItemConsumer> bufferConsumer;
|
||||
String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
|
||||
width, height, format, maxImages, getpid(),
|
||||
width, height, nativeFormat, maxImages, getpid(),
|
||||
createProcessUniqueId());
|
||||
uint64_t consumerUsage =
|
||||
android_hardware_HardwareBuffer_convertToGrallocUsageBits(ndkUsage);
|
||||
@@ -527,7 +522,8 @@ static void ImageReader_imageRelease(JNIEnv* env, jobject thiz, jobject image)
|
||||
ALOGV("%s: Image (format: 0x%x) has been released", __FUNCTION__, ctx->getBufferFormat());
|
||||
}
|
||||
|
||||
static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) {
|
||||
static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image,
|
||||
jboolean legacyValidateImageFormat) {
|
||||
ALOGV("%s:", __FUNCTION__);
|
||||
JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
|
||||
if (ctx == NULL) {
|
||||
@@ -590,7 +586,7 @@ static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) {
|
||||
ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
|
||||
__FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
|
||||
}
|
||||
if (imgReaderFmt != bufferFormat) {
|
||||
if (legacyValidateImageFormat && imgReaderFmt != bufferFormat) {
|
||||
if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 &&
|
||||
isPossiblyYUV(bufferFormat)) {
|
||||
// Treat formats that are compatible with flexible YUV
|
||||
@@ -958,10 +954,10 @@ static jobject Image_getHardwareBuffer(JNIEnv* env, jobject thiz) {
|
||||
|
||||
static const JNINativeMethod gImageReaderMethods[] = {
|
||||
{"nativeClassInit", "()V", (void*)ImageReader_classInit },
|
||||
{"nativeInit", "(Ljava/lang/Object;IIIIJ)V", (void*)ImageReader_init },
|
||||
{"nativeInit", "(Ljava/lang/Object;IIIJIJ)V", (void*)ImageReader_init },
|
||||
{"nativeClose", "()V", (void*)ImageReader_close },
|
||||
{"nativeReleaseImage", "(Landroid/media/Image;)V", (void*)ImageReader_imageRelease },
|
||||
{"nativeImageSetup", "(Landroid/media/Image;)I", (void*)ImageReader_imageSetup },
|
||||
{"nativeImageSetup", "(Landroid/media/Image;Z)I", (void*)ImageReader_imageSetup },
|
||||
{"nativeGetSurface", "()Landroid/view/Surface;", (void*)ImageReader_getSurface },
|
||||
{"nativeDetachImage", "(Landroid/media/Image;)I", (void*)ImageReader_detachImage },
|
||||
{"nativeCreateImagePlanes",
|
||||
|
||||
@@ -1454,6 +1454,7 @@ extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
|
||||
extern int register_android_media_MediaMuxer(JNIEnv *env);
|
||||
extern int register_android_media_MediaRecorder(JNIEnv *env);
|
||||
extern int register_android_media_MediaSync(JNIEnv *env);
|
||||
extern int register_android_media_PublicFormatUtils(JNIEnv *env);
|
||||
extern int register_android_media_ResampleInputStream(JNIEnv *env);
|
||||
extern int register_android_media_MediaProfiles(JNIEnv *env);
|
||||
extern int register_android_mtp_MtpDatabase(JNIEnv *env);
|
||||
@@ -1501,6 +1502,11 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (register_android_media_PublicFormatUtils(env) < 0) {
|
||||
ALOGE("ERROR: PublicFormatUtils native registration failed\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (register_android_media_ResampleInputStream(env) < 0) {
|
||||
ALOGE("ERROR: ResampleInputStream native registration failed\n");
|
||||
goto bail;
|
||||
|
||||
59
media/jni/android_media_PublicFormatUtils.cpp
Normal file
59
media/jni/android_media_PublicFormatUtils.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "PublicFormatUtils_JNI"
|
||||
|
||||
#include <utils/misc.h>
|
||||
#include <ui/PublicFormat.h>
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
#include <jni.h>
|
||||
|
||||
using namespace android;
|
||||
|
||||
static jint android_media_PublicFormatUtils_getHalFormat(JNIEnv* /*env*/, jobject /*thiz*/,
|
||||
jint imageFormat) {
|
||||
PublicFormat publicFormat = static_cast<PublicFormat>(imageFormat);
|
||||
int nativeFormat = mapPublicFormatToHalFormat(publicFormat);
|
||||
return static_cast<jint>(nativeFormat);
|
||||
}
|
||||
|
||||
static jlong android_media_PublicFormatUtils_getHalDataspace(JNIEnv* /*env*/, jobject /*thiz*/,
|
||||
jint imageFormat) {
|
||||
PublicFormat publicFormat = static_cast<PublicFormat>(imageFormat);
|
||||
android_dataspace
|
||||
nativeDataspace = mapPublicFormatToHalDataspace(publicFormat);
|
||||
return static_cast<jlong>(nativeDataspace);
|
||||
}
|
||||
|
||||
static jint android_media_PublicFormatUtils_getPublicFormat(JNIEnv* /*env*/, jobject /*thiz*/,
|
||||
jint hardwareBufferFormat,
|
||||
jlong dataspace) {
|
||||
PublicFormat nativeFormat = mapHalFormatDataspaceToPublicFormat(
|
||||
hardwareBufferFormat, static_cast<android_dataspace>(dataspace));
|
||||
return static_cast<jint>(nativeFormat);
|
||||
}
|
||||
|
||||
static const JNINativeMethod gMethods[] = {
|
||||
{"nativeGetHalFormat", "(I)I", (void*)android_media_PublicFormatUtils_getHalFormat},
|
||||
{"nativeGetHalDataspace", "(I)J", (void*)android_media_PublicFormatUtils_getHalDataspace},
|
||||
{"nativeGetPublicFormat", "(IJ)I",(void*)android_media_PublicFormatUtils_getPublicFormat}
|
||||
};
|
||||
|
||||
int register_android_media_PublicFormatUtils(JNIEnv *env) {
|
||||
return AndroidRuntime::registerNativeMethods(env,
|
||||
"android/media/PublicFormatUtils", gMethods, NELEM(gMethods));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user