Clean up JNI code

o Move the Set/Map/Iterator calls from JNI to Java
o The JNI function receives arrays instead of Maps
o Removed Set/Iterator calls from the Java code as suggested

Change-Id: I34068bf24b61abaf2833dad1f65abc733ed760dd
This commit is contained in:
James Dong
2011-05-04 13:41:58 -07:00
parent 588f280fe0
commit 17524dc0d2
4 changed files with 108 additions and 194 deletions

View File

@@ -68,7 +68,21 @@ public class MediaMetadataRetriever
* @param headers the headers to be sent together with the request for the data
* @throws IllegalArgumentException If the URI is invalid.
*/
public native void setDataSource(String uri, Map<String, String> headers)
public void setDataSource(String uri, Map<String, String> headers)
throws IllegalArgumentException {
int i = 0;
String[] keys = new String[headers.size()];
String[] values = new String[headers.size()];
for (Map.Entry<String, String> entry: headers.entrySet()) {
keys[i] = entry.getKey();
values[i] = entry.getValue();
++i;
}
_setDataSource(uri, keys, values);
}
private native void _setDataSource(
String uri, String[] keys, String[] values)
throws IllegalArgumentException;
/**

View File

@@ -799,8 +799,23 @@ public class MediaPlayer
* @throws IllegalStateException if it is called in an invalid state
* @hide pending API council
*/
public native void setDataSource(String path, Map<String, String> headers)
throws IOException, IllegalArgumentException, IllegalStateException;
public void setDataSource(String path, Map<String, String> headers)
throws IOException, IllegalArgumentException, IllegalStateException
{
int i = 0;
String[] keys = new String[headers.size()];
String[] values = new String[headers.size()];
for (Map.Entry<String, String> entry: headers.entrySet()) {
keys[i] = entry.getKey();
values[i] = entry.getValue();
++i;
}
_setDataSource(path, keys, values);
}
private native void _setDataSource(
String path, String[] keys, String[] values)
throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Sets the data source (FileDescriptor) to use. It is the caller's responsibility

View File

