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 #define LOG_TAG "C2SoftG711Dec"
19 #include <log/log.h>
20 
21 #include <media/stagefright/foundation/MediaDefs.h>
22 
23 #include <C2PlatformSupport.h>
24 #include <SimpleC2Interface.h>
25 
26 #include "C2SoftG711Dec.h"
27 
28 namespace android {
29 
30 #ifdef ALAW
31 constexpr char COMPONENT_NAME[] = "c2.android.g711.alaw.decoder";
32 #else
33 constexpr char COMPONENT_NAME[] = "c2.android.g711.mlaw.decoder";
34 #endif
35 
36 class C2SoftG711Dec::IntfImpl : public C2InterfaceHelper {
37 public:
38     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
39         : C2InterfaceHelper(helper) {
40 
41         setDerivedInstance(this);
42 
43         addParameter(
44                 DefineParam(mInputFormat, C2_NAME_INPUT_STREAM_FORMAT_SETTING)
45                 .withConstValue(new C2StreamFormatConfig::input(0u, C2FormatCompressed))
46                 .build());
47 
48         addParameter(
49                 DefineParam(mOutputFormat, C2_NAME_OUTPUT_STREAM_FORMAT_SETTING)
50                 .withConstValue(new C2StreamFormatConfig::output(0u, C2FormatAudio))
51                 .build());
52 
53         addParameter(
54                 DefineParam(mInputMediaType, C2_NAME_INPUT_PORT_MIME_SETTING)
55                 .withConstValue(AllocSharedString<C2PortMimeConfig::input>(
56 #ifdef ALAW
57                         MEDIA_MIMETYPE_AUDIO_G711_ALAW
58 #else
59                         MEDIA_MIMETYPE_AUDIO_G711_MLAW
60 #endif
61                 )).build());
62 
63         addParameter(
64                 DefineParam(mOutputMediaType, C2_NAME_OUTPUT_PORT_MIME_SETTING)
65                 .withConstValue(AllocSharedString<C2PortMimeConfig::output>(
66                         MEDIA_MIMETYPE_AUDIO_RAW))
67                 .build());
68 
69         addParameter(
70                 DefineParam(mSampleRate, C2_NAME_STREAM_SAMPLE_RATE_SETTING)
71                 .withDefault(new C2StreamSampleRateInfo::output(0u, 8000))
72                 .withFields({C2F(mSampleRate, value).inRange(8000, 48000)})
73                 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
74                 .build());
75 
76         addParameter(
77                 DefineParam(mChannelCount, C2_NAME_STREAM_CHANNEL_COUNT_SETTING)
78                 .withDefault(new C2StreamChannelCountInfo::output(0u, 1))
79                 .withFields({C2F(mChannelCount, value).equalTo(1)})
80                 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
81                 .build());
82 
83         addParameter(
84                 DefineParam(mBitrate, C2_NAME_STREAM_BITRATE_SETTING)
85                 .withDefault(new C2BitrateTuning::input(0u, 64000))
86                 .withFields({C2F(mBitrate, value).equalTo(64000)})
87                 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
88                 .build());
89     }
90 
91 private:
92     std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
93     std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
94     std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
95     std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
96     std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
97     std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
98     std::shared_ptr<C2BitrateTuning::input> mBitrate;
99 };
100 
101 C2SoftG711Dec::C2SoftG711Dec(
102         const char *name,
103         c2_node_id_t id,
104         const std::shared_ptr<IntfImpl> &intfImpl)
105     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
106       mIntf(intfImpl) {
107 }
108 
109 C2SoftG711Dec::~C2SoftG711Dec() {
110     onRelease();
111 }
112 
113 c2_status_t C2SoftG711Dec::onInit() {
114     mSignalledOutputEos = false;
115     return C2_OK;
116 }
117 
118 c2_status_t C2SoftG711Dec::onStop() {
119     mSignalledOutputEos = false;
120     return C2_OK;
121 }
122 
123 void C2SoftG711Dec::onReset() {
124     (void)onStop();
125 }
126 
127 void C2SoftG711Dec::onRelease() {
128 }
129 
130 c2_status_t C2SoftG711Dec::onFlush_sm() {
131     return onStop();
132 }
133 
134 void C2SoftG711Dec::process(
135         const std::unique_ptr<C2Work> &work,
136         const std::shared_ptr<C2BlockPool> &pool) {
137     work->result = C2_OK;
138     work->workletsProcessed = 0u;
139     if (mSignalledOutputEos) {
140         work->result = C2_BAD_VALUE;
141         return;
142     }
143 
144     C2ReadView rView = mDummyReadView;
145     size_t inOffset = 0u;
146     size_t inSize = 0u;
147     if (!work->input.buffers.empty()) {
148         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
149         inSize = rView.capacity();
150         if (inSize && rView.error()) {
151             ALOGE("read view map failed %d", rView.error());
152             work->result = C2_CORRUPTED;
153             return;
154         }
155     }
156     bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
157     int outSize = inSize * sizeof(int16_t);
158 
159     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
160           (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
161 
162     if (inSize == 0) {
163         work->worklets.front()->output.flags = work->input.flags;
164         work->worklets.front()->output.buffers.clear();
165         work->worklets.front()->output.ordinal = work->input.ordinal;
166         work->workletsProcessed = 1u;
167         if (eos) {
168             mSignalledOutputEos = true;
169             ALOGV("signalled EOS");
170         }
171         return;
172     }
173 
174     uint8_t *inputptr = const_cast<uint8_t *>(rView.data() + inOffset);
175 
176     std::shared_ptr<C2LinearBlock> block;
177     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
178     c2_status_t err = pool->fetchLinearBlock(outSize, usage, &block);
179     if (err != C2_OK) {
180         ALOGE("fetchLinearBlock for Output failed with status %d", err);
181         work->result = C2_NO_MEMORY;
182         return;
183     }
184     C2WriteView wView = block->map().get();
185     if (wView.error()) {
186         ALOGE("write view map failed %d", wView.error());
187         work->result = C2_CORRUPTED;
188         return;
189     }
190     int16_t *outputptr = reinterpret_cast<int16_t *>(wView.data());
191 
192 #ifdef ALAW
193     DecodeALaw(outputptr, inputptr, inSize);
194 #else
195     DecodeMLaw(outputptr, inputptr, inSize);
196 #endif
197 
198     work->worklets.front()->output.flags = work->input.flags;
199     work->worklets.front()->output.buffers.clear();
200     work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
201     work->worklets.front()->output.ordinal = work->input.ordinal;
202     work->workletsProcessed = 1u;
203 
204     if (eos) {
205         mSignalledOutputEos = true;
206         ALOGV("signalled EOS");
207     }
208 }
209 
210 c2_status_t C2SoftG711Dec::drain(
211         uint32_t drainMode,
212         const std::shared_ptr<C2BlockPool> &pool) {
213     (void) pool;
214     if (drainMode == NO_DRAIN) {
215         ALOGW("drain with NO_DRAIN: no-op");
216         return C2_OK;
217     }
218     if (drainMode == DRAIN_CHAIN) {
219         ALOGW("DRAIN_CHAIN not supported");
220         return C2_OMITTED;
221     }
222 
223     return C2_OK;
224 }
225 
226 #ifdef ALAW
227 void C2SoftG711Dec::DecodeALaw(
228         int16_t *out, const uint8_t *in, size_t inSize) {
229     while (inSize > 0) {
230         inSize--;
231         int32_t x = *in++;
232 
233         int32_t ix = x ^ 0x55;
234         ix &= 0x7f;
235 
236         int32_t iexp = ix >> 4;
237         int32_t mant = ix & 0x0f;
238 
239         if (iexp > 0) {
240             mant += 16;
241         }
242 
243         mant = (mant << 4) + 8;
244 
245         if (iexp > 1) {
246             mant = mant << (iexp - 1);
247         }
248 
249         *out++ = (x > 127) ? mant : -mant;
250     }
251 }
252 #else
253 void C2SoftG711Dec::DecodeMLaw(
254         int16_t *out, const uint8_t *in, size_t inSize) {
255     while (inSize > 0) {
256         inSize--;
257         int32_t x = *in++;
258 
259         int32_t mantissa = ~x;
260         int32_t exponent = (mantissa >> 4) & 7;
261         int32_t segment = exponent + 1;
262         mantissa &= 0x0f;
263 
264         int32_t step = 4 << segment;
265 
266         int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
267 
268         *out++ = (x < 0x80) ? -abs : abs;
269     }
270 }
271 #endif
272 
273 class C2SoftG711DecFactory : public C2ComponentFactory {
274 public:
275     C2SoftG711DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
276             GetCodec2PlatformComponentStore()->getParamReflector())) {
277     }
278 
279     virtual c2_status_t createComponent(
280             c2_node_id_t id,
281             std::shared_ptr<C2Component>* const component,
282             std::function<void(C2Component*)> deleter) override {
283         *component = std::shared_ptr<C2Component>(
284                 new C2SoftG711Dec(COMPONENT_NAME, id,
285                                std::make_shared<C2SoftG711Dec::IntfImpl>(mHelper)),
286                 deleter);
287         return C2_OK;
288     }
289 
290     virtual c2_status_t createInterface(
291             c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
292             std::function<void(C2ComponentInterface*)> deleter) override {
293         *interface = std::shared_ptr<C2ComponentInterface>(
294                 new SimpleInterface<C2SoftG711Dec::IntfImpl>(
295                         COMPONENT_NAME, id, std::make_shared<C2SoftG711Dec::IntfImpl>(mHelper)),
296                 deleter);
297         return C2_OK;
298     }
299 
300     virtual ~C2SoftG711DecFactory() override = default;
301 
302 private:
303     std::shared_ptr<C2ReflectorHelper> mHelper;
304 };
305 
306 }  // namespace android
307 
308 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
309     ALOGV("in %s", __func__);
310     return new ::android::C2SoftG711DecFactory();
311 }
312 
313 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
314     ALOGV("in %s", __func__);
315     delete factory;
316 }
317