SoftVorbis.cpp revision d089c2540e4f0897c166693f4f13e2023241720e
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 (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 192OMX_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 226bool SoftVorbis::isConfigured() const { 227 return mInputBufferCount >= 2; 228} 229 230static 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 246void 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 ALOGW("vorbis_dsp_synthesis returned %d", err); 359 } else { 360 numFrames = vorbis_dsp_pcmout( 361 mState, (int16_t *)outHeader->pBuffer, 362 kMaxNumSamplesPerBuffer); 363 364 if (numFrames < 0) { 365 ALOGE("vorbis_dsp_pcmout returned %d", numFrames); 366 numFrames = 0; 367 } 368 } 369 370 if (mNumFramesLeftOnPage >= 0) { 371 if (numFrames > mNumFramesLeftOnPage) { 372 ALOGV("discarding %d frames at end of page", 373 numFrames - mNumFramesLeftOnPage); 374 numFrames = mNumFramesLeftOnPage; 375 if (mSawInputEos) { 376 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 377 mSignalledOutputEos = true; 378 } 379 } 380 mNumFramesLeftOnPage -= numFrames; 381 } 382 383 outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels; 384 outHeader->nOffset = 0; 385 386 outHeader->nTimeStamp = 387 mAnchorTimeUs 388 + (mNumFramesOutput * 1000000ll) / mVi->rate; 389 390 mNumFramesOutput += numFrames; 391 392 if (inHeader) { 393 inInfo->mOwnedByUs = false; 394 inQueue.erase(inQueue.begin()); 395 inInfo = NULL; 396 notifyEmptyBufferDone(inHeader); 397 inHeader = NULL; 398 } 399 400 outInfo->mOwnedByUs = false; 401 outQueue.erase(outQueue.begin()); 402 outInfo = NULL; 403 notifyFillBufferDone(outHeader); 404 outHeader = NULL; 405 406 ++mInputBufferCount; 407 } 408} 409 410void SoftVorbis::onPortFlushCompleted(OMX_U32 portIndex) { 411 if (portIndex == 0 && mState != NULL) { 412 // Make sure that the next buffer output does not still 413 // depend on fragments from the last one decoded. 414 415 mNumFramesOutput = 0; 416 vorbis_dsp_restart(mState); 417 } 418} 419 420void SoftVorbis::onReset() { 421 mInputBufferCount = 0; 422 mNumFramesOutput = 0; 423 if (mState != NULL) { 424 vorbis_dsp_clear(mState); 425 delete mState; 426 mState = NULL; 427 } 428 429 if (mVi != NULL) { 430 vorbis_info_clear(mVi); 431 delete mVi; 432 mVi = NULL; 433 } 434 435 mSawInputEos = false; 436 mSignalledOutputEos = false; 437 mOutputPortSettingsChange = NONE; 438} 439 440void SoftVorbis::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { 441 if (portIndex != 1) { 442 return; 443 } 444 445 switch (mOutputPortSettingsChange) { 446 case NONE: 447 break; 448 449 case AWAITING_DISABLED: 450 { 451 CHECK(!enabled); 452 mOutputPortSettingsChange = AWAITING_ENABLED; 453 break; 454 } 455 456 default: 457 { 458 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); 459 CHECK(enabled); 460 mOutputPortSettingsChange = NONE; 461 break; 462 } 463 } 464} 465 466} // namespace android 467 468android::SoftOMXComponent *createSoftOMXComponent( 469 const char *name, const OMX_CALLBACKTYPE *callbacks, 470 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 471 return new android::SoftVorbis(name, callbacks, appData, component); 472} 473