Home | History | Annotate | Download | only in dec
      1 /*
      2  * Copyright (C) 2011 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 "SoftVorbis"
     19 #include <utils/Log.h>
     20 
     21 #include "SoftVorbis.h"
     22 
     23 #include <media/stagefright/foundation/ADebug.h>
     24 #include <media/stagefright/MediaDefs.h>
     25 
     26 extern "C" {
     27     #include <Tremolo/codec_internal.h>
     28 
     29     int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb);
     30     int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb);
     31     int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb);
     32 }
     33 
     34 namespace android {
     35 
     36 template<class T>
     37 static void InitOMXParams(T *params) {
     38     params->nSize = sizeof(T);
     39     params->nVersion.s.nVersionMajor = 1;
     40     params->nVersion.s.nVersionMinor = 0;
     41     params->nVersion.s.nRevision = 0;
     42     params->nVersion.s.nStep = 0;
     43 }
     44 
     45 SoftVorbis::SoftVorbis(
     46         const char *name,
     47         const OMX_CALLBACKTYPE *callbacks,
     48         OMX_PTR appData,
     49         OMX_COMPONENTTYPE **component)
     50     : SimpleSoftOMXComponent(name, callbacks, appData, component),
     51       mInputBufferCount(0),
     52       mState(NULL),
     53       mVi(NULL),
     54       mAnchorTimeUs(0),
     55       mNumFramesOutput(0),
     56       mNumFramesLeftOnPage(-1),
     57       mSawInputEos(false),
     58       mSignalledOutputEos(false),
     59       mSignalledError(false),
     60       mOutputPortSettingsChange(NONE) {
     61     initPorts();
     62     CHECK_EQ(initDecoder(), (status_t)OK);
     63 }
     64 
     65 SoftVorbis::~SoftVorbis() {
     66     if (mState != NULL) {
     67         vorbis_dsp_clear(mState);
     68         delete mState;
     69         mState = NULL;
     70     }
     71 
     72     if (mVi != NULL) {
     73         vorbis_info_clear(mVi);
     74         delete mVi;
     75         mVi = NULL;
     76     }
     77 }
     78 
     79 void SoftVorbis::initPorts() {
     80     OMX_PARAM_PORTDEFINITIONTYPE def;
     81     InitOMXParams(&def);
     82 
     83     def.nPortIndex = 0;
     84     def.eDir = OMX_DirInput;
     85     def.nBufferCountMin = kNumBuffers;
     86     def.nBufferCountActual = def.nBufferCountMin;
     87     def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
     88     def.bEnabled = OMX_TRUE;
     89     def.bPopulated = OMX_FALSE;
     90     def.eDomain = OMX_PortDomainAudio;
     91     def.bBuffersContiguous = OMX_FALSE;
     92     def.nBufferAlignment = 1;
     93 
     94     def.format.audio.cMIMEType =
     95         const_cast<char *>(MEDIA_MIMETYPE_AUDIO_VORBIS);
     96 
     97     def.format.audio.pNativeRender = NULL;
     98     def.format.audio.bFlagErrorConcealment = OMX_FALSE;
     99     def.format.audio.eEncoding = OMX_AUDIO_CodingVORBIS;
    100 
    101     addPort(def);
    102 
    103     def.nPortIndex = 1;
    104     def.eDir = OMX_DirOutput;
    105     def.nBufferCountMin = kNumBuffers;
    106     def.nBufferCountActual = def.nBufferCountMin;
    107     def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
    108     def.bEnabled = OMX_TRUE;
    109     def.bPopulated = OMX_FALSE;
    110     def.eDomain = OMX_PortDomainAudio;
    111     def.bBuffersContiguous = OMX_FALSE;
    112     def.nBufferAlignment = 2;
    113 
    114     def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
    115     def.format.audio.pNativeRender = NULL;
    116     def.format.audio.bFlagErrorConcealment = OMX_FALSE;
    117     def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
    118 
    119     addPort(def);
    120 }
    121 
    122 status_t SoftVorbis::initDecoder() {
    123     return OK;
    124 }
    125 
    126 OMX_ERRORTYPE SoftVorbis::internalGetParameter(
    127         OMX_INDEXTYPE index, OMX_PTR params) {
    128     switch (index) {
    129         case OMX_IndexParamAudioVorbis:
    130         {
    131             OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
    132                 (OMX_AUDIO_PARAM_VORBISTYPE *)params;
    133 
    134             if (!isValidOMXParam(vorbisParams)) {
    135                 return OMX_ErrorBadParameter;
    136             }
    137 
    138             if (vorbisParams->nPortIndex != 0) {
    139                 return OMX_ErrorUndefined;
    140             }
    141 
    142             vorbisParams->nBitRate = 0;
    143             vorbisParams->nMinBitRate = 0;
    144             vorbisParams->nMaxBitRate = 0;
    145             vorbisParams->nAudioBandWidth = 0;
    146             vorbisParams->nQuality = 3;
    147             vorbisParams->bManaged = OMX_FALSE;
    148             vorbisParams->bDownmix = OMX_FALSE;
    149 
    150             if (!isConfigured()) {
    151                 vorbisParams->nChannels = 1;
    152                 vorbisParams->nSampleRate = 44100;
    153             } else {
    154                 vorbisParams->nChannels = mVi->channels;
    155                 vorbisParams->nSampleRate = mVi->rate;
    156                 vorbisParams->nBitRate = mVi->bitrate_nominal;
    157                 vorbisParams->nMinBitRate = mVi->bitrate_lower;
    158                 vorbisParams->nMaxBitRate = mVi->bitrate_upper;
    159             }
    160 
    161             return OMX_ErrorNone;
    162         }
    163 
    164         case OMX_IndexParamAudioPcm:
    165         {
    166             OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
    167                 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
    168 
    169             if (!isValidOMXParam(pcmParams)) {
    170                 return OMX_ErrorBadParameter;
    171             }
    172 
    173             if (pcmParams->nPortIndex != 1) {
    174                 return OMX_ErrorUndefined;
    175             }
    176 
    177             pcmParams->eNumData = OMX_NumericalDataSigned;
    178             pcmParams->eEndian = OMX_EndianBig;
    179             pcmParams->bInterleaved = OMX_TRUE;
    180             pcmParams->nBitPerSample = 16;
    181             pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
    182             pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
    183             pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
    184 
    185             if (!isConfigured()) {
    186                 pcmParams->nChannels = 1;
    187                 pcmParams->nSamplingRate = 44100;
    188             } else {
    189                 pcmParams->nChannels = mVi->channels;
    190                 pcmParams->nSamplingRate = mVi->rate;
    191             }
    192 
    193             return OMX_ErrorNone;
    194         }
    195 
    196         default:
    197             return SimpleSoftOMXComponent::internalGetParameter(index, params);
    198     }
    199 }
    200 
    201 OMX_ERRORTYPE SoftVorbis::internalSetParameter(
    202         OMX_INDEXTYPE index, const OMX_PTR params) {
    203     switch (index) {
    204         case OMX_IndexParamStandardComponentRole:
    205         {
    206             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
    207                 (const OMX_PARAM_COMPONENTROLETYPE *)params;
    208 
    209             if (!isValidOMXParam(roleParams)) {
    210                 return OMX_ErrorBadParameter;
    211             }
    212 
    213             if (strncmp((const char *)roleParams->cRole,
    214                         "audio_decoder.vorbis",
    215                         OMX_MAX_STRINGNAME_SIZE - 1)) {
    216                 return OMX_ErrorUndefined;
    217             }
    218 
    219             return OMX_ErrorNone;
    220         }
    221 
    222         case OMX_IndexParamAudioVorbis:
    223         {
    224             const OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
    225                 (const OMX_AUDIO_PARAM_VORBISTYPE *)params;
    226 
    227             if (!isValidOMXParam(vorbisParams)) {
    228                 return OMX_ErrorBadParameter;
    229             }
    230 
    231             if (vorbisParams->nPortIndex != 0) {
    232                 return OMX_ErrorUndefined;
    233             }
    234 
    235             return OMX_ErrorNone;
    236         }
    237 
    238         default:
    239             return SimpleSoftOMXComponent::internalSetParameter(index, params);
    240     }
    241 }
    242 
    243 bool SoftVorbis::isConfigured() const {
    244     return mInputBufferCount >= 2;
    245 }
    246 
    247 static void makeBitReader(
    248         const void *data, size_t size,
    249         ogg_buffer *buf, ogg_reference *ref, oggpack_buffer *bits) {
    250     buf->data = (uint8_t *)data;
    251     buf->size = size;
    252     buf->refcount = 1;
    253     buf->ptr.owner = NULL;
    254 
    255     ref->buffer = buf;
    256     ref->begin = 0;
    257     ref->length = size;
    258     ref->next = NULL;
    259 
    260     oggpack_readinit(bits, ref);
    261 }
    262 
    263 void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {
    264     List<BufferInfo *> &inQueue = getPortQueue(0);
    265     List<BufferInfo *> &outQueue = getPortQueue(1);
    266 
    267     if (mSignalledError || mOutputPortSettingsChange != NONE) {
    268         return;
    269     }
    270 
    271     if (portIndex == 0 && mInputBufferCount < 2) {
    272         BufferInfo *info = *inQueue.begin();
    273         OMX_BUFFERHEADERTYPE *header = info->mHeader;
    274 
    275         const uint8_t *data = header->pBuffer + header->nOffset;
    276         size_t size = header->nFilledLen;
    277         if (size < 7) {
    278             ALOGE("Too small input buffer: %zu bytes", size);
    279             android_errorWriteLog(0x534e4554, "27833616");
    280             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    281             mSignalledError = true;
    282             return;
    283         }
    284 
    285         ogg_buffer buf;
    286         ogg_reference ref;
    287         oggpack_buffer bits;
    288 
    289         makeBitReader(
    290                 (const uint8_t *)data + 7, size - 7,
    291                 &buf, &ref, &bits);
    292 
    293         if (mInputBufferCount == 0) {
    294             CHECK(mVi == NULL);
    295             mVi = new vorbis_info;
    296             vorbis_info_init(mVi);
    297 
    298             int ret = _vorbis_unpack_info(mVi, &bits);
    299             if (ret != 0) {
    300                 notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
    301                 mSignalledError = true;
    302                 return;
    303             }
    304         } else {
    305             int ret = _vorbis_unpack_books(mVi, &bits);
    306             if (ret != 0) {
    307                 notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
    308                 mSignalledError = true;
    309                 return;
    310             }
    311 
    312             CHECK(mState == NULL);
    313             mState = new vorbis_dsp_state;
    314             CHECK_EQ(0, vorbis_dsp_init(mState, mVi));
    315 
    316             notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
    317             mOutputPortSettingsChange = AWAITING_DISABLED;
    318         }
    319 
    320         inQueue.erase(inQueue.begin());
    321         info->mOwnedByUs = false;
    322         notifyEmptyBufferDone(header);
    323 
    324         ++mInputBufferCount;
    325 
    326         return;
    327     }
    328 
    329     while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
    330         BufferInfo *inInfo = NULL;
    331         OMX_BUFFERHEADERTYPE *inHeader = NULL;
    332         if (!inQueue.empty()) {
    333             inInfo = *inQueue.begin();
    334             inHeader = inInfo->mHeader;
    335         }
    336 
    337         BufferInfo *outInfo = *outQueue.begin();
    338         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
    339 
    340         int32_t numPageSamples = 0;
    341 
    342         if (inHeader) {
    343             if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    344                 mSawInputEos = true;
    345             }
    346 
    347             if (inHeader->nFilledLen || !mSawInputEos) {
    348                 if (inHeader->nFilledLen < sizeof(numPageSamples)) {
    349                     notify(OMX_EventError, OMX_ErrorBadParameter, 0, NULL);
    350                     mSignalledError = true;
    351                     ALOGE("onQueueFilled, input header has nFilledLen %u, expected %zu",
    352                             inHeader->nFilledLen, sizeof(numPageSamples));
    353                     return;
    354                 }
    355                 memcpy(&numPageSamples,
    356                        inHeader->pBuffer
    357                         + inHeader->nOffset + inHeader->nFilledLen - 4,
    358                        sizeof(numPageSamples));
    359 
    360                 if (inHeader->nOffset == 0) {
    361                     mAnchorTimeUs = inHeader->nTimeStamp;
    362                     mNumFramesOutput = 0;
    363                 }
    364 
    365                 inHeader->nFilledLen -= sizeof(numPageSamples);;
    366             }
    367         }
    368 
    369         if (numPageSamples >= 0) {
    370             mNumFramesLeftOnPage = numPageSamples;
    371         }
    372 
    373         ogg_buffer buf;
    374         buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL;
    375         buf.size = inHeader ? inHeader->nFilledLen : 0;
    376         buf.refcount = 1;
    377         buf.ptr.owner = NULL;
    378 
    379         ogg_reference ref;
    380         ref.buffer = &buf;
    381         ref.begin = 0;
    382         ref.length = buf.size;
    383         ref.next = NULL;
    384 
    385         ogg_packet pack;
    386         pack.packet = &ref;
    387         pack.bytes = ref.length;
    388         pack.b_o_s = 0;
    389         pack.e_o_s = 0;
    390         pack.granulepos = 0;
    391         pack.packetno = 0;
    392 
    393         int numFrames = 0;
    394 
    395         outHeader->nFlags = 0;
    396         int err = vorbis_dsp_synthesis(mState, &pack, 1);
    397         if (err != 0) {
    398             // FIXME temporary workaround for log spam
    399 #if !defined(__arm__) && !defined(__aarch64__)
    400             ALOGV("vorbis_dsp_synthesis returned %d", err);
    401 #else
    402             ALOGW("vorbis_dsp_synthesis returned %d", err);
    403 #endif
    404         } else {
    405             size_t numSamplesPerBuffer = kMaxNumSamplesPerBuffer;
    406             if (numSamplesPerBuffer > outHeader->nAllocLen / sizeof(int16_t)) {
    407                 numSamplesPerBuffer = outHeader->nAllocLen / sizeof(int16_t);
    408                 android_errorWriteLog(0x534e4554, "27833616");
    409             }
    410             numFrames = vorbis_dsp_pcmout(
    411                     mState, (int16_t *)outHeader->pBuffer,
    412                     (numSamplesPerBuffer / mVi->channels));
    413 
    414             if (numFrames < 0) {
    415                 ALOGE("vorbis_dsp_pcmout returned %d", numFrames);
    416                 numFrames = 0;
    417             }
    418         }
    419 
    420         if (mNumFramesLeftOnPage >= 0) {
    421             if (numFrames > mNumFramesLeftOnPage) {
    422                 ALOGV("discarding %d frames at end of page",
    423                      numFrames - mNumFramesLeftOnPage);
    424                 numFrames = mNumFramesLeftOnPage;
    425                 if (mSawInputEos) {
    426                     outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    427                     mSignalledOutputEos = true;
    428                 }
    429             }
    430             mNumFramesLeftOnPage -= numFrames;
    431         }
    432 
    433         outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels;
    434         outHeader->nOffset = 0;
    435 
    436         outHeader->nTimeStamp =
    437             mAnchorTimeUs
    438                 + (mNumFramesOutput * 1000000ll) / mVi->rate;
    439 
    440         mNumFramesOutput += numFrames;
    441 
    442         if (inHeader) {
    443             inInfo->mOwnedByUs = false;
    444             inQueue.erase(inQueue.begin());
    445             inInfo = NULL;
    446             notifyEmptyBufferDone(inHeader);
    447             inHeader = NULL;
    448         }
    449 
    450         outInfo->mOwnedByUs = false;
    451         outQueue.erase(outQueue.begin());
    452         outInfo = NULL;
    453         notifyFillBufferDone(outHeader);
    454         outHeader = NULL;
    455 
    456         ++mInputBufferCount;
    457     }
    458 }
    459 
    460 void SoftVorbis::onPortFlushCompleted(OMX_U32 portIndex) {
    461     if (portIndex == 0 && mState != NULL) {
    462         // Make sure that the next buffer output does not still
    463         // depend on fragments from the last one decoded.
    464 
    465         mNumFramesOutput = 0;
    466         mSawInputEos = false;
    467         mSignalledOutputEos = false;
    468         mNumFramesLeftOnPage = -1;
    469         vorbis_dsp_restart(mState);
    470     }
    471 }
    472 
    473 void SoftVorbis::onReset() {
    474     mInputBufferCount = 0;
    475     mNumFramesOutput = 0;
    476     if (mState != NULL) {
    477         vorbis_dsp_clear(mState);
    478         delete mState;
    479         mState = NULL;
    480     }
    481 
    482     if (mVi != NULL) {
    483         vorbis_info_clear(mVi);
    484         delete mVi;
    485         mVi = NULL;
    486     }
    487 
    488     mSawInputEos = false;
    489     mSignalledOutputEos = false;
    490     mSignalledError = false;
    491     mOutputPortSettingsChange = NONE;
    492 }
    493 
    494 void SoftVorbis::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
    495     if (portIndex != 1) {
    496         return;
    497     }
    498 
    499     switch (mOutputPortSettingsChange) {
    500         case NONE:
    501             break;
    502 
    503         case AWAITING_DISABLED:
    504         {
    505             CHECK(!enabled);
    506             mOutputPortSettingsChange = AWAITING_ENABLED;
    507             break;
    508         }
    509 
    510         default:
    511         {
    512             CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
    513             CHECK(enabled);
    514             mOutputPortSettingsChange = NONE;
    515             break;
    516         }
    517     }
    518 }
    519 
    520 }  // namespace android
    521 
    522 android::SoftOMXComponent *createSoftOMXComponent(
    523         const char *name, const OMX_CALLBACKTYPE *callbacks,
    524         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    525     return new android::SoftVorbis(name, callbacks, appData, component);
    526 }
    527