• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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