blob: 86b16e8a649986290e1ab848697cf314146cb9c9 [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
30constexpr char COMPONENT_NAME[] = "c2.android.flac.decoder";
31
32class C2SoftFlacDec::IntfImpl : public C2InterfaceHelper {
33public:
34 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
35 : C2InterfaceHelper(helper) {
36
37 setDerivedInstance(this);
38
39 addParameter(
40 DefineParam(mInputFormat, C2_NAME_INPUT_STREAM_FORMAT_SETTING)
41 .withConstValue(new C2StreamFormatConfig::input(0u, C2FormatCompressed))
42 .build());
43
44 addParameter(
45 DefineParam(mOutputFormat, C2_NAME_OUTPUT_STREAM_FORMAT_SETTING)
46 .withConstValue(new C2StreamFormatConfig::output(0u, C2FormatAudio))
47 .build());
48
49 addParameter(
50 DefineParam(mInputMediaType, C2_NAME_INPUT_PORT_MIME_SETTING)
51 .withConstValue(AllocSharedString<C2PortMimeConfig::input>(
52 MEDIA_MIMETYPE_AUDIO_FLAC))
53 .build());
54
55 addParameter(
56 DefineParam(mOutputMediaType, C2_NAME_OUTPUT_PORT_MIME_SETTING)
57 .withConstValue(AllocSharedString<C2PortMimeConfig::output>(
58 MEDIA_MIMETYPE_AUDIO_RAW))
59 .build());
60
61 addParameter(
62 DefineParam(mSampleRate, C2_NAME_STREAM_SAMPLE_RATE_SETTING)
63 .withDefault(new C2StreamSampleRateInfo::output(0u, 44100))
64 .withFields({C2F(mSampleRate, value).inRange(1, 655350)})
65 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
66 .build());
67
68 addParameter(
69 DefineParam(mChannelCount, C2_NAME_STREAM_CHANNEL_COUNT_SETTING)
70 .withDefault(new C2StreamChannelCountInfo::output(0u, 1))
71 .withFields({C2F(mChannelCount, value).inRange(1, 8)})
72 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
73 .build());
74
75 addParameter(
76 DefineParam(mBitrate, C2_NAME_STREAM_BITRATE_SETTING)
77 .withDefault(new C2BitrateTuning::input(0u, 768000))
78 .withFields({C2F(mBitrate, value).inRange(1, 21000000)})
79 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
80 .build());
81
82 addParameter(
83 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
84 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 32768))
85 .build());
Andy Hung9ed79de2018-12-28 15:53:55 -080086
87 addParameter(
88 DefineParam(mPcmEncodingInfo, C2_PARAMKEY_PCM_ENCODING)
89 .withDefault(new C2StreamPcmEncodingInfo::output(0u, C2Config::PCM_16))
90 .withFields({C2F(mPcmEncodingInfo, value).oneOf({
91 C2Config::PCM_16,
92 // C2Config::PCM_8,
93 C2Config::PCM_FLOAT})
94 })
95 .withSetter((Setter<decltype(*mPcmEncodingInfo)>::StrictValueWithNoDeps))
96 .build());
Pawin Vongmasa36653902018-11-15 00:10:25 -080097 }
98
Andy Hung9ed79de2018-12-28 15:53:55 -080099 int32_t getPcmEncodingInfo() const { return mPcmEncodingInfo->value; }
100
Pawin Vongmasa36653902018-11-15 00:10:25 -0800101private:
102 std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
103 std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
104 std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
105 std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
106 std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
107 std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
108 std::shared_ptr<C2BitrateTuning::input> mBitrate;
109 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
Andy Hung9ed79de2018-12-28 15:53:55 -0800110 std::shared_ptr<C2StreamPcmEncodingInfo::output> mPcmEncodingInfo;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800111};
112
113C2SoftFlacDec::C2SoftFlacDec(
114 const char *name,
115 c2_node_id_t id,
116 const std::shared_ptr<IntfImpl> &intfImpl)
117 : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
118 mIntf(intfImpl),
119 mFLACDecoder(nullptr) {
120}
121
122C2SoftFlacDec::~C2SoftFlacDec() {
123 onRelease();
124}
125
126c2_status_t C2SoftFlacDec::onInit() {
127 status_t err = initDecoder();
128 return err == OK ? C2_OK : C2_NO_MEMORY;
129}
130
131c2_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
140void C2SoftFlacDec::onReset() {
141 mInputBufferCount = 0;
142 (void)onStop();
143}
144
145void C2SoftFlacDec::onRelease() {
146 mInputBufferCount = 0;
147 if (mFLACDecoder) delete mFLACDecoder;
148 mFLACDecoder = nullptr;
149}
150
151c2_status_t C2SoftFlacDec::onFlush_sm() {
152 return onStop();
153}
154
155status_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
175static 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
183void 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 status_t decoderErr = mFLACDecoder->parseMetadata(input, inSize);
232 if (decoderErr != OK && decoderErr != WOULD_BLOCK) {
233 ALOGE("process: FLACDecoder parseMetaData returns error %d", decoderErr);
234 mSignalledError = true;
235 work->result = C2_CORRUPTED;
236 return;
237 }
238
239 mInputBufferCount++;
240 fillEmptyWork(work);
241 if (eos) {
242 mSignalledOutputEos = true;
243 ALOGV("signalled EOS");
244 }
245
246 if (decoderErr == WOULD_BLOCK) {
247 ALOGV("process: parseMetadata is Blocking, Continue %d", decoderErr);
248 } else {
249 mStreamInfo = mFLACDecoder->getStreamInfo();
250 if (mStreamInfo.sample_rate && mStreamInfo.max_blocksize &&
251 mStreamInfo.channels) {
252 mHasStreamInfo = true;
253 C2StreamSampleRateInfo::output sampleRateInfo(
254 0u, mStreamInfo.sample_rate);
255 C2StreamChannelCountInfo::output channelCountInfo(
256 0u, mStreamInfo.channels);
257 std::vector<std::unique_ptr<C2SettingResult>> failures;
258 c2_status_t err =
259 mIntf->config({&sampleRateInfo, &channelCountInfo},
260 C2_MAY_BLOCK, &failures);
261 if (err == OK) {
262 work->worklets.front()->output.configUpdate.push_back(
263 C2Param::Copy(sampleRateInfo));
264 work->worklets.front()->output.configUpdate.push_back(
265 C2Param::Copy(channelCountInfo));
266 } else {
267 ALOGE("Config Update failed");
268 mSignalledError = true;
269 work->result = C2_CORRUPTED;
270 return;
271 }
272 }
273 ALOGD("process: decoder configuration : %d Hz, %d channels, %d samples,"
274 " %d block size", mStreamInfo.sample_rate, mStreamInfo.channels,
275 (int)mStreamInfo.total_samples, mStreamInfo.max_blocksize);
276 }
277 return;
278 }
279
Andy Hung9ed79de2018-12-28 15:53:55 -0800280 const bool outputFloat = mIntf->getPcmEncodingInfo() == C2Config::PCM_FLOAT;
281 const size_t sampleSize = outputFloat ? sizeof(float) : sizeof(short);
282 size_t outSize = mHasStreamInfo ?
283 mStreamInfo.max_blocksize * mStreamInfo.channels * sampleSize
284 : kMaxBlockSize * FLACDecoder::kMaxChannels * sampleSize;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800285
286 std::shared_ptr<C2LinearBlock> block;
287 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
288 c2_status_t err = pool->fetchLinearBlock(outSize, usage, &block);
289 if (err != C2_OK) {
290 ALOGE("fetchLinearBlock for Output failed with status %d", err);
291 work->result = C2_NO_MEMORY;
292 return;
293 }
294 C2WriteView wView = block->map().get();
295 if (wView.error()) {
296 ALOGE("write view map failed %d", wView.error());
297 work->result = C2_CORRUPTED;
298 return;
299 }
300
Pawin Vongmasa36653902018-11-15 00:10:25 -0800301 status_t decoderErr = mFLACDecoder->decodeOneFrame(
Andy Hung9ed79de2018-12-28 15:53:55 -0800302 input, inSize, wView.data(), &outSize, outputFloat);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800303 if (decoderErr != OK) {
304 ALOGE("process: FLACDecoder decodeOneFrame returns error %d", decoderErr);
305 mSignalledError = true;
306 work->result = C2_CORRUPTED;
307 return;
308 }
309
310 mInputBufferCount++;
311 ALOGV("out buffer attr. size %zu", outSize);
312 work->worklets.front()->output.flags = work->input.flags;
313 work->worklets.front()->output.buffers.clear();
314 work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, 0, outSize));
315 work->worklets.front()->output.ordinal = work->input.ordinal;
316 if (eos) {
317 mSignalledOutputEos = true;
318 ALOGV("signalled EOS");
319 }
320}
321
322c2_status_t C2SoftFlacDec::drain(
323 uint32_t drainMode,
324 const std::shared_ptr<C2BlockPool> &pool) {
325 (void) pool;
326 if (drainMode == NO_DRAIN) {
327 ALOGW("drain with NO_DRAIN: no-op");
328 return C2_OK;
329 }
330 if (drainMode == DRAIN_CHAIN) {
331 ALOGW("DRAIN_CHAIN not supported");
332 return C2_OMITTED;
333 }
334
335 if (mFLACDecoder) mFLACDecoder->flush();
336
337 return C2_OK;
338}
339
340class C2SoftFlacDecFactory : public C2ComponentFactory {
341public:
342 C2SoftFlacDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
343 GetCodec2PlatformComponentStore()->getParamReflector())) {
344 }
345
346 virtual c2_status_t createComponent(
347 c2_node_id_t id,
348 std::shared_ptr<C2Component>* const component,
349 std::function<void(C2Component*)> deleter) override {
350 *component = std::shared_ptr<C2Component>(
351 new C2SoftFlacDec(COMPONENT_NAME,
352 id,
353 std::make_shared<C2SoftFlacDec::IntfImpl>(mHelper)),
354 deleter);
355 return C2_OK;
356 }
357
358 virtual c2_status_t createInterface(
359 c2_node_id_t id,
360 std::shared_ptr<C2ComponentInterface>* const interface,
361 std::function<void(C2ComponentInterface*)> deleter) override {
362 *interface = std::shared_ptr<C2ComponentInterface>(
363 new SimpleInterface<C2SoftFlacDec::IntfImpl>(
364 COMPONENT_NAME, id, std::make_shared<C2SoftFlacDec::IntfImpl>(mHelper)),
365 deleter);
366 return C2_OK;
367 }
368
369 virtual ~C2SoftFlacDecFactory() override = default;
370
371private:
372 std::shared_ptr<C2ReflectorHelper> mHelper;
373};
374
375} // namespace android
376
377extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
378 ALOGV("in %s", __func__);
379 return new ::android::C2SoftFlacDecFactory();
380}
381
382extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
383 ALOGV("in %s", __func__);
384 delete factory;
385}