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 "SoftAACEncoder2"
19#include <utils/Log.h>
20
21#include "SoftAACEncoder2.h"
22#include <OMX_AudioExt.h>
23
24#include <media/stagefright/foundation/ADebug.h>
25#include <media/stagefright/foundation/hexdump.h>
26
27namespace android {
28
29template<class T>
30static void InitOMXParams(T *params) {
31    params->nSize = sizeof(T);
32    params->nVersion.s.nVersionMajor = 1;
33    params->nVersion.s.nVersionMinor = 0;
34    params->nVersion.s.nRevision = 0;
35    params->nVersion.s.nStep = 0;
36}
37
38SoftAACEncoder2::SoftAACEncoder2(
39        const char *name,
40        const OMX_CALLBACKTYPE *callbacks,
41        OMX_PTR appData,
42        OMX_COMPONENTTYPE **component)
43    : SimpleSoftOMXComponent(name, callbacks, appData, component),
44      mAACEncoder(NULL),
45      mNumChannels(1),
46      mSampleRate(44100),
47      mBitRate(0),
48      mSBRMode(-1),
49      mSBRRatio(0),
50      mAACProfile(OMX_AUDIO_AACObjectLC),
51      mSentCodecSpecificData(false),
52      mInputSize(0),
53      mInputFrame(NULL),
54      mInputTimeUs(-1ll),
55      mSawInputEOS(false),
56      mSignalledError(false) {
57    initPorts();
58    CHECK_EQ(initEncoder(), (status_t)OK);
59    setAudioParams();
60}
61
62SoftAACEncoder2::~SoftAACEncoder2() {
63    aacEncClose(&mAACEncoder);
64
65    delete[] mInputFrame;
66    mInputFrame = NULL;
67}
68
69void SoftAACEncoder2::initPorts() {
70    OMX_PARAM_PORTDEFINITIONTYPE def;
71    InitOMXParams(&def);
72
73    def.nPortIndex = 0;
74    def.eDir = OMX_DirInput;
75    def.nBufferCountMin = kNumBuffers;
76    def.nBufferCountActual = def.nBufferCountMin;
77    def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 2;
78    def.bEnabled = OMX_TRUE;
79    def.bPopulated = OMX_FALSE;
80    def.eDomain = OMX_PortDomainAudio;
81    def.bBuffersContiguous = OMX_FALSE;
82    def.nBufferAlignment = 1;
83
84    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
85    def.format.audio.pNativeRender = NULL;
86    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
87    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
88
89    addPort(def);
90
91    def.nPortIndex = 1;
92    def.eDir = OMX_DirOutput;
93    def.nBufferCountMin = kNumBuffers;
94    def.nBufferCountActual = def.nBufferCountMin;
95    def.nBufferSize = 8192;
96    def.bEnabled = OMX_TRUE;
97    def.bPopulated = OMX_FALSE;
98    def.eDomain = OMX_PortDomainAudio;
99    def.bBuffersContiguous = OMX_FALSE;
100    def.nBufferAlignment = 2;
101
102    def.format.audio.cMIMEType = const_cast<char *>("audio/aac");
103    def.format.audio.pNativeRender = NULL;
104    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
105    def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
106
107    addPort(def);
108}
109
110status_t SoftAACEncoder2::initEncoder() {
111    if (AACENC_OK != aacEncOpen(&mAACEncoder, 0, 0)) {
112        ALOGE("Failed to init AAC encoder");
113        return UNKNOWN_ERROR;
114    }
115    return OK;
116}
117
118OMX_ERRORTYPE SoftAACEncoder2::internalGetParameter(
119        OMX_INDEXTYPE index, OMX_PTR params) {
120    switch (index) {
121        case OMX_IndexParamAudioPortFormat:
122        {
123            OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
124                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
125
126            if (formatParams->nPortIndex > 1) {
127                return OMX_ErrorUndefined;
128            }
129
130            if (formatParams->nIndex > 0) {
131                return OMX_ErrorNoMore;
132            }
133
134            formatParams->eEncoding =
135                (formatParams->nPortIndex == 0)
136                    ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAAC;
137
138            return OMX_ErrorNone;
139        }
140
141        case OMX_IndexParamAudioAac:
142        {
143            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
144                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
145
146            if (aacParams->nPortIndex != 1) {
147                return OMX_ErrorUndefined;
148            }
149
150            aacParams->nBitRate = mBitRate;
151            aacParams->nAudioBandWidth = 0;
152            aacParams->nAACtools = 0;
153            aacParams->nAACERtools = 0;
154            aacParams->eAACProfile = (OMX_AUDIO_AACPROFILETYPE) mAACProfile;
155            aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
156            aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
157
158            aacParams->nChannels = mNumChannels;
159            aacParams->nSampleRate = mSampleRate;
160            aacParams->nFrameLength = 0;
161
162            switch (mSBRMode) {
163            case 1: // sbr on
164                switch (mSBRRatio) {
165                case 0:
166                    // set both OMX AAC tool flags
167                    aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidSSBR;
168                    aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidDSBR;
169                    break;
170                case 1:
171                    // set single-rate SBR active
172                    aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidSSBR;
173                    aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR;
174                    break;
175                case 2:
176                    // set dual-rate SBR active
177                    aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR;
178                    aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidDSBR;
179                    break;
180                default:
181                    ALOGE("invalid SBR ratio %d", mSBRRatio);
182                    TRESPASS();
183                }
184                break;
185            case 0:  // sbr off
186            case -1: // sbr undefined
187                aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR;
188                aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR;
189                break;
190            default:
191                ALOGE("invalid SBR mode %d", mSBRMode);
192                TRESPASS();
193            }
194
195
196
197            return OMX_ErrorNone;
198        }
199
200        case OMX_IndexParamAudioPcm:
201        {
202            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
203                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
204
205            if (pcmParams->nPortIndex != 0) {
206                return OMX_ErrorUndefined;
207            }
208
209            pcmParams->eNumData = OMX_NumericalDataSigned;
210            pcmParams->eEndian = OMX_EndianBig;
211            pcmParams->bInterleaved = OMX_TRUE;
212            pcmParams->nBitPerSample = 16;
213            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
214            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
215            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
216
217            pcmParams->nChannels = mNumChannels;
218            pcmParams->nSamplingRate = mSampleRate;
219
220            return OMX_ErrorNone;
221        }
222
223        default:
224            return SimpleSoftOMXComponent::internalGetParameter(index, params);
225    }
226}
227
228OMX_ERRORTYPE SoftAACEncoder2::internalSetParameter(
229        OMX_INDEXTYPE index, const OMX_PTR params) {
230    switch (index) {
231        case OMX_IndexParamStandardComponentRole:
232        {
233            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
234                (const OMX_PARAM_COMPONENTROLETYPE *)params;
235
236            if (strncmp((const char *)roleParams->cRole,
237                        "audio_encoder.aac",
238                        OMX_MAX_STRINGNAME_SIZE - 1)) {
239                return OMX_ErrorUndefined;
240            }
241
242            return OMX_ErrorNone;
243        }
244
245        case OMX_IndexParamAudioPortFormat:
246        {
247            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
248                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
249
250            if (formatParams->nPortIndex > 1) {
251                return OMX_ErrorUndefined;
252            }
253
254            if (formatParams->nIndex > 0) {
255                return OMX_ErrorNoMore;
256            }
257
258            if ((formatParams->nPortIndex == 0
259                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
260                || (formatParams->nPortIndex == 1
261                        && formatParams->eEncoding != OMX_AUDIO_CodingAAC)) {
262                return OMX_ErrorUndefined;
263            }
264
265            return OMX_ErrorNone;
266        }
267
268        case OMX_IndexParamAudioAac:
269        {
270            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
271                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
272
273            if (aacParams->nPortIndex != 1) {
274                return OMX_ErrorUndefined;
275            }
276
277            mBitRate = aacParams->nBitRate;
278            mNumChannels = aacParams->nChannels;
279            mSampleRate = aacParams->nSampleRate;
280            if (aacParams->eAACProfile != OMX_AUDIO_AACObjectNull) {
281                mAACProfile = aacParams->eAACProfile;
282            }
283
284            if (!(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR)
285                    && !(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) {
286                mSBRMode = 0;
287                mSBRRatio = 0;
288            } else if ((aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR)
289                    && !(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) {
290                mSBRMode = 1;
291                mSBRRatio = 1;
292            } else if (!(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR)
293                    && (aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) {
294                mSBRMode = 1;
295                mSBRRatio = 2;
296            } else {
297                mSBRMode = -1; // codec default sbr mode
298                mSBRRatio = 0;
299            }
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 (pcmParams->nPortIndex != 0) {
314                return OMX_ErrorUndefined;
315            }
316
317            mNumChannels = pcmParams->nChannels;
318            mSampleRate = pcmParams->nSamplingRate;
319            if (setAudioParams() != OK) {
320                return OMX_ErrorUndefined;
321            }
322
323            return OMX_ErrorNone;
324        }
325
326        default:
327            return SimpleSoftOMXComponent::internalSetParameter(index, params);
328    }
329}
330
331static CHANNEL_MODE getChannelMode(OMX_U32 nChannels) {
332    CHANNEL_MODE chMode = MODE_INVALID;
333    switch (nChannels) {
334        case 1: chMode = MODE_1; break;
335        case 2: chMode = MODE_2; break;
336        case 3: chMode = MODE_1_2; break;
337        case 4: chMode = MODE_1_2_1; break;
338        case 5: chMode = MODE_1_2_2; break;
339        case 6: chMode = MODE_1_2_2_1; break;
340        default: chMode = MODE_INVALID;
341    }
342    return chMode;
343}
344
345static AUDIO_OBJECT_TYPE getAOTFromProfile(OMX_U32 profile) {
346    if (profile == OMX_AUDIO_AACObjectLC) {
347        return AOT_AAC_LC;
348    } else if (profile == OMX_AUDIO_AACObjectHE) {
349        return AOT_SBR;
350    } else if (profile == OMX_AUDIO_AACObjectHE_PS) {
351        return AOT_PS;
352    } else if (profile == OMX_AUDIO_AACObjectLD) {
353        return AOT_ER_AAC_LD;
354    } else if (profile == OMX_AUDIO_AACObjectELD) {
355        return AOT_ER_AAC_ELD;
356    } else {
357        ALOGW("Unsupported AAC profile - defaulting to AAC-LC");
358        return AOT_AAC_LC;
359    }
360}
361
362status_t SoftAACEncoder2::setAudioParams() {
363    // We call this whenever sample rate, number of channels, bitrate or SBR mode change
364    // in reponse to setParameter calls.
365
366    ALOGV("setAudioParams: %u Hz, %u channels, %u bps, %i sbr mode, %i sbr ratio",
367         mSampleRate, mNumChannels, mBitRate, mSBRMode, mSBRRatio);
368
369    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT,
370            getAOTFromProfile(mAACProfile))) {
371        ALOGE("Failed to set AAC encoder parameters");
372        return UNKNOWN_ERROR;
373    }
374
375    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SAMPLERATE, mSampleRate)) {
376        ALOGE("Failed to set AAC encoder parameters");
377        return UNKNOWN_ERROR;
378    }
379    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_BITRATE, mBitRate)) {
380        ALOGE("Failed to set AAC encoder parameters");
381        return UNKNOWN_ERROR;
382    }
383    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_CHANNELMODE,
384            getChannelMode(mNumChannels))) {
385        ALOGE("Failed to set AAC encoder parameters");
386        return UNKNOWN_ERROR;
387    }
388    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_TRANSMUX, TT_MP4_RAW)) {
389        ALOGE("Failed to set AAC encoder parameters");
390        return UNKNOWN_ERROR;
391    }
392
393    if (mSBRMode != -1 && mAACProfile == OMX_AUDIO_AACObjectELD) {
394        if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_MODE, mSBRMode)) {
395            ALOGE("Failed to set AAC encoder parameters");
396            return UNKNOWN_ERROR;
397        }
398    }
399
400    /* SBR ratio parameter configurations:
401       0: Default configuration wherein SBR ratio is configured depending on audio object type by
402          the FDK.
403       1: Downsampled SBR (default for ELD)
404       2: Dualrate SBR (default for HE-AAC)
405     */
406    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_RATIO, mSBRRatio)) {
407        ALOGE("Failed to set AAC encoder parameters");
408        return UNKNOWN_ERROR;
409    }
410
411    return OK;
412}
413
414void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) {
415    if (mSignalledError) {
416        return;
417    }
418
419    List<BufferInfo *> &inQueue = getPortQueue(0);
420    List<BufferInfo *> &outQueue = getPortQueue(1);
421
422    if (!mSentCodecSpecificData) {
423        // The very first thing we want to output is the codec specific
424        // data. It does not require any input data but we will need an
425        // output buffer to store it in.
426
427        if (outQueue.empty()) {
428            return;
429        }
430
431        if (AACENC_OK != aacEncEncode(mAACEncoder, NULL, NULL, NULL, NULL)) {
432            ALOGE("Unable to initialize encoder for profile / sample-rate / bit-rate / channels");
433            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
434            mSignalledError = true;
435            return;
436        }
437
438        OMX_U32 actualBitRate  = aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE);
439        if (mBitRate != actualBitRate) {
440            ALOGW("Requested bitrate %u unsupported, using %u", mBitRate, actualBitRate);
441        }
442
443        AACENC_InfoStruct encInfo;
444        if (AACENC_OK != aacEncInfo(mAACEncoder, &encInfo)) {
445            ALOGE("Failed to get AAC encoder info");
446            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
447            mSignalledError = true;
448            return;
449        }
450
451        BufferInfo *outInfo = *outQueue.begin();
452        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
453        outHeader->nFilledLen = encInfo.confSize;
454        outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
455
456        uint8_t *out = outHeader->pBuffer + outHeader->nOffset;
457        memcpy(out, encInfo.confBuf, encInfo.confSize);
458
459        outQueue.erase(outQueue.begin());
460        outInfo->mOwnedByUs = false;
461        notifyFillBufferDone(outHeader);
462
463        mSentCodecSpecificData = true;
464    }
465
466    size_t numBytesPerInputFrame =
467        mNumChannels * kNumSamplesPerFrame * sizeof(int16_t);
468
469    // Limit input size so we only get one ELD frame
470    if (mAACProfile == OMX_AUDIO_AACObjectELD && numBytesPerInputFrame > 512) {
471        numBytesPerInputFrame = 512;
472    }
473
474    for (;;) {
475        // We do the following until we run out of buffers.
476
477        while (mInputSize < numBytesPerInputFrame) {
478            // As long as there's still input data to be read we
479            // will drain "kNumSamplesPerFrame * mNumChannels" samples
480            // into the "mInputFrame" buffer and then encode those
481            // as a unit into an output buffer.
482
483            if (mSawInputEOS || inQueue.empty()) {
484                return;
485            }
486
487            BufferInfo *inInfo = *inQueue.begin();
488            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
489
490            const void *inData = inHeader->pBuffer + inHeader->nOffset;
491
492            size_t copy = numBytesPerInputFrame - mInputSize;
493            if (copy > inHeader->nFilledLen) {
494                copy = inHeader->nFilledLen;
495            }
496
497            if (mInputFrame == NULL) {
498                mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
499            }
500
501            if (mInputSize == 0) {
502                mInputTimeUs = inHeader->nTimeStamp;
503            }
504
505            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
506            mInputSize += copy;
507
508            inHeader->nOffset += copy;
509            inHeader->nFilledLen -= copy;
510
511            // "Time" on the input buffer has in effect advanced by the
512            // number of audio frames we just advanced nOffset by.
513            inHeader->nTimeStamp +=
514                (copy * 1000000ll / mSampleRate)
515                    / (mNumChannels * sizeof(int16_t));
516
517            if (inHeader->nFilledLen == 0) {
518                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
519                    mSawInputEOS = true;
520
521                    // Pad any remaining data with zeroes.
522                    memset((uint8_t *)mInputFrame + mInputSize,
523                           0,
524                           numBytesPerInputFrame - mInputSize);
525
526                    mInputSize = numBytesPerInputFrame;
527                }
528
529                inQueue.erase(inQueue.begin());
530                inInfo->mOwnedByUs = false;
531                notifyEmptyBufferDone(inHeader);
532
533                inData = NULL;
534                inHeader = NULL;
535                inInfo = NULL;
536            }
537        }
538
539        // At this  point we have all the input data necessary to encode
540        // a single frame, all we need is an output buffer to store the result
541        // in.
542
543        if (outQueue.empty()) {
544            return;
545        }
546
547        BufferInfo *outInfo = *outQueue.begin();
548        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
549
550        uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset;
551        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
552
553        AACENC_InArgs inargs;
554        AACENC_OutArgs outargs;
555        memset(&inargs, 0, sizeof(inargs));
556        memset(&outargs, 0, sizeof(outargs));
557        inargs.numInSamples = numBytesPerInputFrame / sizeof(int16_t);
558
559        void* inBuffer[]        = { (unsigned char *)mInputFrame };
560        INT   inBufferIds[]     = { IN_AUDIO_DATA };
561        INT   inBufferSize[]    = { (INT)numBytesPerInputFrame };
562        INT   inBufferElSize[]  = { sizeof(int16_t) };
563
564        AACENC_BufDesc inBufDesc;
565        inBufDesc.numBufs           = sizeof(inBuffer) / sizeof(void*);
566        inBufDesc.bufs              = (void**)&inBuffer;
567        inBufDesc.bufferIdentifiers = inBufferIds;
568        inBufDesc.bufSizes          = inBufferSize;
569        inBufDesc.bufElSizes        = inBufferElSize;
570
571        void* outBuffer[]       = { outPtr };
572        INT   outBufferIds[]    = { OUT_BITSTREAM_DATA };
573        INT   outBufferSize[]   = { 0 };
574        INT   outBufferElSize[] = { sizeof(UCHAR) };
575
576        AACENC_BufDesc outBufDesc;
577        outBufDesc.numBufs           = sizeof(outBuffer) / sizeof(void*);
578        outBufDesc.bufs              = (void**)&outBuffer;
579        outBufDesc.bufferIdentifiers = outBufferIds;
580        outBufDesc.bufSizes          = outBufferSize;
581        outBufDesc.bufElSizes        = outBufferElSize;
582
583        // Encode the mInputFrame, which is treated as a modulo buffer
584        AACENC_ERROR encoderErr = AACENC_OK;
585        size_t nOutputBytes = 0;
586
587        do {
588            memset(&outargs, 0, sizeof(outargs));
589
590            outBuffer[0] = outPtr;
591            outBufferSize[0] = outAvailable - nOutputBytes;
592
593            encoderErr = aacEncEncode(mAACEncoder,
594                                      &inBufDesc,
595                                      &outBufDesc,
596                                      &inargs,
597                                      &outargs);
598
599            if (encoderErr == AACENC_OK) {
600                outPtr += outargs.numOutBytes;
601                nOutputBytes += outargs.numOutBytes;
602
603                if (outargs.numInSamples > 0) {
604                    int numRemainingSamples = inargs.numInSamples - outargs.numInSamples;
605                    if (numRemainingSamples > 0) {
606                        memmove(mInputFrame,
607                                &mInputFrame[outargs.numInSamples],
608                                sizeof(int16_t) * numRemainingSamples);
609                    }
610                    inargs.numInSamples -= outargs.numInSamples;
611                }
612            }
613        } while (encoderErr == AACENC_OK && inargs.numInSamples > 0);
614
615        outHeader->nFilledLen = nOutputBytes;
616
617        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
618
619        if (mSawInputEOS) {
620            // We also tag this output buffer with EOS if it corresponds
621            // to the final input buffer.
622            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
623        }
624
625        outHeader->nTimeStamp = mInputTimeUs;
626
627#if 0
628        ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
629              nOutputBytes, mInputTimeUs, outHeader->nFlags);
630
631        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
632#endif
633
634        outQueue.erase(outQueue.begin());
635        outInfo->mOwnedByUs = false;
636        notifyFillBufferDone(outHeader);
637
638        outHeader = NULL;
639        outInfo = NULL;
640
641        mInputSize = 0;
642    }
643}
644
645}  // namespace android
646
647android::SoftOMXComponent *createSoftOMXComponent(
648        const char *name, const OMX_CALLBACKTYPE *callbacks,
649        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
650    return new android::SoftAACEncoder2(name, callbacks, appData, component);
651}
652