Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 08945576 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change I9ac0777e into eclair-mr2

* changes:
  Initial checkin of software AMR NB encoder based on PV source code.
parents b7f0367c d49b526d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ enum {
    kKeyHeight            = 'heig',
    kKeyChannelCount      = '#chn',
    kKeySampleRate        = 'srte',
    kKeyBitRate           = 'brte',
    kKeyBitRate           = 'brte',  // int32_t (bps)
    kKeyESDS              = 'esds',  // raw data
    kKeyAVCC              = 'avcc',  // raw data
    kKeyWantsNALFragments = 'NALf',
+1 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
LOCAL_STATIC_LIBRARIES := \
        libstagefright_aacdec \
        libstagefright_amrnbdec \
        libstagefright_amrnbenc \
        libstagefright_amrwbdec \
        libstagefright_avcdec \
        libstagefright_mp3dec
+3 −3
Original line number Diff line number Diff line
@@ -366,7 +366,7 @@ MP3Extractor::MP3Extractor(const sp<DataSource> &source)

        mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
        mMeta->setInt32(kKeySampleRate, sample_rate);
        mMeta->setInt32(kKeyBitRate, bitrate);
        mMeta->setInt32(kKeyBitRate, bitrate * 1000);
        mMeta->setInt32(kKeyChannelCount, num_channels);

        off_t fileSize;
@@ -462,14 +462,14 @@ status_t MP3Source::read(
    if (options != NULL && options->getSeekTo(&seekTimeUs)) {
        int32_t bitrate;
        if (!mMeta->findInt32(kKeyBitRate, &bitrate)) {
            // bitrate is in kbits/sec.
            // bitrate is in bits/sec.
            LOGI("no bitrate");

            return ERROR_UNSUPPORTED;
        }

        mCurrentTimeUs = seekTimeUs;
        mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 1000000 * 125;
        mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 8000000;
    }

    MediaBuffer *buffer;
+5 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#if BUILD_WITH_FULL_STAGEFRIGHT
#include "include/AACDecoder.h"
#include "include/AMRNBDecoder.h"
#include "include/AMRNBEncoder.h"
#include "include/AMRWBDecoder.h"
#include "include/AVCDecoder.h"
#include "include/MP3Decoder.h"
@@ -306,6 +307,10 @@ sp<MediaSource> OMXCodec::Create(
                    && (flags & kPreferSoftwareCodecs)) {
            return new AVCDecoder(source);
        }
    } else {
        if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
            return new AMRNBEncoder(source);
        }
    }
#endif

+234 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "AMRNBEncoder.h"

#include "gsmamr_enc.h"

#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>

namespace android {

static const int32_t kNumSamplesPerFrame = 160;
static const int32_t kSampleRate = 8000;

AMRNBEncoder::AMRNBEncoder(const sp<MediaSource> &source)
    : mSource(source),
      mStarted(false),
      mBufferGroup(NULL),
      mEncState(NULL),
      mSidState(NULL),
      mAnchorTimeUs(0),
      mNumFramesOutput(0),
      mInputBuffer(NULL),
      mMode(MR475),
      mNumInputSamples(0) {
}

AMRNBEncoder::~AMRNBEncoder() {
    if (mStarted) {
        stop();
    }
}

static Mode PickModeFromBitrate(int32_t bps) {
    if (bps <= 4750) {
        return MR475;
    } else if (bps <= 5150) {
        return MR515;
    } else if (bps <= 5900) {
        return MR59;
    } else if (bps <= 6700) {
        return MR67;
    } else if (bps <= 7400) {
        return MR74;
    } else if (bps <= 7950) {
        return MR795;
    } else if (bps <= 10200) {
        return MR102;
    } else {
        return MR122;
    }
}

status_t AMRNBEncoder::start(MetaData *params) {
    CHECK(!mStarted);

    mBufferGroup = new MediaBufferGroup;
    mBufferGroup->add_buffer(new MediaBuffer(32));

    CHECK_EQ(AMREncodeInit(
                &mEncState, &mSidState, false /* dtx_enable */),
             0);

    mSource->start();

    mAnchorTimeUs = 0;
    mNumFramesOutput = 0;
    mStarted = true;
    mNumInputSamples = 0;

    int32_t bitrate;
    if (params && params->findInt32(kKeyBitRate, &bitrate)) {
        mMode = PickModeFromBitrate(bitrate);
    } else {
        mMode = MR475;
    }

    return OK;
}

status_t AMRNBEncoder::stop() {
    CHECK(mStarted);

    if (mInputBuffer) {
        mInputBuffer->release();
        mInputBuffer = NULL;
    }

    delete mBufferGroup;
    mBufferGroup = NULL;

    mSource->stop();

    AMREncodeExit(&mEncState, &mSidState);
    mEncState = mSidState = NULL;

    mStarted = false;

    return OK;
}

sp<MetaData> AMRNBEncoder::getFormat() {
    sp<MetaData> srcFormat = mSource->getFormat();

    int32_t numChannels;
    int32_t sampleRate;

    CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels));
    CHECK_EQ(numChannels, 1);

    CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
    CHECK_EQ(sampleRate, kSampleRate);

    sp<MetaData> meta = new MetaData;
    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
    meta->setInt32(kKeyChannelCount, numChannels);
    meta->setInt32(kKeySampleRate, sampleRate);

    int64_t durationUs;
    if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
        meta->setInt64(kKeyDuration, durationUs);
    }

    return meta;
}

