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:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)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 
C2SoftAmrDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)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 
~C2SoftAmrDec()133 C2SoftAmrDec::~C2SoftAmrDec() {
134     (void)onRelease();
135 }
136 
onInit()137 c2_status_t C2SoftAmrDec::onInit() {
138     status_t err = initDecoder();
139     return err == OK ? C2_OK : C2_NO_MEMORY;
140 }
141 
onStop()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 
onReset()154 void C2SoftAmrDec::onReset() {
155     (void)onStop();
156 }
157 
onRelease()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 
onFlush_sm()174 c2_status_t C2SoftAmrDec::onFlush_sm() {
175     return onStop();
176 }
177 
initDecoder()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 
getFrameSize(bool isWide,unsigned FM)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 
calculateNumFrames(const uint8 * input,size_t inSize,std::vector<size_t> * frameSizeList,bool isWide)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 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)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 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)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:
C2SoftAMRDecFactory()389     C2SoftAMRDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
390             GetCodec2PlatformComponentStore()->getParamReflector())) {
391     }
392 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)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 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)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 
CreateCodec2Factory()423 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
424     ALOGV("in %s", __func__);
425     return new ::android::C2SoftAMRDecFactory();
426 }
427 
DestroyCodec2Factory(::C2ComponentFactory * factory)428 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
429     ALOGV("in %s", __func__);
430     delete factory;
431 }
432