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:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)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
getSampleRate() const92 uint32_t getSampleRate() const { return mSampleRate->value; }
getChannelCount() const93 uint32_t getChannelCount() const { return mChannelCount->value; }
getBitrate() const94 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
C2SoftAmrWbEnc(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)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
~C2SoftAmrWbEnc()117 C2SoftAmrWbEnc::~C2SoftAmrWbEnc() {
118 onRelease();
119 }
120
onInit()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
onRelease()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
onStop()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
onReset()186 void C2SoftAmrWbEnc::onReset() {
187 (void) onStop();
188 }
189
onFlush_sm()190 c2_status_t C2SoftAmrWbEnc::onFlush_sm() {
191 return onStop();
192 }
193
initEncoder()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
encodeInput(uint8_t * buffer,uint32_t length)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
fillEmptyWork(const std::unique_ptr<C2Work> & work)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
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)271 void C2SoftAmrWbEnc::process(
272 const std::unique_ptr<C2Work> &work,
273 const std::shared_ptr<C2BlockPool> &pool) {
274 // Initialize output work
275 work->result = C2_OK;
276 work->workletsProcessed = 1u;
277 work->worklets.front()->output.flags = work->input.flags;
278
279 if (mSignalledError || mSignalledOutputEos) {
280 work->result = C2_BAD_VALUE;
281 return;
282 }
283
284 size_t inOffset = 0u;
285 size_t inSize = 0u;
286 C2ReadView rView = mDummyReadView;
287 if (!work->input.buffers.empty()) {
288 rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
289 inSize = rView.capacity();
290 if (inSize && rView.error()) {
291 ALOGE("read view map failed %d", rView.error());
292 work->result = rView.error();
293 return;
294 }
295 }
296 bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
297
298 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
299 inSize, (int)work->input.ordinal.timestamp.peeku(),
300 (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
301
302 size_t outCapacity = kNumBytesPerInputFrame;
303 outCapacity += mFilledLen + inSize;
304 std::shared_ptr<C2LinearBlock> outputBlock;
305 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
306 c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &outputBlock);
307 if (err != C2_OK) {
308 ALOGE("fetchLinearBlock for Output failed with status %d", err);
309 work->result = C2_NO_MEMORY;
310 return;
311 }
312 C2WriteView wView = outputBlock->map().get();
313 if (wView.error()) {
314 ALOGE("write view map failed %d", wView.error());
315 work->result = wView.error();
316 return;
317 }
318 uint64_t outTimeStamp =
319 mProcessedSamples * 1000000ll / mIntf->getSampleRate();
320 size_t inPos = 0;
321 size_t outPos = 0;
322 while (inPos < inSize) {
323 const uint8_t *inPtr = rView.data() + inOffset;
324 int validSamples = mFilledLen / sizeof(int16_t);
325 if ((inPos + (kNumBytesPerInputFrame - mFilledLen)) <= inSize) {
326 memcpy(mInputFrame + validSamples, inPtr + inPos,
327 (kNumBytesPerInputFrame - mFilledLen));
328 inPos += (kNumBytesPerInputFrame - mFilledLen);
329 } else {
330 memcpy(mInputFrame + validSamples, inPtr + inPos, (inSize - inPos));
331 mFilledLen += (inSize - inPos);
332 inPos += (inSize - inPos);
333 if (eos) {
334 validSamples = mFilledLen / sizeof(int16_t);
335 memset(mInputFrame + validSamples, 0, (kNumBytesPerInputFrame - mFilledLen));
336 } else break;
337 }
338 int numEncBytes = encodeInput((wView.data() + outPos), outCapacity - outPos);
339 if (numEncBytes < 0) {
340 ALOGE("encodeFrame call failed, state [%d %zu %zu]", numEncBytes, outPos, outCapacity);
341 mSignalledError = true;
342 work->result = C2_CORRUPTED;
343 return;
344 }
345 outPos += numEncBytes;
346 mProcessedSamples += kNumSamplesPerFrame;
347 mFilledLen = 0;
348 }
349 ALOGV("causal sample size %d", mFilledLen);
350 if (mIsFirst) {
351 mIsFirst = false;
352 mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
353 }
354 fillEmptyWork(work);
355 if (outPos != 0) {
356 work->worklets.front()->output.buffers.push_back(
357 createLinearBuffer(std::move(outputBlock), 0, outPos));
358 work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
359 }
360 if (eos) {
361 mSignalledOutputEos = true;
362 ALOGV("signalled EOS");
363 if (mFilledLen) ALOGV("Discarding trailing %d bytes", mFilledLen);
364 }
365 }
366
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)367 c2_status_t C2SoftAmrWbEnc::drain(
368 uint32_t drainMode,
369 const std::shared_ptr<C2BlockPool> &pool) {
370 (void) pool;
371 if (drainMode == NO_DRAIN) {
372 ALOGW("drain with NO_DRAIN: no-op");
373 return C2_OK;
374 }
375 if (drainMode == DRAIN_CHAIN) {
376 ALOGW("DRAIN_CHAIN not supported");
377 return C2_OMITTED;
378 }
379
380 onFlush_sm();
381 return C2_OK;
382 }
383
384 class C2SoftAmrWbEncFactory : public C2ComponentFactory {
385 public:
C2SoftAmrWbEncFactory()386 C2SoftAmrWbEncFactory()
387 : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
388 GetCodec2PlatformComponentStore()->getParamReflector())) {}
389
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)390 virtual c2_status_t createComponent(
391 c2_node_id_t id,
392 std::shared_ptr<C2Component>* const component,
393 std::function<void(C2Component*)> deleter) override {
394 *component = std::shared_ptr<C2Component>(
395 new C2SoftAmrWbEnc(
396 COMPONENT_NAME, id,
397 std::make_shared<C2SoftAmrWbEnc::IntfImpl>(mHelper)),
398 deleter);
399 return C2_OK;
400 }
401
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)402 virtual c2_status_t createInterface(
403 c2_node_id_t id,
404 std::shared_ptr<C2ComponentInterface>* const interface,
405 std::function<void(C2ComponentInterface*)> deleter) override {
406 *interface = std::shared_ptr<C2ComponentInterface>(
407 new SimpleInterface<C2SoftAmrWbEnc::IntfImpl>(
408 COMPONENT_NAME, id,
409 std::make_shared<C2SoftAmrWbEnc::IntfImpl>(mHelper)),
410 deleter);
411 return C2_OK;
412 }
413
414 virtual ~C2SoftAmrWbEncFactory() override = default;
415
416 private:
417 std::shared_ptr<C2ReflectorHelper> mHelper;
418 };
419
420 } // namespace android
421
CreateCodec2Factory()422 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
423 ALOGV("in %s", __func__);
424 return new ::android::C2SoftAmrWbEncFactory();
425 }
426
DestroyCodec2Factory(::C2ComponentFactory * factory)427 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
428 ALOGV("in %s", __func__);
429 delete factory;
430 }
431