diff options
author | 2022-01-13 00:53:07 +0000 | |
---|---|---|
committer | 2022-01-13 00:53:07 +0000 | |
commit | cd599a961edb99bf5f09bf24e3d12b15e48517bd (patch) | |
tree | 1c2ab16d0b3aba850f8bd33ee01cdc2493567445 | |
parent | d7fe72bfbd96e0ef62f9f38e137a6ec094c5e64e (diff) | |
parent | aba398d87d91afcdbc8a8ff766af86c3b6dc9c25 (diff) |
Merge "Introduce Builder in ImageReader class for setup and construct an ImageReader instance."
-rw-r--r-- | core/api/current.txt | 13 | ||||
-rw-r--r-- | media/java/android/media/ImageReader.java | 314 | ||||
-rw-r--r-- | media/java/android/media/ImageUtils.java | 29 | ||||
-rw-r--r-- | media/java/android/media/PublicFormatUtils.java | 34 | ||||
-rw-r--r-- | media/jni/Android.bp | 1 | ||||
-rw-r--r-- | media/jni/android_media_ImageReader.cpp | 24 | ||||
-rw-r--r-- | media/jni/android_media_MediaPlayer.cpp | 6 | ||||
-rw-r--r-- | media/jni/android_media_PublicFormatUtils.cpp | 59 |
8 files changed, 430 insertions, 50 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 1f2dcf25c288..a0f650027690 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -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); } diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java index bd0f32e6ffee..69ce8d2a3d93 100644 --- a/media/java/android/media/ImageReader.java +++ b/media/java/android/media/ImageReader.java @@ -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, maxImages, usage, + hardwareBufferFormat, dataSpace); - nativeInit(new WeakReference<>(this), width, height, format, maxImages, usage); + mIsReaderValid = true; mSurface = nativeGetSurface(); - - mIsReaderValid = true; // 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 @@ -363,6 +393,32 @@ public class ImageReader implements AutoCloseable { } /** + * 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}). * @@ -384,6 +440,15 @@ public class ImageReader implements AutoCloseable { } /** + * 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 diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java index 7837d7e39599..2f1a36cba9d0 100644 --- a/media/java/android/media/ImageUtils.java +++ b/media/java/android/media/ImageUtils.java @@ -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; @@ -77,6 +78,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. * </p> diff --git a/media/java/android/media/PublicFormatUtils.java b/media/java/android/media/PublicFormatUtils.java new file mode 100644 index 000000000000..6268804128c6 --- /dev/null +++ b/media/java/android/media/PublicFormatUtils.java @@ -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); +} diff --git a/media/jni/Android.bp b/media/jni/Android.bp index e817f2dc9e1d..feae6065c680 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -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", diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 021507c8631c..6002e2884db8 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.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", diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 8dcdc989ec8f..a548a472fc3a 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -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; diff --git a/media/jni/android_media_PublicFormatUtils.cpp b/media/jni/android_media_PublicFormatUtils.cpp new file mode 100644 index 000000000000..09ebdeeff06f --- /dev/null +++ b/media/jni/android_media_PublicFormatUtils.cpp @@ -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)); +} + |