blob: c0a588f7cb379612ff31cf59746a05a9ca0a7fd5 [file] [log] [blame]
Andreas Huber4b3913a2011-05-11 14:13:42 -07001/*
2 * Copyright (C) 2011 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//#define LOG_NDEBUG 0
18#define LOG_TAG "SoftAMR"
19#include <utils/Log.h>
20
21#include "SoftAMR.h"
22
23#include "gsmamr_dec.h"
24#include "pvamrwbdecoder.h"
25
26#include <media/stagefright/foundation/ADebug.h>
27
28namespace android {
29
30template<class T>
31static void InitOMXParams(T *params) {
32 params->nSize = sizeof(T);
33 params->nVersion.s.nVersionMajor = 1;
34 params->nVersion.s.nVersionMinor = 0;
35 params->nVersion.s.nRevision = 0;
36 params->nVersion.s.nStep = 0;
37}
38
39SoftAMR::SoftAMR(
40 const char *name,
41 const OMX_CALLBACKTYPE *callbacks,
42 OMX_PTR appData,
43 OMX_COMPONENTTYPE **component)
44 : SimpleSoftOMXComponent(name, callbacks, appData, component),
45 mMode(MODE_NARROW),
46 mState(NULL),
47 mDecoderBuf(NULL),
48 mDecoderCookie(NULL),
49 mInputBufferCount(0),
50 mAnchorTimeUs(0),
51 mNumSamplesOutput(0),
52 mSignalledError(false),
53 mOutputPortSettingsChange(NONE) {
54 if (!strcmp(name, "OMX.google.amrwb.decoder")) {
55 mMode = MODE_WIDE;
56 } else {
57 CHECK(!strcmp(name, "OMX.google.amrnb.decoder"));
58 }
59
60 initPorts();
61 CHECK_EQ(initDecoder(), (status_t)OK);
62}
63
64SoftAMR::~SoftAMR() {
65 if (mMode == MODE_NARROW) {
66 GSMDecodeFrameExit(&mState);
67 mState = NULL;
68 } else {
69 free(mDecoderBuf);
70 mDecoderBuf = NULL;
71
72 mState = NULL;
73 mDecoderCookie = NULL;
74 }
75}
76
77void SoftAMR::initPorts() {
78 OMX_PARAM_PORTDEFINITIONTYPE def;
79 InitOMXParams(&def);
80
81 def.nPortIndex = 0;
82 def.eDir = OMX_DirInput;
83 def.nBufferCountMin = kNumBuffers;
84 def.nBufferCountActual = def.nBufferCountMin;
85 def.nBufferSize = 8192;
86 def.bEnabled = OMX_TRUE;
87 def.bPopulated = OMX_FALSE;
88 def.eDomain = OMX_PortDomainAudio;
89 def.bBuffersContiguous = OMX_FALSE;
90 def.nBufferAlignment = 1;
91
92 def.format.audio.cMIMEType =
93 mMode == MODE_NARROW
94 ? const_cast<char *>("audio/amr")
95 : const_cast<char *>("audio/amrwb");
96
97 def.format.audio.pNativeRender = NULL;
98 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
99 def.format.audio.eEncoding = OMX_AUDIO_CodingAMR;
100
101 addPort(def);
102
103 def.nPortIndex = 1;
104 def.eDir = OMX_DirOutput;
105 def.nBufferCountMin = kNumBuffers;
106 def.nBufferCountActual = def.nBufferCountMin;
107
108 def.nBufferSize =
109 (mMode == MODE_NARROW ? kNumSamplesPerFrameNB : kNumSamplesPerFrameWB)
110 * sizeof(int16_t);
111
112 def.bEnabled = OMX_TRUE;
113 def.bPopulated = OMX_FALSE;
114 def.eDomain = OMX_PortDomainAudio;
115 def.bBuffersContiguous = OMX_FALSE;
116 def.nBufferAlignment = 2;
117
118 def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
119 def.format.audio.pNativeRender = NULL;
120 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
121 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
122
123 addPort(def);
124}
125
126status_t SoftAMR::initDecoder() {
127 if (mMode == MODE_NARROW) {
128 Word16 err = GSMInitDecode(&mState, (Word8 *)"AMRNBDecoder");
129
130 if (err != 0) {
131 return UNKNOWN_ERROR;
132 }
133 } else {
134 int32_t memReq = pvDecoder_AmrWbMemRequirements();
135 mDecoderBuf = malloc(memReq);
136
137 pvDecoder_AmrWb_Init(&mState, mDecoderBuf, &mDecoderCookie);
138 }
139
140 return OK;
141}
142
143OMX_ERRORTYPE SoftAMR::internalGetParameter(
144 OMX_INDEXTYPE index, OMX_PTR params) {
145 switch (index) {
146 case OMX_IndexParamAudioAmr:
147 {
148 OMX_AUDIO_PARAM_AMRTYPE *amrParams =
149 (OMX_AUDIO_PARAM_AMRTYPE *)params;
150
151 if (amrParams->nPortIndex != 0) {
152 return OMX_ErrorUndefined;
153 }
154
155 amrParams->nChannels = 1;
156 amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
157 amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatConformance;
158
159 if (!isConfigured()) {
160 amrParams->nBitRate = 0;
161 amrParams->eAMRBandMode = OMX_AUDIO_AMRBandModeUnused;
162 } else {
163 amrParams->nBitRate = 0;
164 amrParams->eAMRBandMode =
165 mMode == MODE_NARROW
166 ? OMX_AUDIO_AMRBandModeNB0 : OMX_AUDIO_AMRBandModeWB0;
167 }
168
169 return OMX_ErrorNone;
170 }
171
172 case OMX_IndexParamAudioPcm:
173 {
174 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
175 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
176
177 if (pcmParams->nPortIndex != 1) {
178 return OMX_ErrorUndefined;
179 }
180
181 pcmParams->nChannels = 1;
182 pcmParams->eNumData = OMX_NumericalDataSigned;
183 pcmParams->eEndian = OMX_EndianBig;
184 pcmParams->bInterleaved = OMX_TRUE;
185 pcmParams->nBitPerSample = 16;
186
187 pcmParams->nSamplingRate =
188 (mMode == MODE_NARROW) ? kSampleRateNB : kSampleRateWB;
189
190 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
191 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
192 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
193
194 return OMX_ErrorNone;
195 }
196
197 default:
198 return SimpleSoftOMXComponent::internalGetParameter(index, params);
199 }
200}
201
202OMX_ERRORTYPE SoftAMR::internalSetParameter(
203 OMX_INDEXTYPE index, const OMX_PTR params) {
204 switch (index) {
205 case OMX_IndexParamStandardComponentRole:
206 {
207 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
208 (const OMX_PARAM_COMPONENTROLETYPE *)params;
209
210 if (mMode == MODE_NARROW) {
211 if (strncmp((const char *)roleParams->cRole,
212 "audio_decoder.amrnb",
213 OMX_MAX_STRINGNAME_SIZE - 1)) {
214 return OMX_ErrorUndefined;
215 }
216 } else {
217 if (strncmp((const char *)roleParams->cRole,
218 "audio_decoder.amrwb",
219 OMX_MAX_STRINGNAME_SIZE - 1)) {
220 return OMX_ErrorUndefined;
221 }
222 }
223
224 return OMX_ErrorNone;
225 }
226
227 case OMX_IndexParamAudioAmr:
228 {
229 const OMX_AUDIO_PARAM_AMRTYPE *aacParams =
230 (const OMX_AUDIO_PARAM_AMRTYPE *)params;
231
232 if (aacParams->nPortIndex != 0) {
233 return OMX_ErrorUndefined;
234 }
235
236 return OMX_ErrorNone;
237 }
238
239 default:
240 return SimpleSoftOMXComponent::internalSetParameter(index, params);
241 }
242}
243
244bool SoftAMR::isConfigured() const {
245 return mInputBufferCount > 0;
246}
247
248static size_t getFrameSize(unsigned FT) {
249 static const size_t kFrameSizeWB[9] = {
250 132, 177, 253, 285, 317, 365, 397, 461, 477
251 };
252
253 size_t frameSize = kFrameSizeWB[FT];
254
255 // Round up bits to bytes and add 1 for the header byte.
256 frameSize = (frameSize + 7) / 8 + 1;
257
258 return frameSize;
259}
260
261void SoftAMR::onQueueFilled(OMX_U32 portIndex) {
262 List<BufferInfo *> &inQueue = getPortQueue(0);
263 List<BufferInfo *> &outQueue = getPortQueue(1);
264
265 if (mSignalledError || mOutputPortSettingsChange != NONE) {
266 return;
267 }
268
269 while (!inQueue.empty() && !outQueue.empty()) {
270 BufferInfo *inInfo = *inQueue.begin();
271 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
272
273 BufferInfo *outInfo = *outQueue.begin();
274 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
275
276 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
277 inQueue.erase(inQueue.begin());
278 inInfo->mOwnedByUs = false;
279 notifyEmptyBufferDone(inHeader);
280
281 outHeader->nFilledLen = 0;
282 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
283
284 outQueue.erase(outQueue.begin());
285 outInfo->mOwnedByUs = false;
286 notifyFillBufferDone(outHeader);
287 return;
288 }
289
290 if (inHeader->nOffset == 0) {
291 mAnchorTimeUs = inHeader->nTimeStamp;
292 mNumSamplesOutput = 0;
293 }
294
295 const uint8_t *inputPtr = inHeader->pBuffer + inHeader->nOffset;
296 int32_t numBytesRead;
297
298 if (mMode == MODE_NARROW) {
299 numBytesRead =
300 AMRDecode(mState,
301 (Frame_Type_3GPP)((inputPtr[0] >> 3) & 0x0f),
302 (UWord8 *)&inputPtr[1],
303 reinterpret_cast<int16_t *>(outHeader->pBuffer),
304 MIME_IETF);
305
306 if (numBytesRead == -1) {
307 LOGE("PV AMR decoder AMRDecode() call failed");
308
309 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
310 mSignalledError = true;
311
312 return;
313 }
314
315 ++numBytesRead; // Include the frame type header byte.
316
317 if (static_cast<size_t>(numBytesRead) > inHeader->nFilledLen) {
318 // This is bad, should never have happened, but did. Abort now.
319
320 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
321 mSignalledError = true;
322
323 return;
324 }
325 } else {
326 int16 mode = ((inputPtr[0] >> 3) & 0x0f);
327 size_t frameSize = getFrameSize(mode);
328 CHECK_GE(inHeader->nFilledLen, frameSize);
329
330 int16 frameType;
331 RX_State_wb rx_state;
332 mime_unsorting(
333 const_cast<uint8_t *>(&inputPtr[1]),
334 mInputSampleBuffer,
335 &frameType, &mode, 1, &rx_state);
336
337 int16_t *outPtr = (int16_t *)outHeader->pBuffer;
338
339 int16_t numSamplesOutput;
340 pvDecoder_AmrWb(
341 mode, mInputSampleBuffer,
342 outPtr,
343 &numSamplesOutput,
344 mDecoderBuf, frameType, mDecoderCookie);
345
346 CHECK_EQ((int)numSamplesOutput, (int)kNumSamplesPerFrameWB);
347
348 for (int i = 0; i < kNumSamplesPerFrameWB; ++i) {
349 /* Delete the 2 LSBs (14-bit output) */
350 outPtr[i] &= 0xfffC;
351 }
352
353 numBytesRead = frameSize;
354 }
355
356 inHeader->nOffset += numBytesRead;
357 inHeader->nFilledLen -= numBytesRead;
358
359 outHeader->nFlags = 0;
360 outHeader->nOffset = 0;
361
362 if (mMode == MODE_NARROW) {
363 outHeader->nFilledLen = kNumSamplesPerFrameNB * sizeof(int16_t);
364
365 outHeader->nTimeStamp =
366 mAnchorTimeUs
367 + (mNumSamplesOutput * 1000000ll) / kSampleRateNB;
368
369 mNumSamplesOutput += kNumSamplesPerFrameNB;
370 } else {
371 outHeader->nFilledLen = kNumSamplesPerFrameWB * sizeof(int16_t);
372
373 outHeader->nTimeStamp =
374 mAnchorTimeUs
375 + (mNumSamplesOutput * 1000000ll) / kSampleRateWB;
376
377 mNumSamplesOutput += kNumSamplesPerFrameWB;
378 }
379
380 if (inHeader->nFilledLen == 0) {
381 inInfo->mOwnedByUs = false;
382 inQueue.erase(inQueue.begin());
383 inInfo = NULL;
384 notifyEmptyBufferDone(inHeader);
385 inHeader = NULL;
386 }
387
388 outInfo->mOwnedByUs = false;
389 outQueue.erase(outQueue.begin());
390 outInfo = NULL;
391 notifyFillBufferDone(outHeader);
392 outHeader = NULL;
393
394 ++mInputBufferCount;
395 }
396}
397
398void SoftAMR::onPortFlushCompleted(OMX_U32 portIndex) {
399}
400
401void SoftAMR::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
402 if (portIndex != 1) {
403 return;
404 }
405
406 switch (mOutputPortSettingsChange) {
407 case NONE:
408 break;
409
410 case AWAITING_DISABLED:
411 {
412 CHECK(!enabled);
413 mOutputPortSettingsChange = AWAITING_ENABLED;
414 break;
415 }
416
417 default:
418 {
419 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
420 CHECK(enabled);
421 mOutputPortSettingsChange = NONE;
422 break;
423 }
424 }
425}
426
427} // namespace android
428
429android::SoftOMXComponent *createSoftOMXComponent(
430 const char *name, const OMX_CALLBACKTYPE *callbacks,
431 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
432 return new android::SoftAMR(name, callbacks, appData, component);
433}
434