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