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