Home | History | Annotate | Download | only in jni
      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