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 28namespace android { 29 30#ifdef ALAW 31constexpr char COMPONENT_NAME[] = "c2.android.g711.alaw.decoder"; 32#else 33constexpr char COMPONENT_NAME[] = "c2.android.g711.mlaw.decoder"; 34#endif 35 36class C2SoftG711Dec::IntfImpl : public C2InterfaceHelper { 37public: 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 91private: 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 101C2SoftG711Dec::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 109C2SoftG711Dec::~C2SoftG711Dec() { 110 onRelease(); 111} 112 113c2_status_t C2SoftG711Dec::onInit() { 114 mSignalledOutputEos = false; 115 return C2_OK; 116} 117 118c2_status_t C2SoftG711Dec::onStop() { 119 mSignalledOutputEos = false; 120 return C2_OK; 121} 122 123void C2SoftG711Dec::onReset() { 124 (void)onStop(); 125} 126 127void C2SoftG711Dec::onRelease() { 128} 129 130c2_status_t C2SoftG711Dec::onFlush_sm() { 131 return onStop(); 132} 133 134void 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 210c2_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 227void 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 253void 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 273class C2SoftG711DecFactory : public C2ComponentFactory { 274public: 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 302private: 303 std::shared_ptr<C2ReflectorHelper> mHelper; 304}; 305 306} // namespace android 307 308extern "C" ::C2ComponentFactory* CreateCodec2Factory() { 309 ALOGV("in %s", __func__); 310 return new ::android::C2SoftG711DecFactory(); 311} 312 313extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) { 314 ALOGV("in %s", __func__); 315 delete factory; 316} 317