Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2019, 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 "AndroidMediaStreams"
     19 
     20 #include <utils/Log.h>
     21 #include "android_media_Streams.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 #include <nativehelper/ScopedLocalRef.h>
     28 
     29 namespace android {
     30 
     31 AssetStream::AssetStream(SkStream* stream)
     32     : mStream(stream), mPosition(0) {
     33 }
     34 
     35 AssetStream::~AssetStream() {
     36 }
     37 
     38 piex::Error AssetStream::GetData(
     39         const size_t offset, const size_t length, std::uint8_t* data) {
     40     // Seek first.
     41     if (mPosition != offset) {
     42         if (!mStream->seek(offset)) {
     43             return piex::Error::kFail;
     44         }
     45     }
     46 
     47     // Read bytes.
     48     size_t size = mStream->read((void*)data, length);
     49     mPosition = offset + size;
     50 
     51     return size == length ? piex::Error::kOk : piex::Error::kFail;
     52 }
     53 
     54 BufferedStream::BufferedStream(SkStream* stream)
     55     : mStream(stream) {
     56 }
     57 
     58 BufferedStream::~BufferedStream() {
     59 }
     60 
     61 piex::Error BufferedStream::GetData(
     62         const size_t offset, const size_t length, std::uint8_t* data) {
     63     // Seek first.
     64     if (offset + length > mStreamBuffer.bytesWritten()) {
     65         size_t sizeToRead = offset + length - mStreamBuffer.bytesWritten();
     66         if (sizeToRead <= kMinSizeToRead) {
     67             sizeToRead = kMinSizeToRead;
     68         }
     69 
     70         void* tempBuffer = malloc(sizeToRead);
     71         if (tempBuffer == NULL) {
     72           return piex::Error::kFail;
     73         }
     74 
     75         size_t bytesRead = mStream->read(tempBuffer, sizeToRead);
     76         if (bytesRead != sizeToRead) {
     77             free(tempBuffer);
     78             return piex::Error::kFail;
     79         }
     80         mStreamBuffer.write(tempBuffer, bytesRead);
     81         free(tempBuffer);
     82     }
     83 
     84     // Read bytes.
     85     if (mStreamBuffer.read((void*)data, offset, length)) {
     86         return piex::Error::kOk;
     87     } else {
     88         return piex::Error::kFail;
     89     }
     90 }
     91 
     92 FileStream::FileStream(const int fd)
     93     : mPosition(0) {
     94     mFile = fdopen(fd, "r");
     95     if (mFile == NULL) {
     96         return;
     97     }
     98 }
     99 
    100 FileStream::FileStream(const String8 filename)
    101     : mPosition(0) {
    102     mFile = fopen(filename.string(), "r");
    103     if (mFile == NULL) {
    104         return;
    105     }
    106 }
    107 
    108 FileStream::~FileStream() {
    109     if (mFile != NULL) {
    110         fclose(mFile);
    111         mFile = NULL;
    112     }
    113 }
    114 
    115 piex::Error FileStream::GetData(
    116         const size_t offset, const size_t length, std::uint8_t* data) {
    117     if (mFile == NULL) {
    118         return piex::Error::kFail;
    119     }
    120 
    121     // Seek first.
    122     if (mPosition != offset) {
    123         fseek(mFile, offset, SEEK_SET);
    124     }
    125 
    126     // Read bytes.
    127     size_t size = fread((void*)data, sizeof(std::uint8_t), length, mFile);
    128     mPosition += size;
    129 
    130     // Handle errors and verify the size.
    131     if (ferror(mFile) || size != length) {
    132         ALOGV("GetData read failed: (offset: %zu, length: %zu)", offset, length);
    133         return piex::Error::kFail;
    134     }
    135     return piex::Error::kOk;
    136 }
    137 
    138 bool FileStream::exists() const {
    139     return mFile != NULL;
    140 }
    141 
    142 bool GetExifFromRawImage(
    143         piex::StreamInterface* stream, const String8& filename,
    144         piex::PreviewImageData& image_data) {
    145     // Reset the PreviewImageData to its default.
    146     image_data = piex::PreviewImageData();
    147 
    148     if (!piex::IsRaw(stream)) {
    149         // Format not supported.
    150         ALOGV("Format not supported: %s", filename.string());
    151         return false;
    152     }
    153 
    154     piex::Error err = piex::GetPreviewImageData(stream, &image_data);
    155 
    156     if (err != piex::Error::kOk) {
    157         // The input data seems to be broken.
    158         ALOGV("Raw image not detected: %s (piex error code: %d)", filename.string(), (int32_t)err);
    159         return false;
    160     }
    161 
    162     return true;
    163 }
    164 
    165 bool ConvertKeyValueArraysToKeyedVector(
    166         JNIEnv *env, jobjectArray keys, jobjectArray values,
    167         KeyedVector<String8, String8>* keyedVector) {
    168 
    169     int nKeyValuePairs = 0;
    170     bool failed = false;
    171     if (keys != NULL && values != NULL) {
    172         nKeyValuePairs = env->GetArrayLength(keys);
    173         failed = (nKeyValuePairs != env->GetArrayLength(values));
    174     }
    175 
    176     if (!failed) {
    177         failed = ((keys != NULL && values == NULL) ||
    178                   (keys == NULL && values != NULL));
    179     }
    180 
    181     if (failed) {
    182         ALOGE("keys and values arrays have different length");
    183         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    184         return false;
    185     }
    186 
    187     for (int i = 0; i < nKeyValuePairs; ++i) {
    188         // No need to check on the ArrayIndexOutOfBoundsException, since
    189         // it won't happen here.
    190         jstring key = (jstring) env->GetObjectArrayElement(keys, i);
    191         jstring value = (jstring) env->GetObjectArrayElement(values, i);
    192 
    193         const char* keyStr = env->GetStringUTFChars(key, NULL);
    194         if (!keyStr) {  // OutOfMemoryError
    195             return false;
    196         }
    197 
    198         const char* valueStr = env->GetStringUTFChars(value, NULL);
    199         if (!valueStr) {  // OutOfMemoryError
    200             env->ReleaseStringUTFChars(key, keyStr);
    201             return false;
    202         }
    203 
    204         keyedVector->add(String8(keyStr), String8(valueStr));
    205 
    206         env->ReleaseStringUTFChars(key, keyStr);
    207         env->ReleaseStringUTFChars(value, valueStr);
    208         env->DeleteLocalRef(key);
    209         env->DeleteLocalRef(value);
    210     }
    211     return true;
    212 }
    213 
    214 static jobject makeIntegerObject(JNIEnv *env, int32_t value) {
    215     ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Integer"));
    216     CHECK(clazz.get() != NULL);
    217 
    218     jmethodID integerConstructID =
    219         env->GetMethodID(clazz.get(), "<init>", "(I)V");
    220     CHECK(integerConstructID != NULL);
    221 
    222     return env->NewObject(clazz.get(), integerConstructID, value);
    223 }
    224 
    225 static jobject makeLongObject(JNIEnv *env, int64_t value) {
    226     ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Long"));
    227     CHECK(clazz.get() != NULL);
    228 
    229     jmethodID longConstructID = env->GetMethodID(clazz.get(), "<init>", "(J)V");
    230     CHECK(longConstructID != NULL);
    231 
    232     return env->NewObject(clazz.get(), longConstructID, value);
    233 }
    234 
    235 static jobject makeFloatObject(JNIEnv *env, float value) {
    236     ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Float"));
    237     CHECK(clazz.get() != NULL);
    238 
    239     jmethodID floatConstructID =
    240         env->GetMethodID(clazz.get(), "<init>", "(F)V");
    241     CHECK(floatConstructID != NULL);
    242 
    243     return env->NewObject(clazz.get(), floatConstructID, value);
    244 }
    245 
    246 static jobject makeByteBufferObject(
    247         JNIEnv *env, const void *data, size_t size) {
    248     jbyteArray byteArrayObj = env->NewByteArray(size);
    249     env->SetByteArrayRegion(byteArrayObj, 0, size, (const jbyte *)data);
    250 
    251     ScopedLocalRef<jclass> clazz(env, env->FindClass("java/nio/ByteBuffer"));
    252     CHECK(clazz.get() != NULL);
    253 
    254     jmethodID byteBufWrapID =
    255         env->GetStaticMethodID(
    256                 clazz.get(), "wrap", "([B)Ljava/nio/ByteBuffer;");
    257     CHECK(byteBufWrapID != NULL);
    258 
    259     jobject byteBufObj = env->CallStaticObjectMethod(
    260             clazz.get(), byteBufWrapID, byteArrayObj);
    261 
    262     env->DeleteLocalRef(byteArrayObj); byteArrayObj = NULL;
    263 
    264     return byteBufObj;
    265 }
    266 
    267 static void SetMapInt32(
    268         JNIEnv *env, jobject hashMapObj, jmethodID hashMapPutID,
    269         const char *key, int32_t value) {
    270     jstring keyObj = env->NewStringUTF(key);
    271     jobject valueObj = makeIntegerObject(env, value);
    272 
    273     env->CallObjectMethod(hashMapObj, hashMapPutID, keyObj, valueObj);
    274 
    275     env->DeleteLocalRef(valueObj); valueObj = NULL;
    276     env->DeleteLocalRef(keyObj); keyObj = NULL;
    277 }
    278 
    279 status_t ConvertMessageToMap(
    280         JNIEnv *env, const sp<AMessage> &msg, jobject *map) {
    281     ScopedLocalRef<jclass> hashMapClazz(
    282             env, env->FindClass("java/util/HashMap"));
    283 
    284     if (hashMapClazz.get() == NULL) {
    285         return -EINVAL;
    286     }
    287 
    288     jmethodID hashMapConstructID =
    289         env->GetMethodID(hashMapClazz.get(), "<init>", "()V");
    290 
    291     if (hashMapConstructID == NULL) {
    292         return -EINVAL;
    293     }
    294 
    295     jmethodID hashMapPutID =
    296         env->GetMethodID(
    297                 hashMapClazz.get(),
    298                 "put",
    299                 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
    300 
    301     if (hashMapPutID == NULL) {
    302         return -EINVAL;
    303     }
    304 
    305     jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID);
    306 
    307     for (size_t i = 0; i < msg->countEntries(); ++i) {
    308         AMessage::Type valueType;
    309         const char *key = msg->getEntryNameAt(i, &valueType);
    310 
    311         if (!strncmp(key, "android._", 9)) {
    312             // don't expose private keys (starting with android._)
    313             continue;
    314         }
    315 
    316         jobject valueObj = NULL;
    317 
    318         switch (valueType) {
    319             case AMessage::kTypeInt32:
    320             {
    321                 int32_t val;
    322                 CHECK(msg->findInt32(key, &val));
    323 
    324                 valueObj = makeIntegerObject(env, val);
    325                 break;
    326             }
    327 
    328             case AMessage::kTypeInt64:
    329             {
    330                 int64_t val;
    331                 CHECK(msg->findInt64(key, &val));
    332 
    333                 valueObj = makeLongObject(env, val);
    334                 break;
    335             }
    336 
    337             case AMessage::kTypeFloat:
    338             {
    339                 float val;
    340                 CHECK(msg->findFloat(key, &val));
    341 
    342                 valueObj = makeFloatObject(env, val);
    343                 break;
    344             }
    345 
    346             case AMessage::kTypeString:
    347             {
    348                 AString val;
    349                 CHECK(msg->findString(key, &val));
    350 
    351                 valueObj = env->NewStringUTF(val.c_str());
    352                 break;
    353             }
    354 
    355             case AMessage::kTypeBuffer:
    356             {
    357                 sp<ABuffer> buffer;
    358                 CHECK(msg->findBuffer(key, &buffer));
    359 
    360                 valueObj = makeByteBufferObject(
    361                         env, buffer->data(), buffer->size());
    362                 break;
    363             }
    364 
    365             case AMessage::kTypeRect:
    366             {
    367                 int32_t left, top, right, bottom;
    368                 CHECK(msg->findRect(key, &left, &top, &right, &bottom));
    369 
    370                 SetMapInt32(
    371                         env,
    372                         hashMap,
    373                         hashMapPutID,
    374                         AStringPrintf("%s-left", key).c_str(),
    375                         left);
    376 
    377                 SetMapInt32(
    378                         env,
    379                         hashMap,
    380                         hashMapPutID,
    381                         AStringPrintf("%s-top", key).c_str(),
    382                         top);
    383 
    384                 SetMapInt32(
    385                         env,
    386                         hashMap,
    387                         hashMapPutID,
    388                         AStringPrintf("%s-right", key).c_str(),
    389                         right);
    390 
    391                 SetMapInt32(
    392                         env,
    393                         hashMap,
    394                         hashMapPutID,
    395                         AStringPrintf("%s-bottom", key).c_str(),
    396                         bottom);
    397                 break;
    398             }
    399 
    400             default:
    401                 break;
    402         }
    403 
    404         if (valueObj != NULL) {
    405             jstring keyObj = env->NewStringUTF(key);
    406 
    407             env->CallObjectMethod(hashMap, hashMapPutID, keyObj, valueObj);
    408 
    409             env->DeleteLocalRef(keyObj); keyObj = NULL;
    410             env->DeleteLocalRef(valueObj); valueObj = NULL;
    411         }
    412     }
    413 
    414     *map = hashMap;
    415 
    416     return OK;
    417 }
    418 
    419 status_t ConvertKeyValueArraysToMessage(
    420         JNIEnv *env, jobjectArray keys, jobjectArray values,
    421         sp<AMessage> *out) {
    422     ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String"));
    423     CHECK(stringClass.get() != NULL);
    424     ScopedLocalRef<jclass> integerClass(env, env->FindClass("java/lang/Integer"));
    425     CHECK(integerClass.get() != NULL);
    426     ScopedLocalRef<jclass> longClass(env, env->FindClass("java/lang/Long"));
    427     CHECK(longClass.get() != NULL);
    428     ScopedLocalRef<jclass> floatClass(env, env->FindClass("java/lang/Float"));
    429     CHECK(floatClass.get() != NULL);
    430     ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer"));
    431     CHECK(byteBufClass.get() != NULL);
    432 
    433     sp<AMessage> msg = new AMessage;
    434 
    435     jsize numEntries = 0;
    436 
    437     if (keys != NULL) {
    438         if (values == NULL) {
    439             return -EINVAL;
    440         }
    441 
    442         numEntries = env->GetArrayLength(keys);
    443 
    444         if (numEntries != env->GetArrayLength(values)) {
    445             return -EINVAL;
    446         }
    447     } else if (values != NULL) {
    448         return -EINVAL;
    449     }
    450 
    451     for (jsize i = 0; i < numEntries; ++i) {
    452         jobject keyObj = env->GetObjectArrayElement(keys, i);
    453 
    454         if (!env->IsInstanceOf(keyObj, stringClass.get())) {
    455             return -EINVAL;
    456         }
    457 
    458         const char *tmp = env->GetStringUTFChars((jstring)keyObj, NULL);
    459 
    460         if (tmp == NULL) {
    461             return -ENOMEM;
    462         }
    463 
    464         AString key = tmp;
    465 
    466         env->ReleaseStringUTFChars((jstring)keyObj, tmp);
    467         tmp = NULL;
    468 
    469         if (key.startsWith("android._")) {
    470             // don't propagate private keys (starting with android._)
    471             continue;
    472         }
    473 
    474         jobject valueObj = env->GetObjectArrayElement(values, i);
    475 
    476         if (env->IsInstanceOf(valueObj, stringClass.get())) {
    477             const char *value = env->GetStringUTFChars((jstring)valueObj, NULL);
    478 
    479             if (value == NULL) {
    480                 return -ENOMEM;
    481             }
    482 
    483             msg->setString(key.c_str(), value);
    484 
    485             env->ReleaseStringUTFChars((jstring)valueObj, value);
    486             value = NULL;
    487         } else if (env->IsInstanceOf(valueObj, integerClass.get())) {
    488             jmethodID intValueID =
    489                 env->GetMethodID(integerClass.get(), "intValue", "()I");
    490             CHECK(intValueID != NULL);
    491 
    492             jint value = env->CallIntMethod(valueObj, intValueID);
    493 
    494             msg->setInt32(key.c_str(), value);
    495         } else if (env->IsInstanceOf(valueObj, longClass.get())) {
    496             jmethodID longValueID =
    497                 env->GetMethodID(longClass.get(), "longValue", "()J");
    498             CHECK(longValueID != NULL);
    499 
    500             jlong value = env->CallLongMethod(valueObj, longValueID);
    501 
    502             msg->setInt64(key.c_str(), value);
    503         } else if (env->IsInstanceOf(valueObj, floatClass.get())) {
    504             jmethodID floatValueID =
    505                 env->GetMethodID(floatClass.get(), "floatValue", "()F");
    506             CHECK(floatValueID != NULL);
    507 
    508             jfloat value = env->CallFloatMethod(valueObj, floatValueID);
    509 
    510             msg->setFloat(key.c_str(), value);
    511         } else if (env->IsInstanceOf(valueObj, byteBufClass.get())) {
    512             jmethodID positionID =
    513                 env->GetMethodID(byteBufClass.get(), "position", "()I");
    514             CHECK(positionID != NULL);
    515 
    516             jmethodID limitID =
    517                 env->GetMethodID(byteBufClass.get(), "limit", "()I");
    518             CHECK(limitID != NULL);
    519 
    520             jint position = env->CallIntMethod(valueObj, positionID);
    521             jint limit = env->CallIntMethod(valueObj, limitID);
    522 
    523             sp<ABuffer> buffer = new ABuffer(limit - position);
    524 
    525             void *data = env->GetDirectBufferAddress(valueObj);
    526 
    527             if (data != NULL) {
    528                 memcpy(buffer->data(),
    529                        (const uint8_t *)data + position,
    530                        buffer->size());
    531             } else {
    532                 jmethodID arrayID =
    533                     env->GetMethodID(byteBufClass.get(), "array", "()[B");
    534                 CHECK(arrayID != NULL);
    535 
    536                 jbyteArray byteArray =
    537                     (jbyteArray)env->CallObjectMethod(valueObj, arrayID);
    538                 CHECK(byteArray != NULL);
    539 
    540                 env->GetByteArrayRegion(
    541                         byteArray,
    542                         position,
    543                         buffer->size(),
    544                         (jbyte *)buffer->data());
    545 
    546                 env->DeleteLocalRef(byteArray); byteArray = NULL;
    547             }
    548 
    549             msg->setBuffer(key.c_str(), buffer);
    550         }
    551     }
    552 
    553     *out = msg;
    554 
    555     return OK;
    556 }
    557 
    558 }  // namespace android
    559 
    560