android_media_Utils.cpp revision 5c850396b39a57baabd37a9c0c8324f1bee408ca
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::kTypeBuffer: 180 { 181 sp<ABuffer> buffer; 182 CHECK(msg->findBuffer(key, &buffer)); 183 184 valueObj = makeByteBufferObject( 185 env, buffer->data(), buffer->size()); 186 break; 187 } 188 189 default: 190 break; 191 } 192 193 if (valueObj != NULL) { 194 jstring keyObj = env->NewStringUTF(key); 195 196 jobject res = env->CallObjectMethod( 197 hashMap, hashMapPutID, keyObj, valueObj); 198 199 env->DeleteLocalRef(keyObj); keyObj = NULL; 200 env->DeleteLocalRef(valueObj); valueObj = NULL; 201 } 202 } 203 204 *map = hashMap; 205 206 return OK; 207} 208 209status_t ConvertKeyValueArraysToMessage( 210 JNIEnv *env, jobjectArray keys, jobjectArray values, 211 sp<AMessage> *out) { 212 jclass stringClass = env->FindClass("java/lang/String"); 213 CHECK(stringClass != NULL); 214 215 jclass integerClass = env->FindClass("java/lang/Integer"); 216 CHECK(integerClass != NULL); 217 218 jclass floatClass = env->FindClass("java/lang/Float"); 219 CHECK(floatClass != NULL); 220 221 jclass byteBufClass = env->FindClass("java/nio/ByteBuffer"); 222 CHECK(byteBufClass != NULL); 223 224 sp<AMessage> msg = new AMessage; 225 226 jsize numEntries = 0; 227 228 if (keys != NULL) { 229 if (values == NULL) { 230 return -EINVAL; 231 } 232 233 numEntries = env->GetArrayLength(keys); 234 235 if (numEntries != env->GetArrayLength(values)) { 236 return -EINVAL; 237 } 238 } else if (values != NULL) { 239 return -EINVAL; 240 } 241 242 for (jsize i = 0; i < numEntries; ++i) { 243 jobject keyObj = env->GetObjectArrayElement(keys, i); 244 245 if (!env->IsInstanceOf(keyObj, stringClass)) { 246 return -EINVAL; 247 } 248 249 const char *tmp = env->GetStringUTFChars((jstring)keyObj, NULL); 250 251 if (tmp == NULL) { 252 return -ENOMEM; 253 } 254 255 AString key = tmp; 256 257 env->ReleaseStringUTFChars((jstring)keyObj, tmp); 258 tmp = NULL; 259 260 jobject valueObj = env->GetObjectArrayElement(values, i); 261 262 if (env->IsInstanceOf(valueObj, stringClass)) { 263 const char *value = env->GetStringUTFChars((jstring)valueObj, NULL); 264 265 if (value == NULL) { 266 return -ENOMEM; 267 } 268 269 msg->setString(key.c_str(), value); 270 271 env->ReleaseStringUTFChars((jstring)valueObj, value); 272 value = NULL; 273 } else if (env->IsInstanceOf(valueObj, integerClass)) { 274 jmethodID intValueID = 275 env->GetMethodID(integerClass, "intValue", "()I"); 276 CHECK(intValueID != NULL); 277 278 jint value = env->CallIntMethod(valueObj, intValueID); 279 280 msg->setInt32(key.c_str(), value); 281 } else if (env->IsInstanceOf(valueObj, floatClass)) { 282 jmethodID floatValueID = 283 env->GetMethodID(floatClass, "floatValue", "()F"); 284 CHECK(floatValueID != NULL); 285 286 jfloat value = env->CallFloatMethod(valueObj, floatValueID); 287 288 msg->setFloat(key.c_str(), value); 289 } else if (env->IsInstanceOf(valueObj, byteBufClass)) { 290 jmethodID positionID = 291 env->GetMethodID(byteBufClass, "position", "()I"); 292 CHECK(positionID != NULL); 293 294 jmethodID limitID = 295 env->GetMethodID(byteBufClass, "limit", "()I"); 296 CHECK(limitID != NULL); 297 298 jint position = env->CallIntMethod(valueObj, positionID); 299 jint limit = env->CallIntMethod(valueObj, limitID); 300 301 sp<ABuffer> buffer = new ABuffer(limit - position); 302 303 void *data = env->GetDirectBufferAddress(valueObj); 304 305 if (data != NULL) { 306 memcpy(buffer->data(), 307 (const uint8_t *)data + position, 308 buffer->size()); 309 } else { 310 jmethodID arrayID = 311 env->GetMethodID(byteBufClass, "array", "()[B"); 312 CHECK(arrayID != NULL); 313 314 jbyteArray byteArray = 315 (jbyteArray)env->CallObjectMethod(valueObj, arrayID); 316 CHECK(byteArray != NULL); 317 318 env->GetByteArrayRegion( 319 byteArray, 320 position, 321 buffer->size(), 322 (jbyte *)buffer->data()); 323 324 env->DeleteLocalRef(byteArray); byteArray = NULL; 325 } 326 327 msg->setObject(key.c_str(), buffer); 328 } 329 } 330 331 *out = msg; 332 333 return OK; 334} 335 336} // namespace android 337 338