status_t AMRNBEncoder::read(
        MediaBuffer **out, const ReadOptions *options) {
    status_t err;

    *out = NULL;

    int64_t seekTimeUs;
    CHECK(options == NULL || !options->getSeekTo(&seekTimeUs));

    while (mNumInputSamples < kNumSamplesPerFrame) {
        if (mInputBuffer == NULL) {
            err = mSource->read(&mInputBuffer, options);

            if (err != OK) {
                if (mNumInputSamples == 0) {
                    return ERROR_END_OF_STREAM;
                }
                memset(&mInputFrame[mNumInputSamples],
                       0,
                       sizeof(int16_t)
                            * (kNumSamplesPerFrame - mNumInputSamples));
                mNumInputSamples = kNumSamplesPerFrame;
                break;
            }

            size_t align = mInputBuffer->range_length() % sizeof(int16_t);
            CHECK_EQ(align, 0);

            int64_t timeUs;
            if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
                mAnchorTimeUs = timeUs;
                mNumFramesOutput = 0;
            }
        }

        size_t copy =
            (kNumSamplesPerFrame - mNumInputSamples) * sizeof(int16_t);

        if (copy > mInputBuffer->range_length()) {
            copy = mInputBuffer->range_length();
        }

        memcpy(&mInputFrame[mNumInputSamples],
               (const uint8_t *)mInputBuffer->data()
                    + mInputBuffer->range_offset(),
               copy);

        mNumInputSamples += copy / sizeof(int16_t);

        mInputBuffer->set_range(
                mInputBuffer->range_offset() + copy,
                mInputBuffer->range_length() - copy);

        if (mInputBuffer->range_length() == 0) {
            mInputBuffer->release();
            mInputBuffer = NULL;
        }
    }

    MediaBuffer *buffer;
    CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);

    uint8_t *outPtr = (uint8_t *)buffer->data();

    Frame_Type_3GPP frameType;
    int res = AMREncode(
            mEncState, mSidState, (Mode)mMode,
            mInputFrame, outPtr, &frameType, AMR_TX_WMF);

    CHECK(res >= 0);
    CHECK((size_t)res < buffer->size());

    // Convert header byte from WMF to IETF format.
    outPtr[0] = ((outPtr[0] << 3) | 4) & 0x7c;

    buffer->set_range(0, res);

    // Each frame of 160 samples is 20ms long.
    buffer->meta_data()->setInt64(
            kKeyTime, mAnchorTimeUs + mNumFramesOutput * 20000);

    ++mNumFramesOutput;

    *out = buffer;

    mNumInputSamples = 0;

    return OK;
}

}  // namespace android
Loading