SoftAACEncoder.cpp revision 423766ca07beb7e3e9cd301385708ca13fcce3e1
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_NDEBUG 0 18#define LOG_TAG "SoftAACEncoder" 19#include <utils/Log.h> 20 21#include "SoftAACEncoder.h" 22 23#include "voAAC.h" 24#include "cmnMemory.h" 25 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/foundation/hexdump.h> 28 29namespace android { 30 31template<class T> 32static void InitOMXParams(T *params) { 33 params->nSize = sizeof(T); 34 params->nVersion.s.nVersionMajor = 1; 35 params->nVersion.s.nVersionMinor = 0; 36 params->nVersion.s.nRevision = 0; 37 params->nVersion.s.nStep = 0; 38} 39 40SoftAACEncoder::SoftAACEncoder( 41 const char *name, 42 const OMX_CALLBACKTYPE *callbacks, 43 OMX_PTR appData, 44 OMX_COMPONENTTYPE **component) 45 : SimpleSoftOMXComponent(name, callbacks, appData, component), 46 mEncoderHandle(NULL), 47 mApiHandle(NULL), 48 mMemOperator(NULL), 49 mNumChannels(1), 50 mSampleRate(44100), 51 mBitRate(0), 52 mSentCodecSpecificData(false), 53 mInputSize(0), 54 mInputFrame(NULL), 55 mInputTimeUs(-1ll), 56 mSawInputEOS(false), 57 mSignalledError(false) { 58 initPorts(); 59 CHECK_EQ(initEncoder(), (status_t)OK); 60 61 setAudioParams(); 62} 63 64SoftAACEncoder::~SoftAACEncoder() { 65 delete[] mInputFrame; 66 mInputFrame = NULL; 67 68 if (mEncoderHandle) { 69 CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle)); 70 mEncoderHandle = NULL; 71 } 72 73 delete mApiHandle; 74 mApiHandle = NULL; 75 76 delete mMemOperator; 77 mMemOperator = NULL; 78} 79 80void SoftAACEncoder::initPorts() { 81 OMX_PARAM_PORTDEFINITIONTYPE def; 82 InitOMXParams(&def); 83 84 def.nPortIndex = 0; 85 def.eDir = OMX_DirInput; 86 def.nBufferCountMin = kNumBuffers; 87 def.nBufferCountActual = def.nBufferCountMin; 88 def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 2; 89 def.bEnabled = OMX_TRUE; 90 def.bPopulated = OMX_FALSE; 91 def.eDomain = OMX_PortDomainAudio; 92 def.bBuffersContiguous = OMX_FALSE; 93 def.nBufferAlignment = 1; 94 95 def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); 96 def.format.audio.pNativeRender = NULL; 97 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 98 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; 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 = 8192; 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/aac"); 114 def.format.audio.pNativeRender = NULL; 115 def.format.audio.bFlagErrorConcealment = OMX_FALSE; 116 def.format.audio.eEncoding = OMX_AUDIO_CodingAAC; 117 118 addPort(def); 119} 120 121status_t SoftAACEncoder::initEncoder() { 122 mApiHandle = new VO_AUDIO_CODECAPI; 123 124 if (VO_ERR_NONE != voGetAACEncAPI(mApiHandle)) { 125 ALOGE("Failed to get api handle"); 126 return UNKNOWN_ERROR; 127 } 128 129 mMemOperator = new VO_MEM_OPERATOR; 130 mMemOperator->Alloc = cmnMemAlloc; 131 mMemOperator->Copy = cmnMemCopy; 132 mMemOperator->Free = cmnMemFree; 133 mMemOperator->Set = cmnMemSet; 134 mMemOperator->Check = cmnMemCheck; 135 136 VO_CODEC_INIT_USERDATA userData; 137 memset(&userData, 0, sizeof(userData)); 138 userData.memflag = VO_IMF_USERMEMOPERATOR; 139 userData.memData = (VO_PTR) mMemOperator; 140 if (VO_ERR_NONE != 141 mApiHandle->Init(&mEncoderHandle, VO_AUDIO_CodingAAC, &userData)) { 142 ALOGE("Failed to init AAC encoder"); 143 return UNKNOWN_ERROR; 144 } 145 146 return OK; 147} 148 149OMX_ERRORTYPE SoftAACEncoder::internalGetParameter( 150 OMX_INDEXTYPE index, OMX_PTR params) { 151 switch (index) { 152 case OMX_IndexParamAudioPortFormat: 153 { 154 OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = 155 (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; 156 157 if (!isValidOMXParam(formatParams)) { 158 return OMX_ErrorBadParameter; 159 } 160 161 if (formatParams->nPortIndex > 1) { 162 return OMX_ErrorUndefined; 163 } 164 165 if (formatParams->nIndex > 0) { 166 return OMX_ErrorNoMore; 167 } 168 169 formatParams->eEncoding = 170 (formatParams->nPortIndex == 0) 171 ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAAC; 172 173 return OMX_ErrorNone; 174 } 175 176 case OMX_IndexParamAudioAac: 177 { 178 OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = 179 (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; 180 181 if (!isValidOMXParam(aacParams)) { 182 return OMX_ErrorBadParameter; 183 } 184 185 if (aacParams->nPortIndex != 1) { 186 return OMX_ErrorUndefined; 187 } 188 189 aacParams->nBitRate = mBitRate; 190 aacParams->nAudioBandWidth = 0; 191 aacParams->nAACtools = 0; 192 aacParams->nAACERtools = 0; 193 aacParams->eAACProfile = OMX_AUDIO_AACObjectMain; 194 aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF; 195 aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo; 196 197 aacParams->nChannels = mNumChannels; 198 aacParams->nSampleRate = mSampleRate; 199 aacParams->nFrameLength = 0; 200 201 return OMX_ErrorNone; 202 } 203 204 case OMX_IndexParamAudioPcm: 205 { 206 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 207 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 208 209 if (!isValidOMXParam(pcmParams)) { 210 return OMX_ErrorBadParameter; 211 } 212 213 if (pcmParams->nPortIndex != 0) { 214 return OMX_ErrorUndefined; 215 } 216 217 pcmParams->eNumData = OMX_NumericalDataSigned; 218 pcmParams->eEndian = OMX_EndianBig; 219 pcmParams->bInterleaved = OMX_TRUE; 220 pcmParams->nBitPerSample = 16; 221 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; 222 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; 223 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; 224 225 pcmParams->nChannels = mNumChannels; 226 pcmParams->nSamplingRate = mSampleRate; 227 228 return OMX_ErrorNone; 229 } 230 231 default: 232 return SimpleSoftOMXComponent::internalGetParameter(index, params); 233 } 234} 235 236OMX_ERRORTYPE SoftAACEncoder::internalSetParameter( 237 OMX_INDEXTYPE index, const OMX_PTR params) { 238 switch (index) { 239 case OMX_IndexParamStandardComponentRole: 240 { 241 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 242 (const OMX_PARAM_COMPONENTROLETYPE *)params; 243 244 if (!isValidOMXParam(roleParams)) { 245 return OMX_ErrorBadParameter; 246 } 247 248 if (strncmp((const char *)roleParams->cRole, 249 "audio_encoder.aac", 250 OMX_MAX_STRINGNAME_SIZE - 1)) { 251 return OMX_ErrorUndefined; 252 } 253 254 return OMX_ErrorNone; 255 } 256 257 case OMX_IndexParamAudioPortFormat: 258 { 259 const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = 260 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; 261 262 if (!isValidOMXParam(formatParams)) { 263 return OMX_ErrorBadParameter; 264 } 265 266 if (formatParams->nPortIndex > 1) { 267 return OMX_ErrorUndefined; 268 } 269 270 if (formatParams->nIndex > 0) { 271 return OMX_ErrorNoMore; 272 } 273 274 if ((formatParams->nPortIndex == 0 275 && formatParams->eEncoding != OMX_AUDIO_CodingPCM) 276 || (formatParams->nPortIndex == 1 277 && formatParams->eEncoding != OMX_AUDIO_CodingAAC)) { 278 return OMX_ErrorUndefined; 279 } 280 281 return OMX_ErrorNone; 282 } 283 284 case OMX_IndexParamAudioAac: 285 { 286 OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = 287 (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; 288 289 if (!isValidOMXParam(aacParams)) { 290 return OMX_ErrorBadParameter; 291 } 292 293 if (aacParams->nPortIndex != 1) { 294 return OMX_ErrorUndefined; 295 } 296 297 mBitRate = aacParams->nBitRate; 298 mNumChannels = aacParams->nChannels; 299 mSampleRate = aacParams->nSampleRate; 300 301 if (setAudioParams() != OK) { 302 return OMX_ErrorUndefined; 303 } 304 305 return OMX_ErrorNone; 306 } 307 308 case OMX_IndexParamAudioPcm: 309 { 310 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 311 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 312 313 if (!isValidOMXParam(pcmParams)) { 314 return OMX_ErrorBadParameter; 315 } 316 317 if (pcmParams->nPortIndex != 0) { 318 return OMX_ErrorUndefined; 319 } 320 321 mNumChannels = pcmParams->nChannels; 322 mSampleRate = pcmParams->nSamplingRate; 323 324 if (setAudioParams() != OK) { 325 return OMX_ErrorUndefined; 326 } 327 328 return OMX_ErrorNone; 329 } 330 331 332 default: 333 return SimpleSoftOMXComponent::internalSetParameter(index, params); 334 } 335} 336 337status_t SoftAACEncoder::setAudioParams() { 338 // We call this whenever sample rate, number of channels or bitrate change 339 // in reponse to setParameter calls. 340 341 ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps", 342 mSampleRate, mNumChannels, mBitRate); 343 344 status_t err = setAudioSpecificConfigData(); 345 346 if (err != OK) { 347 return err; 348 } 349 350 AACENC_PARAM params; 351 memset(¶ms, 0, sizeof(params)); 352 params.sampleRate = mSampleRate; 353 params.bitRate = mBitRate; 354 params.nChannels = mNumChannels; 355 params.adtsUsed = 0; // We add adts header in the file writer if needed. 356 if (VO_ERR_NONE != mApiHandle->SetParam( 357 mEncoderHandle, VO_PID_AAC_ENCPARAM, ¶ms)) { 358 ALOGE("Failed to set AAC encoder parameters"); 359 return UNKNOWN_ERROR; 360 } 361 362 return OK; 363} 364 365static status_t getSampleRateTableIndex(int32_t sampleRate, int32_t &index) { 366 static const int32_t kSampleRateTable[] = { 367 96000, 88200, 64000, 48000, 44100, 32000, 368 24000, 22050, 16000, 12000, 11025, 8000 369 }; 370 const int32_t tableSize = 371 sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]); 372 373 for (int32_t i = 0; i < tableSize; ++i) { 374 if (sampleRate == kSampleRateTable[i]) { 375 index = i; 376 return OK; 377 } 378 } 379 380 return UNKNOWN_ERROR; 381} 382 383status_t SoftAACEncoder::setAudioSpecificConfigData() { 384 // The AAC encoder's audio specific config really only encodes 385 // number of channels and the sample rate (mapped to an index into 386 // a fixed sample rate table). 387 388 int32_t index; 389 status_t err = getSampleRateTableIndex(mSampleRate, index); 390 if (err != OK) { 391 ALOGE("Unsupported sample rate (%lu Hz)", mSampleRate); 392 return err; 393 } 394 395 if (mNumChannels > 2 || mNumChannels <= 0) { 396 ALOGE("Unsupported number of channels(%lu)", mNumChannels); 397 return UNKNOWN_ERROR; 398 } 399 400 // OMX_AUDIO_AACObjectLC 401 mAudioSpecificConfigData[0] = ((0x02 << 3) | (index >> 1)); 402 mAudioSpecificConfigData[1] = ((index & 0x01) << 7) | (mNumChannels << 3); 403 404 return OK; 405} 406 407void SoftAACEncoder::onQueueFilled(OMX_U32 portIndex) { 408 if (mSignalledError) { 409 return; 410 } 411 412 List<BufferInfo *> &inQueue = getPortQueue(0); 413 List<BufferInfo *> &outQueue = getPortQueue(1); 414 415 if (!mSentCodecSpecificData) { 416 // The very first thing we want to output is the codec specific 417 // data. It does not require any input data but we will need an 418 // output buffer to store it in. 419 420 if (outQueue.empty()) { 421 return; 422 } 423 424 BufferInfo *outInfo = *outQueue.begin(); 425 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 426 outHeader->nFilledLen = sizeof(mAudioSpecificConfigData); 427 outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG; 428 429 uint8_t *out = outHeader->pBuffer + outHeader->nOffset; 430 memcpy(out, mAudioSpecificConfigData, sizeof(mAudioSpecificConfigData)); 431 432#if 0 433 ALOGI("sending codec specific data."); 434 hexdump(out, sizeof(mAudioSpecificConfigData)); 435#endif 436 437 outQueue.erase(outQueue.begin()); 438 outInfo->mOwnedByUs = false; 439 notifyFillBufferDone(outHeader); 440 441 mSentCodecSpecificData = true; 442 } 443 444 size_t numBytesPerInputFrame = 445 mNumChannels * kNumSamplesPerFrame * sizeof(int16_t); 446 447 for (;;) { 448 // We do the following until we run out of buffers. 449 450 while (mInputSize < numBytesPerInputFrame) { 451 // As long as there's still input data to be read we 452 // will drain "kNumSamplesPerFrame * mNumChannels" samples 453 // into the "mInputFrame" buffer and then encode those 454 // as a unit into an output buffer. 455 456 if (mSawInputEOS || inQueue.empty()) { 457 return; 458 } 459 460 BufferInfo *inInfo = *inQueue.begin(); 461 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 462 463 const void *inData = inHeader->pBuffer + inHeader->nOffset; 464 465 size_t copy = numBytesPerInputFrame - mInputSize; 466 if (copy > inHeader->nFilledLen) { 467 copy = inHeader->nFilledLen; 468 } 469 470 if (mInputFrame == NULL) { 471 mInputFrame = new int16_t[kNumSamplesPerFrame * mNumChannels]; 472 } 473 474 if (mInputSize == 0) { 475 mInputTimeUs = inHeader->nTimeStamp; 476 } 477 478 memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy); 479 mInputSize += copy; 480 481 inHeader->nOffset += copy; 482 inHeader->nFilledLen -= copy; 483 484 // "Time" on the input buffer has in effect advanced by the 485 // number of audio frames we just advanced nOffset by. 486 inHeader->nTimeStamp += 487 (copy * 1000000ll / mSampleRate) 488 / (mNumChannels * sizeof(int16_t)); 489 490 if (inHeader->nFilledLen == 0) { 491 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 492 ALOGV("saw input EOS"); 493 mSawInputEOS = true; 494 495 // Pad any remaining data with zeroes. 496 memset((uint8_t *)mInputFrame + mInputSize, 497 0, 498 numBytesPerInputFrame - mInputSize); 499 500 mInputSize = numBytesPerInputFrame; 501 } 502 503 inQueue.erase(inQueue.begin()); 504 inInfo->mOwnedByUs = false; 505 notifyEmptyBufferDone(inHeader); 506 507 inData = NULL; 508 inHeader = NULL; 509 inInfo = NULL; 510 } 511 } 512 513 // At this point we have all the input data necessary to encode 514 // a single frame, all we need is an output buffer to store the result 515 // in. 516 517 if (outQueue.empty()) { 518 return; 519 } 520 521 BufferInfo *outInfo = *outQueue.begin(); 522 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 523 524 VO_CODECBUFFER inputData; 525 memset(&inputData, 0, sizeof(inputData)); 526 inputData.Buffer = (unsigned char *)mInputFrame; 527 inputData.Length = numBytesPerInputFrame; 528 CHECK(VO_ERR_NONE == 529 mApiHandle->SetInputData(mEncoderHandle, &inputData)); 530 531 VO_CODECBUFFER outputData; 532 memset(&outputData, 0, sizeof(outputData)); 533 VO_AUDIO_OUTPUTINFO outputInfo; 534 memset(&outputInfo, 0, sizeof(outputInfo)); 535 536 uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset; 537 size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset; 538 539 VO_U32 ret = VO_ERR_NONE; 540 size_t nOutputBytes = 0; 541 do { 542 outputData.Buffer = outPtr; 543 outputData.Length = outAvailable - nOutputBytes; 544 ret = mApiHandle->GetOutputData( 545 mEncoderHandle, &outputData, &outputInfo); 546 if (ret == VO_ERR_NONE) { 547 outPtr += outputData.Length; 548 nOutputBytes += outputData.Length; 549 } 550 } while (ret != VO_ERR_INPUT_BUFFER_SMALL); 551 552 outHeader->nFilledLen = nOutputBytes; 553 554 outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; 555 556 if (mSawInputEOS) { 557 // We also tag this output buffer with EOS if it corresponds 558 // to the final input buffer. 559 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 560 } 561 562 outHeader->nTimeStamp = mInputTimeUs; 563 564#if 0 565 ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)", 566 nOutputBytes, mInputTimeUs, outHeader->nFlags); 567 568 hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen); 569#endif 570 571 outQueue.erase(outQueue.begin()); 572 outInfo->mOwnedByUs = false; 573 notifyFillBufferDone(outHeader); 574 575 outHeader = NULL; 576 outInfo = NULL; 577 578 mInputSize = 0; 579 } 580} 581 582} // namespace android 583 584android::SoftOMXComponent *createSoftOMXComponent( 585 const char *name, const OMX_CALLBACKTYPE *callbacks, 586 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 587 return new android::SoftAACEncoder(name, callbacks, appData, component); 588} 589