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