blob: 54c5e9bdd267b4a301d7f8ff81b8f394ab473f8c [file] [log] [blame]
James Dong79f407c2011-05-05 12:50:04 -07001/*
2 * Copyright 2011, 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 "AndroidMediaUtils"
19
20#include <utils/Log.h>
21#include "android_media_Utils.h"
22
Andreas Huber88572f72012-02-21 11:47:18 -080023#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/foundation/ABuffer.h>
25#include <media/stagefright/foundation/AMessage.h>
26
Andreas Huber8d5f3e32013-08-12 09:19:45 -070027#include <nativehelper/ScopedLocalRef.h>
28
James Dong79f407c2011-05-05 12:50:04 -070029namespace android {
30
31bool ConvertKeyValueArraysToKeyedVector(
32 JNIEnv *env, jobjectArray keys, jobjectArray values,
33 KeyedVector<String8, String8>* keyedVector) {
34
35 int nKeyValuePairs = 0;
36 bool failed = false;
37 if (keys != NULL && values != NULL) {
38 nKeyValuePairs = env->GetArrayLength(keys);
39 failed = (nKeyValuePairs != env->GetArrayLength(values));
40 }
41
42 if (!failed) {
43 failed = ((keys != NULL && values == NULL) ||
44 (keys == NULL && values != NULL));
45 }
46
47 if (failed) {
Steve Block3762c312012-01-06 19:20:56 +000048 ALOGE("keys and values arrays have different length");
James Dong79f407c2011-05-05 12:50:04 -070049 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
50 return false;
51 }
52
53 for (int i = 0; i < nKeyValuePairs; ++i) {
54 // No need to check on the ArrayIndexOutOfBoundsException, since
55 // it won't happen here.
56 jstring key = (jstring) env->GetObjectArrayElement(keys, i);
57 jstring value = (jstring) env->GetObjectArrayElement(values, i);
58
59 const char* keyStr = env->GetStringUTFChars(key, NULL);
60 if (!keyStr) { // OutOfMemoryError
61 return false;
62 }
63
64 const char* valueStr = env->GetStringUTFChars(value, NULL);
65 if (!valueStr) { // OutOfMemoryError
66 env->ReleaseStringUTFChars(key, keyStr);
67 return false;
68 }
69
70 keyedVector->add(String8(keyStr), String8(valueStr));
71
72 env->ReleaseStringUTFChars(key, keyStr);
73 env->ReleaseStringUTFChars(value, valueStr);
74 env->DeleteLocalRef(key);
75 env->DeleteLocalRef(value);
76 }
77 return true;
78}
79
Andreas Huber88572f72012-02-21 11:47:18 -080080static jobject makeIntegerObject(JNIEnv *env, int32_t value) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -070081 ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Integer"));
82 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -080083
Andreas Huber8d5f3e32013-08-12 09:19:45 -070084 jmethodID integerConstructID =
85 env->GetMethodID(clazz.get(), "<init>", "(I)V");
Andreas Huber88572f72012-02-21 11:47:18 -080086 CHECK(integerConstructID != NULL);
87
Andreas Huber8d5f3e32013-08-12 09:19:45 -070088 return env->NewObject(clazz.get(), integerConstructID, value);
Andreas Huber88572f72012-02-21 11:47:18 -080089}
90
Andreas Huber07ea4262012-04-11 12:21:20 -070091static jobject makeLongObject(JNIEnv *env, int64_t value) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -070092 ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Long"));
93 CHECK(clazz.get() != NULL);
Andreas Huber07ea4262012-04-11 12:21:20 -070094
Andreas Huber8d5f3e32013-08-12 09:19:45 -070095 jmethodID longConstructID = env->GetMethodID(clazz.get(), "<init>", "(J)V");
Andreas Huber07ea4262012-04-11 12:21:20 -070096 CHECK(longConstructID != NULL);
97
Andreas Huber8d5f3e32013-08-12 09:19:45 -070098 return env->NewObject(clazz.get(), longConstructID, value);
Andreas Huber07ea4262012-04-11 12:21:20 -070099}
100
Andreas Huber88572f72012-02-21 11:47:18 -0800101static jobject makeFloatObject(JNIEnv *env, float value) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700102 ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Float"));
103 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -0800104
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700105 jmethodID floatConstructID =
106 env->GetMethodID(clazz.get(), "<init>", "(F)V");
Andreas Huber88572f72012-02-21 11:47:18 -0800107 CHECK(floatConstructID != NULL);
108
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700109 return env->NewObject(clazz.get(), floatConstructID, value);
Andreas Huber88572f72012-02-21 11:47:18 -0800110}
111
112static jobject makeByteBufferObject(
113 JNIEnv *env, const void *data, size_t size) {
114 jbyteArray byteArrayObj = env->NewByteArray(size);
115 env->SetByteArrayRegion(byteArrayObj, 0, size, (const jbyte *)data);
116
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700117 ScopedLocalRef<jclass> clazz(env, env->FindClass("java/nio/ByteBuffer"));
118 CHECK(clazz.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -0800119
120 jmethodID byteBufWrapID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700121 env->GetStaticMethodID(
122 clazz.get(), "wrap", "([B)Ljava/nio/ByteBuffer;");
Andreas Huber88572f72012-02-21 11:47:18 -0800123 CHECK(byteBufWrapID != NULL);
124
125 jobject byteBufObj = env->CallStaticObjectMethod(
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700126 clazz.get(), byteBufWrapID, byteArrayObj);
Andreas Huber88572f72012-02-21 11:47:18 -0800127
128 env->DeleteLocalRef(byteArrayObj); byteArrayObj = NULL;
129
130 return byteBufObj;
131}
132
Andreas Huberb8425992012-05-10 11:32:15 -0700133static void SetMapInt32(
134 JNIEnv *env, jobject hashMapObj, jmethodID hashMapPutID,
135 const char *key, int32_t value) {
136 jstring keyObj = env->NewStringUTF(key);
137 jobject valueObj = makeIntegerObject(env, value);
138
139 jobject res = env->CallObjectMethod(
140 hashMapObj, hashMapPutID, keyObj, valueObj);
141
142 env->DeleteLocalRef(valueObj); valueObj = NULL;
143 env->DeleteLocalRef(keyObj); keyObj = NULL;
144}
145
Andreas Huber88572f72012-02-21 11:47:18 -0800146status_t ConvertMessageToMap(
147 JNIEnv *env, const sp<AMessage> &msg, jobject *map) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700148 ScopedLocalRef<jclass> hashMapClazz(
149 env, env->FindClass("java/util/HashMap"));
Andreas Huber88572f72012-02-21 11:47:18 -0800150
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700151 if (hashMapClazz.get() == NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800152 return -EINVAL;
153 }
154
155 jmethodID hashMapConstructID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700156 env->GetMethodID(hashMapClazz.get(), "<init>", "()V");
Andreas Huber88572f72012-02-21 11:47:18 -0800157
158 if (hashMapConstructID == NULL) {
159 return -EINVAL;
160 }
161
162 jmethodID hashMapPutID =
163 env->GetMethodID(
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700164 hashMapClazz.get(),
Andreas Huber88572f72012-02-21 11:47:18 -0800165 "put",
166 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
167
168 if (hashMapPutID == NULL) {
169 return -EINVAL;
170 }
171
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700172 jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID);
Andreas Huber88572f72012-02-21 11:47:18 -0800173
174 for (size_t i = 0; i < msg->countEntries(); ++i) {
175 AMessage::Type valueType;
176 const char *key = msg->getEntryNameAt(i, &valueType);
177
178 jobject valueObj = NULL;
179
180 switch (valueType) {
181 case AMessage::kTypeInt32:
182 {
183 int32_t val;
184 CHECK(msg->findInt32(key, &val));
185
186 valueObj = makeIntegerObject(env, val);
187 break;
188 }
189
Andreas Huber07ea4262012-04-11 12:21:20 -0700190 case AMessage::kTypeInt64:
191 {
192 int64_t val;
193 CHECK(msg->findInt64(key, &val));
194
195 valueObj = makeLongObject(env, val);
196 break;
197 }
198
Andreas Huber88572f72012-02-21 11:47:18 -0800199 case AMessage::kTypeFloat:
200 {
201 float val;
202 CHECK(msg->findFloat(key, &val));
203
204 valueObj = makeFloatObject(env, val);
205 break;
206 }
207
208 case AMessage::kTypeString:
209 {
210 AString val;
211 CHECK(msg->findString(key, &val));
212
213 valueObj = env->NewStringUTF(val.c_str());
214 break;
215 }
216
Andreas Huber5c850392012-02-21 14:38:23 -0800217 case AMessage::kTypeBuffer:
Andreas Huber88572f72012-02-21 11:47:18 -0800218 {
Andreas Huber5c850392012-02-21 14:38:23 -0800219 sp<ABuffer> buffer;
220 CHECK(msg->findBuffer(key, &buffer));
Andreas Huber88572f72012-02-21 11:47:18 -0800221
222 valueObj = makeByteBufferObject(
223 env, buffer->data(), buffer->size());
224 break;
225 }
226
Andreas Huberb8425992012-05-10 11:32:15 -0700227 case AMessage::kTypeRect:
228 {
229 int32_t left, top, right, bottom;
230 CHECK(msg->findRect(key, &left, &top, &right, &bottom));
231
232 SetMapInt32(
233 env,
234 hashMap,
235 hashMapPutID,
236 StringPrintf("%s-left", key).c_str(),
237 left);
238
239 SetMapInt32(
240 env,
241 hashMap,
242 hashMapPutID,
243 StringPrintf("%s-top", key).c_str(),
244 top);
245
246 SetMapInt32(
247 env,
248 hashMap,
249 hashMapPutID,
250 StringPrintf("%s-right", key).c_str(),
251 right);
252
253 SetMapInt32(
254 env,
255 hashMap,
256 hashMapPutID,
257 StringPrintf("%s-bottom", key).c_str(),
258 bottom);
259 break;
260 }
261
Andreas Huber88572f72012-02-21 11:47:18 -0800262 default:
263 break;
264 }
265
266 if (valueObj != NULL) {
267 jstring keyObj = env->NewStringUTF(key);
268
269 jobject res = env->CallObjectMethod(
270 hashMap, hashMapPutID, keyObj, valueObj);
271
272 env->DeleteLocalRef(keyObj); keyObj = NULL;
273 env->DeleteLocalRef(valueObj); valueObj = NULL;
274 }
275 }
276
277 *map = hashMap;
278
279 return OK;
280}
281
282status_t ConvertKeyValueArraysToMessage(
283 JNIEnv *env, jobjectArray keys, jobjectArray values,
284 sp<AMessage> *out) {
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700285 ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String"));
286 CHECK(stringClass.get() != NULL);
287 ScopedLocalRef<jclass> integerClass(env, env->FindClass("java/lang/Integer"));
288 CHECK(integerClass.get() != NULL);
289 ScopedLocalRef<jclass> longClass(env, env->FindClass("java/lang/Long"));
290 CHECK(longClass.get() != NULL);
291 ScopedLocalRef<jclass> floatClass(env, env->FindClass("java/lang/Float"));
292 CHECK(floatClass.get() != NULL);
293 ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer"));
294 CHECK(byteBufClass.get() != NULL);
Andreas Huber88572f72012-02-21 11:47:18 -0800295
296 sp<AMessage> msg = new AMessage;
297
298 jsize numEntries = 0;
299
300 if (keys != NULL) {
301 if (values == NULL) {
302 return -EINVAL;
303 }
304
305 numEntries = env->GetArrayLength(keys);
306
307 if (numEntries != env->GetArrayLength(values)) {
308 return -EINVAL;
309 }
310 } else if (values != NULL) {
311 return -EINVAL;
312 }
313
314 for (jsize i = 0; i < numEntries; ++i) {
315 jobject keyObj = env->GetObjectArrayElement(keys, i);
316
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700317 if (!env->IsInstanceOf(keyObj, stringClass.get())) {
Andreas Huber88572f72012-02-21 11:47:18 -0800318 return -EINVAL;
319 }
320
321 const char *tmp = env->GetStringUTFChars((jstring)keyObj, NULL);
322
323 if (tmp == NULL) {
324 return -ENOMEM;
325 }
326
327 AString key = tmp;
328
329 env->ReleaseStringUTFChars((jstring)keyObj, tmp);
330 tmp = NULL;
331
332 jobject valueObj = env->GetObjectArrayElement(values, i);
333
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700334 if (env->IsInstanceOf(valueObj, stringClass.get())) {
Andreas Huber88572f72012-02-21 11:47:18 -0800335 const char *value = env->GetStringUTFChars((jstring)valueObj, NULL);
336
337 if (value == NULL) {
338 return -ENOMEM;
339 }
340
341 msg->setString(key.c_str(), value);
342
343 env->ReleaseStringUTFChars((jstring)valueObj, value);
344 value = NULL;
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700345 } else if (env->IsInstanceOf(valueObj, integerClass.get())) {
Andreas Huber88572f72012-02-21 11:47:18 -0800346 jmethodID intValueID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700347 env->GetMethodID(integerClass.get(), "intValue", "()I");
Andreas Huber88572f72012-02-21 11:47:18 -0800348 CHECK(intValueID != NULL);
349
350 jint value = env->CallIntMethod(valueObj, intValueID);
351
352 msg->setInt32(key.c_str(), value);
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700353 } else if (env->IsInstanceOf(valueObj, longClass.get())) {
354 jmethodID longValueID =
355 env->GetMethodID(longClass.get(), "longValue", "()J");
356 CHECK(longValueID != NULL);
357
358 jlong value = env->CallLongMethod(valueObj, longValueID);
359
360 msg->setInt64(key.c_str(), value);
361 } else if (env->IsInstanceOf(valueObj, floatClass.get())) {
Andreas Huber88572f72012-02-21 11:47:18 -0800362 jmethodID floatValueID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700363 env->GetMethodID(floatClass.get(), "floatValue", "()F");
Andreas Huber88572f72012-02-21 11:47:18 -0800364 CHECK(floatValueID != NULL);
365
366 jfloat value = env->CallFloatMethod(valueObj, floatValueID);
367
368 msg->setFloat(key.c_str(), value);
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700369 } else if (env->IsInstanceOf(valueObj, byteBufClass.get())) {
Andreas Huber88572f72012-02-21 11:47:18 -0800370 jmethodID positionID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700371 env->GetMethodID(byteBufClass.get(), "position", "()I");
Andreas Huber88572f72012-02-21 11:47:18 -0800372 CHECK(positionID != NULL);
373
374 jmethodID limitID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700375 env->GetMethodID(byteBufClass.get(), "limit", "()I");
Andreas Huber88572f72012-02-21 11:47:18 -0800376 CHECK(limitID != NULL);
377
378 jint position = env->CallIntMethod(valueObj, positionID);
379 jint limit = env->CallIntMethod(valueObj, limitID);
380
381 sp<ABuffer> buffer = new ABuffer(limit - position);
382
383 void *data = env->GetDirectBufferAddress(valueObj);
384
385 if (data != NULL) {
386 memcpy(buffer->data(),
387 (const uint8_t *)data + position,
388 buffer->size());
389 } else {
390 jmethodID arrayID =
Andreas Huber8d5f3e32013-08-12 09:19:45 -0700391 env->GetMethodID(byteBufClass.get(), "array", "()[B");
Andreas Huber88572f72012-02-21 11:47:18 -0800392 CHECK(arrayID != NULL);
393
394 jbyteArray byteArray =
395 (jbyteArray)env->CallObjectMethod(valueObj, arrayID);
396 CHECK(byteArray != NULL);
397
398 env->GetByteArrayRegion(
399 byteArray,
400 position,
401 buffer->size(),
402 (jbyte *)buffer->data());
403
404 env->DeleteLocalRef(byteArray); byteArray = NULL;
405 }
406
Andreas Huber9b8e4962012-03-26 11:13:27 -0700407 msg->setBuffer(key.c_str(), buffer);
Andreas Huber88572f72012-02-21 11:47:18 -0800408 }
409 }
410
411 *out = msg;
412
413 return OK;
414}
415
James Dong79f407c2011-05-05 12:50:04 -0700416} // namespace android
417