Home | History | Annotate | Download | only in enc
      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 #include "AMRNBEncoder.h"
     18 
     19 #include "gsmamr_enc.h"
     20 
     21 #include <media/stagefright/MediaBufferGroup.h>
     22 #include <media/stagefright/MediaDebug.h>
     23 #include <media/stagefright/MediaDefs.h>
     24 #include <media/stagefright/MediaErrors.h>
     25 #include <media/stagefright/MetaData.h>
     26 
     27 namespace android {
     28 
     29 static const int32_t kNumSamplesPerFrame = 160;
     30 static const int32_t kSampleRate = 8000;
     31 
     32 AMRNBEncoder::AMRNBEncoder(const sp<MediaSource> &source, const sp<MetaData> &meta)
     33     : mSource(source),
     34       mMeta(meta),
     35       mStarted(false),
     36       mBufferGroup(NULL),
     37       mEncState(NULL),
     38       mSidState(NULL),
     39       mAnchorTimeUs(0),
     40       mNumFramesOutput(0),
     41       mInputBuffer(NULL),
     42       mMode(MR475),
     43       mNumInputSamples(0) {
     44 }
     45 
     46 AMRNBEncoder::~AMRNBEncoder() {
     47     if (mStarted) {
     48         stop();
     49     }
     50 }
     51 
     52 static Mode PickModeFromBitrate(int32_t bps) {
     53     if (bps <= 4750) {
     54         return MR475;
     55     } else if (bps <= 5150) {
     56         return MR515;
     57     } else if (bps <= 5900) {
     58         return MR59;
     59     } else if (bps <= 6700) {
     60         return MR67;
     61     } else if (bps <= 7400) {
     62         return MR74;
     63     } else if (bps <= 7950) {
     64         return MR795;
     65     } else if (bps <= 10200) {
     66         return MR102;
     67     } else {
     68         return MR122;
     69     }
     70 }
     71 
     72 status_t AMRNBEncoder::start(MetaData *params) {
     73     if (mStarted) {
     74         LOGW("Call start() when encoder already started");
     75         return OK;
     76     }
     77 
     78     mBufferGroup = new MediaBufferGroup;
     79     mBufferGroup->add_buffer(new MediaBuffer(32));
     80 
     81     CHECK_EQ(AMREncodeInit(
     82                 &mEncState, &mSidState, false /* dtx_enable */),
     83              0);
     84 
     85     status_t err = mSource->start(params);
     86     if (err != OK) {
     87         LOGE("AudioSource is not available");
     88         return err;
     89     }
     90 
     91     mAnchorTimeUs = 0;
     92     mNumFramesOutput = 0;
     93     mStarted = true;
     94     mNumInputSamples = 0;
     95 
     96     int32_t bitrate;
     97     if (params && params->findInt32(kKeyBitRate, &bitrate)) {
     98         mMode = PickModeFromBitrate(bitrate);
     99     } else {
    100         mMode = MR475;
    101     }
    102 
    103     return OK;
    104 }
    105 
    106 status_t AMRNBEncoder::stop() {
    107     if (!mStarted) {
    108         LOGW("Call stop() when encoder has not started.");
    109         return OK;
    110     }
    111 
    112     if (mInputBuffer) {
    113         mInputBuffer->release();
    114         mInputBuffer = NULL;
    115     }
    116 
    117     delete mBufferGroup;
    118     mBufferGroup = NULL;
    119 
    120     mSource->stop();
    121 
    122     AMREncodeExit(&mEncState, &mSidState);
    123     mEncState = mSidState = NULL;
    124 
    125     mStarted = false;
    126 
    127     return OK;
    128 }
    129 
    130 sp<MetaData> AMRNBEncoder::getFormat() {
    131     sp<MetaData> srcFormat = mSource->getFormat();
    132 
    133     mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
    134 
    135     int64_t durationUs;
    136     if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
    137         mMeta->setInt64(kKeyDuration, durationUs);
    138     }
    139 
    140     mMeta->setCString(kKeyDecoderComponent, "AMRNBEncoder");
    141 
    142     return mMeta;
    143 }
    144 
    145 status_t AMRNBEncoder::read(
    146         MediaBuffer **out, const ReadOptions *options) {
    147     status_t err;
    148 
    149     *out = NULL;
    150 
    151     int64_t seekTimeUs;
    152     ReadOptions::SeekMode mode;
    153     CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
    154     bool readFromSource = false;
    155     int64_t wallClockTimeUs = -1;
    156 
    157     while (mNumInputSamples < kNumSamplesPerFrame) {
    158         if (mInputBuffer == NULL) {
    159             err = mSource->read(&mInputBuffer, options);
    160 
    161             if (err != OK) {
    162                 if (mNumInputSamples == 0) {
    163                     return ERROR_END_OF_STREAM;
    164                 }
    165                 memset(&mInputFrame[mNumInputSamples],
    166                        0,
    167                        sizeof(int16_t)
    168                             * (kNumSamplesPerFrame - mNumInputSamples));
    169                 mNumInputSamples = kNumSamplesPerFrame;
    170                 break;
    171             }
    172 
    173             size_t align = mInputBuffer->range_length() % sizeof(int16_t);
    174             CHECK_EQ(align, 0);
    175             readFromSource = true;
    176 
    177             int64_t timeUs;
    178             if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
    179                 wallClockTimeUs = timeUs;
    180             }
    181             if (mInputBuffer->meta_data()->findInt64(kKeyAnchorTime, &timeUs)) {
    182                 mAnchorTimeUs = timeUs;
    183             }
    184         } else {
    185             readFromSource = false;
    186         }
    187 
    188         size_t copy =
    189             (kNumSamplesPerFrame - mNumInputSamples) * sizeof(int16_t);
    190 
    191         if (copy > mInputBuffer->range_length()) {
    192             copy = mInputBuffer->range_length();
    193         }
    194 
    195         memcpy(&mInputFrame[mNumInputSamples],
    196                (const uint8_t *)mInputBuffer->data()
    197                     + mInputBuffer->range_offset(),
    198                copy);
    199 
    200         mNumInputSamples += copy / sizeof(int16_t);
    201 
    202         mInputBuffer->set_range(
    203                 mInputBuffer->range_offset() + copy,
    204                 mInputBuffer->range_length() - copy);
    205 
    206         if (mInputBuffer->range_length() == 0) {
    207             mInputBuffer->release();
    208             mInputBuffer = NULL;
    209         }
    210     }
    211 
    212     MediaBuffer *buffer;
    213     CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
    214 
    215     uint8_t *outPtr = (uint8_t *)buffer->data();
    216 
    217     Frame_Type_3GPP frameType;
    218     int res = AMREncode(
    219             mEncState, mSidState, (Mode)mMode,
    220             mInputFrame, outPtr, &frameType, AMR_TX_WMF);
    221 
    222     CHECK(res >= 0);
    223     CHECK((size_t)res < buffer->size());
    224 
    225     // Convert header byte from WMF to IETF format.
    226     outPtr[0] = ((outPtr[0] << 3) | 4) & 0x7c;
    227 
    228     buffer->set_range(0, res);
    229 
    230     // Each frame of 160 samples is 20ms long.
    231     int64_t mediaTimeUs = mNumFramesOutput * 20000LL;
    232     buffer->meta_data()->setInt64(
    233             kKeyTime, mAnchorTimeUs + mediaTimeUs);
    234 
    235     if (readFromSource && wallClockTimeUs != -1) {
    236         buffer->meta_data()->setInt64(kKeyDriftTime,
    237             mediaTimeUs - wallClockTimeUs);
    238     }
    239 
    240     ++mNumFramesOutput;
    241 
    242     *out = buffer;
    243 
    244     mNumInputSamples = 0;
    245 
    246     return OK;
    247 }
    248 
    249 }  // namespace android
    250