android_media_Utils.cpp revision 07ea426e3ae8915ca6bf67135f523f42cd920af0
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 27namespace android { 28 29bool 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 78static 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 88static 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 98static 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 108static 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 128status_t ConvertMessageToMap( 129 JNIEnv *env, const sp<AMessage> &msg, jobject *map) { 130 jclass hashMapClazz = env->FindClass("java/util/HashMap"); 131 132 if (hashMapClazz == NULL) { 133 return -EINVAL; 134 } 135 136 jmethodID hashMapConstructID = 137 env->GetMethodID(hashMapClazz, "<init>", "()V"); 138 139 if (hashMapConstructID == NULL) { 140 return -EINVAL; 141 } 142 143 jmethodID hashMapPutID = 144 env->GetMethodID( 145 hashMapClazz, 146 "put", 147 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 148 149 if (hashMapPutID == NULL) { 150 return -EINVAL; 151 } 152 153 jobject hashMap = env->NewObject(hashMapClazz, hashMapConstructID); 154 155 for (size_t i = 0; i < msg->countEntries(); ++i) { 156 AMessage::Type valueType; 157 const char *key = msg->getEntryNameAt(i, &valueType); 158 159 jobject valueObj = NULL; 160 161 switch (valueType) { 162 case AMessage::kTypeInt32: 163 { 164 int32_t val; 165 CHECK(msg->findInt32(key, &val)); 166 167 valueObj = makeIntegerObject(env, val); 168 break; 169 } 170 171 case AMessage::kTypeInt64: 172 { 173 int64_t val; 174 CHECK(msg->findInt64(key, &val)); 175 176 valueObj = makeLongObject(env, val); 177 break; 178 } 179 180 case AMessage::kTypeFloat: 181 { 182 float val; 183 CHECK(msg->findFloat(key, &val)); 184 185 valueObj = makeFloatObject(env, val); 186 break; 187 } 188 189 case AMessage::kTypeString: 190 { 191 AString val; 192 CHECK(msg->findString(key, &val)); 193 194 valueObj = env->NewStringUTF(val.c_str()); 195 break; 196 } 197 198 case AMessage::kTypeBuffer: 199 { 200 sp<ABuffer> buffer; 201 CHECK(msg->findBuffer(key, &buffer)); 202 203 valueObj = makeByteBufferObject( 204 env, buffer->data(), buffer->size()); 205 break; 206 } 207 208 default: 209 break; 210 } 211 212 if (valueObj != NULL) { 213 jstring keyObj = env->NewStringUTF(key); 214 215 jobject res = env->CallObjectMethod( 216 hashMap, hashMapPutID, keyObj, valueObj); 217 218 env->DeleteLocalRef(keyObj); keyObj = NULL; 219 env->DeleteLocalRef(valueObj); valueObj = NULL; 220 } 221 } 222 223 *map = hashMap; 224 225 return OK; 226} 227 228status_t ConvertKeyValueArraysToMessage( 229 JNIEnv *env, jobjectArray keys, jobjectArray values, 230 sp<AMessage> *out) { 231 jclass stringClass = env->FindClass("java/lang/String"); 232 CHECK(stringClass != NULL); 233 234 jclass integerClass = env->FindClass("java/lang/Integer"); 235 CHECK(integerClass != NULL); 236 237 jclass floatClass = env->FindClass("java/lang/Float"); 238 CHECK(floatClass != NULL); 239 240 jclass byteBufClass = env->FindClass("java/nio/ByteBuffer"); 241 CHECK(byteBufClass != NULL); 242 243 sp<AMessage> msg = new AMessage; 244 245 jsize numEntries = 0; 246 247 if (keys != NULL) { 248 if (values == NULL) { 249 return -EINVAL; 250 } 251 252 numEntries = env->GetArrayLength(keys); 253 254 if (numEntries != env->GetArrayLength(values)) { 255 return -EINVAL; 256 } 257 } else if (values != NULL) { 258 return -EINVAL; 259 } 260 261 for (jsize i = 0; i < numEntries; ++i) { 262 jobject keyObj = env->GetObjectArrayElement(keys, i); 263 264 if (!env->IsInstanceOf(keyObj, stringClass)) { 265 return -EINVAL; 266 } 267 268 const char *tmp = env->GetStringUTFChars((jstring)keyObj, NULL); 269 270 if (tmp == NULL) { 271 return -ENOMEM; 272 } 273 274 AString key = tmp; 275 276 env->ReleaseStringUTFChars((jstring)keyObj, tmp); 277 tmp = NULL; 278 279 jobject valueObj = env->GetObjectArrayElement(values, i); 280 281 if (env->IsInstanceOf(valueObj, stringClass)) { 282 const char *value = env->GetStringUTFChars((jstring)valueObj, NULL); 283 284 if (value == NULL) { 285 return -ENOMEM; 286 } 287 288 msg->setString(key.c_str(), value); 289 290 env->ReleaseStringUTFChars((jstring)valueObj, value); 291 value = NULL; 292 } else if (env->IsInstanceOf(valueObj, integerClass)) { 293 jmethodID intValueID = 294 env->GetMethodID(integerClass, "intValue", "()I"); 295 CHECK(intValueID != NULL); 296 297 jint value = env->CallIntMethod(valueObj, intValueID); 298 299 msg->setInt32(key.c_str(), value); 300 } else if (env->IsInstanceOf(valueObj, floatClass)) { 301 jmethodID floatValueID = 302 env->GetMethodID(floatClass, "floatValue", "()F"); 303 CHECK(floatValueID != NULL); 304 305 jfloat value = env->CallFloatMethod(valueObj, floatValueID); 306 307 msg->setFloat(key.c_str(), value); 308 } else if (env->IsInstanceOf(valueObj, byteBufClass)) { 309 jmethodID positionID = 310 env->GetMethodID(byteBufClass, "position", "()I"); 311 CHECK(positionID != NULL); 312 313 jmethodID limitID = 314 env->GetMethodID(byteBufClass, "limit", "()I"); 315 CHECK(limitID != NULL); 316 317 jint position = env->CallIntMethod(valueObj, positionID); 318 jint limit = env->CallIntMethod(valueObj, limitID); 319 320 sp<ABuffer> buffer = new ABuffer(limit - position); 321 322 void *data = env->GetDirectBufferAddress(valueObj); 323 324 if (data != NULL) { 325 memcpy(buffer->data(), 326 (const uint8_t *)data + position, 327 buffer->size()); 328 } else { 329 jmethodID arrayID = 330 env->GetMethodID(byteBufClass, "array", "()[B"); 331 CHECK(arrayID != NULL); 332 333 jbyteArray byteArray = 334 (jbyteArray)env->CallObjectMethod(valueObj, arrayID); 335 CHECK(byteArray != NULL); 336 337 env->GetByteArrayRegion( 338 byteArray, 339 position, 340 buffer->size(), 341 (jbyte *)buffer->data()); 342 343 env->DeleteLocalRef(byteArray); byteArray = NULL; 344 } 345 346 msg->setBuffer(key.c_str(), buffer); 347 } 348 } 349 350 *out = msg; 351 352 return OK; 353} 354 355} // namespace android 356 357