SoftAACEncoder.cpp revision 2b1892db4a2ab47bfc09e59a4c11751aea99e4ea
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 (formatParams->nPortIndex > 1) {
158                return OMX_ErrorUndefined;
159            }
160
161            if (formatParams->nIndex > 0) {
162                return OMX_ErrorNoMore;
163            }
164
165            formatParams->eEncoding =
166                (formatParams->nPortIndex == 0)
167                    ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAAC;
168
169            return OMX_ErrorNone;
170        }
171
172        case OMX_IndexParamAudioAac:
173        {
174            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
175                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
176
177            if (aacParams->nPortIndex != 1) {
178                return OMX_ErrorUndefined;
179            }
180
181            aacParams->nBitRate = mBitRate;
182            aacParams->nAudioBandWidth = 0;
183            aacParams->nAACtools = 0;
184            aacParams->nAACERtools = 0;
185            aacParams->eAACProfile = OMX_AUDIO_AACObjectMain;
186            aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
187            aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
188
189            aacParams->nChannels = mNumChannels;
190            aacParams->nSampleRate = mSampleRate;
191            aacParams->nFrameLength = 0;
192
193            return OMX_ErrorNone;
194        }
195
196        case OMX_IndexParamAudioPcm:
197        {
198            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
199                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
200
201            if (pcmParams->nPortIndex != 0) {
202                return OMX_ErrorUndefined;
203            }
204
205            pcmParams->eNumData = OMX_NumericalDataSigned;
206            pcmParams->eEndian = OMX_EndianBig;
207            pcmParams->bInterleaved = OMX_TRUE;
208            pcmParams->nBitPerSample = 16;
209            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
210            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
211            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
212
213            pcmParams->nChannels = mNumChannels;
214            pcmParams->nSamplingRate = mSampleRate;
215
216            return OMX_ErrorNone;
217        }
218
219        default:
220            return SimpleSoftOMXComponent::internalGetParameter(index, params);
221    }
222}
223
224OMX_ERRORTYPE SoftAACEncoder::internalSetParameter(
225        OMX_INDEXTYPE index, const OMX_PTR params) {
226    switch (index) {
227        case OMX_IndexParamStandardComponentRole:
228        {
229            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
230                (const OMX_PARAM_COMPONENTROLETYPE *)params;
231
232            if (strncmp((const char *)roleParams->cRole,
233                        "audio_encoder.aac",
234                        OMX_MAX_STRINGNAME_SIZE - 1)) {
235                return OMX_ErrorUndefined;
236            }
237
238            return OMX_ErrorNone;
239        }
240
241        case OMX_IndexParamAudioPortFormat:
242        {
243            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
244                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
245
246            if (formatParams->nPortIndex > 1) {
247                return OMX_ErrorUndefined;
248            }
249
250            if (formatParams->nIndex > 0) {
251                return OMX_ErrorNoMore;
252            }
253
254            if ((formatParams->nPortIndex == 0
255                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
256                || (formatParams->nPortIndex == 1
257                        && formatParams->eEncoding != OMX_AUDIO_CodingAAC)) {
258                return OMX_ErrorUndefined;
259            }
260
261            return OMX_ErrorNone;
262        }
263
264        case OMX_IndexParamAudioAac:
265        {
266            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
267                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
268
269            if (aacParams->nPortIndex != 1) {
270                return OMX_ErrorUndefined;
271            }
272
273            mBitRate = aacParams->nBitRate;
274            mNumChannels = aacParams->nChannels;
275            mSampleRate = aacParams->nSampleRate;
276
277            if (setAudioParams() != OK) {
278                return OMX_ErrorUndefined;
279            }
280
281            return OMX_ErrorNone;
282        }
283
284        case OMX_IndexParamAudioPcm:
285        {
286            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
287                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
288
289            if (pcmParams->nPortIndex != 0) {
290                return OMX_ErrorUndefined;
291            }
292
293            mNumChannels = pcmParams->nChannels;
294            mSampleRate = pcmParams->nSamplingRate;
295
296            if (setAudioParams() != OK) {
297                return OMX_ErrorUndefined;
298            }
299
300            return OMX_ErrorNone;
301        }
302
303
304        default:
305            return SimpleSoftOMXComponent::internalSetParameter(index, params);
306    }
307}
308
309status_t SoftAACEncoder::setAudioParams() {
310    // We call this whenever sample rate, number of channels or bitrate change
311    // in reponse to setParameter calls.
312
313    ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps",
314         mSampleRate, mNumChannels, mBitRate);
315
316    status_t err = setAudioSpecificConfigData();
317
318    if (err != OK) {
319        return err;
320    }
321
322    AACENC_PARAM params;
323    memset(&params, 0, sizeof(params));
324    params.sampleRate = mSampleRate;
325    params.bitRate = mBitRate;
326    params.nChannels = mNumChannels;
327    params.adtsUsed = 0;  // We add adts header in the file writer if needed.
328    if (VO_ERR_NONE != mApiHandle->SetParam(
329                mEncoderHandle, VO_PID_AAC_ENCPARAM,  &params)) {
330        ALOGE("Failed to set AAC encoder parameters");
331        return UNKNOWN_ERROR;
332    }
333
334    return OK;
335}
336
337static status_t getSampleRateTableIndex(int32_t sampleRate, int32_t &index) {
338    static const int32_t kSampleRateTable[] = {
339        96000, 88200, 64000, 48000, 44100, 32000,
340        24000, 22050, 16000, 12000, 11025, 8000
341    };
342    const int32_t tableSize =
343        sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]);
344
345    for (int32_t i = 0; i < tableSize; ++i) {
346        if (sampleRate == kSampleRateTable[i]) {
347            index = i;
348            return OK;
349        }
350    }
351
352    return UNKNOWN_ERROR;
353}
354
355status_t SoftAACEncoder::setAudioSpecificConfigData() {
356    // The AAC encoder's audio specific config really only encodes
357    // number of channels and the sample rate (mapped to an index into
358    // a fixed sample rate table).
359
360    int32_t index;
361    status_t err = getSampleRateTableIndex(mSampleRate, index);
362    if (err != OK) {
363        ALOGE("Unsupported sample rate (%lu Hz)", mSampleRate);
364        return err;
365    }
366
367    if (mNumChannels > 2 || mNumChannels <= 0) {
368        ALOGE("Unsupported number of channels(%lu)", mNumChannels);
369        return UNKNOWN_ERROR;
370    }
371
372    // OMX_AUDIO_AACObjectLC
373    mAudioSpecificConfigData[0] = ((0x02 << 3) | (index >> 1));
374    mAudioSpecificConfigData[1] = ((index & 0x01) << 7) | (mNumChannels << 3);
375
376    return OK;
377}
378
379void SoftAACEncoder::onQueueFilled(OMX_U32 portIndex) {
380    if (mSignalledError) {
381        return;
382    }
383
384    List<BufferInfo *> &inQueue = getPortQueue(0);
385    List<BufferInfo *> &outQueue = getPortQueue(1);
386
387    if (!mSentCodecSpecificData) {
388        // The very first thing we want to output is the codec specific
389        // data. It does not require any input data but we will need an
390        // output buffer to store it in.
391
392        if (outQueue.empty()) {
393            return;
394        }
395
396        BufferInfo *outInfo = *outQueue.begin();
397        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
398        outHeader->nFilledLen = sizeof(mAudioSpecificConfigData);
399        outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
400
401        uint8_t *out = outHeader->pBuffer + outHeader->nOffset;
402        memcpy(out, mAudioSpecificConfigData, sizeof(mAudioSpecificConfigData));
403
404#if 0
405        ALOGI("sending codec specific data.");
406        hexdump(out, sizeof(mAudioSpecificConfigData));
407#endif
408
409        outQueue.erase(outQueue.begin());
410        outInfo->mOwnedByUs = false;
411        notifyFillBufferDone(outHeader);
412
413        mSentCodecSpecificData = true;
414    }
415
416    size_t numBytesPerInputFrame =
417        mNumChannels * kNumSamplesPerFrame * sizeof(int16_t);
418
419    for (;;) {
420        // We do the following until we run out of buffers.
421
422        while (mInputSize < numBytesPerInputFrame) {
423            // As long as there's still input data to be read we
424            // will drain "kNumSamplesPerFrame * mNumChannels" samples
425            // into the "mInputFrame" buffer and then encode those
426            // as a unit into an output buffer.
427
428            if (mSawInputEOS || inQueue.empty()) {
429                return;
430            }
431
432            BufferInfo *inInfo = *inQueue.begin();
433            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
434
435            const void *inData = inHeader->pBuffer + inHeader->nOffset;
436
437            size_t copy = numBytesPerInputFrame - mInputSize;
438            if (copy > inHeader->nFilledLen) {
439                copy = inHeader->nFilledLen;
440            }
441
442            if (mInputFrame == NULL) {
443                mInputFrame = new int16_t[kNumSamplesPerFrame * mNumChannels];
444            }
445
446            if (mInputSize == 0) {
447                mInputTimeUs = inHeader->nTimeStamp;
448            }
449
450            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
451            mInputSize += copy;
452
453            inHeader->nOffset += copy;
454            inHeader->nFilledLen -= copy;
455
456            // "Time" on the input buffer has in effect advanced by the
457            // number of audio frames we just advanced nOffset by.
458            inHeader->nTimeStamp +=
459                (copy * 1000000ll / mSampleRate)
460                    / (mNumChannels * sizeof(int16_t));
461
462            if (inHeader->nFilledLen == 0) {
463                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
464                    ALOGV("saw input EOS");
465                    mSawInputEOS = true;
466
467                    // Pad any remaining data with zeroes.
468                    memset((uint8_t *)mInputFrame + mInputSize,
469                           0,
470                           numBytesPerInputFrame - mInputSize);
471
472                    mInputSize = numBytesPerInputFrame;
473                }
474
475                inQueue.erase(inQueue.begin());
476                inInfo->mOwnedByUs = false;
477                notifyEmptyBufferDone(inHeader);
478
479                inData = NULL;
480                inHeader = NULL;
481                inInfo = NULL;
482            }
483        }
484
485        // At this  point we have all the input data necessary to encode
486        // a single frame, all we need is an output buffer to store the result
487        // in.
488
489        if (outQueue.empty()) {
490            return;
491        }
492
493        BufferInfo *outInfo = *outQueue.begin();
494        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
495
496        VO_CODECBUFFER inputData;
497        memset(&inputData, 0, sizeof(inputData));
498        inputData.Buffer = (unsigned char *)mInputFrame;
499        inputData.Length = numBytesPerInputFrame;
500        CHECK(VO_ERR_NONE ==
501                mApiHandle->SetInputData(mEncoderHandle, &inputData));
502
503        VO_CODECBUFFER outputData;
504        memset(&outputData, 0, sizeof(outputData));
505        VO_AUDIO_OUTPUTINFO outputInfo;
506        memset(&outputInfo, 0, sizeof(outputInfo));
507
508        uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset;
509        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
510
511        VO_U32 ret = VO_ERR_NONE;
512        size_t nOutputBytes = 0;
513        do {
514            outputData.Buffer = outPtr;
515            outputData.Length = outAvailable - nOutputBytes;
516            ret = mApiHandle->GetOutputData(
517                    mEncoderHandle, &outputData, &outputInfo);
518            if (ret == VO_ERR_NONE) {
519                outPtr += outputData.Length;
520                nOutputBytes += outputData.Length;
521            }
522        } while (ret != VO_ERR_INPUT_BUFFER_SMALL);
523
524        outHeader->nFilledLen = nOutputBytes;
525
526        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
527
528        if (mSawInputEOS) {
529            // We also tag this output buffer with EOS if it corresponds
530            // to the final input buffer.
531            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
532        }
533
534        outHeader->nTimeStamp = mInputTimeUs;
535
536#if 0
537        ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
538              nOutputBytes, mInputTimeUs, outHeader->nFlags);
539
540        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
541#endif
542
543        outQueue.erase(outQueue.begin());
544        outInfo->mOwnedByUs = false;
545        notifyFillBufferDone(outHeader);
546
547        outHeader = NULL;
548        outInfo = NULL;
549
550        mInputSize = 0;
551    }
552}
553
554}  // namespace android
555
556android::SoftOMXComponent *createSoftOMXComponent(
557        const char *name, const OMX_CALLBACKTYPE *callbacks,
558        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
559    return new android::SoftAACEncoder(name, callbacks, appData, component);
560}
561