15a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber/*
25a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber * Copyright 2012, The Android Open Source Project
35a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber *
45a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
55a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber * you may not use this file except in compliance with the License.
65a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber * You may obtain a copy of the License at
75a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber *
85a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber *     http://www.apache.org/licenses/LICENSE-2.0
95a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber *
105a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber * Unless required by applicable law or agreed to in writing, software
115a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
125a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber * See the License for the specific language governing permissions and
145a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber * limitations under the License.
155a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber */
165a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
175a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber//#define LOG_NDEBUG 0
185a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber#define LOG_TAG "MediaCodec-JNI"
195a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber#include <utils/Log.h>
205a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
215a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber#include <media/stagefright/foundation/ADebug.h>
225a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber#include <media/stagefright/MediaCodecList.h>
235a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
245a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber#include "android_runtime/AndroidRuntime.h"
255a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber#include "jni.h"
265a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber#include "JNIHelp.h"
275a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
285a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huberusing namespace android;
295a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
3060d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huberstatic jint android_media_MediaCodecList_getCodecCount(
315a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        JNIEnv *env, jobject thiz) {
325a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    return MediaCodecList::getInstance()->countCodecs();
335a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber}
345a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
355a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huberstatic jstring android_media_MediaCodecList_getCodecName(
365a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        JNIEnv *env, jobject thiz, jint index) {
375a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    const char *name = MediaCodecList::getInstance()->getCodecName(index);
385a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
395a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    if (name == NULL) {
405a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
415a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        return NULL;
425a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    }
435a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
445a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    return env->NewStringUTF(name);
455a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber}
465a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
475a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huberstatic jboolean android_media_MediaCodecList_isEncoder(
485a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        JNIEnv *env, jobject thiz, jint index) {
495a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    return MediaCodecList::getInstance()->isEncoder(index);
505a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber}
515a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
525a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huberstatic jarray android_media_MediaCodecList_getSupportedTypes(
535a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        JNIEnv *env, jobject thiz, jint index) {
545a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    Vector<AString> types;
555a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    status_t err =
565a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        MediaCodecList::getInstance()->getSupportedTypes(index, &types);
575a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
585a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    if (err != OK) {
595a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
605a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        return NULL;
615a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    }
625a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
635a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    jclass clazz = env->FindClass("java/lang/String");
645a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    CHECK(clazz != NULL);
655a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
665a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    jobjectArray array = env->NewObjectArray(types.size(), clazz, NULL);
675a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
685a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    for (size_t i = 0; i < types.size(); ++i) {
695a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        jstring obj = env->NewStringUTF(types.itemAt(i).c_str());
705a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        env->SetObjectArrayElement(array, i, obj);
715a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        env->DeleteLocalRef(obj);
725a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        obj = NULL;
735a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    }
745a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
755a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    return array;
765a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber}
775a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
785a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huberstatic jobject android_media_MediaCodecList_getCodecCapabilities(
795a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        JNIEnv *env, jobject thiz, jint index, jstring type) {
805a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    if (type == NULL) {
815a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
825a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        return NULL;
835a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    }
845a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
855a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    const char *typeStr = env->GetStringUTFChars(type, NULL);
865a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
875a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    if (typeStr == NULL) {
885a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        // Out of memory exception already pending.
895a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        return NULL;
905a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    }
915a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
925a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    Vector<MediaCodecList::ProfileLevel> profileLevels;
935a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    Vector<uint32_t> colorFormats;
945a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
955a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    status_t err =
965a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        MediaCodecList::getInstance()->getCodecCapabilities(
975a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber                index, typeStr, &profileLevels, &colorFormats);
985a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
995a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    env->ReleaseStringUTFChars(type, typeStr);
1005a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    typeStr = NULL;
1015a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1025a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    if (err != OK) {
1035a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1045a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        return NULL;
1055a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    }
1065a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1075a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    jclass capsClazz =
10860d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber        env->FindClass("android/media/MediaCodecInfo$CodecCapabilities");
1095a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    CHECK(capsClazz != NULL);
1105a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1115a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    jobject caps = env->AllocObject(capsClazz);
1125a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1135a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    jclass profileLevelClazz =
11460d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber        env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel");
1155a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    CHECK(profileLevelClazz != NULL);
1165a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1175a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    jobjectArray profileLevelArray =
1185a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        env->NewObjectArray(profileLevels.size(), profileLevelClazz, NULL);
1195a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1205a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    jfieldID profileField =
12107ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        env->GetFieldID(profileLevelClazz, "profile", "I");
1225a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1235a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    jfieldID levelField =
12407ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber        env->GetFieldID(profileLevelClazz, "level", "I");
1255a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1265a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    for (size_t i = 0; i < profileLevels.size(); ++i) {
1275a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        const MediaCodecList::ProfileLevel &src = profileLevels.itemAt(i);
1285a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1295a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        jobject profileLevelObj = env->AllocObject(profileLevelClazz);
1305a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1315a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        env->SetIntField(profileLevelObj, profileField, src.mProfile);
1325a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        env->SetIntField(profileLevelObj, levelField, src.mLevel);
1335a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1345a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        env->SetObjectArrayElement(profileLevelArray, i, profileLevelObj);
1355a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1365a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        env->DeleteLocalRef(profileLevelObj);
1375a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        profileLevelObj = NULL;
1385a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    }
1395a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1405a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    jfieldID profileLevelsField = env->GetFieldID(
1415a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber            capsClazz,
14207ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            "profileLevels",
14360d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber            "[Landroid/media/MediaCodecInfo$CodecProfileLevel;");
1445a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1455a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    env->SetObjectField(caps, profileLevelsField, profileLevelArray);
1465a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1475a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    env->DeleteLocalRef(profileLevelArray);
1485a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    profileLevelArray = NULL;
1495a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1505a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    jintArray colorFormatsArray = env->NewIntArray(colorFormats.size());
1515a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1525a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    for (size_t i = 0; i < colorFormats.size(); ++i) {
1535a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        jint val = colorFormats.itemAt(i);
1545a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber        env->SetIntArrayRegion(colorFormatsArray, i, 1, &val);
1555a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    }
1565a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1575a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    jfieldID colorFormatsField = env->GetFieldID(
15807ea426e3ae8915ca6bf67135f523f42cd920af0Andreas Huber            capsClazz, "colorFormats", "[I");
1595a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1605a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    env->SetObjectField(caps, colorFormatsField, colorFormatsArray);
1615a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1625a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    env->DeleteLocalRef(colorFormatsArray);
1635a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    colorFormatsArray = NULL;
1645a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1655a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    return caps;
1665a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber}
1675a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1685a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huberstatic void android_media_MediaCodecList_native_init(JNIEnv *env) {
1695a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber}
1705a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1715a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huberstatic JNINativeMethod gMethods[] = {
17260d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber    { "getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
1735a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    { "getCodecName", "(I)Ljava/lang/String;",
1745a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber      (void *)android_media_MediaCodecList_getCodecName },
1755a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    { "isEncoder", "(I)Z", (void *)android_media_MediaCodecList_isEncoder },
1765a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    { "getSupportedTypes", "(I)[Ljava/lang/String;",
1775a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber      (void *)android_media_MediaCodecList_getSupportedTypes },
1785a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1795a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    { "getCodecCapabilities",
18060d610bf103379277a4b29a7ead4f013f6128e4eAndreas Huber      "(ILjava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;",
1815a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber      (void *)android_media_MediaCodecList_getCodecCapabilities },
1825a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1835a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    { "native_init", "()V", (void *)android_media_MediaCodecList_native_init },
1845a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber};
1855a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
1865a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huberint register_android_media_MediaCodecList(JNIEnv *env) {
1875a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber    return AndroidRuntime::registerNativeMethods(env,
1885a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber                "android/media/MediaCodecList", gMethods, NELEM(gMethods));
1895a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber}
1905a04bf395514a9342dd26af519b88f4b3e309eb9Andreas Huber
191