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