blob: cb680ba97fb4d31f64c53fceca57d7e4cd010cd0 [file] [log] [blame]
/*
* 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, const sp<MetaData> &meta)
: mSource(source),
mMeta(meta),
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();
mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
int64_t durationUs;
if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
mMeta->setInt64(kKeyDuration, durationUs);
}
mMeta->setCString(kKeyDecoderComponent, "AMRNBEncoder");
return mMeta;
}
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