Home | History | Annotate | Download | only in flac
      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 "C2SoftFlacEnc"
     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 "C2SoftFlacEnc.h"
     27 
     28 namespace android {
     29 
     30 class C2SoftFlacEnc::IntfImpl : public C2InterfaceHelper {
     31 public:
     32     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
     33         : C2InterfaceHelper(helper) {
     34         setDerivedInstance(this);
     35         addParameter(
     36                 DefineParam(mInputFormat, C2_NAME_INPUT_STREAM_FORMAT_SETTING)
     37                 .withConstValue(new C2StreamFormatConfig::input(0u, C2FormatAudio))
     38                 .build());
     39         addParameter(
     40                 DefineParam(mOutputFormat, C2_NAME_OUTPUT_STREAM_FORMAT_SETTING)
     41                 .withConstValue(new C2StreamFormatConfig::output(0u, C2FormatCompressed))
     42                 .build());
     43         addParameter(
     44                 DefineParam(mInputMediaType, C2_NAME_INPUT_PORT_MIME_SETTING)
     45                 .withConstValue(AllocSharedString<C2PortMimeConfig::input>(
     46                         MEDIA_MIMETYPE_AUDIO_RAW))
     47                 .build());
     48         addParameter(
     49                 DefineParam(mOutputMediaType, C2_NAME_OUTPUT_PORT_MIME_SETTING)
     50                 .withConstValue(AllocSharedString<C2PortMimeConfig::output>(
     51                         MEDIA_MIMETYPE_AUDIO_FLAC))
     52                 .build());
     53         addParameter(
     54                 DefineParam(mSampleRate, C2_NAME_STREAM_SAMPLE_RATE_SETTING)
     55                 .withDefault(new C2StreamSampleRateInfo::input(0u, 44100))
     56                 .withFields({C2F(mSampleRate, value).inRange(1, 655350)})
     57                 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
     58                 .build());
     59         addParameter(
     60                 DefineParam(mChannelCount, C2_NAME_STREAM_CHANNEL_COUNT_SETTING)
     61                 .withDefault(new C2StreamChannelCountInfo::input(0u, 1))
     62                 .withFields({C2F(mChannelCount, value).inRange(1, 2)})
     63                 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
     64                 .build());
     65         addParameter(
     66                 DefineParam(mBitrate, C2_NAME_STREAM_BITRATE_SETTING)
     67                 .withDefault(new C2BitrateTuning::output(0u, 768000))
     68                 .withFields({C2F(mBitrate, value).inRange(1, 21000000)})
     69                 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
     70                 .build());
     71         addParameter(
     72                 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
     73                 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 4608))
     74                 .build());
     75     }
     76 
     77     uint32_t getSampleRate() const { return mSampleRate->value; }
     78     uint32_t getChannelCount() const { return mChannelCount->value; }
     79     uint32_t getBitrate() const { return mBitrate->value; }
     80 
     81 private:
     82     std::shared_ptr<C2StreamFormatConfig::input> mInputFormat;
     83     std::shared_ptr<C2StreamFormatConfig::output> mOutputFormat;
     84     std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
     85     std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
     86     std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate;
     87     std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
     88     std::shared_ptr<C2BitrateTuning::output> mBitrate;
     89     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
     90 };
     91 constexpr char COMPONENT_NAME[] = "c2.android.flac.encoder";
     92 
     93 C2SoftFlacEnc::C2SoftFlacEnc(
     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       mFlacStreamEncoder(nullptr),
    100       mInputBufferPcm32(nullptr) {
    101 }
    102 
    103 C2SoftFlacEnc::~C2SoftFlacEnc() {
    104     onRelease();
    105 }
    106 
    107 c2_status_t C2SoftFlacEnc::onInit() {
    108     mFlacStreamEncoder = FLAC__stream_encoder_new();
    109     if (!mFlacStreamEncoder) return C2_CORRUPTED;
    110 
    111     mInputBufferPcm32 = (FLAC__int32*) malloc(
    112             kInBlockSize * kMaxNumChannels * sizeof(FLAC__int32));
    113     if (!mInputBufferPcm32) return C2_NO_MEMORY;
    114 
    115     mSignalledError = false;
    116     mSignalledOutputEos = false;
    117     mCompressionLevel = FLAC_COMPRESSION_LEVEL_DEFAULT;
    118     mIsFirstFrame = true;
    119     mAnchorTimeStamp = 0ull;
    120     mProcessedSamples = 0u;
    121     mEncoderWriteData = false;
    122     mEncoderReturnedNbBytes = 0;
    123     mHeaderOffset = 0;
    124     mWroteHeader = false;
    125 
    126     status_t err = configureEncoder();
    127     return err == OK ? C2_OK : C2_CORRUPTED;
    128 }
    129 
    130 void C2SoftFlacEnc::onRelease() {
    131     if (mFlacStreamEncoder) {
    132         FLAC__stream_encoder_delete(mFlacStreamEncoder);
    133         mFlacStreamEncoder = nullptr;
    134     }
    135 
    136     if (mInputBufferPcm32) {
    137         free(mInputBufferPcm32);
    138         mInputBufferPcm32 = nullptr;
    139     }
    140 }
    141 
    142 void C2SoftFlacEnc::onReset() {
    143     mCompressionLevel = FLAC_COMPRESSION_LEVEL_DEFAULT;
    144     (void) onStop();
    145 }
    146 
    147 c2_status_t C2SoftFlacEnc::onStop() {
    148     mSignalledError = false;
    149     mSignalledOutputEos = false;
    150     mIsFirstFrame = true;
    151     mAnchorTimeStamp = 0ull;
    152     mProcessedSamples = 0u;
    153     mEncoderWriteData = false;
    154     mEncoderReturnedNbBytes = 0;
    155     mHeaderOffset = 0;
    156     mWroteHeader = false;
    157 
    158     c2_status_t status = drain(DRAIN_COMPONENT_NO_EOS, nullptr);
    159     if (C2_OK != status) return status;
    160 
    161     status_t err = configureEncoder();
    162     if (err != OK) mSignalledError = true;
    163     return C2_OK;
    164 }
    165 
    166 c2_status_t C2SoftFlacEnc::onFlush_sm() {
    167     return onStop();
    168 }
    169 
    170 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
    171     work->worklets.front()->output.flags = work->input.flags;
    172     work->worklets.front()->output.buffers.clear();
    173     work->worklets.front()->output.ordinal = work->input.ordinal;
    174 }
    175 
    176 void C2SoftFlacEnc::process(
    177         const std::unique_ptr<C2Work> &work,
    178         const std::shared_ptr<C2BlockPool> &pool) {
    179     work->result = C2_OK;
    180     work->workletsProcessed = 1u;
    181     if (mSignalledError || mSignalledOutputEos) {
    182         work->result = C2_BAD_VALUE;
    183         return;
    184     }
    185 
    186     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
    187     C2ReadView rView = mDummyReadView;
    188     size_t inOffset = 0u;
    189     size_t inSize = 0u;
    190     if (!work->input.buffers.empty()) {
    191         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
    192         inSize = rView.capacity();
    193         if (inSize && rView.error()) {
    194             ALOGE("read view map failed %d", rView.error());
    195             work->result = C2_CORRUPTED;
    196             return;
    197         }
    198     }
    199 
    200     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
    201               inSize, (int)work->input.ordinal.timestamp.peeku(),
    202               (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
    203     if (mIsFirstFrame && inSize) {
    204         mAnchorTimeStamp = work->input.ordinal.timestamp.peekull();
    205         mIsFirstFrame = false;
    206     }
    207 
    208     if (!mWroteHeader) {
    209         std::unique_ptr<C2StreamCsdInfo::output> csd =
    210             C2StreamCsdInfo::output::AllocUnique(mHeaderOffset, 0u);
    211         // TODO: check NO_MEMORY
    212         memcpy(csd->m.value, mHeader, mHeaderOffset);
    213         ALOGV("put csd, %d bytes", mHeaderOffset);
    214 
    215         work->worklets.front()->output.configUpdate.push_back(std::move(csd));
    216         mWroteHeader = true;
    217     }
    218 
    219     uint32_t sampleRate = mIntf->getSampleRate();
    220     uint32_t channelCount = mIntf->getChannelCount();
    221     uint64_t outTimeStamp = mProcessedSamples * 1000000ll / sampleRate;
    222 
    223     size_t outCapacity = inSize;
    224     outCapacity += mBlockSize * channelCount * sizeof(int16_t);
    225 
    226     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
    227     c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &mOutputBlock);
    228     if (err != C2_OK) {
    229         ALOGE("fetchLinearBlock for Output failed with status %d", err);
    230         work->result = C2_NO_MEMORY;
    231         return;
    232     }
    233     C2WriteView wView = mOutputBlock->map().get();
    234     if (wView.error()) {
    235         ALOGE("write view map failed %d", wView.error());
    236         work->result = C2_CORRUPTED;
    237         return;
    238     }
    239 
    240     mEncoderWriteData = true;
    241     mEncoderReturnedNbBytes = 0;
    242     size_t inPos = 0;
    243     while (inPos < inSize) {
    244         const uint8_t *inPtr = rView.data() + inOffset;
    245         size_t processSize = MIN(kInBlockSize * channelCount * sizeof(int16_t), (inSize - inPos));
    246         const unsigned nbInputFrames = processSize / (channelCount * sizeof(int16_t));
    247         const unsigned nbInputSamples = processSize / sizeof(int16_t);
    248         const int16_t *pcm16 = reinterpret_cast<const int16_t *>(inPtr + inPos);
    249         ALOGV("about to encode %zu bytes", processSize);
    250 
    251         for (unsigned i = 0; i < nbInputSamples; i++) {
    252             mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
    253         }
    254 
    255         FLAC__bool ok = FLAC__stream_encoder_process_interleaved(
    256                 mFlacStreamEncoder, mInputBufferPcm32, nbInputFrames);
    257         if (!ok) {
    258             ALOGE("error encountered during encoding");
    259             mSignalledError = true;
    260             work->result = C2_CORRUPTED;
    261             mOutputBlock.reset();
    262             return;
    263         }
    264         inPos += processSize;
    265     }
    266     if (eos && (C2_OK != drain(DRAIN_COMPONENT_WITH_EOS, pool))) {
    267         ALOGE("error encountered during encoding");
    268         mSignalledError = true;
    269         work->result = C2_CORRUPTED;
    270         mOutputBlock.reset();
    271         return;
    272     }
    273     fillEmptyWork(work);
    274     if (mEncoderReturnedNbBytes != 0) {
    275         std::shared_ptr<C2Buffer> buffer = createLinearBuffer(std::move(mOutputBlock), 0, mEncoderReturnedNbBytes);
    276         work->worklets.front()->output.buffers.push_back(buffer);
    277         work->worklets.front()->output.ordinal.timestamp = mAnchorTimeStamp + outTimeStamp;
    278     } else {
    279         ALOGV("encoder process_interleaved returned without data to write");
    280     }
    281     mOutputBlock = nullptr;
    282     if (eos) {
    283         mSignalledOutputEos = true;
    284         ALOGV("signalled EOS");
    285     }
    286     mEncoderWriteData = false;
    287     mEncoderReturnedNbBytes = 0;
    288 }
    289 
    290 FLAC__StreamEncoderWriteStatus C2SoftFlacEnc::onEncodedFlacAvailable(
    291         const FLAC__byte buffer[], size_t bytes, unsigned samples,
    292         unsigned current_frame) {
    293     (void) current_frame;
    294     ALOGV("%s (bytes=%zu, samples=%u, curr_frame=%u)", __func__, bytes, samples,
    295           current_frame);
    296 
    297     if (samples == 0) {
    298         ALOGI("saving %zu bytes of header", bytes);
    299         memcpy(mHeader + mHeaderOffset, buffer, bytes);
    300         mHeaderOffset += bytes;// will contain header size when finished receiving header
    301         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    302     }
    303 
    304     if ((samples == 0) || !mEncoderWriteData) {
    305         // called by the encoder because there's header data to save, but it's not the role
    306         // of this component (unless WRITE_FLAC_HEADER_IN_FIRST_BUFFER is defined)
    307         ALOGV("ignoring %zu bytes of header data (samples=%d)", bytes, samples);
    308         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    309     }
    310 
    311     // write encoded data
    312     C2WriteView wView = mOutputBlock->map().get();
    313     uint8_t* outData = wView.data();
    314     ALOGV("writing %zu bytes of encoded data on output", bytes);
    315     // increment mProcessedSamples to maintain audio synchronization during
    316     // play back
    317     mProcessedSamples += samples;
    318     if (bytes + mEncoderReturnedNbBytes > mOutputBlock->capacity()) {
    319         ALOGE("not enough space left to write encoded data, dropping %zu bytes", bytes);
    320         // a fatal error would stop the encoding
    321         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    322     }
    323     memcpy(outData + mEncoderReturnedNbBytes, buffer, bytes);
    324     mEncoderReturnedNbBytes += bytes;
    325     return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    326 }
    327 
    328 
    329 status_t C2SoftFlacEnc::configureEncoder() {
    330     ALOGV("%s numChannel=%d, sampleRate=%d", __func__, mIntf->getChannelCount(), mIntf->getSampleRate());
    331 
    332     if (mSignalledError || !mFlacStreamEncoder) {
    333         ALOGE("can't configure encoder: no encoder or invalid state");
    334         return UNKNOWN_ERROR;
    335     }
    336 
    337     FLAC__bool ok = true;
    338     ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mIntf->getChannelCount());
    339     ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mIntf->getSampleRate());
    340     ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, 16);
    341     ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder, mCompressionLevel);
    342     ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
    343     if (!ok) {
    344         ALOGE("unknown error when configuring encoder");
    345         return UNKNOWN_ERROR;
    346     }
    347 
    348     ok &= FLAC__STREAM_ENCODER_INIT_STATUS_OK ==
    349             FLAC__stream_encoder_init_stream(mFlacStreamEncoder,
    350                     flacEncoderWriteCallback    /*write_callback*/,
    351                     nullptr /*seek_callback*/,
    352                     nullptr /*tell_callback*/,
    353                     nullptr /*metadata_callback*/,
    354                     (void *) this /*client_data*/);
    355 
    356     if (!ok) {
    357         ALOGE("unknown error when configuring encoder");
    358         return UNKNOWN_ERROR;
    359     }
    360 
    361     mBlockSize = FLAC__stream_encoder_get_blocksize(mFlacStreamEncoder);
    362 
    363     ALOGV("encoder successfully configured");
    364     return OK;
    365 }
    366 
    367 FLAC__StreamEncoderWriteStatus C2SoftFlacEnc::flacEncoderWriteCallback(
    368             const FLAC__StreamEncoder *,
    369             const FLAC__byte buffer[],
    370             size_t bytes,
    371             unsigned samples,
    372             unsigned current_frame,
    373             void *client_data) {
    374     return ((C2SoftFlacEnc*) client_data)->onEncodedFlacAvailable(
    375             buffer, bytes, samples, current_frame);
    376 }
    377 
    378 c2_status_t C2SoftFlacEnc::drain(
    379         uint32_t drainMode,
    380         const std::shared_ptr<C2BlockPool> &pool) {
    381     (void) pool;
    382     switch (drainMode) {
    383         case NO_DRAIN:
    384             ALOGW("drain with NO_DRAIN: no-op");
    385             return C2_OK;
    386         case DRAIN_CHAIN:
    387             ALOGW("DRAIN_CHAIN not supported");
    388             return C2_OMITTED;
    389         case DRAIN_COMPONENT_WITH_EOS:
    390             // TODO: This flag is not being sent back to the client
    391             // because there are no items in PendingWork queue as all the
    392             // inputs are being sent back with emptywork or valid encoded data
    393             // mSignalledOutputEos = true;
    394         case DRAIN_COMPONENT_NO_EOS:
    395             break;
    396         default:
    397             return C2_BAD_VALUE;
    398     }
    399     FLAC__bool ok = FLAC__stream_encoder_finish(mFlacStreamEncoder);
    400     if (!ok) return C2_CORRUPTED;
    401     mIsFirstFrame = true;
    402     mAnchorTimeStamp = 0ull;
    403     mProcessedSamples = 0u;
    404 
    405     return C2_OK;
    406 }
    407 
    408 class C2SoftFlacEncFactory : public C2ComponentFactory {
    409 public:
    410     C2SoftFlacEncFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
    411             GetCodec2PlatformComponentStore()->getParamReflector())) {
    412     }
    413 
    414     virtual c2_status_t createComponent(
    415             c2_node_id_t id,
    416             std::shared_ptr<C2Component>* const component,
    417             std::function<void(C2Component*)> deleter) override {
    418         *component = std::shared_ptr<C2Component>(
    419                 new C2SoftFlacEnc(COMPONENT_NAME,
    420                                   id,
    421                                   std::make_shared<C2SoftFlacEnc::IntfImpl>(mHelper)),
    422                 deleter);
    423         return C2_OK;
    424     }
    425 
    426     virtual c2_status_t createInterface(
    427             c2_node_id_t id,
    428             std::shared_ptr<C2ComponentInterface>* const interface,
    429             std::function<void(C2ComponentInterface*)> deleter) override {
    430         *interface = std::shared_ptr<C2ComponentInterface>(
    431                 new SimpleInterface<C2SoftFlacEnc::IntfImpl>(
    432                         COMPONENT_NAME, id, std::make_shared<C2SoftFlacEnc::IntfImpl>(mHelper)),
    433                 deleter);
    434         return C2_OK;
    435     }
    436 
    437     virtual ~C2SoftFlacEncFactory() override = default;
    438 private:
    439     std::shared_ptr<C2ReflectorHelper> mHelper;
    440 };
    441 
    442 }  // namespace android
    443 
    444 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
    445     ALOGV("in %s", __func__);
    446     return new ::android::C2SoftFlacEncFactory();
    447 }
    448 
    449 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
    450     ALOGV("in %s", __func__);
    451     delete factory;
    452 }
    453