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