Loading media/java/android/media/MediaExtractor.java +4 −1 Original line number Diff line number Diff line Loading @@ -434,9 +434,12 @@ final public class MediaExtractor { */ @NonNull public List<AudioPresentation> getAudioPresentations(int trackIndex) { return new ArrayList<AudioPresentation>(); return native_getAudioPresentations(trackIndex); } @NonNull private native List<AudioPresentation> native_getAudioPresentations(int trackIndex); /** * Get the PSSH info if present. * @return a map of uuid-to-bytes, with the uuid specifying Loading media/jni/android_media_AudioPresentation.h +93 −131 Original line number Diff line number Diff line Loading @@ -14,173 +14,135 @@ * limitations under the License. */ #ifndef _ANDROID_MEDIA_AUDIO_PRESENTATION_H_ #define _ANDROID_MEDIA_AUDIO_PRESENTATION_H_ #ifndef _ANDROID_MEDIA_AUDIOPRESENTATION_H_ #define _ANDROID_MEDIA_AUDIOPRESENTATION_H_ #include "jni.h" #include <media/AudioPresentationInfo.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/foundation/ADebug.h> // CHECK #include <media/stagefright/foundation/AudioPresentationInfo.h> #include <nativehelper/ScopedLocalRef.h> namespace android { struct JAudioPresentationInfo { struct fields_t { jclass clazz; jclass clazz = NULL; jmethodID constructID; // list parameters jclass listclazz; jclass listClazz = NULL; jmethodID listConstructId; jmethodID listAddId; // hashmap parameters jclass hashMapClazz = NULL; jmethodID hashMapConstructID; jmethodID hashMapPutID; // ulocale parameters jclass ulocaleClazz = NULL; jmethodID ulocaleConstructID; void init(JNIEnv *env) { jclass lclazz = env->FindClass("android/media/AudioPresentation"); if (lclazz == NULL) { return; } CHECK(lclazz != NULL); clazz = (jclass)env->NewGlobalRef(lclazz); if (clazz == NULL) { return; } CHECK(clazz != NULL); constructID = env->GetMethodID(clazz, "<init>", "(IILandroid/icu/util/ULocale;IZZZLjava/util/Map;)V"); env->DeleteLocalRef(lclazz); CHECK(constructID != NULL); // list objects jclass llistclazz = env->FindClass("java/util/ArrayList"); CHECK(llistclazz != NULL); listclazz = static_cast<jclass>(env->NewGlobalRef(llistclazz)); CHECK(listclazz != NULL); listConstructId = env->GetMethodID(listclazz, "<init>", "()V"); jclass llistClazz = env->FindClass("java/util/ArrayList"); CHECK(llistClazz != NULL); listClazz = static_cast<jclass>(env->NewGlobalRef(llistClazz)); CHECK(listClazz != NULL); listConstructId = env->GetMethodID(listClazz, "<init>", "()V"); CHECK(listConstructId != NULL); listAddId = env->GetMethodID(listclazz, "add", "(Ljava/lang/Object;)Z"); listAddId = env->GetMethodID(listClazz, "add", "(Ljava/lang/Object;)Z"); CHECK(listAddId != NULL); env->DeleteLocalRef(llistclazz); } void exit(JNIEnv *env) { env->DeleteGlobalRef(clazz); clazz = NULL; env->DeleteGlobalRef(listclazz); listclazz = NULL; } }; static status_t ConvertMessageToMap(JNIEnv *env, const sp<AMessage> &msg, jobject *map) { ScopedLocalRef<jclass> hashMapClazz(env, env->FindClass("java/util/HashMap")); if (hashMapClazz.get() == NULL) { return -EINVAL; } jmethodID hashMapConstructID = env->GetMethodID(hashMapClazz.get(), "<init>", "()V"); if (hashMapConstructID == NULL) { return -EINVAL; } jmethodID hashMapPutID = env->GetMethodID( hashMapClazz.get(), // hashmap objects jclass lhashMapClazz = env->FindClass("java/util/HashMap"); CHECK(lhashMapClazz != NULL); hashMapClazz = (jclass)env->NewGlobalRef(lhashMapClazz); CHECK(hashMapClazz != NULL); hashMapConstructID = env->GetMethodID(hashMapClazz, "<init>", "()V"); CHECK(hashMapConstructID != NULL); hashMapPutID = env->GetMethodID( hashMapClazz, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); CHECK(hashMapPutID != NULL); if (hashMapPutID == NULL) { return -EINVAL; } jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID); for (size_t i = 0; i < msg->countEntries(); ++i) { AMessage::Type valueType; const char *key = msg->getEntryNameAt(i, &valueType); if (!strncmp(key, "android._", 9)) { // don't expose private keys (starting with android._) continue; } jobject valueObj = NULL; AString val; CHECK(msg->findString(key, &val)); valueObj = env->NewStringUTF(val.c_str()); if (valueObj != NULL) { ScopedLocalRef<jclass> localeClazz(env, env->FindClass("android/icu/util/ULocale")); if (localeClazz.get() == NULL) { return -EINVAL; } jmethodID localeConstructID = env->GetMethodID(localeClazz.get(), "<init>", "(Ljava/lang/String;)V"); if (localeConstructID == NULL) { return -EINVAL; } jstring jLanguage = env->NewStringUTF(key); jobject jLocale = env->NewObject(localeClazz.get(), localeConstructID, jLanguage); env->CallObjectMethod(hashMap, hashMapPutID, jLocale, valueObj); env->DeleteLocalRef(jLocale); jLocale = NULL; env->DeleteLocalRef(valueObj); valueObj = NULL; env->DeleteLocalRef(jLanguage); jLanguage = NULL; } } *map = hashMap; return OK; jclass lulocaleClazz = env->FindClass("android/icu/util/ULocale"); CHECK(lulocaleClazz != NULL); ulocaleClazz = (jclass)env->NewGlobalRef(lulocaleClazz); CHECK(ulocaleClazz != NULL); ulocaleConstructID = env->GetMethodID(ulocaleClazz, "<init>", "(Ljava/lang/String;)V"); CHECK(ulocaleConstructID != NULL); } jobject asJobject(JNIEnv *env, const fields_t& fields, const AudioPresentationInfo &info) { jobject list = env->NewObject(fields.listclazz, fields.listConstructId); for (size_t i = 0; i < info.countPresentations(); ++i) { const sp<AudioPresentation> &ap = info.getPresentation(i); jobject jLabelObject; sp<AMessage> labelMessage = new AMessage(); for (size_t i = 0; i < ap->mLabels.size(); ++i) { labelMessage->setString(ap->mLabels.keyAt(i).string(), ap->mLabels.valueAt(i).string()); } if (ConvertMessageToMap(env, labelMessage, &jLabelObject) != OK) { return NULL; } ScopedLocalRef<jclass> localeClazz(env, env->FindClass("android/icu/util/ULocale")); if (localeClazz.get() == NULL) { return NULL; } jmethodID localeConstructID = env->GetMethodID(localeClazz.get(), "<init>", "(Ljava/lang/String;)V"); if (localeConstructID == NULL) { return NULL; } jstring jLanguage = env->NewStringUTF(ap->mLanguage.c_str()); jobject jLocale = env->NewObject(localeClazz.get(), localeConstructID, jLanguage); jobject jValueObj = env->NewObject(fields.clazz, fields.constructID, static_cast<jint>(ap->mPresentationId), static_cast<jint>(ap->mProgramId), jLocale, static_cast<jint>(ap->mMasteringIndication), static_cast<jboolean>((ap->mAudioDescriptionAvailable == 1) ? 1 : 0), static_cast<jboolean>((ap->mSpokenSubtitlesAvailable == 1) ? 1 : 0), static_cast<jboolean>((ap->mDialogueEnhancementAvailable == 1) ? 1 : 0), jLabelObject); if (jValueObj == NULL) { env->DeleteLocalRef(jLanguage); jLanguage = NULL; return NULL; void exit(JNIEnv *env) { env->DeleteGlobalRef(clazz); clazz = NULL; env->DeleteGlobalRef(listClazz); listClazz = NULL; env->DeleteGlobalRef(hashMapClazz); hashMapClazz = NULL; env->DeleteGlobalRef(ulocaleClazz); ulocaleClazz = NULL; } }; env->CallBooleanMethod(list, fields.listAddId, jValueObj); env->DeleteLocalRef(jLocale); jLocale = NULL; env->DeleteLocalRef(jValueObj); jValueObj = NULL; env->DeleteLocalRef(jLanguage); jLanguage = NULL; } return list; static jobject asJobject(JNIEnv *env, const fields_t& fields) { return env->NewObject(fields.listClazz, fields.listConstructId); } static void addPresentations(JNIEnv *env, const fields_t& fields, const AudioPresentationCollection& presentations, jobject presentationsJObj) { for (const auto& ap : presentations) { ScopedLocalRef<jobject> jLabelObject = convertLabelsToMap(env, fields, ap.mLabels); if (jLabelObject == nullptr) return; ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(ap.mLanguage.c_str())); if (jLanguage == nullptr) return; ScopedLocalRef<jobject> jLocale(env, env->NewObject( fields.ulocaleClazz, fields.ulocaleConstructID, jLanguage.get())); ScopedLocalRef<jobject> jValueObj(env, env->NewObject(fields.clazz, fields.constructID, static_cast<jint>(ap.mPresentationId), static_cast<jint>(ap.mProgramId), jLocale.get(), static_cast<jint>(ap.mMasteringIndication), static_cast<jboolean>((ap.mAudioDescriptionAvailable == 1) ? 1 : 0), static_cast<jboolean>((ap.mSpokenSubtitlesAvailable == 1) ? 1 : 0), static_cast<jboolean>((ap.mDialogueEnhancementAvailable == 1) ? 1 : 0), jLabelObject.get())); if (jValueObj != nullptr) { env->CallBooleanMethod(presentationsJObj, fields.listAddId, jValueObj.get()); } } } private: static ScopedLocalRef<jobject> convertLabelsToMap( JNIEnv *env, const fields_t& fields, const std::map<std::string, std::string> &labels) { ScopedLocalRef<jobject> nullMap(env, nullptr); ScopedLocalRef<jobject> hashMap(env, env->NewObject( fields.hashMapClazz, fields.hashMapConstructID)); if (hashMap == nullptr) { return nullMap; } for (const auto& label : labels) { ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(label.first.c_str())); if (jLanguage == nullptr) return nullMap; ScopedLocalRef<jobject> jLocale(env, env->NewObject( fields.ulocaleClazz, fields.ulocaleConstructID, jLanguage.get())); if (jLocale == nullptr) return nullMap; ScopedLocalRef<jobject> jValue(env, env->NewStringUTF(label.second.c_str())); if (jValue == nullptr) return nullMap; env->CallObjectMethod(hashMap.get(), fields.hashMapPutID, jLocale.get(), jValue.get()); } return hashMap; } }; } // namespace android Loading media/jni/android_media_MediaExtractor.cpp +33 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define LOG_TAG "MediaExtractor-JNI" #include <utils/Log.h> #include "android_media_AudioPresentation.h" #include "android_media_MediaDataSource.h" #include "android_media_MediaExtractor.h" #include "android_media_MediaMetricsJNI.h" Loading Loading @@ -56,6 +57,7 @@ struct fields_t { }; static fields_t gFields; static JAudioPresentationInfo::fields_t gAudioPresentationFields; JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz) : mClass(NULL), Loading Loading @@ -289,6 +291,10 @@ bool JMediaExtractor::getCachedDuration(int64_t *durationUs, bool *eos) const { return mImpl->getCachedDuration(durationUs, eos); } status_t JMediaExtractor::getAudioPresentations(size_t trackIdx, AudioPresentationCollection *presentations) const { return mImpl->getAudioPresentations(trackIdx, presentations); } } // namespace android //////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -668,6 +674,28 @@ static jboolean android_media_MediaExtractor_getSampleCryptoInfo( return JNI_TRUE; } static jobject android_media_MediaExtractor_getAudioPresentations( JNIEnv *env, jobject thiz, jint trackIdx) { sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); jobject presentationsJObj = JAudioPresentationInfo::asJobject(env, gAudioPresentationFields); if (extractor == NULL) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return presentationsJObj; } AudioPresentationCollection presentations; status_t err = extractor->getAudioPresentations(trackIdx, &presentations); if (err == ERROR_END_OF_STREAM || err == ERROR_UNSUPPORTED) { return presentationsJObj; } else if (err != OK) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return presentationsJObj; } JAudioPresentationInfo::addPresentations( env, gAudioPresentationFields, presentations, presentationsJObj); return presentationsJObj; } static void android_media_MediaExtractor_native_init(JNIEnv *env) { jclass clazz = env->FindClass("android/media/MediaExtractor"); CHECK(clazz != NULL); Loading @@ -683,6 +711,8 @@ static void android_media_MediaExtractor_native_init(JNIEnv *env) { gFields.cryptoInfoSetPatternID = env->GetMethodID(clazz, "setPattern", "(II)V"); gAudioPresentationFields.init(env); } static void android_media_MediaExtractor_native_setup( Loading Loading @@ -963,6 +993,9 @@ static const JNINativeMethod gMethods[] = { {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaExtractor_native_getMetrics}, { "native_getAudioPresentations", "(I)Ljava/util/List;", (void *)android_media_MediaExtractor_getAudioPresentations }, }; int register_android_media_MediaExtractor(JNIEnv *env) { Loading media/jni/android_media_MediaExtractor.h +3 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define _ANDROID_MEDIA_MEDIAEXTRACTOR_H_ #include <media/stagefright/foundation/ABase.h> #include <media/stagefright/foundation/AudioPresentationInfo.h> #include <media/MediaSource.h> #include <media/DataSource.h> #include <utils/Errors.h> Loading Loading @@ -66,6 +67,8 @@ struct JMediaExtractor : public RefBase { status_t getMetrics(Parcel *reply) const; bool getCachedDuration(int64_t *durationUs, bool *eos) const; status_t getAudioPresentations(size_t trackIdx, AudioPresentationCollection *presentations) const; protected: virtual ~JMediaExtractor(); Loading Loading
media/java/android/media/MediaExtractor.java +4 −1 Original line number Diff line number Diff line Loading @@ -434,9 +434,12 @@ final public class MediaExtractor { */ @NonNull public List<AudioPresentation> getAudioPresentations(int trackIndex) { return new ArrayList<AudioPresentation>(); return native_getAudioPresentations(trackIndex); } @NonNull private native List<AudioPresentation> native_getAudioPresentations(int trackIndex); /** * Get the PSSH info if present. * @return a map of uuid-to-bytes, with the uuid specifying Loading
media/jni/android_media_AudioPresentation.h +93 −131 Original line number Diff line number Diff line Loading @@ -14,173 +14,135 @@ * limitations under the License. */ #ifndef _ANDROID_MEDIA_AUDIO_PRESENTATION_H_ #define _ANDROID_MEDIA_AUDIO_PRESENTATION_H_ #ifndef _ANDROID_MEDIA_AUDIOPRESENTATION_H_ #define _ANDROID_MEDIA_AUDIOPRESENTATION_H_ #include "jni.h" #include <media/AudioPresentationInfo.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/foundation/ADebug.h> // CHECK #include <media/stagefright/foundation/AudioPresentationInfo.h> #include <nativehelper/ScopedLocalRef.h> namespace android { struct JAudioPresentationInfo { struct fields_t { jclass clazz; jclass clazz = NULL; jmethodID constructID; // list parameters jclass listclazz; jclass listClazz = NULL; jmethodID listConstructId; jmethodID listAddId; // hashmap parameters jclass hashMapClazz = NULL; jmethodID hashMapConstructID; jmethodID hashMapPutID; // ulocale parameters jclass ulocaleClazz = NULL; jmethodID ulocaleConstructID; void init(JNIEnv *env) { jclass lclazz = env->FindClass("android/media/AudioPresentation"); if (lclazz == NULL) { return; } CHECK(lclazz != NULL); clazz = (jclass)env->NewGlobalRef(lclazz); if (clazz == NULL) { return; } CHECK(clazz != NULL); constructID = env->GetMethodID(clazz, "<init>", "(IILandroid/icu/util/ULocale;IZZZLjava/util/Map;)V"); env->DeleteLocalRef(lclazz); CHECK(constructID != NULL); // list objects jclass llistclazz = env->FindClass("java/util/ArrayList"); CHECK(llistclazz != NULL); listclazz = static_cast<jclass>(env->NewGlobalRef(llistclazz)); CHECK(listclazz != NULL); listConstructId = env->GetMethodID(listclazz, "<init>", "()V"); jclass llistClazz = env->FindClass("java/util/ArrayList"); CHECK(llistClazz != NULL); listClazz = static_cast<jclass>(env->NewGlobalRef(llistClazz)); CHECK(listClazz != NULL); listConstructId = env->GetMethodID(listClazz, "<init>", "()V"); CHECK(listConstructId != NULL); listAddId = env->GetMethodID(listclazz, "add", "(Ljava/lang/Object;)Z"); listAddId = env->GetMethodID(listClazz, "add", "(Ljava/lang/Object;)Z"); CHECK(listAddId != NULL); env->DeleteLocalRef(llistclazz); } void exit(JNIEnv *env) { env->DeleteGlobalRef(clazz); clazz = NULL; env->DeleteGlobalRef(listclazz); listclazz = NULL; } }; static status_t ConvertMessageToMap(JNIEnv *env, const sp<AMessage> &msg, jobject *map) { ScopedLocalRef<jclass> hashMapClazz(env, env->FindClass("java/util/HashMap")); if (hashMapClazz.get() == NULL) { return -EINVAL; } jmethodID hashMapConstructID = env->GetMethodID(hashMapClazz.get(), "<init>", "()V"); if (hashMapConstructID == NULL) { return -EINVAL; } jmethodID hashMapPutID = env->GetMethodID( hashMapClazz.get(), // hashmap objects jclass lhashMapClazz = env->FindClass("java/util/HashMap"); CHECK(lhashMapClazz != NULL); hashMapClazz = (jclass)env->NewGlobalRef(lhashMapClazz); CHECK(hashMapClazz != NULL); hashMapConstructID = env->GetMethodID(hashMapClazz, "<init>", "()V"); CHECK(hashMapConstructID != NULL); hashMapPutID = env->GetMethodID( hashMapClazz, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); CHECK(hashMapPutID != NULL); if (hashMapPutID == NULL) { return -EINVAL; } jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID); for (size_t i = 0; i < msg->countEntries(); ++i) { AMessage::Type valueType; const char *key = msg->getEntryNameAt(i, &valueType); if (!strncmp(key, "android._", 9)) { // don't expose private keys (starting with android._) continue; } jobject valueObj = NULL; AString val; CHECK(msg->findString(key, &val)); valueObj = env->NewStringUTF(val.c_str()); if (valueObj != NULL) { ScopedLocalRef<jclass> localeClazz(env, env->FindClass("android/icu/util/ULocale")); if (localeClazz.get() == NULL) { return -EINVAL; } jmethodID localeConstructID = env->GetMethodID(localeClazz.get(), "<init>", "(Ljava/lang/String;)V"); if (localeConstructID == NULL) { return -EINVAL; } jstring jLanguage = env->NewStringUTF(key); jobject jLocale = env->NewObject(localeClazz.get(), localeConstructID, jLanguage); env->CallObjectMethod(hashMap, hashMapPutID, jLocale, valueObj); env->DeleteLocalRef(jLocale); jLocale = NULL; env->DeleteLocalRef(valueObj); valueObj = NULL; env->DeleteLocalRef(jLanguage); jLanguage = NULL; } } *map = hashMap; return OK; jclass lulocaleClazz = env->FindClass("android/icu/util/ULocale"); CHECK(lulocaleClazz != NULL); ulocaleClazz = (jclass)env->NewGlobalRef(lulocaleClazz); CHECK(ulocaleClazz != NULL); ulocaleConstructID = env->GetMethodID(ulocaleClazz, "<init>", "(Ljava/lang/String;)V"); CHECK(ulocaleConstructID != NULL); } jobject asJobject(JNIEnv *env, const fields_t& fields, const AudioPresentationInfo &info) { jobject list = env->NewObject(fields.listclazz, fields.listConstructId); for (size_t i = 0; i < info.countPresentations(); ++i) { const sp<AudioPresentation> &ap = info.getPresentation(i); jobject jLabelObject; sp<AMessage> labelMessage = new AMessage(); for (size_t i = 0; i < ap->mLabels.size(); ++i) { labelMessage->setString(ap->mLabels.keyAt(i).string(), ap->mLabels.valueAt(i).string()); } if (ConvertMessageToMap(env, labelMessage, &jLabelObject) != OK) { return NULL; } ScopedLocalRef<jclass> localeClazz(env, env->FindClass("android/icu/util/ULocale")); if (localeClazz.get() == NULL) { return NULL; } jmethodID localeConstructID = env->GetMethodID(localeClazz.get(), "<init>", "(Ljava/lang/String;)V"); if (localeConstructID == NULL) { return NULL; } jstring jLanguage = env->NewStringUTF(ap->mLanguage.c_str()); jobject jLocale = env->NewObject(localeClazz.get(), localeConstructID, jLanguage); jobject jValueObj = env->NewObject(fields.clazz, fields.constructID, static_cast<jint>(ap->mPresentationId), static_cast<jint>(ap->mProgramId), jLocale, static_cast<jint>(ap->mMasteringIndication), static_cast<jboolean>((ap->mAudioDescriptionAvailable == 1) ? 1 : 0), static_cast<jboolean>((ap->mSpokenSubtitlesAvailable == 1) ? 1 : 0), static_cast<jboolean>((ap->mDialogueEnhancementAvailable == 1) ? 1 : 0), jLabelObject); if (jValueObj == NULL) { env->DeleteLocalRef(jLanguage); jLanguage = NULL; return NULL; void exit(JNIEnv *env) { env->DeleteGlobalRef(clazz); clazz = NULL; env->DeleteGlobalRef(listClazz); listClazz = NULL; env->DeleteGlobalRef(hashMapClazz); hashMapClazz = NULL; env->DeleteGlobalRef(ulocaleClazz); ulocaleClazz = NULL; } }; env->CallBooleanMethod(list, fields.listAddId, jValueObj); env->DeleteLocalRef(jLocale); jLocale = NULL; env->DeleteLocalRef(jValueObj); jValueObj = NULL; env->DeleteLocalRef(jLanguage); jLanguage = NULL; } return list; static jobject asJobject(JNIEnv *env, const fields_t& fields) { return env->NewObject(fields.listClazz, fields.listConstructId); } static void addPresentations(JNIEnv *env, const fields_t& fields, const AudioPresentationCollection& presentations, jobject presentationsJObj) { for (const auto& ap : presentations) { ScopedLocalRef<jobject> jLabelObject = convertLabelsToMap(env, fields, ap.mLabels); if (jLabelObject == nullptr) return; ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(ap.mLanguage.c_str())); if (jLanguage == nullptr) return; ScopedLocalRef<jobject> jLocale(env, env->NewObject( fields.ulocaleClazz, fields.ulocaleConstructID, jLanguage.get())); ScopedLocalRef<jobject> jValueObj(env, env->NewObject(fields.clazz, fields.constructID, static_cast<jint>(ap.mPresentationId), static_cast<jint>(ap.mProgramId), jLocale.get(), static_cast<jint>(ap.mMasteringIndication), static_cast<jboolean>((ap.mAudioDescriptionAvailable == 1) ? 1 : 0), static_cast<jboolean>((ap.mSpokenSubtitlesAvailable == 1) ? 1 : 0), static_cast<jboolean>((ap.mDialogueEnhancementAvailable == 1) ? 1 : 0), jLabelObject.get())); if (jValueObj != nullptr) { env->CallBooleanMethod(presentationsJObj, fields.listAddId, jValueObj.get()); } } } private: static ScopedLocalRef<jobject> convertLabelsToMap( JNIEnv *env, const fields_t& fields, const std::map<std::string, std::string> &labels) { ScopedLocalRef<jobject> nullMap(env, nullptr); ScopedLocalRef<jobject> hashMap(env, env->NewObject( fields.hashMapClazz, fields.hashMapConstructID)); if (hashMap == nullptr) { return nullMap; } for (const auto& label : labels) { ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(label.first.c_str())); if (jLanguage == nullptr) return nullMap; ScopedLocalRef<jobject> jLocale(env, env->NewObject( fields.ulocaleClazz, fields.ulocaleConstructID, jLanguage.get())); if (jLocale == nullptr) return nullMap; ScopedLocalRef<jobject> jValue(env, env->NewStringUTF(label.second.c_str())); if (jValue == nullptr) return nullMap; env->CallObjectMethod(hashMap.get(), fields.hashMapPutID, jLocale.get(), jValue.get()); } return hashMap; } }; } // namespace android Loading
media/jni/android_media_MediaExtractor.cpp +33 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define LOG_TAG "MediaExtractor-JNI" #include <utils/Log.h> #include "android_media_AudioPresentation.h" #include "android_media_MediaDataSource.h" #include "android_media_MediaExtractor.h" #include "android_media_MediaMetricsJNI.h" Loading Loading @@ -56,6 +57,7 @@ struct fields_t { }; static fields_t gFields; static JAudioPresentationInfo::fields_t gAudioPresentationFields; JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz) : mClass(NULL), Loading Loading @@ -289,6 +291,10 @@ bool JMediaExtractor::getCachedDuration(int64_t *durationUs, bool *eos) const { return mImpl->getCachedDuration(durationUs, eos); } status_t JMediaExtractor::getAudioPresentations(size_t trackIdx, AudioPresentationCollection *presentations) const { return mImpl->getAudioPresentations(trackIdx, presentations); } } // namespace android //////////////////////////////////////////////////////////////////////////////// Loading Loading @@ -668,6 +674,28 @@ static jboolean android_media_MediaExtractor_getSampleCryptoInfo( return JNI_TRUE; } static jobject android_media_MediaExtractor_getAudioPresentations( JNIEnv *env, jobject thiz, jint trackIdx) { sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); jobject presentationsJObj = JAudioPresentationInfo::asJobject(env, gAudioPresentationFields); if (extractor == NULL) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return presentationsJObj; } AudioPresentationCollection presentations; status_t err = extractor->getAudioPresentations(trackIdx, &presentations); if (err == ERROR_END_OF_STREAM || err == ERROR_UNSUPPORTED) { return presentationsJObj; } else if (err != OK) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return presentationsJObj; } JAudioPresentationInfo::addPresentations( env, gAudioPresentationFields, presentations, presentationsJObj); return presentationsJObj; } static void android_media_MediaExtractor_native_init(JNIEnv *env) { jclass clazz = env->FindClass("android/media/MediaExtractor"); CHECK(clazz != NULL); Loading @@ -683,6 +711,8 @@ static void android_media_MediaExtractor_native_init(JNIEnv *env) { gFields.cryptoInfoSetPatternID = env->GetMethodID(clazz, "setPattern", "(II)V"); gAudioPresentationFields.init(env); } static void android_media_MediaExtractor_native_setup( Loading Loading @@ -963,6 +993,9 @@ static const JNINativeMethod gMethods[] = { {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaExtractor_native_getMetrics}, { "native_getAudioPresentations", "(I)Ljava/util/List;", (void *)android_media_MediaExtractor_getAudioPresentations }, }; int register_android_media_MediaExtractor(JNIEnv *env) { Loading
media/jni/android_media_MediaExtractor.h +3 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define _ANDROID_MEDIA_MEDIAEXTRACTOR_H_ #include <media/stagefright/foundation/ABase.h> #include <media/stagefright/foundation/AudioPresentationInfo.h> #include <media/MediaSource.h> #include <media/DataSource.h> #include <utils/Errors.h> Loading Loading @@ -66,6 +67,8 @@ struct JMediaExtractor : public RefBase { status_t getMetrics(Parcel *reply) const; bool getCachedDuration(int64_t *durationUs, bool *eos) const; status_t getAudioPresentations(size_t trackIdx, AudioPresentationCollection *presentations) const; protected: virtual ~JMediaExtractor(); Loading