| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 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 |  | 
 | 30 | namespace android { | 
 | 31 |  | 
| Rakesh Kumar | 66d9d06 | 2019-03-12 17:46:17 +0530 | [diff] [blame] | 32 | namespace { | 
 | 33 |  | 
 | 34 | constexpr char COMPONENT_NAME[] = "c2.android.aac.encoder"; | 
 | 35 |  | 
 | 36 | }  // namespace | 
 | 37 |  | 
 | 38 | class C2SoftAacEnc::IntfImpl : public SimpleInterface<void>::BaseParams { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 39 | public: | 
 | 40 |     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper) | 
| Rakesh Kumar | 66d9d06 | 2019-03-12 17:46:17 +0530 | [diff] [blame] | 41 |         : SimpleInterface<void>::BaseParams( | 
 | 42 |                 helper, | 
 | 43 |                 COMPONENT_NAME, | 
 | 44 |                 C2Component::KIND_ENCODER, | 
 | 45 |                 C2Component::DOMAIN_AUDIO, | 
 | 46 |                 MEDIA_MIMETYPE_AUDIO_AAC) { | 
 | 47 |         noPrivateBuffers(); | 
 | 48 |         noInputReferences(); | 
 | 49 |         noOutputReferences(); | 
 | 50 |         noInputLatency(); | 
 | 51 |         noTimeStretch(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 52 |         setDerivedInstance(this); | 
 | 53 |  | 
 | 54 |         addParameter( | 
| Rakesh Kumar | 66d9d06 | 2019-03-12 17:46:17 +0530 | [diff] [blame] | 55 |                 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES) | 
 | 56 |                 .withConstValue(new C2ComponentAttributesSetting( | 
 | 57 |                     C2Component::ATTRIB_IS_TEMPORAL)) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 58 |                 .build()); | 
 | 59 |  | 
 | 60 |         addParameter( | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 61 |                 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 62 |                 .withDefault(new C2StreamSampleRateInfo::input(0u, 44100)) | 
 | 63 |                 .withFields({C2F(mSampleRate, value).oneOf({ | 
 | 64 |                     8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 | 
 | 65 |                 })}) | 
 | 66 |                 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps)) | 
 | 67 |                 .build()); | 
 | 68 |  | 
 | 69 |         addParameter( | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 70 |                 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 71 |                 .withDefault(new C2StreamChannelCountInfo::input(0u, 1)) | 
 | 72 |                 .withFields({C2F(mChannelCount, value).inRange(1, 6)}) | 
 | 73 |                 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps) | 
 | 74 |                 .build()); | 
 | 75 |  | 
 | 76 |         addParameter( | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 77 |                 DefineParam(mBitrate, C2_PARAMKEY_BITRATE) | 
 | 78 |                 .withDefault(new C2StreamBitrateInfo::output(0u, 64000)) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 79 |                 .withFields({C2F(mBitrate, value).inRange(8000, 960000)}) | 
 | 80 |                 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps) | 
 | 81 |                 .build()); | 
 | 82 |  | 
 | 83 |         addParameter( | 
 | 84 |                 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE) | 
 | 85 |                 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 8192)) | 
 | 86 |                 .calculatedAs(MaxBufSizeCalculator, mChannelCount) | 
 | 87 |                 .build()); | 
 | 88 |  | 
 | 89 |         addParameter( | 
 | 90 |                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) | 
 | 91 |                 .withDefault(new C2StreamProfileLevelInfo::output(0u, | 
 | 92 |                         C2Config::PROFILE_AAC_LC, C2Config::LEVEL_UNUSED)) | 
 | 93 |                 .withFields({ | 
 | 94 |                     C2F(mProfileLevel, profile).oneOf({ | 
 | 95 |                             C2Config::PROFILE_AAC_LC, | 
 | 96 |                             C2Config::PROFILE_AAC_HE, | 
 | 97 |                             C2Config::PROFILE_AAC_HE_PS, | 
 | 98 |                             C2Config::PROFILE_AAC_LD, | 
 | 99 |                             C2Config::PROFILE_AAC_ELD}), | 
 | 100 |                     C2F(mProfileLevel, level).oneOf({ | 
 | 101 |                             C2Config::LEVEL_UNUSED | 
 | 102 |                     }) | 
 | 103 |                 }) | 
 | 104 |                 .withSetter(ProfileLevelSetter) | 
 | 105 |                 .build()); | 
 | 106 |     } | 
 | 107 |  | 
 | 108 |     uint32_t getSampleRate() const { return mSampleRate->value; } | 
 | 109 |     uint32_t getChannelCount() const { return mChannelCount->value; } | 
 | 110 |     uint32_t getBitrate() const { return mBitrate->value; } | 
 | 111 |     static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::output> &me) { | 
 | 112 |         (void)mayBlock; | 
 | 113 |         (void)me;  // TODO: validate | 
 | 114 |         return C2R::Ok(); | 
 | 115 |     } | 
 | 116 |  | 
 | 117 |     static C2R MaxBufSizeCalculator( | 
 | 118 |             bool mayBlock, | 
 | 119 |             C2P<C2StreamMaxBufferSizeInfo::input> &me, | 
 | 120 |             const C2P<C2StreamChannelCountInfo::input> &channelCount) { | 
 | 121 |         (void)mayBlock; | 
 | 122 |         me.set().value = 1024 * sizeof(short) * channelCount.v.value; | 
 | 123 |         return C2R::Ok(); | 
 | 124 |     } | 
 | 125 |  | 
 | 126 | private: | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 127 |     std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate; | 
 | 128 |     std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount; | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 129 |     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 130 |     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize; | 
 | 131 |     std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel; | 
 | 132 | }; | 
 | 133 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 134 | C2SoftAacEnc::C2SoftAacEnc( | 
 | 135 |         const char *name, | 
 | 136 |         c2_node_id_t id, | 
 | 137 |         const std::shared_ptr<IntfImpl> &intfImpl) | 
 | 138 |     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)), | 
 | 139 |       mIntf(intfImpl), | 
 | 140 |       mAACEncoder(nullptr), | 
 | 141 |       mSBRMode(-1), | 
 | 142 |       mSBRRatio(0), | 
 | 143 |       mAACProfile(AOT_AAC_LC), | 
 | 144 |       mNumBytesPerInputFrame(0u), | 
 | 145 |       mOutBufferSize(0u), | 
 | 146 |       mSentCodecSpecificData(false), | 
