diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java index 6dd4f699f8300..37c578542bf31 100644 --- a/media/java/android/media/Image.java +++ b/media/java/android/media/Image.java @@ -185,6 +185,13 @@ public abstract class Image implements AutoCloseable { */ public abstract long getTimestamp(); + /** + * Get the transformation associated with this frame. + * @return The window transformation that needs to be applied for this frame. + * @hide + */ + public abstract int getTransform(); + /** * Get the {@link android.hardware.HardwareBuffer HardwareBuffer} handle of the input image * intended for GPU and/or hardware access. diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java index fb0de5c57c86d..56edace6e93b6 100644 --- a/media/java/android/media/ImageReader.java +++ b/media/java/android/media/ImageReader.java @@ -875,6 +875,12 @@ public class ImageReader implements AutoCloseable { return mTimestamp; } + @Override + public int getTransform() { + throwISEIfImageIsInvalid(); + return mTransform; + } + @Override public HardwareBuffer getHardwareBuffer() { throwISEIfImageIsInvalid(); @@ -1013,6 +1019,11 @@ public class ImageReader implements AutoCloseable { */ private long mTimestamp; + /** + * This field is set by native code during nativeImageSetup(). + */ + private int mTransform; + private SurfacePlane[] mPlanes; private int mFormat = ImageFormat.UNKNOWN; // If this image is detached from the ImageReader. diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java index 2b7309f189775..8ee27ae58105c 100644 --- a/media/java/android/media/ImageWriter.java +++ b/media/java/android/media/ImageWriter.java @@ -371,7 +371,7 @@ public class ImageWriter implements AutoCloseable { Rect crop = image.getCropRect(); nativeQueueInputImage(mNativeContext, image, image.getTimestamp(), crop.left, crop.top, - crop.right, crop.bottom); + crop.right, crop.bottom, image.getTransform()); /** * Only remove and cleanup the Images that are owned by this @@ -557,7 +557,8 @@ public class ImageWriter implements AutoCloseable { // buffer caused leak. Rect crop = image.getCropRect(); nativeAttachAndQueueImage(mNativeContext, image.getNativeContext(), image.getFormat(), - image.getTimestamp(), crop.left, crop.top, crop.right, crop.bottom); + image.getTimestamp(), crop.left, crop.top, crop.right, crop.bottom, + image.getTransform()); } /** @@ -674,6 +675,8 @@ public class ImageWriter implements AutoCloseable { private final long DEFAULT_TIMESTAMP = Long.MIN_VALUE; private long mTimestamp = DEFAULT_TIMESTAMP; + private int mTransform = 0; //Default no transform + public WriterSurfaceImage(ImageWriter writer) { mOwner = writer; } @@ -710,6 +713,13 @@ public class ImageWriter implements AutoCloseable { return mHeight; } + @Override + public int getTransform() { + throwISEIfImageIsInvalid(); + + return mTransform; + } + @Override public long getTimestamp() { throwISEIfImageIsInvalid(); @@ -856,11 +866,11 @@ public class ImageWriter implements AutoCloseable { private synchronized native void nativeDequeueInputImage(long nativeCtx, Image wi); private synchronized native void nativeQueueInputImage(long nativeCtx, Image image, - long timestampNs, int left, int top, int right, int bottom); + long timestampNs, int left, int top, int right, int bottom, int transform); private synchronized native int nativeAttachAndQueueImage(long nativeCtx, long imageNativeBuffer, int imageFormat, long timestampNs, int left, - int top, int right, int bottom); + int top, int right, int bottom, int transform); private synchronized native void cancelImage(long nativeCtx, Image image); diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 3d5f6bc9ac713..e72dff39a9d8d 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -3510,6 +3510,8 @@ final public class MediaCodec { private final static int TYPE_YUV = 1; + private final int mTransform = 0; //Default no transform + @Override public int getFormat() { throwISEIfImageIsInvalid(); @@ -3528,6 +3530,12 @@ final public class MediaCodec { return mWidth; } + @Override + public int getTransform() { + throwISEIfImageIsInvalid(); + return mTransform; + } + @Override public long getTimestamp() { throwISEIfImageIsInvalid(); diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index f5311764e5650..bfb3ea2a353cd 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -45,6 +45,7 @@ #define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID "mNativeContext" #define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID "mNativeBuffer" #define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID "mTimestamp" +#define ANDROID_MEDIA_SURFACEIMAGE_TF_JNI_ID "mTransform" #define CONSUMER_BUFFER_USAGE_UNKNOWN 0; // ---------------------------------------------------------------------------- @@ -66,6 +67,7 @@ static struct { static struct { jfieldID mNativeBuffer; jfieldID mTimestamp; + jfieldID mTransform; jfieldID mPlanes; } gSurfaceImageClassInfo; @@ -307,6 +309,12 @@ static void ImageReader_classInit(JNIEnv* env, jclass clazz) "can't find android/graphics/ImageReader.%s", ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID); + gSurfaceImageClassInfo.mTransform = env->GetFieldID( + imageClazz, ANDROID_MEDIA_SURFACEIMAGE_TF_JNI_ID, "I"); + LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mTransform == NULL, + "can't find android/graphics/ImageReader.%s", + ANDROID_MEDIA_SURFACEIMAGE_TF_JNI_ID); + gSurfaceImageClassInfo.mPlanes = env->GetFieldID( imageClazz, "mPlanes", "[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;"); LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mPlanes == NULL, @@ -596,6 +604,8 @@ static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) { Image_setBufferItem(env, image, buffer); env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp, static_cast(buffer->mTimestamp)); + env->SetIntField(image, gSurfaceImageClassInfo.mTransform, + static_cast(buffer->mTransform)); return ACQUIRE_SUCCESS; } diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp index 2c7499237841c..2b8f9f8933d33 100644 --- a/media/jni/android_media_ImageWriter.cpp +++ b/media/jni/android_media_ImageWriter.cpp @@ -421,7 +421,7 @@ static void ImageWriter_cancelImage(JNIEnv* env, jobject thiz, jlong nativeCtx, } static void ImageWriter_queueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, jobject image, - jlong timestampNs, jint left, jint top, jint right, jint bottom) { + jlong timestampNs, jint left, jint top, jint right, jint bottom, jint transform) { ALOGV("%s", __FUNCTION__); JNIImageWriterContext* const ctx = reinterpret_cast(nativeCtx); if (ctx == NULL || thiz == NULL) { @@ -465,6 +465,12 @@ static void ImageWriter_queueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, j return; } + res = native_window_set_buffers_transform(anw.get(), transform); + if (res != OK) { + jniThrowRuntimeException(env, "Set transform failed"); + return; + } + // Finally, queue input buffer res = anw->queueBuffer(anw.get(), buffer, fenceFd); if (res != OK) { @@ -487,7 +493,7 @@ static void ImageWriter_queueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, j static jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, jlong nativeBuffer, jint imageFormat, jlong timestampNs, jint left, jint top, - jint right, jint bottom) { + jint right, jint bottom, jint transform) { ALOGV("%s", __FUNCTION__); JNIImageWriterContext* const ctx = reinterpret_cast(nativeCtx); if (ctx == NULL || thiz == NULL) { @@ -530,7 +536,7 @@ static jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nat } sp < ANativeWindow > anw = surface; - // Step 2. Set timestamp and crop. Note that we do not need unlock the image because + // Step 2. Set timestamp, crop and transform. Note that we do not need unlock the image because // it was not locked. ALOGV("timestamp to be queued: %" PRId64, timestampNs); res = native_window_set_buffers_timestamp(anw.get(), timestampNs); @@ -550,6 +556,12 @@ static jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nat return res; } + res = native_window_set_buffers_transform(anw.get(), transform); + if (res != OK) { + jniThrowRuntimeException(env, "Set transform failed"); + return res; + } + // Step 3. Queue Image. res = anw->queueBuffer(anw.get(), buffer->mGraphicBuffer.get(), /*fenceFd*/ -1); @@ -785,9 +797,9 @@ static JNINativeMethod gImageWriterMethods[] = { {"nativeInit", "(Ljava/lang/Object;Landroid/view/Surface;II)J", (void*)ImageWriter_init }, {"nativeClose", "(J)V", (void*)ImageWriter_close }, - {"nativeAttachAndQueueImage", "(JJIJIIII)I", (void*)ImageWriter_attachAndQueueImage }, + {"nativeAttachAndQueueImage", "(JJIJIIIII)I", (void*)ImageWriter_attachAndQueueImage }, {"nativeDequeueInputImage", "(JLandroid/media/Image;)V", (void*)ImageWriter_dequeueImage }, - {"nativeQueueInputImage", "(JLandroid/media/Image;JIIII)V", (void*)ImageWriter_queueImage }, + {"nativeQueueInputImage", "(JLandroid/media/Image;JIIIII)V", (void*)ImageWriter_queueImage }, {"cancelImage", "(JLandroid/media/Image;)V", (void*)ImageWriter_cancelImage }, };