SoftAAC2.cpp revision 7c5abbb0e1b20df4b265a08a8560899f637f9b44
1/* 2 * Copyright (C) 2012 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_TAG "SoftAAC2" 18//#define LOG_NDEBUG 0 19#include <utils/Log.h> 20 21#include "SoftAAC2.h" 22 23#include <cutils/properties.h> 24#include <media/stagefright/foundation/ADebug.h> 25#include <media/stagefright/foundation/hexdump.h> 26#include <media/stagefright/MediaErrors.h> 27 28#define FILEREAD_MAX_LAYERS 2 29 30#define DRC_DEFAULT_MOBILE_REF_LEVEL 64 /* 64*-0.25dB = -16 dB below full scale for mobile conf */ 31#define DRC_DEFAULT_MOBILE_DRC_CUT 127 /* maximum compression of dynamic range for mobile conf */ 32#define MAX_CHANNEL_COUNT 6 /* maximum number of audio channels that can be decoded */ 33// names of properties that can be used to override the default DRC settings 34#define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level" 35#define PROP_DRC_OVERRIDE_CUT "aac_drc_cut" 36#define PROP_DRC_OVERRIDE_BOOST "aac_drc_boost" 37 38namespace android { 39 40template<class T> 41static void InitOMXParams(T *params) { 42 params->nSize = sizeof(T); 43 params->nVersion.s.nVersionMajor = 1; 44 params->nVersion.s.nVersionMinor = 0; 45 params->nVersion.s.nRevision = 0; 46 params->nVersion.s.nStep = 0; 47} 48 49SoftAAC2::SoftAAC2( 50 const char *name, 51 const OMX_CALLBACKTYPE *callbacks, 52 OMX_PTR appData, 53 OMX_COMPONENTTYPE **component) 54 : SimpleSoftOMXComponent(name, callbacks, appData, component), 55 mAACDecoder(NULL), 56 mStreamInfo(NULL), 57 mIsADTS(false), 58 mInputBufferCount(0), 59 mSignalledError(false), 60 mAnchorTimeUs(0), 61 mNumSamplesOutput(0), 62 mOutputPortSettingsChange(NONE) { 63 initPorts(); 64 CHECK_EQ(initDecoder(), (status_t)OK); 65} 66 67SoftAAC2::~SoftAAC2() { 68 aacDecoder_Close(mAACDecoder); 69} 70 71void SoftAAC2::initPorts() { 72 OMX_PARAM_PORTDEFINITIONTYPE def; 73 InitOMXParams(&def); 74 75 def.nPortIndex = 0; 76 def.eDir = OMX_DirInput; 77 def.nBufferCountMin = kNumInputBuffers; 78 def.nBufferCountActual = def.nBufferCountMin; 79 def.nBufferSize = 8192; 80 def.bEnabled = OMX_TRUE; 81 def.bPopulated = OMX_FALSE; 82 def.eDomain = OMX_PortDomainAudio; 83 def.bBuffersContiguous = OMX_FALSE; 84 def.nBufferAlignment = 1; 85 86 def.format.audio.cMIMEType = const_cast<char *>("audio/aac"); 87 def.format.audio.pNativeRender = NULL; 88 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 89 def.format.audio.eEncoding = OMX_AUDIO_CodingAAC; 90 91 addPort(def); 92 93 def.nPortIndex = 1; 94 def.eDir = OMX_DirOutput; 95 def.nBufferCountMin = kNumOutputBuffers; 96 def.nBufferCountActual = def.nBufferCountMin; 97 def.nBufferSize = 4096 * MAX_CHANNEL_COUNT; 98 def.bEnabled = OMX_TRUE; 99 def.bPopulated = OMX_FALSE; 100 def.eDomain = OMX_PortDomainAudio; 101 def.bBuffersContiguous = OMX_FALSE; 102 def.nBufferAlignment = 2; 103 104 def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); 105 def.format.audio.pNativeRender = NULL; 106 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 107 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; 108 109 addPort(def); 110} 111 112status_t SoftAAC2::initDecoder() { 113 status_t status = UNKNOWN_ERROR; 114 mAACDecoder = aacDecoder_Open(TT_MP4_ADIF, /* num layers */ 1); 115 if (mAACDecoder != NULL) { 116 mStreamInfo = aacDecoder_GetStreamInfo(mAACDecoder); 117 if (mStreamInfo != NULL) { 118 status = OK; 119 } 120 } 121 mDecoderHasData = false; 122 123 // for streams that contain metadata, use the mobile profile DRC settings unless overridden 124 // by platform properties: 125 char value[PROPERTY_VALUE_MAX]; 126 // * AAC_DRC_REFERENCE_LEVEL 127 if (property_get(PROP_DRC_OVERRIDE_REF_LEVEL, value, NULL)) { 128 unsigned refLevel = atoi(value); 129 ALOGV("AAC decoder using AAC_DRC_REFERENCE_LEVEL of %d instead of %d", 130 refLevel, DRC_DEFAULT_MOBILE_REF_LEVEL); 131 aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, refLevel); 132 } else { 133 aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, DRC_DEFAULT_MOBILE_REF_LEVEL); 134 } 135 // * AAC_DRC_ATTENUATION_FACTOR 136 if (property_get(PROP_DRC_OVERRIDE_CUT, value, NULL)) { 137 unsigned cut = atoi(value); 138 ALOGV("AAC decoder using AAC_DRC_ATTENUATION_FACTOR of %d instead of %d", 139 cut, DRC_DEFAULT_MOBILE_DRC_CUT); 140 aacDecoder_SetParam(mAACDecoder, AAC_DRC_ATTENUATION_FACTOR, cut); 141 } else { 142 aacDecoder_SetParam(mAACDecoder, AAC_DRC_ATTENUATION_FACTOR, DRC_DEFAULT_MOBILE_DRC_CUT); 143 } 144 // * AAC_DRC_BOOST_FACTOR (note: no default, using cut) 145 if (property_get(PROP_DRC_OVERRIDE_BOOST, value, NULL)) { 146 unsigned boost = atoi(value); 147 ALOGV("AAC decoder using AAC_DRC_BOOST_FACTOR of %d", boost); 148 aacDecoder_SetParam(mAACDecoder, AAC_DRC_BOOST_FACTOR, boost); 149 } 150 151 return status; 152} 153 154OMX_ERRORTYPE SoftAAC2::internalGetParameter( 155 OMX_INDEXTYPE index, OMX_PTR params) { 156 switch (index) { 157 case OMX_IndexParamAudioAac: 158 { 159 OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = 160 (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; 161 162 if (aacParams->nPortIndex != 0) { 163 return OMX_ErrorUndefined; 164 } 165 166 aacParams->nBitRate = 0; 167 aacParams->nAudioBandWidth = 0; 168 aacParams->nAACtools = 0; 169 aacParams->nAACERtools = 0; 170 aacParams->eAACProfile = OMX_AUDIO_AACObjectMain; 171 172 aacParams->eAACStreamFormat = 173 mIsADTS 174 ? OMX_AUDIO_AACStreamFormatMP4ADTS 175 : OMX_AUDIO_AACStreamFormatMP4FF; 176 177 aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo; 178 179 if (!isConfigured()) { 180 aacParams->nChannels = 1; 181 aacParams->nSampleRate = 44100; 182 aacParams->nFrameLength = 0; 183 } else { 184 aacParams->nChannels = mStreamInfo->numChannels; 185 aacParams->nSampleRate = mStreamInfo->sampleRate; 186 aacParams->nFrameLength = mStreamInfo->frameSize; 187 } 188 189 return OMX_ErrorNone; 190 } 191 192 case OMX_IndexParamAudioPcm: 193 { 194 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 195 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 196 197 if (pcmParams->nPortIndex != 1) { 198 return OMX_ErrorUndefined; 199 } 200 201 pcmParams->eNumData = OMX_NumericalDataSigned; 202 pcmParams->eEndian = OMX_EndianBig; 203 pcmParams->bInterleaved = OMX_TRUE; 204 pcmParams->nBitPerSample = 16; 205 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; 206 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; 207 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; 208 pcmParams->eChannelMapping[2] = OMX_AUDIO_ChannelCF; 209 pcmParams->eChannelMapping[3] = OMX_AUDIO_ChannelLFE; 210 pcmParams->eChannelMapping[4] = OMX_AUDIO_ChannelLS; 211 pcmParams->eChannelMapping[5] = OMX_AUDIO_ChannelRS; 212 213 if (!isConfigured()) { 214 pcmParams->nChannels = 1; 215 pcmParams->nSamplingRate = 44100; 216 } else { 217 pcmParams->nChannels = mStreamInfo->numChannels; 218 pcmParams->nSamplingRate = mStreamInfo->sampleRate; 219 } 220 221 return OMX_ErrorNone; 222 } 223 224 default: 225 return SimpleSoftOMXComponent::internalGetParameter(index, params); 226 } 227} 228 229OMX_ERRORTYPE SoftAAC2::internalSetParameter( 230 OMX_INDEXTYPE index, const OMX_PTR params) { 231 switch (index) { 232 case OMX_IndexParamStandardComponentRole: 233 { 234 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 235 (const OMX_PARAM_COMPONENTROLETYPE *)params; 236 237 if (strncmp((const char *)roleParams->cRole, 238 "audio_decoder.aac", 239 OMX_MAX_STRINGNAME_SIZE - 1)) { 240 return OMX_ErrorUndefined; 241 } 242 243 return OMX_ErrorNone; 244 } 245 246 case OMX_IndexParamAudioAac: 247 { 248 const OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = 249 (const OMX_AUDIO_PARAM_AACPROFILETYPE *)params; 250 251 if (aacParams->nPortIndex != 0) { 252 return OMX_ErrorUndefined; 253 } 254 255 if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) { 256 mIsADTS = false; 257 } else if (aacParams->eAACStreamFormat 258 == OMX_AUDIO_AACStreamFormatMP4ADTS) { 259 mIsADTS = true; 260 } else { 261 return OMX_ErrorUndefined; 262 } 263 264 return OMX_ErrorNone; 265 } 266 267 case OMX_IndexParamAudioPcm: 268 { 269 const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 270 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 271 272 if (pcmParams->nPortIndex != 1) { 273 return OMX_ErrorUndefined; 274 } 275 276 return OMX_ErrorNone; 277 } 278 279 default: 280 return SimpleSoftOMXComponent::internalSetParameter(index, params); 281 } 282} 283 284bool SoftAAC2::isConfigured() const { 285 return mInputBufferCount > 0; 286} 287 288void SoftAAC2::maybeConfigureDownmix() const { 289 if (mStreamInfo->numChannels > 2) { 290 char value[PROPERTY_VALUE_MAX]; 291 if (!(property_get("media.aac_51_output_enabled", value, NULL) && 292 (!strcmp(value, "1") || !strcasecmp(value, "true")))) { 293 ALOGI("Downmixing multichannel AAC to stereo"); 294 aacDecoder_SetParam(mAACDecoder, AAC_PCM_OUTPUT_CHANNELS, 2); 295 mStreamInfo->numChannels = 2; 296 } 297 } 298} 299 300void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { 301 if (mSignalledError || mOutputPortSettingsChange != NONE) { 302 return; 303 } 304 305 UCHAR* inBuffer[FILEREAD_MAX_LAYERS]; 306 UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0}; 307 UINT bytesValid[FILEREAD_MAX_LAYERS] = {0}; 308 309 List<BufferInfo *> &inQueue = getPortQueue(0); 310 List<BufferInfo *> &outQueue = getPortQueue(1); 311 312 if (portIndex == 0 && mInputBufferCount == 0) { 313 ++mInputBufferCount; 314 BufferInfo *info = *inQueue.begin(); 315 OMX_BUFFERHEADERTYPE *header = info->mHeader; 316 317 inBuffer[0] = header->pBuffer + header->nOffset; 318 inBufferLength[0] = header->nFilledLen; 319 320 AAC_DECODER_ERROR decoderErr = 321 aacDecoder_ConfigRaw(mAACDecoder, 322 inBuffer, 323 inBufferLength); 324 325 if (decoderErr != AAC_DEC_OK) { 326 mSignalledError = true; 327 notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); 328 return; 329 } 330 331 inQueue.erase(inQueue.begin()); 332 info->mOwnedByUs = false; 333 notifyEmptyBufferDone(header); 334 335 // Only send out port settings changed event if both sample rate 336 // and numChannels are valid. 337 if (mStreamInfo->sampleRate && mStreamInfo->numChannels) { 338 maybeConfigureDownmix(); 339 ALOGI("Initially configuring decoder: %d Hz, %d channels", 340 mStreamInfo->sampleRate, 341 mStreamInfo->numChannels); 342 343 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 344 mOutputPortSettingsChange = AWAITING_DISABLED; 345 } 346 347 return; 348 } 349 350 while (!inQueue.empty() && !outQueue.empty()) { 351 BufferInfo *inInfo = *inQueue.begin(); 352 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 353 354 BufferInfo *outInfo = *outQueue.begin(); 355 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 356 357 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 358 inQueue.erase(inQueue.begin()); 359 inInfo->mOwnedByUs = false; 360 notifyEmptyBufferDone(inHeader); 361 362 if (mDecoderHasData) { 363 // flush out the decoder's delayed data by calling DecodeFrame 364 // one more time, with the AACDEC_FLUSH flag set 365 INT_PCM *outBuffer = 366 reinterpret_cast<INT_PCM *>( 367 outHeader->pBuffer + outHeader->nOffset); 368 369 AAC_DECODER_ERROR decoderErr = 370 aacDecoder_DecodeFrame(mAACDecoder, 371 outBuffer, 372 outHeader->nAllocLen, 373 AACDEC_FLUSH); 374 mDecoderHasData = false; 375 376 if (decoderErr != AAC_DEC_OK) { 377 mSignalledError = true; 378 379 notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, 380 NULL); 381 382 return; 383 } 384 385 outHeader->nFilledLen = 386 mStreamInfo->frameSize 387 * sizeof(int16_t) 388 * mStreamInfo->numChannels; 389 } else { 390 // we never submitted any data to the decoder, so there's nothing to flush out 391 outHeader->nFilledLen = 0; 392 } 393 394 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 395 396 outQueue.erase(outQueue.begin()); 397 outInfo->mOwnedByUs = false; 398 notifyFillBufferDone(outHeader); 399 return; 400 } 401 402 if (inHeader->nOffset == 0) { 403 mAnchorTimeUs = inHeader->nTimeStamp; 404 mNumSamplesOutput = 0; 405 } 406 407 size_t adtsHeaderSize = 0; 408 if (mIsADTS) { 409 // skip 30 bits, aac_frame_length follows. 410 // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? 411 412 const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; 413 414 bool signalError = false; 415 if (inHeader->nFilledLen < 7) { 416 ALOGE("Audio data too short to contain even the ADTS header. " 417 "Got %ld bytes.", inHeader->nFilledLen); 418 hexdump(adtsHeader, inHeader->nFilledLen); 419 signalError = true; 420 } else { 421 bool protectionAbsent = (adtsHeader[1] & 1); 422 423 unsigned aac_frame_length = 424 ((adtsHeader[3] & 3) << 11) 425 | (adtsHeader[4] << 3) 426 | (adtsHeader[5] >> 5); 427 428 if (inHeader->nFilledLen < aac_frame_length) { 429 ALOGE("Not enough audio data for the complete frame. " 430 "Got %ld bytes, frame size according to the ADTS " 431 "header is %u bytes.", 432 inHeader->nFilledLen, aac_frame_length); 433 hexdump(adtsHeader, inHeader->nFilledLen); 434 signalError = true; 435 } else { 436 adtsHeaderSize = (protectionAbsent ? 7 : 9); 437 438 inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize; 439 inBufferLength[0] = aac_frame_length - adtsHeaderSize; 440 441 inHeader->nOffset += adtsHeaderSize; 442 inHeader->nFilledLen -= adtsHeaderSize; 443 } 444 } 445 446 if (signalError) { 447 mSignalledError = true; 448 449 notify(OMX_EventError, 450 OMX_ErrorStreamCorrupt, 451 ERROR_MALFORMED, 452 NULL); 453 454 return; 455 } 456 } else { 457 inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; 458 inBufferLength[0] = inHeader->nFilledLen; 459 } 460 461 // Fill and decode 462 INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>( 463 outHeader->pBuffer + outHeader->nOffset); 464 465 bytesValid[0] = inBufferLength[0]; 466 467 int prevSampleRate = mStreamInfo->sampleRate; 468 int prevNumChannels = mStreamInfo->numChannels; 469 470 AAC_DECODER_ERROR decoderErr = AAC_DEC_NOT_ENOUGH_BITS; 471 while (bytesValid[0] > 0 && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { 472 aacDecoder_Fill(mAACDecoder, 473 inBuffer, 474 inBufferLength, 475 bytesValid); 476 mDecoderHasData = true; 477 478 decoderErr = aacDecoder_DecodeFrame(mAACDecoder, 479 outBuffer, 480 outHeader->nAllocLen, 481 0 /* flags */); 482 483 if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) { 484 ALOGW("Not enough bits, bytesValid %d", bytesValid[0]); 485 } 486 } 487 488 size_t numOutBytes = 489 mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; 490 491 if (decoderErr == AAC_DEC_OK) { 492 UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; 493 inHeader->nFilledLen -= inBufferUsedLength; 494 inHeader->nOffset += inBufferUsedLength; 495 } else { 496 ALOGW("AAC decoder returned error %d, substituting silence", 497 decoderErr); 498 499 memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes); 500 501 // Discard input buffer. 502 inHeader->nFilledLen = 0; 503 504 aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); 505 506 // fall through 507 } 508 509 if (inHeader->nFilledLen == 0) { 510 inInfo->mOwnedByUs = false; 511 inQueue.erase(inQueue.begin()); 512 inInfo = NULL; 513 notifyEmptyBufferDone(inHeader); 514 inHeader = NULL; 515 } 516 517 /* 518 * AAC+/eAAC+ streams can be signalled in two ways: either explicitly 519 * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual 520 * rate system and the sampling rate in the final output is actually 521 * doubled compared with the core AAC decoder sampling rate. 522 * 523 * Explicit signalling is done by explicitly defining SBR audio object 524 * type in the bitstream. Implicit signalling is done by embedding 525 * SBR content in AAC extension payload specific to SBR, and hence 526 * requires an AAC decoder to perform pre-checks on actual audio frames. 527 * 528 * Thus, we could not say for sure whether a stream is 529 * AAC+/eAAC+ until the first data frame is decoded. 530 */ 531 if (mInputBufferCount <= 2) { 532 if (mStreamInfo->sampleRate != prevSampleRate || 533 mStreamInfo->numChannels != prevNumChannels) { 534 maybeConfigureDownmix(); 535 ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", 536 prevSampleRate, mStreamInfo->sampleRate, 537 prevNumChannels, mStreamInfo->numChannels); 538 539 notify(OMX_EventPortSettingsChanged, 1, 0, NULL); 540 mOutputPortSettingsChange = AWAITING_DISABLED; 541 return; 542 } 543 } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) { 544 ALOGW("Invalid AAC stream"); 545 mSignalledError = true; 546 notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); 547 return; 548 } 549 550 if (decoderErr == AAC_DEC_OK || mNumSamplesOutput > 0) { 551 // We'll only output data if we successfully decoded it or 552 // we've previously decoded valid data, in the latter case 553 // (decode failed) we'll output a silent frame. 554 outHeader->nFilledLen = numOutBytes; 555 outHeader->nFlags = 0; 556 557 outHeader->nTimeStamp = 558 mAnchorTimeUs 559 + (mNumSamplesOutput * 1000000ll) / mStreamInfo->sampleRate; 560 561 mNumSamplesOutput += mStreamInfo->frameSize; 562 563 outInfo->mOwnedByUs = false; 564 outQueue.erase(outQueue.begin()); 565 outInfo = NULL; 566 notifyFillBufferDone(outHeader); 567 outHeader = NULL; 568 } 569 570 if (decoderErr == AAC_DEC_OK) { 571 ++mInputBufferCount; 572 } 573 } 574} 575 576void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { 577 if (portIndex == 0) { 578 // Make sure that the next buffer output does not still 579 // depend on fragments from the last one decoded. 580 // drain all existing data 581 drainDecoder(); 582 } 583} 584 585void SoftAAC2::drainDecoder() { 586 short buf [2048]; 587 aacDecoder_DecodeFrame(mAACDecoder, buf, 4096, AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR); 588 aacDecoder_DecodeFrame(mAACDecoder, buf, 4096, AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR); 589 aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1); 590 mDecoderHasData = false; 591} 592 593void SoftAAC2::onReset() { 594 drainDecoder(); 595 // reset the "configured" state 596 mInputBufferCount = 0; 597 mNumSamplesOutput = 0; 598 // To make the codec behave the same before and after a reset, we need to invalidate the 599 // streaminfo struct. This does that: 600 mStreamInfo->sampleRate = 0; 601} 602 603void SoftAAC2::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { 604 if (portIndex != 1) { 605 return; 606 } 607 608 switch (mOutputPortSettingsChange) { 609 case NONE: 610 break; 611 612 case AWAITING_DISABLED: 613 { 614 CHECK(!enabled); 615 mOutputPortSettingsChange = AWAITING_ENABLED; 616 break; 617 } 618 619 default: 620 { 621 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); 622 CHECK(enabled); 623 mOutputPortSettingsChange = NONE; 624 break; 625 } 626 } 627} 628 629} // namespace android 630 631android::SoftOMXComponent *createSoftOMXComponent( 632 const char *name, const OMX_CALLBACKTYPE *callbacks, 633 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 634 return new android::SoftAAC2(name, callbacks, appData, component); 635} 636