diff options
Diffstat (limited to 'media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp')
-rw-r--r-- | media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp new file mode 100644 index 0000000..856e29c --- /dev/null +++ b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp @@ -0,0 +1,180 @@ +/* + * 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 "AMRNBDecoder.h" + +#include "gsmamr_dec.h" + +#include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MetaData.h> + +namespace android { + +static const int32_t kNumSamplesPerFrame = 160; +static const int32_t kSampleRate = 8000; + +AMRNBDecoder::AMRNBDecoder(const sp<MediaSource> &source) + : mSource(source), + mStarted(false), + mBufferGroup(NULL), + mState(NULL), + mAnchorTimeUs(0), + mNumSamplesOutput(0), + mInputBuffer(NULL) { +} + +AMRNBDecoder::~AMRNBDecoder() { + if (mStarted) { + stop(); + } +} + +status_t AMRNBDecoder::start(MetaData *params) { + CHECK(!mStarted); + + mBufferGroup = new MediaBufferGroup; + mBufferGroup->add_buffer( + new MediaBuffer(kNumSamplesPerFrame * sizeof(int16_t))); + + CHECK_EQ(GSMInitDecode(&mState, (Word8 *)"AMRNBDecoder"), 0); + + mSource->start(); + + mAnchorTimeUs = 0; + mNumSamplesOutput = 0; + mStarted = true; + + return OK; +} + +status_t AMRNBDecoder::stop() { + CHECK(mStarted); + + if (mInputBuffer) { + mInputBuffer->release(); + mInputBuffer = NULL; + } + + delete mBufferGroup; + mBufferGroup = NULL; + + GSMDecodeFrameExit(&mState); + + mSource->stop(); + + mStarted = false; + + return OK; +} + +sp<MetaData> AMRNBDecoder::getFormat() { + sp<MetaData> srcFormat = mSource->getFormat(); + + int32_t numChannels; + int32_t sampleRate; + int64_t durationUs; + + CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels)); + CHECK_EQ(numChannels, 1); + + CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate)); + CHECK_EQ(sampleRate, kSampleRate); + + CHECK(srcFormat->findInt64(kKeyDuration, &durationUs)); + + sp<MetaData> meta = new MetaData; + meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); + meta->setInt32(kKeyChannelCount, numChannels); + meta->setInt32(kKeySampleRate, sampleRate); + meta->setInt64(kKeyDuration, durationUs); + + return meta; +} + +status_t AMRNBDecoder::read( + MediaBuffer **out, const ReadOptions *options) { + status_t err; + + *out = NULL; + + int64_t seekTimeUs; + if (options && options->getSeekTo(&seekTimeUs)) { + CHECK(seekTimeUs >= 0); + + mNumSamplesOutput = 0; + + if (mInputBuffer) { + mInputBuffer->release(); + mInputBuffer = NULL; + } + } else { + seekTimeUs = -1; + } + + if (mInputBuffer == NULL) { + err = mSource->read(&mInputBuffer, options); + + if (err != OK) { + return err; + } + + int64_t timeUs; + if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { + mAnchorTimeUs = timeUs; + mNumSamplesOutput = 0; + } else { + // We must have a new timestamp after seeking. + CHECK(seekTimeUs < 0); + } + } + + MediaBuffer *buffer; + CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK); + + const uint8_t *inputPtr = + (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(); + + size_t numBytesRead = + AMRDecode(mState, + (Frame_Type_3GPP)((inputPtr[0] >> 3) & 0x0f), + (UWord8 *)&inputPtr[1], + static_cast<int16_t *>(buffer->data()), + MIME_IETF); + + ++numBytesRead; // Include the frame type header byte. + + buffer->set_range(0, kNumSamplesPerFrame * sizeof(int16_t)); + + CHECK_EQ(numBytesRead, mInputBuffer->range_length()); + + mInputBuffer->release(); + mInputBuffer = NULL; + + buffer->meta_data()->setInt64( + kKeyTime, + mAnchorTimeUs + + (mNumSamplesOutput * 1000000) / kSampleRate); + + mNumSamplesOutput += kNumSamplesPerFrame; + + *out = buffer; + + return OK; +} + +} // namespace android |