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