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:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)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
C2SoftG711Dec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)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
~C2SoftG711Dec()109 C2SoftG711Dec::~C2SoftG711Dec() {
110 onRelease();
111 }
112
onInit()113 c2_status_t C2SoftG711Dec::onInit() {
114 mSignalledOutputEos = false;
115 return C2_OK;
116 }
117
onStop()118 c2_status_t C2SoftG711Dec::onStop() {
119 mSignalledOutputEos = false;
120 return C2_OK;
121 }
122
onReset()123 void C2SoftG711Dec::onReset() {
124 (void)onStop();
125 }
126
onRelease()127 void C2SoftG711Dec::onRelease() {
128 }
129
onFlush_sm()130 c2_status_t C2SoftG711Dec::onFlush_sm() {
131 return onStop();
132 }
133
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)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
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)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
DecodeALaw(int16_t * out,const uint8_t * in,size_t inSize)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
DecodeMLaw(int16_t * out,const uint8_t * in,size_t inSize)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:
C2SoftG711DecFactory()275 C2SoftG711DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
276 GetCodec2PlatformComponentStore()->getParamReflector())) {
277 }
278
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)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
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)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
CreateCodec2Factory()308 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
309 ALOGV("in %s", __func__);
310 return new ::android::C2SoftG711DecFactory();
311 }
312
DestroyCodec2Factory(::C2ComponentFactory * factory)313 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
314 ALOGV("in %s", __func__);
315 delete factory;
316 }
317