blob: a11d46bbd1e79433bfe11739b11bec599d294ab3 [file] [log] [blame]
Andreas Hubera30d4002009-12-08 15:40:06 -08001/*
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
Sidipotu Ashok14e974a2011-03-08 15:54:36 +053017//#define LOG_NDEBUG 0
18#define LOG_TAG "AMRNBDecoder"
19#include <utils/Log.h>
20
Andreas Hubera30d4002009-12-08 15:40:06 -080021#include "AMRNBDecoder.h"
22
23#include "gsmamr_dec.h"
24
25#include <media/stagefright/MediaBufferGroup.h>
26#include <media/stagefright/MediaDebug.h>
27#include <media/stagefright/MediaDefs.h>
Andreas Huberbd278752010-03-18 14:03:47 -070028#include <media/stagefright/MediaErrors.h>
Andreas Hubera30d4002009-12-08 15:40:06 -080029#include <media/stagefright/MetaData.h>
30
31namespace android {
32
33static const int32_t kNumSamplesPerFrame = 160;
34static const int32_t kSampleRate = 8000;
35
36AMRNBDecoder::AMRNBDecoder(const sp<MediaSource> &source)
37 : mSource(source),
38 mStarted(false),
39 mBufferGroup(NULL),
40 mState(NULL),
41 mAnchorTimeUs(0),
42 mNumSamplesOutput(0),
43 mInputBuffer(NULL) {
44}
45
46AMRNBDecoder::~AMRNBDecoder() {
47 if (mStarted) {
48 stop();
49 }
50}
51
52status_t AMRNBDecoder::start(MetaData *params) {
53 CHECK(!mStarted);
54
55 mBufferGroup = new MediaBufferGroup;
56 mBufferGroup->add_buffer(
57 new MediaBuffer(kNumSamplesPerFrame * sizeof(int16_t)));
58
59 CHECK_EQ(GSMInitDecode(&mState, (Word8 *)"AMRNBDecoder"), 0);
60
61 mSource->start();
62
63 mAnchorTimeUs = 0;
64 mNumSamplesOutput = 0;
65 mStarted = true;
66
67 return OK;
68}
69
70status_t AMRNBDecoder::stop() {
71 CHECK(mStarted);
72
73 if (mInputBuffer) {
74 mInputBuffer->release();
75 mInputBuffer = NULL;
76 }
77
78 delete mBufferGroup;
79 mBufferGroup = NULL;
80
81 GSMDecodeFrameExit(&mState);
82
83 mSource->stop();
84
85 mStarted = false;
86
87 return OK;
88}
89
90sp<MetaData> AMRNBDecoder::getFormat() {
91 sp<MetaData> srcFormat = mSource->getFormat();
92
93 int32_t numChannels;
94 int32_t sampleRate;
Andreas Hubera30d4002009-12-08 15:40:06 -080095
96 CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels));
97 CHECK_EQ(numChannels, 1);
98
99 CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
100 CHECK_EQ(sampleRate, kSampleRate);
101
Andreas Hubera30d4002009-12-08 15:40:06 -0800102 sp<MetaData> meta = new MetaData;
103 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
104 meta->setInt32(kKeyChannelCount, numChannels);
105 meta->setInt32(kKeySampleRate, sampleRate);
Andreas Huber85adf5e2009-12-11 11:27:02 -0800106
107 int64_t durationUs;
108 if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
109 meta->setInt64(kKeyDuration, durationUs);
110 }
Andreas Hubera30d4002009-12-08 15:40:06 -0800111
Andreas Huber71674722010-03-30 13:50:38 -0700112 meta->setCString(kKeyDecoderComponent, "AMRNBDecoder");
113
Andreas Hubera30d4002009-12-08 15:40:06 -0800114 return meta;
115}
116
117status_t AMRNBDecoder::read(
118 MediaBuffer **out, const ReadOptions *options) {
119 status_t err;
120
121 *out = NULL;
122
123 int64_t seekTimeUs;
Andreas Huber6624c9f2010-07-20 15:04:28 -0700124 ReadOptions::SeekMode mode;
125 if (options && options->getSeekTo(&seekTimeUs, &mode)) {
Andreas Hubera30d4002009-12-08 15:40:06 -0800126 CHECK(seekTimeUs >= 0);
127
128 mNumSamplesOutput = 0;
129
130 if (mInputBuffer) {
131 mInputBuffer->release();
132 mInputBuffer = NULL;
133 }
134 } else {
135 seekTimeUs = -1;
136 }
137
138 if (mInputBuffer == NULL) {
139 err = mSource->read(&mInputBuffer, options);
140
141 if (err != OK) {
142 return err;
143 }
144
145 int64_t timeUs;
146 if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
147 mAnchorTimeUs = timeUs;
148 mNumSamplesOutput = 0;
149 } else {
150 // We must have a new timestamp after seeking.
151 CHECK(seekTimeUs < 0);
152 }
153 }
154
155 MediaBuffer *buffer;
156 CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
157
158 const uint8_t *inputPtr =
159 (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
160
Sidipotu Ashok14e974a2011-03-08 15:54:36 +0530161 int32_t numBytesRead =
Andreas Hubera30d4002009-12-08 15:40:06 -0800162 AMRDecode(mState,
163 (Frame_Type_3GPP)((inputPtr[0] >> 3) & 0x0f),
164 (UWord8 *)&inputPtr[1],
165 static_cast<int16_t *>(buffer->data()),
166 MIME_IETF);
167
Sidipotu Ashok14e974a2011-03-08 15:54:36 +0530168 if (numBytesRead == -1 ) {
169 LOGE("PV AMR decoder AMRDecode() call failed");
170 buffer->release();
171 buffer = NULL;
172 return ERROR_MALFORMED;
173 }
Andreas Hubera30d4002009-12-08 15:40:06 -0800174 ++numBytesRead; // Include the frame type header byte.
175
176 buffer->set_range(0, kNumSamplesPerFrame * sizeof(int16_t));
177
Sidipotu Ashok14e974a2011-03-08 15:54:36 +0530178 if (static_cast<size_t>(numBytesRead) > mInputBuffer->range_length()) {
Andreas Huberbd278752010-03-18 14:03:47 -0700179 // This is bad, should never have happened, but did. Abort now.
180
181 buffer->release();
182 buffer = NULL;
183
184 return ERROR_MALFORMED;
185 }
Andreas Hubera30d4002009-12-08 15:40:06 -0800186
Andreas Huber85adf5e2009-12-11 11:27:02 -0800187 mInputBuffer->set_range(
188 mInputBuffer->range_offset() + numBytesRead,
189 mInputBuffer->range_length() - numBytesRead);
190
191 if (mInputBuffer->range_length() == 0) {
192 mInputBuffer->release();
193 mInputBuffer = NULL;
194 }
Andreas Hubera30d4002009-12-08 15:40:06 -0800195
196 buffer->meta_data()->setInt64(
197 kKeyTime,
198 mAnchorTimeUs
199 + (mNumSamplesOutput * 1000000) / kSampleRate);
200
201 mNumSamplesOutput += kNumSamplesPerFrame;
202
203 *out = buffer;
204
205 return OK;
206}
207
208} // namespace android