@@ -79,7 +79,9 @@ static void setRetriever(JNIEnv* env, jobject thiz, int retriever)
static void
android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
JNIEnv *env, jobject thiz, jstring path, jobject headers) {
JNIEnv *env, jobject thiz, jstring path,
jobjectArray keys, jobjectArray values) {
LOGV("setDataSource");
MediaMetadataRetriever* retriever = getRetriever(env, thiz);
if (retriever == 0) {
@@ -103,10 +105,17 @@ android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
}
String8 pathStr(tmp);
env->ReleaseStringUTFChars(path, tmp);
tmp = NULL;
int nKeyValuePairs = env->GetArrayLength(keys);
if (nKeyValuePairs != env->GetArrayLength(values)) {
LOGE("keys and values have different length: %d <--> %d",
nKeyValuePairs, env->GetArrayLength(values));
jniThrowException(
env, "java/lang/IllegalArgumentException", NULL);
return;
}
// Don't let somebody trick us in to reading some random block of memory
if (strncmp("mem://", pathStr.string(), 6) == 0) {
jniThrowException(
@@ -114,110 +123,38 @@ android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
return;
}
// headers is a Map<String, String>.
// We build a similar KeyedVector out of it.
KeyedVector<String8, String8> headersVector;
if (headers) {
// Get the Map's entry Set.
jclass mapClass = env->FindClass("java/util/Map");
if (mapClass == NULL) {
for (int i = 0; i < nKeyValuePairs; ++i) {
// No need to check on the ArrayIndexOutOfBoundsException, since
// it won't happen here.
jstring key = (jstring) env->GetObjectArrayElement(keys, i);
jstring value = (jstring) env->GetObjectArrayElement(values, i);
const char* keyStr = env->GetStringUTFChars(key, NULL);
if (!keyStr) { // OutOfMemoryError
return;
}
jmethodID entrySet =
env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
if (entrySet == NULL) {
return;
}
jobject set = env->CallObjectMethod(headers, entrySet);
if (set == NULL) {
return;
}
// Obtain an iterator over the Set
jclass setClass = env->FindClass("java/util/Set");
if (setClass == NULL) {
return;
}
jmethodID iterator =
env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
if (iterator == NULL) {
return;
}
jobject iter = env->CallObjectMethod(set, iterator);
if (iter == NULL) {
return;
}
// Get the Iterator method IDs
jclass iteratorClass = env->FindClass("java/util/Iterator");
if (iteratorClass == NULL) {
return;
}
jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
if (hasNext == NULL) {
return;
}
jmethodID next =
env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
if (next == NULL) {
return;
}
// Get the Entry class method IDs
jclass entryClass = env->FindClass("java/util/Map$Entry");
if (entryClass == NULL) {
return;
}
jmethodID getKey =
env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
if (getKey == NULL) {
return;
}
jmethodID getValue =
env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
if (getValue == NULL) {
return;
}
// Iterate over the entry Set
while (env->CallBooleanMethod(iter, hasNext)) {
jobject entry = env->CallObjectMethod(iter, next);
jstring key = (jstring) env->CallObjectMethod(entry, getKey);
jstring value = (jstring) env->CallObjectMethod(entry, getValue);
const char* keyStr = env->GetStringUTFChars(key, NULL);
if (!keyStr) { // Out of memory
return;
}
const char* valueStr = env->GetStringUTFChars(value, NULL);
if (!valueStr) { // Out of memory
env->ReleaseStringUTFChars(key, keyStr);
return;
}
headersVector.add(String8(keyStr), String8(valueStr));
env->DeleteLocalRef(entry);
const char* valueStr = env->GetStringUTFChars(value, NULL);
if (!valueStr) { // OutOfMemoryError
env->ReleaseStringUTFChars(key, keyStr);
env->DeleteLocalRef(key);
env->ReleaseStringUTFChars(value, valueStr);
env->DeleteLocalRef(value);
return;
}
headersVector.add(String8(keyStr), String8(valueStr));
env->ReleaseStringUTFChars(key, keyStr);
env->ReleaseStringUTFChars(value, valueStr);
env->DeleteLocalRef(key);
env->DeleteLocalRef(value);
}
process_media_retriever_call(
env,
retriever->setDataSource(
pathStr.string(), headers ? &headersVector : NULL),
pathStr.string(), nKeyValuePairs > 0 ? &headersVector : NULL),
"java/lang/RuntimeException",
"setDataSource failed");
@@ -226,7 +163,7 @@ android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
static void android_media_MediaMetadataRetriever_setDataSource(
JNIEnv *env, jobject thiz, jstring path) {
android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
env, thiz, path, NULL);
env, thiz, path, NULL, NULL);
}
static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
@@ -539,7 +476,13 @@ static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobje
// JNI mapping between Java methods and native methods
static JNINativeMethod nativeMethods[] = {
{"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource},
{"setDataSource", "(Ljava/lang/String;Ljava/util/Map;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders},
{
"_setDataSource",
"(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
(void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders
},
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
{"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
{"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},

View File

@@ -186,7 +186,9 @@ static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStat
static void
android_media_MediaPlayer_setDataSourceAndHeaders(
JNIEnv *env, jobject thiz, jstring path, jobject headers) {
JNIEnv *env, jobject thiz, jstring path,
jobjectArray keys, jobjectArray values) {
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -207,112 +209,46 @@ android_media_MediaPlayer_setDataSourceAndHeaders(
env->ReleaseStringUTFChars(path, tmp);
tmp = NULL;
// headers is a Map<String, String>.
// We build a similar KeyedVector out of it.
int nKeyValuePairs = env->GetArrayLength(keys);
if (nKeyValuePairs != env->GetArrayLength(values)) {
LOGE("keys and values have different length: %d <-> %d",
nKeyValuePairs, env->GetArrayLength(values));
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
// We build a KeyedVector out of the key and val arrays
KeyedVector<String8, String8> headersVector;
if (headers) {
// Get the Map's entry Set.
jclass mapClass = env->FindClass("java/util/Map");
if (mapClass == NULL) {
for (int i = 0; i < nKeyValuePairs; ++i) {
// No need to check ArrayIndexOutOfBoundsException, since we
// know it won't happen here.
jstring key = (jstring) env->GetObjectArrayElement(keys, i);
jstring val = (jstring) env->GetObjectArrayElement(values, i);
const char* keyStr = env->GetStringUTFChars(key, NULL);
if (!keyStr) { // OutOfMemoryError
return;
}
jmethodID entrySet =
env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
if (entrySet == NULL) {
return;
}
jobject set = env->CallObjectMethod(headers, entrySet);
if (set == NULL) {
return;
}
// Obtain an iterator over the Set
jclass setClass = env->FindClass("java/util/Set");
if (setClass == NULL) {
return;
}
jmethodID iterator =
env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
if (iterator == NULL) {
return;
}
jobject iter = env->CallObjectMethod(set, iterator);
if (iter == NULL) {
return;
}
// Get the Iterator method IDs
jclass iteratorClass = env->FindClass("java/util/Iterator");
if (iteratorClass == NULL) {
return;
}
jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
if (hasNext == NULL) {
return;
}
jmethodID next =
env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
if (next == NULL) {
return;
}
// Get the Entry class method IDs
jclass entryClass = env->FindClass("java/util/Map$Entry");
if (entryClass == NULL) {
return;
}
jmethodID getKey =
env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
if (getKey == NULL) {
return;
}
jmethodID getValue =
env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
if (getValue == NULL) {
return;
}
// Iterate over the entry Set
while (env->CallBooleanMethod(iter, hasNext)) {
jobject entry = env->CallObjectMethod(iter, next);
jstring key = (jstring) env->CallObjectMethod(entry, getKey);
jstring value = (jstring) env->CallObjectMethod(entry, getValue);
const char* keyStr = env->GetStringUTFChars(key, NULL);
if (!keyStr) { // Out of memory
return;
}
const char* valueStr = env->GetStringUTFChars(value, NULL);
if (!valueStr) { // Out of memory
env->ReleaseStringUTFChars(key, keyStr);
return;
}
headersVector.add(String8(keyStr), String8(valueStr));
env->DeleteLocalRef(entry);
const char* valueStr = env->GetStringUTFChars(val, NULL);
if (!valueStr) { // OutOfMemoryError
env->ReleaseStringUTFChars(key, keyStr);
env->DeleteLocalRef(key);
env->ReleaseStringUTFChars(value, valueStr);
env->DeleteLocalRef(value);
return;
}
headersVector.add(String8(keyStr), String8(valueStr));
env->ReleaseStringUTFChars(key, keyStr);
env->ReleaseStringUTFChars(val, valueStr);
env->DeleteLocalRef(key);
env->DeleteLocalRef(val);
}
LOGV("setDataSource: path %s", pathStr);
status_t opStatus =
mp->setDataSource(
pathStr,
headers ? &headersVector : NULL);
nKeyValuePairs > 0? &headersVector : NULL);
process_media_player_call(
env, thiz, opStatus, "java/io/IOException",
@@ -322,7 +258,7 @@ android_media_MediaPlayer_setDataSourceAndHeaders(
static void
android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)
{
android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, 0);
android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, NULL, NULL);
}
static void
@@ -851,7 +787,13 @@ android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobj
static JNINativeMethod gMethods[] = {
{"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource},
{"setDataSource", "(Ljava/lang/String;Ljava/util/Map;)V",(void *)android_media_MediaPlayer_setDataSourceAndHeaders},
{
"_setDataSource",
"(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
(void *)android_media_MediaPlayer_setDataSourceAndHeaders
},
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
{"_setVideoSurfaceOrSurfaceTexture", "()V", (void *)android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture},
{"prepare", "()V", (void *)android_media_MediaPlayer_prepare},