Home | History | Annotate | Download | only in libstagefright
      1 /*
      2  * Copyright (C) 2009 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 "AMRExtractor"
     19 #include <utils/Log.h>
     20 
     21 #include "include/AMRExtractor.h"
     22 
     23 #include <media/stagefright/foundation/ADebug.h>
     24 #include <media/stagefright/DataSource.h>
     25 #include <media/stagefright/MediaBufferGroup.h>
     26 #include <media/stagefright/MediaDefs.h>
     27 #include <media/stagefright/MediaErrors.h>
     28 #include <media/stagefright/MediaSource.h>
     29 #include <media/stagefright/MetaData.h>
     30 #include <utils/String8.h>
     31 
     32 namespace android {
     33 
     34 class AMRSource : public MediaSource {
     35 public:
     36     AMRSource(const sp<DataSource> &source,
     37               const sp<MetaData> &meta,
     38               bool isWide,
     39               const off64_t *offset_table,
     40               size_t offset_table_length);
     41 
     42     virtual status_t start(MetaData *params = NULL);
     43     virtual status_t stop();
     44 
     45     virtual sp<MetaData> getFormat();
     46 
     47     virtual status_t read(
     48             MediaBuffer **buffer, const ReadOptions *options = NULL);
     49 
     50 protected:
     51     virtual ~AMRSource();
     52 
     53 private:
     54     sp<DataSource> mDataSource;
     55     sp<MetaData> mMeta;
     56     bool mIsWide;
     57 
     58     off64_t mOffset;
     59     int64_t mCurrentTimeUs;
     60     bool mStarted;
     61     MediaBufferGroup *mGroup;
     62 
     63     off64_t mOffsetTable[OFFSET_TABLE_LEN];
     64     size_t mOffsetTableLength;
     65 
     66     AMRSource(const AMRSource &);
     67     AMRSource &operator=(const AMRSource &);
     68 };
     69 
     70 ////////////////////////////////////////////////////////////////////////////////
     71 
     72 static size_t getFrameSize(bool isWide, unsigned FT) {
     73     static const size_t kFrameSizeNB[16] = {
     74         95, 103, 118, 134, 148, 159, 204, 244,
     75         39, 43, 38, 37, // SID
     76         0, 0, 0, // future use
     77         0 // no data
     78     };
     79     static const size_t kFrameSizeWB[16] = {
     80         132, 177, 253, 285, 317, 365, 397, 461, 477,
     81         40, // SID
     82         0, 0, 0, 0, // future use
     83         0, // speech lost
     84         0 // no data
     85     };
     86 
     87     if (FT > 15 || (isWide && FT > 9 && FT < 14) || (!isWide && FT > 11 && FT < 15)) {
     88         ALOGE("illegal AMR frame type %d", FT);
     89         return 0;
     90     }
     91 
     92     size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT];
     93 
     94     // Round up bits to bytes and add 1 for the header byte.
     95     frameSize = (frameSize + 7) / 8 + 1;
     96 
     97     return frameSize;
     98 }
     99 
    100 static status_t getFrameSizeByOffset(const sp<DataSource> &source,
    101         off64_t offset, bool isWide, size_t *frameSize) {
    102     uint8_t header;
    103     ssize_t count = source->readAt(offset, &header, 1);
    104     if (count == 0) {
    105         return ERROR_END_OF_STREAM;
    106     } else if (count < 0) {
    107         return ERROR_IO;
    108     }
    109 
    110     unsigned FT = (header >> 3) & 0x0f;
    111 
    112     *frameSize = getFrameSize(isWide, FT);
    113     if (*frameSize == 0) {
    114         return ERROR_MALFORMED;
    115     }
    116     return OK;
    117 }
    118 
    119 AMRExtractor::AMRExtractor(const sp<DataSource> &source)
    120     : mDataSource(source),
    121       mInitCheck(NO_INIT),
    122       mOffsetTableLength(0) {
    123     String8 mimeType;
    124     float confidence;
    125     if (!SniffAMR(mDataSource, &mimeType, &confidence, NULL)) {
    126         return;
    127     }
    128 
    129     mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB);
    130 
    131     mMeta = new MetaData;
    132     mMeta->setCString(
    133             kKeyMIMEType, mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB
    134                                   : MEDIA_MIMETYPE_AUDIO_AMR_NB);
    135 
    136     mMeta->setInt32(kKeyChannelCount, 1);
    137     mMeta->setInt32(kKeySampleRate, mIsWide ? 16000 : 8000);
    138 
    139     off64_t offset = mIsWide ? 9 : 6;
    140     off64_t streamSize;
    141     size_t frameSize, numFrames = 0;
    142     int64_t duration = 0;
    143 
    144     if (mDataSource->getSize(&streamSize) == OK) {
    145          while (offset < streamSize) {
    146              status_t status = getFrameSizeByOffset(source, offset, mIsWide, &frameSize);
    147              if (status == ERROR_END_OF_STREAM) {
    148                  break;
    149              } else if (status != OK) {
    150                 return;
    151             }
    152 
    153             if ((numFrames % 50 == 0) && (numFrames / 50 < OFFSET_TABLE_LEN)) {
    154                 CHECK_EQ(mOffsetTableLength, numFrames / 50);
    155                 mOffsetTable[mOffsetTableLength] = offset - (mIsWide ? 9: 6);
    156                 mOffsetTableLength ++;
    157             }
    158 
    159             offset += frameSize;
    160             duration += 20000;  // Each frame is 20ms
    161             numFrames ++;
    162         }
    163 
    164         mMeta->setInt64(kKeyDuration, duration);
    165     }
    166 
    167     mInitCheck = OK;
    168 }
    169 
    170 AMRExtractor::~AMRExtractor() {
    171 }
    172 
    173 sp<MetaData> AMRExtractor::getMetaData() {
    174     sp<MetaData> meta = new MetaData;
    175 
    176     if (mInitCheck != OK) {
    177         return meta;
    178     }
    179 
    180     meta->setCString(kKeyMIMEType, mIsWide ? "audio/amr-wb" : "audio/amr");
    181 
    182     return meta;
    183 }
    184 
    185 size_t AMRExtractor::countTracks() {
    186     return mInitCheck == OK ? 1 : 0;
    187 }
    188 
    189 sp<IMediaSource> AMRExtractor::getTrack(size_t index) {
    190     if (mInitCheck != OK || index != 0) {
    191         return NULL;
    192     }
    193 
    194     return new AMRSource(mDataSource, mMeta, mIsWide,
    195             mOffsetTable, mOffsetTableLength);
    196 }
    197 
    198 sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t /* flags */) {
    199     if (mInitCheck != OK || index != 0) {
    200         return NULL;
    201     }
    202 
    203     return mMeta;
    204 }
    205 
    206 ////////////////////////////////////////////////////////////////////////////////
    207 
    208 AMRSource::AMRSource(
    209         const sp<DataSource> &source, const sp<MetaData> &meta,
    210         bool isWide, const off64_t *offset_table, size_t offset_table_length)
    211     : mDataSource(source),
    212       mMeta(meta),
    213       mIsWide(isWide),
    214       mOffset(mIsWide ? 9 : 6),
    215       mCurrentTimeUs(0),
    216       mStarted(false),
    217       mGroup(NULL),
    218       mOffsetTableLength(offset_table_length) {
    219     if (mOffsetTableLength > 0 && mOffsetTableLength <= OFFSET_TABLE_LEN) {
    220         memcpy ((char*)mOffsetTable, (char*)offset_table, sizeof(off64_t) * mOffsetTableLength);
    221     }
    222 }
    223 
    224 AMRSource::~AMRSource() {
    225     if (mStarted) {
    226         stop();
    227     }
    228 }
    229 
    230 status_t AMRSource::start(MetaData * /* params */) {
    231     CHECK(!mStarted);
    232 
    233     mOffset = mIsWide ? 9 : 6;
    234     mCurrentTimeUs = 0;
    235     mGroup = new MediaBufferGroup;
    236     mGroup->add_buffer(new MediaBuffer(128));
    237     mStarted = true;
    238 
    239     return OK;
    240 }
    241 
    242 status_t AMRSource::stop() {
    243     CHECK(mStarted);
    244 
    245     delete mGroup;
    246     mGroup = NULL;
    247 
    248     mStarted = false;
    249     return OK;
    250 }
    251 
    252 sp<MetaData> AMRSource::getFormat() {
    253     return mMeta;
    254 }
    255 
    256 status_t AMRSource::read(
    257         MediaBuffer **out, const ReadOptions *options) {
    258     *out = NULL;
    259 
    260     int64_t seekTimeUs;
    261     ReadOptions::SeekMode mode;
    262     if (mOffsetTableLength > 0 && options && options->getSeekTo(&seekTimeUs, &mode)) {
    263         size_t size;
    264         int64_t seekFrame = seekTimeUs / 20000ll;  // 20ms per frame.
    265         mCurrentTimeUs = seekFrame * 20000ll;
    266 
    267         size_t index = seekFrame < 0 ? 0 : seekFrame / 50;
    268         if (index >= mOffsetTableLength) {
    269             index = mOffsetTableLength - 1;
    270         }
    271 
    272         mOffset = mOffsetTable[index] + (mIsWide ? 9 : 6);
    273 
    274         for (size_t i = 0; i< seekFrame - index * 50; i++) {
    275             status_t err;
    276             if ((err = getFrameSizeByOffset(mDataSource, mOffset,
    277                             mIsWide, &size)) != OK) {
    278                 return err;
    279             }
    280             mOffset += size;
    281         }
    282     }
    283 
    284     uint8_t header;
    285     ssize_t n = mDataSource->readAt(mOffset, &header, 1);
    286 
    287     if (n < 1) {
    288         return ERROR_END_OF_STREAM;
    289     }
    290 
    291     if (header & 0x83) {
    292         // Padding bits must be 0.
    293 
    294         ALOGE("padding bits must be 0, header is 0x%02x", header);
    295 
    296         return ERROR_MALFORMED;
    297     }
    298 
    299     unsigned FT = (header >> 3) & 0x0f;
    300 
    301     size_t frameSize = getFrameSize(mIsWide, FT);
    302     if (frameSize == 0) {
    303         return ERROR_MALFORMED;
    304     }
    305 
    306     MediaBuffer *buffer;
    307     status_t err = mGroup->acquire_buffer(&buffer);
    308     if (err != OK) {
    309         return err;
    310     }
    311 
    312     n = mDataSource->readAt(mOffset, buffer->data(), frameSize);
    313 
    314     if (n != (ssize_t)frameSize) {
    315         buffer->release();
    316         buffer = NULL;
    317 
    318         if (n < 0) {
    319             return ERROR_IO;
    320         } else {
    321             // only partial frame is available, treat it as EOS.
    322             mOffset += n;
    323             return ERROR_END_OF_STREAM;
    324         }
    325     }
    326 
    327     buffer->set_range(0, frameSize);
    328     buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
    329     buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
    330 
    331     mOffset += frameSize;
    332     mCurrentTimeUs += 20000;  // Each frame is 20ms
    333 
    334     *out = buffer;
    335 
    336     return OK;
    337 }
    338 
    339 ////////////////////////////////////////////////////////////////////////////////
    340 
    341 bool SniffAMR(
    342         const sp<DataSource> &source, String8 *mimeType, float *confidence,
    343         sp<AMessage> *) {
    344     char header[9];
    345 
    346     if (source->readAt(0, header, sizeof(header)) != sizeof(header)) {
    347         return false;
    348     }
    349 
    350     if (!memcmp(header, "#!AMR\n", 6)) {
    351         *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB;
    352         *confidence = 0.5;
    353 
    354         return true;
    355     } else if (!memcmp(header, "#!AMR-WB\n", 9)) {
    356         *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB;
    357         *confidence = 0.5;
    358 
    359         return true;
    360     }
    361 
    362     return false;
    363 }
    364 
    365 }  // namespace android
    366