Avoid using private Bitmap constructor to generate bitmaps
bug - 2433195
Change-Id: Ic74225286c9884055ae751cf76a1d65e8e70b3ae
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 9662817..4ccdd9a 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -22,6 +22,20 @@
#include <utils/Log.h>
#include <utils/threads.h>
#include <core/SkBitmap.h>
+
+// Please do not enable "USE_PRIVATE_NATIVE_BITMAP_CONSTUCTOR"
+// This mode will be removed and it is kept here for
+// convenient comparsion just in case. Will be removed soon.
+// Tests show that this mode is also ~30ms slower,
+// when rotation is involved.
+#define USE_PRIVATE_NATIVE_BITMAP_CONSTUCTOR 0
+
+#if (!USE_PRIVATE_NATIVE_BITMAP_CONSTUCTOR)
+#include <core/SkCanvas.h>
+#include <core/SkDevice.h>
+#include <core/SkScalar.h>
+#endif
+
#include <media/mediametadataretriever.h>
#include <private/media/VideoFrame.h>
@@ -35,8 +49,15 @@
struct fields_t {
jfieldID context;
jclass bitmapClazz;
+#if USE_PRIVATE_NATIVE_BITMAP_CONSTUCTOR
jmethodID bitmapConstructor;
+ jmethodID createBitmapRotationMethod;
+#else
+ jfieldID nativeBitmap;
jmethodID createBitmapMethod;
+ jclass configClazz;
+ jmethodID createConfigMethod;
+#endif
};
static fields_t fields;
@@ -162,6 +183,12 @@
return NULL;
}
+ LOGV("Dimension = %dx%d and bytes = %d",
+ videoFrame->mDisplayWidth,
+ videoFrame->mDisplayHeight,
+ videoFrame->mSize);
+
+#if USE_PRIVATE_NATIVE_BITMAP_CONSTUCTOR
jobject matrix = NULL;
if (videoFrame->mRotationAngle != 0) {
LOGD("Create a rotation matrix: %d degrees", videoFrame->mRotationAngle);
@@ -217,9 +244,9 @@
jobject jSrcBitmap = env->NewObject(fields.bitmapClazz,
fields.bitmapConstructor, (int) bitmap, NULL, true, NULL, -1);
- LOGV("Return a new bitmap constructed with the rotation matrix");
- return env->CallStaticObjectMethod(
- fields.bitmapClazz, fields.createBitmapMethod,
+ jobject jBitmap = env->CallStaticObjectMethod(
+ fields.bitmapClazz,
+ fields.createBitmapRotationMethod,
jSrcBitmap, // source Bitmap
0, // x
0, // y
@@ -227,6 +254,39 @@
videoFrame->mDisplayHeight, // height
matrix, // transform matrix
false); // filter
+
+#else
+
+ jobject config = env->CallStaticObjectMethod(
+ fields.configClazz,
+ fields.createConfigMethod,
+ SkBitmap::kRGB_565_Config);
+
+ jobject jBitmap = env->CallStaticObjectMethod(
+ fields.bitmapClazz,
+ fields.createBitmapMethod,
+ videoFrame->mDisplayWidth,
+ videoFrame->mDisplayHeight,
+ config);
+ SkBitmap *bitmap =
+ (SkBitmap *) env->GetIntField(jBitmap, fields.nativeBitmap);
+
+ bitmap->lockPixels();
+
+ memcpy((uint8_t*)bitmap->getPixels(),
+ (uint8_t*)videoFrame + sizeof(VideoFrame), videoFrame->mSize);
+
+ bitmap->unlockPixels();
+
+ if (videoFrame->mRotationAngle != 0) {
+ SkDevice device(*bitmap);
+ SkCanvas canvas(&device);
+ canvas.rotate((SkScalar) (videoFrame->mRotationAngle * 1.0));
+ canvas.drawBitmap(*bitmap, 0, 0);
+ }
+#endif
+ LOGV("Return a new bitmap constructed with the rotation matrix");
+ return jBitmap;
}
static jbyteArray android_media_MediaMetadataRetriever_extractAlbumArt(JNIEnv *env, jobject thiz)
@@ -293,7 +353,6 @@
static void android_media_MediaMetadataRetriever_native_finalize(JNIEnv *env, jobject thiz)
{
LOGV("native_finalize");
-
// No lock is needed, since android_media_MediaMetadataRetriever_release() is protected
android_media_MediaMetadataRetriever_release(env, thiz);
}
@@ -320,21 +379,52 @@
jniThrowException(env, "java/lang/RuntimeException", "Can't find android/graphics/Bitmap");
return;
}
-
+#if USE_PRIVATE_NATIVE_BITMAP_CONSTUCTOR
fields.bitmapConstructor = env->GetMethodID(fields.bitmapClazz, "<init>", "(I[BZ[BI)V");
if (fields.bitmapConstructor == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Can't find Bitmap constructor");
return;
}
- fields.createBitmapMethod =
+ fields.createBitmapRotationMethod =
env->GetStaticMethodID(fields.bitmapClazz, "createBitmap",
"(Landroid/graphics/Bitmap;IIIILandroid/graphics/Matrix;Z)"
"Landroid/graphics/Bitmap;");
- if (fields.createBitmapMethod == NULL) {
+ if (fields.createBitmapRotationMethod == NULL) {
jniThrowException(env, "java/lang/RuntimeException",
"Can't find Bitmap.createBitmap method");
return;
}
+#else
+ fields.createBitmapMethod =
+ env->GetStaticMethodID(fields.bitmapClazz, "createBitmap",
+ "(IILandroid/graphics/Bitmap$Config;)"
+ "Landroid/graphics/Bitmap;");
+ if (fields.createBitmapMethod == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Can't find Bitmap.createBitmap(int, int, Config) method");
+ return;
+ }
+ fields.nativeBitmap = env->GetFieldID(fields.bitmapClazz, "mNativeBitmap", "I");
+ if (fields.nativeBitmap == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Can't find Bitmap.mNativeBitmap field");
+ }
+
+ fields.configClazz = env->FindClass("android/graphics/Bitmap$Config");
+ if (fields.configClazz == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Can't find Bitmap$Config class");
+ return;
+ }
+ fields.createConfigMethod =
+ env->GetStaticMethodID(fields.configClazz, "nativeToConfig",
+ "(I)Landroid/graphics/Bitmap$Config;");
+ if (fields.createConfigMethod == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Can't find Bitmap$Config.nativeToConfig(int) method");
+ return;
+ }
+#endif
}
static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobject thiz)