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