diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index 5f7f36fb19252..02d6b661aae6e 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -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 headers) + public void setDataSource(String uri, Map headers) + throws IllegalArgumentException { + int i = 0; + String[] keys = new String[headers.size()]; + String[] values = new String[headers.size()]; + for (Map.Entry 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; /** diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 3f799cf4bed9a..6c61297550d14 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -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 headers) - throws IOException, IllegalArgumentException, IllegalStateException; + public void setDataSource(String path, Map headers) + throws IOException, IllegalArgumentException, IllegalStateException + { + int i = 0; + String[] keys = new String[headers.size()]; + String[] values = new String[headers.size()]; + for (Map.Entry 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 diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 2ba9b3f533094..4a2a4af0fa142 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -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. // We build a similar KeyedVector out of it. KeyedVector 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}, diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 8763ebdbc593c..ad744dc28ab83 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -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 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. - // 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 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},