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 namespace {
37
38 #ifdef AMRNB
39 constexpr char COMPONENT_NAME[] = "c2.android.amrnb.decoder";
40 #else
41 constexpr char COMPONENT_NAME[] = "c2.android.amrwb.decoder";
42 #endif
43
44 } // namespace
45
46 class C2SoftAmrDec::IntfImpl : public SimpleInterface<void>::BaseParams {
47 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)48 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
49 : SimpleInterface<void>::BaseParams(
50 helper,
51 COMPONENT_NAME,
52 C2Component::KIND_DECODER,
53 C2Component::DOMAIN_AUDIO,
54 #ifdef AMRNB
55 MEDIA_MIMETYPE_AUDIO_AMR_NB
56 #else
57 MEDIA_MIMETYPE_AUDIO_AMR_WB
58 #endif
59 ) {
60 noPrivateBuffers();
61 noInputReferences();
62 noOutputReferences();
63 noInputLatency();
64 noTimeStretch();
65 setDerivedInstance(this);
66
67 addParameter(
68 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
69 .withConstValue(new C2ComponentAttributesSetting(
70 C2Component::ATTRIB_IS_TEMPORAL))
71 .build());
72
73 addParameter(
74 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
75 #ifdef AMRNB
76 .withDefault(new C2StreamSampleRateInfo::output(0u, 8000))
77 .withFields({C2F(mSampleRate, value).equalTo(8000)})
78 #else
79 .withDefault(new C2StreamSampleRateInfo::output(0u, 16000))
80 .withFields({C2F(mSampleRate, value).equalTo(16000)})
81 #endif
82 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
83 .build());
84
85 addParameter(
86 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
87 .withDefault(new C2StreamChannelCountInfo::output(0u, 1))
88 .withFields({C2F(mChannelCount, value).equalTo(1)})
89 .withSetter((Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps))
90 .build());
91
92 addParameter(
93 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
94 #ifdef AMRNB
95 .withDefault(new C2StreamBitrateInfo::input(0u, 4750))
96 .withFields({C2F(mBitrate, value).inRange(4750, 12200)})
97 #else
98 .withDefault(new C2StreamBitrateInfo::input(0u, 6600))
99 .withFields({C2F(mBitrate, value).inRange(6600, 23850)})
100 #endif
101 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
102 .build());
103
104 addParameter(
105 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
106 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 8192))
107 .build());
108 }
109
110 private:
111 std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
112 std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
113 std::shared_ptr<C2StreamBitrateInfo::input> mBitrate;
114 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
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 // Initialize output work
243 work->result = C2_OK;
244 work->workletsProcessed = 1u;
245 work->worklets.front()->output.flags = work->input.flags;
246
247 if (mSignalledError || mSignalledOutputEos) {
248 work->result = C2_BAD_VALUE;
249 return;
250 }
251
252 C2ReadView rView = mDummyReadView;
253 size_t inOffset = 0u;
254 size_t inSize = 0u;
255 if (!work->input.buffers.empty()) {
256 rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
257 inSize = rView.capacity();
258 if (inSize && rView.error()) {
259 ALOGE("read view map failed %d", rView.error());
260 work->result = rView.error();
261 return;
262 }
263 }
264
265 bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
266 if (inSize == 0) {
267 work->worklets.front()->output.flags = work->input.flags;
268 work->worklets.front()->output.buffers.clear();
269 work->worklets.front()->output.ordinal = work->input.ordinal;
270 if (eos) {
271 mSignalledOutputEos = true;
272 ALOGV("signalled EOS");
273 }
274 return;
275 }
276
277 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
278 (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
279
280 std::vector<size_t> frameSizeList;
281 if (OK != calculateNumFrames(rView.data() + inOffset, inSize, &frameSizeList,
282 mIsWide)) {
283 work->result = C2_CORRUPTED;
284 mSignalledError = true;
285 return;
286 }
287 if (frameSizeList.empty()) {
288 ALOGE("input size smaller than expected");
289 work->result = C2_CORRUPTED;
290 mSignalledError = true;
291 return;
292 }
293
294 int16_t outSamples = mIsWide ? kNumSamplesPerFrameWB : kNumSamplesPerFrameNB;
295 size_t calOutSize = outSamples * frameSizeList.size() * sizeof(int16_t);
296 std::shared_ptr<C2LinearBlock> block;
297 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
298 c2_status_t err = pool->fetchLinearBlock(calOutSize, usage, &block);
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 = block->map().get();
305 if (wView.error()) {
306 ALOGE("write view map failed %d", wView.error());
307 work->result = wView.error();
308 return;
309 }
310
311 int16_t *output = reinterpret_cast<int16_t *>(wView.data());
312 auto it = frameSizeList.begin();
313 const uint8_t *inPtr = rView.data() + inOffset;
314 size_t inPos = 0;
315 while (inPos < inSize) {
316 if (it == frameSizeList.end()) {
317 ALOGD("unexpected trailing bytes, ignoring them");
318 break;
319 }
320 uint8_t *input = const_cast<uint8_t *>(inPtr + inPos);
321 int16_t FM = ((*input >> 3) & 0x0f);
322 if (!mIsWide) {
323 int32_t numBytesRead = AMRDecode(mAmrHandle,
324 (Frame_Type_3GPP) FM,
325 input + 1, output, MIME_IETF);
326 if (static_cast<size_t>(numBytesRead + 1) != *it) {
327 ALOGE("panic, parsed size does not match decoded size");
328 work->result = C2_CORRUPTED;
329 mSignalledError = true;
330 return;
331 }
332 } else {
333 if (FM >= 9) {
334 // Produce silence instead of comfort noise and for
335 // speech lost/no data.
336 memset(output, 0, outSamples * sizeof(int16_t));
337 } else {
338 int16_t FT;
339 int16_t numRecSamples;
340
341 mime_unsorting(const_cast<uint8_t *>(&input[1]),
342 mInputSampleBuffer, &FT, &FM, 1, &mRxState);
343 pvDecoder_AmrWb(FM, mInputSampleBuffer, output, &numRecSamples,
344 mDecoderBuf, FT, mDecoderCookie);
345 if (numRecSamples != outSamples) {
346 ALOGE("Sample output per frame incorrect");
347 work->result = C2_CORRUPTED;
348 mSignalledError = true;
349 return;
350 }
351 /* Delete the 2 LSBs (14-bit output) */
352 for (int i = 0; i < numRecSamples; ++i) {
353 output[i] &= 0xfffC;
354 }
355 }
356 }
357 inPos += *it;
358 output += outSamples;
359 ++it;
360 }
361
362 work->worklets.front()->output.flags = work->input.flags;
363 work->worklets.front()->output.buffers.clear();
364 work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
365 work->worklets.front()->output.ordinal = work->input.ordinal;
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