| Wonsik Kim | 353e167 | 2019-01-07 16:31:29 -0800 | [diff] [blame] | 147 |       mInputTimeSet(false), | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 148 |       mInputSize(0), | 
| Wonsik Kim | 8ead39d | 2019-04-01 13:56:12 -0700 | [diff] [blame] | 149 |       mInputTimeUs(0), | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 150 |       mSignalledError(false), | 
 | 151 |       mOutIndex(0u) { | 
 | 152 | } | 
 | 153 |  | 
 | 154 | C2SoftAacEnc::~C2SoftAacEnc() { | 
 | 155 |     onReset(); | 
 | 156 | } | 
 | 157 |  | 
 | 158 | c2_status_t C2SoftAacEnc::onInit() { | 
 | 159 |     status_t err = initEncoder(); | 
 | 160 |     return err == OK ? C2_OK : C2_CORRUPTED; | 
 | 161 | } | 
 | 162 |  | 
 | 163 | status_t C2SoftAacEnc::initEncoder() { | 
 | 164 |     if (AACENC_OK != aacEncOpen(&mAACEncoder, 0, 0)) { | 
 | 165 |         ALOGE("Failed to init AAC encoder"); | 
 | 166 |         return UNKNOWN_ERROR; | 
 | 167 |     } | 
 | 168 |     return setAudioParams(); | 
 | 169 | } | 
 | 170 |  | 
 | 171 | c2_status_t C2SoftAacEnc::onStop() { | 
 | 172 |     mSentCodecSpecificData = false; | 
| Wonsik Kim | 353e167 | 2019-01-07 16:31:29 -0800 | [diff] [blame] | 173 |     mInputTimeSet = false; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 174 |     mInputSize = 0u; | 
| Wonsik Kim | 8ead39d | 2019-04-01 13:56:12 -0700 | [diff] [blame] | 175 |     mInputTimeUs = 0; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 176 |     mSignalledError = false; | 
 | 177 |     return C2_OK; | 
 | 178 | } | 
 | 179 |  | 
 | 180 | void C2SoftAacEnc::onReset() { | 
 | 181 |     (void)onStop(); | 
 | 182 |     aacEncClose(&mAACEncoder); | 
 | 183 | } | 
 | 184 |  | 
 | 185 | void C2SoftAacEnc::onRelease() { | 
 | 186 |     // no-op | 
 | 187 | } | 
 | 188 |  | 
 | 189 | c2_status_t C2SoftAacEnc::onFlush_sm() { | 
 | 190 |     mSentCodecSpecificData = false; | 
| Wonsik Kim | 353e167 | 2019-01-07 16:31:29 -0800 | [diff] [blame] | 191 |     mInputTimeSet = false; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 192 |     mInputSize = 0u; | 
| Wonsik Kim | 8ead39d | 2019-04-01 13:56:12 -0700 | [diff] [blame] | 193 |     mInputTimeUs = 0; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 194 |     return C2_OK; | 
 | 195 | } | 
 | 196 |  | 
 | 197 | static CHANNEL_MODE getChannelMode(uint32_t nChannels) { | 
 | 198 |     CHANNEL_MODE chMode = MODE_INVALID; | 
 | 199 |     switch (nChannels) { | 
 | 200 |         case 1: chMode = MODE_1; break; | 
 | 201 |         case 2: chMode = MODE_2; break; | 
 | 202 |         case 3: chMode = MODE_1_2; break; | 
 | 203 |         case 4: chMode = MODE_1_2_1; break; | 
 | 204 |         case 5: chMode = MODE_1_2_2; break; | 
 | 205 |         case 6: chMode = MODE_1_2_2_1; break; | 
 | 206 |         default: chMode = MODE_INVALID; | 
 | 207 |     } | 
 | 208 |     return chMode; | 
 | 209 | } | 
 | 210 |  | 
 | 211 | //static AUDIO_OBJECT_TYPE getAOTFromProfile(OMX_U32 profile) { | 
 | 212 | //    if (profile == OMX_AUDIO_AACObjectLC) { | 
 | 213 | //        return AOT_AAC_LC; | 
 | 214 | //    } else if (profile == OMX_AUDIO_AACObjectHE) { | 
 | 215 | //        return AOT_SBR; | 
 | 216 | //    } else if (profile == OMX_AUDIO_AACObjectHE_PS) { | 
 | 217 | //        return AOT_PS; | 
 | 218 | //    } else if (profile == OMX_AUDIO_AACObjectLD) { | 
 | 219 | //        return AOT_ER_AAC_LD; | 
 | 220 | //    } else if (profile == OMX_AUDIO_AACObjectELD) { | 
 | 221 | //        return AOT_ER_AAC_ELD; | 
 | 222 | //    } else { | 
 | 223 | //        ALOGW("Unsupported AAC profile - defaulting to AAC-LC"); | 
 | 224 | //        return AOT_AAC_LC; | 
 | 225 | //    } | 
 | 226 | //} | 
 | 227 |  | 
 | 228 | status_t C2SoftAacEnc::setAudioParams() { | 
 | 229 |     // We call this whenever sample rate, number of channels, bitrate or SBR mode change | 
 | 230 |     // in reponse to setParameter calls. | 
 | 231 |  | 
 | 232 |     ALOGV("setAudioParams: %u Hz, %u channels, %u bps, %i sbr mode, %i sbr ratio", | 
 | 233 |          mIntf->getSampleRate(), mIntf->getChannelCount(), mIntf->getBitrate(), mSBRMode, mSBRRatio); | 
 | 234 |  | 
 | 235 |     if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT, mAACProfile)) { | 
 | 236 |         ALOGE("Failed to set AAC encoder parameters"); | 
 | 237 |         return UNKNOWN_ERROR; | 
 | 238 |     } | 
 | 239 |  | 
 | 240 |     if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SAMPLERATE, mIntf->getSampleRate())) { | 
 | 241 |         ALOGE("Failed to set AAC encoder parameters"); | 
 | 242 |         return UNKNOWN_ERROR; | 
 | 243 |     } | 
 | 244 |     if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_BITRATE, mIntf->getBitrate())) { | 
 | 245 |         ALOGE("Failed to set AAC encoder parameters"); | 
 | 246 |         return UNKNOWN_ERROR; | 
 | 247 |     } | 
 | 248 |     if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_CHANNELMODE, | 
 | 249 |             getChannelMode(mIntf->getChannelCount()))) { | 
 | 250 |         ALOGE("Failed to set AAC encoder parameters"); | 
 | 251 |         return UNKNOWN_ERROR; | 
 | 252 |     } | 
 | 253 |     if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_TRANSMUX, TT_MP4_RAW)) { | 
 | 254 |         ALOGE("Failed to set AAC encoder parameters"); | 
 | 255 |         return UNKNOWN_ERROR; | 
 | 256 |     } | 
 | 257 |  | 
 | 258 |     if (mSBRMode != -1 && mAACProfile == AOT_ER_AAC_ELD) { | 
 | 259 |         if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_MODE, mSBRMode)) { | 
 | 260 |             ALOGE("Failed to set AAC encoder parameters"); | 
 | 261 |             return UNKNOWN_ERROR; | 
 | 262 |         } | 
 | 263 |     } | 
 | 264 |  | 
 | 265 |     /* SBR ratio parameter configurations: | 
 | 266 |        0: Default configuration wherein SBR ratio is configured depending on audio object type by | 
 | 267 |           the FDK. | 
 | 268 |        1: Downsampled SBR (default for ELD) | 
 | 269 |        2: Dualrate SBR (default for HE-AAC) | 
 | 270 |      */ | 
 | 271 |     if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_RATIO, mSBRRatio)) { | 
 | 272 |         ALOGE("Failed to set AAC encoder parameters"); | 
 | 273 |         return UNKNOWN_ERROR; | 
 | 274 |     } | 
 | 275 |  | 
 | 276 |     return OK; | 
 | 277 | } | 
 | 278 |  | 
 | 279 | void C2SoftAacEnc::process( | 
 | 280 |         const std::unique_ptr<C2Work> &work, | 
 | 281 |         const std::shared_ptr<C2BlockPool> &pool) { | 
 | 282 |     // Initialize output work | 
 | 283 |     work->result = C2_OK; | 
 | 284 |     work->workletsProcessed = 1u; | 
 | 285 |     work->worklets.front()->output.flags = work->input.flags; | 
 | 286 |  | 
 | 287 |     if (mSignalledError) { | 
 | 288 |         return; | 
 | 289 |     } | 
 | 290 |     bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0; | 
 | 291 |  | 
 | 292 |     uint32_t sampleRate = mIntf->getSampleRate(); | 
 | 293 |     uint32_t channelCount = mIntf->getChannelCount(); | 
 | 294 |  | 
 | 295 |     if (!mSentCodecSpecificData) { | 
 | 296 |         // The very first thing we want to output is the codec specific | 
 | 297 |         // data. | 
 | 298 |  | 
 | 299 |         if (AACENC_OK != aacEncEncode(mAACEncoder, nullptr, nullptr, nullptr, nullptr)) { | 
 | 300 |             ALOGE("Unable to initialize encoder for profile / sample-rate / bit-rate / channels"); | 
 | 301 |             mSignalledError = true; | 
 | 302 |             work->result = C2_CORRUPTED; | 
 | 303 |             return; | 
 | 304 |         } | 
 | 305 |  | 
 | 306 |         uint32_t bitrate = mIntf->getBitrate(); | 
 | 307 |         uint32_t actualBitRate = aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE); | 
 | 308 |         if (bitrate != actualBitRate) { | 
 | 309 |             ALOGW("Requested bitrate %u unsupported, using %u", bitrate, actualBitRate); | 
 | 310 |         } | 
 | 311 |  | 
 | 312 |         AACENC_InfoStruct encInfo; | 
 | 313 |         if (AACENC_OK != aacEncInfo(mAACEncoder, &encInfo)) { | 
 | 314 |             ALOGE("Failed to get AAC encoder info"); | 
 | 315 |             mSignalledError = true; | 
 | 316 |             work->result = C2_CORRUPTED; | 
 | 317 |             return; | 
 | 318 |         } | 
 | 319 |  | 
| Lajos Molnar | 3bb81cd | 2019-02-20 15:10:30 -0800 | [diff] [blame] | 320 |         std::unique_ptr<C2StreamInitDataInfo::output> csd = | 
 | 321 |             C2StreamInitDataInfo::output::AllocUnique(encInfo.confSize, 0u); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 322 |         if (!csd) { | 
 | 323 |             ALOGE("CSD allocation failed"); | 
 | 324 |             mSignalledError = true; | 
 | 325 |             work->result = C2_NO_MEMORY; | 
 | 326 |             return; | 
 | 327 |         } | 
 | 328 |         memcpy(csd->m.value, encInfo.confBuf, encInfo.confSize); | 
 | 329 |         ALOGV("put csd"); | 
 | 330 | #if defined(LOG_NDEBUG) && !LOG_NDEBUG | 
 | 331 |         hexdump(csd->m.value, csd->flexCount()); | 
 | 332 | #endif | 
 | 333 |         work->worklets.front()->output.configUpdate.push_back(std::move(csd)); | 
 | 334 |  | 
 | 335 |         mOutBufferSize = encInfo.maxOutBufBytes; | 
 | 336 |         mNumBytesPerInputFrame = encInfo.frameLength * channelCount * sizeof(int16_t); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 337 |  | 
 | 338 |         mSentCodecSpecificData = true; | 
 | 339 |     } | 
 | 340 |  | 
 | 341 |     uint8_t temp[1]; | 
 | 342 |     C2ReadView view = mDummyReadView; | 
 | 343 |     const uint8_t *data = temp; | 
 | 344 |     size_t capacity = 0u; | 
 | 345 |     if (!work->input.buffers.empty()) { | 
 | 346 |         view = work->input.buffers[0]->data().linearBlocks().front().map().get(); | 
 | 347 |         data = view.data(); | 
 | 348 |         capacity = view.capacity(); | 
 | 349 |     } | 
