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 "SoftAMRWBEncoder"
19 #include <utils/Log.h>
20
21 #include "SoftAMRWBEncoder.h"
22
23 #include "cmnMemory.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 = 16000;
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
SoftAMRWBEncoder(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)41 SoftAMRWBEncoder::SoftAMRWBEncoder(
42 const char *name,
43 const OMX_CALLBACKTYPE *callbacks,
44 OMX_PTR appData,
45 OMX_COMPONENTTYPE **component)
46 : SimpleSoftOMXComponent(name, callbacks, appData, component),
47 mEncoderHandle(NULL),
48 mApiHandle(NULL),
49 mMemOperator(NULL),
50 mBitRate(0),
51 mMode(VOAMRWB_MD66),
52 mInputSize(0),
53 mInputTimeUs(-1LL),
54 mSawInputEOS(false),
55 mSignalledError(false) {
56 initPorts();
57 CHECK_EQ(initEncoder(), (status_t)OK);
58 }
59
~SoftAMRWBEncoder()60 SoftAMRWBEncoder::~SoftAMRWBEncoder() {
61 if (mEncoderHandle != NULL) {
62 CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
63 mEncoderHandle = NULL;
64 }
65
66 delete mApiHandle;
67 mApiHandle = NULL;
68
69 delete mMemOperator;
70 mMemOperator = NULL;
71 }
72
initPorts()73 void SoftAMRWBEncoder::initPorts() {
74 OMX_PARAM_PORTDEFINITIONTYPE def;
75 InitOMXParams(&def);
76
77 def.nPortIndex = 0;
78 def.eDir = OMX_DirInput;
79 def.nBufferCountMin = kNumBuffers;
80 def.nBufferCountActual = def.nBufferCountMin;
81 def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t);
82 def.bEnabled = OMX_TRUE;
83 def.bPopulated = OMX_FALSE;
84 def.eDomain = OMX_PortDomainAudio;
85 def.bBuffersContiguous = OMX_FALSE;
86 def.nBufferAlignment = 1;
87
88 def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
89 def.format.audio.pNativeRender = NULL;
90 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
91 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
92
93 addPort(def);
94
95 def.nPortIndex = 1;
96 def.eDir = OMX_DirOutput;
97 def.nBufferCountMin = kNumBuffers;
98 def.nBufferCountActual = def.nBufferCountMin;
99 def.nBufferSize = 8192;
100 def.bEnabled = OMX_TRUE;
101 def.bPopulated = OMX_FALSE;
102 def.eDomain = OMX_PortDomainAudio;
103 def.bBuffersContiguous = OMX_FALSE;
104 def.nBufferAlignment = 2;
105
106 def.format.audio.cMIMEType = const_cast<char *>("audio/amr-wb");
107 def.format.audio.pNativeRender = NULL;
108 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
109 def.format.audio.eEncoding = OMX_AUDIO_CodingAMR;
110
111 addPort(def);
112 }
113
initEncoder()114 status_t SoftAMRWBEncoder::initEncoder() {
115 mApiHandle = new VO_AUDIO_CODECAPI;
116
117 if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) {
118 ALOGE("Failed to get api handle");
119 return UNKNOWN_ERROR;
120 }
121
122 mMemOperator = new VO_MEM_OPERATOR;
123 mMemOperator->Alloc = cmnMemAlloc;
124 mMemOperator->Copy = cmnMemCopy;
125 mMemOperator->Free = cmnMemFree;
126 mMemOperator->Set = cmnMemSet;
127 mMemOperator->Check = cmnMemCheck;
128
129 VO_CODEC_INIT_USERDATA userData;
130 memset(&userData, 0, sizeof(userData));
131 userData.memflag = VO_IMF_USERMEMOPERATOR;
132 userData.memData = (VO_PTR) mMemOperator;
133
134 if (VO_ERR_NONE != mApiHandle->Init(
135 &mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) {
136 ALOGE("Failed to init AMRWB encoder");
137 return UNKNOWN_ERROR;
138 }
139
140 VOAMRWBFRAMETYPE type = VOAMRWB_RFC3267;
141 if (VO_ERR_NONE != mApiHandle->SetParam(
142 mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &type)) {
143 ALOGE("Failed to set AMRWB encoder frame type to %d", type);
144 return UNKNOWN_ERROR;
145 }
146
147 return OK;
148 }
149
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)150 OMX_ERRORTYPE SoftAMRWBEncoder::internalGetParameter(
151 OMX_INDEXTYPE index, OMX_PTR params) {
152 switch (index) {
153 case OMX_IndexParamAudioPortFormat:
154 {
155 OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
156 (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
157
158 if (!isValidOMXParam(formatParams)) {
159 return OMX_ErrorBadParameter;
160 }
161
162 if (formatParams->nPortIndex > 1) {
163 return OMX_ErrorUndefined;
164 }
165
166 if (formatParams->nIndex > 0) {
167 return OMX_ErrorNoMore;
168 }
169
170 formatParams->eEncoding =
171 (formatParams->nPortIndex == 0)
172 ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR;
173
174 return OMX_ErrorNone;
175 }
176
177 case OMX_IndexParamAudioAmr:
178 {
179 OMX_AUDIO_PARAM_AMRTYPE *amrParams =
180 (OMX_AUDIO_PARAM_AMRTYPE *)params;
181
182 if (!isValidOMXParam(amrParams)) {
183 return OMX_ErrorBadParameter;
184 }
185
186 if (amrParams->nPortIndex != 1) {
187 return OMX_ErrorUndefined;
188 }
189
190 amrParams->nChannels = 1;
191 amrParams->nBitRate = mBitRate;
192
193 amrParams->eAMRBandMode =
194 (OMX_AUDIO_AMRBANDMODETYPE)(mMode + OMX_AUDIO_AMRBandModeWB0);
195
196 amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
197 amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
198
199 return OMX_ErrorNone;
200 }
201
202 case OMX_IndexParamAudioPcm:
203 {
204 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
205 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
206
207 if (!isValidOMXParam(pcmParams)) {
208 return OMX_ErrorBadParameter;
209 }
210
211 if (pcmParams->nPortIndex != 0) {
212 return OMX_ErrorUndefined;
213 }
214
215 pcmParams->eNumData = OMX_NumericalDataSigned;
216 pcmParams->eEndian = OMX_EndianBig;
217 pcmParams->bInterleaved = OMX_TRUE;
218 pcmParams->nBitPerSample = 16;
219 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
220 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF;
221
222 pcmParams->nChannels = 1;
223 pcmParams->nSamplingRate = kSampleRate;
224
225 return OMX_ErrorNone;
226 }
227
228 default:
229 return SimpleSoftOMXComponent::internalGetParameter(index, params);
230 }
231 }
232
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)233 OMX_ERRORTYPE SoftAMRWBEncoder::internalSetParameter(
234 OMX_INDEXTYPE index, const OMX_PTR params) {
235 switch (index) {
236 case OMX_IndexParamStandardComponentRole:
237 {
238 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
239 (const OMX_PARAM_COMPONENTROLETYPE *)params;
240
241 if (!isValidOMXParam(roleParams)) {
242 return OMX_ErrorBadParameter;
243 }
244
245 if (strncmp((const char *)roleParams->cRole,
246 "audio_encoder.amrwb",
247 OMX_MAX_STRINGNAME_SIZE - 1)) {
248 return OMX_ErrorUndefined;
249 }
250
251 return OMX_ErrorNone;
252 }
253
254 case OMX_IndexParamAudioPortFormat:
255 {
256 const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
257 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
258
259 if (!isValidOMXParam(formatParams)) {
260 return OMX_ErrorBadParameter;
261 }
262
263 if (formatParams->nPortIndex > 1) {
264 return OMX_ErrorUndefined;
265 }
266
267 if ((formatParams->nPortIndex == 0
268 && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
269 || (formatParams->nPortIndex == 1
270 && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) {
271 return OMX_ErrorUndefined;
272 }
273
274 return OMX_ErrorNone;
275 }
276
277 case OMX_IndexParamAudioAmr:
278 {
279 OMX_AUDIO_PARAM_AMRTYPE *amrParams =
280 (OMX_AUDIO_PARAM_AMRTYPE *)params;
281
282 if (!isValidOMXParam(amrParams)) {
283 return OMX_ErrorBadParameter;
284 }
285
286 if (amrParams->nPortIndex != 1) {
287 return OMX_ErrorUndefined;
288 }
289
290 if (amrParams->nChannels != 1
291 || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff
292 || amrParams->eAMRFrameFormat
293 != OMX_AUDIO_AMRFrameFormatFSF
294 || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeWB0
295 || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeWB8) {
296 return OMX_ErrorUndefined;
297 }
298
299 mBitRate = amrParams->nBitRate;
300
301 mMode = (VOAMRWBMODE)(
302 amrParams->eAMRBandMode - OMX_AUDIO_AMRBandModeWB0);
303
304 amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
305 amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
306
307 if (VO_ERR_NONE !=
308 mApiHandle->SetParam(
309 mEncoderHandle, VO_PID_AMRWB_MODE, &mMode)) {
310 ALOGE("Failed to set AMRWB encoder mode to %d", mMode);
311 return OMX_ErrorUndefined;
312 }
313
314 return OMX_ErrorNone;
315 }
316
317 case OMX_IndexParamAudioPcm:
318 {
319 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
320 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
321
322 if (!isValidOMXParam(pcmParams)) {
323 return OMX_ErrorBadParameter;
324 }
325
326 if (pcmParams->nPortIndex != 0) {
327 return OMX_ErrorUndefined;
328 }
329
330 if (pcmParams->nChannels != 1
331 || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) {
332 return OMX_ErrorUndefined;
333 }
334
335 return OMX_ErrorNone;
336 }
337
338
339 default:
340 return SimpleSoftOMXComponent::internalSetParameter(index, params);
341 }
342 }
343
onQueueFilled(OMX_U32)344 void SoftAMRWBEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
345 if (mSignalledError) {
346 return;
347 }
348
349 List<BufferInfo *> &inQueue = getPortQueue(0);
350 List<BufferInfo *> &outQueue = getPortQueue(1);
351
352 size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t);
353
354 for (;;) {
355 // We do the following until we run out of buffers.
356
357 while (mInputSize < numBytesPerInputFrame) {
358 // As long as there's still input data to be read we
359 // will drain "kNumSamplesPerFrame" samples
360 // into the "mInputFrame" buffer and then encode those
361 // as a unit into an output buffer.
362
363 if (mSawInputEOS || inQueue.empty()) {
364 return;
365 }
366
367 BufferInfo *inInfo = *inQueue.begin();
368 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
369
370 const void *inData = inHeader->pBuffer + inHeader->nOffset;
371
372 size_t copy = numBytesPerInputFrame - mInputSize;
373 if (copy > inHeader->nFilledLen) {
374 copy = inHeader->nFilledLen;
375 }
376
377 if (mInputSize == 0) {
378 mInputTimeUs = inHeader->nTimeStamp;
379 }
380
381 memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
382 mInputSize += copy;
383
384 inHeader->nOffset += copy;
385 inHeader->nFilledLen -= copy;
386
387 // "Time" on the input buffer has in effect advanced by the
388 // number of audio frames we just advanced nOffset by.
389 inHeader->nTimeStamp +=
390 (copy * 1000000LL / kSampleRate) / sizeof(int16_t);
391
392 if (inHeader->nFilledLen == 0) {
393 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
394 ALOGV("saw input EOS");
395 mSawInputEOS = true;
396
397 // Pad any remaining data with zeroes.
398 memset((uint8_t *)mInputFrame + mInputSize,
399 0,
400 numBytesPerInputFrame - mInputSize);
401
402 mInputSize = numBytesPerInputFrame;
403 }
404
405 inQueue.erase(inQueue.begin());
406 inInfo->mOwnedByUs = false;
407 notifyEmptyBufferDone(inHeader);
408
409 inData = NULL;
410 inHeader = NULL;
411 inInfo = NULL;
412 }
413 }
414
415 // At this point we have all the input data necessary to encode
416 // a single frame, all we need is an output buffer to store the result
417 // in.
418
419 if (outQueue.empty()) {
420 return;
421 }
422
423 BufferInfo *outInfo = *outQueue.begin();
424 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
425
426 uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset;
427 size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
428
429 VO_CODECBUFFER inputData;
430 memset(&inputData, 0, sizeof(inputData));
431 inputData.Buffer = (unsigned char *) mInputFrame;
432 inputData.Length = mInputSize;
433
434 CHECK_EQ((VO_U32)VO_ERR_NONE,
435 mApiHandle->SetInputData(mEncoderHandle, &inputData));
436
437 VO_CODECBUFFER outputData;
438 memset(&outputData, 0, sizeof(outputData));
439 VO_AUDIO_OUTPUTINFO outputInfo;
440 memset(&outputInfo, 0, sizeof(outputInfo));
441
442 outputData.Buffer = outPtr;
443 outputData.Length = outAvailable;
444 VO_U32 ret = mApiHandle->GetOutputData(
445 mEncoderHandle, &outputData, &outputInfo);
446 CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL);
447
448 outHeader->nFilledLen = outputData.Length;
449 outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
450
451 if (mSawInputEOS) {
452 // We also tag this output buffer with EOS if it corresponds
453 // to the final input buffer.
454 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
455 }
456
457 outHeader->nTimeStamp = mInputTimeUs;
458
459 #if 0
460 ALOGI("sending %ld bytes of data (time = %lld us, flags = 0x%08lx)",
461 outHeader->nFilledLen, mInputTimeUs, outHeader->nFlags);
462
463 hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
464 #endif
465
466 outQueue.erase(outQueue.begin());
467 outInfo->mOwnedByUs = false;
468 notifyFillBufferDone(outHeader);
469
470 outHeader = NULL;
471 outInfo = NULL;
472
473 mInputSize = 0;
474 }
475 }
476
477 } // namespace android
478
479 __attribute__((cfi_canonical_jump_table))
createSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)480 android::SoftOMXComponent *createSoftOMXComponent(
481 const char *name, const OMX_CALLBACKTYPE *callbacks,
482 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
483 return new android::SoftAMRWBEncoder(name, callbacks, appData, component);
484 }
485