blob: cf1494296756e423e63ad127e44796fce1bf3c40 [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>
Lajos Molnarcd5e3f92014-08-06 12:18:34 -070024#include <media/IMediaCodecList.h>
25#include <media/MediaCodecInfo.h>
Andreas Huber5a04bf32012-03-29 16:41:38 -070026
27#include "android_runtime/AndroidRuntime.h"
28#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070029#include <nativehelper/JNIHelp.h>
Lajos Molnarb58dc312014-07-18 12:10:33 -070030#include "android_media_Utils.h"
Andreas Huber5a04bf32012-03-29 16:41:38 -070031
32using namespace android;
33
Lajos Molnarcd5e3f92014-08-06 12:18:34 -070034static sp<IMediaCodecList> getCodecList(JNIEnv *env) {
35 sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
36 if (mcl == NULL) {
37 // This should never happen unless something is really wrong
38 jniThrowException(
39 env, "java/lang/RuntimeException", "cannot get MediaCodecList");
40 }
41 return mcl;
42}
43
Lajos Molnard2a7f472018-11-15 12:49:20 -080044static sp<MediaCodecInfo> getCodecInfo(JNIEnv *env, jint index) {
45 sp<IMediaCodecList> mcl = getCodecList(env);
46 if (mcl == NULL) {
47 // Runtime exception already pending.
48 return NULL;
49 }
50
51 sp<MediaCodecInfo> info = mcl->getCodecInfo(index);
52 if (info == NULL) {
53 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
54 }
55
56 return info;
57}
58
Andreas Huber60d610b2012-05-02 16:06:09 -070059static jint android_media_MediaCodecList_getCodecCount(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -080060 JNIEnv *env, jobject /* thiz */) {
Lajos Molnarcd5e3f92014-08-06 12:18:34 -070061 sp<IMediaCodecList> mcl = getCodecList(env);
62 if (mcl == NULL) {
63 // Runtime exception already pending.
64 return 0;
65 }
66 return mcl->countCodecs();
Andreas Huber5a04bf32012-03-29 16:41:38 -070067}
68
69static jstring android_media_MediaCodecList_getCodecName(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -080070 JNIEnv *env, jobject /* thiz */, jint index) {
Lajos Molnard2a7f472018-11-15 12:49:20 -080071 sp<MediaCodecInfo> info = getCodecInfo(env, index);
72 if (info == NULL) {
Lajos Molnarcd5e3f92014-08-06 12:18:34 -070073 // Runtime exception already pending.
74 return NULL;
75 }
Andreas Huber5a04bf32012-03-29 16:41:38 -070076
Lajos Molnard2a7f472018-11-15 12:49:20 -080077 // TODO: support aliases
78 const char *name = info->getCodecName();
79 return env->NewStringUTF(name);
80}
81
82static jstring android_media_MediaCodecList_getCanonicalName(
83 JNIEnv *env, jobject /* thiz */, jint index) {
84 sp<MediaCodecInfo> info = getCodecInfo(env, index);
Lajos Molnarcd5e3f92014-08-06 12:18:34 -070085 if (info == NULL) {
Lajos Molnard2a7f472018-11-15 12:49:20 -080086 // Runtime exception already pending.
Andreas Huber5a04bf32012-03-29 16:41:38 -070087 return NULL;
88 }
89
Lajos Molnarcd5e3f92014-08-06 12:18:34 -070090 const char *name = info->getCodecName();
Andreas Huber5a04bf32012-03-29 16:41:38 -070091 return env->NewStringUTF(name);
92}
93
Martin Storsjo93077a22012-09-25 11:55:25 +030094static jint android_media_MediaCodecList_findCodecByName(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -080095 JNIEnv *env, jobject /* thiz */, jstring name) {
Martin Storsjo93077a22012-09-25 11:55:25 +030096 if (name == NULL) {
97 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
98 return -ENOENT;
99 }
100
101 const char *nameStr = env->GetStringUTFChars(name, NULL);
Martin Storsjo93077a22012-09-25 11:55:25 +0300102 if (nameStr == NULL) {
103 // Out of memory exception already pending.
104 return -ENOENT;
105 }
106
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700107 sp<IMediaCodecList> mcl = getCodecList(env);
108 if (mcl == NULL) {
109 // Runtime exception already pending.
Lajos Molnar018b70f2014-08-12 11:37:24 -0700110 env->ReleaseStringUTFChars(name, nameStr);
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700111 return -ENOENT;
112 }
113
114 jint ret = mcl->findCodecByName(nameStr);
Martin Storsjo93077a22012-09-25 11:55:25 +0300115 env->ReleaseStringUTFChars(name, nameStr);
116 return ret;
117}
118
Lajos Molnard2a7f472018-11-15 12:49:20 -0800119static jboolean android_media_MediaCodecList_getAttributes(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800120 JNIEnv *env, jobject /* thiz */, jint index) {
Lajos Molnard2a7f472018-11-15 12:49:20 -0800121 sp<MediaCodecInfo> info = getCodecInfo(env, index);
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700122 if (info == NULL) {
Lajos Molnard2a7f472018-11-15 12:49:20 -0800123 // Runtime exception already pending.
124 return 0;
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700125 }
126
Lajos Molnard2a7f472018-11-15 12:49:20 -0800127 return info->getAttributes();
Andreas Huber5a04bf32012-03-29 16:41:38 -0700128}
129
130static jarray android_media_MediaCodecList_getSupportedTypes(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800131 JNIEnv *env, jobject /* thiz */, jint index) {
Lajos Molnard2a7f472018-11-15 12:49:20 -0800132 sp<MediaCodecInfo> info = getCodecInfo(env, index);
133 if (info == NULL) {
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700134 // Runtime exception already pending.
135 return NULL;
136 }
Andreas Huber5a04bf32012-03-29 16:41:38 -0700137
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700138 Vector<AString> types;
Lajos Molnard2a7f472018-11-15 12:49:20 -0800139 info->getSupportedMediaTypes(&types);
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700140
Andreas Huber5a04bf32012-03-29 16:41:38 -0700141 jclass clazz = env->FindClass("java/lang/String");
142 CHECK(clazz != NULL);
143
144 jobjectArray array = env->NewObjectArray(types.size(), clazz, NULL);
145
146 for (size_t i = 0; i < types.size(); ++i) {
147 jstring obj = env->NewStringUTF(types.itemAt(i).c_str());
148 env->SetObjectArrayElement(array, i, obj);
149 env->DeleteLocalRef(obj);
150 obj = NULL;
151 }
152
153 return array;
154}
155
156static jobject android_media_MediaCodecList_getCodecCapabilities(
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800157 JNIEnv *env, jobject /* thiz */, jint index, jstring type) {
Andreas Huber5a04bf32012-03-29 16:41:38 -0700158 if (type == NULL) {
159 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
160 return NULL;
161 }
162
Lajos Molnard2a7f472018-11-15 12:49:20 -0800163 sp<MediaCodecInfo> info = getCodecInfo(env, index);
164 if (info == NULL) {
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700165 // Runtime exception already pending.
166 return NULL;
167 }
168
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700169
Andreas Huber5a04bf32012-03-29 16:41:38 -0700170 const char *typeStr = env->GetStringUTFChars(type, NULL);
Andreas Huber5a04bf32012-03-29 16:41:38 -0700171 if (typeStr == NULL) {
172 // Out of memory exception already pending.
173 return NULL;
174 }
175
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700176 Vector<MediaCodecInfo::ProfileLevel> profileLevels;
Andreas Huber5a04bf32012-03-29 16:41:38 -0700177 Vector<uint32_t> colorFormats;
Lajos Molnarb58dc312014-07-18 12:10:33 -0700178
179 sp<AMessage> defaultFormat = new AMessage();
180 defaultFormat->setString("mime", typeStr);
181
182 // TODO query default-format also from codec/codec list
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700183 const sp<MediaCodecInfo::Capabilities> &capabilities =
184 info->getCapabilitiesFor(typeStr);
Lajos Molnar018b70f2014-08-12 11:37:24 -0700185 env->ReleaseStringUTFChars(type, typeStr);
186 typeStr = NULL;
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700187 if (capabilities == NULL) {
Andreas Huber5a04bf32012-03-29 16:41:38 -0700188 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
189 return NULL;
190 }
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700191
192 capabilities->getSupportedColorFormats(&colorFormats);
193 capabilities->getSupportedProfileLevels(&profileLevels);
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700194 sp<AMessage> details = capabilities->getDetails();
195 bool isEncoder = info->isEncoder();
Andreas Huber5a04bf32012-03-29 16:41:38 -0700196
Lajos Molnarb58dc312014-07-18 12:10:33 -0700197 jobject defaultFormatObj = NULL;
198 if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
199 return NULL;
200 }
201
202 jobject infoObj = NULL;
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700203 if (ConvertMessageToMap(env, details, &infoObj)) {
Lajos Molnarb58dc312014-07-18 12:10:33 -0700204 env->DeleteLocalRef(defaultFormatObj);
205 return NULL;
206 }
207
Andreas Huber5a04bf32012-03-29 16:41:38 -0700208 jclass capsClazz =
Andreas Huber60d610b2012-05-02 16:06:09 -0700209 env->FindClass("android/media/MediaCodecInfo$CodecCapabilities");
Andreas Huber5a04bf32012-03-29 16:41:38 -0700210 CHECK(capsClazz != NULL);
211
Andreas Huber5a04bf32012-03-29 16:41:38 -0700212 jclass profileLevelClazz =
Andreas Huber60d610b2012-05-02 16:06:09 -0700213 env->FindClass("android/media/MediaCodecInfo$CodecProfileLevel");
Andreas Huber5a04bf32012-03-29 16:41:38 -0700214 CHECK(profileLevelClazz != NULL);
215
216 jobjectArray profileLevelArray =
217 env->NewObjectArray(profileLevels.size(), profileLevelClazz, NULL);
218
219 jfieldID profileField =
Andreas Huber07ea4262012-04-11 12:21:20 -0700220 env->GetFieldID(profileLevelClazz, "profile", "I");
Andreas Huber5a04bf32012-03-29 16:41:38 -0700221
222 jfieldID levelField =
Andreas Huber07ea4262012-04-11 12:21:20 -0700223 env->GetFieldID(profileLevelClazz, "level", "I");
Andreas Huber5a04bf32012-03-29 16:41:38 -0700224
225 for (size_t i = 0; i < profileLevels.size(); ++i) {
Lajos Molnarcd5e3f92014-08-06 12:18:34 -0700226 const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
Andreas Huber5a04bf32012-03-29 16:41:38 -0700227
228 jobject profileLevelObj = env->AllocObject(profileLevelClazz);
229
230 env->SetIntField(profileLevelObj, profileField, src.mProfile);
231 env->SetIntField(profileLevelObj, levelField, src.mLevel);
232
233 env->SetObjectArrayElement(profileLevelArray, i, profileLevelObj);
234
235 env->DeleteLocalRef(profileLevelObj);
236 profileLevelObj = NULL;
237 }
238
Andreas Huber5a04bf32012-03-29 16:41:38 -0700239 jintArray colorFormatsArray = env->NewIntArray(colorFormats.size());
240
241 for (size_t i = 0; i < colorFormats.size(); ++i) {
242 jint val = colorFormats.itemAt(i);
243 env->SetIntArrayRegion(colorFormatsArray, i, 1, &val);
244 }
245
Lajos Molnarb58dc312014-07-18 12:10:33 -0700246 jmethodID capsConstructID = env->GetMethodID(capsClazz, "<init>",
Lajos Molnard2a7f472018-11-15 12:49:20 -0800247 "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
Lajos Molnarb58dc312014-07-18 12:10:33 -0700248 "Ljava/util/Map;Ljava/util/Map;)V");
249
250 jobject caps = env->NewObject(capsClazz, capsConstructID,
Lajos Molnard2a7f472018-11-15 12:49:20 -0800251 profileLevelArray, colorFormatsArray, isEncoder,
Lajos Molnarb58dc312014-07-18 12:10:33 -0700252 defaultFormatObj, infoObj);
253
Lajos Molnarb58dc312014-07-18 12:10:33 -0700254 env->DeleteLocalRef(profileLevelArray);
255 profileLevelArray = NULL;
256
Andreas Huber5a04bf32012-03-29 16:41:38 -0700257 env->DeleteLocalRef(colorFormatsArray);
258 colorFormatsArray = NULL;
259
Lajos Molnarb58dc312014-07-18 12:10:33 -0700260 env->DeleteLocalRef(defaultFormatObj);
261 defaultFormatObj = NULL;
262
263 env->DeleteLocalRef(infoObj);
264 infoObj = NULL;
265
Andreas Huber5a04bf32012-03-29 16:41:38 -0700266 return caps;
267}
268
Ronghua Wuee299752015-03-25 10:53:04 -0700269static jobject android_media_MediaCodecList_getGlobalSettings(JNIEnv *env, jobject /* thiz */) {
270 sp<IMediaCodecList> mcl = getCodecList(env);
271 if (mcl == NULL) {
272 // Runtime exception already pending.
273 return NULL;
274 }
275
276 const sp<AMessage> settings = mcl->getGlobalSettings();
277 if (settings == NULL) {
278 jniThrowException(env, "java/lang/RuntimeException", "cannot get global settings");
279 return NULL;
280 }
281
282 jobject settingsObj = NULL;
283 if (ConvertMessageToMap(env, settings, &settingsObj)) {
284 return NULL;
285 }
286
287 return settingsObj;
288}
289
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800290static void android_media_MediaCodecList_native_init(JNIEnv* /* env */) {
Andreas Huber5a04bf32012-03-29 16:41:38 -0700291}
292
Daniel Micay76f6a862015-09-19 17:31:01 -0400293static const JNINativeMethod gMethods[] = {
Lajos Molnarb58dc312014-07-18 12:10:33 -0700294 { "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
Lajos Molnard2a7f472018-11-15 12:49:20 -0800295
296 { "getCanonicalName", "(I)Ljava/lang/String;",
297 (void *)android_media_MediaCodecList_getCanonicalName },
298
Andreas Huber5a04bf32012-03-29 16:41:38 -0700299 { "getCodecName", "(I)Ljava/lang/String;",
300 (void *)android_media_MediaCodecList_getCodecName },
Lajos Molnard2a7f472018-11-15 12:49:20 -0800301
302 { "getAttributes", "(I)I", (void *)android_media_MediaCodecList_getAttributes },
303
Andreas Huber5a04bf32012-03-29 16:41:38 -0700304 { "getSupportedTypes", "(I)[Ljava/lang/String;",
305 (void *)android_media_MediaCodecList_getSupportedTypes },
306
307 { "getCodecCapabilities",
Andreas Huber60d610b2012-05-02 16:06:09 -0700308 "(ILjava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;",
Andreas Huber5a04bf32012-03-29 16:41:38 -0700309 (void *)android_media_MediaCodecList_getCodecCapabilities },
310
Ronghua Wuee299752015-03-25 10:53:04 -0700311 { "native_getGlobalSettings",
312 "()Ljava/util/Map;",
313 (void *)android_media_MediaCodecList_getGlobalSettings },
314
Martin Storsjo93077a22012-09-25 11:55:25 +0300315 { "findCodecByName", "(Ljava/lang/String;)I",
316 (void *)android_media_MediaCodecList_findCodecByName },
317
Andreas Huber5a04bf32012-03-29 16:41:38 -0700318 { "native_init", "()V", (void *)android_media_MediaCodecList_native_init },
319};
320
321int register_android_media_MediaCodecList(JNIEnv *env) {
322 return AndroidRuntime::registerNativeMethods(env,
323 "android/media/MediaCodecList", gMethods, NELEM(gMethods));
324}
325