android_media_Utils.cpp revision 88572f7a3e9d7ef85c26865a0150f3c2041561c2
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 makeFloatObject(JNIEnv *env, float value) { 89 jclass clazz = env->FindClass("java/lang/Float"); 90 CHECK(clazz != NULL); 91 92 jmethodID floatConstructID = env->GetMethodID(clazz, "<init>", "(F)V"); 93 CHECK(floatConstructID != NULL); 94 95 return env->NewObject(clazz, floatConstructID, value); 96} 97 98static jobject makeByteBufferObject( 99 JNIEnv *env, const void *data, size_t size) { 100 jbyteArray byteArrayObj = env->NewByteArray(size); 101 env->SetByteArrayRegion(byteArrayObj, 0, size, (const jbyte *)data); 102 103 jclass clazz = env->FindClass("java/nio/ByteBuffer"); 104 CHECK(clazz != NULL); 105 106 jmethodID byteBufWrapID = 107 env->GetStaticMethodID(clazz, "wrap", "([B)Ljava/nio/ByteBuffer;"); 108 CHECK(byteBufWrapID != NULL); 109 110 jobject byteBufObj = env->CallStaticObjectMethod( 111 clazz, byteBufWrapID, byteArrayObj); 112 113 env->DeleteLocalRef(byteArrayObj); byteArrayObj = NULL; 114 115 return byteBufObj; 116} 117 118status_t ConvertMessageToMap( 119 JNIEnv *env, const sp<AMessage> &msg, jobject *map) { 120 jclass hashMapClazz = env->FindClass("java/util/HashMap"); 121 122 if (hashMapClazz == NULL) { 123 return -EINVAL; 124 } 125 126 jmethodID hashMapConstructID = 127 env->GetMethodID(hashMapClazz, "<init>", "()V"); 128 129 if (hashMapConstructID == NULL) { 130 return -EINVAL; 131 } 132 133 jmethodID hashMapPutID = 134 env->GetMethodID( 135 hashMapClazz, 136 "put", 137 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 138 139 if (hashMapPutID == NULL) { 140 return -EINVAL; 141 } 142 143 jobject hashMap = env->NewObject(hashMapClazz, hashMapConstructID); 144 145 for (size_t i = 0; i < msg->countEntries(); ++i) { 146 AMessage::Type valueType; 147 const char *key = msg->getEntryNameAt(i, &valueType); 148 149 jobject valueObj = NULL; 150 151 switch (valueType) { 152 case AMessage::kTypeInt32: 153 { 154 int32_t val; 155 CHECK(msg->findInt32(key, &val)); 156 157 valueObj = makeIntegerObject(env, val); 158 break; 159 } 160 161 case AMessage::kTypeFloat: 162 { 163 float val; 164 CHECK(msg->findFloat(key, &val)); 165 166 valueObj = makeFloatObject(env, val); 167 break; 168 } 169 170 case AMessage::kTypeString: 171 { 172 AString val; 173 CHECK(msg->findString(key, &val)); 174 175 valueObj = env->NewStringUTF(val.c_str()); 176 break; 177 } 178 179 case AMessage::kTypeObject: 180 { 181 sp<RefBase> obj; 182 CHECK(msg->findObject(key, &obj)); 183 184 // XXX dangerous, object is not guaranteed to be a buffer. 185 sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get()); 186 187 valueObj = makeByteBufferObject( 188 env, buffer->data(), buffer->size()); 189 break; 190 } 191 192 default: 193 break; 194 } 195 196 if (valueObj != NULL) { 197 jstring keyObj = env->NewStringUTF(key); 198 199 jobject res = env->CallObjectMethod( 200 hashMap, hashMapPutID, keyObj, valueObj); 201 202 env->DeleteLocalRef(keyObj); keyObj = NULL; 203 env->DeleteLocalRef(valueObj); valueObj = NULL; 204 } 205 } 206 207 *map = hashMap; 208 209 return OK; 210} 211 212status_t ConvertKeyValueArraysToMessage( 213 JNIEnv *env, jobjectArray keys, jobjectArray values, 214 sp<AMessage> *out) { 215 jclass stringClass = env->FindClass("java/lang/String"); 216 CHECK(stringClass != NULL); 217 218 jclass integerClass = env->FindClass("java/lang/Integer"); 219 CHECK(integerClass != NULL); 220 221 jclass floatClass = env->FindClass("java/lang/Float"); 222 CHECK(floatClass != NULL); 223 224 jclass byteBufClass = env->FindClass("java/nio/ByteBuffer"); 225 CHECK(byteBufClass != NULL); 226 227 sp<AMessage> msg = new AMessage; 228 229 jsize numEntries = 0; 230 231 if (keys != NULL) { 232 if (values == NULL) { 233 return -EINVAL; 234 } 235 236 numEntries = env->GetArrayLength(keys); 237 238 if (numEntries != env->GetArrayLength(values)) { 239 return -EINVAL; 240 } 241 } else if (values != NULL) { 242 return -EINVAL; 243 } 244 245 for (jsize i = 0; i < numEntries; ++i) { 246 jobject keyObj = env->GetObjectArrayElement(keys, i); 247 248 if (!env->IsInstanceOf(keyObj, stringClass)) { 249 return -EINVAL; 250 } 251 252 const char *tmp = env->GetStringUTFChars((jstring)keyObj, NULL); 253 254 if (tmp == NULL) { 255 return -ENOMEM; 256 } 257 258 AString key = tmp; 259 260 env->ReleaseStringUTFChars((jstring)keyObj, tmp); 261 tmp = NULL; 262 263 jobject valueObj = env->GetObjectArrayElement(values, i); 264 265 if (env->IsInstanceOf(valueObj, stringClass)) { 266 const char *value = env->GetStringUTFChars((jstring)valueObj, NULL); 267 268 if (value == NULL) { 269 return -ENOMEM; 270 } 271 272 msg->setString(key.c_str(), value); 273 274 env->ReleaseStringUTFChars((jstring)valueObj, value); 275 value = NULL; 276 } else if (env->IsInstanceOf(valueObj, integerClass)) { 277 jmethodID intValueID = 278 env->GetMethodID(integerClass, "intValue", "()I"); 279 CHECK(intValueID != NULL); 280 281 jint value = env->CallIntMethod(valueObj, intValueID); 282 283 msg->setInt32(key.c_str(), value); 284 } else if (env->IsInstanceOf(valueObj, floatClass)) { 285 jmethodID floatValueID = 286 env->GetMethodID(floatClass, "floatValue", "()F"); 287 CHECK(floatValueID != NULL); 288 289 jfloat value = env->CallFloatMethod(valueObj, floatValueID); 290 291 msg->setFloat(key.c_str(), value); 292 } else if (env->IsInstanceOf(valueObj, byteBufClass)) { 293 jmethodID positionID = 294 env->GetMethodID(byteBufClass, "position", "()I"); 295 CHECK(positionID != NULL); 296 297 jmethodID limitID = 298 env->GetMethodID(byteBufClass, "limit", "()I"); 299 CHECK(limitID != NULL); 300 301 jint position = env->CallIntMethod(valueObj, positionID); 302 jint limit = env->CallIntMethod(valueObj, limitID); 303 304 sp<ABuffer> buffer = new ABuffer(limit - position); 305 306 void *data = env->GetDirectBufferAddress(valueObj); 307 308 if (data != NULL) { 309 memcpy(buffer->data(), 310 (const uint8_t *)data + position, 311 buffer->size()); 312 } else { 313 jmethodID arrayID = 314 env->GetMethodID(byteBufClass, "array", "()[B"); 315 CHECK(arrayID != NULL); 316 317 jbyteArray byteArray = 318 (jbyteArray)env->CallObjectMethod(valueObj, arrayID); 319 CHECK(byteArray != NULL); 320 321 env->GetByteArrayRegion( 322 byteArray, 323 position, 324 buffer->size(), 325 (jbyte *)buffer->data()); 326 327 env->DeleteLocalRef(byteArray); byteArray = NULL; 328 } 329 330 msg->setObject(key.c_str(), buffer); 331 } 332 } 333 334 *out = msg; 335 336 return OK; 337} 338 339} // namespace android 340 341