blob: ed1eeb9733093ed3dc08e8e900aa52437fd2dd13 [file] [log] [blame]
Andreas Huber5a04bf32012-03-29 16:41:38 -07001/*
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>
Lajos Molnarb58dc312014-07-18 12:10:33 -070022#include <media/stagefright/foundation/AMessage.h>
Andreas Huber5a04bf32012-03-29 16:41:38 -070023#include <media/stagefright/MediaCodecList.h>
24
25#include "android_runtime/AndroidRuntime.h"
26#include "jni.h"
27#include "JNIHelp.h"
Lajos Molnarb58dc312014-07-18 12:10:33 -070028#include "android_media_Utils.h"
Andreas Huber5a04bf32012-03-29 16:41:38 -070029
30using namespace android;
31
Andreas Huber60d610b2012-05-02 16:06:09 -070032static jint android_media_MediaCodecList_getCodecCount(
Andreas Huber5a04bf32012-03-29 16:41:38 -070033 JNIEnv *env, jobject thiz) {
34 return MediaCodecList::getInstance()->countCodecs();
35}
36
37static jstring android_media_MediaCodecList_getCodecName(
38 JNIEnv *env, jobject thiz, jint index) {
39 const char *name = MediaCodecList::getInstance()->getCodecName(index);
40
41 if (name == NULL) {
42 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
43 return NULL;
44 }
45
46 return env->NewStringUTF(name);
47}
48
Martin Storsjo93077a22012-09-25 11:55:25 +030049static jint android_media_MediaCodecList_findCodecByName(
50 JNIEnv *env, jobject thiz, jstring name) {
51 if (name == NULL) {
52 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
53 return -ENOENT;
54 }
55
56 const char *nameStr = env->GetStringUTFChars(name, NULL);
57
58 if (nameStr == NULL) {
59 // Out of memory exception already pending.
60 return -ENOENT;
61 }
62
63 jint ret = MediaCodecList::getInstance()->findCodecByName(nameStr);
64 env->ReleaseStringUTFChars(name, nameStr);
65 return ret;
66}
67
Andreas Huber5a04bf32012-03-29 16:41:38 -070068static jboolean android_media_MediaCodecList_isEncoder(
69 JNIEnv *env, jobject thiz, jint index) {
70 return MediaCodecList::getInstance()->isEncoder(index);
71}
72
73static jarray android_media_MediaCodecList_getSupportedTypes(
74 JNIEnv *env, jobject thiz, jint index) {
75 Vector<AString> types;
76 status_t err =
77 MediaCodecList::getInstance()->getSupportedTypes(index, &types);
78
79 if (err != OK) {
80 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
81 return NULL;
82 }
83
84 jclass clazz = env->FindClass("java/lang/String");
85 CHECK(clazz != NULL);
86
87 jobjectArray array = env->NewObjectArray(types.size(), clazz, NULL);
88
89 for (size_t i = 0; i < types.size(); ++i) {
90 jstring obj = env->NewStringUTF(types.itemAt(i).c_str());
91 env->SetObjectArrayElement(array, i, obj);
92 env->DeleteLocalRef(obj);
93 obj = NULL;
94 }
95
96 return array;
97}
98
99static jobject android_media_MediaCodecList_getCodecCapabilities(
100 JNIEnv *env, jobject thiz, jint index, jstring type) {
101 if (type == NULL) {
102 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
103 return NULL;
104 }
105
106 const char *typeStr = env->GetStringUTFChars(type, NULL);
107
108 if (typeStr == NULL) {
109 // Out of memory exception already pending.
110 return NULL;
111 }
112
113 Vector<MediaCodecList::ProfileLevel> profileLevels;
114 Vector<uint32_t> colorFormats;
Lajos Molnar80c44372013-05-10 09:24:12 -0700115 uint32_t flags;
Lajos Molnarb58dc312014-07-18 12:10:33 -0700116 sp<AMessage> capabilities;
117
118 sp<AMessage> defaultFormat = new AMessage();
119 defaultFormat->setString("mime", typeStr);
120
121 // TODO query default-format also from codec/codec list
Andreas Huber5a04bf32012-03-29 16:41:38 -0700122
123 status_t err =
124 MediaCodecList::getInstance()->getCodecCapabilities(
Lajos Molnarb58dc312014-07-18 12:10:33 -0700125 index, typeStr, &profileLevels, &colorFormats, &flags,
126 &capabilities);
127
128 bool isEncoder = MediaCodecList::getInstance()->isEncoder(index);
Andreas Huber5a04bf32012-03-29 16:41:38 -0700129
130 env->ReleaseStringUTFChars(type, typeStr);
131 typeStr = NULL;
132
133 if (err != OK) {
134 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
135 return NULL;
136 }
137
Lajos Molnarb58dc312014-07-18 12:10:33 -0700138 jobject defaultFormatObj = NULL;
139 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
140 return NULL;
141 }
142
143 jobject infoObj = NULL;
144 if (ConvertMessageToMap(env, capabilities, &infoObj)) {
145 env->DeleteLocalRef(defaultFormatObj);
146 return NULL;
147 }
148
Andreas Huber5a04bf32012-03-29 16:41:38 -0700149 jclass capsClazz =
Andreas Huber60d610b2012-05-02 16:06:09 -0700150 env->FindClass("android/media/MediaCodecInfo$CodecCapabilities");
Andreas Huber5a04bf32012-03-29 16:41:38 -0700151 CHECK(capsClazz != NULL);
152
Andreas Huber5a04bf32012-03-29 16:41:38 -0700153 jclass profileLevelClazz =
Andreas Huber60d610b2012-05-02 16:06:09 -0700154 env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel");
Andreas Huber5a04bf32012-03-29 16:41:38 -0700155 CHECK(profileLevelClazz != NULL);
156
157 jobjectArray profileLevelArray =
158 env->NewObjectArray(profileLevels.size(), profileLevelClazz, NULL);
159
160 jfieldID profileField =
Andreas Huber07ea4262012-04-11 12:21:20 -0700161 env->GetFieldID(profileLevelClazz, "profile", "I");
Andreas Huber5a04bf32012-03-29 16:41:38 -0700162
163 jfieldID levelField =
Andreas Huber07ea4262012-04-11 12:21:20 -0700164 env->GetFieldID(profileLevelClazz, "level", "I");
Andreas Huber5a04bf32012-03-29 16:41:38 -0700165
166 for (size_t i = 0; i < profileLevels.size(); ++i) {
167 const MediaCodecList::ProfileLevel &src = profileLevels.itemAt(i);
168
169 jobject profileLevelObj = env->AllocObject(profileLevelClazz);
170
171 env->SetIntField(profileLevelObj, profileField, src.mProfile);
172 env->SetIntField(profileLevelObj, levelField, src.mLevel);
173
174 env->SetObjectArrayElement(profileLevelArray, i, profileLevelObj);
175
176 env->DeleteLocalRef(profileLevelObj);
177 profileLevelObj = NULL;
178 }
179
Andreas Huber5a04bf32012-03-29 16:41:38 -0700180 jintArray colorFormatsArray = env->NewIntArray(colorFormats.size());
181
182 for (size_t i = 0; i < colorFormats.size(); ++i) {
183 jint val = colorFormats.itemAt(i);
184 env->SetIntArrayRegion(colorFormatsArray, i, 1, &val);
185 }
186
Lajos Molnarb58dc312014-07-18 12:10:33 -0700187 jmethodID capsConstructID = env->GetMethodID(capsClazz, "<init>",
188 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI"
189 "Ljava/util/Map;Ljava/util/Map;)V");
190
191 jobject caps = env->NewObject(capsClazz, capsConstructID,
192 profileLevelArray, colorFormatsArray, isEncoder, flags,
193 defaultFormatObj, infoObj);
194
195#if 0
196 jfieldID profileLevelsField = env->GetFieldID(
197 capsClazz,
198 "profileLevels",
199 "[Landroid/media/MediaCodecInfo$CodecProfileLevel;");
200
201 env->SetObjectField(caps, profileLevelsField, profileLevelArray);
202
203 jfieldID flagsField =
204 env->GetFieldID(capsClazz, "mFlagsVerified", "I");
205
206 env->SetIntField(caps, flagsField, flags);
207
Andreas Huber5a04bf32012-03-29 16:41:38 -0700208 jfieldID colorFormatsField = env->GetFieldID(
Andreas Huber07ea4262012-04-11 12:21:20 -0700209 capsClazz, "colorFormats", "[I");
Andreas Huber5a04bf32012-03-29 16:41:38 -0700210
211 env->SetObjectField(caps, colorFormatsField, colorFormatsArray);
212
Lajos Molnarb58dc312014-07-18 12:10:33 -0700213#endif
214
215 env->DeleteLocalRef(profileLevelArray);
216 profileLevelArray = NULL;
217
Andreas Huber5a04bf32012-03-29 16:41:38 -0700218 env->DeleteLocalRef(colorFormatsArray);
219 colorFormatsArray = NULL;
220
Lajos Molnarb58dc312014-07-18 12:10:33 -0700221 env->DeleteLocalRef(defaultFormatObj);
222 defaultFormatObj = NULL;
223
224 env->DeleteLocalRef(infoObj);
225 infoObj = NULL;
226
Andreas Huber5a04bf32012-03-29 16:41:38 -0700227 return caps;
228}
229
230static void android_media_MediaCodecList_native_init(JNIEnv *env) {
231}
232
233static JNINativeMethod gMethods[] = {
Lajos Molnarb58dc312014-07-18 12:10:33 -0700234 { "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
Andreas Huber5a04bf32012-03-29 16:41:38 -0700235 { "getCodecName", "(I)Ljava/lang/String;",
236 (void *)android_media_MediaCodecList_getCodecName },
237 { "isEncoder", "(I)Z", (void *)android_media_MediaCodecList_isEncoder },
238 { "getSupportedTypes", "(I)[Ljava/lang/String;",
239 (void *)android_media_MediaCodecList_getSupportedTypes },
240
241 { "getCodecCapabilities",
Andreas Huber60d610b2012-05-02 16:06:09 -0700242 "(ILjava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;",
Andreas Huber5a04bf32012-03-29 16:41:38 -0700243 (void *)android_media_MediaCodecList_getCodecCapabilities },
244
Martin Storsjo93077a22012-09-25 11:55:25 +0300245 { "findCodecByName", "(Ljava/lang/String;)I",
246 (void *)android_media_MediaCodecList_findCodecByName },
247
Andreas Huber5a04bf32012-03-29 16:41:38 -0700248 { "native_init", "()V", (void *)android_media_MediaCodecList_native_init },
249};
250
251int register_android_media_MediaCodecList(JNIEnv *env) {
252 return AndroidRuntime::registerNativeMethods(env,
253 "android/media/MediaCodecList", gMethods, NELEM(gMethods));
254}
255