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 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 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 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 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 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 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 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 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