blob: 49892a4f7ac2cd6f2454ec75d8ab786c49c72c2b [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 "C2SoftFlacDec"
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 "C2SoftFlacDec.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.flac.decoder";
33
Rakesh Kumared134642019-03-12 14:18:42 +053034} // namespace
35
36class C2SoftFlacDec::IntfImpl : public SimpleInterface<void>::BaseParams {
Pawin Vongmasa36653902018-11-15 00:10:25 -080037public:
38 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
Rakesh Kumared134642019-03-12 14:18:42 +053039 : SimpleInterface<void>::BaseParams(
40 helper,
41 COMPONENT_NAME,
42 C2Component::KIND_DECODER,
43 C2Component::DOMAIN_AUDIO,
44 MEDIA_MIMETYPE_AUDIO_FLAC) {
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, 44100))
61 .withFields({C2F(mSampleRate, value).inRange(1, 655350)})
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).inRange(1, 8)})
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, 768000))
Pawin Vongmasa36653902018-11-15 00:10:25 -080075 .withFields({C2F(mBitrate, value).inRange(1, 21000000)})
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, 32768))
82 .build());
Andy Hung9ed79de2018-12-28 15:53:55 -080083
84 addParameter(
85 DefineParam(mPcmEncodingInfo, C2_PARAMKEY_PCM_ENCODING)
86 .withDefault(new C2StreamPcmEncodingInfo::output(0u, C2Config::PCM_16))
87 .withFields({C2F(mPcmEncodingInfo, value).oneOf({
88 C2Config::PCM_16,
89 // C2Config::PCM_8,
90 C2Config::PCM_FLOAT})
91 })
92 .withSetter((Setter<decltype(*mPcmEncodingInfo)>::StrictValueWithNoDeps))
93 .build());
Pawin Vongmasa36653902018-11-15 00:10:25 -080094 }
95
Andy Hung9ed79de2018-12-28 15:53:55 -080096 int32_t getPcmEncodingInfo() const { return mPcmEncodingInfo->value; }
97
Pawin Vongmasa36653902018-11-15 00:10:25 -080098private:
Pawin Vongmasa36653902018-11-15 00:10:25 -080099 std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
100 std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800101 std::shared_ptr<C2StreamBitrateInfo::input> mBitrate;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800102 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
Andy Hung9ed79de2018-12-28 15:53:55 -0800103 std::shared_ptr<C2StreamPcmEncodingInfo::output> mPcmEncodingInfo;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800104};
105
106C2SoftFlacDec::C2SoftFlacDec(
107 const char *name,
108 c2_node_id_t id,
109 const std::shared_ptr<IntfImpl> &intfImpl)
110 : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
111 mIntf(intfImpl),
112 mFLACDecoder(nullptr) {
113}
114
115C2SoftFlacDec::~C2SoftFlacDec() {
116 onRelease();
117}
118
119c2_status_t C2SoftFlacDec::onInit() {
120 status_t err = initDecoder();
121 return err == OK ? C2_OK : C2_NO_MEMORY;
122}
123
124c2_status_t C2SoftFlacDec::onStop() {
125 if (mFLACDecoder) mFLACDecoder->flush();
126 memset(&mStreamInfo, 0, sizeof(mStreamInfo));
127 mHasStreamInfo = false;
128 mSignalledError = false;
129 mSignalledOutputEos = false;
130 return C2_OK;
131}
132
133void C2SoftFlacDec::onReset() {
134 mInputBufferCount = 0;
135 (void)onStop();
136}
137
138void C2SoftFlacDec::onRelease() {
139 mInputBufferCount = 0;
140 if (mFLACDecoder) delete mFLACDecoder;
141 mFLACDecoder = nullptr;
142}
143
144c2_status_t C2SoftFlacDec::onFlush_sm() {
145 return onStop();
146}
147
148status_t C2SoftFlacDec::initDecoder() {
149 if (mFLACDecoder) {
150 delete mFLACDecoder;
151 }
152 mFLACDecoder = FLACDecoder::Create();
153 if (!mFLACDecoder) {
154 ALOGE("initDecoder: failed to create FLACDecoder");
155 mSignalledError = true;
156 return NO_MEMORY;
157 }
158
159 memset(&mStreamInfo, 0, sizeof(mStreamInfo));
160 mHasStreamInfo = false;
161 mSignalledError = false;
162 mSignalledOutputEos = false;
163 mInputBufferCount = 0;
164
165 return OK;
166}
167
168static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
169 work->worklets.front()->output.flags = work->input.flags;
170 work->worklets.front()->output.buffers.clear();
171 work->worklets.front()->output.ordinal = work->input.ordinal;
172 work->workletsProcessed = 1u;
173}
174
175// (TODO) add multiframe support, in plugin and FLACDecoder.cpp
176void C2SoftFlacDec::process(
177 const std::unique_ptr<C2Work> &work,
178 const std::shared_ptr<C2BlockPool> &pool) {
179 // Initialize output work
180 work->result = C2_OK;
181 work->workletsProcessed = 1u;
182 work->worklets.front()->output.configUpdate.clear();
183 work->worklets.front()->output.flags = work->input.flags;
184
185 if (mSignalledError || mSignalledOutputEos) {
186 work->result = C2_BAD_VALUE;
187 return;
188 }
189
190 C2ReadView rView = mDummyReadView;
191 size_t inOffset = 0u;
192 size_t inSize = 0u;
193 if (!work->input.buffers.empty()) {
194 rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
195 inSize = rView.capacity();
196 if (inSize && rView.error()) {
197 ALOGE("read view map failed %d", rView.error());
198 work->result = C2_CORRUPTED;
199 return;
200 }
201 }
202 bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
203 bool codecConfig = (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0;
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 if (inSize == 0) {
209 fillEmptyWork(work);
210 if (eos) {
211 mSignalledOutputEos = true;
212 ALOGV("signalled EOS");
213 }
214 return;
215 }
216
217 if (mInputBufferCount == 0 && !codecConfig) {
218 ALOGV("First frame has to include configuration, forcing config");
219 codecConfig = true;
220 }
221
222 uint8_t *input = const_cast<uint8_t *>(rView.data() + inOffset);
223 if (codecConfig) {
Manisha Jajooec42fa22021-04-12 18:53:36 +0530224 if (mHasStreamInfo) {
225 ALOGV("Ignore Codec Config");
226 fillEmptyWork(work);
227 return;
228 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800229 status_t decoderErr = mFLACDecoder->parseMetadata(input, inSize);
230 if (decoderErr != OK && decoderErr != WOULD_BLOCK) {
231 ALOGE("process: FLACDecoder parseMetaData returns error %d", decoderErr);
232 mSignalledError = true;
233 work->result = C2_CORRUPTED;
234 return;
235 }
236
237 mInputBufferCount++;
238 fillEmptyWork(work);
239 if (eos) {
240 mSignalledOutputEos = true;
241 ALOGV("signalled EOS");
242 }
243
244 if (decoderErr == WOULD_BLOCK) {
245 ALOGV("process: parseMetadata is Blocking, Continue %d", decoderErr);
246 } else {
247 mStreamInfo = mFLACDecoder->getStreamInfo();
248 if (mStreamInfo.sample_rate && mStreamInfo.max_blocksize &&
249 mStreamInfo.channels) {
250 mHasStreamInfo = true;
251 C2StreamSampleRateInfo::output sampleRateInfo(
252 0u, mStreamInfo.sample_rate);
253 C2StreamChannelCountInfo::output channelCountInfo(
254 0u, mStreamInfo.channels);
255 std::vector<std::unique_ptr<C2SettingResult>> failures;
256 c2_status_t err =
257 mIntf->config({&sampleRateInfo, &channelCountInfo},
258 C2_MAY_BLOCK, &failures);
259 if (err == OK) {
260 work->worklets.front()->output.configUpdate.push_back(
261 C2Param::Copy(sampleRateInfo));
262 work->worklets.front()->output.configUpdate.push_back(
263 C2Param::Copy(channelCountInfo));
264 } else {
265 ALOGE("Config Update failed");
266 mSignalledError = true;
267 work->result = C2_CORRUPTED;
268 return;
269 }
270 }
271 ALOGD("process: decoder configuration : %d Hz, %d channels, %d samples,"
272 " %d block size", mStreamInfo.sample_rate, mStreamInfo.channels,
273 (int)mStreamInfo.total_samples, mStreamInfo.max_blocksize);
274 }
275 return;
276 }
277
Andy Hung9ed79de2018-12-28 15:53:55 -0800278 const bool outputFloat = mIntf->getPcmEncodingInfo() == C2Config::PCM_FLOAT;
279 const size_t sampleSize = outputFloat ? sizeof(float) : sizeof(short);
280 size_t outSize = mHasStreamInfo ?
281 mStreamInfo.max_blocksize * mStreamInfo.channels * sampleSize
282 : kMaxBlockSize * FLACDecoder::kMaxChannels * sampleSize;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800283
284 std::shared_ptr<C2LinearBlock> block;
285 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
286 c2_status_t err = pool->fetchLinearBlock(outSize, usage, &block);
287 if (err != C2_OK) {
288 ALOGE("fetchLinearBlock for Output failed with status %d", err);
289 work->result = C2_NO_MEMORY;
290 return;
291 }
292 C2WriteView wView = block->map().get();
293 if (wView.error()) {
294 ALOGE("write view map failed %d", wView.error());
295 work->result = C2_CORRUPTED;
296 return;
297 }
298
Pawin Vongmasa36653902018-11-15 00:10:25 -0800299 status_t decoderErr = mFLACDecoder->decodeOneFrame(
Andy Hung9ed79de2018-12-28 15:53:55 -0800300 input, inSize, wView.data(), &outSize, outputFloat);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800301 if (decoderErr != OK) {
302 ALOGE("process: FLACDecoder decodeOneFrame returns error %d", decoderErr);
303 mSignalledError = true;
304 work->result = C2_CORRUPTED;
305 return;
306 }
307
308 mInputBufferCount++;
309 ALOGV("out buffer attr. size %zu", outSize);
310 work->worklets.front()->output.flags = work->input.flags;
311 work->worklets.front()->output.buffers.clear();
312 work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, 0, outSize));
313 work->worklets.front()->output.ordinal = work->input.ordinal;
314 if (eos) {
315 mSignalledOutputEos = true;
316 ALOGV("signalled EOS");
317 }
318}
319
320c2_status_t C2SoftFlacDec::drain(
321 uint32_t drainMode,
322 const std::shared_ptr<C2BlockPool> &pool) {
323 (void) pool;
324 if (drainMode == NO_DRAIN) {
325 ALOGW("drain with NO_DRAIN: no-op");
326 return C2_OK;
327 }
328 if (drainMode == DRAIN_CHAIN) {
329 ALOGW("DRAIN_CHAIN not supported");
330 return C2_OMITTED;
331 }
332
333 if (mFLACDecoder) mFLACDecoder->flush();
334
335 return C2_OK;
336}
337
338class C2SoftFlacDecFactory : public C2ComponentFactory {
339public:
340 C2SoftFlacDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
341 GetCodec2PlatformComponentStore()->getParamReflector())) {
342 }
343
344 virtual c2_status_t createComponent(
345 c2_node_id_t id,
346 std::shared_ptr<C2Component>* const component,
347 std::function<void(C2Component*)> deleter) override {
348 *component = std::shared_ptr<C2Component>(
349 new C2SoftFlacDec(COMPONENT_NAME,
350 id,
351 std::make_shared<C2SoftFlacDec::IntfImpl>(mHelper)),
352 deleter);
353 return C2_OK;
354 }
355
356 virtual c2_status_t createInterface(
357 c2_node_id_t id,
358 std::shared_ptr<C2ComponentInterface>* const interface,
359 std::function<void(C2ComponentInterface*)> deleter) override {
360 *interface = std::shared_ptr<C2ComponentInterface>(
361 new SimpleInterface<C2SoftFlacDec::IntfImpl>(
362 COMPONENT_NAME, id, std::make_shared<C2SoftFlacDec::IntfImpl>(mHelper)),
363 deleter);
364 return C2_OK;
365 }
366
367 virtual ~C2SoftFlacDecFactory() override = default;
368
369private:
370 std::shared_ptr<C2ReflectorHelper> mHelper;
371};
372
373} // namespace android
374
Cindy Zhouf6c0c3c2020-12-02 10:53:40 -0800375__attribute__((cfi_canonical_jump_table))
Pawin Vongmasa36653902018-11-15 00:10:25 -0800376extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
377 ALOGV("in %s", __func__);
378 return new ::android::C2SoftFlacDecFactory();
379}
380
Cindy Zhouf6c0c3c2020-12-02 10:53:40 -0800381__attribute__((cfi_canonical_jump_table))
Pawin Vongmasa36653902018-11-15 00:10:25 -0800382extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
383 ALOGV("in %s", __func__);
384 delete factory;
385}