Home | History | Annotate | Download | only in amrwbenc
      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 
     28 namespace android {
     29 
     30 static const int32_t kSampleRate = 16000;
     31 
     32 template<class T>
     33 static 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 
     41 SoftAMRWBEncoder::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 
     60 SoftAMRWBEncoder::~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 
     73 void 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 
    114 status_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 
    150 OMX_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 (formatParams->nPortIndex > 1) {
    159                 return OMX_ErrorUndefined;
    160             }
    161 
    162             if (formatParams->nIndex > 0) {
    163                 return OMX_ErrorNoMore;
    164             }
    165 
    166             formatParams->eEncoding =
    167                 (formatParams->nPortIndex == 0)
    168                     ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR;
    169 
    170             return OMX_ErrorNone;
    171         }
    172 
    173         case OMX_IndexParamAudioAmr:
    174         {
    175             OMX_AUDIO_PARAM_AMRTYPE *amrParams =
    176                 (OMX_AUDIO_PARAM_AMRTYPE *)params;
    177 
    178             if (amrParams->nPortIndex != 1) {
    179                 return OMX_ErrorUndefined;
    180             }
    181 
    182             amrParams->nChannels = 1;
    183             amrParams->nBitRate = mBitRate;
    184 
    185             amrParams->eAMRBandMode =
    186                 (OMX_AUDIO_AMRBANDMODETYPE)(mMode + OMX_AUDIO_AMRBandModeWB0);
    187 
    188             amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
    189             amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
    190 
    191             return OMX_ErrorNone;
    192         }
    193 
    194         case OMX_IndexParamAudioPcm:
    195         {
    196             OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
    197                 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
    198 
    199             if (pcmParams->nPortIndex != 0) {
    200                 return OMX_ErrorUndefined;
    201             }
    202 
    203             pcmParams->eNumData = OMX_NumericalDataSigned;
    204             pcmParams->eEndian = OMX_EndianBig;
    205             pcmParams->bInterleaved = OMX_TRUE;
    206             pcmParams->nBitPerSample = 16;
    207             pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
    208             pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF;
    209 
    210             pcmParams->nChannels = 1;
    211             pcmParams->nSamplingRate = kSampleRate;
    212 
    213             return OMX_ErrorNone;
    214         }
    215 
    216         default:
    217             return SimpleSoftOMXComponent::internalGetParameter(index, params);
    218     }
    219 }
    220 
    221 OMX_ERRORTYPE SoftAMRWBEncoder::internalSetParameter(
    222         OMX_INDEXTYPE index, const OMX_PTR params) {
    223     switch (index) {
    224         case OMX_IndexParamStandardComponentRole:
    225         {
    226             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
    227                 (const OMX_PARAM_COMPONENTROLETYPE *)params;
    228 
    229             if (strncmp((const char *)roleParams->cRole,
    230                         "audio_encoder.amrwb",
    231                         OMX_MAX_STRINGNAME_SIZE - 1)) {
    232                 return OMX_ErrorUndefined;
    233             }
    234 
    235             return OMX_ErrorNone;
    236         }
    237 
    238         case OMX_IndexParamAudioPortFormat:
    239         {
    240             const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
    241                 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
    242 
    243             if (formatParams->nPortIndex > 1) {
    244                 return OMX_ErrorUndefined;
    245             }
    246 
    247             if (formatParams->nIndex > 0) {
    248                 return OMX_ErrorNoMore;
    249             }
    250 
    251             if ((formatParams->nPortIndex == 0
    252                         && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
    253                 || (formatParams->nPortIndex == 1
    254                         && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) {
    255                 return OMX_ErrorUndefined;
    256             }
    257 
    258             return OMX_ErrorNone;
    259         }
    260 
    261         case OMX_IndexParamAudioAmr:
    262         {
    263             OMX_AUDIO_PARAM_AMRTYPE *amrParams =
    264                 (OMX_AUDIO_PARAM_AMRTYPE *)params;
    265 
    266             if (amrParams->nPortIndex != 1) {
    267                 return OMX_ErrorUndefined;
    268             }
    269 
    270             if (amrParams->nChannels != 1
    271                     || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff
    272                     || amrParams->eAMRFrameFormat
    273                             != OMX_AUDIO_AMRFrameFormatFSF
    274                     || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeWB0
    275                     || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeWB8) {
    276                 return OMX_ErrorUndefined;
    277             }
    278 
    279             mBitRate = amrParams->nBitRate;
    280 
    281             mMode = (VOAMRWBMODE)(
    282                     amrParams->eAMRBandMode - OMX_AUDIO_AMRBandModeWB0);
    283 
    284             amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
    285             amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
    286 
    287             if (VO_ERR_NONE !=
    288                     mApiHandle->SetParam(
    289                         mEncoderHandle, VO_PID_AMRWB_MODE,  &mMode)) {
    290                 ALOGE("Failed to set AMRWB encoder mode to %d", mMode);
    291                 return OMX_ErrorUndefined;
    292             }
    293 
    294             return OMX_ErrorNone;
    295         }
    296 
    297         case OMX_IndexParamAudioPcm:
    298         {
    299             OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
    300                 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
    301 
    302             if (pcmParams->nPortIndex != 0) {
    303                 return OMX_ErrorUndefined;
    304             }
    305 
    306             if (pcmParams->nChannels != 1
    307                     || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) {
    308                 return OMX_ErrorUndefined;
    309             }
    310 
    311             return OMX_ErrorNone;
    312         }
    313 
    314 
    315         default:
    316             return SimpleSoftOMXComponent::internalSetParameter(index, params);
    317     }
    318 }
    319 
    320 void SoftAMRWBEncoder::onQueueFilled(OMX_U32 portIndex) {
    321     if (mSignalledError) {
    322         return;
    323     }
    324 
    325     List<BufferInfo *> &inQueue = getPortQueue(0);
    326     List<BufferInfo *> &outQueue = getPortQueue(1);
    327 
    328     size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t);
    329 
    330     for (;;) {
    331         // We do the following until we run out of buffers.
    332 
    333         while (mInputSize < numBytesPerInputFrame) {
    334             // As long as there's still input data to be read we
    335             // will drain "kNumSamplesPerFrame" samples
    336             // into the "mInputFrame" buffer and then encode those
    337             // as a unit into an output buffer.
    338 
    339             if (mSawInputEOS || inQueue.empty()) {
    340                 return;
    341             }
    342 
    343             BufferInfo *inInfo = *inQueue.begin();
    344             OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
    345 
    346             const void *inData = inHeader->pBuffer + inHeader->nOffset;
    347 
    348             size_t copy = numBytesPerInputFrame - mInputSize;
    349             if (copy > inHeader->nFilledLen) {
    350                 copy = inHeader->nFilledLen;
    351             }
    352 
    353             if (mInputSize == 0) {
    354                 mInputTimeUs = inHeader->nTimeStamp;
    355             }
    356 
    357             memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
    358             mInputSize += copy;
    359 
    360             inHeader->nOffset += copy;
    361             inHeader->nFilledLen -= copy;
    362 
    363             // "Time" on the input buffer has in effect advanced by the
    364             // number of audio frames we just advanced nOffset by.
    365             inHeader->nTimeStamp +=
    366                 (copy * 1000000ll / kSampleRate) / sizeof(int16_t);
    367 
    368             if (inHeader->nFilledLen == 0) {
    369                 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    370                     ALOGV("saw input EOS");
    371                     mSawInputEOS = true;
    372 
    373                     // Pad any remaining data with zeroes.
    374                     memset((uint8_t *)mInputFrame + mInputSize,
    375                            0,
    376                            numBytesPerInputFrame - mInputSize);
    377 
    378                     mInputSize = numBytesPerInputFrame;
    379                 }
    380 
    381                 inQueue.erase(inQueue.begin());
    382                 inInfo->mOwnedByUs = false;
    383                 notifyEmptyBufferDone(inHeader);
    384 
    385                 inData = NULL;
    386                 inHeader = NULL;
    387                 inInfo = NULL;
    388             }
    389         }
    390 
    391         // At this  point we have all the input data necessary to encode
    392         // a single frame, all we need is an output buffer to store the result
    393         // in.
    394 
    395         if (outQueue.empty()) {
    396             return;
    397         }
    398 
    399         BufferInfo *outInfo = *outQueue.begin();
    400         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
    401 
    402         uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset;
    403         size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
    404 
    405         VO_CODECBUFFER inputData;
    406         memset(&inputData, 0, sizeof(inputData));
    407         inputData.Buffer = (unsigned char *) mInputFrame;
    408         inputData.Length = mInputSize;
    409 
    410         CHECK_EQ(VO_ERR_NONE,
    411                  mApiHandle->SetInputData(mEncoderHandle, &inputData));
    412 
    413         VO_CODECBUFFER outputData;
    414         memset(&outputData, 0, sizeof(outputData));
    415         VO_AUDIO_OUTPUTINFO outputInfo;
    416         memset(&outputInfo, 0, sizeof(outputInfo));
    417 
    418         outputData.Buffer = outPtr;
    419         outputData.Length = outAvailable;
    420         VO_U32 ret = mApiHandle->GetOutputData(
    421                 mEncoderHandle, &outputData, &outputInfo);
    422         CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL);
    423 
    424         outHeader->nFilledLen = outputData.Length;
    425         outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
    426 
    427         if (mSawInputEOS) {
    428             // We also tag this output buffer with EOS if it corresponds
    429             // to the final input buffer.
    430             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    431         }
    432 
    433         outHeader->nTimeStamp = mInputTimeUs;
    434 
    435 #if 0
    436         ALOGI("sending %ld bytes of data (time = %lld us, flags = 0x%08lx)",
    437               outHeader->nFilledLen, mInputTimeUs, outHeader->nFlags);
    438 
    439         hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
    440 #endif
    441 
    442         outQueue.erase(outQueue.begin());
    443         outInfo->mOwnedByUs = false;
    444         notifyFillBufferDone(outHeader);
    445 
    446         outHeader = NULL;
    447         outInfo = NULL;
    448 
    449         mInputSize = 0;
    450     }
    451 }
    452 
    453 }  // namespace android
    454 
    455 android::SoftOMXComponent *createSoftOMXComponent(
    456         const char *name, const OMX_CALLBACKTYPE *callbacks,
    457         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    458     return new android::SoftAMRWBEncoder(name, callbacks, appData, component);
    459 }
    460