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