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