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 "C2SoftAacEnc" 19#include <utils/Log.h> 20 21#include <inttypes.h> 22 23#include <C2PlatformSupport.h> 24#include <SimpleC2Interface.h> 25#include <media/stagefright/foundation/MediaDefs.h> 26#include <media/stagefright/foundation/hexdump.h> 27 28#include "C2SoftAacEnc.h" 29 30namespace android { 31 32class C2SoftAacEnc::IntfImpl : public C2InterfaceHelper { 33public: 34 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper) 35 : C2InterfaceHelper(helper) { 36 37 setDerivedInstance(this); 38 39 addParameter( 40 DefineParam(mInputFormat, C2_NAME_INPUT_STREAM_FORMAT_SETTING) 41 .withConstValue(new C2StreamFormatConfig::input(0u, C2FormatAudio)) 42 .build()); 43 44 addParameter( 45 DefineParam(mOutputFormat, C2_NAME_OUTPUT_STREAM_FORMAT_SETTING) 46 .withConstValue(new C2StreamFormatConfig::output(0u, C2FormatCompressed)) 47 .build()); 48 49 addParameter( 50 DefineParam(mInputMediaType, C2_NAME_INPUT_PORT_MIME_SETTING) 51 .withConstValue(AllocSharedString<C2PortMimeConfig::input>( 52 MEDIA_MIMETYPE_AUDIO_RAW)) 53 .build()); 54 55 addParameter( 56 DefineParam(mOutputMediaType, C2_NAME_OUTPUT_PORT_MIME_SETTING) 57 .withConstValue(AllocSharedString<C2PortMimeConfig::output>( 58 MEDIA_MIMETYPE_AUDIO_AAC)) 59 .build()); 60 61 addParameter( 62 DefineParam(mSampleRate, C2_NAME_STREAM_SAMPLE_RATE_SETTING) 63 .withDefault(new C2StreamSampleRateInfo::input(0u, 44100)) 64 .withFields({C2F(mSampleRate, value).oneOf({ 65 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 66 })}) 67 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps)) 68 .build()); 69 70 addParameter( 71 DefineParam(mChannelCount, C2_NAME_STREAM_CHANNEL_COUNT_SETTING) 72 .withDefault(new C2StreamChannelCountInfo::input(0u, 1)) 73 .withFields({C2F(mChannelCount, value).inRange(1, 6)}) 74 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps) 75 .build()); 76 77 addParameter( 78 DefineParam(mBitrate, C2_NAME_STREAM_BITRATE_SETTING) 79 .withDefault(new C2BitrateTuning::output(0u, 64000)) 80 .withFields({C2F(mBitrate, value).inRange(8000, 960000)}) 81 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps) 82 .build()); 83 } 84 85 uint32_t getSampleRate() const { return mSampleRate->value; } 86 uint32_t getChannelCount() const { return mChannelCount->value; } 87 uint32_t getBitrate() const { return mBitrate->value; } 88 89private: 90 std::shared_ptr<C2StreamFormatConfig::input> mInputFormat; 91 std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat; 92 std::shared_ptr<C2PortMimeConfig::input> mInputMediaType; 93 std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType; 94 std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate; 95 std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount; 96 std::shared_ptr<C2BitrateTuning::output> mBitrate; 97}; 98 99constexpr char COMPONENT_NAME[] = "c2.android.aac.encoder"; 100 101C2SoftAacEnc::C2SoftAacEnc( 102 const char *name, 103 c2_node_id_t id, 104 const std::shared_ptr<IntfImpl> &intfImpl) 105 : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)), 106 mIntf(intfImpl), 107 mAACEncoder(NULL), 108 mSBRMode(-1), 109 mSBRRatio(0), 110 mAACProfile(AOT_AAC_LC), 111 mNumBytesPerInputFrame(0u), 112 mOutBufferSize(0u), 113 mSentCodecSpecificData(false), 114 mInputSize(0), 115 mInputTimeUs(-1ll), 116 mSignalledError(false) { 117} 118 119C2SoftAacEnc::~C2SoftAacEnc() { 120 onReset(); 121} 122 123c2_status_t C2SoftAacEnc::onInit() { 124 status_t err = initEncoder(); 125 return err == OK ? C2_OK : C2_CORRUPTED; 126} 127 128status_t C2SoftAacEnc::initEncoder() { 129 if (AACENC_OK != aacEncOpen(&mAACEncoder, 0, 0)) { 130 ALOGE("Failed to init AAC encoder"); 131 return UNKNOWN_ERROR; 132 } 133 return setAudioParams(); 134} 135 136c2_status_t C2SoftAacEnc::onStop() { 137 mSentCodecSpecificData = false; 138 mInputSize = 0u; 139 mInputTimeUs = -1ll; 140 mSignalledError = false; 141 return C2_OK; 142} 143 144void C2SoftAacEnc::onReset() { 145 (void)onStop(); 146 aacEncClose(&mAACEncoder); 147} 148 149void C2SoftAacEnc::onRelease() { 150 // no-op 151} 152 153c2_status_t C2SoftAacEnc::onFlush_sm() { 154 mSentCodecSpecificData = false; 155 mInputSize = 0u; 156 return C2_OK; 157} 158 159static CHANNEL_MODE getChannelMode(uint32_t nChannels) { 160 CHANNEL_MODE chMode = MODE_INVALID; 161 switch (nChannels) { 162 case 1: chMode = MODE_1; break; 163 case 2: chMode = MODE_2; break; 164 case 3: chMode = MODE_1_2; break; 165 case 4: chMode = MODE_1_2_1; break; 166 case 5: chMode = MODE_1_2_2; break; 167 case 6: chMode = MODE_1_2_2_1; break; 168 default: chMode = MODE_INVALID; 169 } 170 return chMode; 171} 172 173//static AUDIO_OBJECT_TYPE getAOTFromProfile(OMX_U32 profile) { 174// if (profile == OMX_AUDIO_AACObjectLC) { 175// return AOT_AAC_LC; 176// } else if (profile == OMX_AUDIO_AACObjectHE) { 177// return AOT_SBR; 178// } else if (profile == OMX_AUDIO_AACObjectHE_PS) { 179// return AOT_PS; 180// } else if (profile == OMX_AUDIO_AACObjectLD) { 181// return AOT_ER_AAC_LD; 182// } else if (profile == OMX_AUDIO_AACObjectELD) { 183// return AOT_ER_AAC_ELD; 184// } else { 185// ALOGW("Unsupported AAC profile - defaulting to AAC-LC"); 186// return AOT_AAC_LC; 187// } 188//} 189 190status_t C2SoftAacEnc::setAudioParams() { 191 // We call this whenever sample rate, number of channels, bitrate or SBR mode change 192 // in reponse to setParameter calls. 193 194 ALOGV("setAudioParams: %u Hz, %u channels, %u bps, %i sbr mode, %i sbr ratio", 195 mIntf->getSampleRate(), mIntf->getChannelCount(), mIntf->getBitrate(), mSBRMode, mSBRRatio); 196 197 if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT, mAACProfile)) { 198 ALOGE("Failed to set AAC encoder parameters"); 199 return UNKNOWN_ERROR; 200 } 201 202 if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SAMPLERATE, mIntf->getSampleRate())) { 203 ALOGE("Failed to set AAC encoder parameters"); 204 return UNKNOWN_ERROR; 205 } 206 if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_BITRATE, mIntf->getBitrate())) { 207 ALOGE("Failed to set AAC encoder parameters"); 208 return UNKNOWN_ERROR; 209 } 210 if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_CHANNELMODE, 211 getChannelMode(mIntf->getChannelCount()))) { 212 ALOGE("Failed to set AAC encoder parameters"); 213 return UNKNOWN_ERROR; 214 } 215 if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_TRANSMUX, TT_MP4_RAW)) { 216 ALOGE("Failed to set AAC encoder parameters"); 217 return UNKNOWN_ERROR; 218 } 219 220 if (mSBRMode != -1 && mAACProfile == AOT_ER_AAC_ELD) { 221 if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_MODE, mSBRMode)) { 222 ALOGE("Failed to set AAC encoder parameters"); 223 return UNKNOWN_ERROR; 224 } 225 } 226 227 /* SBR ratio parameter configurations: 228 0: Default configuration wherein SBR ratio is configured depending on audio object type by 229 the FDK. 230 1: Downsampled SBR (default for ELD) 231 2: Dualrate SBR (default for HE-AAC) 232 */ 233 if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_RATIO, mSBRRatio)) { 234 ALOGE("Failed to set AAC encoder parameters"); 235 return UNKNOWN_ERROR; 236 } 237 238 return OK; 239} 240 241void C2SoftAacEnc::process( 242 const std::unique_ptr<C2Work> &work, 243 const std::shared_ptr<C2BlockPool> &pool) { 244 work->result = C2_OK; 245 work->workletsProcessed = 0u; 246 247 if (mSignalledError) { 248 return; 249 } 250 bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0; 251 252 uint32_t sampleRate = mIntf->getSampleRate(); 253 uint32_t channelCount = mIntf->getChannelCount(); 254 255 if (!mSentCodecSpecificData) { 256 // The very first thing we want to output is the codec specific 257 // data. 258 259 if (AACENC_OK != aacEncEncode(mAACEncoder, NULL, NULL, NULL, NULL)) { 260 ALOGE("Unable to initialize encoder for profile / sample-rate / bit-rate / channels"); 261 // TODO: notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 262 mSignalledError = true; 263 return; 264 } 265 266 uint32_t bitrate = mIntf->getBitrate(); 267 uint32_t actualBitRate = aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE); 268 if (bitrate != actualBitRate) { 269 ALOGW("Requested bitrate %u unsupported, using %u", bitrate, actualBitRate); 270 } 271 272 AACENC_InfoStruct encInfo; 273 if (AACENC_OK != aacEncInfo(mAACEncoder, &encInfo)) { 274 ALOGE("Failed to get AAC encoder info"); 275 // TODO: notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 276 mSignalledError = true; 277 return; 278 } 279 280 std::unique_ptr<C2StreamCsdInfo::output> csd = 281 C2StreamCsdInfo::output::AllocUnique(encInfo.confSize, 0u); 282 // TODO: check NO_MEMORY 283 memcpy(csd->m.value, encInfo.confBuf, encInfo.confSize); 284 ALOGV("put csd"); 285#if defined(LOG_NDEBUG) && !LOG_NDEBUG 286 hexdump(csd->m.value, csd->flexCount()); 287#endif 288 work->worklets.front()->output.configUpdate.push_back(std::move(csd)); 289 290 mOutBufferSize = encInfo.maxOutBufBytes; 291 mNumBytesPerInputFrame = encInfo.frameLength * channelCount * sizeof(int16_t); 292 mInputTimeUs = work->input.ordinal.timestamp; 293 294 mSentCodecSpecificData = true; 295 } 296 297 uint8_t temp[1]; 298 C2ReadView view = mDummyReadView; 299 const uint8_t *data = temp; 300 size_t capacity = 0u; 301 if (!work->input.buffers.empty()) { 302 view = work->input.buffers[0]->data().linearBlocks().front().map().get(); 303 data = view.data(); 304 capacity = view.capacity(); 305 } 306 uint64_t timestamp = mInputTimeUs.peeku(); 307 308 size_t numFrames = (capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0)) 309 / mNumBytesPerInputFrame; 310 ALOGV("capacity = %u; mInputSize = %zu; numFrames = %zu mNumBytesPerInputFrame = %u", 311 capacity, mInputSize, numFrames, mNumBytesPerInputFrame); 312 313 std::shared_ptr<C2LinearBlock> block; 314 std::unique_ptr<C2WriteView> wView; 315 uint8_t *outPtr = temp; 316 size_t outAvailable = 0u; 317 318 if (numFrames) { 319 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; 320 // TODO: error handling, proper usage, etc. 321 c2_status_t err = pool->fetchLinearBlock(mOutBufferSize * numFrames, usage, &block); 322 if (err != C2_OK) { 323 ALOGE("err = %d", err); 324 } 325 326 wView.reset(new C2WriteView(block->map().get())); 327 outPtr = wView->data(); 328 outAvailable = wView->size(); 329 } 330 331 AACENC_InArgs inargs; 332 AACENC_OutArgs outargs; 333 memset(&inargs, 0, sizeof(inargs)); 334 memset(&outargs, 0, sizeof(outargs)); 335 inargs.numInSamples = capacity / sizeof(int16_t); 336 337 void* inBuffer[] = { (unsigned char *)data }; 338 INT inBufferIds[] = { IN_AUDIO_DATA }; 339 INT inBufferSize[] = { (INT)capacity }; 340 INT inBufferElSize[] = { sizeof(int16_t) }; 341 342 AACENC_BufDesc inBufDesc; 343 inBufDesc.numBufs = sizeof(inBuffer) / sizeof(void*); 344 inBufDesc.bufs = (void**)&inBuffer; 345 inBufDesc.bufferIdentifiers = inBufferIds; 346 inBufDesc.bufSizes = inBufferSize; 347 inBufDesc.bufElSizes = inBufferElSize; 348 349 void* outBuffer[] = { outPtr }; 350 INT outBufferIds[] = { OUT_BITSTREAM_DATA }; 351 INT outBufferSize[] = { 0 }; 352 INT outBufferElSize[] = { sizeof(UCHAR) }; 353 354 AACENC_BufDesc outBufDesc; 355 outBufDesc.numBufs = sizeof(outBuffer) / sizeof(void*); 356 outBufDesc.bufs = (void**)&outBuffer; 357 outBufDesc.bufferIdentifiers = outBufferIds; 358 outBufDesc.bufSizes = outBufferSize; 359 outBufDesc.bufElSizes = outBufferElSize; 360 361 // Encode the mInputFrame, which is treated as a modulo buffer 362 AACENC_ERROR encoderErr = AACENC_OK; 363 size_t nOutputBytes = 0; 364 365 while (encoderErr == AACENC_OK && inargs.numInSamples > 0) { 366 memset(&outargs, 0, sizeof(outargs)); 367 368 outBuffer[0] = outPtr; 369 outBufferSize[0] = outAvailable - nOutputBytes; 370 371 encoderErr = aacEncEncode(mAACEncoder, 372 &inBufDesc, 373 &outBufDesc, 374 &inargs, 375 &outargs); 376 377 if (encoderErr == AACENC_OK) { 378 if (outargs.numOutBytes > 0) { 379 mInputSize = 0; 380 int consumed = ((capacity / sizeof(int16_t)) - inargs.numInSamples); 381 mInputTimeUs = work->input.ordinal.timestamp 382 + (consumed * 1000000ll / channelCount / sampleRate); 383 } else { 384 mInputSize += outargs.numInSamples * sizeof(int16_t); 385 mInputTimeUs += outargs.numInSamples * 1000000ll / channelCount / sampleRate; 386 } 387 outPtr += outargs.numOutBytes; 388 nOutputBytes += outargs.numOutBytes; 389 390 if (outargs.numInSamples > 0) { 391 inBuffer[0] = (int16_t *)inBuffer[0] + outargs.numInSamples; 392 inBufferSize[0] -= outargs.numInSamples * sizeof(int16_t); 393 inargs.numInSamples -= outargs.numInSamples; 394 } 395 } 396 ALOGV("encoderErr = %d nOutputBytes = %zu; mInputSize = %zu inargs.numInSamples = %d", 397 encoderErr, nOutputBytes, mInputSize, inargs.numInSamples); 398 } 399 400 if (eos && inBufferSize[0] > 0) { 401 memset(&outargs, 0, sizeof(outargs)); 402 403 outBuffer[0] = outPtr; 404 outBufferSize[0] = outAvailable - nOutputBytes; 405 406 // Flush 407 inargs.numInSamples = -1; 408 409 (void)aacEncEncode(mAACEncoder, 410 &inBufDesc, 411 &outBufDesc, 412 &inargs, 413 &outargs); 414 415 nOutputBytes += outargs.numOutBytes; 416 } 417 418 work->worklets.front()->output.flags = 419 (C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0); 420 work->worklets.front()->output.buffers.clear(); 421 work->worklets.front()->output.ordinal = work->input.ordinal; 422 work->worklets.front()->output.ordinal.timestamp = timestamp; 423 work->workletsProcessed = 1u; 424 if (nOutputBytes) { 425 work->worklets.front()->output.buffers.push_back( 426 createLinearBuffer(block, 0, nOutputBytes)); 427 } 428 429#if 0 430 ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)", 431 nOutputBytes, mInputTimeUs.peekll(), outHeader->nFlags); 432 433 hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen); 434#endif 435} 436 437c2_status_t C2SoftAacEnc::drain( 438 uint32_t drainMode, 439 const std::shared_ptr<C2BlockPool> &pool) { 440 switch (drainMode) { 441 case DRAIN_COMPONENT_NO_EOS: // fall-through 442 case NO_DRAIN: 443 // no-op 444 return C2_OK; 445 case DRAIN_CHAIN: 446 return C2_OMITTED; 447 case DRAIN_COMPONENT_WITH_EOS: 448 break; 449 default: 450 return C2_BAD_VALUE; 451 } 452 453 (void)pool; 454 mSentCodecSpecificData = false; 455 mInputSize = 0u; 456 457 // TODO: we don't have any pending work at this time to drain. 458 return C2_OK; 459} 460 461class C2SoftAacEncFactory : public C2ComponentFactory { 462public: 463 C2SoftAacEncFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>( 464 GetCodec2PlatformComponentStore()->getParamReflector())) { 465 } 466 467 virtual c2_status_t createComponent( 468 c2_node_id_t id, 469 std::shared_ptr<C2Component>* const component, 470 std::function<void(C2Component*)> deleter) override { 471 *component = std::shared_ptr<C2Component>( 472 new C2SoftAacEnc(COMPONENT_NAME, 473 id, 474 std::make_shared<C2SoftAacEnc::IntfImpl>(mHelper)), 475 deleter); 476 return C2_OK; 477 } 478 479 virtual c2_status_t createInterface( 480 c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface, 481 std::function<void(C2ComponentInterface*)> deleter) override { 482 *interface = std::shared_ptr<C2ComponentInterface>( 483 new SimpleInterface<C2SoftAacEnc::IntfImpl>( 484 COMPONENT_NAME, id, std::make_shared<C2SoftAacEnc::IntfImpl>(mHelper)), 485 deleter); 486 return C2_OK; 487 } 488 489 virtual ~C2SoftAacEncFactory() override = default; 490 491private: 492 std::shared_ptr<C2ReflectorHelper> mHelper; 493}; 494 495} // namespace android 496 497extern "C" ::C2ComponentFactory* CreateCodec2Factory() { 498 ALOGV("in %s", __func__); 499 return new ::android::C2SoftAacEncFactory(); 500} 501 502extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) { 503 ALOGV("in %s", __func__); 504 delete factory; 505} 506