123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- /*
- * Copyright 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- //#define LOG_NDEBUG 0
- #define LOG_TAG "MediaCodec-JNI"
- #include <utils/Log.h>
- #include <media/stagefright/foundation/ADebug.h>
- #include <media/stagefright/foundation/AMessage.h>
- #include <media/stagefright/MediaCodecList.h>
- #include <media/IMediaCodecList.h>
- #include <media/MediaCodecInfo.h>
- #include <utils/Vector.h>
- #include <vector>
- #include "android_runtime/AndroidRuntime.h"
- #include "jni.h"
- #include <nativehelper/JNIHelp.h>
- #include "android_media_Streams.h"
- using namespace android;
- /**
- * This object unwraps codec aliases into individual codec infos as the Java interface handles
- * aliases in this way.
- */
- class JavaMediaCodecListWrapper {
- public:
- struct Info {
- sp<MediaCodecInfo> info;
- AString alias;
- };
- const Info getCodecInfo(size_t index) const {
- if (index < mInfoList.size()) {
- return mInfoList[index];
- }
- // return
- return Info { nullptr /* info */, "(none)" /* alias */ };
- }
- size_t countCodecs() const {
- return mInfoList.size();
- }
- sp<IMediaCodecList> getCodecList() const {
- return mCodecList;
- }
- size_t findCodecByName(AString name) const {
- auto it = mInfoIndex.find(name);
- return it == mInfoIndex.end() ? -ENOENT : it->second;
- }
- JavaMediaCodecListWrapper(sp<IMediaCodecList> mcl)
- : mCodecList(mcl) {
- size_t numCodecs = mcl->countCodecs();
- for (size_t ix = 0; ix < numCodecs; ++ix) {
- sp<MediaCodecInfo> info = mcl->getCodecInfo(ix);
- Vector<AString> namesAndAliases;
- info->getAliases(&namesAndAliases);
- namesAndAliases.insertAt(0);
- namesAndAliases.editItemAt(0) = info->getCodecName();
- for (const AString &nameOrAlias : namesAndAliases) {
- if (mInfoIndex.count(nameOrAlias) > 0) {
- // skip duplicate names or aliases
- continue;
- }
- mInfoIndex.emplace(nameOrAlias, mInfoList.size());
- mInfoList.emplace_back(Info { info, nameOrAlias });
- }
- }
- }
- private:
- sp<IMediaCodecList> mCodecList;
- std::vector<Info> mInfoList;
- std::map<AString, size_t> mInfoIndex;
- };
- static std::mutex sMutex;
- static std::unique_ptr<JavaMediaCodecListWrapper> sListWrapper;
- static const JavaMediaCodecListWrapper *getCodecList(JNIEnv *env) {
- std::lock_guard<std::mutex> lock(sMutex);
- if (sListWrapper == nullptr) {
- sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
- if (mcl == NULL) {
- // This should never happen unless something is really wrong
- jniThrowException(
- env, "java/lang/RuntimeException", "cannot get MediaCodecList");
- }
- sListWrapper.reset(new JavaMediaCodecListWrapper(mcl));
- }
- return sListWrapper.get();
- }
- static JavaMediaCodecListWrapper::Info getCodecInfo(JNIEnv *env, jint index) {
- const JavaMediaCodecListWrapper *mcl = getCodecList(env);
- if (mcl == nullptr) {
- // Runtime exception already pending.
- return JavaMediaCodecListWrapper::Info { nullptr /* info */, "(none)" /* alias */ };
- }
- JavaMediaCodecListWrapper::Info info = mcl->getCodecInfo(index);
- if (info.info == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- }
- return info;
- }
- static jint android_media_MediaCodecList_getCodecCount(
- JNIEnv *env, jobject /* thiz */) {
- const JavaMediaCodecListWrapper *mcl = getCodecList(env);
- if (mcl == NULL) {
- // Runtime exception already pending.
- return 0;
- }
- return mcl->countCodecs();
- }
- static jstring android_media_MediaCodecList_getCodecName(
- JNIEnv *env, jobject /* thiz */, jint index) {
- JavaMediaCodecListWrapper::Info info = getCodecInfo(env, index);
- if (info.info == NULL) {
- // Runtime exception already pending.
- return NULL;
- }
- const char *name = info.alias.c_str();
- return env->NewStringUTF(name);
- }
- static jstring android_media_MediaCodecList_getCanonicalName(
- JNIEnv *env, jobject /* thiz */, jint index) {
- JavaMediaCodecListWrapper::Info info = getCodecInfo(env, index);
- if (info.info == NULL) {
- // Runtime exception already pending.
- return NULL;
- }
- const char *name = info.info->getCodecName();
- return env->NewStringUTF(name);
- }
- static jint android_media_MediaCodecList_findCodecByName(
- JNIEnv *env, jobject /* thiz */, jstring name) {
- if (name == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return -ENOENT;
- }
- const char *nameStr = env->GetStringUTFChars(name, NULL);
- if (nameStr == NULL) {
- // Out of memory exception already pending.
- return -ENOENT;
- }
- const JavaMediaCodecListWrapper *mcl = getCodecList(env);
- if (mcl == NULL) {
- // Runtime exception already pending.
- env->ReleaseStringUTFChars(name, nameStr);
- return -ENOENT;
- }
- jint ret = mcl->findCodecByName(nameStr);
- env->ReleaseStringUTFChars(name, nameStr);
- return ret;
- }
- static jboolean android_media_MediaCodecList_getAttributes(
- JNIEnv *env, jobject /* thiz */, jint index) {
- JavaMediaCodecListWrapper::Info info = getCodecInfo(env, index);
- if (info.info == NULL) {
- // Runtime exception already pending.
- return 0;
- }
- return info.info->getAttributes();
- }
- static jarray android_media_MediaCodecList_getSupportedTypes(
- JNIEnv *env, jobject /* thiz */, jint index) {
- JavaMediaCodecListWrapper::Info info = getCodecInfo(env, index);
- if (info.info == NULL) {
- // Runtime exception already pending.
- return NULL;
- }
- Vector<AString> types;
- info.info->getSupportedMediaTypes(&types);
- jclass clazz = env->FindClass("java/lang/String");
- CHECK(clazz != NULL);
- jobjectArray array = env->NewObjectArray(types.size(), clazz, NULL);
- for (size_t i = 0; i < types.size(); ++i) {
- jstring obj = env->NewStringUTF(types.itemAt(i).c_str());
- env->SetObjectArrayElement(array, i, obj);
- env->DeleteLocalRef(obj);
- obj = NULL;
- }
- return array;
- }
- static jobject android_media_MediaCodecList_getCodecCapabilities(
- JNIEnv *env, jobject /* thiz */, jint index, jstring type) {
- if (type == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return NULL;
- }
- JavaMediaCodecListWrapper::Info info = getCodecInfo(env, index);
- if (info.info == NULL) {
- // Runtime exception already pending.
- return NULL;
- }
- const char *typeStr = env->GetStringUTFChars(type, NULL);
- if (typeStr == NULL) {
- // Out of memory exception already pending.
- return NULL;
- }
- Vector<MediaCodecInfo::ProfileLevel> profileLevels;
- Vector<uint32_t> colorFormats;
- sp<AMessage> defaultFormat = new AMessage();
- defaultFormat->setString("mime", typeStr);
- // TODO query default-format also from codec/codec list
- const sp<MediaCodecInfo::Capabilities> &capabilities =
- info.info->getCapabilitiesFor(typeStr);
- env->ReleaseStringUTFChars(type, typeStr);
- typeStr = NULL;
- if (capabilities == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return NULL;
- }
- capabilities->getSupportedColorFormats(&colorFormats);
- capabilities->getSupportedProfileLevels(&profileLevels);
- sp<AMessage> details = capabilities->getDetails();
- bool isEncoder = info.info->isEncoder();
- jobject defaultFormatObj = NULL;
- if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
- return NULL;
- }
- jobject infoObj = NULL;
- if (ConvertMessageToMap(env, details, &infoObj)) {
- env->DeleteLocalRef(defaultFormatObj);
- return NULL;
- }
- jclass capsClazz =
- env->FindClass("android/media/MediaCodecInfo$CodecCapabilities");
- CHECK(capsClazz != NULL);
- jclass profileLevelClazz =
- env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel");
- CHECK(profileLevelClazz != NULL);
- jobjectArray profileLevelArray =
- env->NewObjectArray(profileLevels.size(), profileLevelClazz, NULL);
- jfieldID profileField =
- env->GetFieldID(profileLevelClazz, "profile", "I");
- jfieldID levelField =
- env->GetFieldID(profileLevelClazz, "level", "I");
- for (size_t i = 0; i < profileLevels.size(); ++i) {
- const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
- jobject profileLevelObj = env->AllocObject(profileLevelClazz);
- env->SetIntField(profileLevelObj, profileField, src.mProfile);
- env->SetIntField(profileLevelObj, levelField, src.mLevel);
- env->SetObjectArrayElement(profileLevelArray, i, profileLevelObj);
- env->DeleteLocalRef(profileLevelObj);
- profileLevelObj = NULL;
- }
- jintArray colorFormatsArray = env->NewIntArray(colorFormats.size());
- for (size_t i = 0; i < colorFormats.size(); ++i) {
- jint val = colorFormats.itemAt(i);
- env->SetIntArrayRegion(colorFormatsArray, i, 1, &val);
- }
- jmethodID capsConstructID = env->GetMethodID(capsClazz, "<init>",
- "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
- "Ljava/util/Map;Ljava/util/Map;)V");
- jobject caps = env->NewObject(capsClazz, capsConstructID,
- profileLevelArray, colorFormatsArray, isEncoder,
- defaultFormatObj, infoObj);
- env->DeleteLocalRef(profileLevelArray);
- profileLevelArray = NULL;
- env->DeleteLocalRef(colorFormatsArray);
- colorFormatsArray = NULL;
- env->DeleteLocalRef(defaultFormatObj);
- defaultFormatObj = NULL;
- env->DeleteLocalRef(infoObj);
- infoObj = NULL;
- return caps;
- }
- static jobject android_media_MediaCodecList_getGlobalSettings(JNIEnv *env, jobject /* thiz */) {
- const JavaMediaCodecListWrapper *mcl = getCodecList(env);
- if (mcl == NULL) {
- // Runtime exception already pending.
- return NULL;
- }
- const sp<AMessage> settings = mcl->getCodecList()->getGlobalSettings();
- if (settings == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "cannot get global settings");
- return NULL;
- }
- jobject settingsObj = NULL;
- if (ConvertMessageToMap(env, settings, &settingsObj)) {
- return NULL;
- }
- return settingsObj;
- }
- static void android_media_MediaCodecList_native_init(JNIEnv* /* env */) {
- }
- static const JNINativeMethod gMethods[] = {
- { "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
- { "getCanonicalName", "(I)Ljava/lang/String;",
- (void *)android_media_MediaCodecList_getCanonicalName },
- { "getCodecName", "(I)Ljava/lang/String;",
- (void *)android_media_MediaCodecList_getCodecName },
- { "getAttributes", "(I)I", (void *)android_media_MediaCodecList_getAttributes },
- { "getSupportedTypes", "(I)[Ljava/lang/String;",
- (void *)android_media_MediaCodecList_getSupportedTypes },
- { "getCodecCapabilities",
- "(ILjava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;",
- (void *)android_media_MediaCodecList_getCodecCapabilities },
- { "native_getGlobalSettings",
- "()Ljava/util/Map;",
- (void *)android_media_MediaCodecList_getGlobalSettings },
- { "findCodecByName", "(Ljava/lang/String;)I",
- (void *)android_media_MediaCodecList_findCodecByName },
- { "native_init", "()V", (void *)android_media_MediaCodecList_native_init },
- };
- int register_android_media_MediaCodecList(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(env,
- "android/media/MediaCodecList", gMethods, NELEM(gMethods));
- }
|