• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
23 #include <media/stagefright/foundation/ADebug.h>
24 #include <media/stagefright/foundation/ABuffer.h>
25 #include <media/stagefright/foundation/AMessage.h>
26 
27 namespace android {
28 
ConvertKeyValueArraysToKeyedVector(JNIEnv * env,jobjectArray keys,jobjectArray values,KeyedVector<String8,String8> * keyedVector)29 bool ConvertKeyValueArraysToKeyedVector(
30         JNIEnv *env, jobjectArray keys, jobjectArray values,
31         KeyedVector<String8, String8>* keyedVector) {
32 
33     int nKeyValuePairs = 0;
34     bool failed = false;
35     if (keys != NULL && values != NULL) {
36         nKeyValuePairs = env->GetArrayLength(keys);
37         failed = (nKeyValuePairs != env->GetArrayLength(values));
38     }
39 
40     if (!failed) {
41         failed = ((keys != NULL && values == NULL) ||
42                   (keys == NULL && values != NULL));
43     }
44 
45     if (failed) {
46         ALOGE("keys and values arrays have different length");
47         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
48         return false;
49     }
50 
51     for (int i = 0; i < nKeyValuePairs; ++i) {
52         // No need to check on the ArrayIndexOutOfBoundsException, since
53         // it won't happen here.
54         jstring key = (jstring) env->GetObjectArrayElement(keys, i);
55         jstring value = (jstring) env->GetObjectArrayElement(values, i);
56 
57         const char* keyStr = env->GetStringUTFChars(key, NULL);
58         if (!keyStr) {  // OutOfMemoryError
59             return false;
60         }
61 
62         const char* valueStr = env->GetStringUTFChars(value, NULL);
63         if (!valueStr) {  // OutOfMemoryError
64             env->ReleaseStringUTFChars(key, keyStr);
65             return false;
66         }
67 
68         keyedVector->add(String8(keyStr), String8(valueStr));
69 
70         env->ReleaseStringUTFChars(key, keyStr);
71         env->ReleaseStringUTFChars(value, valueStr);
72         env->DeleteLocalRef(key);
73         env->DeleteLocalRef(value);
74     }
75     return true;
76 }
77 
makeIntegerObject(JNIEnv * env,int32_t value)78 static jobject makeIntegerObject(JNIEnv *env, int32_t value) {
79     jclass clazz = env->FindClass("java/lang/Integer");
80     CHECK(clazz != NULL);
81 
82     jmethodID integerConstructID = env->GetMethodID(clazz, "<init>", "(I)V");
83     CHECK(integerConstructID != NULL);
84 
85     return env->NewObject(clazz, integerConstructID, value);
86 }
87 
makeLongObject(JNIEnv * env,int64_t value)88 static jobject makeLongObject(JNIEnv *env, int64_t value) {
89     jclass clazz = env->FindClass("java/lang/Long");
90     CHECK(clazz != NULL);
91 
92     jmethodID longConstructID = env->GetMethodID(clazz, "<init>", "(J)V");
93     CHECK(longConstructID != NULL);
94 
95     return env->NewObject(clazz, longConstructID, value);
96 }
97 
makeFloatObject(JNIEnv * env,float value)98 static jobject makeFloatObject(JNIEnv *env, float value) {
99     jclass clazz = env->FindClass("java/lang/Float");
100     CHECK(clazz != NULL);
101 
102     jmethodID floatConstructID = env->GetMethodID(clazz, "<init>", "(F)V");
103     CHECK(floatConstructID != NULL);
104 
105     return env->NewObject(clazz, floatConstructID, value);
106 }
107 
makeByteBufferObject(JNIEnv * env,const void * data,size_t size)108 static jobject makeByteBufferObject(
109         JNIEnv *env, const void *data, size_t size) {
110     jbyteArray byteArrayObj = env->NewByteArray(size);
111     env->SetByteArrayRegion(byteArrayObj, 0, size, (const jbyte *)data);
112 
113     jclass clazz = env->FindClass("java/nio/ByteBuffer");
114     CHECK(clazz != NULL);
115 
116     jmethodID byteBufWrapID =
117         env->GetStaticMethodID(clazz, "wrap", "([B)Ljava/nio/ByteBuffer;");
118     CHECK(byteBufWrapID != NULL);
119 
120     jobject byteBufObj = env->CallStaticObjectMethod(
121             clazz, byteBufWrapID, byteArrayObj);
122 
123     env->DeleteLocalRef(byteArrayObj); byteArrayObj = NULL;
124 
125     return byteBufObj;
126 }
127 
SetMapInt32(JNIEnv * env,jobject hashMapObj,jmethodID hashMapPutID,const char * key,int32_t value)128 static void SetMapInt32(
129         JNIEnv *env, jobject hashMapObj, jmethodID hashMapPutID,
130         const char *key, int32_t value) {
131     jstring keyObj = env->NewStringUTF(key);
132     jobject valueObj = makeIntegerObject(env, value);
133 
134     jobject res = env->CallObjectMethod(
135             hashMapObj, hashMapPutID, keyObj, valueObj);
136 
137     env->DeleteLocalRef(valueObj); valueObj = NULL;
138     env->DeleteLocalRef(keyObj); keyObj = NULL;
139 }
140 
ConvertMessageToMap(JNIEnv * env,const sp<AMessage> & msg,jobject * map)141 status_t ConvertMessageToMap(
142         JNIEnv *env, const sp<AMessage> &msg, jobject *map) {
143     jclass hashMapClazz = env->FindClass("java/util/HashMap");
144 
145     if (hashMapClazz == NULL) {
146         return -EINVAL;
147     }
148 
149     jmethodID hashMapConstructID =
150         env->GetMethodID(hashMapClazz, "<init>", "()V");
151 
152     if (hashMapConstructID == NULL) {
153         return -EINVAL;
154     }
155 
156     jmethodID hashMapPutID =
157         env->GetMethodID(
158                 hashMapClazz,
159                 "put",
160                 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
161 
162     if (hashMapPutID == NULL) {
163         return -EINVAL;
164     }
165 
166     jobject hashMap = env->NewObject(hashMapClazz, hashMapConstructID);
167 
168     for (size_t i = 0; i < msg->countEntries(); ++i) {
169         AMessage::Type valueType;
170         const char *key = msg->getEntryNameAt(i, &valueType);
171 
172         jobject valueObj = NULL;
173 
174         switch (valueType) {
175             case AMessage::kTypeInt32:
176             {
177                 int32_t val;
178                 CHECK(msg->findInt32(key, &val));
179 
180                 valueObj = makeIntegerObject(env, val);
181                 break;
182             }
183 
184             case AMessage::kTypeInt64:
185             {
186                 int64_t val;
187                 CHECK(msg->findInt64(key, &val));
188 
189                 valueObj = makeLongObject(env, val);
190                 break;
191             }
192 
193             case AMessage::kTypeFloat:
194             {
195                 float val;
196                 CHECK(msg->findFloat(key, &val));
197 
198                 valueObj = makeFloatObject(env, val);
199                 break;
200             }
201 
202             case AMessage::kTypeString:
203             {
204                 AString val;
205                 CHECK(msg->findString(key, &val));
206 
207                 valueObj = env->NewStringUTF(val.c_str());
208                 break;
209             }
210 
211             case AMessage::kTypeBuffer:
212             {
213                 sp<ABuffer> buffer;
214                 CHECK(msg->findBuffer(key, &buffer));
215 
216                 valueObj = makeByteBufferObject(
217                         env, buffer->data(), buffer->size());
218                 break;
219             }
220 
221             case AMessage::kTypeRect:
222             {
223                 int32_t left, top, right, bottom;
224                 CHECK(msg->findRect(key, &left, &top, &right, &bottom));
225 
226                 SetMapInt32(
227                         env,
228                         hashMap,
229                         hashMapPutID,
230                         StringPrintf("%s-left", key).c_str(),
231                         left);
232 
233                 SetMapInt32(
234                         env,
235                         hashMap,
236                         hashMapPutID,
237                         StringPrintf("%s-top", key).c_str(),
238                         top);
239 
240                 SetMapInt32(
241                         env,
242                         hashMap,
243                         hashMapPutID,
244                         StringPrintf("%s-right", key).c_str(),
245                         right);
246 
247                 SetMapInt32(
248                         env,
249                         hashMap,
250                         hashMapPutID,
251                         StringPrintf("%s-bottom", key).c_str(),
252                         bottom);
253                 break;
254             }
255 
256             default:
257                 break;
258         }
259 
260         if (valueObj != NULL) {
261             jstring keyObj = env->NewStringUTF(key);
262 
263             jobject res = env->CallObjectMethod(
264                     hashMap, hashMapPutID, keyObj, valueObj);
265 
266             env->DeleteLocalRef(keyObj); keyObj = NULL;
267             env->DeleteLocalRef(valueObj); valueObj = NULL;
268         }
269     }
270 
271     *map = hashMap;
272 
273     return OK;
274 }
275 
ConvertKeyValueArraysToMessage(JNIEnv * env,jobjectArray keys,jobjectArray values,sp<AMessage> * out)276 status_t ConvertKeyValueArraysToMessage(
277         JNIEnv *env, jobjectArray keys, jobjectArray values,
278         sp<AMessage> *out) {
279     jclass stringClass = env->FindClass("java/lang/String");
280     CHECK(stringClass != NULL);
281 
282     jclass integerClass = env->FindClass("java/lang/Integer");
283     CHECK(integerClass != NULL);
284 
285     jclass floatClass = env->FindClass("java/lang/Float");
286     CHECK(floatClass != NULL);
287 
288     jclass byteBufClass = env->FindClass("java/nio/ByteBuffer");
289     CHECK(byteBufClass != NULL);
290 
291     sp<AMessage> msg = new AMessage;
292 
293     jsize numEntries = 0;
294 
295     if (keys != NULL) {
296         if (values == NULL) {
297             return -EINVAL;
298         }
299 
300         numEntries = env->GetArrayLength(keys);
301 
302         if (numEntries != env->GetArrayLength(values)) {
303             return -EINVAL;
304         }
305     } else if (values != NULL) {
306         return -EINVAL;
307     }
308 
309     for (jsize i = 0; i < numEntries; ++i) {
310         jobject keyObj = env->GetObjectArrayElement(keys, i);
311 
312         if (!env->IsInstanceOf(keyObj, stringClass)) {
313             return -EINVAL;
314         }
315 
316         const char *tmp = env->GetStringUTFChars((jstring)keyObj, NULL);
317 
318         if (tmp == NULL) {
319             return -ENOMEM;
320         }
321 
322         AString key = tmp;
323 
324         env->ReleaseStringUTFChars((jstring)keyObj, tmp);
325         tmp = NULL;
326 
327         jobject valueObj = env->GetObjectArrayElement(values, i);
328 
329         if (env->IsInstanceOf(valueObj, stringClass)) {
330             const char *value = env->GetStringUTFChars((jstring)valueObj, NULL);
331 
332             if (value == NULL) {
333                 return -ENOMEM;
334             }
335 
336             msg->setString(key.c_str(), value);
337 
338             env->ReleaseStringUTFChars((jstring)valueObj, value);
339             value = NULL;
340         } else if (env->IsInstanceOf(valueObj, integerClass)) {
341             jmethodID intValueID =
342                 env->GetMethodID(integerClass, "intValue", "()I");
343             CHECK(intValueID != NULL);
344 
345             jint value = env->CallIntMethod(valueObj, intValueID);
346 
347             msg->setInt32(key.c_str(), value);
348         } else if (env->IsInstanceOf(valueObj, floatClass)) {
349             jmethodID floatValueID =
350                 env->GetMethodID(floatClass, "floatValue", "()F");
351             CHECK(floatValueID != NULL);
352 
353             jfloat value = env->CallFloatMethod(valueObj, floatValueID);
354 
355             msg->setFloat(key.c_str(), value);
356         } else if (env->IsInstanceOf(valueObj, byteBufClass)) {
357             jmethodID positionID =
358                 env->GetMethodID(byteBufClass, "position", "()I");
359             CHECK(positionID != NULL);
360 
361             jmethodID limitID =
362                 env->GetMethodID(byteBufClass, "limit", "()I");
363             CHECK(limitID != NULL);
364 
365             jint position = env->CallIntMethod(valueObj, positionID);
366             jint limit = env->CallIntMethod(valueObj, limitID);
367 
368             sp<ABuffer> buffer = new ABuffer(limit - position);
369 
370             void *data = env->GetDirectBufferAddress(valueObj);
371 
372             if (data != NULL) {
373                 memcpy(buffer->data(),
374                        (const uint8_t *)data + position,
375                        buffer->size());
376             } else {
377                 jmethodID arrayID =
378                     env->GetMethodID(byteBufClass, "array", "()[B");
379                 CHECK(arrayID != NULL);
380 
381                 jbyteArray byteArray =
382                     (jbyteArray)env->CallObjectMethod(valueObj, arrayID);
383                 CHECK(byteArray != NULL);
384 
385                 env->GetByteArrayRegion(
386                         byteArray,
387                         position,
388                         buffer->size(),
389                         (jbyte *)buffer->data());
390 
391                 env->DeleteLocalRef(byteArray); byteArray = NULL;
392             }
393 
394             msg->setBuffer(key.c_str(), buffer);
395         }
396     }
397 
398     *out = msg;
399 
400     return OK;
401 }
402 
403 }  // namespace android
404 
405