SoftVorbis.cpp revision b5ce7ae2857d0ab1767244b9f212f5f3799f5aba
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 = 8192; 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 278 ogg_buffer buf; 279 ogg_reference ref; 280 oggpack_buffer bits; 281 282 makeBitReader( 283 (const uint8_t *)data + 7, size - 7, 284 &buf, &ref, &bits); 285 286 if (mInputBufferCount == 0) { 287 CHECK(mVi == NULL); 288 mVi = new vorbis_info; 289 vorbis_info_init(mVi); 290 291 int ret = _vorbis_unpack_info(mVi, &bits); 292 if (ret != 0) { 293 notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL); 294 mSignalledError = true; 295 return; 296 } 297 } else { 298 int ret = _vorbis_unpack_books(mVi, &bits); 299 if (ret != 0) { 300 notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL); 301 mSignalledError = true; 302 return; 303 } 304 305 CHECK(mState == NULL); 306 mState = new vorbis_dsp_state; 307 CHECK_EQ(0, vorbis_dsp_init(mState, mVi)); 308 309 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 310 mOutputPortSettingsChange = AWAITING_DISABLED; 311 } 312 313 inQueue.erase(inQueue.begin()); 314 info->mOwnedByUs = false; 315 notifyEmptyBufferDone(header); 316 317 ++mInputBufferCount; 318 319 return; 320 } 321 322 while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) { 323 BufferInfo *inInfo = NULL; 324 OMX_BUFFERHEADERTYPE *inHeader = NULL; 325 if (!inQueue.empty()) { 326 inInfo = *inQueue.begin(); 327 inHeader = inInfo->mHeader; 328 } 329 330 BufferInfo *outInfo = *outQueue.begin(); 331 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 332 333 int32_t numPageSamples = 0; 334 335 if (inHeader) { 336 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 337 mSawInputEos = true; 338 } 339 340 if (inHeader->nFilledLen || !mSawInputEos) { 341 if (inHeader->nFilledLen < sizeof(numPageSamples)) { 342 notify(OMX_EventError, OMX_ErrorBadParameter, 0, NULL); 343 mSignalledError = true; 344 ALOGE("onQueueFilled, input header has nFilledLen %u, expected %zu", 345 inHeader->nFilledLen, sizeof(numPageSamples)); 346 return; 347 } 348 memcpy(&numPageSamples, 349 inHeader->pBuffer 350 + inHeader->nOffset + inHeader->nFilledLen - 4, 351 sizeof(numPageSamples)); 352 353 if (inHeader->nOffset == 0) { 354 mAnchorTimeUs = inHeader->nTimeStamp; 355 mNumFramesOutput = 0; 356 } 357 358 inHeader->nFilledLen -= sizeof(numPageSamples);; 359 } 360 } 361 362 if (numPageSamples >= 0) { 363 mNumFramesLeftOnPage = numPageSamples; 364 } 365 366 ogg_buffer buf; 367 buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL; 368 buf.size = inHeader ? inHeader->nFilledLen : 0; 369 buf.refcount = 1; 370 buf.ptr.owner = NULL; 371 372 ogg_reference ref; 373 ref.buffer = &buf; 374 ref.begin = 0; 375 ref.length = buf.size; 376 ref.next = NULL; 377 378 ogg_packet pack; 379 pack.packet = &ref; 380 pack.bytes = ref.length; 381 pack.b_o_s = 0; 382 pack.e_o_s = 0; 383 pack.granulepos = 0; 384 pack.packetno = 0; 385 386 int numFrames = 0; 387 388 outHeader->nFlags = 0; 389 int err = vorbis_dsp_synthesis(mState, &pack, 1); 390 if (err != 0) { 391 // FIXME temporary workaround for log spam 392#if !defined(__arm__) && !defined(__aarch64__) 393 ALOGV("vorbis_dsp_synthesis returned %d", err); 394#else 395 ALOGW("vorbis_dsp_synthesis returned %d", err); 396#endif 397 } else { 398 numFrames = vorbis_dsp_pcmout( 399 mState, (int16_t *)outHeader->pBuffer, 400 (kMaxNumSamplesPerBuffer / mVi->channels)); 401 402 if (numFrames < 0) { 403 ALOGE("vorbis_dsp_pcmout returned %d", numFrames); 404 numFrames = 0; 405 } 406 } 407 408 if (mNumFramesLeftOnPage >= 0) { 409 if (numFrames > mNumFramesLeftOnPage) { 410 ALOGV("discarding %d frames at end of page", 411 numFrames - mNumFramesLeftOnPage); 412 numFrames = mNumFramesLeftOnPage; 413 if (mSawInputEos) { 414 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 415 mSignalledOutputEos = true; 416 } 417 } 418 mNumFramesLeftOnPage -= numFrames; 419 } 420 421 outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels; 422 outHeader->nOffset = 0; 423 424 outHeader->nTimeStamp = 425 mAnchorTimeUs 426 + (mNumFramesOutput * 1000000ll) / mVi->rate; 427 428 mNumFramesOutput += numFrames; 429 430 if (inHeader) { 431 inInfo->mOwnedByUs = false; 432 inQueue.erase(inQueue.begin()); 433 inInfo = NULL; 434 notifyEmptyBufferDone(inHeader); 435 inHeader = NULL; 436 } 437 438 outInfo->mOwnedByUs = false; 439 outQueue.erase(outQueue.begin()); 440 outInfo = NULL; 441 notifyFillBufferDone(outHeader); 442 outHeader = NULL; 443 444 ++mInputBufferCount; 445 } 446} 447 448void SoftVorbis::onPortFlushCompleted(OMX_U32 portIndex) { 449 if (portIndex == 0 && mState != NULL) { 450 // Make sure that the next buffer output does not still 451 // depend on fragments from the last one decoded. 452 453 mNumFramesOutput = 0; 454 mSawInputEos = false; 455 mSignalledOutputEos = false; 456 mNumFramesLeftOnPage = -1; 457 vorbis_dsp_restart(mState); 458 } 459} 460 461void SoftVorbis::onReset() { 462 mInputBufferCount = 0; 463 mNumFramesOutput = 0; 464 if (mState != NULL) { 465 vorbis_dsp_clear(mState); 466 delete mState; 467 mState = NULL; 468 } 469 470 if (mVi != NULL) { 471 vorbis_info_clear(mVi); 472 delete mVi; 473 mVi = NULL; 474 } 475 476 mSawInputEos = false; 477 mSignalledOutputEos = false; 478 mSignalledError = false; 479 mOutputPortSettingsChange = NONE; 480} 481 482void SoftVorbis::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { 483 if (portIndex != 1) { 484 return; 485 } 486 487 switch (mOutputPortSettingsChange) { 488 case NONE: 489 break; 490 491 case AWAITING_DISABLED: 492 { 493 CHECK(!enabled); 494 mOutputPortSettingsChange = AWAITING_ENABLED; 495 break; 496 } 497 498 default: 499 { 500 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); 501 CHECK(enabled); 502 mOutputPortSettingsChange = NONE; 503 break; 504 } 505 } 506} 507 508} // namespace android 509 510android::SoftOMXComponent *createSoftOMXComponent( 511 const char *name, const OMX_CALLBACKTYPE *callbacks, 512 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 513 return new android::SoftVorbis(name, callbacks, appData, component); 514} 515