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:
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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},
|
||||
|
||||
Reference in New Issue
Block a user