Home | History | Annotate | Download | only in aacenc
      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 
     29 namespace android {
     30 
     31 template<class T>
     32 static 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 
     40 SoftAACEncoder::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 
     64 SoftAACEncoder::~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 
     80 void 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 
    121 status_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 
    149 OMX_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 
    224 OMX_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 
    309 status_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 
    337 static 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 
    355 status_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 
    379 void 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 
    556 android::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