Home | History | Annotate | Download | only in g711
      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 "C2SoftG711Dec"
     19 #include <log/log.h>
     20 
     21 #include <media/stagefright/foundation/MediaDefs.h>
     22 
     23 #include <C2PlatformSupport.h>
     24 #include <SimpleC2Interface.h>
     25 
     26 #include "C2SoftG711Dec.h"
     27 
     28 namespace android {
     29 
     30 #ifdef ALAW
     31 constexpr char COMPONENT_NAME[] = "c2.android.g711.alaw.decoder";
     32 #else
     33 constexpr char COMPONENT_NAME[] = "c2.android.g711.mlaw.decoder";
     34 #endif
     35 
     36 class C2SoftG711Dec::IntfImpl : public C2InterfaceHelper {
     37 public:
     38     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
     39         : C2InterfaceHelper(helper) {
     40 
     41         setDerivedInstance(this);
     42 
     43         addParameter(
     44                 DefineParam(mInputFormat, C2_NAME_INPUT_STREAM_FORMAT_SETTING)
     45                 .withConstValue(new C2StreamFormatConfig::input(0u, C2FormatCompressed))
     46                 .build());
     47 
     48         addParameter(
     49                 DefineParam(mOutputFormat, C2_NAME_OUTPUT_STREAM_FORMAT_SETTING)
     50                 .withConstValue(new C2StreamFormatConfig::output(0u, C2FormatAudio))
     51                 .build());
     52 
     53         addParameter(
     54                 DefineParam(mInputMediaType, C2_NAME_INPUT_PORT_MIME_SETTING)
     55                 .withConstValue(AllocSharedString<C2PortMimeConfig::input>(
     56 #ifdef ALAW
     57                         MEDIA_MIMETYPE_AUDIO_G711_ALAW
     58 #else
     59                         MEDIA_MIMETYPE_AUDIO_G711_MLAW
     60 #endif
     61                 )).build());
     62 
     63         addParameter(
     64                 DefineParam(mOutputMediaType, C2_NAME_OUTPUT_PORT_MIME_SETTING)
     65                 .withConstValue(AllocSharedString<C2PortMimeConfig::output>(
     66                         MEDIA_MIMETYPE_AUDIO_RAW))
     67                 .build());
     68 
     69         addParameter(
     70                 DefineParam(mSampleRate, C2_NAME_STREAM_SAMPLE_RATE_SETTING)
     71                 .withDefault(new C2StreamSampleRateInfo::output(0u, 8000))
     72                 .withFields({C2F(mSampleRate, value).inRange(8000, 48000)})
     73                 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
     74                 .build());
     75 
     76         addParameter(
     77                 DefineParam(mChannelCount, C2_NAME_STREAM_CHANNEL_COUNT_SETTING)
     78                 .withDefault(new C2StreamChannelCountInfo::output(0u, 1))
     79                 .withFields({C2F(mChannelCount, value).equalTo(1)})
     80                 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
     81                 .build());
     82 
     83         addParameter(
     84                 DefineParam(mBitrate, C2_NAME_STREAM_BITRATE_SETTING)
     85                 .withDefault(new C2BitrateTuning::input(0u, 64000))
     86                 .withFields({C2F(mBitrate, value).equalTo(64000)})
     87                 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
     88                 .build());
     89     }
     90 
     91 private:
     92     std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
     93     std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
     94     std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
     95     std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
     96     std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
     97     std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
     98     std::shared_ptr<C2BitrateTuning::input> mBitrate;
     99 };
    100 
    101 C2SoftG711Dec::C2SoftG711Dec(
    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 }
    108 
    109 C2SoftG711Dec::~C2SoftG711Dec() {
    110     onRelease();
    111 }
    112 
    113 c2_status_t C2SoftG711Dec::onInit() {
    114     mSignalledOutputEos = false;
    115     return C2_OK;
    116 }
    117 
    118 c2_status_t C2SoftG711Dec::onStop() {
    119     mSignalledOutputEos = false;
    120     return C2_OK;
    121 }
    122 
    123 void C2SoftG711Dec::onReset() {
    124     (void)onStop();
    125 }
    126 
    127 void C2SoftG711Dec::onRelease() {
    128 }
    129 
    130 c2_status_t C2SoftG711Dec::onFlush_sm() {
    131     return onStop();
    132 }
    133 
    134 void C2SoftG711Dec::process(
    135         const std::unique_ptr<C2Work> &work,
    136         const std::shared_ptr<C2BlockPool> &pool) {
    137     work->result = C2_OK;
    138     work->workletsProcessed = 0u;
    139     if (mSignalledOutputEos) {
    140         work->result = C2_BAD_VALUE;
    141         return;
    142     }
    143 
    144     C2ReadView rView = mDummyReadView;
    145     size_t inOffset = 0u;
    146     size_t inSize = 0u;
    147     if (!work->input.buffers.empty()) {
    148         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
    149         inSize = rView.capacity();
    150         if (inSize && rView.error()) {
    151             ALOGE("read view map failed %d", rView.error());
    152             work->result = C2_CORRUPTED;
    153             return;
    154         }
    155     }
    156     bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
    157     int outSize = inSize * sizeof(int16_t);
    158 
    159     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
    160           (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
    161 
    162     if (inSize == 0) {
    163         work->worklets.front()->output.flags = work->input.flags;
    164         work->worklets.front()->output.buffers.clear();
    165         work->worklets.front()->output.ordinal = work->input.ordinal;
    166         work->workletsProcessed = 1u;
    167         if (eos) {
    168             mSignalledOutputEos = true;
    169             ALOGV("signalled EOS");
    170         }
    171         return;
    172     }
    173 
    174     uint8_t *inputptr = const_cast<uint8_t *>(rView.data() + inOffset);
    175 
    176     std::shared_ptr<C2LinearBlock> block;
    177     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
    178     c2_status_t err = pool->fetchLinearBlock(outSize, usage, &block);
    179     if (err != C2_OK) {
    180         ALOGE("fetchLinearBlock for Output failed with status %d", err);
    181         work->result = C2_NO_MEMORY;
    182         return;
    183     }
    184     C2WriteView wView = block->map().get();
    185     if (wView.error()) {
    186         ALOGE("write view map failed %d", wView.error());
    187         work->result = C2_CORRUPTED;
    188         return;
    189     }
    190     int16_t *outputptr = reinterpret_cast<int16_t *>(wView.data());
    191 
    192 #ifdef ALAW
    193     DecodeALaw(outputptr, inputptr, inSize);
    194 #else
    195     DecodeMLaw(outputptr, inputptr, inSize);
    196 #endif
    197 
    198     work->worklets.front()->output.flags = work->input.flags;
    199     work->worklets.front()->output.buffers.clear();
    200     work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
    201     work->worklets.front()->output.ordinal = work->input.ordinal;
    202     work->workletsProcessed = 1u;
    203 
    204     if (eos) {
    205         mSignalledOutputEos = true;
    206         ALOGV("signalled EOS");
    207     }
    208 }
    209 
    210 c2_status_t C2SoftG711Dec::drain(
    211         uint32_t drainMode,
    212         const std::shared_ptr<C2BlockPool> &pool) {
    213     (void) pool;
    214     if (drainMode == NO_DRAIN) {
    215         ALOGW("drain with NO_DRAIN: no-op");
    216         return C2_OK;
    217     }
    218     if (drainMode == DRAIN_CHAIN) {
    219         ALOGW("DRAIN_CHAIN not supported");
    220         return C2_OMITTED;
    221     }
    222 
    223     return C2_OK;
    224 }
    225 
    226 #ifdef ALAW
    227 void C2SoftG711Dec::DecodeALaw(
    228         int16_t *out, const uint8_t *in, size_t inSize) {
    229     while (inSize > 0) {
    230         inSize--;
    231         int32_t x = *in++;
    232 
    233         int32_t ix = x ^ 0x55;
    234         ix &= 0x7f;
    235 
    236         int32_t iexp = ix >> 4;
    237         int32_t mant = ix & 0x0f;
    238 
    239         if (iexp > 0) {
    240             mant += 16;
    241         }
    242 
    243         mant = (mant << 4) + 8;
    244 
    245         if (iexp > 1) {
    246             mant = mant << (iexp - 1);
    247         }
    248 
    249         *out++ = (x > 127) ? mant : -mant;
    250     }
    251 }
    252 #else
    253 void C2SoftG711Dec::DecodeMLaw(
    254         int16_t *out, const uint8_t *in, size_t inSize) {
    255     while (inSize > 0) {
    256         inSize--;
    257         int32_t x = *in++;
    258 
    259         int32_t mantissa = ~x;
    260         int32_t exponent = (mantissa >> 4) & 7;
    261         int32_t segment = exponent + 1;
    262         mantissa &= 0x0f;
    263 
    264         int32_t step = 4 << segment;
    265 
    266         int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
    267 
    268         *out++ = (x < 0x80) ? -abs : abs;
    269     }
    270 }
    271 #endif
    272 
    273 class C2SoftG711DecFactory : public C2ComponentFactory {
    274 public:
    275     C2SoftG711DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
    276             GetCodec2PlatformComponentStore()->getParamReflector())) {
    277     }
    278 
    279     virtual c2_status_t createComponent(
    280             c2_node_id_t id,
    281             std::shared_ptr<C2Component>* const component,
    282             std::function<void(C2Component*)> deleter) override {
    283         *component = std::shared_ptr<C2Component>(
    284                 new C2SoftG711Dec(COMPONENT_NAME, id,
    285                                std::make_shared<C2SoftG711Dec::IntfImpl>(mHelper)),
    286                 deleter);
    287         return C2_OK;
    288     }
    289 
    290     virtual c2_status_t createInterface(
    291             c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
    292             std::function<void(C2ComponentInterface*)> deleter) override {
    293         *interface = std::shared_ptr<C2ComponentInterface>(
    294                 new SimpleInterface<C2SoftG711Dec::IntfImpl>(
    295                         COMPONENT_NAME, id, std::make_shared<C2SoftG711Dec::IntfImpl>(mHelper)),
    296                 deleter);
    297         return C2_OK;
    298     }
    299 
    300     virtual ~C2SoftG711DecFactory() override = default;
    301 
    302 private:
    303     std::shared_ptr<C2ReflectorHelper> mHelper;
    304 };
    305 
    306 }  // namespace android
    307 
    308 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
    309     ALOGV("in %s", __func__);
    310     return new ::android::C2SoftG711DecFactory();
    311 }
    312 
    313 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
    314     ALOGV("in %s", __func__);
    315     delete factory;
    316 }
    317