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