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 #ifdef AMRNB
     19 #define LOG_TAG "C2SoftAmrNbDec"
     20 #else
     21 #define LOG_TAG "C2SoftAmrWbDec"
     22 #endif
     23 #include <log/log.h>
     24 
     25 #include <media/stagefright/foundation/MediaDefs.h>
     26 
     27 #include <C2PlatformSupport.h>
     28 #include <SimpleC2Interface.h>
     29 
     30 #include "C2SoftAmrDec.h"
     31 #include "gsmamr_dec.h"
     32 #include "pvamrwbdecoder.h"
     33 
     34 namespace android {
     35 
     36 #ifdef AMRNB
     37   constexpr char COMPONENT_NAME[] = "c2.android.amrnb.decoder";
     38 #else
     39   constexpr char COMPONENT_NAME[] = "c2.android.amrwb.decoder";
     40 #endif
     41 
     42 class C2SoftAmrDec::IntfImpl : public C2InterfaceHelper {
     43 public:
     44     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
     45         : C2InterfaceHelper(helper) {
     46 
     47         setDerivedInstance(this);
     48 
     49         addParameter(
     50                 DefineParam(mInputFormat, C2_NAME_INPUT_STREAM_FORMAT_SETTING)
     51                 .withConstValue(new C2StreamFormatConfig::input(0u, C2FormatCompressed))
     52                 .build());
     53 
     54         addParameter(
     55                 DefineParam(mOutputFormat, C2_NAME_OUTPUT_STREAM_FORMAT_SETTING)
     56                 .withConstValue(new C2StreamFormatConfig::output(0u, C2FormatAudio))
     57                 .build());
     58 
     59         addParameter(
     60                 DefineParam(mInputMediaType, C2_NAME_INPUT_PORT_MIME_SETTING)
     61                 .withConstValue(AllocSharedString<C2PortMimeConfig::input>(
     62 #ifdef AMRNB
     63                         MEDIA_MIMETYPE_AUDIO_AMR_NB
     64 #else
     65                         MEDIA_MIMETYPE_AUDIO_AMR_WB
     66 #endif
     67                 )).build());
     68 
     69         addParameter(
     70                 DefineParam(mOutputMediaType, C2_NAME_OUTPUT_PORT_MIME_SETTING)
     71                 .withConstValue(AllocSharedString<C2PortMimeConfig::output>(
     72                         MEDIA_MIMETYPE_AUDIO_RAW))
     73                 .build());
     74 
     75         addParameter(
     76                 DefineParam(mSampleRate, C2_NAME_STREAM_SAMPLE_RATE_SETTING)
     77 #ifdef AMRNB
     78                 .withDefault(new C2StreamSampleRateInfo::output(0u, 8000))
     79                 .withFields({C2F(mSampleRate, value).equalTo(8000)})
     80 #else
     81                 .withDefault(new C2StreamSampleRateInfo::output(0u, 16000))
     82                 .withFields({C2F(mSampleRate, value).equalTo(16000)})
     83 #endif
     84                 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
     85                 .build());
     86 
     87         addParameter(
     88                 DefineParam(mChannelCount, C2_NAME_STREAM_CHANNEL_COUNT_SETTING)
     89                 .withDefault(new C2StreamChannelCountInfo::output(0u, 1))
     90                 .withFields({C2F(mChannelCount, value).equalTo(1)})
     91                 .withSetter((Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps))
     92                 .build());
     93 
     94         addParameter(
     95                 DefineParam(mBitrate, C2_NAME_STREAM_BITRATE_SETTING)
     96 #ifdef AMRNB
     97                 .withDefault(new C2BitrateTuning::input(0u, 4750))
     98                 .withFields({C2F(mBitrate, value).inRange(4750, 12200)})
     99 #else
    100                 .withDefault(new C2BitrateTuning::input(0u, 6600))
    101                 .withFields({C2F(mBitrate, value).inRange(6600, 23850)})
    102 #endif
    103                 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
    104                 .build());
    105     }
    106 
    107 private:
    108     std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
    109     std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
    110     std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
    111     std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
    112     std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
    113     std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
    114     std::shared_ptr<C2BitrateTuning::input> mBitrate;
    115 };
    116 
    117 C2SoftAmrDec::C2SoftAmrDec(
    118         const char *name,
    119         c2_node_id_t id,
    120         const std::shared_ptr<IntfImpl> &intfImpl)
    121     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
    122       mIntf(intfImpl),
    123       mAmrHandle(nullptr),
    124       mDecoderBuf(nullptr),
    125       mDecoderCookie(nullptr) {
    126 #ifdef AMRNB
    127     mIsWide = false;
    128 #else
    129     mIsWide = true;
    130 #endif
    131 }
    132 
    133 C2SoftAmrDec::~C2SoftAmrDec() {
    134     (void)onRelease();
    135 }
    136 
    137 c2_status_t C2SoftAmrDec::onInit() {
    138     status_t err = initDecoder();
    139     return err == OK ? C2_OK : C2_NO_MEMORY;
    140 }
    141 
    142 c2_status_t C2SoftAmrDec::onStop() {
    143     if (!mIsWide) {
    144         Speech_Decode_Frame_reset(mAmrHandle);
    145     } else {
    146         pvDecoder_AmrWb_Reset(mAmrHandle, 0 /* reset_all */);
    147     }
    148     mSignalledError = false;
    149     mSignalledOutputEos = false;
    150 
    151     return C2_OK;
    152 }
    153 
    154 void C2SoftAmrDec::onReset() {
    155     (void)onStop();
    156 }
    157 
    158 void C2SoftAmrDec::onRelease() {
    159     if (!mIsWide) {
    160         if (mAmrHandle) {
    161             GSMDecodeFrameExit(&mAmrHandle);
    162         }
    163         mAmrHandle = nullptr;
    164     } else {
    165         if (mDecoderBuf) {
    166             free(mDecoderBuf);
    167         }
    168         mDecoderBuf = nullptr;
    169         mAmrHandle = nullptr;
    170         mDecoderCookie = nullptr;
    171     }
    172 }
    173 
    174 c2_status_t C2SoftAmrDec::onFlush_sm() {
    175     return onStop();
    176 }
    177 
    178 status_t C2SoftAmrDec::initDecoder() {
    179     if (!mIsWide) {
    180         if (GSMInitDecode(&mAmrHandle, (int8_t *)"AMRNBDecoder"))
    181             return UNKNOWN_ERROR;
    182     } else {
    183         uint32_t memReq = pvDecoder_AmrWbMemRequirements();
    184         mDecoderBuf = malloc(memReq);
    185         if (mDecoderBuf) {
    186             pvDecoder_AmrWb_Init(&mAmrHandle, mDecoderBuf, &mDecoderCookie);
    187         }
    188         else {
    189             return NO_MEMORY;
    190         }
    191     }
    192     mSignalledError = false;
    193     mSignalledOutputEos = false;
    194 
    195     return OK;
    196 }
    197 
    198 static size_t getFrameSize(bool isWide, unsigned FM) {
    199     static const size_t kFrameSizeNB[16] = {
    200         12, 13, 15, 17, 19, 20, 26, 31,
    201         5, 6, 5, 5, // SID
    202         0, 0, 0, // future use
    203         0 // no data
    204     };
    205     static const size_t kFrameSizeWB[16] = {
    206         17, 23, 32, 36, 40, 46, 50, 58, 60,
    207         5, // SID
    208         0, 0, 0, 0, // future use
    209         0, // speech lost
    210         0 // no data
    211     };
    212 
    213     if (FM > 15 || (isWide && FM > 9 && FM < 14) || (!isWide && FM > 11 && FM < 15)) {
    214         ALOGE("illegal AMR frame mode %d", FM);
    215         return 0;
    216     }
    217     // add 1 for header byte
    218     return (isWide ? kFrameSizeWB[FM] : kFrameSizeNB[FM]) + 1;
    219 }
    220 
    221 static status_t calculateNumFrames(const uint8 *input, size_t inSize,
    222                                    std::vector<size_t> *frameSizeList, bool isWide) {
    223     for (size_t k = 0; k < inSize;) {
    224         int16_t FM = ((input[0] >> 3) & 0x0f);
    225         size_t frameSize = getFrameSize(isWide, FM);
    226         if (frameSize == 0) {
    227             return UNKNOWN_ERROR;
    228         }
    229         if ((inSize - k) >= frameSize) {
    230             input += frameSize;
    231             k += frameSize;
    232         }
    233         else break;
    234         frameSizeList->push_back(frameSize);
    235     }
    236     return OK;
    237 }
    238 
    239 void C2SoftAmrDec::process(
    240         const std::unique_ptr<C2Work> &work,
    241         const std::shared_ptr<C2BlockPool> &pool) {
    242     work->result = C2_OK;
    243     work->workletsProcessed = 0u;
    244     if (mSignalledError || mSignalledOutputEos) {
    245         work->result = C2_BAD_VALUE;
    246         return;
    247     }
    248 
    249     C2ReadView rView = mDummyReadView;
    250     size_t inOffset = 0u;
    251     size_t inSize = 0u;
    252     if (!work->input.buffers.empty()) {
    253         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
    254         inSize = rView.capacity();
    255         if (inSize && rView.error()) {
    256             ALOGE("read view map failed %d", rView.error());
    257             work->result = rView.error();
    258             return;
    259         }
    260     }
    261 
    262     bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
    263     if (inSize == 0) {
    264         work->worklets.front()->output.flags = work->input.flags;
    265         work->worklets.front()->output.buffers.clear();
    266         work->worklets.front()->output.ordinal = work->input.ordinal;
    267         work->workletsProcessed = 1u;
    268         if (eos) {
    269             mSignalledOutputEos = true;
    270             ALOGV("signalled EOS");
    271         }
    272         return;
    273     }
    274 
    275     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
    276           (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
    277 
    278     std::vector<size_t> frameSizeList;
    279     if (OK != calculateNumFrames(rView.data() + inOffset, inSize, &frameSizeList,
    280                                  mIsWide)) {
    281         work->result = C2_CORRUPTED;
    282         mSignalledError = true;
    283         return;
    284     }
    285     if (frameSizeList.empty()) {
    286         ALOGE("input size smaller than expected");
    287         work->result = C2_CORRUPTED;
    288         mSignalledError = true;
    289         return;
    290     }
    291 
    292     int16_t outSamples = mIsWide ? kNumSamplesPerFrameWB : kNumSamplesPerFrameNB;
    293     size_t calOutSize = outSamples * frameSizeList.size() * sizeof(int16_t);
    294     std::shared_ptr<C2LinearBlock> block;
    295     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
    296     c2_status_t err = pool->fetchLinearBlock(calOutSize, usage, &block);
    297     if (err != C2_OK) {
    298         ALOGE("fetchLinearBlock for Output failed with status %d", err);
    299         work->result = C2_NO_MEMORY;
    300         return;
    301     }
    302     C2WriteView wView = block->map().get();
    303     if (wView.error()) {
    304         ALOGE("write view map failed %d", wView.error());
    305         work->result = wView.error();
    306         return;
    307     }
    308 
    309     int16_t *output = reinterpret_cast<int16_t *>(wView.data());
    310     auto it = frameSizeList.begin();
    311     const uint8_t *inPtr = rView.data() + inOffset;
    312     size_t inPos = 0;
    313     while (inPos < inSize) {
    314         if (it == frameSizeList.end()) {
    315             ALOGD("unexpected trailing bytes, ignoring them");
    316             break;
    317         }
    318         uint8_t *input = const_cast<uint8_t *>(inPtr + inPos);
    319         int16_t FM = ((*input >> 3) & 0x0f);
    320         if (!mIsWide) {
    321             int32_t numBytesRead = AMRDecode(mAmrHandle,
    322                                              (Frame_Type_3GPP) FM,
    323                                              input + 1, output, MIME_IETF);
    324             if (static_cast<size_t>(numBytesRead + 1) != *it) {
    325                 ALOGE("panic, parsed size does not match decoded size");
    326                 work->result = C2_CORRUPTED;
    327                 mSignalledError = true;
    328                 return;
    329             }
    330         } else {
    331             if (FM >= 9) {
    332                 // Produce silence instead of comfort noise and for
    333                 // speech lost/no data.
    334                 memset(output, 0, outSamples * sizeof(int16_t));
    335             } else {
    336                 int16_t FT;
    337                 RX_State_wb rx_state;
    338                 int16_t numRecSamples;
    339 
    340                 mime_unsorting(const_cast<uint8_t *>(&input[1]),
    341                                mInputSampleBuffer, &FT, &FM, 1, &rx_state);
    342                 pvDecoder_AmrWb(FM, mInputSampleBuffer, output, &numRecSamples,
    343                                 mDecoderBuf, FT, mDecoderCookie);
    344                 if (numRecSamples != outSamples) {
    345                     ALOGE("Sample output per frame incorrect");
    346                     work->result = C2_CORRUPTED;
    347                     mSignalledError = true;
    348                     return;
    349                 }
    350                 /* Delete the 2 LSBs (14-bit output) */
    351                 for (int i = 0; i < numRecSamples; ++i) {
    352                     output[i] &= 0xfffC;
    353                 }
    354             }
    355         }
    356         inPos += *it;
    357         output += outSamples;
    358         ++it;
    359     }
    360 
    361     work->worklets.front()->output.flags = work->input.flags;
    362     work->worklets.front()->output.buffers.clear();
    363     work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
    364     work->worklets.front()->output.ordinal = work->input.ordinal;
    365     work->workletsProcessed = 1u;
    366     if (eos) {
    367         mSignalledOutputEos = true;
    368         ALOGV("signalled EOS");
    369     }
    370 }
    371 
    372 c2_status_t C2SoftAmrDec::drain(
    373         uint32_t drainMode,
    374         const std::shared_ptr<C2BlockPool> &pool) {
    375     (void)pool;
    376     if (drainMode == NO_DRAIN) {
    377         ALOGW("drain with NO_DRAIN: no-op");
    378         return C2_OK;
    379     }
    380     if (drainMode == DRAIN_CHAIN) {
    381         ALOGW("DRAIN_CHAIN not supported");
    382         return C2_OMITTED;
    383     }
    384     return C2_OK;
    385 }
    386 
    387 class C2SoftAMRDecFactory : public C2ComponentFactory {
    388 public:
    389     C2SoftAMRDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
    390             GetCodec2PlatformComponentStore()->getParamReflector())) {
    391     }
    392 
    393     virtual c2_status_t createComponent(
    394             c2_node_id_t id,
    395             std::shared_ptr<C2Component>* const component,
    396             std::function<void(C2Component*)> deleter) override {
    397         *component = std::shared_ptr<C2Component>(
    398                 new C2SoftAmrDec(COMPONENT_NAME, id,
    399                               std::make_shared<C2SoftAmrDec::IntfImpl>(mHelper)),
    400                 deleter);
    401         return C2_OK;
    402     }
    403 
    404     virtual c2_status_t createInterface(
    405             c2_node_id_t id,
    406             std::shared_ptr<C2ComponentInterface>* const interface,
    407             std::function<void(C2ComponentInterface*)> deleter) override {
    408         *interface = std::shared_ptr<C2ComponentInterface>(
    409                 new SimpleInterface<C2SoftAmrDec::IntfImpl>(
    410                         COMPONENT_NAME, id, std::make_shared<C2SoftAmrDec::IntfImpl>(mHelper)),
    411                 deleter);
    412         return C2_OK;
    413     }
    414 
    415     virtual ~C2SoftAMRDecFactory() override = default;
    416 
    417 private:
    418     std::shared_ptr<C2ReflectorHelper> mHelper;
    419 };
    420 
    421 }  // namespace android
    422 
    423 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
    424     ALOGV("in %s", __func__);
    425     return new ::android::C2SoftAMRDecFactory();
    426 }
    427 
    428 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
    429     ALOGV("in %s", __func__);
    430     delete factory;
    431 }
    432