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