android_media_MediaCodecList.cpp revision 80c4437ebfe3e679267a64e4c9d7bdd585b7afce
1/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "MediaCodec-JNI"
19#include <utils/Log.h>
20
21#include <media/stagefright/foundation/ADebug.h>
22#include <media/stagefright/MediaCodecList.h>
23
24#include "android_runtime/AndroidRuntime.h"
25#include "jni.h"
26#include "JNIHelp.h"
27
28using namespace android;
29
30static jint android_media_MediaCodecList_getCodecCount(
31        JNIEnv *env, jobject thiz) {
32    return MediaCodecList::getInstance()->countCodecs();
33}
34
35static jstring android_media_MediaCodecList_getCodecName(
36        JNIEnv *env, jobject thiz, jint index) {
37    const char *name = MediaCodecList::getInstance()->getCodecName(index);
38
39    if (name == NULL) {
40        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
41        return NULL;
42    }
43
44    return env->NewStringUTF(name);
45}
46
47static jint android_media_MediaCodecList_findCodecByName(
48        JNIEnv *env, jobject thiz, jstring name) {
49    if (name == NULL) {
50        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
51        return -ENOENT;
52    }
53
54    const char *nameStr = env->GetStringUTFChars(name, NULL);
55
56    if (nameStr == NULL) {
57        // Out of memory exception already pending.
58        return -ENOENT;
59    }
60
61    jint ret = MediaCodecList::getInstance()->findCodecByName(nameStr);
62    env->ReleaseStringUTFChars(name, nameStr);
63    return ret;
64}
65
66static jboolean android_media_MediaCodecList_isEncoder(
67        JNIEnv *env, jobject thiz, jint index) {
68    return MediaCodecList::getInstance()->isEncoder(index);
69}
70
71static jarray android_media_MediaCodecList_getSupportedTypes(
72        JNIEnv *env, jobject thiz, jint index) {
73    Vector<AString> types;
74    status_t err =
75        MediaCodecList::getInstance()->getSupportedTypes(index, &types);
76
77    if (err != OK) {
78        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
79        return NULL;
80    }
81
82    jclass clazz = env->FindClass("java/lang/String");
83    CHECK(clazz != NULL);
84
85    jobjectArray array = env->NewObjectArray(types.size(), clazz, NULL);
86
87    for (size_t i = 0; i < types.size(); ++i) {
88        jstring obj = env->NewStringUTF(types.itemAt(i).c_str());
89        env->SetObjectArrayElement(array, i, obj);
90        env->DeleteLocalRef(obj);
91        obj = NULL;
92    }
93
94    return array;
95}
96
97static jobject android_media_MediaCodecList_getCodecCapabilities(
98        JNIEnv *env, jobject thiz, jint index, jstring type) {
99    if (type == NULL) {
100        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
101        return NULL;
102    }
103
104    const char *typeStr = env->GetStringUTFChars(type, NULL);
105
106    if (typeStr == NULL) {
107        // Out of memory exception already pending.
108        return NULL;
109    }
110
111    Vector<MediaCodecList::ProfileLevel> profileLevels;
112    Vector<uint32_t> colorFormats;
113    uint32_t flags;
114
115    status_t err =
116        MediaCodecList::getInstance()->getCodecCapabilities(
117                index, typeStr, &profileLevels, &colorFormats, &flags);
118
119    env->ReleaseStringUTFChars(type, typeStr);
120    typeStr = NULL;
121
122    if (err != OK) {
123        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
124        return NULL;
125    }
126
127    jclass capsClazz =
128        env->FindClass("android/media/MediaCodecInfo$CodecCapabilities");
129    CHECK(capsClazz != NULL);
130
131    jfieldID flagsField =
132        env->GetFieldID(capsClazz, "flags", "I");
133
134    jobject caps = env->AllocObject(capsClazz);
135
136    jclass profileLevelClazz =
137        env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel");
138    CHECK(profileLevelClazz != NULL);
139
140    jobjectArray profileLevelArray =
141        env->NewObjectArray(profileLevels.size(), profileLevelClazz, NULL);
142
143    jfieldID profileField =
144        env->GetFieldID(profileLevelClazz, "profile", "I");
145
146    jfieldID levelField =
147        env->GetFieldID(profileLevelClazz, "level", "I");
148
149    for (size_t i = 0; i < profileLevels.size(); ++i) {
150        const MediaCodecList::ProfileLevel &src = profileLevels.itemAt(i);
151
152        jobject profileLevelObj = env->AllocObject(profileLevelClazz);
153
154        env->SetIntField(profileLevelObj, profileField, src.mProfile);
155        env->SetIntField(profileLevelObj, levelField, src.mLevel);
156
157        env->SetObjectArrayElement(profileLevelArray, i, profileLevelObj);
158
159        env->DeleteLocalRef(profileLevelObj);
160        profileLevelObj = NULL;
161    }
162
163    jfieldID profileLevelsField = env->GetFieldID(
164            capsClazz,
165            "profileLevels",
166            "[Landroid/media/MediaCodecInfo$CodecProfileLevel;");
167
168    env->SetObjectField(caps, profileLevelsField, profileLevelArray);
169
170    env->SetIntField(caps, flagsField, flags);
171
172    env->DeleteLocalRef(profileLevelArray);
173    profileLevelArray = NULL;
174
175    jintArray colorFormatsArray = env->NewIntArray(colorFormats.size());
176
177    for (size_t i = 0; i < colorFormats.size(); ++i) {
178        jint val = colorFormats.itemAt(i);
179        env->SetIntArrayRegion(colorFormatsArray, i, 1, &val);
180    }
181
182    jfieldID colorFormatsField = env->GetFieldID(
183            capsClazz, "colorFormats", "[I");
184
185    env->SetObjectField(caps, colorFormatsField, colorFormatsArray);
186
187    env->DeleteLocalRef(colorFormatsArray);
188    colorFormatsArray = NULL;
189
190    return caps;
191}
192
193static void android_media_MediaCodecList_native_init(JNIEnv *env) {
194}
195
196static JNINativeMethod gMethods[] = {
197    { "getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
198    { "getCodecName", "(I)Ljava/lang/String;",
199      (void *)android_media_MediaCodecList_getCodecName },
200    { "isEncoder", "(I)Z", (void *)android_media_MediaCodecList_isEncoder },
201    { "getSupportedTypes", "(I)[Ljava/lang/String;",
202      (void *)android_media_MediaCodecList_getSupportedTypes },
203
204    { "getCodecCapabilities",
205      "(ILjava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;",
206      (void *)android_media_MediaCodecList_getCodecCapabilities },
207
208    { "findCodecByName", "(Ljava/lang/String;)I",
209      (void *)android_media_MediaCodecList_findCodecByName },
210
211    { "native_init", "()V", (void *)android_media_MediaCodecList_native_init },
212};
213
214int register_android_media_MediaCodecList(JNIEnv *env) {
215    return AndroidRuntime::registerNativeMethods(env,
216                "android/media/MediaCodecList", gMethods, NELEM(gMethods));
217}
218
219