Home | History | Annotate | Download | only in ndk
      1 /*
      2  * Copyright (C) 2014 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 "NdkMediaExtractor"
     19 
     20 
     21 #include <media/NdkMediaError.h>
     22 #include <media/NdkMediaExtractor.h>
     23 #include "NdkMediaDataSourcePriv.h"
     24 #include "NdkMediaFormatPriv.h"
     25 
     26 
     27 #include <inttypes.h>
     28 #include <utils/Log.h>
     29 #include <utils/StrongPointer.h>
     30 #include <media/hardware/CryptoAPI.h>
     31 #include <media/stagefright/foundation/ABuffer.h>
     32 #include <media/stagefright/foundation/AMessage.h>
     33 #include <media/stagefright/MetaData.h>
     34 #include <media/stagefright/NuMediaExtractor.h>
     35 #include <media/IMediaHTTPService.h>
     36 #include <android_runtime/AndroidRuntime.h>
     37 #include <android_util_Binder.h>
     38 
     39 #include <jni.h>
     40 
     41 using namespace android;
     42 
     43 static media_status_t translate_error(status_t err) {
     44     if (err == OK) {
     45         return AMEDIA_OK;
     46     } else if (err == ERROR_END_OF_STREAM) {
     47         return AMEDIA_ERROR_END_OF_STREAM;
     48     } else if (err == ERROR_IO) {
     49         return AMEDIA_ERROR_IO;
     50     }
     51 
     52     ALOGE("sf error code: %d", err);
     53     return AMEDIA_ERROR_UNKNOWN;
     54 }
     55 
     56 struct AMediaExtractor {
     57     sp<NuMediaExtractor> mImpl;
     58     sp<ABuffer> mPsshBuf;
     59 };
     60 
     61 extern "C" {
     62 
     63 EXPORT
     64 AMediaExtractor* AMediaExtractor_new() {
     65     ALOGV("ctor");
     66     AMediaExtractor *mData = new AMediaExtractor();
     67     mData->mImpl = new NuMediaExtractor();
     68     return mData;
     69 }
     70 
     71 EXPORT
     72 media_status_t AMediaExtractor_delete(AMediaExtractor *mData) {
     73     ALOGV("dtor");
     74     delete mData;
     75     return AMEDIA_OK;
     76 }
     77 
     78 EXPORT
     79 media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset,
     80         off64_t length) {
     81     ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
     82     return translate_error(mData->mImpl->setDataSource(fd, offset, length));
     83 }
     84 
     85 EXPORT
     86 media_status_t AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) {
     87     ALOGV("setDataSource(%s)", location);
     88     // TODO: add header support
     89 
     90     JNIEnv *env = AndroidRuntime::getJNIEnv();
     91     jobject service = NULL;
     92     if (env == NULL) {
     93         ALOGE("setDataSource(path) must be called from Java thread");
     94         return AMEDIA_ERROR_UNSUPPORTED;
     95     }
     96 
     97     jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService");
     98     if (mediahttpclass == NULL) {
     99         ALOGE("can't find MediaHttpService");
    100         env->ExceptionClear();
    101         return AMEDIA_ERROR_UNSUPPORTED;
    102     }
    103 
    104     jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass,
    105             "createHttpServiceBinderIfNecessary", "(Ljava/lang/String;)Landroid/os/IBinder;");
    106     if (mediaHttpCreateMethod == NULL) {
    107         ALOGE("can't find method");
    108         env->ExceptionClear();
    109         return AMEDIA_ERROR_UNSUPPORTED;
    110     }
    111 
    112     jstring jloc = env->NewStringUTF(location);
    113 
    114     service = env->CallStaticObjectMethod(mediahttpclass, mediaHttpCreateMethod, jloc);
    115     env->DeleteLocalRef(jloc);
    116 
    117     sp<IMediaHTTPService> httpService;
    118     if (service != NULL) {
    119         sp<IBinder> binder = ibinderForJavaObject(env, service);
    120         httpService = interface_cast<IMediaHTTPService>(binder);
    121     }
    122 
    123     status_t err = mData->mImpl->setDataSource(httpService, location, NULL);
    124     env->ExceptionClear();
    125     return translate_error(err);
    126 }
    127 
    128 EXPORT
    129 media_status_t AMediaExtractor_setDataSourceCustom(AMediaExtractor* mData, AMediaDataSource *src) {
    130     return translate_error(mData->mImpl->setDataSource(new NdkDataSource(src)));
    131 }
    132 
    133 EXPORT
    134 AMediaFormat* AMediaExtractor_getFileFormat(AMediaExtractor *mData) {
    135     sp<AMessage> format;
    136     mData->mImpl->getFileFormat(&format);
    137     return AMediaFormat_fromMsg(&format);
    138 }
    139 
    140 EXPORT
    141 size_t AMediaExtractor_getTrackCount(AMediaExtractor *mData) {
    142     return mData->mImpl->countTracks();
    143 }
    144 
    145 EXPORT
    146 AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor *mData, size_t idx) {
    147     sp<AMessage> format;
    148     mData->mImpl->getTrackFormat(idx, &format);
    149     return AMediaFormat_fromMsg(&format);
    150 }
    151 
    152 EXPORT
    153 media_status_t AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) {
    154     ALOGV("selectTrack(%zu)", idx);
    155     return translate_error(mData->mImpl->selectTrack(idx));
    156 }
    157 
    158 EXPORT
    159 media_status_t AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) {
    160     ALOGV("unselectTrack(%zu)", idx);
    161     return translate_error(mData->mImpl->unselectTrack(idx));
    162 }
    163 
    164 EXPORT
    165 bool AMediaExtractor_advance(AMediaExtractor *mData) {
    166     //ALOGV("advance");
    167     status_t err = mData->mImpl->advance();
    168     if (err == ERROR_END_OF_STREAM) {
    169         return false;
    170     } else if (err != OK) {
    171         ALOGE("sf error code: %d", err);
    172         return false;
    173     }
    174     return true;
    175 }
    176 
    177 EXPORT
    178 media_status_t AMediaExtractor_seekTo(AMediaExtractor *ex, int64_t seekPosUs, SeekMode mode) {
    179     android::MediaSource::ReadOptions::SeekMode sfmode;
    180     if (mode == AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC) {
    181         sfmode = android::MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC;
    182     } else if (mode == AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC) {
    183         sfmode = android::MediaSource::ReadOptions::SEEK_CLOSEST_SYNC;
    184     } else {
    185         sfmode = android::MediaSource::ReadOptions::SEEK_NEXT_SYNC;
    186     }
    187 
    188     return translate_error(ex->mImpl->seekTo(seekPosUs, sfmode));
    189 }
    190 
    191 EXPORT
    192 ssize_t AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) {
    193     //ALOGV("readSampleData");
    194     sp<ABuffer> tmp = new ABuffer(buffer, capacity);
    195     if (mData->mImpl->readSampleData(tmp) == OK) {
    196         return tmp->size();
    197     }
    198     return -1;
    199 }
    200 
    201 EXPORT
    202 ssize_t AMediaExtractor_getSampleSize(AMediaExtractor *mData) {
    203     size_t sampleSize;
    204     status_t err = mData->mImpl->getSampleSize(&sampleSize);
    205     if (err != OK) {
    206         return -1;
    207     }
    208     return sampleSize;
    209 }
    210 
    211 EXPORT
    212 uint32_t AMediaExtractor_getSampleFlags(AMediaExtractor *mData) {
    213     int sampleFlags = 0;
    214     sp<MetaData> meta;
    215     status_t err = mData->mImpl->getSampleMeta(&meta);
    216     if (err != OK) {
    217         return -1;
    218     }
    219     int32_t val;
    220     if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
    221         sampleFlags |= AMEDIAEXTRACTOR_SAMPLE_FLAG_SYNC;
    222     }
    223 
    224     uint32_t type;
    225     const void *data;
    226     size_t size;
    227     if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
    228         sampleFlags |= AMEDIAEXTRACTOR_SAMPLE_FLAG_ENCRYPTED;
    229     }
    230     return sampleFlags;
    231 }
    232 
    233 EXPORT
    234 int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) {
    235     size_t idx;
    236     if (mData->mImpl->getSampleTrackIndex(&idx) != OK) {
    237         return -1;
    238     }
    239     return idx;
    240 }
    241 
    242 EXPORT
    243 int64_t AMediaExtractor_getSampleTime(AMediaExtractor *mData) {
    244     int64_t time;
    245     if (mData->mImpl->getSampleTime(&time) != OK) {
    246         return -1;
    247     }
    248     return time;
    249 }
    250 
    251 EXPORT
    252 PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor *ex) {
    253 
    254     if (ex->mPsshBuf != NULL) {
    255         return (PsshInfo*) ex->mPsshBuf->data();
    256     }
    257 
    258     sp<AMessage> format;
    259     ex->mImpl->getFileFormat(&format);
    260     sp<ABuffer> buffer;
    261     if(!format->findBuffer("pssh", &buffer)) {
    262         return NULL;
    263     }
    264 
    265     // the format of the buffer is 1 or more of:
    266     //    {
    267     //        16 byte uuid
    268     //        4 byte data length N
    269     //        N bytes of data
    270     //    }
    271 
    272     // Determine the number of entries in the source data.
    273     // Since we got the data from stagefright, we trust it is valid and properly formatted.
    274     const uint8_t* data = buffer->data();
    275     size_t len = buffer->size();
    276     size_t numentries = 0;
    277     while (len > 0) {
    278         numentries++;
    279 
    280         if (len < 16) {
    281             ALOGE("invalid PSSH data");
    282             return NULL;
    283         }
    284         // skip uuid
    285         data += 16;
    286         len -= 16;
    287 
    288         // get data length
    289         if (len < 4) {
    290             ALOGE("invalid PSSH data");
    291             return NULL;
    292         }
    293         uint32_t datalen = *((uint32_t*)data);
    294         data += 4;
    295         len -= 4;
    296 
    297         if (len < datalen) {
    298             ALOGE("invalid PSSH data");
    299             return NULL;
    300         }
    301         // skip the data
    302         data += datalen;
    303         len -= datalen;
    304     }
    305 
    306     // there are <numentries> in the source buffer, we need
    307     // (source buffer size) - (sizeof(uint32_t) * numentries) + sizeof(size_t)
    308     //  + ((sizeof(void*) + sizeof(size_t)) * numentries) bytes for the PsshInfo structure
    309     // Or in other words, the data lengths in the source structure are replaced by size_t
    310     // (which may be the same size or larger, for 64 bit), and in addition there is an
    311     // extra pointer for each entry, and an extra size_t for the entire PsshInfo.
    312     size_t newsize = buffer->size() - (sizeof(uint32_t) * numentries) + sizeof(size_t)
    313             + ((sizeof(void*) + sizeof(size_t)) * numentries);
    314     if (newsize <= buffer->size()) {
    315         ALOGE("invalid PSSH data");
    316         return NULL;
    317     }
    318     ex->mPsshBuf = new ABuffer(newsize);
    319     ex->mPsshBuf->setRange(0, newsize);
    320 
    321     // copy data
    322     const uint8_t* src = buffer->data();
    323     uint8_t* dst = ex->mPsshBuf->data();
    324     uint8_t* dstdata = dst + sizeof(size_t) + numentries * sizeof(PsshEntry);
    325     *((size_t*)dst) = numentries;
    326     dst += sizeof(size_t);
    327     for (size_t i = 0; i < numentries; i++) {
    328         // copy uuid
    329         memcpy(dst, src, 16);
    330         src += 16;
    331         dst += 16;
    332 
    333         // get/copy data length
    334         uint32_t datalen = *((uint32_t*)src);
    335         *((size_t*)dst) = datalen;
    336         src += sizeof(uint32_t);
    337         dst += sizeof(size_t);
    338 
    339         // the next entry in the destination is a pointer to the actual data, which we store
    340         // after the array of PsshEntry
    341         *((void**)dst) = dstdata;
    342         dst += sizeof(void*);
    343 
    344         // copy the actual data
    345         memcpy(dstdata, src, datalen);
    346         dstdata += datalen;
    347         src += datalen;
    348     }
    349 
    350     return (PsshInfo*) ex->mPsshBuf->data();
    351 }
    352 
    353 EXPORT
    354 AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex) {
    355     sp<MetaData> meta;
    356     if(ex->mImpl->getSampleMeta(&meta) != 0) {
    357         return NULL;
    358     }
    359 
    360     uint32_t type;
    361     const void *crypteddata;
    362     size_t cryptedsize;
    363     if (!meta->findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) {
    364         return NULL;
    365     }
    366     size_t numSubSamples = cryptedsize / sizeof(size_t);
    367 
    368     const void *cleardata;
    369     size_t clearsize;
    370     if (meta->findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) {
    371         if (clearsize != cryptedsize) {
    372             // The two must be of the same length.
    373             return NULL;
    374         }
    375     }
    376 
    377     const void *key;
    378     size_t keysize;
    379     if (meta->findData(kKeyCryptoKey, &type, &key, &keysize)) {
    380         if (keysize != 16) {
    381             // Keys must be 16 bytes in length.
    382             return NULL;
    383         }
    384     }
    385 
    386     const void *iv;
    387     size_t ivsize;
    388     if (meta->findData(kKeyCryptoIV, &type, &iv, &ivsize)) {
    389         if (ivsize != 16) {
    390             // IVs must be 16 bytes in length.
    391             return NULL;
    392         }
    393     }
    394 
    395     int32_t mode;
    396     if (!meta->findInt32(kKeyCryptoMode, &mode)) {
    397         mode = CryptoPlugin::kMode_AES_CTR;
    398     }
    399 
    400     return AMediaCodecCryptoInfo_new(
    401             numSubSamples,
    402             (uint8_t*) key,
    403             (uint8_t*) iv,
    404             (cryptoinfo_mode_t) mode,
    405             (size_t*) cleardata,
    406             (size_t*) crypteddata);
    407 }
    408 
    409 EXPORT
    410 int64_t AMediaExtractor_getCachedDuration(AMediaExtractor *ex) {
    411     bool eos;
    412     int64_t durationUs;
    413     if (ex->mImpl->getCachedDuration(&durationUs, &eos)) {
    414         return durationUs;
    415     }
    416     return -1;
    417 }
    418 
    419 EXPORT
    420 media_status_t AMediaExtractor_getSampleFormat(AMediaExtractor *ex, AMediaFormat *fmt) {
    421     if (fmt == NULL) {
    422         return AMEDIA_ERROR_INVALID_PARAMETER;
    423     }
    424 
    425     sp<MetaData> sampleMeta;
    426     status_t err = ex->mImpl->getSampleMeta(&sampleMeta);
    427     if (err != OK) {
    428         return translate_error(err);
    429     }
    430 
    431     sp<AMessage> meta;
    432     AMediaFormat_getFormat(fmt, &meta);
    433     meta->clear();
    434 
    435     int32_t layerId;
    436     if (sampleMeta->findInt32(kKeyTemporalLayerId, &layerId)) {
    437         meta->setInt32(AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID, layerId);
    438     }
    439 
    440     size_t trackIndex;
    441     err = ex->mImpl->getSampleTrackIndex(&trackIndex);
    442     if (err == OK) {
    443         meta->setInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, trackIndex);
    444         sp<AMessage> trackFormat;
    445         AString mime;
    446         err = ex->mImpl->getTrackFormat(trackIndex, &trackFormat);
    447         if (err == OK
    448                 && trackFormat != NULL
    449                 && trackFormat->findString(AMEDIAFORMAT_KEY_MIME, &mime)) {
    450             meta->setString(AMEDIAFORMAT_KEY_MIME, mime);
    451         }
    452     }
    453 
    454     int64_t durationUs;
    455     if (sampleMeta->findInt64(kKeyDuration, &durationUs)) {
    456         meta->setInt64(AMEDIAFORMAT_KEY_DURATION, durationUs);
    457     }
    458 
    459     uint32_t dataType; // unused
    460     const void *seiData;
    461     size_t seiLength;
    462     if (sampleMeta->findData(kKeySEI, &dataType, &seiData, &seiLength)) {
    463         sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);;
    464         meta->setBuffer(AMEDIAFORMAT_KEY_SEI, sei);
    465     }
    466 
    467     const void *mpegUserDataPointer;
    468     size_t mpegUserDataLength;
    469     if (sampleMeta->findData(
    470             kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) {
    471         sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength);
    472         meta->setBuffer(AMEDIAFORMAT_KEY_MPEG_USER_DATA, mpegUserData);
    473     }
    474 
    475     return AMEDIA_OK;
    476 }
    477 
    478 EXPORT
    479 media_status_t AMediaExtractor_disconnect(AMediaExtractor * ex) {
    480     ex->mImpl->disconnect();
    481     return AMEDIA_OK;
    482 }
    483 
    484 } // extern "C"
    485 
    486