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