Loading media/java/android/media/ImageWriter.java +68 −31 Original line number Diff line number Diff line Loading @@ -102,11 +102,10 @@ public class ImageWriter implements AutoCloseable { private int mWidth; private int mHeight; private final int mMaxImages; private @Usage long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN; private long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN; private @HardwareBuffer.Format int mHardwareBufferFormat; private @NamedDataSpace long mDataSpace; private boolean mUseLegacyImageFormat; private boolean mUseSurfaceImageFormatInfo; // Field below is used by native code, do not access or modify. private int mWriterFormat; Loading Loading @@ -255,17 +254,21 @@ public class ImageWriter implements AutoCloseable { + ", maxImages: " + maxImages); } mUseSurfaceImageFormatInfo = useSurfaceImageFormatInfo; mUseLegacyImageFormat = useLegacyImageFormat; // Note that the underlying BufferQueue is working in synchronous mode // to avoid dropping any buffers. mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, width, height, useSurfaceImageFormatInfo, hardwareBufferFormat, dataSpace, usage); // if useSurfaceImageFormatInfo is true, imageformat should be read from the surface. if (useSurfaceImageFormatInfo) { // nativeInit internally overrides UNKNOWN format. So does surface format query after // nativeInit and before getEstimatedNativeAllocBytes(). imageFormat = SurfaceUtils.getSurfaceFormat(surface); mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat); mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat); } // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native // allocation estimation sequence depends on the public formats values. To avoid // possible errors, convert where necessary. Loading @@ -284,7 +287,6 @@ public class ImageWriter implements AutoCloseable { default: imageFormat = ImageFormat.JPEG; } } mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat); mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat); } Loading @@ -307,7 +309,6 @@ public class ImageWriter implements AutoCloseable { private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, int imageFormat, int width, int height) { mMaxImages = maxImages; // update hal format and dataspace only if image format is overridden by producer. mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat); mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat); Loading Loading @@ -566,6 +567,9 @@ public class ImageWriter implements AutoCloseable { /** * Get the ImageWriter usage flag. * * <p>It is not recommended to use this function if {@link Builder#setUsage} is not called. * Invalid usage value will be returned if so.</p> * * @return The ImageWriter usage flag. */ public @Usage long getUsage() { Loading Loading @@ -873,7 +877,7 @@ public class ImageWriter implements AutoCloseable { private int mHeight = -1; private int mMaxImages = 1; private int mImageFormat = ImageFormat.UNKNOWN; private @Usage long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN; private long mUsage = -1; private @HardwareBuffer.Format int mHardwareBufferFormat = HardwareBuffer.RGBA_8888; private @NamedDataSpace long mDataSpace = DataSpace.DATASPACE_UNKNOWN; private boolean mUseSurfaceImageFormatInfo = true; Loading @@ -885,10 +889,19 @@ public class ImageWriter implements AutoCloseable { /** * Constructs a new builder for {@link ImageWriter}. * * <p>Uses {@code surface} input parameter to retrieve image format, hal format * and hal dataspace value for default. </p> * * @param surface The destination Surface this writer produces Image data into. * * @throws IllegalArgumentException if the surface is already abandoned. */ public Builder(@NonNull Surface surface) { mSurface = surface; // retrieve format from surface mImageFormat = SurfaceUtils.getSurfaceFormat(surface); mDataSpace = SurfaceUtils.getSurfaceDataspace(surface); mHardwareBufferFormat = PublicFormatUtils.getHalFormat(mImageFormat); } /** Loading Loading @@ -926,6 +939,8 @@ public class ImageWriter implements AutoCloseable { * @param imageFormat The format of the {@link ImageWriter}. It can be any valid specified * by {@link ImageFormat} or {@link PixelFormat}. * @return the Builder instance with customized image format. * * @throws IllegalArgumentException if {@code imageFormat} is invalid. */ @SuppressLint("MissingGetterMatchingBuilder") public @NonNull Builder setImageFormat(@Format int imageFormat) { Loading Loading @@ -985,12 +1000,16 @@ public class ImageWriter implements AutoCloseable { /** * Set the usage flag of this ImageWriter. * Default value is {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN}. * * <p>If this function is not called, usage bit will be set * to {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN} if the image format is not * {@link ImageFormat#PRIVATE PRIVATE}.</p> * * @param usage The intended usage of the images produced by this ImageWriter. * @return the Builder instance with customized usage flag. * * @see HardwareBuffer * @see #getUsage */ public @NonNull Builder setUsage(@Usage long usage) { mUsage = usage; Loading Loading @@ -1022,6 +1041,7 @@ public class ImageWriter implements AutoCloseable { private int mHeight = -1; private int mWidth = -1; private int mFormat = -1; private @NamedDataSpace long mDataSpace = DataSpace.DATASPACE_UNKNOWN; // When this default timestamp is used, timestamp for the input Image // will be generated automatically when queueInputBuffer is called. private final long DEFAULT_TIMESTAMP = Long.MIN_VALUE; Loading @@ -1034,19 +1054,34 @@ public class ImageWriter implements AutoCloseable { mOwner = writer; mWidth = writer.mWidth; mHeight = writer.mHeight; mDataSpace = writer.mDataSpace; if (!writer.mUseLegacyImageFormat) { if (!mOwner.mUseLegacyImageFormat) { mFormat = PublicFormatUtils.getPublicFormat( writer.mHardwareBufferFormat, writer.mDataSpace); mOwner.mHardwareBufferFormat, mDataSpace); } } @Override public @NamedDataSpace long getDataSpace() { throwISEIfImageIsInvalid(); return mDataSpace; } @Override public void setDataSpace(@NamedDataSpace long dataSpace) { throwISEIfImageIsInvalid(); mDataSpace = dataSpace; } @Override public int getFormat() { throwISEIfImageIsInvalid(); if (mFormat == -1) { mFormat = nativeGetFormat(); if (mOwner.mUseLegacyImageFormat && mFormat == -1) { mFormat = nativeGetFormat(mDataSpace); } return mFormat; } Loading Loading @@ -1114,7 +1149,8 @@ public class ImageWriter implements AutoCloseable { if (mPlanes == null) { int numPlanes = ImageUtils.getNumPlanesForFormat(getFormat()); mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat()); mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat(), getOwner().getDataSpace()); } return mPlanes.clone(); Loading Loading @@ -1222,13 +1258,14 @@ public class ImageWriter implements AutoCloseable { } // Create the SurfacePlane object and fill the information private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt); private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt, long dataSpace); private synchronized native int nativeGetWidth(); private synchronized native int nativeGetHeight(); private synchronized native int nativeGetFormat(); private synchronized native int nativeGetFormat(long dataSpace); private synchronized native HardwareBuffer nativeGetHardwareBuffer(); } Loading media/jni/android_media_ImageWriter.cpp +24 −17 Original line number Diff line number Diff line Loading @@ -460,8 +460,6 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje } else { // Set consumer buffer format to user specified format android_dataspace nativeDataspace = static_cast<android_dataspace>(dataSpace); int userFormat = static_cast<int>(mapHalFormatDataspaceToPublicFormat( hardwareBufferFormat, nativeDataspace)); res = native_window_set_buffers_format(anw.get(), hardwareBufferFormat); if (res != OK) { ALOGE("%s: Unable to configure consumer native buffer format to %#x", Loading @@ -478,21 +476,30 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje return 0; } ctx->setBufferDataSpace(nativeDataspace); surfaceFormat = userFormat; surfaceFormat = static_cast<int32_t>(mapHalFormatDataspaceToPublicFormat( hardwareBufferFormat, nativeDataspace)); } ctx->setBufferFormat(surfaceFormat); env->SetIntField(thiz, gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(surfaceFormat)); // ndkUsage == -1 means setUsage in ImageWriter class is not called. // skip usage setting if setUsage in ImageWriter is not called and imageformat is opaque. if (!(ndkUsage == -1 && isFormatOpaque(surfaceFormat))) { if (ndkUsage == -1) { ndkUsage = GRALLOC_USAGE_SW_WRITE_OFTEN; } res = native_window_set_usage(anw.get(), ndkUsage); if (res != OK) { ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)", __FUNCTION__, static_cast<unsigned int>(ndkUsage), surfaceFormat, strerror(-res), res); jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage"); jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage"); return 0; } } int minUndequeuedBufferCount = 0; res = anw->query(anw.get(), Loading Loading @@ -952,7 +959,7 @@ static jint Image_getHeight(JNIEnv* env, jobject thiz) { return buffer->getHeight(); } static jint Image_getFormat(JNIEnv* env, jobject thiz) { static jint Image_getFormat(JNIEnv* env, jobject thiz, jlong dataSpace) { ALOGV("%s", __FUNCTION__); GraphicBuffer* buffer; Image_getNativeContext(env, thiz, &buffer, NULL); Loading @@ -962,9 +969,9 @@ static jint Image_getFormat(JNIEnv* env, jobject thiz) { return 0; } // ImageWriter doesn't support data space yet, assuming it is unknown. PublicFormat publicFmt = mapHalFormatDataspaceToPublicFormat(buffer->getPixelFormat(), HAL_DATASPACE_UNKNOWN); static_cast<android_dataspace>(dataSpace)); return static_cast<jint>(publicFmt); } Loading Loading @@ -1031,14 +1038,14 @@ static bool Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx, } static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz, int numPlanes, int writerFormat) { int numPlanes, int writerFormat, long dataSpace) { ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes); int rowStride, pixelStride; uint8_t *pData; uint32_t dataSize; jobject byteBuffer; int format = Image_getFormat(env, thiz); int format = Image_getFormat(env, thiz, dataSpace); if (isFormatOpaque(format) && numPlanes > 0) { String8 msg; msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)" Loading Loading @@ -1108,11 +1115,11 @@ static JNINativeMethod gImageWriterMethods[] = { }; static JNINativeMethod gImageMethods[] = { {"nativeCreatePlanes", "(II)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;", {"nativeCreatePlanes", "(IIJ)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;", (void*)Image_createSurfacePlanes }, {"nativeGetWidth", "()I", (void*)Image_getWidth }, {"nativeGetHeight", "()I", (void*)Image_getHeight }, {"nativeGetFormat", "()I", (void*)Image_getFormat }, {"nativeGetFormat", "(J)I", (void*)Image_getFormat }, {"nativeGetHardwareBuffer", "()Landroid/hardware/HardwareBuffer;", (void*)Image_getHardwareBuffer }, }; Loading Loading
media/java/android/media/ImageWriter.java +68 −31 Original line number Diff line number Diff line Loading @@ -102,11 +102,10 @@ public class ImageWriter implements AutoCloseable { private int mWidth; private int mHeight; private final int mMaxImages; private @Usage long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN; private long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN; private @HardwareBuffer.Format int mHardwareBufferFormat; private @NamedDataSpace long mDataSpace; private boolean mUseLegacyImageFormat; private boolean mUseSurfaceImageFormatInfo; // Field below is used by native code, do not access or modify. private int mWriterFormat; Loading Loading @@ -255,17 +254,21 @@ public class ImageWriter implements AutoCloseable { + ", maxImages: " + maxImages); } mUseSurfaceImageFormatInfo = useSurfaceImageFormatInfo; mUseLegacyImageFormat = useLegacyImageFormat; // Note that the underlying BufferQueue is working in synchronous mode // to avoid dropping any buffers. mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, width, height, useSurfaceImageFormatInfo, hardwareBufferFormat, dataSpace, usage); // if useSurfaceImageFormatInfo is true, imageformat should be read from the surface. if (useSurfaceImageFormatInfo) { // nativeInit internally overrides UNKNOWN format. So does surface format query after // nativeInit and before getEstimatedNativeAllocBytes(). imageFormat = SurfaceUtils.getSurfaceFormat(surface); mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat); mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat); } // Several public formats use the same native HAL_PIXEL_FORMAT_BLOB. The native // allocation estimation sequence depends on the public formats values. To avoid // possible errors, convert where necessary. Loading @@ -284,7 +287,6 @@ public class ImageWriter implements AutoCloseable { default: imageFormat = ImageFormat.JPEG; } } mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat); mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat); } Loading @@ -307,7 +309,6 @@ public class ImageWriter implements AutoCloseable { private ImageWriter(Surface surface, int maxImages, boolean useSurfaceImageFormatInfo, int imageFormat, int width, int height) { mMaxImages = maxImages; // update hal format and dataspace only if image format is overridden by producer. mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat); mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat); Loading Loading @@ -566,6 +567,9 @@ public class ImageWriter implements AutoCloseable { /** * Get the ImageWriter usage flag. * * <p>It is not recommended to use this function if {@link Builder#setUsage} is not called. * Invalid usage value will be returned if so.</p> * * @return The ImageWriter usage flag. */ public @Usage long getUsage() { Loading Loading @@ -873,7 +877,7 @@ public class ImageWriter implements AutoCloseable { private int mHeight = -1; private int mMaxImages = 1; private int mImageFormat = ImageFormat.UNKNOWN; private @Usage long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN; private long mUsage = -1; private @HardwareBuffer.Format int mHardwareBufferFormat = HardwareBuffer.RGBA_8888; private @NamedDataSpace long mDataSpace = DataSpace.DATASPACE_UNKNOWN; private boolean mUseSurfaceImageFormatInfo = true; Loading @@ -885,10 +889,19 @@ public class ImageWriter implements AutoCloseable { /** * Constructs a new builder for {@link ImageWriter}. * * <p>Uses {@code surface} input parameter to retrieve image format, hal format * and hal dataspace value for default. </p> * * @param surface The destination Surface this writer produces Image data into. * * @throws IllegalArgumentException if the surface is already abandoned. */ public Builder(@NonNull Surface surface) { mSurface = surface; // retrieve format from surface mImageFormat = SurfaceUtils.getSurfaceFormat(surface); mDataSpace = SurfaceUtils.getSurfaceDataspace(surface); mHardwareBufferFormat = PublicFormatUtils.getHalFormat(mImageFormat); } /** Loading Loading @@ -926,6 +939,8 @@ public class ImageWriter implements AutoCloseable { * @param imageFormat The format of the {@link ImageWriter}. It can be any valid specified * by {@link ImageFormat} or {@link PixelFormat}. * @return the Builder instance with customized image format. * * @throws IllegalArgumentException if {@code imageFormat} is invalid. */ @SuppressLint("MissingGetterMatchingBuilder") public @NonNull Builder setImageFormat(@Format int imageFormat) { Loading Loading @@ -985,12 +1000,16 @@ public class ImageWriter implements AutoCloseable { /** * Set the usage flag of this ImageWriter. * Default value is {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN}. * * <p>If this function is not called, usage bit will be set * to {@link HardwareBuffer#USAGE_CPU_WRITE_OFTEN} if the image format is not * {@link ImageFormat#PRIVATE PRIVATE}.</p> * * @param usage The intended usage of the images produced by this ImageWriter. * @return the Builder instance with customized usage flag. * * @see HardwareBuffer * @see #getUsage */ public @NonNull Builder setUsage(@Usage long usage) { mUsage = usage; Loading Loading @@ -1022,6 +1041,7 @@ public class ImageWriter implements AutoCloseable { private int mHeight = -1; private int mWidth = -1; private int mFormat = -1; private @NamedDataSpace long mDataSpace = DataSpace.DATASPACE_UNKNOWN; // When this default timestamp is used, timestamp for the input Image // will be generated automatically when queueInputBuffer is called. private final long DEFAULT_TIMESTAMP = Long.MIN_VALUE; Loading @@ -1034,19 +1054,34 @@ public class ImageWriter implements AutoCloseable { mOwner = writer; mWidth = writer.mWidth; mHeight = writer.mHeight; mDataSpace = writer.mDataSpace; if (!writer.mUseLegacyImageFormat) { if (!mOwner.mUseLegacyImageFormat) { mFormat = PublicFormatUtils.getPublicFormat( writer.mHardwareBufferFormat, writer.mDataSpace); mOwner.mHardwareBufferFormat, mDataSpace); } } @Override public @NamedDataSpace long getDataSpace() { throwISEIfImageIsInvalid(); return mDataSpace; } @Override public void setDataSpace(@NamedDataSpace long dataSpace) { throwISEIfImageIsInvalid(); mDataSpace = dataSpace; } @Override public int getFormat() { throwISEIfImageIsInvalid(); if (mFormat == -1) { mFormat = nativeGetFormat(); if (mOwner.mUseLegacyImageFormat && mFormat == -1) { mFormat = nativeGetFormat(mDataSpace); } return mFormat; } Loading Loading @@ -1114,7 +1149,8 @@ public class ImageWriter implements AutoCloseable { if (mPlanes == null) { int numPlanes = ImageUtils.getNumPlanesForFormat(getFormat()); mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat()); mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat(), getOwner().getDataSpace()); } return mPlanes.clone(); Loading Loading @@ -1222,13 +1258,14 @@ public class ImageWriter implements AutoCloseable { } // Create the SurfacePlane object and fill the information private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt); private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt, long dataSpace); private synchronized native int nativeGetWidth(); private synchronized native int nativeGetHeight(); private synchronized native int nativeGetFormat(); private synchronized native int nativeGetFormat(long dataSpace); private synchronized native HardwareBuffer nativeGetHardwareBuffer(); } Loading
media/jni/android_media_ImageWriter.cpp +24 −17 Original line number Diff line number Diff line Loading @@ -460,8 +460,6 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje } else { // Set consumer buffer format to user specified format android_dataspace nativeDataspace = static_cast<android_dataspace>(dataSpace); int userFormat = static_cast<int>(mapHalFormatDataspaceToPublicFormat( hardwareBufferFormat, nativeDataspace)); res = native_window_set_buffers_format(anw.get(), hardwareBufferFormat); if (res != OK) { ALOGE("%s: Unable to configure consumer native buffer format to %#x", Loading @@ -478,21 +476,30 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje return 0; } ctx->setBufferDataSpace(nativeDataspace); surfaceFormat = userFormat; surfaceFormat = static_cast<int32_t>(mapHalFormatDataspaceToPublicFormat( hardwareBufferFormat, nativeDataspace)); } ctx->setBufferFormat(surfaceFormat); env->SetIntField(thiz, gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(surfaceFormat)); // ndkUsage == -1 means setUsage in ImageWriter class is not called. // skip usage setting if setUsage in ImageWriter is not called and imageformat is opaque. if (!(ndkUsage == -1 && isFormatOpaque(surfaceFormat))) { if (ndkUsage == -1) { ndkUsage = GRALLOC_USAGE_SW_WRITE_OFTEN; } res = native_window_set_usage(anw.get(), ndkUsage); if (res != OK) { ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)", __FUNCTION__, static_cast<unsigned int>(ndkUsage), surfaceFormat, strerror(-res), res); jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage"); jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage"); return 0; } } int minUndequeuedBufferCount = 0; res = anw->query(anw.get(), Loading Loading @@ -952,7 +959,7 @@ static jint Image_getHeight(JNIEnv* env, jobject thiz) { return buffer->getHeight(); } static jint Image_getFormat(JNIEnv* env, jobject thiz) { static jint Image_getFormat(JNIEnv* env, jobject thiz, jlong dataSpace) { ALOGV("%s", __FUNCTION__); GraphicBuffer* buffer; Image_getNativeContext(env, thiz, &buffer, NULL); Loading @@ -962,9 +969,9 @@ static jint Image_getFormat(JNIEnv* env, jobject thiz) { return 0; } // ImageWriter doesn't support data space yet, assuming it is unknown. PublicFormat publicFmt = mapHalFormatDataspaceToPublicFormat(buffer->getPixelFormat(), HAL_DATASPACE_UNKNOWN); static_cast<android_dataspace>(dataSpace)); return static_cast<jint>(publicFmt); } Loading Loading @@ -1031,14 +1038,14 @@ static bool Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx, } static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz, int numPlanes, int writerFormat) { int numPlanes, int writerFormat, long dataSpace) { ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes); int rowStride, pixelStride; uint8_t *pData; uint32_t dataSize; jobject byteBuffer; int format = Image_getFormat(env, thiz); int format = Image_getFormat(env, thiz, dataSpace); if (isFormatOpaque(format) && numPlanes > 0) { String8 msg; msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)" Loading Loading @@ -1108,11 +1115,11 @@ static JNINativeMethod gImageWriterMethods[] = { }; static JNINativeMethod gImageMethods[] = { {"nativeCreatePlanes", "(II)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;", {"nativeCreatePlanes", "(IIJ)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;", (void*)Image_createSurfacePlanes }, {"nativeGetWidth", "()I", (void*)Image_getWidth }, {"nativeGetHeight", "()I", (void*)Image_getHeight }, {"nativeGetFormat", "()I", (void*)Image_getFormat }, {"nativeGetFormat", "(J)I", (void*)Image_getFormat }, {"nativeGetHardwareBuffer", "()Landroid/hardware/HardwareBuffer;", (void*)Image_getHardwareBuffer }, }; Loading