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
32 class C2SoftAacEnc::IntfImpl : public C2InterfaceHelper {
33 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)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
getSampleRate() const85 uint32_t getSampleRate() const { return mSampleRate->value; }
getChannelCount() const86 uint32_t getChannelCount() const { return mChannelCount->value; }
getBitrate() const87 uint32_t getBitrate() const { return mBitrate->value; }
88
89 private:
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
99 constexpr char COMPONENT_NAME[] = "c2.android.aac.encoder";
100
C2SoftAacEnc(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)101 C2SoftAacEnc::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
~C2SoftAacEnc()119 C2SoftAacEnc::~C2SoftAacEnc() {
120 onReset();
121 }
122
onInit()123 c2_status_t C2SoftAacEnc::onInit() {
124 status_t err = initEncoder();
125 return err == OK ? C2_OK : C2_CORRUPTED;
126 }
127
initEncoder()128 status_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
onStop()136 c2_status_t C2SoftAacEnc::onStop() {
137 mSentCodecSpecificData = false;
138 mInputSize = 0u;
139 mInputTimeUs = -1ll;
140 mSignalledError = false;
141 return C2_OK;
142 }
143
onReset()144 void C2SoftAacEnc::onReset() {
145 (void)onStop();
146 aacEncClose(&mAACEncoder);
147 }
148
onRelease()149 void C2SoftAacEnc::onRelease() {
150 // no-op
151 }
152
onFlush_sm()153 c2_status_t C2SoftAacEnc::onFlush_sm() {
154 mSentCodecSpecificData = false;
155 mInputSize = 0u;
156 return C2_OK;
157 }
158
getChannelMode(uint32_t nChannels)159 static 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
setAudioParams()190 status_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
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)241 void 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
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)437 c2_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
461 class C2SoftAacEncFactory : public C2ComponentFactory {
462 public:
C2SoftAacEncFactory()463 C2SoftAacEncFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
464 GetCodec2PlatformComponentStore()->getParamReflector())) {
465 }
466
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)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
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)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
491 private:
492 std::shared_ptr<C2ReflectorHelper> mHelper;
493 };
494
495 } // namespace android
496
CreateCodec2Factory()497 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
498 ALOGV("in %s", __func__);
499 return new ::android::C2SoftAacEncFactory();
500 }
501
DestroyCodec2Factory(::C2ComponentFactory * factory)502 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
503 ALOGV("in %s", __func__);
504 delete factory;
505 }
506