text: /*
   * Copyright (C) 2016 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  #ifndef FLAC_PARSER_H_
  #define FLAC_PARSER_H_
  
  #include <stdint.h>
  
  #include <array>
  #include <cstdlib>
  #include <string>
  #include <vector>
  
  // libFLAC parser
  #include "FLAC/stream_decoder.h"
  
  #include "include/data_source.h"
  
  typedef int status_t;
  
  struct FlacPicture {
    int type;
    std::string mimeType;
    std::string description;
    FLAC__uint32 width;
    FLAC__uint32 height;
    FLAC__uint32 depth;
    FLAC__uint32 colors;
    std::vector<char> data;
  };
  
  class FLACParser {
   public:
    FLACParser(DataSource *source);
    ~FLACParser();
  
    bool init();
  
    // stream properties
    unsigned getMaxBlockSize() const { return mStreamInfo.max_blocksize; }
    unsigned getSampleRate() const { return mStreamInfo.sample_rate; }
    unsigned getChannels() const { return mStreamInfo.channels; }
    unsigned getBitsPerSample() const { return mStreamInfo.bits_per_sample; }
    FLAC__uint64 getTotalSamples() const { return mStreamInfo.total_samples; }
  
    const FLAC__StreamMetadata_StreamInfo& getStreamInfo() const {
      return mStreamInfo;
    }
  
    bool areVorbisCommentsValid() const { return mVorbisCommentsValid; }
  
    const std::vector<std::string>& getVorbisComments() const {
      return mVorbisComments;
    }
  
    bool arePicturesValid() const { return mPicturesValid; }
  
    const std::vector<FlacPicture> &getPictures() const { return mPictures; }
  
    int64_t getLastFrameTimestamp() const {
      return (1000000LL * mWriteHeader.number.sample_number) / getSampleRate();
    }
  
    int64_t getLastFrameFirstSampleIndex() const {
      return mWriteHeader.number.sample_number;
    }
  
    int64_t getNextFrameFirstSampleIndex() const {
      return mWriteHeader.number.sample_number + mWriteHeader.blocksize;
    }
  
    bool decodeMetadata();
    size_t readBuffer(void *output, size_t output_size);
  
    bool getSeekPositions(int64_t timeUs, std::array<int64_t, 4> &result);
  
    void flush() {
      reset(mCurrentPos);
    }
  
    void reset(int64_t newPosition) {
      if (mDecoder != NULL) {
        mCurrentPos = newPosition;
        mEOF = false;
        if (newPosition == 0) {
          mStreamInfoValid = false;
          mVorbisCommentsValid = false;
          mPicturesValid = false;
          mVorbisComments.clear();
          mPictures.clear();
          FLAC__stream_decoder_reset(mDecoder);
        } else {
          FLAC__stream_decoder_flush(mDecoder);
        }
      }
    }
  
    int64_t getDecodePosition() {
      uint64_t position;
      if (mDecoder != NULL
          && FLAC__stream_decoder_get_decode_position(mDecoder, &position)) {
        return position;
      }
      return -1;
    }
  
    const char *getDecoderStateString() {
      return FLAC__stream_decoder_get_resolved_state_string(mDecoder);
    }
  
    bool isDecoderAtEndOfStream() const {
      return FLAC__stream_decoder_get_state(mDecoder) ==
             FLAC__STREAM_DECODER_END_OF_STREAM;
    }
  
   private:
    DataSource *mDataSource;
  
    void (*mCopy)(int8_t *dst, const int *const *src, unsigned bytesPerSample,
                  unsigned nSamples, unsigned nChannels);
  
    // handle to underlying libFLAC parser
    FLAC__StreamDecoder *mDecoder;
  
    // current position within the data source
    off64_t mCurrentPos;
    bool mEOF;
  
    // cached when the STREAMINFO metadata is parsed by libFLAC
    FLAC__StreamMetadata_StreamInfo mStreamInfo;
    bool mStreamInfoValid;
  
    const FLAC__StreamMetadata_SeekTable *mSeekTable;
    uint64_t firstFrameOffset;
  
    // cached when the VORBIS_COMMENT metadata is parsed by libFLAC
    std::vector<std::string> mVorbisComments;
    bool mVorbisCommentsValid;
  
    // cached when the PICTURE metadata is parsed by libFLAC
    std::vector<FlacPicture> mPictures;
    bool mPicturesValid;
  
    // cached when a decoded PCM block is "written" by libFLAC parser
    bool mWriteRequested;
    bool mWriteCompleted;
    FLAC__FrameHeader mWriteHeader;
    const FLAC__int32 *const *mWriteBuffer;
  
    // most recent error reported by libFLAC parser
    FLAC__StreamDecoderErrorStatus mErrorStatus;
  
    // no copy constructor or assignment
    FLACParser(const FLACParser &);
    FLACParser &operator=(const FLACParser &);
  
    // FLAC parser callbacks as C++ instance methods
    FLAC__StreamDecoderReadStatus readCallback(FLAC__byte buffer[],
                                               size_t *bytes);
    FLAC__StreamDecoderSeekStatus seekCallback(FLAC__uint64 absolute_byte_offset);
    FLAC__StreamDecoderTellStatus tellCallback(
        FLAC__uint64 *absolute_byte_offset);
    FLAC__StreamDecoderLengthStatus lengthCallback(FLAC__uint64 *stream_length);
    FLAC__bool eofCallback();
    FLAC__StreamDecoderWriteStatus writeCallback(
        const FLAC__Frame *frame, const FLAC__int32 *const buffer[]);
    void metadataCallback(const FLAC__StreamMetadata *metadata);
    void errorCallback(FLAC__StreamDecoderErrorStatus status);
  
    // FLAC parser callbacks as C-callable functions
    static FLAC__StreamDecoderReadStatus read_callback(
        const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes,
        void *client_data);
    static FLAC__StreamDecoderSeekStatus seek_callback(
        const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset,
        void *client_data);
    static FLAC__StreamDecoderTellStatus tell_callback(
        const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset,
        void *client_data);
    static FLAC__StreamDecoderLengthStatus length_callback(
        const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length,
        void *client_data);
    static FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder,
                                   void *client_data);
    static FLAC__StreamDecoderWriteStatus write_callback(
        const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
        const FLAC__int32 *const buffer[], void *client_data);
    static void metadata_callback(const FLAC__StreamDecoder *decoder,
                                  const FLAC__StreamMetadata *metadata,
                                  void *client_data);
    static void error_callback(const FLAC__StreamDecoder *decoder,
                               FLAC__StreamDecoderErrorStatus status,
                               void *client_data);
  };
  
  #endif  // FLAC_PARSER_H_
  