/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "C2SoftXaacDec" #include #include #include #include #include #include #include #include #include "C2SoftXaacDec.h" #define DRC_DEFAULT_MOBILE_REF_LEVEL -16.0 /* 64*-0.25dB = -16 dB below full scale for mobile conf */ #define DRC_DEFAULT_MOBILE_DRC_CUT 1.0 /* maximum compression of dynamic range for mobile conf */ #define DRC_DEFAULT_MOBILE_DRC_BOOST 1.0 /* maximum compression of dynamic range for mobile conf */ #define DRC_DEFAULT_MOBILE_DRC_HEAVY C2Config::DRC_COMPRESSION_HEAVY /* switch for heavy compression for mobile conf */ #define DRC_DEFAULT_MOBILE_DRC_EFFECT 3 /* MPEG-D DRC effect type; 3 => Limited playback range */ #define DRC_DEFAULT_MOBILE_ENC_LEVEL (0.25) /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */ #define MAX_CHANNEL_COUNT 8 /* maximum number of audio channels that can be decoded */ // names of properties that can be used to override the default DRC settings #define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level" #define PROP_DRC_OVERRIDE_CUT "aac_drc_cut" #define PROP_DRC_OVERRIDE_BOOST "aac_drc_boost" #define PROP_DRC_OVERRIDE_HEAVY "aac_drc_heavy" #define PROP_DRC_OVERRIDE_ENC_LEVEL "aac_drc_enc_target_level" #define PROP_DRC_OVERRIDE_EFFECT_TYPE "ro.aac_drc_effect_type" #define RETURN_IF_FATAL(retval, str) \ if (retval & IA_FATAL_ERROR) { \ ALOGE("Error in %s: Returned: %d", str, retval); \ return retval; \ } else if (retval != IA_NO_ERROR) { \ ALOGW("Warning in %s: Returned: %d", str, retval); \ } namespace android { namespace { constexpr char COMPONENT_NAME[] = "c2.android.xaac.decoder"; } // namespace class C2SoftXaacDec::IntfImpl : public SimpleInterface::BaseParams { public: explicit IntfImpl(const std::shared_ptr &helper) : SimpleInterface::BaseParams( helper, COMPONENT_NAME, C2Component::KIND_DECODER, C2Component::DOMAIN_AUDIO, MEDIA_MIMETYPE_AUDIO_AAC) { noPrivateBuffers(); noInputReferences(); noOutputReferences(); noInputLatency(); noTimeStretch(); addParameter( DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES) .withConstValue(new C2ComponentAttributesSetting( C2Component::ATTRIB_IS_TEMPORAL)) .build()); addParameter( DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE) .withDefault(new C2StreamSampleRateInfo::output(0u, 44100)) .withFields({C2F(mSampleRate, value).oneOf({ 7350, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 })}) .withSetter((Setter::StrictValueWithNoDeps)) .build()); addParameter( DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT) .withDefault(new C2StreamChannelCountInfo::output(0u, 1)) .withFields({C2F(mChannelCount, value).inRange(1, 8)}) .withSetter(Setter::StrictValueWithNoDeps) .build()); addParameter( DefineParam(mBitrate, C2_PARAMKEY_BITRATE) .withDefault(new C2StreamBitrateInfo::input(0u, 64000)) .withFields({C2F(mBitrate, value).inRange(8000, 960000)}) .withSetter(Setter::NonStrictValueWithNoDeps) .build()); addParameter( DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE) .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 8192)) .build()); addParameter( DefineParam(mAacFormat, C2_PARAMKEY_AAC_PACKAGING) .withDefault(new C2StreamAacFormatInfo::input(0u, C2Config::AAC_PACKAGING_RAW)) .withFields({C2F(mAacFormat, value).oneOf({ C2Config::AAC_PACKAGING_RAW, C2Config::AAC_PACKAGING_ADTS })}) .withSetter(Setter::StrictValueWithNoDeps) .build()); addParameter( DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) .withDefault(new C2StreamProfileLevelInfo::input(0u, C2Config::PROFILE_AAC_LC, C2Config::LEVEL_UNUSED)) .withFields({ C2F(mProfileLevel, profile).oneOf({ C2Config::PROFILE_AAC_LC, C2Config::PROFILE_AAC_HE, C2Config::PROFILE_AAC_HE_PS, C2Config::PROFILE_AAC_LD, C2Config::PROFILE_AAC_ELD, C2Config::PROFILE_AAC_XHE}), C2F(mProfileLevel, level).oneOf({ C2Config::LEVEL_UNUSED }) }) .withSetter(ProfileLevelSetter) .build()); addParameter( DefineParam(mDrcCompressMode, C2_PARAMKEY_DRC_COMPRESSION_MODE) .withDefault(new C2StreamDrcCompressionModeTuning::input(0u, C2Config::DRC_COMPRESSION_HEAVY)) .withFields({ C2F(mDrcCompressMode, value).oneOf({ C2Config::DRC_COMPRESSION_ODM_DEFAULT, C2Config::DRC_COMPRESSION_NONE, C2Config::DRC_COMPRESSION_LIGHT, C2Config::DRC_COMPRESSION_HEAVY}) }) .withSetter(Setter::StrictValueWithNoDeps) .build()); addParameter( DefineParam(mDrcTargetRefLevel, C2_PARAMKEY_DRC_TARGET_REFERENCE_LEVEL) .withDefault(new C2StreamDrcTargetReferenceLevelTuning::input(0u, DRC_DEFAULT_MOBILE_REF_LEVEL)) .withFields({C2F(mDrcTargetRefLevel, value).inRange(-31.75, 0.25)}) .withSetter(Setter::StrictValueWithNoDeps) .build()); addParameter( DefineParam(mDrcEncTargetLevel, C2_PARAMKEY_DRC_ENCODED_TARGET_LEVEL) .withDefault(new C2StreamDrcEncodedTargetLevelTuning::input(0u, DRC_DEFAULT_MOBILE_ENC_LEVEL)) .withFields({C2F(mDrcEncTargetLevel, value).inRange(-31.75, 0.25)}) .withSetter(Setter::StrictValueWithNoDeps) .build()); addParameter( DefineParam(mDrcBoostFactor, C2_PARAMKEY_DRC_BOOST_FACTOR) .withDefault(new C2StreamDrcBoostFactorTuning::input(0u, DRC_DEFAULT_MOBILE_DRC_BOOST)) .withFields({C2F(mDrcBoostFactor, value).inRange(0, 1.)}) .withSetter(Setter::StrictValueWithNoDeps) .build()); addParameter( DefineParam(mDrcAttenuationFactor, C2_PARAMKEY_DRC_ATTENUATION_FACTOR) .withDefault(new C2StreamDrcAttenuationFactorTuning::input(0u, DRC_DEFAULT_MOBILE_DRC_CUT)) .withFields({C2F(mDrcAttenuationFactor, value).inRange(0, 1.)}) .withSetter(Setter::StrictValueWithNoDeps) .build()); addParameter( DefineParam(mDrcEffectType, C2_PARAMKEY_DRC_EFFECT_TYPE) .withDefault(new C2StreamDrcEffectTypeTuning::input(0u, C2Config::DRC_EFFECT_LIMITED_PLAYBACK_RANGE)) .withFields({ C2F(mDrcEffectType, value).oneOf({ C2Config::DRC_EFFECT_ODM_DEFAULT, C2Config::DRC_EFFECT_OFF, C2Config::DRC_EFFECT_NONE, C2Config::DRC_EFFECT_LATE_NIGHT, C2Config::DRC_EFFECT_NOISY_ENVIRONMENT, C2Config::DRC_EFFECT_LIMITED_PLAYBACK_RANGE, C2Config::DRC_EFFECT_LOW_PLAYBACK_LEVEL, C2Config::DRC_EFFECT_DIALOG_ENHANCEMENT, C2Config::DRC_EFFECT_GENERAL_COMPRESSION}) }) .withSetter(Setter::StrictValueWithNoDeps) .build()); } bool isAdts() const { return mAacFormat->value == C2Config::AAC_PACKAGING_ADTS; } uint32_t getBitrate() const { return mBitrate->value; } static C2R ProfileLevelSetter(bool mayBlock, C2P &me) { (void)mayBlock; (void)me; // TODO: validate return C2R::Ok(); } int32_t getDrcCompressMode() const { return mDrcCompressMode->value == C2Config::DRC_COMPRESSION_HEAVY ? 1 : 0; } int32_t getDrcTargetRefLevel() const { return (mDrcTargetRefLevel->value <= 0 ? -mDrcTargetRefLevel->value * 4. + 0.5 : -1); } int32_t getDrcEncTargetLevel() const { return (mDrcEncTargetLevel->value <= 0 ? -mDrcEncTargetLevel->value * 4. + 0.5 : -1); } int32_t getDrcBoostFactor() const { return mDrcBoostFactor->value * 127. + 0.5; } int32_t getDrcAttenuationFactor() const { return mDrcAttenuationFactor->value * 127. + 0.5; } int32_t getDrcEffectType() const { return mDrcEffectType->value; } private: std::shared_ptr mSampleRate; std::shared_ptr mChannelCount; std::shared_ptr mBitrate; std::shared_ptr mInputMaxBufSize; std::shared_ptr mAacFormat; std::shared_ptr mProfileLevel; std::shared_ptr mDrcCompressMode; std::shared_ptr mDrcTargetRefLevel; std::shared_ptr mDrcEncTargetLevel; std::shared_ptr mDrcBoostFactor; std::shared_ptr mDrcAttenuationFactor; std::shared_ptr mDrcEffectType; // TODO Add : C2StreamAacSbrModeTuning }; C2SoftXaacDec::C2SoftXaacDec( const char* name, c2_node_id_t id, const std::shared_ptr &intfImpl) : SimpleC2Component(std::make_shared>(name, id, intfImpl)), mIntf(intfImpl), mXheaacCodecHandle(nullptr), mMpegDDrcHandle(nullptr), mOutputDrainBuffer(nullptr) { } C2SoftXaacDec::~C2SoftXaacDec() { onRelease(); } c2_status_t C2SoftXaacDec::onInit() { mOutputFrameLength = 1024; mInputBuffer = nullptr; mOutputBuffer = nullptr; mSampFreq = 0; mNumChannels = 0; mPcmWdSz = 0; mChannelMask = 0; mNumOutBytes = 0; mCurFrameIndex = 0; mCurTimestamp = 0; mIsCodecInitialized = false; mIsCodecConfigFlushRequired = false; mSignalledOutputEos = false; mSignalledError = false; mOutputDrainBufferWritePos = 0; mDRCFlag = 0; mMpegDDRCPresent = 0; mMemoryVec.clear(); mDrcMemoryVec.clear(); IA_ERRORCODE err = initDecoder(); return err == IA_NO_ERROR ? C2_OK : C2_CORRUPTED; } c2_status_t C2SoftXaacDec::onStop() { mOutputFrameLength = 1024; drainDecoder(); // reset the "configured" state mSampFreq = 0; mNumChannels = 0; mPcmWdSz = 0; mChannelMask = 0; mNumOutBytes = 0; mCurFrameIndex = 0; mCurTimestamp = 0; mSignalledOutputEos = false; mSignalledError = false; mOutputDrainBufferWritePos = 0; mDRCFlag = 0; mMpegDDRCPresent = 0; return C2_OK; } void C2SoftXaacDec::onReset() { (void)onStop(); } void C2SoftXaacDec::onRelease() { IA_ERRORCODE errCode = deInitXAACDecoder(); if (IA_NO_ERROR != errCode) ALOGE("deInitXAACDecoder() failed %d", errCode); errCode = deInitMPEGDDDrc(); if (IA_NO_ERROR != errCode) ALOGE("deInitMPEGDDDrc() failed %d", errCode); if (mOutputDrainBuffer) { delete[] mOutputDrainBuffer; mOutputDrainBuffer = nullptr; } } IA_ERRORCODE C2SoftXaacDec::initDecoder() { ALOGV("initDecoder()"); IA_ERRORCODE err_code = IA_NO_ERROR; err_code = initXAACDecoder(); if (err_code != IA_NO_ERROR) { ALOGE("initXAACDecoder Failed"); /* Call deInit to free any allocated memory */ deInitXAACDecoder(); return IA_FATAL_ERROR; } if (!mOutputDrainBuffer) { mOutputDrainBuffer = new (std::nothrow) char[kOutputDrainBufferSize]; if (!mOutputDrainBuffer) return IA_FATAL_ERROR; } err_code = initXAACDrc(); RETURN_IF_FATAL(err_code, "initXAACDrc"); return IA_NO_ERROR; } static void fillEmptyWork(const std::unique_ptr& work) { uint32_t flags = 0; if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) { flags |= C2FrameData::FLAG_END_OF_STREAM; ALOGV("signalling eos"); } work->worklets.front()->output.flags = (C2FrameData::flags_t)flags; work->worklets.front()->output.buffers.clear(); work->worklets.front()->output.ordinal = work->input.ordinal; work->workletsProcessed = 1u; } void C2SoftXaacDec::finishWork(const std::unique_ptr& work, const std::shared_ptr& pool) { ALOGV("mCurFrameIndex = %" PRIu64, mCurFrameIndex); std::shared_ptr block; C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}; // TODO: error handling, proper usage, etc. c2_status_t err = pool->fetchLinearBlock(mOutputDrainBufferWritePos, usage, &block); if (err != C2_OK) { ALOGE("fetchLinearBlock failed : err = %d", err); work->result = C2_NO_MEMORY; return; } C2WriteView wView = block->map().get(); int16_t* outBuffer = reinterpret_cast(wView.data()); memcpy(outBuffer, mOutputDrainBuffer, mOutputDrainBufferWritePos); auto fillWork = [buffer = createLinearBuffer(block, 0, mOutputDrainBufferWritePos)]( const std::unique_ptr& work) { uint32_t flags = 0; if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) { flags |= C2FrameData::FLAG_END_OF_STREAM; ALOGV("signalling eos"); } work->worklets.front()->output.flags = (C2FrameData::flags_t)flags; work->worklets.front()->output.buffers.clear(); work->worklets.front()->output.buffers.push_back(buffer); work->worklets.front()->output.ordinal = work->input.ordinal; work->workletsProcessed = 1u; }; mOutputDrainBufferWritePos = 0; if (work && work->input.ordinal.frameIndex == c2_cntr64_t(mCurFrameIndex)) { fillWork(work); } else { finish(mCurFrameIndex, fillWork); } ALOGV("out timestamp %" PRIu64 " / %u", mCurTimestamp, block->capacity()); } void C2SoftXaacDec::process(const std::unique_ptr& work, const std::shared_ptr& pool) { // Initialize output work work->result = C2_OK; work->workletsProcessed = 1u; work->worklets.front()->output.configUpdate.clear(); work->worklets.front()->output.flags = work->input.flags; if (mSignalledError || mSignalledOutputEos) { work->result = C2_BAD_VALUE; return; } uint8_t* inBuffer = nullptr; uint32_t inBufferLength = 0; C2ReadView view = mDummyReadView; size_t offset = 0u; size_t size = 0u; if (!work->input.buffers.empty()) { view = work->input.buffers[0]->data().linearBlocks().front().map().get(); size = view.capacity(); } if (size && view.error()) { ALOGE("read view map failed %d", view.error()); work->result = view.error(); return; } bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0; bool codecConfig = (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0; if (codecConfig) { if (size == 0u) { ALOGE("empty codec config"); mSignalledError = true; work->result = C2_CORRUPTED; return; } // const_cast because of libAACdec method signature. inBuffer = const_cast(view.data() + offset); inBufferLength = size; /* GA header configuration sent to Decoder! */ IA_ERRORCODE err_code = configXAACDecoder(inBuffer, inBufferLength); if (IA_NO_ERROR != err_code) { ALOGE("configXAACDecoder err_code = %d", err_code); mSignalledError = true; work->result = C2_CORRUPTED; return; } work->worklets.front()->output.flags = work->input.flags; work->worklets.front()->output.ordinal = work->input.ordinal; work->worklets.front()->output.buffers.clear(); return; } mCurFrameIndex = work->input.ordinal.frameIndex.peeku(); mCurTimestamp = work->input.ordinal.timestamp.peeku(); mOutputDrainBufferWritePos = 0; char* tempOutputDrainBuffer = mOutputDrainBuffer; while (size > 0u) { if ((kOutputDrainBufferSize * sizeof(int16_t) - mOutputDrainBufferWritePos) < (mOutputFrameLength * sizeof(int16_t) * mNumChannels)) { ALOGV("skipping decode: not enough space left in DrainBuffer"); break; } ALOGV("inAttribute size = %zu", size); if (mIntf->isAdts()) { ALOGV("ADTS"); size_t adtsHeaderSize = 0; // skip 30 bits, aac_frame_length follows. // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? const uint8_t* adtsHeader = view.data() + offset; bool signalError = false; if (size < 7) { ALOGE("Audio data too short to contain even the ADTS header. " "Got %zu bytes.", size); hexdump(adtsHeader, size); signalError = true; } else { bool protectionAbsent = (adtsHeader[1] & 1); unsigned aac_frame_length = ((adtsHeader[3] & 3) << 11) | (adtsHeader[4] << 3) | (adtsHeader[5] >> 5); if (size < aac_frame_length) { ALOGE("Not enough audio data for the complete frame. " "Got %zu bytes, frame size according to the ADTS " "header is %u bytes.", size, aac_frame_length); hexdump(adtsHeader, size); signalError = true; } else { adtsHeaderSize = (protectionAbsent ? 7 : 9); if (aac_frame_length < adtsHeaderSize) { signalError = true; } else { // const_cast because of libAACdec method signature. inBuffer = const_cast(adtsHeader + adtsHeaderSize); inBufferLength = aac_frame_length - adtsHeaderSize; offset += adtsHeaderSize; size -= adtsHeaderSize; } } } if (signalError) { mSignalledError = true; work->result = C2_CORRUPTED; return; } } else { ALOGV("Non ADTS"); // const_cast because of libAACdec method signature. inBuffer = const_cast(view.data() + offset); inBufferLength = size; } signed int prevSampleRate = mSampFreq; signed int prevNumChannels = mNumChannels; /* XAAC decoder expects first frame to be fed via configXAACDecoder API * which should initialize the codec. Once this state is reached, call the * decodeXAACStream API with same frame to decode! */ if (!mIsCodecInitialized) { IA_ERRORCODE err_code = configXAACDecoder(inBuffer, inBufferLength); if (IA_NO_ERROR != err_code) { ALOGE("configXAACDecoder Failed 2 err_code = %d", err_code); mSignalledError = true; work->result = C2_CORRUPTED; return; } if ((mSampFreq != prevSampleRate) || (mNumChannels != prevNumChannels)) { ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels", prevSampleRate, mSampFreq, prevNumChannels, mNumChannels); C2StreamSampleRateInfo::output sampleRateInfo(0u, mSampFreq); C2StreamChannelCountInfo::output channelCountInfo(0u, mNumChannels); std::vector> failures; c2_status_t err = mIntf->config( { &sampleRateInfo, &channelCountInfo }, C2_MAY_BLOCK, &failures); if (err == OK) { work->worklets.front()->output.configUpdate.push_back( C2Param::Copy(sampleRateInfo)); work->worklets.front()->output.configUpdate.push_back( C2Param::Copy(channelCountInfo)); } else { ALOGE("Config Update failed"); mSignalledError = true; work->result = C2_CORRUPTED; return; } } } signed int bytesConsumed = 0; IA_ERRORCODE errorCode = IA_NO_ERROR; if (mIsCodecInitialized) { mIsCodecConfigFlushRequired = true; errorCode = decodeXAACStream(inBuffer, inBufferLength, &bytesConsumed, &mNumOutBytes); } else if (!mIsCodecConfigFlushRequired) { ALOGW("Assumption that first frame after header initializes decoder Failed!"); mSignalledError = true; work->result = C2_CORRUPTED; return; } size -= bytesConsumed; offset += bytesConsumed; if (inBufferLength != (uint32_t)bytesConsumed) ALOGW("All data not consumed"); /* In case of error, decoder would have given out empty buffer */ if ((IA_NO_ERROR != errorCode) && (0 == mNumOutBytes) && mIsCodecInitialized) mNumOutBytes = mOutputFrameLength * (mPcmWdSz / 8) * mNumChannels; if (!bytesConsumed) { ALOGW("bytesConsumed = 0 should never happen"); } if ((uint32_t)mNumOutBytes > mOutputFrameLength * sizeof(int16_t) * mNumChannels) { ALOGE("mNumOutBytes > mOutputFrameLength * sizeof(int16_t) * mNumChannels, should never happen"); mSignalledError = true; work->result = C2_CORRUPTED; return; } if (IA_NO_ERROR != errorCode) { // TODO: check for overflow, ASAN memset(mOutputBuffer, 0, mNumOutBytes); // Discard input buffer. size = 0; // fall through } memcpy(tempOutputDrainBuffer, mOutputBuffer, mNumOutBytes); tempOutputDrainBuffer += mNumOutBytes; mOutputDrainBufferWritePos += mNumOutBytes; } if (mOutputDrainBufferWritePos) { finishWork(work, pool); } else { fillEmptyWork(work); } if (eos) mSignalledOutputEos = true; } c2_status_t C2SoftXaacDec::drain(uint32_t drainMode, const std::shared_ptr& pool) { (void)pool; if (drainMode == NO_DRAIN) { ALOGW("drain with NO_DRAIN: no-op"); return C2_OK; } if (drainMode == DRAIN_CHAIN) { ALOGW("DRAIN_CHAIN not supported"); return C2_OMITTED; } return C2_OK; } IA_ERRORCODE C2SoftXaacDec::configflushDecode() { IA_ERRORCODE err_code; uint32_t ui_init_done; uint32_t inBufferLength = 8203; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_FLUSH_MEM, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_FLUSH_MEM"); err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_INPUT_BYTES, 0, &inBufferLength); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES"); err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_FLUSH_MEM, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_FLUSH_MEM"); err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_DONE_QUERY, &ui_init_done); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_DONE_QUERY"); if (ui_init_done) { err_code = getXAACStreamInfo(); RETURN_IF_FATAL(err_code, "getXAACStreamInfo"); ALOGV("Found Codec with below config---\nsampFreq %d\nnumChannels %d\npcmWdSz %d\nchannelMask %d\noutputFrameLength %d", mSampFreq, mNumChannels, mPcmWdSz, mChannelMask, mOutputFrameLength); mIsCodecInitialized = true; } return IA_NO_ERROR; } c2_status_t C2SoftXaacDec::onFlush_sm() { if (mIsCodecInitialized) { IA_ERRORCODE err_code = configflushDecode(); if (err_code != IA_NO_ERROR) { ALOGE("Error in configflushDecode: Error %d", err_code); } } drainDecoder(); mSignalledOutputEos = false; mSignalledError = false; return C2_OK; } IA_ERRORCODE C2SoftXaacDec::drainDecoder() { /* Output delay compensation logic should sit here. */ /* Nothing to be done as XAAC decoder does not introduce output buffer delay */ return 0; } IA_ERRORCODE C2SoftXaacDec::initXAACDecoder() { /* First part */ /* Error Handler Init */ /* Get Library Name, Library Version and API Version */ /* Initialize API structure + Default config set */ /* Set config params from user */ /* Initialize memory tables */ /* Get memory information and allocate memory */ mInputBufferSize = 0; mInputBuffer = nullptr; mOutputBuffer = nullptr; /* Process struct initing end */ /* ******************************************************************/ /* Initialize API structure and set config params to default */ /* ******************************************************************/ /* API size */ uint32_t pui_api_size; /* Get the API size */ IA_ERRORCODE err_code = ixheaacd_dec_api(nullptr, IA_API_CMD_GET_API_SIZE, 0, &pui_api_size); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_API_SIZE"); /* Allocate memory for API */ mXheaacCodecHandle = memalign(4, pui_api_size); if (!mXheaacCodecHandle) { ALOGE("malloc for pui_api_size + 4 >> %d Failed", pui_api_size + 4); return IA_FATAL_ERROR; } mMemoryVec.push(mXheaacCodecHandle); /* Set the config params to default values */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS"); /* Get the API size */ err_code = ia_drc_dec_api(nullptr, IA_API_CMD_GET_API_SIZE, 0, &pui_api_size); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_API_SIZE"); /* Allocate memory for API */ mMpegDDrcHandle = memalign(4, pui_api_size); if (!mMpegDDrcHandle) { ALOGE("malloc for pui_api_size + 4 >> %d Failed", pui_api_size + 4); return IA_FATAL_ERROR; } mMemoryVec.push(mMpegDDrcHandle); /* Set the config params to default values */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS"); /* ******************************************************************/ /* Set config parameters */ /* ******************************************************************/ uint32_t ui_mp4_flag = 1; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_ISMP4, &ui_mp4_flag); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_ISMP4"); /* ******************************************************************/ /* Initialize Memory info tables */ /* ******************************************************************/ uint32_t ui_proc_mem_tabs_size; pVOID pv_alloc_ptr; /* Get memory info tables size */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_MEMTABS_SIZE, 0, &ui_proc_mem_tabs_size); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEMTABS_SIZE"); pv_alloc_ptr = memalign(4, ui_proc_mem_tabs_size); if (!pv_alloc_ptr) { ALOGE("Malloc for size (ui_proc_mem_tabs_size + 4) = %d failed!", ui_proc_mem_tabs_size + 4); return IA_FATAL_ERROR; } mMemoryVec.push(pv_alloc_ptr); /* Set pointer for process memory tables */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_MEMTABS_PTR, 0, pv_alloc_ptr); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEMTABS_PTR"); /* initialize the API, post config, fill memory tables */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS"); /* ******************************************************************/ /* Allocate Memory with info from library */ /* ******************************************************************/ /* There are four different types of memories, that needs to be allocated */ /* persistent,scratch,input and output */ for (int i = 0; i < 4; i++) { int ui_size = 0, ui_alignment = 0, ui_type = 0; /* Get memory size */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_MEM_INFO_SIZE, i, &ui_size); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_SIZE"); /* Get memory alignment */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_MEM_INFO_ALIGNMENT, i, &ui_alignment); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_ALIGNMENT"); /* Get memory type */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_MEM_INFO_TYPE, i, &ui_type); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_TYPE"); pv_alloc_ptr = memalign(ui_alignment, ui_size); if (!pv_alloc_ptr) { ALOGE("Malloc for size (ui_size + ui_alignment) = %d failed!", ui_size + ui_alignment); return IA_FATAL_ERROR; } mMemoryVec.push(pv_alloc_ptr); /* Set the buffer pointer */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_MEM_PTR, i, pv_alloc_ptr); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR"); if (ui_type == IA_MEMTYPE_INPUT) { mInputBuffer = (pWORD8)pv_alloc_ptr; mInputBufferSize = ui_size; } if (ui_type == IA_MEMTYPE_OUTPUT) mOutputBuffer = (pWORD8)pv_alloc_ptr; } /* End first part */ return IA_NO_ERROR; } status_t C2SoftXaacDec::initXAACDrc() { IA_ERRORCODE err_code = IA_NO_ERROR; unsigned int ui_drc_val; // DRC_PRES_MODE_WRAP_DESIRED_TARGET int32_t targetRefLevel = mIntf->getDrcTargetRefLevel(); ALOGV("AAC decoder using desired DRC target reference level of %d", targetRefLevel); ui_drc_val = (unsigned int)targetRefLevel; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LEVEL, &ui_drc_val); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LEVEL"); /* Use ui_drc_val from PROP_DRC_OVERRIDE_REF_LEVEL or DRC_DEFAULT_MOBILE_REF_LEVEL * for IA_ENHAACPLUS_DEC_DRC_TARGET_LOUDNESS too */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_DRC_TARGET_LOUDNESS, &ui_drc_val); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_DRC_TARGET_LOUDNESS"); int32_t attenuationFactor = mIntf->getDrcAttenuationFactor(); ALOGV("AAC decoder using desired DRC attenuation factor of %d", attenuationFactor); ui_drc_val = (unsigned int)attenuationFactor; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_CUT, &ui_drc_val); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_CUT"); // DRC_PRES_MODE_WRAP_DESIRED_BOOST_FACTOR int32_t boostFactor = mIntf->getDrcBoostFactor(); ALOGV("AAC decoder using desired DRC boost factor of %d", boostFactor); ui_drc_val = (unsigned int)boostFactor; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_BOOST, &ui_drc_val); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_BOOST"); // DRC_PRES_MODE_WRAP_DESIRED_HEAVY int32_t compressMode = mIntf->getDrcCompressMode(); ALOGV("AAC decoder using desried DRC heavy compression switch of %d", compressMode); ui_drc_val = (unsigned int)compressMode; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_HEAVY_COMP, &ui_drc_val); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_HEAVY_COMP"); // AAC_UNIDRC_SET_EFFECT int32_t effectType = mIntf->getDrcEffectType(); ALOGV("AAC decoder using MPEG-D DRC effect type %d", effectType); ui_drc_val = (unsigned int)effectType; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_DRC_EFFECT_TYPE, &ui_drc_val); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_DRC_EFFECT_TYPE"); return IA_NO_ERROR; } IA_ERRORCODE C2SoftXaacDec::deInitXAACDecoder() { ALOGV("deInitXAACDecoder"); /* Error code */ IA_ERRORCODE err_code = IA_NO_ERROR; if (mXheaacCodecHandle) { /* Tell that the input is over in this buffer */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INPUT_OVER, 0, nullptr); } /* Irrespective of error returned in IA_API_CMD_INPUT_OVER, free allocated memory */ for (void* buf : mMemoryVec) { if (buf) free(buf); } mMemoryVec.clear(); mXheaacCodecHandle = nullptr; return err_code; } IA_ERRORCODE C2SoftXaacDec::deInitMPEGDDDrc() { ALOGV("deInitMPEGDDDrc"); for (void* buf : mDrcMemoryVec) { if (buf) free(buf); } mDrcMemoryVec.clear(); return IA_NO_ERROR; } IA_ERRORCODE C2SoftXaacDec::configXAACDecoder(uint8_t* inBuffer, uint32_t inBufferLength) { if (mInputBufferSize < inBufferLength) { ALOGE("Cannot config AAC, input buffer size %d < inBufferLength %d", mInputBufferSize, inBufferLength); return false; } /* Copy the buffer passed by Android plugin to codec input buffer */ memcpy(mInputBuffer, inBuffer, inBufferLength); /* Set number of bytes to be processed */ IA_ERRORCODE err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_INPUT_BYTES, 0, &inBufferLength); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES"); if (mIsCodecConfigFlushRequired) { /* If codec is already initialized, then GA header is passed again */ /* Need to call the Flush API instead of INIT_PROCESS */ mIsCodecInitialized = false; /* Codec needs to be Reinitialized after flush */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_GA_HDR, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_GA_HDR"); } else { /* Initialize the process */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_PROCESS, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_PROCESS"); } uint32_t ui_init_done; /* Checking for end of initialization */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_DONE_QUERY, &ui_init_done); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_DONE_QUERY"); /* How much buffer is used in input buffers */ int32_t i_bytes_consumed; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CURIDX_INPUT_BUF, 0, &i_bytes_consumed); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_CURIDX_INPUT_BUF"); if (ui_init_done) { err_code = getXAACStreamInfo(); RETURN_IF_FATAL(err_code, "getXAACStreamInfo"); ALOGI("Found Codec with below config---\nsampFreq %d\nnumChannels %d\npcmWdSz %d\nchannelMask %d\noutputFrameLength %d", mSampFreq, mNumChannels, mPcmWdSz, mChannelMask, mOutputFrameLength); mIsCodecInitialized = true; err_code = configMPEGDDrc(); RETURN_IF_FATAL(err_code, "configMPEGDDrc"); } return IA_NO_ERROR; } IA_ERRORCODE C2SoftXaacDec::initMPEGDDDrc() { IA_ERRORCODE err_code = IA_NO_ERROR; for (int i = 0; i < (WORD32)2; i++) { WORD32 ui_size, ui_alignment, ui_type; pVOID pv_alloc_ptr; /* Get memory size */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_SIZE, i, &ui_size); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_SIZE"); /* Get memory alignment */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_ALIGNMENT, i, &ui_alignment); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_ALIGNMENT"); /* Get memory type */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEM_INFO_TYPE, i, &ui_type); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEM_INFO_TYPE"); pv_alloc_ptr = memalign(4, ui_size); if (pv_alloc_ptr == nullptr) { ALOGE(" Cannot create requested memory %d", ui_size); return IA_FATAL_ERROR; } mDrcMemoryVec.push(pv_alloc_ptr); /* Set the buffer pointer */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, i, pv_alloc_ptr); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR"); } WORD32 ui_size; ui_size = 8192 * 2; mDrcInBuf = (int8_t*)memalign(4, ui_size); if (mDrcInBuf == nullptr) { ALOGE(" Cannot create requested memory %d", ui_size); return IA_FATAL_ERROR; } mDrcMemoryVec.push(mDrcInBuf); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, 2, mDrcInBuf); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR"); mDrcOutBuf = (int8_t*)memalign(4, ui_size); if (mDrcOutBuf == nullptr) { ALOGE(" Cannot create requested memory %d", ui_size); return IA_FATAL_ERROR; } mDrcMemoryVec.push(mDrcOutBuf); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEM_PTR, 3, mDrcOutBuf); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEM_PTR"); return IA_NO_ERROR; } int C2SoftXaacDec::configMPEGDDrc() { IA_ERRORCODE err_code = IA_NO_ERROR; int i_effect_type; int i_loud_norm; int i_target_loudness; unsigned int i_sbr_mode; uint32_t ui_proc_mem_tabs_size = 0; pVOID pv_alloc_ptr = NULL; /* Sampling Frequency */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_PARAM_SAMP_FREQ, &mSampFreq); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_SAMP_FREQ"); /* Total Number of Channels */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_PARAM_NUM_CHANNELS, &mNumChannels); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_NUM_CHANNELS"); /* PCM word size */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_PARAM_PCM_WDSZ, &mPcmWdSz); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_PCM_WDSZ"); /*Set Effect Type*/ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_EFFECT_TYPE, &i_effect_type); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_EFFECT_TYPE"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_DRC_EFFECT_TYPE, &i_effect_type); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_EFFECT_TYPE"); /*Set target loudness */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LOUDNESS, &i_target_loudness); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LOUDNESS"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_DRC_TARGET_LOUDNESS, &i_target_loudness); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_TARGET_LOUDNESS"); /*Set loud_norm_flag*/ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_LOUD_NORM, &i_loud_norm); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_LOUD_NORM"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_DRC_LOUD_NORM, &i_loud_norm); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_LOUD_NORM"); err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE, &i_sbr_mode); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE"); /* Get memory info tables size */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_MEMTABS_SIZE, 0, &ui_proc_mem_tabs_size); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_MEMTABS_SIZE"); pv_alloc_ptr = memalign(4, ui_proc_mem_tabs_size); if (pv_alloc_ptr == NULL) { ALOGE(" Cannot create requested memory %d", ui_proc_mem_tabs_size); return IA_FATAL_ERROR; } memset(pv_alloc_ptr, 0, ui_proc_mem_tabs_size); mMemoryVec.push(pv_alloc_ptr); /* Set pointer for process memory tables */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_MEMTABS_PTR, 0, pv_alloc_ptr); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_MEMTABS_PTR"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS"); /* Free any memory that is allocated for MPEG D Drc so far */ deInitMPEGDDDrc(); err_code = initMPEGDDDrc(); if (err_code != IA_NO_ERROR) { ALOGE("initMPEGDDDrc failed with error %d", err_code); deInitMPEGDDDrc(); return err_code; } /* DRC buffers buf[0] - contains extension element pay load loudness related buf[1] - contains extension element pay load*/ { VOID* p_array[2][16]; WORD32 ii; WORD32 buf_sizes[2][16]; WORD32 num_elements; WORD32 num_config_ext; WORD32 bit_str_fmt = 1; WORD32 uo_num_chan; memset(buf_sizes, 0, 32 * sizeof(WORD32)); err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_EXT_ELE_BUF_SIZES, &buf_sizes[0][0]); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_EXT_ELE_BUF_SIZES"); err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_EXT_ELE_PTR, &p_array); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_EXT_ELE_PTR"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_SET_BUFF_PTR, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_SET_BUFF_PTR"); err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_NUM_ELE, &num_elements); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_NUM_ELE"); err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_NUM_CONFIG_EXT, &num_config_ext); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_NUM_CONFIG_EXT"); for (ii = 0; ii < num_config_ext; ii++) { /*copy loudness bitstream*/ if (buf_sizes[0][ii] > 0) { memcpy(mDrcInBuf, p_array[0][ii], buf_sizes[0][ii]); /*Set bitstream_split_format */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); /* Set number of bytes to be processed */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_IL_BS, 0, &buf_sizes[0][ii]); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES_IL_BS"); /* Execute process */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_CPY_IL_BSF_BUFF, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_CPY_IL_BSF_BUFF"); mDRCFlag = 1; } } for (ii = 0; ii < num_elements; ii++) { /*copy config bitstream*/ if (buf_sizes[1][ii] > 0) { memcpy(mDrcInBuf, p_array[1][ii], buf_sizes[1][ii]); /* Set number of bytes to be processed */ /*Set bitstream_split_format */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_IC_BS, 0, &buf_sizes[1][ii]); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES_IC_BS"); /* Execute process */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_CPY_IC_BSF_BUFF, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_CPY_IC_BSF_BUFF"); mDRCFlag = 1; } } if (mDRCFlag == 1) { mMpegDDRCPresent = 1; } else { mMpegDDRCPresent = 0; } /*Read interface buffer config file bitstream*/ if (mMpegDDRCPresent == 1) { WORD32 interface_is_present = 1; if (i_sbr_mode != 0) { if (i_sbr_mode == 1) { mOutputFrameLength = 2048; } else if (i_sbr_mode == 3) { mOutputFrameLength = 4096; } else { mOutputFrameLength = 1024; } } else { mOutputFrameLength = 4096; } err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_PARAM_FRAME_SIZE, (WORD32 *)&mOutputFrameLength); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_FRAME_SIZE"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_PARAM_INT_PRESENT, &interface_is_present); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_INT_PRESENT"); /* Execute process */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_CPY_IN_BSF_BUFF, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_CPY_IN_BSF_BUFF"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_PROCESS, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_INIT_PROCESS"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_PARAM_NUM_CHANNELS, &uo_num_chan); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_NUM_CHANNELS"); } } return err_code; } IA_ERRORCODE C2SoftXaacDec::decodeXAACStream(uint8_t* inBuffer, uint32_t inBufferLength, int32_t* bytesConsumed, int32_t* outBytes) { if (mInputBufferSize < inBufferLength) { ALOGE("Cannot config AAC, input buffer size %d < inBufferLength %d", mInputBufferSize, inBufferLength); return -1; } /* Copy the buffer passed by Android plugin to codec input buffer */ memcpy(mInputBuffer, inBuffer, inBufferLength); /* Set number of bytes to be processed */ IA_ERRORCODE err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_INPUT_BYTES, 0, &inBufferLength); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES"); /* Execute process */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE"); /* Checking for end of processing */ uint32_t ui_exec_done; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DONE_QUERY, &ui_exec_done); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DONE_QUERY"); int32_t num_preroll = 0; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES, &num_preroll); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES"); { int32_t preroll_frame_offset = 0; do { if (ui_exec_done != 1) { VOID* p_array; // ITTIAM:buffer to handle gain payload WORD32 buf_size = 0; // ITTIAM:gain payload length WORD32 bit_str_fmt = 1; WORD32 gain_stream_flag = 1; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN, &buf_size); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN"); err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF, &p_array); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF"); if (buf_size > 0) { /*Set bitstream_split_format */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); memcpy(mDrcInBuf, p_array, buf_size); /* Set number of bytes to be processed */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_BS, 0, &buf_size); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG, &gain_stream_flag); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); /* Execute process */ err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_CPY_BSF_BUFF, nullptr); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT"); mMpegDDRCPresent = 1; } } /* How much buffer is used in input buffers */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CURIDX_INPUT_BUF, 0, bytesConsumed); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_CURIDX_INPUT_BUF"); /* Get the output bytes */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_OUTPUT_BYTES, 0, outBytes); RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_OUTPUT_BYTES"); if (mMpegDDRCPresent == 1) { memcpy(mDrcInBuf, mOutputBuffer + preroll_frame_offset, *outBytes); preroll_frame_offset += *outBytes; err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES, 0, outBytes); RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, nullptr); RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE"); memcpy(mOutputBuffer, mDrcOutBuf, *outBytes); } num_preroll--; } while (num_preroll > 0); } return IA_NO_ERROR; } IA_ERRORCODE C2SoftXaacDec::getXAACStreamInfo() { IA_ERRORCODE err_code = IA_NO_ERROR; /* Sampling frequency */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_SAMP_FREQ, &mSampFreq); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_SAMP_FREQ"); /* Total Number of Channels */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_NUM_CHANNELS, &mNumChannels); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_NUM_CHANNELS"); if (mNumChannels > MAX_CHANNEL_COUNT) { ALOGE(" No of channels are more than max channels\n"); return IA_FATAL_ERROR; } /* PCM word size */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_PCM_WDSZ, &mPcmWdSz); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_PCM_WDSZ"); if ((mPcmWdSz / 8) != 2) { ALOGE(" No of channels are more than max channels\n"); return IA_FATAL_ERROR; } /* channel mask to tell the arrangement of channels in bit stream */ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_CHANNEL_MASK, &mChannelMask); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_CHANNEL_MASK"); /* Channel mode to tell MONO/STEREO/DUAL-MONO/NONE_OF_THESE */ uint32_t ui_channel_mode; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_CHANNEL_MODE, &ui_channel_mode); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_CHANNEL_MODE"); if (ui_channel_mode == 0) ALOGV("Channel Mode: MONO_OR_PS\n"); else if (ui_channel_mode == 1) ALOGV("Channel Mode: STEREO\n"); else if (ui_channel_mode == 2) ALOGV("Channel Mode: DUAL-MONO\n"); else ALOGV("Channel Mode: NONE_OF_THESE or MULTICHANNEL\n"); /* Channel mode to tell SBR PRESENT/NOT_PRESENT */ uint32_t ui_sbr_mode; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE, &ui_sbr_mode); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_SBR_MODE"); if (ui_sbr_mode == 0) ALOGV("SBR Mode: NOT_PRESENT\n"); else if (ui_sbr_mode == 1) ALOGV("SBR Mode: PRESENT\n"); else ALOGV("SBR Mode: ILLEGAL\n"); /* mOutputFrameLength = 1024 * (1 + SBR_MODE) for AAC */ /* For USAC it could be 1024 * 3 , support to query */ /* not yet added in codec */ mOutputFrameLength = 1024 * (1 + ui_sbr_mode); ALOGI("mOutputFrameLength %d ui_sbr_mode %d", mOutputFrameLength, ui_sbr_mode); return IA_NO_ERROR; } IA_ERRORCODE C2SoftXaacDec::setXAACDRCInfo(int32_t drcCut, int32_t drcBoost, int32_t drcRefLevel, int32_t drcHeavyCompression, int32_t drEffectType) { IA_ERRORCODE err_code = IA_NO_ERROR; int32_t ui_drc_enable = 1; err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_ENABLE, &ui_drc_enable); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_ENABLE"); if (drcCut != -1) { err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_CUT, &drcCut); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_CUT"); } if (drcBoost != -1) { err_code = ixheaacd_dec_api( mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_BOOST, &drcBoost); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_BOOST"); } if (drcRefLevel != -1) { err_code = ixheaacd_dec_api( mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LEVEL, &drcRefLevel); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LEVEL"); } if (drcRefLevel != -1) { err_code = ixheaacd_dec_api( mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_DRC_TARGET_LOUDNESS, &drcRefLevel); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_DRC_TARGET_LOUDNESS"); } if (drcHeavyCompression != -1) { err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_HEAVY_COMP, &drcHeavyCompression); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_HEAVY_COMP"); } err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_DRC_EFFECT_TYPE, &drEffectType); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_DRC_EFFECT_TYPE"); int32_t i_effect_type, i_target_loudness, i_loud_norm; /*Set Effect Type*/ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_EFFECT_TYPE, &i_effect_type); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_EFFECT_TYPE"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_DRC_EFFECT_TYPE, &i_effect_type); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_EFFECT_TYPE"); /*Set target loudness */ err_code = ixheaacd_dec_api( mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LOUDNESS, &i_target_loudness); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_TARGET_LOUDNESS"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_DRC_TARGET_LOUDNESS, &i_target_loudness); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_TARGET_LOUDNESS"); /*Set loud_norm_flag*/ err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_LOUD_NORM, &i_loud_norm); RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_PARAM_DRC_LOUD_NORM"); err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM, IA_DRC_DEC_CONFIG_DRC_LOUD_NORM, &i_loud_norm); RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_DRC_LOUD_NORM"); return IA_NO_ERROR; } class C2SoftXaacDecFactory : public C2ComponentFactory { public: C2SoftXaacDecFactory() : mHelper(std::static_pointer_cast( GetCodec2PlatformComponentStore()->getParamReflector())) { } virtual c2_status_t createComponent( c2_node_id_t id, std::shared_ptr* const component, std::function deleter) override { *component = std::shared_ptr( new C2SoftXaacDec(COMPONENT_NAME, id, std::make_shared(mHelper)), deleter); return C2_OK; } virtual c2_status_t createInterface( c2_node_id_t id, std::shared_ptr* const interface, std::function deleter) override { *interface = std::shared_ptr( new SimpleInterface( COMPONENT_NAME, id, std::make_shared(mHelper)), deleter); return C2_OK; } virtual ~C2SoftXaacDecFactory() override = default; private: std::shared_ptr mHelper; }; } // namespace android __attribute__((cfi_canonical_jump_table)) extern "C" ::C2ComponentFactory* CreateCodec2Factory() { ALOGV("in %s", __func__); return new ::android::C2SoftXaacDecFactory(); } __attribute__((cfi_canonical_jump_table)) extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) { ALOGV("in %s", __func__); delete factory; }