SoftMP3.cpp revision 9a8ded7348c5b2302dd27b285b395416bc842c49
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 "SoftMP3" 19#include <utils/Log.h> 20 21#include "SoftMP3.h" 22 23#include <media/stagefright/foundation/ADebug.h> 24#include <media/stagefright/MediaDefs.h> 25 26#include "include/pvmp3decoder_api.h" 27 28namespace android { 29 30template<class T> 31static void InitOMXParams(T *params) { 32 params->nSize = sizeof(T); 33 params->nVersion.s.nVersionMajor = 1; 34 params->nVersion.s.nVersionMinor = 0; 35 params->nVersion.s.nRevision = 0; 36 params->nVersion.s.nStep = 0; 37} 38 39SoftMP3::SoftMP3( 40 const char *name, 41 const OMX_CALLBACKTYPE *callbacks, 42 OMX_PTR appData, 43 OMX_COMPONENTTYPE **component) 44 : SimpleSoftOMXComponent(name, callbacks, appData, component), 45 mConfig(new tPVMP3DecoderExternal), 46 mDecoderBuf(NULL), 47 mAnchorTimeUs(0), 48 mNumFramesOutput(0), 49 mNumChannels(2), 50 mSamplingRate(44100), 51 mSignalledError(false), 52 mOutputPortSettingsChange(NONE) { 53 initPorts(); 54 initDecoder(); 55} 56 57SoftMP3::~SoftMP3() { 58 if (mDecoderBuf != NULL) { 59 free(mDecoderBuf); 60 mDecoderBuf = NULL; 61 } 62 63 delete mConfig; 64 mConfig = NULL; 65} 66 67void SoftMP3::initPorts() { 68 OMX_PARAM_PORTDEFINITIONTYPE def; 69 InitOMXParams(&def); 70 71 def.nPortIndex = 0; 72 def.eDir = OMX_DirInput; 73 def.nBufferCountMin = kNumBuffers; 74 def.nBufferCountActual = def.nBufferCountMin; 75 def.nBufferSize = 8192; 76 def.bEnabled = OMX_TRUE; 77 def.bPopulated = OMX_FALSE; 78 def.eDomain = OMX_PortDomainAudio; 79 def.bBuffersContiguous = OMX_FALSE; 80 def.nBufferAlignment = 1; 81 82 def.format.audio.cMIMEType = 83 const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MPEG); 84 85 def.format.audio.pNativeRender = NULL; 86 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 87 def.format.audio.eEncoding = OMX_AUDIO_CodingMP3; 88 89 addPort(def); 90 91 def.nPortIndex = 1; 92 def.eDir = OMX_DirOutput; 93 def.nBufferCountMin = kNumBuffers; 94 def.nBufferCountActual = def.nBufferCountMin; 95 def.nBufferSize = kOutputBufferSize; 96 def.bEnabled = OMX_TRUE; 97 def.bPopulated = OMX_FALSE; 98 def.eDomain = OMX_PortDomainAudio; 99 def.bBuffersContiguous = OMX_FALSE; 100 def.nBufferAlignment = 2; 101 102 def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); 103 def.format.audio.pNativeRender = NULL; 104 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 105 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; 106 107 addPort(def); 108} 109 110void SoftMP3::initDecoder() { 111 mConfig->equalizerType = flat; 112 mConfig->crcEnabled = false; 113 114 uint32_t memRequirements = pvmp3_decoderMemRequirements(); 115 mDecoderBuf = malloc(memRequirements); 116 117 pvmp3_InitDecoder(mConfig, mDecoderBuf); 118} 119 120OMX_ERRORTYPE SoftMP3::internalGetParameter( 121 OMX_INDEXTYPE index, OMX_PTR params) { 122 switch (index) { 123 case OMX_IndexParamAudioPcm: 124 { 125 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 126 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 127 128 if (pcmParams->nPortIndex > 1) { 129 return OMX_ErrorUndefined; 130 } 131 132 pcmParams->eNumData = OMX_NumericalDataSigned; 133 pcmParams->eEndian = OMX_EndianBig; 134 pcmParams->bInterleaved = OMX_TRUE; 135 pcmParams->nBitPerSample = 16; 136 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; 137 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; 138 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; 139 140 pcmParams->nChannels = mNumChannels; 141 pcmParams->nSamplingRate = mSamplingRate; 142 143 return OMX_ErrorNone; 144 } 145 146 default: 147 return SimpleSoftOMXComponent::internalGetParameter(index, params); 148 } 149} 150 151OMX_ERRORTYPE SoftMP3::internalSetParameter( 152 OMX_INDEXTYPE index, const OMX_PTR params) { 153 switch (index) { 154 case OMX_IndexParamStandardComponentRole: 155 { 156 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 157 (const OMX_PARAM_COMPONENTROLETYPE *)params; 158 159 if (strncmp((const char *)roleParams->cRole, 160 "audio_decoder.mp3", 161 OMX_MAX_STRINGNAME_SIZE - 1)) { 162 return OMX_ErrorUndefined; 163 } 164 165 return OMX_ErrorNone; 166 } 167 168 default: 169 return SimpleSoftOMXComponent::internalSetParameter(index, params); 170 } 171} 172 173void SoftMP3::onQueueFilled(OMX_U32 portIndex) { 174 if (mSignalledError || mOutputPortSettingsChange != NONE) { 175 return; 176 } 177 178 List<BufferInfo *> &inQueue = getPortQueue(0); 179 List<BufferInfo *> &outQueue = getPortQueue(1); 180 181 while (!inQueue.empty() && !outQueue.empty()) { 182 BufferInfo *inInfo = *inQueue.begin(); 183 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 184 185 BufferInfo *outInfo = *outQueue.begin(); 186 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 187 188 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 189 inQueue.erase(inQueue.begin()); 190 inInfo->mOwnedByUs = false; 191 notifyEmptyBufferDone(inHeader); 192 193 outHeader->nFilledLen = 0; 194 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 195 196 outQueue.erase(outQueue.begin()); 197 outInfo->mOwnedByUs = false; 198 notifyFillBufferDone(outHeader); 199 return; 200 } 201 202 if (inHeader->nOffset == 0) { 203 mAnchorTimeUs = inHeader->nTimeStamp; 204 mNumFramesOutput = 0; 205 } 206 207 mConfig->pInputBuffer = 208 inHeader->pBuffer + inHeader->nOffset; 209 210 mConfig->inputBufferCurrentLength = inHeader->nFilledLen; 211 mConfig->inputBufferMaxLength = 0; 212 mConfig->inputBufferUsedLength = 0; 213 214 mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t); 215 216 mConfig->pOutputBuffer = 217 reinterpret_cast<int16_t *>(outHeader->pBuffer); 218 219 ERROR_CODE decoderErr; 220 if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf)) 221 != NO_DECODING_ERROR) { 222 ALOGV("mp3 decoder returned error %d", decoderErr); 223 224 if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR || 225 mConfig->outputFrameSize == 0) { 226 ALOGE("mp3 decoder returned error %d", decoderErr); 227 228 if (mConfig->outputFrameSize == 0) { 229 ALOGE("Output frame size is 0"); 230 } 231 232 notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); 233 mSignalledError = true; 234 return; 235 } 236 237 // This is recoverable, just ignore the current frame and 238 // play silence instead. 239 memset(outHeader->pBuffer, 240 0, 241 mConfig->outputFrameSize * sizeof(int16_t)); 242 243 mConfig->inputBufferUsedLength = inHeader->nFilledLen; 244 } else if (mConfig->samplingRate != mSamplingRate 245 || mConfig->num_channels != mNumChannels) { 246 mSamplingRate = mConfig->samplingRate; 247 mNumChannels = mConfig->num_channels; 248 249 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 250 mOutputPortSettingsChange = AWAITING_DISABLED; 251 return; 252 } 253 254 outHeader->nOffset = 0; 255 outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t); 256 257 outHeader->nTimeStamp = 258 mAnchorTimeUs 259 + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate; 260 261 outHeader->nFlags = 0; 262 263 CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength); 264 265 inHeader->nOffset += mConfig->inputBufferUsedLength; 266 inHeader->nFilledLen -= mConfig->inputBufferUsedLength; 267 268 mNumFramesOutput += mConfig->outputFrameSize / mNumChannels; 269 270 if (inHeader->nFilledLen == 0) { 271 inInfo->mOwnedByUs = false; 272 inQueue.erase(inQueue.begin()); 273 inInfo = NULL; 274 notifyEmptyBufferDone(inHeader); 275 inHeader = NULL; 276 } 277 278 outInfo->mOwnedByUs = false; 279 outQueue.erase(outQueue.begin()); 280 outInfo = NULL; 281 notifyFillBufferDone(outHeader); 282 outHeader = NULL; 283 } 284} 285 286void SoftMP3::onPortFlushCompleted(OMX_U32 portIndex) { 287 if (portIndex == 0) { 288 // Make sure that the next buffer output does not still 289 // depend on fragments from the last one decoded. 290 pvmp3_InitDecoder(mConfig, mDecoderBuf); 291 } 292} 293 294void SoftMP3::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { 295 if (portIndex != 1) { 296 return; 297 } 298 299 switch (mOutputPortSettingsChange) { 300 case NONE: 301 break; 302 303 case AWAITING_DISABLED: 304 { 305 CHECK(!enabled); 306 mOutputPortSettingsChange = AWAITING_ENABLED; 307 break; 308 } 309 310 default: 311 { 312 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); 313 CHECK(enabled); 314 mOutputPortSettingsChange = NONE; 315 break; 316 } 317 } 318} 319 320} // namespace android 321 322android::SoftOMXComponent *createSoftOMXComponent( 323 const char *name, const OMX_CALLBACKTYPE *callbacks, 324 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 325 return new android::SoftMP3(name, callbacks, appData, component); 326} 327