• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         addParameter(
107                 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
108                 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 8192))
109                 .build());
110     }
111 
112 private:
113     std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
114     std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
115     std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
116     std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
117     std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
118     std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
119     std::shared_ptr<C2BitrateTuning::input> mBitrate;
120     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
121 };
122 
C2SoftAmrDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)123 C2SoftAmrDec::C2SoftAmrDec(
124         const char *name,
125         c2_node_id_t id,
126         const std::shared_ptr<IntfImpl> &intfImpl)
127     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
128       mIntf(intfImpl),
129       mAmrHandle(nullptr),
130       mDecoderBuf(nullptr),
131       mDecoderCookie(nullptr) {
132 #ifdef AMRNB
133     mIsWide = false;
134 #else
135     mIsWide = true;
136 #endif
137 }
138 
~C2SoftAmrDec()139 C2SoftAmrDec::~C2SoftAmrDec() {
140     (void)onRelease();
141 }
142 
onInit()143 c2_status_t C2SoftAmrDec::onInit() {
144     status_t err = initDecoder();
145     return err == OK ? C2_OK : C2_NO_MEMORY;
146 }
147 
onStop()148 c2_status_t C2SoftAmrDec::onStop() {
149     if (!mIsWide) {
150         Speech_Decode_Frame_reset(mAmrHandle);
151     } else {
152         pvDecoder_AmrWb_Reset(mAmrHandle, 0 /* reset_all */);
153     }
154     mSignalledError = false;
155     mSignalledOutputEos = false;
156 
157     return C2_OK;
158 }
159 
onReset()160 void C2SoftAmrDec::onReset() {
161     (void)onStop();
162 }
163 
onRelease()164 void C2SoftAmrDec::onRelease() {
165     if (!mIsWide) {
166         if (mAmrHandle) {
167             GSMDecodeFrameExit(&mAmrHandle);
168         }
169         mAmrHandle = nullptr;
170     } else {
171         if (mDecoderBuf) {
172             free(mDecoderBuf);
173         }
174         mDecoderBuf = nullptr;
175         mAmrHandle = nullptr;
176         mDecoderCookie = nullptr;
177     }
178 }
179 
onFlush_sm()180 c2_status_t C2SoftAmrDec::onFlush_sm() {
181     return onStop();
182 }
183 
initDecoder()184 status_t C2SoftAmrDec::initDecoder() {
185     if (!mIsWide) {
186         if (GSMInitDecode(&mAmrHandle, (int8_t *)"AMRNBDecoder"))
187             return UNKNOWN_ERROR;
188     } else {
189         uint32_t memReq = pvDecoder_AmrWbMemRequirements();
190         mDecoderBuf = malloc(memReq);
191         if (mDecoderBuf) {
192             pvDecoder_AmrWb_Init(&mAmrHandle, mDecoderBuf, &mDecoderCookie);
193         }
194         else {
195             return NO_MEMORY;
196         }
197     }
198     mSignalledError = false;
199     mSignalledOutputEos = false;
200 
201     return OK;
202 }
203 
getFrameSize(bool isWide,unsigned FM)204 static size_t getFrameSize(bool isWide, unsigned FM) {
205     static const size_t kFrameSizeNB[16] = {
206         12, 13, 15, 17, 19, 20, 26, 31,
207         5, 6, 5, 5, // SID
208         0, 0, 0, // future use
209         0 // no data
210     };
211     static const size_t kFrameSizeWB[16] = {
212         17, 23, 32, 36, 40, 46, 50, 58, 60,
213         5, // SID
214         0, 0, 0, 0, // future use
215         0, // speech lost
216         0 // no data
217     };
218 
219     if (FM > 15 || (isWide && FM > 9 && FM < 14) || (!isWide && FM > 11 && FM < 15)) {
220         ALOGE("illegal AMR frame mode %d", FM);
221         return 0;
222     }
223     // add 1 for header byte
224     return (isWide ? kFrameSizeWB[FM] : kFrameSizeNB[FM]) + 1;
225 }
226 
calculateNumFrames(const uint8 * input,size_t inSize,std::vector<size_t> * frameSizeList,bool isWide)227 static status_t calculateNumFrames(const uint8 *input, size_t inSize,
228                                    std::vector<size_t> *frameSizeList, bool isWide) {
229     for (size_t k = 0; k < inSize;) {
230         int16_t FM = ((input[0] >> 3) & 0x0f);
231         size_t frameSize = getFrameSize(isWide, FM);
232         if (frameSize == 0) {
233             return UNKNOWN_ERROR;
234         }
235         if ((inSize - k) >= frameSize) {
236             input += frameSize;
237             k += frameSize;
238         }
239         else break;
240         frameSizeList->push_back(frameSize);
241     }
242     return OK;
243 }
244 
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)245 void C2SoftAmrDec::process(
246         const std::unique_ptr<C2Work> &work,
247         const std::shared_ptr<C2BlockPool> &pool) {
248     // Initialize output work
249     work->result = C2_OK;
250     work->workletsProcessed = 1u;
251     work->worklets.front()->output.flags = work->input.flags;
252 
253     if (mSignalledError || mSignalledOutputEos) {
254         work->result = C2_BAD_VALUE;
255         return;
256     }
257 
258     C2ReadView rView = mDummyReadView;
259     size_t inOffset = 0u;
260     size_t inSize = 0u;
261     if (!work->input.buffers.empty()) {
262         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
263         inSize = rView.capacity();
264         if (inSize && rView.error()) {
265             ALOGE("read view map failed %d", rView.error());
266             work->result = rView.error();
267             return;
268         }
269     }
270 
271     bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
272     if (inSize == 0) {
273         work->worklets.front()->output.flags = work->input.flags;
274         work->worklets.front()->output.buffers.clear();
275         work->worklets.front()->output.ordinal = work->input.ordinal;
276         if (eos) {
277             mSignalledOutputEos = true;
278             ALOGV("signalled EOS");
279         }
280         return;
281     }
282 
283     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
284           (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
285 
286     std::vector<size_t> frameSizeList;
287     if (OK != calculateNumFrames(rView.data() + inOffset, inSize, &frameSizeList,
288                                  mIsWide)) {
289         work->result = C2_CORRUPTED;
290         mSignalledError = true;
291         return;
292     }
293     if (frameSizeList.empty()) {
294         ALOGE("input size smaller than expected");
295         work->result = C2_CORRUPTED;
296         mSignalledError = true;
297         return;
298     }
299 
300     int16_t outSamples = mIsWide ? kNumSamplesPerFrameWB : kNumSamplesPerFrameNB;
301     size_t calOutSize = outSamples * frameSizeList.size() * sizeof(int16_t);
302     std::shared_ptr<C2LinearBlock> block;
303     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
304     c2_status_t err = pool->fetchLinearBlock(calOutSize, usage, &block);
305     if (err != C2_OK) {
306         ALOGE("fetchLinearBlock for Output failed with status %d", err);
307         work->result = C2_NO_MEMORY;
308         return;
309     }
310     C2WriteView wView = block->map().get();
311     if (wView.error()) {
312         ALOGE("write view map failed %d", wView.error());
313         work->result = wView.error();
314         return;
315     }
316 
317     int16_t *output = reinterpret_cast<int16_t *>(wView.data());
318     auto it = frameSizeList.begin();
319     const uint8_t *inPtr = rView.data() + inOffset;
320     size_t inPos = 0;
321     while (inPos < inSize) {
322         if (it == frameSizeList.end()) {
323             ALOGD("unexpected trailing bytes, ignoring them");
324             break;
325         }
326         uint8_t *input = const_cast<uint8_t *>(inPtr + inPos);
327         int16_t FM = ((*input >> 3) & 0x0f);
328         if (!mIsWide) {
329             int32_t numBytesRead = AMRDecode(mAmrHandle,
330                                              (Frame_Type_3GPP) FM,
331                                              input + 1, output, MIME_IETF);
332             if (static_cast<size_t>(numBytesRead + 1) != *it) {
333                 ALOGE("panic, parsed size does not match decoded size");
334                 work->result = C2_CORRUPTED;
335                 mSignalledError = true;
336                 return;
337             }
338         } else {
339             if (FM >= 9) {
340                 // Produce silence instead of comfort noise and for
341                 // speech lost/no data.
342                 memset(output, 0, outSamples * sizeof(int16_t));
343             } else {
344                 int16_t FT;
345                 RX_State_wb rx_state;
346                 int16_t numRecSamples;
347 
348                 mime_unsorting(const_cast<uint8_t *>(&input[1]),
349                                mInputSampleBuffer, &FT, &FM, 1, &rx_state);
350                 pvDecoder_AmrWb(FM, mInputSampleBuffer, output, &numRecSamples,
351                                 mDecoderBuf, FT, mDecoderCookie);
352                 if (numRecSamples != outSamples) {
353                     ALOGE("Sample output per frame incorrect");
354                     work->result = C2_CORRUPTED;
355                     mSignalledError = true;
356                     return;
357                 }
358                 /* Delete the 2 LSBs (14-bit output) */
359                 for (int i = 0; i < numRecSamples; ++i) {
360                     output[i] &= 0xfffC;
361                 }
362             }
363         }
364         inPos += *it;
365         output += outSamples;
366         ++it;
367     }
368 
369     work->worklets.front()->output.flags = work->input.flags;
370     work->worklets.front()->output.buffers.clear();
371     work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
372     work->worklets.front()->output.ordinal = work->input.ordinal;
373     if (eos) {
374         mSignalledOutputEos = true;
375         ALOGV("signalled EOS");
376     }
377 }
378 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)379 c2_status_t C2SoftAmrDec::drain(
380         uint32_t drainMode,
381         const std::shared_ptr<C2BlockPool> &pool) {
382     (void)pool;
383     if (drainMode == NO_DRAIN) {
384         ALOGW("drain with NO_DRAIN: no-op");
385         return C2_OK;
386     }
387     if (drainMode == DRAIN_CHAIN) {
388         ALOGW("DRAIN_CHAIN not supported");
389         return C2_OMITTED;
390     }
391     return C2_OK;
392 }
393 
394 class C2SoftAMRDecFactory : public C2ComponentFactory {
395 public:
C2SoftAMRDecFactory()396     C2SoftAMRDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
397             GetCodec2PlatformComponentStore()->getParamReflector())) {
398     }
399 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)400     virtual c2_status_t createComponent(
401             c2_node_id_t id,
402             std::shared_ptr<C2Component>* const component,
403             std::function<void(C2Component*)> deleter) override {
404         *component = std::shared_ptr<C2Component>(
405                 new C2SoftAmrDec(COMPONENT_NAME, id,
406                               std::make_shared<C2SoftAmrDec::IntfImpl>(mHelper)),
407                 deleter);
408         return C2_OK;
409     }
410 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)411     virtual c2_status_t createInterface(
412             c2_node_id_t id,
413             std::shared_ptr<C2ComponentInterface>* const interface,
414             std::function<void(C2ComponentInterface*)> deleter) override {
415         *interface = std::shared_ptr<C2ComponentInterface>(
416                 new SimpleInterface<C2SoftAmrDec::IntfImpl>(
417                         COMPONENT_NAME, id, std::make_shared<C2SoftAmrDec::IntfImpl>(mHelper)),
418                 deleter);
419         return C2_OK;
420     }
421 
422     virtual ~C2SoftAMRDecFactory() override = default;
423 
424 private:
425     std::shared_ptr<C2ReflectorHelper> mHelper;
426 };
427 
428 }  // namespace android
429 
CreateCodec2Factory()430 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
431     ALOGV("in %s", __func__);
432     return new ::android::C2SoftAMRDecFactory();
433 }
434 
DestroyCodec2Factory(::C2ComponentFactory * factory)435 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
436     ALOGV("in %s", __func__);
437     delete factory;
438 }
439