1 /*
2 * Copyright (C) 2012 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 "SoftAMRNBEncoder"
19 #include <utils/Log.h>
20
21 #include "SoftAMRNBEncoder.h"
22
23 #include "gsmamr_enc.h"
24
25 #include <media/stagefright/foundation/ADebug.h>
26 #include <media/stagefright/foundation/hexdump.h>
27
28 namespace android {
29
30 static const int32_t kSampleRate = 8000;
31
32 template<class T>
InitOMXParams(T * params)33 static void InitOMXParams(T *params) {
34 params->nSize = sizeof(T);
35 params->nVersion.s.nVersionMajor = 1;
36 params->nVersion.s.nVersionMinor = 0;
37 params->nVersion.s.nRevision = 0;
38 params->nVersion.s.nStep = 0;
39 }
40
SoftAMRNBEncoder(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)41 SoftAMRNBEncoder::SoftAMRNBEncoder(
42 const char *name,
43 const OMX_CALLBACKTYPE *callbacks,
44 OMX_PTR appData,
45 OMX_COMPONENTTYPE **component)
46 : SimpleSoftOMXComponent(name, callbacks, appData, component),
47 mEncState(NULL),
48 mSidState(NULL),
49 mBitRate(0),
50 mMode(MR475),
51 mInputSize(0),
52 mInputTimeUs(-1LL),
53 mSawInputEOS(false),
54 mSignalledError(false) {
55 initPorts();
56 CHECK_EQ(initEncoder(), (status_t)OK);
57 }
58
~SoftAMRNBEncoder()59 SoftAMRNBEncoder::~SoftAMRNBEncoder() {
60 if (mEncState != NULL) {
61 AMREncodeExit(&mEncState, &mSidState);
62 mEncState = mSidState = NULL;
63 }
64 }
65
initPorts()66 void SoftAMRNBEncoder::initPorts() {
67 OMX_PARAM_PORTDEFINITIONTYPE def;
68 InitOMXParams(&def);
69
70 def.nPortIndex = 0;
71 def.eDir = OMX_DirInput;
72 def.nBufferCountMin = kNumBuffers;
73 def.nBufferCountActual = def.nBufferCountMin;
74 def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t);
75 def.bEnabled = OMX_TRUE;
76 def.bPopulated = OMX_FALSE;
77 def.eDomain = OMX_PortDomainAudio;
78 def.bBuffersContiguous = OMX_FALSE;
79 def.nBufferAlignment = 1;
80
81 def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
82 def.format.audio.pNativeRender = NULL;
83 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
84 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
85
86 addPort(def);
87
88 def.nPortIndex = 1;
89 def.eDir = OMX_DirOutput;
90 def.nBufferCountMin = kNumBuffers;
91 def.nBufferCountActual = def.nBufferCountMin;
92 def.nBufferSize = 8192;
93 def.bEnabled = OMX_TRUE;
94 def.bPopulated = OMX_FALSE;
95 def.eDomain = OMX_PortDomainAudio;
96 def.bBuffersContiguous = OMX_FALSE;
97 def.nBufferAlignment = 2;
98
99 def.format.audio.cMIMEType = const_cast<char *>("audio/3gpp");
100 def.format.audio.pNativeRender = NULL;
101 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
102 def.format.audio.eEncoding = OMX_AUDIO_CodingAMR;
103
104 addPort(def);
105 }
106
initEncoder()107 status_t SoftAMRNBEncoder::initEncoder() {
108 if (AMREncodeInit(&mEncState, &mSidState, false /* dtx_enable */) != 0) {
109 return UNKNOWN_ERROR;
110 }
111
112 return OK;
113 }
114
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)115 OMX_ERRORTYPE SoftAMRNBEncoder::internalGetParameter(
116 OMX_INDEXTYPE index, OMX_PTR params) {
117 switch (index) {
118 case OMX_IndexParamAudioPortFormat:
119 {
120 OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
121 (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
122
123 if (!isValidOMXParam(formatParams)) {
124 return OMX_ErrorBadParameter;
125 }
126
127 if (formatParams->nPortIndex > 1) {
128 return OMX_ErrorUndefined;
129 }
130
131 if (formatParams->nIndex > 0) {
132 return OMX_ErrorNoMore;
133 }
134
135 formatParams->eEncoding =
136 (formatParams->nPortIndex == 0)
137 ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR;
138
139 return OMX_ErrorNone;
140 }
141
142 case OMX_IndexParamAudioAmr:
143 {
144 OMX_AUDIO_PARAM_AMRTYPE *amrParams =
145 (OMX_AUDIO_PARAM_AMRTYPE *)params;
146
147 if (!isValidOMXParam(amrParams)) {
148 return OMX_ErrorBadParameter;
149 }
150
151 if (amrParams->nPortIndex != 1) {
152 return OMX_ErrorUndefined;
153 }
154
155 amrParams->nChannels = 1;
156 amrParams->nBitRate = mBitRate;
157 amrParams->eAMRBandMode = (OMX_AUDIO_AMRBANDMODETYPE)(mMode + 1);
158 amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
159 amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
160
161 return OMX_ErrorNone;
162 }
163
164 case OMX_IndexParamAudioPcm:
165 {
166 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
167 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
168
169 if (!isValidOMXParam(pcmParams)) {
170 return OMX_ErrorBadParameter;
171 }
172
173 if (pcmParams->nPortIndex != 0) {
174 return OMX_ErrorUndefined;
175 }
176
177 pcmParams->eNumData = OMX_NumericalDataSigned;
178 pcmParams->eEndian = OMX_EndianBig;
179 pcmParams->bInterleaved = OMX_TRUE;
180 pcmParams->nBitPerSample = 16;
181 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
182 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF;
183
184 pcmParams->nChannels = 1;
185 pcmParams->nSamplingRate = kSampleRate;
186
187 return OMX_ErrorNone;
188 }
189
190 default:
191 return SimpleSoftOMXComponent::internalGetParameter(index, params);
192 }
193 }
194
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)195 OMX_ERRORTYPE SoftAMRNBEncoder::internalSetParameter(
196 OMX_INDEXTYPE index, const OMX_PTR params) {
197 switch (index) {
198 case OMX_IndexParamStandardComponentRole:
199 {
200 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
201 (const OMX_PARAM_COMPONENTROLETYPE *)params;
202
203 if (!isValidOMXParam(roleParams)) {
204 return OMX_ErrorBadParameter;
205 }
206
207 if (strncmp((const char *)roleParams->cRole,
208 "audio_encoder.amrnb",
209 OMX_MAX_STRINGNAME_SIZE - 1)) {
210 return OMX_ErrorUndefined;
211 }
212
213 return OMX_ErrorNone;
214 }
215
216 case OMX_IndexParamAudioPortFormat:
217 {
218 const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
219 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
220
221 if (!isValidOMXParam(formatParams)) {
222 return OMX_ErrorBadParameter;
223 }
224
225 if (formatParams->nPortIndex > 1) {
226 return OMX_ErrorUndefined;
227 }
228
229 if ((formatParams->nPortIndex == 0
230 && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
231 || (formatParams->nPortIndex == 1
232 && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) {
233 return OMX_ErrorUndefined;
234 }
235
236 return OMX_ErrorNone;
237 }
238
239 case OMX_IndexParamAudioAmr:
240 {
241 OMX_AUDIO_PARAM_AMRTYPE *amrParams =
242 (OMX_AUDIO_PARAM_AMRTYPE *)params;
243
244 if (!isValidOMXParam(amrParams)) {
245 return OMX_ErrorBadParameter;
246 }
247
248 if (amrParams->nPortIndex != 1) {
249 return OMX_ErrorUndefined;
250 }
251
252 if (amrParams->nChannels != 1
253 || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff
254 || amrParams->eAMRFrameFormat
255 != OMX_AUDIO_AMRFrameFormatFSF
256 || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeNB0
257 || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeNB7) {
258 return OMX_ErrorUndefined;
259 }
260
261 mBitRate = amrParams->nBitRate;
262 mMode = amrParams->eAMRBandMode - 1;
263
264 amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
265 amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
266
267 return OMX_ErrorNone;
268 }
269
270 case OMX_IndexParamAudioPcm:
271 {
272 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
273 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
274
275 if (!isValidOMXParam(pcmParams)) {
276 return OMX_ErrorBadParameter;
277 }
278
279 if (pcmParams->nPortIndex != 0) {
280 return OMX_ErrorUndefined;
281 }
282
283 if (pcmParams->nChannels != 1
284 || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) {
285 return OMX_ErrorUndefined;
286 }
287
288 return OMX_ErrorNone;
289 }
290
291
292 default:
293 return SimpleSoftOMXComponent::internalSetParameter(index, params);
294 }
295 }
296
onQueueFilled(OMX_U32)297 void SoftAMRNBEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
298 if (mSignalledError) {
299 return;
300 }
301
302 List<BufferInfo *> &inQueue = getPortQueue(0);
303 List<BufferInfo *> &outQueue = getPortQueue(1);
304
305 size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t);
306
307 for (;;) {
308 // We do the following until we run out of buffers.
309
310 while (mInputSize < numBytesPerInputFrame) {
311 // As long as there's still input data to be read we
312 // will drain "kNumSamplesPerFrame" samples
313 // into the "mInputFrame" buffer and then encode those
314 // as a unit into an output buffer.
315
316 if (mSawInputEOS || inQueue.empty()) {
317 return;
318 }
319
320 BufferInfo *inInfo = *inQueue.begin();
321 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
322
323 const void *inData = inHeader->pBuffer + inHeader->nOffset;
324
325 size_t copy = numBytesPerInputFrame - mInputSize;
326 if (copy > inHeader->nFilledLen) {
327 copy = inHeader->nFilledLen;
328 }
329
330 if (mInputSize == 0) {
331 mInputTimeUs = inHeader->nTimeStamp;
332 }
333
334 memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
335 mInputSize += copy;
336
337 inHeader->nOffset += copy;
338 inHeader->nFilledLen -= copy;
339
340 // "Time" on the input buffer has in effect advanced by the
341 // number of audio frames we just advanced nOffset by.
342 inHeader->nTimeStamp +=
343 (copy * 1000000LL / kSampleRate) / sizeof(int16_t);
344
345 if (inHeader->nFilledLen == 0) {
346 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
347 ALOGV("saw input EOS");
348 mSawInputEOS = true;
349
350 // Pad any remaining data with zeroes.
351 memset((uint8_t *)mInputFrame + mInputSize,
352 0,
353 numBytesPerInputFrame - mInputSize);
354
355 mInputSize = numBytesPerInputFrame;
356 }
357
358 inQueue.erase(inQueue.begin());
359 inInfo->mOwnedByUs = false;
360 notifyEmptyBufferDone(inHeader);
361
362 inData = NULL;
363 inHeader = NULL;
364 inInfo = NULL;
365 }
366 }
367
368 // At this point we have all the input data necessary to encode
369 // a single frame, all we need is an output buffer to store the result
370 // in.
371
372 if (outQueue.empty()) {
373 return;
374 }
375
376 BufferInfo *outInfo = *outQueue.begin();
377 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
378
379 uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset;
380 size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
381
382 Frame_Type_3GPP frameType;
383 int res = AMREncode(
384 mEncState, mSidState, (Mode)mMode,
385 mInputFrame, outPtr, &frameType, AMR_TX_WMF);
386
387 CHECK_GE(res, 0);
388 CHECK_LE((size_t)res, outAvailable);
389
390 // Convert header byte from WMF to IETF format.
391 outPtr[0] = ((outPtr[0] << 3) | 4) & 0x7c;
392
393 outHeader->nFilledLen = res;
394 outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
395
396 if (mSawInputEOS) {
397 // We also tag this output buffer with EOS if it corresponds
398 // to the final input buffer.
399 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
400 }
401
402 outHeader->nTimeStamp = mInputTimeUs;
403
404 #if 0
405 ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
406 nOutputBytes, mInputTimeUs, outHeader->nFlags);
407
408 hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
409 #endif
410
411 outQueue.erase(outQueue.begin());
412 outInfo->mOwnedByUs = false;
413 notifyFillBufferDone(outHeader);
414
415 outHeader = NULL;
416 outInfo = NULL;
417
418 mInputSize = 0;
419 }
420 }
421
422 } // namespace android
423
424 __attribute__((cfi_canonical_jump_table))
createSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)425 android::SoftOMXComponent *createSoftOMXComponent(
426 const char *name, const OMX_CALLBACKTYPE *callbacks,
427 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
428 return new android::SoftAMRNBEncoder(name, callbacks, appData, component);
429 }
430