Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2012, 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 "MediaExtractor-JNI"
     19 #include <utils/Log.h>
     20 
     21 #include "android_media_AudioPresentation.h"
     22 #include "android_media_MediaDataSource.h"
     23 #include "android_media_MediaExtractor.h"
     24 #include "android_media_MediaMetricsJNI.h"
     25 #include "android_media_Streams.h"
     26 #include "android_os_HwRemoteBinder.h"
     27 #include "android_runtime/AndroidRuntime.h"
     28 #include "android_runtime/Log.h"
     29 #include "android_util_Binder.h"
     30 #include "jni.h"
     31 #include <nativehelper/JNIHelp.h>
     32 
     33 #include <android/hardware/cas/1.0/BpHwCas.h>
     34 #include <android/hardware/cas/1.0/BnHwCas.h>
     35 #include <hidl/HybridInterface.h>
     36 #include <media/IMediaHTTPService.h>
     37 #include <media/hardware/CryptoAPI.h>
     38 #include <media/stagefright/foundation/ABuffer.h>
     39 #include <media/stagefright/foundation/ADebug.h>
     40 #include <media/stagefright/foundation/AMessage.h>
     41 #include <media/DataSource.h>
     42 #include <media/stagefright/InterfaceUtils.h>
     43 #include <media/stagefright/MediaErrors.h>
     44 #include <media/stagefright/MetaData.h>
     45 #include <media/stagefright/NuMediaExtractor.h>
     46 #include <nativehelper/ScopedLocalRef.h>
     47 
     48 namespace android {
     49 
     50 using namespace hardware::cas::V1_0;
     51 
     52 struct fields_t {
     53     jfieldID context;
     54 
     55     jmethodID cryptoInfoSetID;
     56     jmethodID cryptoInfoSetPatternID;
     57 };
     58 
     59 static fields_t gFields;
     60 static JAudioPresentationInfo::fields_t gAudioPresentationFields;
     61 
     62 JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz)
     63     : mClass(NULL),
     64       mObject(NULL) {
     65     jclass clazz = env->GetObjectClass(thiz);
     66     CHECK(clazz != NULL);
     67 
     68     mClass = (jclass)env->NewGlobalRef(clazz);
     69     mObject = env->NewWeakGlobalRef(thiz);
     70 
     71     mImpl = new NuMediaExtractor;
     72 }
     73 
     74 JMediaExtractor::~JMediaExtractor() {
     75     JNIEnv *env = AndroidRuntime::getJNIEnv();
     76 
     77     env->DeleteWeakGlobalRef(mObject);
     78     mObject = NULL;
     79     env->DeleteGlobalRef(mClass);
     80     mClass = NULL;
     81 }
     82 
     83 status_t JMediaExtractor::setDataSource(
     84         const sp<IMediaHTTPService> &httpService,
     85         const char *path,
     86         const KeyedVector<String8, String8> *headers) {
     87     return mImpl->setDataSource(httpService, path, headers);
     88 }
     89 
     90 status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
     91     return mImpl->setDataSource(fd, offset, size);
     92 }
     93 
     94 status_t JMediaExtractor::setDataSource(const sp<DataSource> &datasource) {
     95     return mImpl->setDataSource(datasource);
     96 }
     97 
     98 status_t JMediaExtractor::setMediaCas(JNIEnv *env, jobject casBinderObj) {
     99     if (casBinderObj == NULL) {
    100         return BAD_VALUE;
    101     }
    102 
    103     sp<hardware::IBinder> hwBinder =
    104         JHwRemoteBinder::GetNativeContext(env, casBinderObj)->getBinder();
    105     if (hwBinder == NULL) {
    106         return BAD_VALUE;
    107     }
    108 
    109     sp<ICas> cas = hardware::fromBinder<ICas, BpHwCas, BnHwCas>(hwBinder);
    110     if (cas == NULL) {
    111         return BAD_VALUE;
    112     }
    113 
    114     HalToken halToken;
    115     if (!createHalToken(cas, &halToken)) {
    116         return BAD_VALUE;
    117     }
    118 
    119     return mImpl->setMediaCas(halToken);
    120 }
    121 
    122 size_t JMediaExtractor::countTracks() const {
    123     return mImpl->countTracks();
    124 }
    125 
    126 status_t JMediaExtractor::getTrackFormat(size_t index, jobject *format) const {
    127     sp<AMessage> msg;
    128     status_t err;
    129     if ((err = mImpl->getTrackFormat(index, &msg)) != OK) {
    130         return err;
    131     }
    132 
    133     JNIEnv *env = AndroidRuntime::getJNIEnv();
    134 
    135     return ConvertMessageToMap(env, msg, format);
    136 }
    137 
    138 status_t JMediaExtractor::getFileFormat(jobject *format) const {
    139     sp<AMessage> msg;
    140     status_t err;
    141     if ((err = mImpl->getFileFormat(&msg)) != OK) {
    142         return err;
    143     }
    144 
    145     JNIEnv *env = AndroidRuntime::getJNIEnv();
    146 
    147     return ConvertMessageToMap(env, msg, format);
    148 }
    149 
    150 status_t JMediaExtractor::selectTrack(size_t index) {
    151     return mImpl->selectTrack(index);
    152 }
    153 
    154 status_t JMediaExtractor::unselectTrack(size_t index) {
    155     return mImpl->unselectTrack(index);
    156 }
    157 
    158 status_t JMediaExtractor::seekTo(
    159         int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) {
    160     return mImpl->seekTo(timeUs, mode);
    161 }
    162 
    163 status_t JMediaExtractor::advance() {
    164     return mImpl->advance();
    165 }
    166 
    167 status_t JMediaExtractor::readSampleData(
    168         jobject byteBuf, size_t offset, size_t *sampleSize) {
    169     JNIEnv *env = AndroidRuntime::getJNIEnv();
    170 
    171     void *dst = env->GetDirectBufferAddress(byteBuf);
    172 
    173     size_t dstSize;
    174     jbyteArray byteArray = NULL;
    175 
    176     ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer"));
    177     CHECK(byteBufClass.get() != NULL);
    178 
    179     if (dst == NULL) {
    180         jmethodID arrayID =
    181             env->GetMethodID(byteBufClass.get(), "array", "()[B");
    182         CHECK(arrayID != NULL);
    183 
    184         byteArray =
    185             (jbyteArray)env->CallObjectMethod(byteBuf, arrayID);
    186 
    187         if (byteArray == NULL) {
    188             return INVALID_OPERATION;
    189         }
    190 
    191         jboolean isCopy;
    192         dst = env->GetByteArrayElements(byteArray, &isCopy);
    193 
    194         dstSize = (size_t) env->GetArrayLength(byteArray);
    195     } else {
    196         dstSize = (size_t) env->GetDirectBufferCapacity(byteBuf);
    197     }
    198 
    199     if (dstSize < offset) {
    200         if (byteArray != NULL) {
    201             env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0);
    202         }
    203 
    204         return -ERANGE;
    205     }
    206 
    207     sp<ABuffer> buffer = new ABuffer((char *)dst + offset, dstSize - offset);
    208 
    209     status_t err = mImpl->readSampleData(buffer);
    210 
    211     if (byteArray != NULL) {
    212         env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0);
    213     }
    214 
    215     if (err != OK) {
    216         return err;
    217     }
    218 
    219     *sampleSize = buffer->size();
    220 
    221     jmethodID positionID = env->GetMethodID(
    222             byteBufClass.get(), "position", "(I)Ljava/nio/Buffer;");
    223 
    224     CHECK(positionID != NULL);
    225 
    226     jmethodID limitID = env->GetMethodID(
    227             byteBufClass.get(), "limit", "(I)Ljava/nio/Buffer;");
    228 
    229     CHECK(limitID != NULL);
    230 
    231     jobject me = env->CallObjectMethod(
    232             byteBuf, limitID, offset + *sampleSize);
    233     env->DeleteLocalRef(me);
    234     me = env->CallObjectMethod(
    235             byteBuf, positionID, offset);
    236     env->DeleteLocalRef(me);
    237     me = NULL;
    238 
    239     return OK;
    240 }
    241 
    242 status_t JMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
    243     return mImpl->getSampleTrackIndex(trackIndex);
    244 }
    245 
    246 status_t JMediaExtractor::getSampleTime(int64_t *sampleTimeUs) {
    247     return mImpl->getSampleTime(sampleTimeUs);
    248 }
    249 
    250 status_t JMediaExtractor::getSampleSize(size_t *sampleSize) {
    251     return mImpl->getSampleSize(sampleSize);
    252 }
    253 
    254 status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
    255     *sampleFlags = 0;
    256 
    257     sp<MetaData> meta;
    258     status_t err = mImpl->getSampleMeta(&meta);
    259 
    260     if (err != OK) {
    261         return err;
    262     }
    263 
    264     int32_t val;
    265     if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
    266         (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_SYNC;
    267     }
    268 
    269     uint32_t type;
    270     const void *data;
    271     size_t size;
    272     if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
    273         (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED;
    274     }
    275 
    276     return OK;
    277 }
    278 
    279 status_t JMediaExtractor::getMetrics(Parcel *reply) const {
    280 
    281     status_t status = mImpl->getMetrics(reply);
    282     return status;
    283 }
    284 
    285 
    286 status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) {
    287     return mImpl->getSampleMeta(sampleMeta);
    288 }
    289 
    290 bool JMediaExtractor::getCachedDuration(int64_t *durationUs, bool *eos) const {
    291     return mImpl->getCachedDuration(durationUs, eos);
    292 }
    293 
    294 status_t JMediaExtractor::getAudioPresentations(size_t trackIdx,
    295         AudioPresentationCollection *presentations) const {
    296     return mImpl->getAudioPresentations(trackIdx, presentations);
    297 }
    298 }  // namespace android
    299 
    300 ////////////////////////////////////////////////////////////////////////////////
    301 
    302 using namespace android;
    303 
    304 static sp<JMediaExtractor> setMediaExtractor(
    305         JNIEnv *env, jobject thiz, const sp<JMediaExtractor> &extractor) {
    306     sp<JMediaExtractor> old =
    307         (JMediaExtractor *)env->GetLongField(thiz, gFields.context);
    308 
    309     if (extractor != NULL) {
    310         extractor->incStrong(thiz);
    311     }
    312     if (old != NULL) {
    313         old->decStrong(thiz);
    314     }
    315     env->SetLongField(thiz, gFields.context, (jlong)extractor.get());
    316 
    317     return old;
    318 }
    319 
    320 static sp<JMediaExtractor> getMediaExtractor(JNIEnv *env, jobject thiz) {
    321     return (JMediaExtractor *)env->GetLongField(thiz, gFields.context);
    322 }
    323 
    324 static void android_media_MediaExtractor_release(JNIEnv *env, jobject thiz) {
    325     setMediaExtractor(env, thiz, NULL);
    326 }
    327 
    328 static jint android_media_MediaExtractor_getTrackCount(
    329         JNIEnv *env, jobject thiz) {
    330     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    331 
    332     if (extractor == NULL) {
    333         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    334         return -1;
    335     }
    336 
    337     return (jint) extractor->countTracks();
    338 }
    339 
    340 static jobject android_media_MediaExtractor_getTrackFormatNative(
    341         JNIEnv *env, jobject thiz, jint index) {
    342     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    343 
    344     if (extractor == NULL) {
    345         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    346         return NULL;
    347     }
    348 
    349     jobject format;
    350     status_t err = extractor->getTrackFormat(index, &format);
    351 
    352     if (err != OK) {
    353         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    354         return NULL;
    355     }
    356 
    357     return format;
    358 }
    359 
    360 static jobject android_media_MediaExtractor_getFileFormatNative(
    361         JNIEnv *env, jobject thiz) {
    362     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    363 
    364     if (extractor == NULL) {
    365         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    366         return NULL;
    367     }
    368 
    369     jobject format;
    370     status_t err = extractor->getFileFormat(&format);
    371 
    372     if (err != OK) {
    373         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    374         return NULL;
    375     }
    376 
    377     return format;
    378 }
    379 
    380 static void android_media_MediaExtractor_selectTrack(
    381         JNIEnv *env, jobject thiz, jint index) {
    382     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    383 
    384     if (extractor == NULL) {
    385         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    386         return;
    387     }
    388 
    389     status_t err = extractor->selectTrack(index);
    390 
    391     if (err != OK) {
    392         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    393         return;
    394     }
    395 }
    396 
    397 static void android_media_MediaExtractor_unselectTrack(
    398         JNIEnv *env, jobject thiz, jint index) {
    399     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    400 
    401     if (extractor == NULL) {
    402         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    403         return;
    404     }
    405 
    406     status_t err = extractor->unselectTrack(index);
    407 
    408     if (err != OK) {
    409         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    410         return;
    411     }
    412 }
    413 
    414 static void android_media_MediaExtractor_seekTo(
    415         JNIEnv *env, jobject thiz, jlong timeUs, jint mode) {
    416     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    417 
    418     if (extractor == NULL) {
    419         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    420         return;
    421     }
    422 
    423     if (mode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC
    424             || mode >= MediaSource::ReadOptions::SEEK_CLOSEST) {
    425         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    426         return;
    427     }
    428 
    429     extractor->seekTo(timeUs, (MediaSource::ReadOptions::SeekMode)mode);
    430 }
    431 
    432 static jboolean android_media_MediaExtractor_advance(
    433         JNIEnv *env, jobject thiz) {
    434     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    435 
    436     if (extractor == NULL) {
    437         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    438         return JNI_FALSE;
    439     }
    440 
    441     status_t err = extractor->advance();
    442 
    443     if (err == ERROR_END_OF_STREAM) {
    444         return JNI_FALSE;
    445     } else if (err != OK) {
    446         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    447         return JNI_FALSE;
    448     }
    449 
    450     return JNI_TRUE;
    451 }
    452 
    453 static jint android_media_MediaExtractor_readSampleData(
    454         JNIEnv *env, jobject thiz, jobject byteBuf, jint offset) {
    455     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    456 
    457     if (extractor == NULL) {
    458         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    459         return -1;
    460     }
    461 
    462     size_t sampleSize;
    463     status_t err = extractor->readSampleData(byteBuf, offset, &sampleSize);
    464 
    465     if (err == ERROR_END_OF_STREAM) {
    466         return -1;
    467     } else if (err != OK) {
    468         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    469         return -1;
    470     }
    471 
    472     return (jint) sampleSize;
    473 }
    474 
    475 static jint android_media_MediaExtractor_getSampleTrackIndex(
    476         JNIEnv *env, jobject thiz) {
    477     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    478 
    479     if (extractor == NULL) {
    480         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    481         return -1;
    482     }
    483 
    484     size_t trackIndex;
    485     status_t err = extractor->getSampleTrackIndex(&trackIndex);
    486 
    487     if (err == ERROR_END_OF_STREAM) {
    488         return -1;
    489     } else if (err != OK) {
    490         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    491         return -1;
    492     }
    493 
    494     return (jint) trackIndex;
    495 }
    496 
    497 static jlong android_media_MediaExtractor_getSampleTime(
    498         JNIEnv *env, jobject thiz) {
    499     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    500 
    501     if (extractor == NULL) {
    502         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    503         return -1LL;
    504     }
    505 
    506     int64_t sampleTimeUs;
    507     status_t err = extractor->getSampleTime(&sampleTimeUs);
    508 
    509     if (err == ERROR_END_OF_STREAM) {
    510         return -1LL;
    511     } else if (err != OK) {
    512         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    513         return -1LL;
    514     }
    515 
    516     return (jlong) sampleTimeUs;
    517 }
    518 
    519 static jlong android_media_MediaExtractor_getSampleSize(
    520         JNIEnv *env, jobject thiz) {
    521     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    522 
    523     if (extractor == NULL) {
    524         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    525         return -1LL;
    526     }
    527 
    528     size_t sampleSize;
    529     status_t err = extractor->getSampleSize(&sampleSize);
    530 
    531     if (err == ERROR_END_OF_STREAM) {
    532         return -1LL;
    533     } else if (err != OK) {
    534         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    535         return -1LL;
    536     }
    537 
    538     return (jlong) sampleSize;
    539 }
    540 
    541 static jint android_media_MediaExtractor_getSampleFlags(
    542         JNIEnv *env, jobject thiz) {
    543     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    544 
    545     if (extractor == NULL) {
    546         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    547         return -1;
    548     }
    549 
    550     uint32_t sampleFlags;
    551     status_t err = extractor->getSampleFlags(&sampleFlags);
    552 
    553     if (err == ERROR_END_OF_STREAM) {
    554         return -1;
    555     } else if (err != OK) {
    556         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    557         return -1;
    558     }
    559 
    560     return (jint) sampleFlags;
    561 }
    562 
    563 static jboolean android_media_MediaExtractor_getSampleCryptoInfo(
    564         JNIEnv *env, jobject thiz, jobject cryptoInfoObj) {
    565     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    566 
    567     if (extractor == NULL) {
    568         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    569         return JNI_FALSE;
    570     }
    571 
    572     sp<MetaData> meta;
    573     status_t err = extractor->getSampleMeta(&meta);
    574 
    575     if (err != OK) {
    576         return JNI_FALSE;
    577     }
    578 
    579     uint32_t type;
    580     const void *data;
    581     size_t size;
    582     if (!meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
    583         return JNI_FALSE;
    584     }
    585 
    586     size_t numSubSamples = size / sizeof(int32_t);
    587 
    588     if (numSubSamples == 0) {
    589         return JNI_FALSE;
    590     }
    591 
    592     jintArray numBytesOfEncryptedDataObj = env->NewIntArray(numSubSamples);
    593     jboolean isCopy;
    594     jint *dst = env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
    595     for (size_t i = 0; i < numSubSamples; ++i) {
    596         dst[i] = ((const int32_t *)data)[i];
    597     }
    598     env->ReleaseIntArrayElements(numBytesOfEncryptedDataObj, dst, 0);
    599     dst = NULL;
    600 
    601     size_t encSize = size;
    602     jintArray numBytesOfPlainDataObj = NULL;
    603     if (meta->findData(kKeyPlainSizes, &type, &data, &size)) {
    604         if (size != encSize) {
    605             // The two must be of the same length.
    606             return JNI_FALSE;
    607         }
    608 
    609         numBytesOfPlainDataObj = env->NewIntArray(numSubSamples);
    610         jboolean isCopy;
    611         jint *dst = env->GetIntArrayElements(numBytesOfPlainDataObj, &isCopy);
    612         for (size_t i = 0; i < numSubSamples; ++i) {
    613             dst[i] = ((const int32_t *)data)[i];
    614         }
    615         env->ReleaseIntArrayElements(numBytesOfPlainDataObj, dst, 0);
    616         dst = NULL;
    617     }
    618 
    619     jbyteArray keyObj = NULL;
    620     if (meta->findData(kKeyCryptoKey, &type, &data, &size)) {
    621         if (size != 16) {
    622             // Keys must be 16 bytes in length.
    623             return JNI_FALSE;
    624         }
    625 
    626         keyObj = env->NewByteArray(size);
    627         jboolean isCopy;
    628         jbyte *dst = env->GetByteArrayElements(keyObj, &isCopy);
    629         memcpy(dst, data, size);
    630         env->ReleaseByteArrayElements(keyObj, dst, 0);
    631         dst = NULL;
    632     }
    633 
    634     jbyteArray ivObj = NULL;
    635     if (meta->findData(kKeyCryptoIV, &type, &data, &size)) {
    636         if (size != 16) {
    637             // IVs must be 16 bytes in length.
    638             return JNI_FALSE;
    639         }
    640 
    641         ivObj = env->NewByteArray(size);
    642         jboolean isCopy;
    643         jbyte *dst = env->GetByteArrayElements(ivObj, &isCopy);
    644         memcpy(dst, data, size);
    645         env->ReleaseByteArrayElements(ivObj, dst, 0);
    646         dst = NULL;
    647     }
    648 
    649     int32_t mode;
    650     if (!meta->findInt32(kKeyCryptoMode, &mode)) {
    651         mode = CryptoPlugin::kMode_AES_CTR;
    652     }
    653 
    654     env->CallVoidMethod(
    655             cryptoInfoObj,
    656             gFields.cryptoInfoSetID,
    657             (jint)numSubSamples,
    658             numBytesOfPlainDataObj,
    659             numBytesOfEncryptedDataObj,
    660             keyObj,
    661             ivObj,
    662             mode);
    663 
    664     int32_t encryptedByteBlock = 0, skipByteBlock = 0;
    665     meta->findInt32(kKeyEncryptedByteBlock, &encryptedByteBlock);
    666     meta->findInt32(kKeySkipByteBlock, &skipByteBlock);
    667 
    668     env->CallVoidMethod(
    669             cryptoInfoObj,
    670             gFields.cryptoInfoSetPatternID,
    671             encryptedByteBlock,
    672             skipByteBlock);
    673 
    674     return JNI_TRUE;
    675 }
    676 
    677 static jobject android_media_MediaExtractor_getAudioPresentations(
    678         JNIEnv *env, jobject thiz, jint trackIdx) {
    679     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    680     jobject presentationsJObj = JAudioPresentationInfo::asJobject(env, gAudioPresentationFields);
    681     if (extractor == NULL) {
    682         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    683         return presentationsJObj;
    684     }
    685     AudioPresentationCollection presentations;
    686     status_t err = extractor->getAudioPresentations(trackIdx, &presentations);
    687     if (err == ERROR_END_OF_STREAM || err == ERROR_UNSUPPORTED) {
    688         return presentationsJObj;
    689     } else if (err != OK) {
    690         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    691         return presentationsJObj;
    692     }
    693 
    694     JAudioPresentationInfo::addPresentations(
    695             env, gAudioPresentationFields, presentations, presentationsJObj);
    696     return presentationsJObj;
    697 }
    698 
    699 static void android_media_MediaExtractor_native_init(JNIEnv *env) {
    700     jclass clazz = env->FindClass("android/media/MediaExtractor");
    701     CHECK(clazz != NULL);
    702 
    703     gFields.context = env->GetFieldID(clazz, "mNativeContext", "J");
    704     CHECK(gFields.context != NULL);
    705 
    706     clazz = env->FindClass("android/media/MediaCodec$CryptoInfo");
    707     CHECK(clazz != NULL);
    708 
    709     gFields.cryptoInfoSetID =
    710         env->GetMethodID(clazz, "set", "(I[I[I[B[BI)V");
    711 
    712     gFields.cryptoInfoSetPatternID =
    713         env->GetMethodID(clazz, "setPattern", "(II)V");
    714 
    715     gAudioPresentationFields.init(env);
    716 }
    717 
    718 static void android_media_MediaExtractor_native_setup(
    719         JNIEnv *env, jobject thiz) {
    720     sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz);
    721     setMediaExtractor(env,thiz, extractor);
    722 }
    723 
    724 static void android_media_MediaExtractor_setDataSource(
    725         JNIEnv *env, jobject thiz,
    726         jobject httpServiceBinderObj,
    727         jstring pathObj,
    728         jobjectArray keysArray,
    729         jobjectArray valuesArray) {
    730     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    731 
    732     if (extractor == NULL) {
    733         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    734         return;
    735     }
    736 
    737     if (pathObj == NULL) {
    738         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    739         return;
    740     }
    741 
    742     KeyedVector<String8, String8> headers;
    743     if (!ConvertKeyValueArraysToKeyedVector(
    744                 env, keysArray, valuesArray, &headers)) {
    745         return;
    746     }
    747 
    748     const char *path = env->GetStringUTFChars(pathObj, NULL);
    749 
    750     if (path == NULL) {
    751         return;
    752     }
    753 
    754     sp<IMediaHTTPService> httpService;
    755     if (httpServiceBinderObj != NULL) {
    756         sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
    757         httpService = interface_cast<IMediaHTTPService>(binder);
    758     }
    759 
    760     status_t err = extractor->setDataSource(httpService, path, &headers);
    761 
    762     env->ReleaseStringUTFChars(pathObj, path);
    763     path = NULL;
    764 
    765     if (err != OK) {
    766         jniThrowException(
    767                 env,
    768                 "java/io/IOException",
    769                 "Failed to instantiate extractor.");
    770         return;
    771     }
    772 }
    773 
    774 static void android_media_MediaExtractor_setDataSourceFd(
    775         JNIEnv *env, jobject thiz,
    776         jobject fileDescObj, jlong offset, jlong length) {
    777     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    778 
    779     if (extractor == NULL) {
    780         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    781         return;
    782     }
    783 
    784     if (fileDescObj == NULL) {
    785         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    786         return;
    787     }
    788 
    789     int fd = jniGetFDFromFileDescriptor(env, fileDescObj);
    790 
    791     status_t err = extractor->setDataSource(fd, offset, length);
    792 
    793     if (err != OK) {
    794         jniThrowException(
    795                 env,
    796                 "java/io/IOException",
    797                 "Failed to instantiate extractor.");
    798         return;
    799     }
    800 }
    801 
    802 static void android_media_MediaExtractor_setDataSourceCallback(
    803         JNIEnv *env, jobject thiz,
    804         jobject callbackObj) {
    805     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    806 
    807     if (extractor == NULL) {
    808         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    809         return;
    810     }
    811 
    812     if (callbackObj == NULL) {
    813         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    814         return;
    815     }
    816 
    817     sp<DataSource> bridge =
    818         CreateDataSourceFromIDataSource(new JMediaDataSource(env, callbackObj));
    819     status_t err = extractor->setDataSource(bridge);
    820 
    821     if (err != OK) {
    822         // Clear bridge so that JMediaDataSource::close() is called _before_
    823         // we throw the IOException.
    824         // Otherwise close() gets called when we go out of scope, it calls
    825         // Java with a pending exception and crashes the process.
    826         bridge.clear();
    827         jniThrowException(
    828                 env,
    829                 "java/io/IOException",
    830                 "Failed to instantiate extractor.");
    831         return;
    832     }
    833 }
    834 
    835 static void android_media_MediaExtractor_setMediaCas(
    836         JNIEnv *env, jobject thiz, jobject casBinderObj) {
    837     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    838 
    839     if (extractor == NULL) {
    840         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    841         return;
    842     }
    843 
    844     status_t err = extractor->setMediaCas(env, casBinderObj);
    845 
    846     if (err != OK) {
    847         extractor.clear();
    848         jniThrowException(
    849                 env,
    850                 "java/lang/IllegalArgumentException",
    851                 "Failed to set MediaCas on extractor.");
    852     }
    853 }
    854 
    855 static jlong android_media_MediaExtractor_getCachedDurationUs(
    856         JNIEnv *env, jobject thiz) {
    857     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    858 
    859     if (extractor == NULL) {
    860         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    861         return -1LL;
    862     }
    863 
    864     int64_t cachedDurationUs;
    865     bool eos;
    866     if (!extractor->getCachedDuration(&cachedDurationUs, &eos)) {
    867         return -1LL;
    868     }
    869 
    870     return (jlong) cachedDurationUs;
    871 }
    872 
    873 static jboolean android_media_MediaExtractor_hasCacheReachedEOS(
    874         JNIEnv *env, jobject thiz) {
    875     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    876 
    877     if (extractor == NULL) {
    878         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    879         return JNI_TRUE;
    880     }
    881 
    882     int64_t cachedDurationUs;
    883     bool eos;
    884     if (!extractor->getCachedDuration(&cachedDurationUs, &eos)) {
    885         return JNI_TRUE;
    886     }
    887 
    888     return eos ? JNI_TRUE : JNI_FALSE;
    889 }
    890 
    891 static void android_media_MediaExtractor_native_finalize(
    892         JNIEnv *env, jobject thiz) {
    893     android_media_MediaExtractor_release(env, thiz);
    894 }
    895 
    896 static jobject
    897 android_media_MediaExtractor_native_getMetrics(JNIEnv * env, jobject thiz)
    898 {
    899     ALOGV("android_media_MediaExtractor_native_getMetrics");
    900 
    901     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
    902     if (extractor == NULL ) {
    903         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    904         return NULL;
    905     }
    906 
    907     // get what we have for the metrics from the codec
    908     Parcel reply;
    909     status_t err = extractor->getMetrics(&reply);
    910     if (err != OK) {
    911         ALOGE("getMetrics failed");
    912         return (jobject) NULL;
    913     }
    914 
    915     // build and return the Bundle
    916     std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create());
    917     item->readFromParcel(reply);
    918     jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item.get(), NULL);
    919 
    920     return mybundle;
    921 }
    922 
    923 
    924 static const JNINativeMethod gMethods[] = {
    925     { "release", "()V", (void *)android_media_MediaExtractor_release },
    926 
    927     { "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount },
    928 
    929     { "getFileFormatNative", "()Ljava/util/Map;",
    930         (void *)android_media_MediaExtractor_getFileFormatNative },
    931 
    932     { "getTrackFormatNative", "(I)Ljava/util/Map;",
    933         (void *)android_media_MediaExtractor_getTrackFormatNative },
    934 
    935     { "selectTrack", "(I)V", (void *)android_media_MediaExtractor_selectTrack },
    936 
    937     { "unselectTrack", "(I)V",
    938         (void *)android_media_MediaExtractor_unselectTrack },
    939 
    940     { "seekTo", "(JI)V", (void *)android_media_MediaExtractor_seekTo },
    941 
    942     { "advance", "()Z", (void *)android_media_MediaExtractor_advance },
    943 
    944     { "readSampleData", "(Ljava/nio/ByteBuffer;I)I",
    945         (void *)android_media_MediaExtractor_readSampleData },
    946 
    947     { "getSampleTrackIndex", "()I",
    948         (void *)android_media_MediaExtractor_getSampleTrackIndex },
    949 
    950     { "getSampleTime", "()J",
    951         (void *)android_media_MediaExtractor_getSampleTime },
    952 
    953     { "getSampleSize", "()J",
    954         (void *)android_media_MediaExtractor_getSampleSize },
    955 
    956     { "getSampleFlags", "()I",
    957         (void *)android_media_MediaExtractor_getSampleFlags },
    958 
    959     { "getSampleCryptoInfo", "(Landroid/media/MediaCodec$CryptoInfo;)Z",
    960         (void *)android_media_MediaExtractor_getSampleCryptoInfo },
    961 
    962     { "native_init", "()V", (void *)android_media_MediaExtractor_native_init },
    963 
    964     { "native_setup", "()V",
    965       (void *)android_media_MediaExtractor_native_setup },
    966 
    967     { "native_finalize", "()V",
    968       (void *)android_media_MediaExtractor_native_finalize },
    969 
    970     { "nativeSetDataSource",
    971         "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
    972         "[Ljava/lang/String;)V",
    973       (void *)android_media_MediaExtractor_setDataSource },
    974 
    975     { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
    976       (void *)android_media_MediaExtractor_setDataSourceFd },
    977 
    978     { "setDataSource", "(Landroid/media/MediaDataSource;)V",
    979       (void *)android_media_MediaExtractor_setDataSourceCallback },
    980 
    981     { "nativeSetMediaCas", "(Landroid/os/IHwBinder;)V",
    982       (void *)android_media_MediaExtractor_setMediaCas },
    983 
    984     { "getCachedDuration", "()J",
    985       (void *)android_media_MediaExtractor_getCachedDurationUs },
    986 
    987     { "hasCacheReachedEndOfStream", "()Z",
    988       (void *)android_media_MediaExtractor_hasCacheReachedEOS },
    989 
    990     {"native_getMetrics",          "()Landroid/os/PersistableBundle;",
    991       (void *)android_media_MediaExtractor_native_getMetrics},
    992 
    993     { "native_getAudioPresentations", "(I)Ljava/util/List;",
    994       (void *)android_media_MediaExtractor_getAudioPresentations },
    995 };
    996 
    997 int register_android_media_MediaExtractor(JNIEnv *env) {
    998     return AndroidRuntime::registerNativeMethods(env,
    999                 "android/media/MediaExtractor", gMethods, NELEM(gMethods));
   1000 }
   1001