| Wonsik Kim | 353e167 | 2019-01-07 16:31:29 -0800 | [diff] [blame] | 350 |     if (!mInputTimeSet && capacity > 0) { | 
 | 351 |         mInputTimeUs = work->input.ordinal.timestamp; | 
 | 352 |         mInputTimeSet = true; | 
 | 353 |     } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 354 |  | 
 | 355 |     size_t numFrames = (capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0)) | 
 | 356 |             / mNumBytesPerInputFrame; | 
 | 357 |     ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu mNumBytesPerInputFrame = %u", | 
 | 358 |           capacity, mInputSize, numFrames, mNumBytesPerInputFrame); | 
 | 359 |  | 
 | 360 |     std::shared_ptr<C2LinearBlock> block; | 
 | 361 |     std::shared_ptr<C2Buffer> buffer; | 
 | 362 |     std::unique_ptr<C2WriteView> wView; | 
 | 363 |     uint8_t *outPtr = temp; | 
 | 364 |     size_t outAvailable = 0u; | 
 | 365 |     uint64_t inputIndex = work->input.ordinal.frameIndex.peeku(); | 
 | 366 |  | 
 | 367 |     AACENC_InArgs inargs; | 
 | 368 |     AACENC_OutArgs outargs; | 
 | 369 |     memset(&inargs, 0, sizeof(inargs)); | 
 | 370 |     memset(&outargs, 0, sizeof(outargs)); | 
 | 371 |     inargs.numInSamples = capacity / sizeof(int16_t); | 
 | 372 |  | 
 | 373 |     void* inBuffer[]        = { (unsigned char *)data }; | 
 | 374 |     INT   inBufferIds[]     = { IN_AUDIO_DATA }; | 
 | 375 |     INT   inBufferSize[]    = { (INT)capacity }; | 
 | 376 |     INT   inBufferElSize[]  = { sizeof(int16_t) }; | 
 | 377 |  | 
 | 378 |     AACENC_BufDesc inBufDesc; | 
 | 379 |     inBufDesc.numBufs           = sizeof(inBuffer) / sizeof(void*); | 
 | 380 |     inBufDesc.bufs              = (void**)&inBuffer; | 
 | 381 |     inBufDesc.bufferIdentifiers = inBufferIds; | 
 | 382 |     inBufDesc.bufSizes          = inBufferSize; | 
 | 383 |     inBufDesc.bufElSizes        = inBufferElSize; | 
 | 384 |  | 
 | 385 |     void* outBuffer[]       = { outPtr }; | 
 | 386 |     INT   outBufferIds[]    = { OUT_BITSTREAM_DATA }; | 
 | 387 |     INT   outBufferSize[]   = { 0 }; | 
 | 388 |     INT   outBufferElSize[] = { sizeof(UCHAR) }; | 
 | 389 |  | 
 | 390 |     AACENC_BufDesc outBufDesc; | 
 | 391 |     outBufDesc.numBufs           = sizeof(outBuffer) / sizeof(void*); | 
 | 392 |     outBufDesc.bufs              = (void**)&outBuffer; | 
 | 393 |     outBufDesc.bufferIdentifiers = outBufferIds; | 
 | 394 |     outBufDesc.bufSizes          = outBufferSize; | 
 | 395 |     outBufDesc.bufElSizes        = outBufferElSize; | 
 | 396 |  | 
 | 397 |     AACENC_ERROR encoderErr = AACENC_OK; | 
 | 398 |  | 
 | 399 |     class FillWork { | 
 | 400 |     public: | 
 | 401 |         FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal, | 
 | 402 |                  const std::shared_ptr<C2Buffer> &buffer) | 
 | 403 |             : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) { | 
 | 404 |         } | 
 | 405 |         ~FillWork() = default; | 
 | 406 |  | 
 | 407 |         void operator()(const std::unique_ptr<C2Work> &work) { | 
 | 408 |             work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags; | 
 | 409 |             work->worklets.front()->output.buffers.clear(); | 
 | 410 |             work->worklets.front()->output.ordinal = mOrdinal; | 
 | 411 |             work->workletsProcessed = 1u; | 
 | 412 |             work->result = C2_OK; | 
 | 413 |             if (mBuffer) { | 
 | 414 |                 work->worklets.front()->output.buffers.push_back(mBuffer); | 
 | 415 |             } | 
 | 416 |             ALOGV("timestamp = %lld, index = %lld, w/%s buffer", | 
 | 417 |                   mOrdinal.timestamp.peekll(), | 
 | 418 |                   mOrdinal.frameIndex.peekll(), | 
 | 419 |                   mBuffer ? "" : "o"); | 
 | 420 |         } | 
 | 421 |  | 
 | 422 |     private: | 
 | 423 |         const uint32_t mFlags; | 
 | 424 |         const C2WorkOrdinalStruct mOrdinal; | 
 | 425 |         const std::shared_ptr<C2Buffer> mBuffer; | 
 | 426 |     }; | 
 | 427 |  | 
 | 428 |     C2WorkOrdinalStruct outOrdinal = work->input.ordinal; | 
 | 429 |  | 
 | 430 |     while (encoderErr == AACENC_OK && inargs.numInSamples > 0) { | 
 | 431 |         if (numFrames && !block) { | 
 | 432 |             C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; | 
 | 433 |             // TODO: error handling, proper usage, etc. | 
 | 434 |             c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block); | 
 | 435 |             if (err != C2_OK) { | 
 | 436 |                 ALOGE("fetchLinearBlock failed : err = %d", err); | 
 | 437 |                 work->result = C2_NO_MEMORY; | 
 | 438 |                 return; | 
 | 439 |             } | 
 | 440 |  | 
 | 441 |             wView.reset(new C2WriteView(block->map().get())); | 
 | 442 |             outPtr = wView->data(); | 
 | 443 |             outAvailable = wView->size(); | 
 | 444 |             --numFrames; | 
 | 445 |         } | 
 | 446 |  | 
 | 447 |         memset(&outargs, 0, sizeof(outargs)); | 
 | 448 |  | 
 | 449 |         outBuffer[0] = outPtr; | 
 | 450 |         outBufferSize[0] = outAvailable; | 
 | 451 |  | 
 | 452 |         encoderErr = aacEncEncode(mAACEncoder, | 
 | 453 |                                   &inBufDesc, | 
 | 454 |                                   &outBufDesc, | 
 | 455 |                                   &inargs, | 
 | 456 |                                   &outargs); | 
 | 457 |  | 
 | 458 |         if (encoderErr == AACENC_OK) { | 
 | 459 |             if (buffer) { | 
 | 460 |                 outOrdinal.frameIndex = mOutIndex++; | 
 | 461 |                 outOrdinal.timestamp = mInputTimeUs; | 
 | 462 |                 cloneAndSend( | 
 | 463 |                         inputIndex, | 
 | 464 |                         work, | 
 | 465 |                         FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer)); | 
 | 466 |                 buffer.reset(); | 
 | 467 |             } | 
 | 468 |  | 
 | 469 |             if (outargs.numOutBytes > 0) { | 
 | 470 |                 mInputSize = 0; | 
| Wonsik Kim | 84889cb | 2019-01-03 17:07:54 -0800 | [diff] [blame] | 471 |                 int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples | 
 | 472 |                         + outargs.numInSamples; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 473 |                 mInputTimeUs = work->input.ordinal.timestamp | 
 | 474 |                         + (consumed * 1000000ll / channelCount / sampleRate); | 
 | 475 |                 buffer = createLinearBuffer(block, 0, outargs.numOutBytes); | 
 | 476 | #if defined(LOG_NDEBUG) && !LOG_NDEBUG | 
 | 477 |                 hexdump(outPtr, std::min(outargs.numOutBytes, 256)); | 
 | 478 | #endif | 
 | 479 |                 outPtr = temp; | 
 | 480 |                 outAvailable = 0; | 
 | 481 |                 block.reset(); | 
 | 482 |             } else { | 
 | 483 |                 mInputSize += outargs.numInSamples * sizeof(int16_t); | 
 | 484 |             } | 
 | 485 |  | 
 | 486 |             if (outargs.numInSamples > 0) { | 
 | 487 |                 inBuffer[0] = (int16_t *)inBuffer[0] + outargs.numInSamples; | 
 | 488 |                 inBufferSize[0] -= outargs.numInSamples * sizeof(int16_t); | 
 | 489 |                 inargs.numInSamples -= outargs.numInSamples; | 
 | 490 |             } | 
 | 491 |         } | 
 | 492 |         ALOGV("encoderErr = %d mInputSize = %zu inargs.numInSamples = %d, mInputTimeUs = %lld", | 
 | 493 |               encoderErr, mInputSize, inargs.numInSamples, mInputTimeUs.peekll()); | 
 | 494 |     } | 
 | 495 |  | 
 | 496 |     if (eos && inBufferSize[0] > 0) { | 
 | 497 |         if (numFrames && !block) { | 
 | 498 |             C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }; | 
 | 499 |             // TODO: error handling, proper usage, etc. | 
 | 500 |             c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block); | 
 | 501 |             if (err != C2_OK) { | 
 | 502 |                 ALOGE("fetchLinearBlock failed : err = %d", err); | 
 | 503 |                 work->result = C2_NO_MEMORY; | 
 | 504 |                 return; | 
 | 505 |             } | 
 | 506 |  | 
 | 507 |             wView.reset(new C2WriteView(block->map().get())); | 
 | 508 |             outPtr = wView->data(); | 
 | 509 |             outAvailable = wView->size(); | 
 | 510 |             --numFrames; | 
 | 511 |         } | 
 | 512 |  | 
 | 513 |         memset(&outargs, 0, sizeof(outargs)); | 
 | 514 |  | 
 | 515 |         outBuffer[0] = outPtr; | 
 | 516 |         outBufferSize[0] = outAvailable; | 
 | 517 |  | 
 | 518 |         // Flush | 
 | 519 |         inargs.numInSamples = -1; | 
 | 520 |  | 
 | 521 |         (void)aacEncEncode(mAACEncoder, | 
 | 522 |                            &inBufDesc, | 
 | 523 |                            &outBufDesc, | 
 | 524 |                            &inargs, | 
 | 525 |                            &outargs); | 
 | 526 |     } | 
 | 527 |  | 
 | 528 |     outOrdinal.frameIndex = mOutIndex++; | 
 | 529 |     outOrdinal.timestamp = mInputTimeUs; | 
 | 530 |     FillWork((C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0), | 
 | 531 |              outOrdinal, buffer)(work); | 
 | 532 | } | 
 | 533 |  | 
 | 534 | c2_status_t C2SoftAacEnc::drain( | 
 | 535 |         uint32_t drainMode, | 
 | 536 |         const std::shared_ptr<C2BlockPool> &pool) { | 
 | 537 |     switch (drainMode) { | 
 | 538 |         case DRAIN_COMPONENT_NO_EOS: | 
 | 539 |             [[fallthrough]]; | 
 | 540 |         case NO_DRAIN: | 
 | 541 |             // no-op | 
 | 542 |             return C2_OK; | 
 | 543 |         case DRAIN_CHAIN: | 
 | 544 |             return C2_OMITTED; | 
 | 545 |         case DRAIN_COMPONENT_WITH_EOS: | 
 | 546 |             break; | 
 | 547 |         default: | 
 | 548 |             return C2_BAD_VALUE; | 
 | 549 |     } | 
 | 550 |  | 
 | 551 |     (void)pool; | 
 | 552 |     mSentCodecSpecificData = false; | 
| Wonsik Kim | 353e167 | 2019-01-07 16:31:29 -0800 | [diff] [blame] | 553 |     mInputTimeSet = false; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 554 |     mInputSize = 0u; | 
| Wonsik Kim | 8ead39d | 2019-04-01 13:56:12 -0700 | [diff] [blame] | 555 |     mInputTimeUs = 0; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 556 |  | 
 | 557 |     // TODO: we don't have any pending work at this time to drain. | 
 | 558 |     return C2_OK; | 
 | 559 | } | 
 | 560 |  | 
 | 561 | class C2SoftAacEncFactory : public C2ComponentFactory { | 
 | 562 | public: | 
 | 563 |     C2SoftAacEncFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>( | 
 | 564 |             GetCodec2PlatformComponentStore()->getParamReflector())) { | 
 | 565 |     } | 
 | 566 |  | 
 | 567 |     virtual c2_status_t createComponent( | 
 | 568 |             c2_node_id_t id, | 
 | 569 |             std::shared_ptr<C2Component>* const component, | 
 | 570 |             std::function<void(C2Component*)> deleter) override { | 
 | 571 |         *component = std::shared_ptr<C2Component>( | 
 | 572 |                 new C2SoftAacEnc(COMPONENT_NAME, | 
 | 573 |                                  id, | 
 | 574 |                                  std::make_shared<C2SoftAacEnc::IntfImpl>(mHelper)), | 
 | 575 |                 deleter); | 
 | 576 |         return C2_OK; | 
 | 577 |     } | 
 | 578 |  | 
 | 579 |     virtual c2_status_t createInterface( | 
 | 580 |             c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface, | 
 | 581 |             std::function<void(C2ComponentInterface*)> deleter) override { | 
 | 582 |         *interface = std::shared_ptr<C2ComponentInterface>( | 
 | 583 |                 new SimpleInterface<C2SoftAacEnc::IntfImpl>( | 
 | 584 |                         COMPONENT_NAME, id, std::make_shared<C2SoftAacEnc::IntfImpl>(mHelper)), | 
 | 585 |                 deleter); | 
 | 586 |         return C2_OK; | 
 | 587 |     } | 
 | 588 |  | 
 | 589 |     virtual ~C2SoftAacEncFactory() override = default; | 
 | 590 |  | 
 | 591 | private: | 
 | 592 |     std::shared_ptr<C2ReflectorHelper> mHelper; | 
 | 593 | }; | 
 | 594 |  | 
 | 595 | }  // namespace android | 
 | 596 |  | 
 | 597 | extern "C" ::C2ComponentFactory* CreateCodec2Factory() { | 
 | 598 |     ALOGV("in %s", __func__); | 
 | 599 |     return new ::android::C2SoftAacEncFactory(); | 
 | 600 | } | 
 | 601 |  | 
 | 602 | extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) { | 
 | 603 |     ALOGV("in %s", __func__); | 
 | 604 |     delete factory; | 
 | 605 | } |