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