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