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 "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
28 namespace android {
29
30 namespace {
31
32 constexpr char COMPONENT_NAME[] = "c2.android.flac.decoder";
33
34 } // namespace
35
36 class C2SoftFlacDec::IntfImpl : public SimpleInterface<void>::BaseParams {
37 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)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_FLAC) {
45 noPrivateBuffers();
46 noInputReferences();
47 noOutputReferences();
48 noInputLatency();
49 noTimeStretch();
50 setDerivedInstance(this);
51
52 addParameter(
53 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
54 .withConstValue(new C2ComponentAttributesSetting(
55 C2Component::ATTRIB_IS_TEMPORAL))
56 .build());
57
58 addParameter(
59 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
60 .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(
66 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
67 .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(
73 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
74 .withDefault(new C2StreamBitrateInfo::input(0u, 768000))
75 .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());
83
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());
94 }
95
getPcmEncodingInfo() const96 int32_t getPcmEncodingInfo() const { return mPcmEncodingInfo->value; }
97
98 private:
99 std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
100 std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
101 std::shared_ptr<C2StreamBitrateInfo::input> mBitrate;
102 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
103 std::shared_ptr<C2StreamPcmEncodingInfo::output> mPcmEncodingInfo;
104 };
105
C2SoftFlacDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)106 C2SoftFlacDec::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
C2SoftFlacDec(const char * name,c2_node_id_t id,const std::shared_ptr<C2ReflectorHelper> & helper)115 C2SoftFlacDec::C2SoftFlacDec(
116 const char *name,
117 c2_node_id_t id,
118 const std::shared_ptr<C2ReflectorHelper> &helper)
119 : C2SoftFlacDec(name, id, std::make_shared<IntfImpl>(helper)) {
120 }
121
~C2SoftFlacDec()122 C2SoftFlacDec::~C2SoftFlacDec() {
123 onRelease();
124 }
125
onInit()126 c2_status_t C2SoftFlacDec::onInit() {
127 status_t err = initDecoder();
128 return err == OK ? C2_OK : C2_NO_MEMORY;
129 }
130
onStop()131 c2_status_t C2SoftFlacDec::onStop() {
132 if (mFLACDecoder) mFLACDecoder->flush();
133 memset(&mStreamInfo, 0, sizeof(mStreamInfo));
134 mHasStreamInfo = false;
135 mSignalledError = false;
136 mSignalledOutputEos = false;
137 return C2_OK;
138 }
139
onReset()140 void C2SoftFlacDec::onReset() {
141 mInputBufferCount = 0;
142 (void)onStop();
143 }
144
onRelease()145 void C2SoftFlacDec::onRelease() {
146 mInputBufferCount = 0;
147 if (mFLACDecoder) delete mFLACDecoder;
148 mFLACDecoder = nullptr;
149 }
150
onFlush_sm()151 c2_status_t C2SoftFlacDec::onFlush_sm() {
152 return onStop();
153 }
154
initDecoder()155 status_t C2SoftFlacDec::initDecoder() {
156 if (mFLACDecoder) {
157 delete mFLACDecoder;
158 }
159 mFLACDecoder = FLACDecoder::Create();
160 if (!mFLACDecoder) {
161 ALOGE("initDecoder: failed to create FLACDecoder");
162 mSignalledError = true;
163 return NO_MEMORY;
164 }
165
166 memset(&mStreamInfo, 0, sizeof(mStreamInfo));
167 mHasStreamInfo = false;
168 mSignalledError = false;
169 mSignalledOutputEos = false;
170 mInputBufferCount = 0;
171
172 return OK;
173 }
174
fillEmptyWork(const std::unique_ptr<C2Work> & work)175 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
176 work->worklets.front()->output.flags = work->input.flags;
177 work->worklets.front()->output.buffers.clear();
178 work->worklets.front()->output.ordinal = work->input.ordinal;
179 work->workletsProcessed = 1u;
180 }
181
182 // (TODO) add multiframe support, in plugin and FLACDecoder.cpp
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)183 void C2SoftFlacDec::process(
184 const std::unique_ptr<C2Work> &work,
185 const std::shared_ptr<C2BlockPool> &pool) {
186 // Initialize output work
187 work->result = C2_OK;
188 work->workletsProcessed = 1u;
189 work->worklets.front()->output.configUpdate.clear();
190 work->worklets.front()->output.flags = work->input.flags;
191
192 if (mSignalledError || mSignalledOutputEos) {
193 work->result = C2_BAD_VALUE;
194 return;
195 }
196
197 C2ReadView rView = mDummyReadView;
198 size_t inOffset = 0u;
199 size_t inSize = 0u;
200 if (!work->input.buffers.empty()) {
201 rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
202 inSize = rView.capacity();
203 if (inSize && rView.error()) {
204 ALOGE("read view map failed %d", rView.error());
205 work->result = C2_CORRUPTED;
206 return;
207 }
208 }
209 bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
210 bool codecConfig = (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0;
211
212 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
213 (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
214
215 if (inSize == 0) {
216 fillEmptyWork(work);
217 if (eos) {
218 mSignalledOutputEos = true;
219 ALOGV("signalled EOS");
220 }
221 return;
222 }
223
224 if (mInputBufferCount == 0 && !codecConfig) {
225 ALOGV("First frame has to include configuration, forcing config");
226 codecConfig = true;
227 }
228
229 uint8_t *input = const_cast<uint8_t *>(rView.data() + inOffset);
230 if (codecConfig) {
231 if (mHasStreamInfo) {
232 ALOGV("Ignore Codec Config");
233 fillEmptyWork(work);
234 return;
235 }
236 status_t decoderErr = mFLACDecoder->parseMetadata(input, inSize);
237 if (decoderErr != OK && decoderErr != WOULD_BLOCK) {
238 ALOGE("process: FLACDecoder parseMetaData returns error %d", decoderErr);
239 mSignalledError = true;
240 work->result = C2_CORRUPTED;
241 return;
242 }
243
244 mInputBufferCount++;
245 fillEmptyWork(work);
246 if (eos) {
247 mSignalledOutputEos = true;
248 ALOGV("signalled EOS");
249 }
250
251 if (decoderErr == WOULD_BLOCK) {
252 ALOGV("process: parseMetadata is Blocking, Continue %d", decoderErr);
253 } else {
254 mStreamInfo = mFLACDecoder->getStreamInfo();
255 if (mStreamInfo.sample_rate && mStreamInfo.max_blocksize &&
256 mStreamInfo.channels) {
257 mHasStreamInfo = true;
258 C2StreamSampleRateInfo::output sampleRateInfo(
259 0u, mStreamInfo.sample_rate);
260 C2StreamChannelCountInfo::output channelCountInfo(
261 0u, mStreamInfo.channels);
262 std::vector<std::unique_ptr<C2SettingResult>> failures;
263 c2_status_t err =
264 mIntf->config({&sampleRateInfo, &channelCountInfo},
265 C2_MAY_BLOCK, &failures);
266 if (err == OK) {
267 work->worklets.front()->output.configUpdate.push_back(
268 C2Param::Copy(sampleRateInfo));
269 work->worklets.front()->output.configUpdate.push_back(
270 C2Param::Copy(channelCountInfo));
271 } else {
272 ALOGE("Config Update failed");
273 mSignalledError = true;
274 work->result = C2_CORRUPTED;
275 return;
276 }
277 }
278 ALOGD("process: decoder configuration : %d Hz, %d channels, %d samples,"
279 " %d block size", mStreamInfo.sample_rate, mStreamInfo.channels,
280 (int)mStreamInfo.total_samples, mStreamInfo.max_blocksize);
281 }
282 return;
283 }
284
285 const bool outputFloat = mIntf->getPcmEncodingInfo() == C2Config::PCM_FLOAT;
286 const size_t sampleSize = outputFloat ? sizeof(float) : sizeof(short);
287 size_t outSize = mHasStreamInfo ?
288 mStreamInfo.max_blocksize * mStreamInfo.channels * sampleSize
289 : kMaxBlockSize * FLACDecoder::kMaxChannels * sampleSize;
290
291 std::shared_ptr<C2LinearBlock> block;
292 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
293 c2_status_t err = pool->fetchLinearBlock(outSize, usage, &block);
294 if (err != C2_OK) {
295 ALOGE("fetchLinearBlock for Output failed with status %d", err);
296 work->result = C2_NO_MEMORY;
297 return;
298 }
299 C2WriteView wView = block->map().get();
300 if (wView.error()) {
301 ALOGE("write view map failed %d", wView.error());
302 work->result = C2_CORRUPTED;
303 return;
304 }
305
306 status_t decoderErr = mFLACDecoder->decodeOneFrame(
307 input, inSize, wView.data(), &outSize, outputFloat);
308 if (decoderErr != OK) {
309 ALOGE("process: FLACDecoder decodeOneFrame returns error %d", decoderErr);
310 mSignalledError = true;
311 work->result = C2_CORRUPTED;
312 return;
313 }
314
315 mInputBufferCount++;
316 ALOGV("out buffer attr. size %zu", outSize);
317 work->worklets.front()->output.flags = work->input.flags;
318 work->worklets.front()->output.buffers.clear();
319 work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, 0, outSize));
320 work->worklets.front()->output.ordinal = work->input.ordinal;
321 if (eos) {
322 mSignalledOutputEos = true;
323 ALOGV("signalled EOS");
324 }
325 }
326
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)327 c2_status_t C2SoftFlacDec::drain(
328 uint32_t drainMode,
329 const std::shared_ptr<C2BlockPool> &pool) {
330 (void) pool;
331 if (drainMode == NO_DRAIN) {
332 ALOGW("drain with NO_DRAIN: no-op");
333 return C2_OK;
334 }
335 if (drainMode == DRAIN_CHAIN) {
336 ALOGW("DRAIN_CHAIN not supported");
337 return C2_OMITTED;
338 }
339
340 if (mFLACDecoder) mFLACDecoder->flush();
341
342 return C2_OK;
343 }
344
345 class C2SoftFlacDecFactory : public C2ComponentFactory {
346 public:
C2SoftFlacDecFactory()347 C2SoftFlacDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
348 GetCodec2PlatformComponentStore()->getParamReflector())) {
349 }
350
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)351 virtual c2_status_t createComponent(
352 c2_node_id_t id,
353 std::shared_ptr<C2Component>* const component,
354 std::function<void(C2Component*)> deleter) override {
355 *component = std::shared_ptr<C2Component>(
356 new C2SoftFlacDec(COMPONENT_NAME,
357 id,
358 std::make_shared<C2SoftFlacDec::IntfImpl>(mHelper)),
359 deleter);
360 return C2_OK;
361 }
362
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)363 virtual c2_status_t createInterface(
364 c2_node_id_t id,
365 std::shared_ptr<C2ComponentInterface>* const interface,
366 std::function<void(C2ComponentInterface*)> deleter) override {
367 *interface = std::shared_ptr<C2ComponentInterface>(
368 new SimpleInterface<C2SoftFlacDec::IntfImpl>(
369 COMPONENT_NAME, id, std::make_shared<C2SoftFlacDec::IntfImpl>(mHelper)),
370 deleter);
371 return C2_OK;
372 }
373
374 virtual ~C2SoftFlacDecFactory() override = default;
375
376 private:
377 std::shared_ptr<C2ReflectorHelper> mHelper;
378 };
379
380 } // namespace android
381
382 __attribute__((cfi_canonical_jump_table))
CreateCodec2Factory()383 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
384 ALOGV("in %s", __func__);
385 return new ::android::C2SoftFlacDecFactory();
386 }
387
388 __attribute__((cfi_canonical_jump_table))
DestroyCodec2Factory(::C2ComponentFactory * factory)389 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
390 ALOGV("in %s", __func__);
391 delete factory;
392 }
393