SoftVorbis.cpp revision 1277aea8405ea3256a2b0f730506c4610cadafa4
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 (vorbisParams->nPortIndex != 0) { 135 return OMX_ErrorUndefined; 136 } 137 138 vorbisParams->nBitRate = 0; 139 vorbisParams->nMinBitRate = 0; 140 vorbisParams->nMaxBitRate = 0; 141 vorbisParams->nAudioBandWidth = 0; 142 vorbisParams->nQuality = 3; 143 vorbisParams->bManaged = OMX_FALSE; 144 vorbisParams->bDownmix = OMX_FALSE; 145 146 if (!isConfigured()) { 147 vorbisParams->nChannels = 1; 148 vorbisParams->nSampleRate = 44100; 149 } else { 150 vorbisParams->nChannels = mVi->channels; 151 vorbisParams->nSampleRate = mVi->rate; 152 vorbisParams->nBitRate = mVi->bitrate_nominal; 153 vorbisParams->nMinBitRate = mVi->bitrate_lower; 154 vorbisParams->nMaxBitRate = mVi->bitrate_upper; 155 } 156 157 return OMX_ErrorNone; 158 } 159 160 case OMX_IndexParamAudioPcm: 161 { 162 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 163 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 164 165 if (pcmParams->nPortIndex != 1) { 166 return OMX_ErrorUndefined; 167 } 168 169 pcmParams->eNumData = OMX_NumericalDataSigned; 170 pcmParams->eEndian = OMX_EndianBig; 171 pcmParams->bInterleaved = OMX_TRUE; 172 pcmParams->nBitPerSample = 16; 173 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; 174 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; 175 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; 176 177 if (!isConfigured()) { 178 pcmParams->nChannels = 1; 179 pcmParams->nSamplingRate = 44100; 180 } else { 181 pcmParams->nChannels = mVi->channels; 182 pcmParams->nSamplingRate = mVi->rate; 183 } 184 185 return OMX_ErrorNone; 186 } 187 188 default: 189 return SimpleSoftOMXComponent::internalGetParameter(index, params); 190 } 191} 192 193OMX_ERRORTYPE SoftVorbis::internalSetParameter( 194 OMX_INDEXTYPE index, const OMX_PTR params) { 195 switch (index) { 196 case OMX_IndexParamStandardComponentRole: 197 { 198 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 199 (const OMX_PARAM_COMPONENTROLETYPE *)params; 200 201 if (strncmp((const char *)roleParams->cRole, 202 "audio_decoder.vorbis", 203 OMX_MAX_STRINGNAME_SIZE - 1)) { 204 return OMX_ErrorUndefined; 205 } 206 207 return OMX_ErrorNone; 208 } 209 210 case OMX_IndexParamAudioVorbis: 211 { 212 const OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams = 213 (const OMX_AUDIO_PARAM_VORBISTYPE *)params; 214 215 if (vorbisParams->nPortIndex != 0) { 216 return OMX_ErrorUndefined; 217 } 218 219 return OMX_ErrorNone; 220 } 221 222 default: 223 return SimpleSoftOMXComponent::internalSetParameter(index, params); 224 } 225} 226 227bool SoftVorbis::isConfigured() const { 228 return mInputBufferCount >= 2; 229} 230 231static void makeBitReader( 232 const void *data, size_t size, 233 ogg_buffer *buf, ogg_reference *ref, oggpack_buffer *bits) { 234 buf->data = (uint8_t *)data; 235 buf->size = size; 236 buf->refcount = 1; 237 buf->ptr.owner = NULL; 238 239 ref->buffer = buf; 240 ref->begin = 0; 241 ref->length = size; 242 ref->next = NULL; 243 244 oggpack_readinit(bits, ref); 245} 246 247void SoftVorbis::onQueueFilled(OMX_U32 portIndex) { 248 List<BufferInfo *> &inQueue = getPortQueue(0); 249 List<BufferInfo *> &outQueue = getPortQueue(1); 250 251 if (mSignalledError || mOutputPortSettingsChange != NONE) { 252 return; 253 } 254 255 if (portIndex == 0 && mInputBufferCount < 2) { 256 BufferInfo *info = *inQueue.begin(); 257 OMX_BUFFERHEADERTYPE *header = info->mHeader; 258 259 const uint8_t *data = header->pBuffer + header->nOffset; 260 size_t size = header->nFilledLen; 261 262 ogg_buffer buf; 263 ogg_reference ref; 264 oggpack_buffer bits; 265 266 makeBitReader( 267 (const uint8_t *)data + 7, size - 7, 268 &buf, &ref, &bits); 269 270 if (mInputBufferCount == 0) { 271 CHECK(mVi == NULL); 272 mVi = new vorbis_info; 273 vorbis_info_init(mVi); 274 275 int ret = _vorbis_unpack_info(mVi, &bits); 276 if (ret != 0) { 277 notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL); 278 mSignalledError = true; 279 return; 280 } 281 } else { 282 int ret = _vorbis_unpack_books(mVi, &bits); 283 if (ret != 0) { 284 notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL); 285 mSignalledError = true; 286 return; 287 } 288 289 CHECK(mState == NULL); 290 mState = new vorbis_dsp_state; 291 CHECK_EQ(0, vorbis_dsp_init(mState, mVi)); 292 293 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 294 mOutputPortSettingsChange = AWAITING_DISABLED; 295 } 296 297 inQueue.erase(inQueue.begin()); 298 info->mOwnedByUs = false; 299 notifyEmptyBufferDone(header); 300 301 ++mInputBufferCount; 302 303 return; 304 } 305 306 while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) { 307 BufferInfo *inInfo = NULL; 308 OMX_BUFFERHEADERTYPE *inHeader = NULL; 309 if (!inQueue.empty()) { 310 inInfo = *inQueue.begin(); 311 inHeader = inInfo->mHeader; 312 } 313 314 BufferInfo *outInfo = *outQueue.begin(); 315 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 316 317 int32_t numPageSamples = 0; 318 319 if (inHeader) { 320 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 321 mSawInputEos = true; 322 } 323 324 if (inHeader->nFilledLen || !mSawInputEos) { 325 CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples)); 326 memcpy(&numPageSamples, 327 inHeader->pBuffer 328 + inHeader->nOffset + inHeader->nFilledLen - 4, 329 sizeof(numPageSamples)); 330 331 if (inHeader->nOffset == 0) { 332 mAnchorTimeUs = inHeader->nTimeStamp; 333 mNumFramesOutput = 0; 334 } 335 336 inHeader->nFilledLen -= sizeof(numPageSamples);; 337 } 338 } 339 340 if (numPageSamples >= 0) { 341 mNumFramesLeftOnPage = numPageSamples; 342 } 343 344 ogg_buffer buf; 345 buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL; 346 buf.size = inHeader ? inHeader->nFilledLen : 0; 347 buf.refcount = 1; 348 buf.ptr.owner = NULL; 349 350 ogg_reference ref; 351 ref.buffer = &buf; 352 ref.begin = 0; 353 ref.length = buf.size; 354 ref.next = NULL; 355 356 ogg_packet pack; 357 pack.packet = &ref; 358 pack.bytes = ref.length; 359 pack.b_o_s = 0; 360 pack.e_o_s = 0; 361 pack.granulepos = 0; 362 pack.packetno = 0; 363 364 int numFrames = 0; 365 366 outHeader->nFlags = 0; 367 int err = vorbis_dsp_synthesis(mState, &pack, 1); 368 if (err != 0) { 369 // FIXME temporary workaround for log spam 370#if !defined(__arm__) && !defined(__aarch64__) 371 ALOGV("vorbis_dsp_synthesis returned %d", err); 372#else 373 ALOGW("vorbis_dsp_synthesis returned %d", err); 374#endif 375 } else { 376 numFrames = vorbis_dsp_pcmout( 377 mState, (int16_t *)outHeader->pBuffer, 378 (kMaxNumSamplesPerBuffer / mVi->channels)); 379 380 if (numFrames < 0) { 381 ALOGE("vorbis_dsp_pcmout returned %d", numFrames); 382 numFrames = 0; 383 } 384 } 385 386 if (mNumFramesLeftOnPage >= 0) { 387 if (numFrames > mNumFramesLeftOnPage) { 388 ALOGV("discarding %d frames at end of page", 389 numFrames - mNumFramesLeftOnPage); 390 numFrames = mNumFramesLeftOnPage; 391 if (mSawInputEos) { 392 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 393 mSignalledOutputEos = true; 394 } 395 } 396 mNumFramesLeftOnPage -= numFrames; 397 } 398 399 outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels; 400 outHeader->nOffset = 0; 401 402 outHeader->nTimeStamp = 403 mAnchorTimeUs 404 + (mNumFramesOutput * 1000000ll) / mVi->rate; 405 406 mNumFramesOutput += numFrames; 407 408 if (inHeader) { 409 inInfo->mOwnedByUs = false; 410 inQueue.erase(inQueue.begin()); 411 inInfo = NULL; 412 notifyEmptyBufferDone(inHeader); 413 inHeader = NULL; 414 } 415 416 outInfo->mOwnedByUs = false; 417 outQueue.erase(outQueue.begin()); 418 outInfo = NULL; 419 notifyFillBufferDone(outHeader); 420 outHeader = NULL; 421 422 ++mInputBufferCount; 423 } 424} 425 426void SoftVorbis::onPortFlushCompleted(OMX_U32 portIndex) { 427 if (portIndex == 0 && mState != NULL) { 428 // Make sure that the next buffer output does not still 429 // depend on fragments from the last one decoded. 430 431 mNumFramesOutput = 0; 432 vorbis_dsp_restart(mState); 433 } 434} 435 436void SoftVorbis::onReset() { 437 mInputBufferCount = 0; 438 mNumFramesOutput = 0; 439 if (mState != NULL) { 440 vorbis_dsp_clear(mState); 441 delete mState; 442 mState = NULL; 443 } 444 445 if (mVi != NULL) { 446 vorbis_info_clear(mVi); 447 delete mVi; 448 mVi = NULL; 449 } 450 451 mSawInputEos = false; 452 mSignalledOutputEos = false; 453 mSignalledError = false; 454 mOutputPortSettingsChange = NONE; 455} 456 457void SoftVorbis::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { 458 if (portIndex != 1) { 459 return; 460 } 461 462 switch (mOutputPortSettingsChange) { 463 case NONE: 464 break; 465 466 case AWAITING_DISABLED: 467 { 468 CHECK(!enabled); 469 mOutputPortSettingsChange = AWAITING_ENABLED; 470 break; 471 } 472 473 default: 474 { 475 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); 476 CHECK(enabled); 477 mOutputPortSettingsChange = NONE; 478 break; 479 } 480 } 481} 482 483} // namespace android 484 485android::SoftOMXComponent *createSoftOMXComponent( 486 const char *name, const OMX_CALLBACKTYPE *callbacks, 487 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 488 return new android::SoftVorbis(name, callbacks, appData, component); 489} 490