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