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 (formatParams->nPortIndex > 1) { 158 return OMX_ErrorUndefined; 159 } 160 161 if (formatParams->nIndex > 0) { 162 return OMX_ErrorNoMore; 163 } 164 165 formatParams->eEncoding = 166 (formatParams->nPortIndex == 0) 167 ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAAC; 168 169 return OMX_ErrorNone; 170 } 171 172 case OMX_IndexParamAudioAac: 173 { 174 OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = 175 (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; 176 177 if (aacParams->nPortIndex != 1) { 178 return OMX_ErrorUndefined; 179 } 180 181 aacParams->nBitRate = mBitRate; 182 aacParams->nAudioBandWidth = 0; 183 aacParams->nAACtools = 0; 184 aacParams->nAACERtools = 0; 185 aacParams->eAACProfile = OMX_AUDIO_AACObjectMain; 186 aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF; 187 aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo; 188 189 aacParams->nChannels = mNumChannels; 190 aacParams->nSampleRate = mSampleRate; 191 aacParams->nFrameLength = 0; 192 193 return OMX_ErrorNone; 194 } 195 196 case OMX_IndexParamAudioPcm: 197 { 198 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 199 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 200 201 if (pcmParams->nPortIndex != 0) { 202 return OMX_ErrorUndefined; 203 } 204 205 pcmParams->eNumData = OMX_NumericalDataSigned; 206 pcmParams->eEndian = OMX_EndianBig; 207 pcmParams->bInterleaved = OMX_TRUE; 208 pcmParams->nBitPerSample = 16; 209 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; 210 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; 211 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; 212 213 pcmParams->nChannels = mNumChannels; 214 pcmParams->nSamplingRate = mSampleRate; 215 216 return OMX_ErrorNone; 217 } 218 219 default: 220 return SimpleSoftOMXComponent::internalGetParameter(index, params); 221 } 222} 223 224OMX_ERRORTYPE SoftAACEncoder::internalSetParameter( 225 OMX_INDEXTYPE index, const OMX_PTR params) { 226 switch (index) { 227 case OMX_IndexParamStandardComponentRole: 228 { 229 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 230 (const OMX_PARAM_COMPONENTROLETYPE *)params; 231 232 if (strncmp((const char *)roleParams->cRole, 233 "audio_encoder.aac", 234 OMX_MAX_STRINGNAME_SIZE - 1)) { 235 return OMX_ErrorUndefined; 236 } 237 238 return OMX_ErrorNone; 239 } 240 241 case OMX_IndexParamAudioPortFormat: 242 { 243 const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = 244 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; 245 246 if (formatParams->nPortIndex > 1) { 247 return OMX_ErrorUndefined; 248 } 249 250 if (formatParams->nIndex > 0) { 251 return OMX_ErrorNoMore; 252 } 253 254 if ((formatParams->nPortIndex == 0 255 && formatParams->eEncoding != OMX_AUDIO_CodingPCM) 256 || (formatParams->nPortIndex == 1 257 && formatParams->eEncoding != OMX_AUDIO_CodingAAC)) { 258 return OMX_ErrorUndefined; 259 } 260 261 return OMX_ErrorNone; 262 } 263 264 case OMX_IndexParamAudioAac: 265 { 266 OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = 267 (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; 268 269 if (aacParams->nPortIndex != 1) { 270 return OMX_ErrorUndefined; 271 } 272 273 mBitRate = aacParams->nBitRate; 274 mNumChannels = aacParams->nChannels; 275 mSampleRate = aacParams->nSampleRate; 276 277 if (setAudioParams() != OK) { 278 return OMX_ErrorUndefined; 279 } 280 281 return OMX_ErrorNone; 282 } 283 284 case OMX_IndexParamAudioPcm: 285 { 286 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = 287 (OMX_AUDIO_PARAM_PCMMODETYPE *)params; 288 289 if (pcmParams->nPortIndex != 0) { 290 return OMX_ErrorUndefined; 291 } 292 293 mNumChannels = pcmParams->nChannels; 294 mSampleRate = pcmParams->nSamplingRate; 295 296 if (setAudioParams() != OK) { 297 return OMX_ErrorUndefined; 298 } 299 300 return OMX_ErrorNone; 301 } 302 303 304 default: 305 return SimpleSoftOMXComponent::internalSetParameter(index, params); 306 } 307} 308 309status_t SoftAACEncoder::setAudioParams() { 310 // We call this whenever sample rate, number of channels or bitrate change 311 // in reponse to setParameter calls. 312 313 ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps", 314 mSampleRate, mNumChannels, mBitRate); 315 316 status_t err = setAudioSpecificConfigData(); 317 318 if (err != OK) { 319 return err; 320 } 321 322 AACENC_PARAM params; 323 memset(¶ms, 0, sizeof(params)); 324 params.sampleRate = mSampleRate; 325 params.bitRate = mBitRate; 326 params.nChannels = mNumChannels; 327 params.adtsUsed = 0; // We add adts header in the file writer if needed. 328 if (VO_ERR_NONE != mApiHandle->SetParam( 329 mEncoderHandle, VO_PID_AAC_ENCPARAM, ¶ms)) { 330 ALOGE("Failed to set AAC encoder parameters"); 331 return UNKNOWN_ERROR; 332 } 333 334 return OK; 335} 336 337static status_t getSampleRateTableIndex(int32_t sampleRate, int32_t &index) { 338 static const int32_t kSampleRateTable[] = { 339 96000, 88200, 64000, 48000, 44100, 32000, 340 24000, 22050, 16000, 12000, 11025, 8000 341 }; 342 const int32_t tableSize = 343 sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]); 344 345 for (int32_t i = 0; i < tableSize; ++i) { 346 if (sampleRate == kSampleRateTable[i]) { 347 index = i; 348 return OK; 349 } 350 } 351 352 return UNKNOWN_ERROR; 353} 354 355status_t SoftAACEncoder::setAudioSpecificConfigData() { 356 // The AAC encoder's audio specific config really only encodes 357 // number of channels and the sample rate (mapped to an index into 358 // a fixed sample rate table). 359 360 int32_t index; 361 status_t err = getSampleRateTableIndex(mSampleRate, index); 362 if (err != OK) { 363 ALOGE("Unsupported sample rate (%lu Hz)", mSampleRate); 364 return err; 365 } 366 367 if (mNumChannels > 2 || mNumChannels <= 0) { 368 ALOGE("Unsupported number of channels(%lu)", mNumChannels); 369 return UNKNOWN_ERROR; 370 } 371 372 // OMX_AUDIO_AACObjectLC 373 mAudioSpecificConfigData[0] = ((0x02 << 3) | (index >> 1)); 374 mAudioSpecificConfigData[1] = ((index & 0x01) << 7) | (mNumChannels << 3); 375 376 return OK; 377} 378 379void SoftAACEncoder::onQueueFilled(OMX_U32 portIndex) { 380 if (mSignalledError) { 381 return; 382 } 383 384 List<BufferInfo *> &inQueue = getPortQueue(0); 385 List<BufferInfo *> &outQueue = getPortQueue(1); 386 387 if (!mSentCodecSpecificData) { 388 // The very first thing we want to output is the codec specific 389 // data. It does not require any input data but we will need an 390 // output buffer to store it in. 391 392 if (outQueue.empty()) { 393 return; 394 } 395 396 BufferInfo *outInfo = *outQueue.begin(); 397 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 398 outHeader->nFilledLen = sizeof(mAudioSpecificConfigData); 399 outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG; 400 401 uint8_t *out = outHeader->pBuffer + outHeader->nOffset; 402 memcpy(out, mAudioSpecificConfigData, sizeof(mAudioSpecificConfigData)); 403 404#if 0 405 ALOGI("sending codec specific data."); 406 hexdump(out, sizeof(mAudioSpecificConfigData)); 407#endif 408 409 outQueue.erase(outQueue.begin()); 410 outInfo->mOwnedByUs = false; 411 notifyFillBufferDone(outHeader); 412 413 mSentCodecSpecificData = true; 414 } 415 416 size_t numBytesPerInputFrame = 417 mNumChannels * kNumSamplesPerFrame * sizeof(int16_t); 418 419 for (;;) { 420 // We do the following until we run out of buffers. 421 422 while (mInputSize < numBytesPerInputFrame) { 423 // As long as there's still input data to be read we 424 // will drain "kNumSamplesPerFrame * mNumChannels" samples 425 // into the "mInputFrame" buffer and then encode those 426 // as a unit into an output buffer. 427 428 if (mSawInputEOS || inQueue.empty()) { 429 return; 430 } 431 432 BufferInfo *inInfo = *inQueue.begin(); 433 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 434 435 const void *inData = inHeader->pBuffer + inHeader->nOffset; 436 437 size_t copy = numBytesPerInputFrame - mInputSize; 438 if (copy > inHeader->nFilledLen) { 439 copy = inHeader->nFilledLen; 440 } 441 442 if (mInputFrame == NULL) { 443 mInputFrame = new int16_t[kNumSamplesPerFrame * mNumChannels]; 444 } 445 446 if (mInputSize == 0) { 447 mInputTimeUs = inHeader->nTimeStamp; 448 } 449 450 memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy); 451 mInputSize += copy; 452 453 inHeader->nOffset += copy; 454 inHeader->nFilledLen -= copy; 455 456 // "Time" on the input buffer has in effect advanced by the 457 // number of audio frames we just advanced nOffset by. 458 inHeader->nTimeStamp += 459 (copy * 1000000ll / mSampleRate) 460 / (mNumChannels * sizeof(int16_t)); 461 462 if (inHeader->nFilledLen == 0) { 463 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 464 ALOGV("saw input EOS"); 465 mSawInputEOS = true; 466 467 // Pad any remaining data with zeroes. 468 memset((uint8_t *)mInputFrame + mInputSize, 469 0, 470 numBytesPerInputFrame - mInputSize); 471 472 mInputSize = numBytesPerInputFrame; 473 } 474 475 inQueue.erase(inQueue.begin()); 476 inInfo->mOwnedByUs = false; 477 notifyEmptyBufferDone(inHeader); 478 479 inData = NULL; 480 inHeader = NULL; 481 inInfo = NULL; 482 } 483 } 484 485 // At this point we have all the input data necessary to encode 486 // a single frame, all we need is an output buffer to store the result 487 // in. 488 489 if (outQueue.empty()) { 490 return; 491 } 492 493 BufferInfo *outInfo = *outQueue.begin(); 494 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 495 496 VO_CODECBUFFER inputData; 497 memset(&inputData, 0, sizeof(inputData)); 498 inputData.Buffer = (unsigned char *)mInputFrame; 499 inputData.Length = numBytesPerInputFrame; 500 CHECK(VO_ERR_NONE == 501 mApiHandle->SetInputData(mEncoderHandle, &inputData)); 502 503 VO_CODECBUFFER outputData; 504 memset(&outputData, 0, sizeof(outputData)); 505 VO_AUDIO_OUTPUTINFO outputInfo; 506 memset(&outputInfo, 0, sizeof(outputInfo)); 507 508 uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset; 509 size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset; 510 511 VO_U32 ret = VO_ERR_NONE; 512 size_t nOutputBytes = 0; 513 do { 514 outputData.Buffer = outPtr; 515 outputData.Length = outAvailable - nOutputBytes; 516 ret = mApiHandle->GetOutputData( 517 mEncoderHandle, &outputData, &outputInfo); 518 if (ret == VO_ERR_NONE) { 519 outPtr += outputData.Length; 520 nOutputBytes += outputData.Length; 521 } 522 } while (ret != VO_ERR_INPUT_BUFFER_SMALL); 523 524 outHeader->nFilledLen = nOutputBytes; 525 526 outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; 527 528 if (mSawInputEOS) { 529 // We also tag this output buffer with EOS if it corresponds 530 // to the final input buffer. 531 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 532 } 533 534 outHeader->nTimeStamp = mInputTimeUs; 535 536#if 0 537 ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)", 538 nOutputBytes, mInputTimeUs, outHeader->nFlags); 539 540 hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen); 541#endif 542 543 outQueue.erase(outQueue.begin()); 544 outInfo->mOwnedByUs = false; 545 notifyFillBufferDone(outHeader); 546 547 outHeader = NULL; 548 outInfo = NULL; 549 550 mInputSize = 0; 551 } 552} 553 554} // namespace android 555 556android::SoftOMXComponent *createSoftOMXComponent( 557 const char *name, const OMX_CALLBACKTYPE *callbacks, 558 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 559 return new android::SoftAACEncoder(name, callbacks, appData, component); 560} 561