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 namespace {
33
34 constexpr char COMPONENT_NAME[] = "c2.android.amrwb.encoder";
35
36 } // namespace
37
38 class C2SoftAmrWbEnc::IntfImpl : public SimpleInterface<void>::BaseParams {
39 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)40 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
41 : SimpleInterface<void>::BaseParams(
42 helper,
43 COMPONENT_NAME,
44 C2Component::KIND_ENCODER,
45 C2Component::DOMAIN_AUDIO,
46 MEDIA_MIMETYPE_AUDIO_AMR_WB) {
47 noPrivateBuffers();
48 noInputReferences();
49 noOutputReferences();
50 noInputLatency();
51 noTimeStretch();
52 setDerivedInstance(this);
53
54 addParameter(
55 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
56 .withConstValue(new C2ComponentAttributesSetting(
57 C2Component::ATTRIB_IS_TEMPORAL))
58 .build());
59
60 addParameter(
61 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
62 .withDefault(new C2StreamChannelCountInfo::input(0u, 1))
63 .withFields({C2F(mChannelCount, value).equalTo(1)})
64 .withSetter((Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps))
65 .build());
66
67 addParameter(
68 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
69 .withDefault(new C2StreamSampleRateInfo::input(0u, 16000))
70 .withFields({C2F(mSampleRate, value).equalTo(16000)})
71 .withSetter(
72 (Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
73 .build());
74
75 addParameter(
76 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
77 .withDefault(new C2StreamBitrateInfo::output(0u, 6600))
78 .withFields({C2F(mBitrate, value).inRange(6600, 23850)})
79 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
80 .build());
81
82 addParameter(
83 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
84 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 8192))
85 .build());
86 }
87
getSampleRate() const88 uint32_t getSampleRate() const { return mSampleRate->value; }
getChannelCount() const89 uint32_t getChannelCount() const { return mChannelCount->value; }
getBitrate() const90 uint32_t getBitrate() const { return mBitrate->value; }
91
92 private:
93 std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate;
94 std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
95 std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
96 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
97 };
98
C2SoftAmrWbEnc(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)99 C2SoftAmrWbEnc::C2SoftAmrWbEnc(const char* name, c2_node_id_t id,
100 const std::shared_ptr<IntfImpl>& intfImpl)
101 : SimpleC2Component(
102 std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
103 mIntf(intfImpl),
104 mEncoderHandle(nullptr),
105 mApiHandle(nullptr),
106 mMemOperator(nullptr) {
107 }
108
~C2SoftAmrWbEnc()109 C2SoftAmrWbEnc::~C2SoftAmrWbEnc() {
110 onRelease();
111 }
112
onInit()113 c2_status_t C2SoftAmrWbEnc::onInit() {
114 // TODO: get mode directly from config
115 switch(mIntf->getBitrate()) {
116 case 6600: mMode = VOAMRWB_MD66;
117 break;
118 case 8850: mMode = VOAMRWB_MD885;
119 break;
120 case 12650: mMode = VOAMRWB_MD1265;
121 break;
122 case 14250: mMode = VOAMRWB_MD1425;
123 break;
124 case 15850: mMode = VOAMRWB_MD1585;
125 break;
126 case 18250: mMode = VOAMRWB_MD1825;
127 break;
128 case 19850: mMode = VOAMRWB_MD1985;
129 break;
130 case 23050: mMode = VOAMRWB_MD2305;
131 break;
132 case 23850: mMode = VOAMRWB_MD2385;
133 break;
134 default: mMode = VOAMRWB_MD2305;
135 }
136 status_t err = initEncoder();
137 mIsFirst = true;
138 mSignalledError = false;
139 mSignalledOutputEos = false;
140 mAnchorTimeStamp = 0;
141 mProcessedSamples = 0;
142 mFilledLen = 0;
143
144 return err == OK ? C2_OK : C2_NO_MEMORY;
145 }
146
onRelease()147 void C2SoftAmrWbEnc::onRelease() {
148 if (mEncoderHandle) {
149 CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
150 mEncoderHandle = nullptr;
151 }
152 if (mApiHandle) {
153 delete mApiHandle;
154 mApiHandle = nullptr;
155 }
156 if (mMemOperator) {
157 delete mMemOperator;
158 mMemOperator = nullptr;
159 }
160 }
161
onStop()162 c2_status_t C2SoftAmrWbEnc::onStop() {
163 for (int i = 0; i < kNumSamplesPerFrame; i++) {
164 mInputFrame[i] = 0x0008; /* EHF_MASK */
165 }
166 uint8_t outBuffer[kNumBytesPerInputFrame];
167 (void) encodeInput(outBuffer, kNumBytesPerInputFrame);
168 mIsFirst = true;
169 mSignalledError = false;
170 mSignalledOutputEos = false;
171 mAnchorTimeStamp = 0;
172 mProcessedSamples = 0;
173 mFilledLen = 0;
174
175 return C2_OK;
176 }
177
onReset()178 void C2SoftAmrWbEnc::onReset() {
179 (void) onStop();
180 }
181
onFlush_sm()182 c2_status_t C2SoftAmrWbEnc::onFlush_sm() {
183 return onStop();
184 }
185
initEncoder()186 status_t C2SoftAmrWbEnc::initEncoder() {
187 mApiHandle = new VO_AUDIO_CODECAPI;
188 if (!mApiHandle) return NO_MEMORY;
189
190 if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) {
191 ALOGE("Failed to get api handle");
192 return UNKNOWN_ERROR;
193 }
194
195 mMemOperator = new VO_MEM_OPERATOR;
196 if (!mMemOperator) return NO_MEMORY;
197
198 mMemOperator->Alloc = cmnMemAlloc;
199 mMemOperator->Copy = cmnMemCopy;
200 mMemOperator->Free = cmnMemFree;
201 mMemOperator->Set = cmnMemSet;
202 mMemOperator->Check = cmnMemCheck;
203
204 VO_CODEC_INIT_USERDATA userData;
205 memset(&userData, 0, sizeof(userData));
206 userData.memflag = VO_IMF_USERMEMOPERATOR;
207 userData.memData = (VO_PTR) mMemOperator;
208
209 if (VO_ERR_NONE != mApiHandle->Init(
210 &mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) {
211 ALOGE("Failed to init AMRWB encoder");
212 return UNKNOWN_ERROR;
213 }
214
215 VOAMRWBFRAMETYPE type = VOAMRWB_RFC3267;
216 if (VO_ERR_NONE != mApiHandle->SetParam(
217 mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &type)) {
218 ALOGE("Failed to set AMRWB encoder frame type to %d", type);
219 return UNKNOWN_ERROR;
220 }
221
222 if (VO_ERR_NONE !=
223 mApiHandle->SetParam(
224 mEncoderHandle, VO_PID_AMRWB_MODE, &mMode)) {
225 ALOGE("Failed to set AMRWB encoder mode to %d", mMode);
226 return UNKNOWN_ERROR;
227 }
228
229 return OK;
230 }
231
encodeInput(uint8_t * buffer,uint32_t length)232 int C2SoftAmrWbEnc::encodeInput(uint8_t *buffer, uint32_t length) {
233 VO_CODECBUFFER inputData;
234 memset(&inputData, 0, sizeof(inputData));
235 inputData.Buffer = (unsigned char *) mInputFrame;
236 inputData.Length = kNumBytesPerInputFrame;
237
238 CHECK_EQ((VO_U32)VO_ERR_NONE,
239 mApiHandle->SetInputData(mEncoderHandle, &inputData));
240
241 VO_AUDIO_OUTPUTINFO outputInfo;
242 memset(&outputInfo, 0, sizeof(outputInfo));
243 VO_CODECBUFFER outputData;
244 memset(&outputData, 0, sizeof(outputData));
245 outputData.Buffer = buffer;
246 outputData.Length = length;
247 VO_U32 ret = mApiHandle->GetOutputData(
248 mEncoderHandle, &outputData, &outputInfo);
249 if (ret != VO_ERR_NONE && ret != VO_ERR_INPUT_BUFFER_SMALL) {
250 ALOGD("encountered error during encode call");
251 return -1;
252 }
253 return outputData.Length;
254 }
255
fillEmptyWork(const std::unique_ptr<C2Work> & work)256 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
257 work->worklets.front()->output.flags = work->input.flags;
258 work->worklets.front()->output.buffers.clear();
259 work->worklets.front()->output.ordinal = work->input.ordinal;
260 work->workletsProcessed = 1u;
261 }
262
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)263 void C2SoftAmrWbEnc::process(
264 const std::unique_ptr<C2Work> &work,
265 const std::shared_ptr<C2BlockPool> &pool) {
266 // Initialize output work
267 work->result = C2_OK;
268 work->workletsProcessed = 1u;
269 work->worklets.front()->output.flags = work->input.flags;
270
271 if (mSignalledError || mSignalledOutputEos) {
272 work->result = C2_BAD_VALUE;
273 return;
274 }
275
276 size_t inOffset = 0u;
277 size_t inSize = 0u;
278 C2ReadView rView = mDummyReadView;
279 if (!work->input.buffers.empty()) {
280 rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
281 inSize = rView.capacity();
282 if (inSize && rView.error()) {
283 ALOGE("read view map failed %d", rView.error());
284 work->result = rView.error();
285 return;
286 }
287 }
288 bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
289
290 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
291 inSize, (int)work->input.ordinal.timestamp.peeku(),
292 (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
293
294 size_t outCapacity = kNumBytesPerInputFrame;
295 outCapacity += mFilledLen + inSize;
296 std::shared_ptr<C2LinearBlock> outputBlock;
297 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
298 c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &outputBlock);
299 if (err != C2_OK) {
300 ALOGE("fetchLinearBlock for Output failed with status %d", err);
301 work->result = C2_NO_MEMORY;
302 return;
303 }
304 C2WriteView wView = outputBlock->map().get();
305 if (wView.error()) {
306 ALOGE("write view map failed %d", wView.error());
307 work->result = wView.error();
308 return;
309 }
310 uint64_t outTimeStamp =
311 mProcessedSamples * 1000000ll / mIntf->getSampleRate();
312 size_t inPos = 0;
313 size_t outPos = 0;
314 while (inPos < inSize) {
315 const uint8_t *inPtr = rView.data() + inOffset;
316 int validSamples = mFilledLen / sizeof(int16_t);
317 if ((inPos + (kNumBytesPerInputFrame - mFilledLen)) <= inSize) {
318 memcpy(mInputFrame + validSamples, inPtr + inPos,
319 (kNumBytesPerInputFrame - mFilledLen));
320 inPos += (kNumBytesPerInputFrame - mFilledLen);
321 } else {
322 memcpy(mInputFrame + validSamples, inPtr + inPos, (inSize - inPos));
323 mFilledLen += (inSize - inPos);
324 inPos += (inSize - inPos);
325 if (eos) {
326 validSamples = mFilledLen / sizeof(int16_t);
327 memset(mInputFrame + validSamples, 0, (kNumBytesPerInputFrame - mFilledLen));
328 } else break;
329 }
330 int numEncBytes = encodeInput((wView.data() + outPos), outCapacity - outPos);
331 if (numEncBytes < 0) {
332 ALOGE("encodeFrame call failed, state [%d %zu %zu]", numEncBytes, outPos, outCapacity);
333 mSignalledError = true;
334 work->result = C2_CORRUPTED;
335 return;
336 }
337 outPos += numEncBytes;
338 mProcessedSamples += kNumSamplesPerFrame;
339 mFilledLen = 0;
340 }
341 ALOGV("causal sample size %d", mFilledLen);
342 if (mIsFirst && outPos != 0) {
343 mIsFirst = false;
344 mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
345 }
346 fillEmptyWork(work);
347 if (outPos != 0) {
348 work->worklets.front()->output.buffers.push_back(
349 createLinearBuffer(std::move(outputBlock), 0, outPos));
350 work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
351 }
352 if (eos) {
353 mSignalledOutputEos = true;
354 ALOGV("signalled EOS");
355 if (mFilledLen) ALOGV("Discarding trailing %d bytes", mFilledLen);
356 }
357 }
358
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)359 c2_status_t C2SoftAmrWbEnc::drain(
360 uint32_t drainMode,
361 const std::shared_ptr<C2BlockPool> &pool) {
362 (void) pool;
363 if (drainMode == NO_DRAIN) {
364 ALOGW("drain with NO_DRAIN: no-op");
365 return C2_OK;
366 }
367 if (drainMode == DRAIN_CHAIN) {
368 ALOGW("DRAIN_CHAIN not supported");
369 return C2_OMITTED;
370 }
371
372 onFlush_sm();
373 return C2_OK;
374 }
375
376 class C2SoftAmrWbEncFactory : public C2ComponentFactory {
377 public:
C2SoftAmrWbEncFactory()378 C2SoftAmrWbEncFactory()
379 : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
380 GetCodec2PlatformComponentStore()->getParamReflector())) {}
381
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)382 virtual c2_status_t createComponent(
383 c2_node_id_t id,
384 std::shared_ptr<C2Component>* const component,
385 std::function<void(C2Component*)> deleter) override {
386 *component = std::shared_ptr<C2Component>(
387 new C2SoftAmrWbEnc(
388 COMPONENT_NAME, id,
389 std::make_shared<C2SoftAmrWbEnc::IntfImpl>(mHelper)),
390 deleter);
391 return C2_OK;
392 }
393
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)394 virtual c2_status_t createInterface(
395 c2_node_id_t id,
396 std::shared_ptr<C2ComponentInterface>* const interface,
397 std::function<void(C2ComponentInterface*)> deleter) override {
398 *interface = std::shared_ptr<C2ComponentInterface>(
399 new SimpleInterface<C2SoftAmrWbEnc::IntfImpl>(
400 COMPONENT_NAME, id,
401 std::make_shared<C2SoftAmrWbEnc::IntfImpl>(mHelper)),
402 deleter);
403 return C2_OK;
404 }
405
406 virtual ~C2SoftAmrWbEncFactory() override = default;
407
408 private:
409 std::shared_ptr<C2ReflectorHelper> mHelper;
410 };
411
412 } // namespace android
413
CreateCodec2Factory()414 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
415 ALOGV("in %s", __func__);
416 return new ::android::C2SoftAmrWbEncFactory();
417 }
418
DestroyCodec2Factory(::C2ComponentFactory * factory)419 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
420 ALOGV("in %s", __func__);
421 delete factory;
422 }
423