SoftAMRWBEncoder.cpp revision f1a2668f4f09e38722424a6a74f0ea26f49e4110
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
28namespace android {
29
30static const int32_t kSampleRate = 16000;
31
32template<class T>
33static 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
41SoftAMRWBEncoder::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
60SoftAMRWBEncoder::~SoftAMRWBEncoder() {
61    if (mEncoderHandle != NULL) {
62        CHECK_EQ(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
73void 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
114status_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
150OMX_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
233OMX_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->nIndex > 0) {
268                return OMX_ErrorNoMore;
269            }
270
271            if ((formatParams->nPortIndex == 0
272                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
273                || (formatParams->nPortIndex == 1
274                        && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) {
275                return OMX_ErrorUndefined;
276            }
277
278            return OMX_ErrorNone;
279        }
280
281        case OMX_IndexParamAudioAmr:
282        {
283            OMX_AUDIO_PARAM_AMRTYPE *amrParams =
284                (OMX_AUDIO_PARAM_AMRTYPE *)params;
285
286            if (!isValidOMXParam(amrParams)) {
287                return OMX_ErrorBadParameter;
288            }
289
290            if (amrParams->nPortIndex != 1) {
291                return OMX_ErrorUndefined;
292            }
293
294            if (amrParams->nChannels != 1
295                    || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff
296                    || amrParams->eAMRFrameFormat
297                            != OMX_AUDIO_AMRFrameFormatFSF
298                    || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeWB0
299                    || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeWB8) {
300                return OMX_ErrorUndefined;
301            }
302
303            mBitRate = amrParams->nBitRate;
304
305            mMode = (VOAMRWBMODE)(
306                    amrParams->eAMRBandMode - OMX_AUDIO_AMRBandModeWB0);
307
308            amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
309            amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
310
311            if (VO_ERR_NONE !=
312                    mApiHandle->SetParam(
313                        mEncoderHandle, VO_PID_AMRWB_MODE,  &mMode)) {
314                ALOGE("Failed to set AMRWB encoder mode to %d", mMode);
315                return OMX_ErrorUndefined;
316            }
317
318            return OMX_ErrorNone;
319        }
320
321        case OMX_IndexParamAudioPcm:
322        {
323            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
324                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
325
326            if (!isValidOMXParam(pcmParams)) {
327                return OMX_ErrorBadParameter;
328            }
329
330            if (pcmParams->nPortIndex != 0) {
331                return OMX_ErrorUndefined;
332            }
333
334            if (pcmParams->nChannels != 1
335                    || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) {
336                return OMX_ErrorUndefined;
337            }
338
339            return OMX_ErrorNone;
340        }
341
342
343        default:
344            return SimpleSoftOMXComponent::internalSetParameter(index, params);
345    }
346}
347
348void SoftAMRWBEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
349    if (mSignalledError) {
350        return;
351    }
352
353    List<BufferInfo *> &inQueue = getPortQueue(0);
354    List<BufferInfo *> &outQueue = getPortQueue(1);
355
356    size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t);
357
358    for (;;) {
359        // We do the following until we run out of buffers.
360
361        while (mInputSize < numBytesPerInputFrame) {
362            // As long as there's still input data to be read we
363            // will drain "kNumSamplesPerFrame" samples
364            // into the "mInputFrame" buffer and then encode those
365            // as a unit into an output buffer.
366
367            if (mSawInputEOS || inQueue.empty()) {
368                return;
369            }
370
371            BufferInfo *inInfo = *inQueue.begin();
372            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
373
374            const void *inData = inHeader->pBuffer + inHeader->nOffset;
375
376            size_t copy = numBytesPerInputFrame - mInputSize;
377            if (copy > inHeader->nFilledLen) {
378                copy = inHeader->nFilledLen;
379            }
380
381            if (mInputSize == 0) {
382                mInputTimeUs = inHeader->nTimeStamp;
383            }
384
385            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
386            mInputSize += copy;
387
388            inHeader->nOffset += copy;
389            inHeader->nFilledLen -= copy;
390
391            // "Time" on the input buffer has in effect advanced by the
392            // number of audio frames we just advanced nOffset by.
393            inHeader->nTimeStamp +=
394                (copy * 1000000ll / kSampleRate) / sizeof(int16_t);
395
396            if (inHeader->nFilledLen == 0) {
397                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
398                    ALOGV("saw input EOS");
399                    mSawInputEOS = true;
400
401                    // Pad any remaining data with zeroes.
402                    memset((uint8_t *)mInputFrame + mInputSize,
403                           0,
404                           numBytesPerInputFrame - mInputSize);
405
406                    mInputSize = numBytesPerInputFrame;
407                }
408
409                inQueue.erase(inQueue.begin());
410                inInfo->mOwnedByUs = false;
411                notifyEmptyBufferDone(inHeader);
412
413                inData = NULL;
414                inHeader = NULL;
415                inInfo = NULL;
416            }
417        }
418
419        // At this  point we have all the input data necessary to encode
420        // a single frame, all we need is an output buffer to store the result
421        // in.
422
423        if (outQueue.empty()) {
424            return;
425        }
426
427        BufferInfo *outInfo = *outQueue.begin();
428        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
429
430        uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset;
431        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
432
433        VO_CODECBUFFER inputData;
434        memset(&inputData, 0, sizeof(inputData));
435        inputData.Buffer = (unsigned char *) mInputFrame;
436        inputData.Length = mInputSize;
437
438        CHECK_EQ(VO_ERR_NONE,
439                 mApiHandle->SetInputData(mEncoderHandle, &inputData));
440
441        VO_CODECBUFFER outputData;
442        memset(&outputData, 0, sizeof(outputData));
443        VO_AUDIO_OUTPUTINFO outputInfo;
444        memset(&outputInfo, 0, sizeof(outputInfo));
445
446        outputData.Buffer = outPtr;
447        outputData.Length = outAvailable;
448        VO_U32 ret = mApiHandle->GetOutputData(
449                mEncoderHandle, &outputData, &outputInfo);
450        CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL);
451
452        outHeader->nFilledLen = outputData.Length;
453        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
454
455        if (mSawInputEOS) {
456            // We also tag this output buffer with EOS if it corresponds
457            // to the final input buffer.
458            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
459        }
460
461        outHeader->nTimeStamp = mInputTimeUs;
462
463#if 0
464        ALOGI("sending %ld bytes of data (time = %lld us, flags = 0x%08lx)",
465              outHeader->nFilledLen, mInputTimeUs, outHeader->nFlags);
466
467        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
468#endif
469
470        outQueue.erase(outQueue.begin());
471        outInfo->mOwnedByUs = false;
472        notifyFillBufferDone(outHeader);
473
474        outHeader = NULL;
475        outInfo = NULL;
476
477        mInputSize = 0;
478    }
479}
480
481}  // namespace android
482
483android::SoftOMXComponent *createSoftOMXComponent(
484        const char *name, const OMX_CALLBACKTYPE *callbacks,
485        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
486    return new android::SoftAMRWBEncoder(name, callbacks, appData, component);
487}
488