SoftAACEncoder.cpp revision 423766ca07beb7e3e9cd301385708ca13fcce3e1
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 "SoftAACEncoder"
19#include <utils/Log.h>
20
21#include "SoftAACEncoder.h"
22
23#include "voAAC.h"
24#include "cmnMemory.h"
25
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/foundation/hexdump.h>
28
29namespace android {
30
31template<class T>
32static void InitOMXParams(T *params) {
33    params->nSize = sizeof(T);
34    params->nVersion.s.nVersionMajor = 1;
35    params->nVersion.s.nVersionMinor = 0;
36    params->nVersion.s.nRevision = 0;
37    params->nVersion.s.nStep = 0;
38}
39
40SoftAACEncoder::SoftAACEncoder(
41        const char *name,
42        const OMX_CALLBACKTYPE *callbacks,
43        OMX_PTR appData,
44        OMX_COMPONENTTYPE **component)
45    : SimpleSoftOMXComponent(name, callbacks, appData, component),
46      mEncoderHandle(NULL),
47      mApiHandle(NULL),
48      mMemOperator(NULL),
49      mNumChannels(1),
50      mSampleRate(44100),
51      mBitRate(0),
52      mSentCodecSpecificData(false),
53      mInputSize(0),
54      mInputFrame(NULL),
55      mInputTimeUs(-1ll),
56      mSawInputEOS(false),
57      mSignalledError(false) {
58    initPorts();
59    CHECK_EQ(initEncoder(), (status_t)OK);
60
61    setAudioParams();
62}
63
64SoftAACEncoder::~SoftAACEncoder() {
65    delete[] mInputFrame;
66    mInputFrame = NULL;
67
68    if (mEncoderHandle) {
69        CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
70        mEncoderHandle = NULL;
71    }
72
73    delete mApiHandle;
74    mApiHandle = NULL;
75
76    delete mMemOperator;
77    mMemOperator = NULL;
78}
79
80void SoftAACEncoder::initPorts() {
81    OMX_PARAM_PORTDEFINITIONTYPE def;
82    InitOMXParams(&def);
83
84    def.nPortIndex = 0;
85    def.eDir = OMX_DirInput;
86    def.nBufferCountMin = kNumBuffers;
87    def.nBufferCountActual = def.nBufferCountMin;
88    def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 2;
89    def.bEnabled = OMX_TRUE;
90    def.bPopulated = OMX_FALSE;
91    def.eDomain = OMX_PortDomainAudio;
92    def.bBuffersContiguous = OMX_FALSE;
93    def.nBufferAlignment = 1;
94
95    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
96    def.format.audio.pNativeRender = NULL;
97    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
98    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
99
100    addPort(def);
101
102    def.nPortIndex = 1;
103    def.eDir = OMX_DirOutput;
104    def.nBufferCountMin = kNumBuffers;
105    def.nBufferCountActual = def.nBufferCountMin;
106    def.nBufferSize = 8192;
107    def.bEnabled = OMX_TRUE;
108    def.bPopulated = OMX_FALSE;
109    def.eDomain = OMX_PortDomainAudio;
110    def.bBuffersContiguous = OMX_FALSE;
111    def.nBufferAlignment = 2;
112
113    def.format.audio.cMIMEType = const_cast<char *>("audio/aac");
114    def.format.audio.pNativeRender = NULL;
115    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
116    def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
117
118    addPort(def);
119}
120
121status_t SoftAACEncoder::initEncoder() {
122    mApiHandle = new VO_AUDIO_CODECAPI;
123
124    if (VO_ERR_NONE != voGetAACEncAPI(mApiHandle)) {
125        ALOGE("Failed to get api handle");
126        return UNKNOWN_ERROR;
127    }
128
129    mMemOperator = new VO_MEM_OPERATOR;
130    mMemOperator->Alloc = cmnMemAlloc;
131    mMemOperator->Copy = cmnMemCopy;
132    mMemOperator->Free = cmnMemFree;
133    mMemOperator->Set = cmnMemSet;
134    mMemOperator->Check = cmnMemCheck;
135
136    VO_CODEC_INIT_USERDATA userData;
137    memset(&userData, 0, sizeof(userData));
138    userData.memflag = VO_IMF_USERMEMOPERATOR;
139    userData.memData = (VO_PTR) mMemOperator;
140    if (VO_ERR_NONE !=
141            mApiHandle->Init(&mEncoderHandle, VO_AUDIO_CodingAAC, &userData)) {
142        ALOGE("Failed to init AAC encoder");
143        return UNKNOWN_ERROR;
144    }
145
146    return OK;
147}
148
149OMX_ERRORTYPE SoftAACEncoder::internalGetParameter(
150        OMX_INDEXTYPE index, OMX_PTR params) {
151    switch (index) {
152        case OMX_IndexParamAudioPortFormat:
153        {
154            OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
155                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
156
157            if (!isValidOMXParam(formatParams)) {
158                return OMX_ErrorBadParameter;
159            }
160
161            if (formatParams->nPortIndex > 1) {
162                return OMX_ErrorUndefined;
163            }
164
165            if (formatParams->nIndex > 0) {
166                return OMX_ErrorNoMore;
167            }
168
169            formatParams->eEncoding =
170                (formatParams->nPortIndex == 0)
171                    ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAAC;
172
173            return OMX_ErrorNone;
174        }
175
176        case OMX_IndexParamAudioAac:
177        {
178            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
179                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
180
181            if (!isValidOMXParam(aacParams)) {
182                return OMX_ErrorBadParameter;
183            }
184
185            if (aacParams->nPortIndex != 1) {
186                return OMX_ErrorUndefined;
187            }
188
189            aacParams->nBitRate = mBitRate;
190            aacParams->nAudioBandWidth = 0;
191            aacParams->nAACtools = 0;
192            aacParams->nAACERtools = 0;
193            aacParams->eAACProfile = OMX_AUDIO_AACObjectMain;
194            aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
195            aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
196
197            aacParams->nChannels = mNumChannels;
198            aacParams->nSampleRate = mSampleRate;
199            aacParams->nFrameLength = 0;
200
201            return OMX_ErrorNone;
202        }
203
204        case OMX_IndexParamAudioPcm:
205        {
206            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
207                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
208
209            if (!isValidOMXParam(pcmParams)) {
210                return OMX_ErrorBadParameter;
211            }
212
213            if (pcmParams->nPortIndex != 0) {
214                return OMX_ErrorUndefined;
215            }
216
217            pcmParams->eNumData = OMX_NumericalDataSigned;
218            pcmParams->eEndian = OMX_EndianBig;
219            pcmParams->bInterleaved = OMX_TRUE;
220            pcmParams->nBitPerSample = 16;
221            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
222            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
223            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
224
225            pcmParams->nChannels = mNumChannels;
226            pcmParams->nSamplingRate = mSampleRate;
227
228            return OMX_ErrorNone;
229        }
230
231        default:
232            return SimpleSoftOMXComponent::internalGetParameter(index, params);
233    }
234}
235
236OMX_ERRORTYPE SoftAACEncoder::internalSetParameter(
237        OMX_INDEXTYPE index, const OMX_PTR params) {
238    switch (index) {
239        case OMX_IndexParamStandardComponentRole:
240        {
241            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
242                (const OMX_PARAM_COMPONENTROLETYPE *)params;
243
244            if (!isValidOMXParam(roleParams)) {
245                return OMX_ErrorBadParameter;
246            }
247
248            if (strncmp((const char *)roleParams->cRole,
249                        "audio_encoder.aac",
250                        OMX_MAX_STRINGNAME_SIZE - 1)) {
251                return OMX_ErrorUndefined;
252            }
253
254            return OMX_ErrorNone;
255        }
256
257        case OMX_IndexParamAudioPortFormat:
258        {
259            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
260                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
261
262            if (!isValidOMXParam(formatParams)) {
263                return OMX_ErrorBadParameter;
264            }
265
266            if (formatParams->nPortIndex > 1) {
267                return OMX_ErrorUndefined;
268            }
269
270            if (formatParams->nIndex > 0) {
271                return OMX_ErrorNoMore;
272            }
273
274            if ((formatParams->nPortIndex == 0
275                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
276                || (formatParams->nPortIndex == 1
277                        && formatParams->eEncoding != OMX_AUDIO_CodingAAC)) {
278                return OMX_ErrorUndefined;
279            }
280
281            return OMX_ErrorNone;
282        }
283
284        case OMX_IndexParamAudioAac:
285        {
286            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
287                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
288
289            if (!isValidOMXParam(aacParams)) {
290                return OMX_ErrorBadParameter;
291            }
292
293            if (aacParams->nPortIndex != 1) {
294                return OMX_ErrorUndefined;
295            }
296
297            mBitRate = aacParams->nBitRate;
298            mNumChannels = aacParams->nChannels;
299            mSampleRate = aacParams->nSampleRate;
300
301            if (setAudioParams() != OK) {
302                return OMX_ErrorUndefined;
303            }
304
305            return OMX_ErrorNone;
306        }
307
308        case OMX_IndexParamAudioPcm:
309        {
310            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
311                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
312
313            if (!isValidOMXParam(pcmParams)) {
314                return OMX_ErrorBadParameter;
315            }
316
317            if (pcmParams->nPortIndex != 0) {
318                return OMX_ErrorUndefined;
319            }
320
321            mNumChannels = pcmParams->nChannels;
322            mSampleRate = pcmParams->nSamplingRate;
323
324            if (setAudioParams() != OK) {
325                return OMX_ErrorUndefined;
326            }
327
328            return OMX_ErrorNone;
329        }
330
331
332        default:
333            return SimpleSoftOMXComponent::internalSetParameter(index, params);
334    }
335}
336
337status_t SoftAACEncoder::setAudioParams() {
338    // We call this whenever sample rate, number of channels or bitrate change
339    // in reponse to setParameter calls.
340
341    ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps",
342         mSampleRate, mNumChannels, mBitRate);
343
344    status_t err = setAudioSpecificConfigData();
345
346    if (err != OK) {
347        return err;
348    }
349
350    AACENC_PARAM params;
351    memset(&params, 0, sizeof(params));
352    params.sampleRate = mSampleRate;
353    params.bitRate = mBitRate;
354    params.nChannels = mNumChannels;
355    params.adtsUsed = 0;  // We add adts header in the file writer if needed.
356    if (VO_ERR_NONE != mApiHandle->SetParam(
357                mEncoderHandle, VO_PID_AAC_ENCPARAM,  &params)) {
358        ALOGE("Failed to set AAC encoder parameters");
359        return UNKNOWN_ERROR;
360    }
361
362    return OK;
363}
364
365static status_t getSampleRateTableIndex(int32_t sampleRate, int32_t &index) {
366    static const int32_t kSampleRateTable[] = {
367        96000, 88200, 64000, 48000, 44100, 32000,
368        24000, 22050, 16000, 12000, 11025, 8000
369    };
370    const int32_t tableSize =
371        sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]);
372
373    for (int32_t i = 0; i < tableSize; ++i) {
374        if (sampleRate == kSampleRateTable[i]) {
375            index = i;
376            return OK;
377        }
378    }
379
380    return UNKNOWN_ERROR;
381}
382
383status_t SoftAACEncoder::setAudioSpecificConfigData() {
384    // The AAC encoder's audio specific config really only encodes
385    // number of channels and the sample rate (mapped to an index into
386    // a fixed sample rate table).
387
388    int32_t index;
389    status_t err = getSampleRateTableIndex(mSampleRate, index);
390    if (err != OK) {
391        ALOGE("Unsupported sample rate (%lu Hz)", mSampleRate);
392        return err;
393    }
394
395    if (mNumChannels > 2 || mNumChannels <= 0) {
396        ALOGE("Unsupported number of channels(%lu)", mNumChannels);
397        return UNKNOWN_ERROR;
398    }
399
400    // OMX_AUDIO_AACObjectLC
401    mAudioSpecificConfigData[0] = ((0x02 << 3) | (index >> 1));
402    mAudioSpecificConfigData[1] = ((index & 0x01) << 7) | (mNumChannels << 3);
403
404    return OK;
405}
406
407void SoftAACEncoder::onQueueFilled(OMX_U32 portIndex) {
408    if (mSignalledError) {
409        return;
410    }
411
412    List<BufferInfo *> &inQueue = getPortQueue(0);
413    List<BufferInfo *> &outQueue = getPortQueue(1);
414
415    if (!mSentCodecSpecificData) {
416        // The very first thing we want to output is the codec specific
417        // data. It does not require any input data but we will need an
418        // output buffer to store it in.
419
420        if (outQueue.empty()) {
421            return;
422        }
423
424        BufferInfo *outInfo = *outQueue.begin();
425        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
426        outHeader->nFilledLen = sizeof(mAudioSpecificConfigData);
427        outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
428
429        uint8_t *out = outHeader->pBuffer + outHeader->nOffset;
430        memcpy(out, mAudioSpecificConfigData, sizeof(mAudioSpecificConfigData));
431
432#if 0
433        ALOGI("sending codec specific data.");
434        hexdump(out, sizeof(mAudioSpecificConfigData));
435#endif
436
437        outQueue.erase(outQueue.begin());
438        outInfo->mOwnedByUs = false;
439        notifyFillBufferDone(outHeader);
440
441        mSentCodecSpecificData = true;
442    }
443
444    size_t numBytesPerInputFrame =
445        mNumChannels * kNumSamplesPerFrame * sizeof(int16_t);
446
447    for (;;) {
448        // We do the following until we run out of buffers.
449
450        while (mInputSize < numBytesPerInputFrame) {
451            // As long as there's still input data to be read we
452            // will drain "kNumSamplesPerFrame * mNumChannels" samples
453            // into the "mInputFrame" buffer and then encode those
454            // as a unit into an output buffer.
455
456            if (mSawInputEOS || inQueue.empty()) {
457                return;
458            }
459
460            BufferInfo *inInfo = *inQueue.begin();
461            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
462
463            const void *inData = inHeader->pBuffer + inHeader->nOffset;
464
465            size_t copy = numBytesPerInputFrame - mInputSize;
466            if (copy > inHeader->nFilledLen) {
467                copy = inHeader->nFilledLen;
468            }
469
470            if (mInputFrame == NULL) {
471                mInputFrame = new int16_t[kNumSamplesPerFrame * mNumChannels];
472            }
473
474            if (mInputSize == 0) {
475                mInputTimeUs = inHeader->nTimeStamp;
476            }
477
478            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
479            mInputSize += copy;
480
481            inHeader->nOffset += copy;
482            inHeader->nFilledLen -= copy;
483
484            // "Time" on the input buffer has in effect advanced by the
485            // number of audio frames we just advanced nOffset by.
486            inHeader->nTimeStamp +=
487                (copy * 1000000ll / mSampleRate)
488                    / (mNumChannels * sizeof(int16_t));
489
490            if (inHeader->nFilledLen == 0) {
491                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
492                    ALOGV("saw input EOS");
493                    mSawInputEOS = true;
494
495                    // Pad any remaining data with zeroes.
496                    memset((uint8_t *)mInputFrame + mInputSize,
497                           0,
498                           numBytesPerInputFrame - mInputSize);
499
500                    mInputSize = numBytesPerInputFrame;
501                }
502
503                inQueue.erase(inQueue.begin());
504                inInfo->mOwnedByUs = false;
505                notifyEmptyBufferDone(inHeader);
506
507                inData = NULL;
508                inHeader = NULL;
509                inInfo = NULL;
510            }
511        }
512
513        // At this  point we have all the input data necessary to encode
514        // a single frame, all we need is an output buffer to store the result
515        // in.
516
517        if (outQueue.empty()) {
518            return;
519        }
520
521        BufferInfo *outInfo = *outQueue.begin();
522        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
523
524        VO_CODECBUFFER inputData;
525        memset(&inputData, 0, sizeof(inputData));
526        inputData.Buffer = (unsigned char *)mInputFrame;
527        inputData.Length = numBytesPerInputFrame;
528        CHECK(VO_ERR_NONE ==
529                mApiHandle->SetInputData(mEncoderHandle, &inputData));
530
531        VO_CODECBUFFER outputData;
532        memset(&outputData, 0, sizeof(outputData));
533        VO_AUDIO_OUTPUTINFO outputInfo;
534        memset(&outputInfo, 0, sizeof(outputInfo));
535
536        uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset;
537        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
538
539        VO_U32 ret = VO_ERR_NONE;
540        size_t nOutputBytes = 0;
541        do {
542            outputData.Buffer = outPtr;
543            outputData.Length = outAvailable - nOutputBytes;
544            ret = mApiHandle->GetOutputData(
545                    mEncoderHandle, &outputData, &outputInfo);
546            if (ret == VO_ERR_NONE) {
547                outPtr += outputData.Length;
548                nOutputBytes += outputData.Length;
549            }
550        } while (ret != VO_ERR_INPUT_BUFFER_SMALL);
551
552        outHeader->nFilledLen = nOutputBytes;
553
554        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
555
556        if (mSawInputEOS) {
557            // We also tag this output buffer with EOS if it corresponds
558            // to the final input buffer.
559            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
560        }
561
562        outHeader->nTimeStamp = mInputTimeUs;
563
564#if 0
565        ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
566              nOutputBytes, mInputTimeUs, outHeader->nFlags);
567
568        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
569#endif
570
571        outQueue.erase(outQueue.begin());
572        outInfo->mOwnedByUs = false;
573        notifyFillBufferDone(outHeader);
574
575        outHeader = NULL;
576        outInfo = NULL;
577
578        mInputSize = 0;
579    }
580}
581
582}  // namespace android
583
584android::SoftOMXComponent *createSoftOMXComponent(
585        const char *name, const OMX_CALLBACKTYPE *callbacks,
586        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
587    return new android::SoftAACEncoder(name, callbacks, appData, component);
588}
589