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