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