Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1cd5f0d4 authored by Andreas Huber's avatar Andreas Huber Committed by Android (Google) Code Review
Browse files

Merge "New API to query available codecs and their capabilities."

parents ee80082e 5a04bf39
Loading
Loading
Loading
Loading
+51 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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.
 */

package android.media;

/**
 * MediaCodecList class can be used to enumerate available codecs,
 * find a codec supporting a given format and query the capabilities
 * of a given codec.
 * @hide
*/
final public class MediaCodecList {
    public static native final int countCodecs();
    public static native final String getCodecName(int index);
    public static native final boolean isEncoder(int index);
    public static native final String[] getSupportedTypes(int index);

    public static final class CodecProfileLevel {
        public int mProfile;
        public int mLevel;
    };

    public static final class CodecCapabilities {
        public CodecProfileLevel[] mProfileLevels;
        public int[] mColorFormats;
    };
    public static native final CodecCapabilities getCodecCapabilities(
            int index, String type);

    private static native final void native_init();

    private MediaCodecList() {}

    static {
        System.loadLibrary("media_jni");
        native_init();
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    android_media_MediaCodec.cpp \
    android_media_MediaCodecList.cpp \
    android_media_MediaExtractor.cpp \
    android_media_MediaPlayer.cpp \
    android_media_MediaRecorder.cpp \
+190 −0
Original line number Diff line number Diff line
/*
 * 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/MediaCodecList.h>

#include "android_runtime/AndroidRuntime.h"
#include "jni.h"
#include "JNIHelp.h"

using namespace android;

static jint android_media_MediaCodecList_countCodecs(
        JNIEnv *env, jobject thiz) {
    return MediaCodecList::getInstance()->countCodecs();
}

static jstring android_media_MediaCodecList_getCodecName(
        JNIEnv *env, jobject thiz, jint index) {
    const char *name = MediaCodecList::getInstance()->getCodecName(index);

    if (name == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return NULL;
    }

    return env->NewStringUTF(name);
}

static jboolean android_media_MediaCodecList_isEncoder(
        JNIEnv *env, jobject thiz, jint index) {
    return MediaCodecList::getInstance()->isEncoder(index);
}

static jarray android_media_MediaCodecList_getSupportedTypes(
        JNIEnv *env, jobject thiz, jint index) {
    Vector<AString> types;
    status_t err =
        MediaCodecList::getInstance()->getSupportedTypes(index, &types);

    if (err != OK) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return NULL;
    }

    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;
    }

    const char *typeStr = env->GetStringUTFChars(type, NULL);

    if (typeStr == NULL) {
        // Out of memory exception already pending.
        return NULL;
    }

    Vector<MediaCodecList::ProfileLevel> profileLevels;
    Vector<uint32_t> colorFormats;

    status_t err =
        MediaCodecList::getInstance()->getCodecCapabilities(
                index, typeStr, &profileLevels, &colorFormats);

    env->ReleaseStringUTFChars(type, typeStr);
    typeStr = NULL;

    if (err != OK) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return NULL;
    }

    jclass capsClazz =
        env->FindClass("android/media/MediaCodecList$CodecCapabilities");
    CHECK(capsClazz != NULL);

    jobject caps = env->AllocObject(capsClazz);

    jclass profileLevelClazz =
        env->FindClass("android/media/MediaCodecList$CodecProfileLevel");
    CHECK(profileLevelClazz != NULL);

    jobjectArray profileLevelArray =
        env->NewObjectArray(profileLevels.size(), profileLevelClazz, NULL);

    jfieldID profileField =
        env->GetFieldID(profileLevelClazz, "mProfile", "I");

    jfieldID levelField =
        env->GetFieldID(profileLevelClazz, "mLevel", "I");

    for (size_t i = 0; i < profileLevels.size(); ++i) {
        const MediaCodecList::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;
    }

    jfieldID profileLevelsField = env->GetFieldID(
            capsClazz,
            "mProfileLevels",
            "[Landroid/media/MediaCodecList$CodecProfileLevel;");

    env->SetObjectField(caps, profileLevelsField, profileLevelArray);

    env->DeleteLocalRef(profileLevelArray);
    profileLevelArray = 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);
    }

    jfieldID colorFormatsField = env->GetFieldID(
            capsClazz, "mColorFormats", "[I");

    env->SetObjectField(caps, colorFormatsField, colorFormatsArray);

    env->DeleteLocalRef(colorFormatsArray);
    colorFormatsArray = NULL;

    return caps;
}

static void android_media_MediaCodecList_native_init(JNIEnv *env) {
}

static JNINativeMethod gMethods[] = {
    { "countCodecs", "()I", (void *)android_media_MediaCodecList_countCodecs },
    { "getCodecName", "(I)Ljava/lang/String;",
      (void *)android_media_MediaCodecList_getCodecName },
    { "isEncoder", "(I)Z", (void *)android_media_MediaCodecList_isEncoder },
    { "getSupportedTypes", "(I)[Ljava/lang/String;",
      (void *)android_media_MediaCodecList_getSupportedTypes },

    { "getCodecCapabilities",
      "(ILjava/lang/String;)Landroid/media/MediaCodecList$CodecCapabilities;",
      (void *)android_media_MediaCodecList_getCodecCapabilities },

    { "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));
}
+6 −0
Original line number Diff line number Diff line
@@ -881,6 +881,7 @@ static int register_android_media_MediaPlayer(JNIEnv *env)

extern int register_android_media_MediaCodec(JNIEnv *env);
extern int register_android_media_MediaExtractor(JNIEnv *env);
extern int register_android_media_MediaCodecList(JNIEnv *env);
extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
extern int register_android_media_MediaRecorder(JNIEnv *env);
extern int register_android_media_MediaScanner(JNIEnv *env);
@@ -962,6 +963,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
        goto bail;
    }

    if (register_android_media_MediaCodecList(env) < 0) {
        ALOGE("ERROR: MediaCodec native registration failed");
        goto bail;
    }

    /* success -- return valid version number */
    result = JNI_VERSION_1_4;