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/DataSource.h>
     24 #include <media/stagefright/MediaBufferGroup.h>
     25 #include <media/stagefright/MediaDebug.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               size_t frameSize,
     39               bool isWide);
     40 
     41     virtual status_t start(MetaData *params = NULL);
     42     virtual status_t stop();
     43 
     44     virtual sp<MetaData> getFormat();
     45 
     46     virtual status_t read(
     47             MediaBuffer **buffer, const ReadOptions *options = NULL);
     48 
     49 protected:
     50     virtual ~AMRSource();
     51 
     52 private:
     53     sp<DataSource> mDataSource;
     54     sp<MetaData> mMeta;
     55     size_t mFrameSize;
     56     bool mIsWide;
     57 
     58     off_t mOffset;
     59     int64_t mCurrentTimeUs;
     60     bool mStarted;
     61     MediaBufferGroup *mGroup;
     62 
     63     AMRSource(const AMRSource &);
     64     AMRSource &operator=(const AMRSource &);
     65 };
     66 
     67 ////////////////////////////////////////////////////////////////////////////////
     68 
     69 static size_t getFrameSize(bool isWide, unsigned FT) {
     70     static const size_t kFrameSizeNB[8] = {
     71         95, 103, 118, 134, 148, 159, 204, 244
     72     };
     73     static const size_t kFrameSizeWB[9] = {
     74         132, 177, 253, 285, 317, 365, 397, 461, 477
     75     };
     76 
     77     size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT];
     78 
     79     // Round up bits to bytes and add 1 for the header byte.
     80     frameSize = (frameSize + 7) / 8 + 1;
     81 
     82     return frameSize;
     83 }
     84 
     85 AMRExtractor::AMRExtractor(const sp<DataSource> &source)
     86     : mDataSource(source),
     87       mInitCheck(NO_INIT) {
     88     String8 mimeType;
     89     float confidence;
     90     if (!SniffAMR(mDataSource, &mimeType, &confidence)) {
     91         return;
     92     }
     93 
     94     mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB);
     95 
     96     mMeta = new MetaData;
     97     mMeta->setCString(
     98             kKeyMIMEType, mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB
     99                                   : MEDIA_MIMETYPE_AUDIO_AMR_NB);
    100 
    101     mMeta->setInt32(kKeyChannelCount, 1);
    102     mMeta->setInt32(kKeySampleRate, mIsWide ? 16000 : 8000);
    103 
    104     size_t offset = mIsWide ? 9 : 6;
    105     uint8_t header;
    106     if (mDataSource->readAt(offset, &header, 1) != 1) {
    107         return;
    108     }
    109 
    110     unsigned FT = (header >> 3) & 0x0f;
    111 
    112     if (FT > 8 || (!mIsWide && FT > 7)) {
    113         return;
    114     }
    115 
    116     mFrameSize = getFrameSize(mIsWide, FT);
    117 
    118     off_t streamSize;
    119     if (mDataSource->getSize(&streamSize) == OK) {
    120         off_t numFrames = streamSize / mFrameSize;
    121 
    122         mMeta->setInt64(kKeyDuration, 20000ll * numFrames);
    123     }
    124 
    125     mInitCheck = OK;
    126 }
    127 
    128 AMRExtractor::~AMRExtractor() {
    129 }
    130 
    131 sp<MetaData> AMRExtractor::getMetaData() {
    132     sp<MetaData> meta = new MetaData;
    133 
    134     if (mInitCheck != OK) {
    135         return meta;
    136     }
    137 
    138     meta->setCString(kKeyMIMEType, mIsWide ? "audio/amr-wb" : "audio/amr");
    139 
    140     return meta;
    141 }
    142 
    143 size_t AMRExtractor::countTracks() {
    144     return mInitCheck == OK ? 1 : 0;
    145 }
    146 
    147 sp<MediaSource> AMRExtractor::getTrack(size_t index) {
    148     if (mInitCheck != OK || index != 0) {
    149         return NULL;
    150     }
    151 
    152     return new AMRSource(mDataSource, mMeta, mFrameSize, mIsWide);
    153 }
    154 
    155 sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
    156     if (mInitCheck != OK || index != 0) {
    157         return NULL;
    158     }
    159 
    160     return mMeta;
    161 }
    162 
    163 ////////////////////////////////////////////////////////////////////////////////
    164 
    165 AMRSource::AMRSource(
    166         const sp<DataSource> &source, const sp<MetaData> &meta,
    167         size_t frameSize, bool isWide)
    168     : mDataSource(source),
    169       mMeta(meta),
    170       mFrameSize(frameSize),
    171       mIsWide(isWide),
    172       mOffset(mIsWide ? 9 : 6),
    173       mCurrentTimeUs(0),
    174       mStarted(false),
    175       mGroup(NULL) {
    176 }
    177 
    178 AMRSource::~AMRSource() {
    179     if (mStarted) {
    180         stop();
    181     }
    182 }
    183 
    184 status_t AMRSource::start(MetaData *params) {
    185     CHECK(!mStarted);
    186 
    187     mOffset = mIsWide ? 9 : 6;
    188     mCurrentTimeUs = 0;
    189     mGroup = new MediaBufferGroup;
    190     mGroup->add_buffer(new MediaBuffer(128));
    191     mStarted = true;
    192 
    193     return OK;
    194 }
    195 
    196 status_t AMRSource::stop() {
    197     CHECK(mStarted);
    198 
    199     delete mGroup;
    200     mGroup = NULL;
    201 
    202     mStarted = false;
    203     return OK;
    204 }
    205 
    206 sp<MetaData> AMRSource::getFormat() {
    207     return mMeta;
    208 }
    209 
    210 status_t AMRSource::read(
    211         MediaBuffer **out, const ReadOptions *options) {
    212     *out = NULL;
    213 
    214     int64_t seekTimeUs;
    215     if (options && options->getSeekTo(&seekTimeUs)) {
    216         int64_t seekFrame = seekTimeUs / 20000ll;  // 20ms per frame.
    217         mCurrentTimeUs = seekFrame * 20000ll;
    218         mOffset = seekFrame * mFrameSize + (mIsWide ? 9 : 6);
    219     }
    220 
    221     uint8_t header;
    222     ssize_t n = mDataSource->readAt(mOffset, &header, 1);
    223 
    224     if (n < 1) {
    225         return ERROR_END_OF_STREAM;
    226     }
    227 
    228     if (header & 0x83) {
    229         // Padding bits must be 0.
    230 
    231         LOGE("padding bits must be 0, header is 0x%02x", header);
    232 
    233         return ERROR_MALFORMED;
    234     }
    235 
    236     unsigned FT = (header >> 3) & 0x0f;
    237 
    238     if (FT > 8 || (!mIsWide && FT > 7)) {
    239 
    240         LOGE("illegal AMR frame type %d", FT);
    241 
    242         return ERROR_MALFORMED;
    243     }
    244 
    245     size_t frameSize = getFrameSize(mIsWide, FT);
    246     CHECK_EQ(frameSize, mFrameSize);
    247 
    248     MediaBuffer *buffer;
    249     status_t err = mGroup->acquire_buffer(&buffer);
    250     if (err != OK) {
    251         return err;
    252     }
    253 
    254     n = mDataSource->readAt(mOffset, buffer->data(), frameSize);
    255 
    256     if (n != (ssize_t)frameSize) {
    257         buffer->release();
    258         buffer = NULL;
    259 
    260         return ERROR_IO;
    261     }
    262 
    263     buffer->set_range(0, frameSize);
    264     buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
    265 
    266     mOffset += frameSize;
    267     mCurrentTimeUs += 20000;  // Each frame is 20ms
    268 
    269     *out = buffer;
    270 
    271     return OK;
    272 }
    273 
    274 ////////////////////////////////////////////////////////////////////////////////
    275 
    276 bool SniffAMR(
    277         const sp<DataSource> &source, String8 *mimeType, float *confidence) {
    278     char header[9];
    279 
    280     if (source->readAt(0, header, sizeof(header)) != sizeof(header)) {
    281         return false;
    282     }
    283 
    284     if (!memcmp(header, "#!AMR\n", 6)) {
    285         *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB;
    286         *confidence = 0.5;
    287 
    288         return true;
    289     } else if (!memcmp(header, "#!AMR-WB\n", 9)) {
    290         *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB;
    291         *confidence = 0.5;
    292 
    293         return true;
    294     }
    295 
    296     return false;
    297 }
    298 
    299 }  // namespace android
    300