Home | History | Annotate | Download | only in amr_nb_wb
      1 /*
      2  * Copyright (C) 2018 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 "C2SoftAmrWbEnc"
     19 #include <log/log.h>
     20 
     21 #include <media/stagefright/foundation/MediaDefs.h>
     22 
     23 #include <C2Debug.h>
     24 #include <C2PlatformSupport.h>
     25 #include <SimpleC2Interface.h>
     26 
     27 #include "C2SoftAmrWbEnc.h"
     28 #include "cmnMemory.h"
     29 
     30 namespace android {
     31 
     32 constexpr char COMPONENT_NAME[] = "c2.android.amrwb.encoder";
     33 
     34 class C2SoftAmrWbEnc::IntfImpl : public C2InterfaceHelper {
     35    public:
     36     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
     37         : C2InterfaceHelper(helper) {
     38         setDerivedInstance(this);
     39 
     40         addParameter(
     41             DefineParam(mInputFormat, C2_NAME_INPUT_STREAM_FORMAT_SETTING)
     42                 .withConstValue(
     43                     new C2StreamFormatConfig::input(0u, C2FormatAudio))
     44                 .build());
     45 
     46         addParameter(
     47             DefineParam(mOutputFormat, C2_NAME_OUTPUT_STREAM_FORMAT_SETTING)
     48                 .withConstValue(
     49                     new C2StreamFormatConfig::output(0u, C2FormatCompressed))
     50                 .build());
     51 
     52         addParameter(
     53             DefineParam(mInputMediaType, C2_NAME_INPUT_PORT_MIME_SETTING)
     54                 .withConstValue(AllocSharedString<C2PortMimeConfig::input>(
     55                     MEDIA_MIMETYPE_AUDIO_RAW))
     56                 .build());
     57 
     58         addParameter(
     59             DefineParam(mOutputMediaType, C2_NAME_OUTPUT_PORT_MIME_SETTING)
     60                 .withConstValue(AllocSharedString<C2PortMimeConfig::output>(
     61                     MEDIA_MIMETYPE_AUDIO_AMR_WB))
     62                 .build());
     63 
     64         addParameter(
     65                 DefineParam(mChannelCount, C2_NAME_STREAM_CHANNEL_COUNT_SETTING)
     66                 .withDefault(new C2StreamChannelCountInfo::input(0u, 1))
     67                 .withFields({C2F(mChannelCount, value).equalTo(1)})
     68                 .withSetter((Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps))
     69                 .build());
     70 
     71         addParameter(
     72             DefineParam(mSampleRate, C2_NAME_STREAM_SAMPLE_RATE_SETTING)
     73                 .withDefault(new C2StreamSampleRateInfo::input(0u, 16000))
     74                 .withFields({C2F(mSampleRate, value).equalTo(16000)})
     75                 .withSetter(
     76                     (Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
     77                 .build());
     78 
     79         addParameter(
     80                 DefineParam(mBitrate, C2_NAME_STREAM_BITRATE_SETTING)
     81                 .withDefault(new C2BitrateTuning::output(0u, 6600))
     82                 .withFields({C2F(mBitrate, value).inRange(6600, 23850)})
     83                 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
     84                 .build());
     85 
     86         addParameter(
     87                 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
     88                 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 8192))
     89                 .build());
     90     }
     91 
     92     uint32_t getSampleRate() const { return mSampleRate->value; }
     93     uint32_t getChannelCount() const { return mChannelCount->value; }
     94     uint32_t getBitrate() const { return mBitrate->value; }
     95 
     96    private:
     97     std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
     98     std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
     99     std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
    100     std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
    101     std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate;
    102     std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
    103     std::shared_ptr<C2BitrateTuning::output> mBitrate;
    104     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
    105 };
    106 
    107 C2SoftAmrWbEnc::C2SoftAmrWbEnc(const char* name, c2_node_id_t id,
    108                                const std::shared_ptr<IntfImpl>& intfImpl)
    109     : SimpleC2Component(
    110           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
    111       mIntf(intfImpl),
    112       mEncoderHandle(nullptr),
    113       mApiHandle(nullptr),
    114       mMemOperator(nullptr) {
    115 }
    116 
    117 C2SoftAmrWbEnc::~C2SoftAmrWbEnc() {
    118     onRelease();
    119 }
    120 
    121 c2_status_t C2SoftAmrWbEnc::onInit() {
    122     // TODO: get mode directly from config
    123     switch(mIntf->getBitrate()) {
    124         case 6600: mMode = VOAMRWB_MD66;
    125             break;
    126         case 8850: mMode = VOAMRWB_MD885;
    127             break;
    128         case 12650: mMode = VOAMRWB_MD1265;
    129             break;
    130         case 14250: mMode = VOAMRWB_MD1425;
    131             break;
    132         case 15850: mMode = VOAMRWB_MD1585;
    133             break;
    134         case 18250: mMode = VOAMRWB_MD1825;
    135             break;
    136         case 19850: mMode = VOAMRWB_MD1985;
    137             break;
    138         case 23050: mMode = VOAMRWB_MD2305;
    139             break;
    140         case 23850: mMode = VOAMRWB_MD2385;
    141             break;
    142         default: mMode = VOAMRWB_MD2305;
    143     }
    144     status_t err = initEncoder();
    145     mIsFirst = true;
    146     mSignalledError = false;
    147     mSignalledOutputEos = false;
    148     mAnchorTimeStamp = 0;
    149     mProcessedSamples = 0;
    150     mFilledLen = 0;
    151 
    152     return err == OK ? C2_OK : C2_NO_MEMORY;
    153 }
    154 
    155 void C2SoftAmrWbEnc::onRelease() {
    156     if (mEncoderHandle) {
    157         CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
    158         mEncoderHandle = nullptr;
    159     }
    160     if (mApiHandle) {
    161         delete mApiHandle;
    162         mApiHandle = nullptr;
    163     }
    164     if (mMemOperator) {
    165         delete mMemOperator;
    166         mMemOperator = nullptr;
    167     }
    168 }
    169 
    170 c2_status_t C2SoftAmrWbEnc::onStop() {
    171     for (int i = 0; i < kNumSamplesPerFrame; i++) {
    172         mInputFrame[i] = 0x0008; /* EHF_MASK */
    173     }
    174     uint8_t outBuffer[kNumBytesPerInputFrame];
    175     (void) encodeInput(outBuffer, kNumBytesPerInputFrame);
    176     mIsFirst = true;
    177     mSignalledError = false;
    178     mSignalledOutputEos = false;
    179     mAnchorTimeStamp = 0;
    180     mProcessedSamples = 0;
    181     mFilledLen = 0;
    182 
    183     return C2_OK;
    184 }
    185 
    186 void C2SoftAmrWbEnc::onReset() {
    187     (void) onStop();
    188 }
    189 
    190 c2_status_t C2SoftAmrWbEnc::onFlush_sm() {
    191     return onStop();
    192 }
    193 
    194 status_t C2SoftAmrWbEnc::initEncoder() {
    195     mApiHandle = new VO_AUDIO_CODECAPI;
    196     if (!mApiHandle) return NO_MEMORY;
    197 
    198     if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) {
    199         ALOGE("Failed to get api handle");
    200         return UNKNOWN_ERROR;
    201     }
    202 
    203     mMemOperator = new VO_MEM_OPERATOR;
    204     if (!mMemOperator) return NO_MEMORY;
    205 
    206     mMemOperator->Alloc = cmnMemAlloc;
    207     mMemOperator->Copy = cmnMemCopy;
    208     mMemOperator->Free = cmnMemFree;
    209     mMemOperator->Set = cmnMemSet;
    210     mMemOperator->Check = cmnMemCheck;
    211 
    212     VO_CODEC_INIT_USERDATA userData;
    213     memset(&userData, 0, sizeof(userData));
    214     userData.memflag = VO_IMF_USERMEMOPERATOR;
    215     userData.memData = (VO_PTR) mMemOperator;
    216 
    217     if (VO_ERR_NONE != mApiHandle->Init(
    218                 &mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) {
    219         ALOGE("Failed to init AMRWB encoder");
    220         return UNKNOWN_ERROR;
    221     }
    222 
    223     VOAMRWBFRAMETYPE type = VOAMRWB_RFC3267;
    224     if (VO_ERR_NONE != mApiHandle->SetParam(
    225                 mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &type)) {
    226         ALOGE("Failed to set AMRWB encoder frame type to %d", type);
    227         return UNKNOWN_ERROR;
    228     }
    229 
    230     if (VO_ERR_NONE !=
    231             mApiHandle->SetParam(
    232                     mEncoderHandle, VO_PID_AMRWB_MODE,  &mMode)) {
    233         ALOGE("Failed to set AMRWB encoder mode to %d", mMode);
    234         return UNKNOWN_ERROR;
    235     }
    236 
    237     return OK;
    238 }
    239 
    240 int C2SoftAmrWbEnc::encodeInput(uint8_t *buffer, uint32_t length) {
    241     VO_CODECBUFFER inputData;
    242     memset(&inputData, 0, sizeof(inputData));
    243     inputData.Buffer = (unsigned char *) mInputFrame;
    244     inputData.Length = kNumBytesPerInputFrame;
    245 
    246     CHECK_EQ((VO_U32)VO_ERR_NONE,
    247              mApiHandle->SetInputData(mEncoderHandle, &inputData));
    248 
    249     VO_AUDIO_OUTPUTINFO outputInfo;
    250     memset(&outputInfo, 0, sizeof(outputInfo));
    251     VO_CODECBUFFER outputData;
    252     memset(&outputData, 0, sizeof(outputData));
    253     outputData.Buffer = buffer;
    254     outputData.Length = length;
    255     VO_U32 ret = mApiHandle->GetOutputData(
    256             mEncoderHandle, &outputData, &outputInfo);
    257     if (ret != VO_ERR_NONE && ret != VO_ERR_INPUT_BUFFER_SMALL) {
    258         ALOGD("encountered error during encode call");
    259         return -1;
    260     }
    261     return outputData.Length;
    262 }
    263 
    264 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
    265     work->worklets.front()->output.flags = work->input.flags;
    266     work->worklets.front()->output.buffers.clear();
    267     work->worklets.front()->output.ordinal = work->input.ordinal;
    268     work->workletsProcessed = 1u;
    269 }
    270 
    271 void C2SoftAmrWbEnc::process(
    272         const std::unique_ptr<C2Work> &work,
    273         const std::shared_ptr<C2BlockPool> &pool) {
    274     work->result = C2_OK;
    275     work->workletsProcessed = 0u;
    276     if (mSignalledError || mSignalledOutputEos) {
    277         work->result = C2_BAD_VALUE;
    278         return;
    279     }
    280 
    281     size_t inOffset = 0u;
    282     size_t inSize = 0u;
    283     C2ReadView rView = mDummyReadView;
    284     if (!work->input.buffers.empty()) {
    285         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
    286         inSize = rView.capacity();
    287         if (inSize && rView.error()) {
    288             ALOGE("read view map failed %d", rView.error());
    289             work->result = rView.error();
    290             return;
    291         }
    292     }
    293     bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
    294 
    295     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
    296           inSize, (int)work->input.ordinal.timestamp.peeku(),
    297           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
    298 
    299     size_t outCapacity = kNumBytesPerInputFrame;
    300     outCapacity += mFilledLen + inSize;
    301     std::shared_ptr<C2LinearBlock> outputBlock;
    302     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
    303     c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &outputBlock);
    304     if (err != C2_OK) {
    305         ALOGE("fetchLinearBlock for Output failed with status %d", err);
    306         work->result = C2_NO_MEMORY;
    307         return;
    308     }
    309     C2WriteView wView = outputBlock->map().get();
    310     if (wView.error()) {
    311         ALOGE("write view map failed %d", wView.error());
    312         work->result = wView.error();
    313         return;
    314     }
    315     uint64_t outTimeStamp =
    316         mProcessedSamples * 1000000ll / mIntf->getSampleRate();
    317     size_t inPos = 0;
    318     size_t outPos = 0;
    319     while (inPos < inSize) {
    320         const uint8_t *inPtr = rView.data() + inOffset;
    321         int validSamples = mFilledLen / sizeof(int16_t);
    322         if ((inPos + (kNumBytesPerInputFrame - mFilledLen)) <= inSize) {
    323             memcpy(mInputFrame + validSamples, inPtr + inPos,
    324                    (kNumBytesPerInputFrame - mFilledLen));
    325             inPos += (kNumBytesPerInputFrame - mFilledLen);
    326         } else {
    327             memcpy(mInputFrame + validSamples, inPtr + inPos, (inSize - inPos));
    328             mFilledLen += (inSize - inPos);
    329             inPos += (inSize - inPos);
    330             if (eos) {
    331                 validSamples = mFilledLen / sizeof(int16_t);
    332                 memset(mInputFrame + validSamples, 0, (kNumBytesPerInputFrame - mFilledLen));
    333             } else break;
    334         }
    335         int numEncBytes = encodeInput((wView.data() + outPos), outCapacity - outPos);
    336         if (numEncBytes < 0) {
    337             ALOGE("encodeFrame call failed, state [%d %zu %zu]", numEncBytes, outPos, outCapacity);
    338             mSignalledError = true;
    339             work->result = C2_CORRUPTED;
    340             return;
    341         }
    342         outPos += numEncBytes;
    343         mProcessedSamples += kNumSamplesPerFrame;
    344         mFilledLen = 0;
    345     }
    346     ALOGV("causal sample size %d", mFilledLen);
    347     if (mIsFirst) {
    348         mIsFirst = false;
    349         mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
    350     }
    351     fillEmptyWork(work);
    352     if (outPos != 0) {
    353         work->worklets.front()->output.buffers.push_back(
    354                 createLinearBuffer(std::move(outputBlock), 0, outPos));
    355         work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
    356     }
    357     if (eos) {
    358         mSignalledOutputEos = true;
    359         ALOGV("signalled EOS");
    360         if (mFilledLen) ALOGV("Discarding trailing %d bytes", mFilledLen);
    361     }
    362 }
    363 
    364 c2_status_t C2SoftAmrWbEnc::drain(
    365         uint32_t drainMode,
    366         const std::shared_ptr<C2BlockPool> &pool) {
    367     (void) pool;
    368     if (drainMode == NO_DRAIN) {
    369         ALOGW("drain with NO_DRAIN: no-op");
    370         return C2_OK;
    371     }
    372     if (drainMode == DRAIN_CHAIN) {
    373         ALOGW("DRAIN_CHAIN not supported");
    374         return C2_OMITTED;
    375     }
    376 
    377     onFlush_sm();
    378     return C2_OK;
    379 }
    380 
    381 class C2SoftAmrWbEncFactory : public C2ComponentFactory {
    382 public:
    383     C2SoftAmrWbEncFactory()
    384         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
    385               GetCodec2PlatformComponentStore()->getParamReflector())) {}
    386 
    387     virtual c2_status_t createComponent(
    388             c2_node_id_t id,
    389             std::shared_ptr<C2Component>* const component,
    390             std::function<void(C2Component*)> deleter) override {
    391         *component = std::shared_ptr<C2Component>(
    392             new C2SoftAmrWbEnc(
    393                 COMPONENT_NAME, id,
    394                 std::make_shared<C2SoftAmrWbEnc::IntfImpl>(mHelper)),
    395             deleter);
    396         return C2_OK;
    397     }
    398 
    399     virtual c2_status_t createInterface(
    400             c2_node_id_t id,
    401             std::shared_ptr<C2ComponentInterface>* const interface,
    402             std::function<void(C2ComponentInterface*)> deleter) override {
    403         *interface = std::shared_ptr<C2ComponentInterface>(
    404             new SimpleInterface<C2SoftAmrWbEnc::IntfImpl>(
    405                 COMPONENT_NAME, id,
    406                 std::make_shared<C2SoftAmrWbEnc::IntfImpl>(mHelper)),
    407             deleter);
    408         return C2_OK;
    409     }
    410 
    411     virtual ~C2SoftAmrWbEncFactory() override = default;
    412 
    413 private:
    414     std::shared_ptr<C2ReflectorHelper> mHelper;
    415 };
    416 
    417 }  // namespace android
    418 
    419 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
    420     ALOGV("in %s", __func__);
    421     return new ::android::C2SoftAmrWbEncFactory();
    422 }
    423 
    424 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
    425     ALOGV("in %s", __func__);
    426     delete factory;
    427 }
    428