/* * 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. */ #include "include/flac_parser.h" #include #include #include #include #include #define LOG_TAG "FLACParser" #define ALOGE(...) \ ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) #define ALOGV(...) \ ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) #define LOG_ALWAYS_FATAL(...) \ (__android_log_assert(NULL, LOG_TAG, ##__VA_ARGS__)) #define LITERAL_TO_STRING_INTERNAL(x) #x #define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x) #define TRESPASS() \ LOG_ALWAYS_FATAL(__FILE__ \ ":" LITERAL_TO_STRING(__LINE__) " Should not be here."); #define CHECK(x) \ if (!(x)) ALOGE("Check failed: %s ", #x) const int endian = 1; #define isBigEndian() (*(reinterpret_cast(&endian)) == 0) // The FLAC parser calls our C++ static callbacks using C calling conventions, // inside FLAC__stream_decoder_process_until_end_of_metadata // and FLAC__stream_decoder_process_single. // We immediately then call our corresponding C++ instance methods // with the same parameter list, but discard redundant information. FLAC__StreamDecoderReadStatus FLACParser::read_callback( const FLAC__StreamDecoder * /* decoder */, FLAC__byte buffer[], size_t *bytes, void *client_data) { return reinterpret_cast(client_data) ->readCallback(buffer, bytes); } FLAC__StreamDecoderSeekStatus FLACParser::seek_callback( const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 absolute_byte_offset, void *client_data) { return reinterpret_cast(client_data) ->seekCallback(absolute_byte_offset); } FLAC__StreamDecoderTellStatus FLACParser::tell_callback( const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 *absolute_byte_offset, void *client_data) { return reinterpret_cast(client_data) ->tellCallback(absolute_byte_offset); } FLAC__StreamDecoderLengthStatus FLACParser::length_callback( const FLAC__StreamDecoder * /* decoder */, FLAC__uint64 *stream_length, void *client_data) { return reinterpret_cast(client_data) ->lengthCallback(stream_length); } FLAC__bool FLACParser::eof_callback(const FLAC__StreamDecoder * /* decoder */, void *client_data) { return reinterpret_cast(client_data)->eofCallback(); } FLAC__StreamDecoderWriteStatus FLACParser::write_callback( const FLAC__StreamDecoder * /* decoder */, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) { return reinterpret_cast(client_data) ->writeCallback(frame, buffer); } void FLACParser::metadata_callback(const FLAC__StreamDecoder * /* decoder */, const FLAC__StreamMetadata *metadata, void *client_data) { reinterpret_cast(client_data)->metadataCallback(metadata); } void FLACParser::error_callback(const FLAC__StreamDecoder * /* decoder */, FLAC__StreamDecoderErrorStatus status, void *client_data) { reinterpret_cast(client_data)->errorCallback(status); } // These are the corresponding callbacks with C++ calling conventions FLAC__StreamDecoderReadStatus FLACParser::readCallback(FLAC__byte buffer[], size_t *bytes) { size_t requested = *bytes; ssize_t actual = mDataSource->readAt(mCurrentPos, buffer, requested); if (0 > actual) { *bytes = 0; return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } else if (0 == actual) { *bytes = 0; mEOF = true; return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; } else { assert(actual <= requested); *bytes = actual; mCurrentPos += actual; return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } } FLAC__StreamDecoderSeekStatus FLACParser::seekCallback( FLAC__uint64 absolute_byte_offset) { mCurrentPos = absolute_byte_offset; mEOF = false; return FLAC__STREAM_DECODER_SEEK_STATUS_OK; } FLAC__StreamDecoderTellStatus FLACParser::tellCallback( FLAC__uint64 *absolute_byte_offset) { *absolute_byte_offset = mCurrentPos; return FLAC__STREAM_DECODER_TELL_STATUS_OK; } FLAC__StreamDecoderLengthStatus FLACParser::lengthCallback( FLAC__uint64 *stream_length) { return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; } FLAC__bool FLACParser::eofCallback() { return mEOF; } FLAC__StreamDecoderWriteStatus FLACParser::writeCallback( const FLAC__Frame *frame, const FLAC__int32 *const buffer[]) { if (mWriteRequested) { mWriteRequested = false; // FLAC parser doesn't free or realloc buffer until next frame or finish mWriteHeader = frame->header; mWriteBuffer = buffer; mWriteCompleted = true; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } else { ALOGE("FLACParser::writeCallback unexpected"); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } } void FLACParser::metadataCallback(const FLAC__StreamMetadata *metadata) { switch (metadata->type) { case FLAC__METADATA_TYPE_STREAMINFO: if (!mStreamInfoValid) { mStreamInfo = metadata->data.stream_info; mStreamInfoValid = true; } else { ALOGE("FLACParser::metadataCallback unexpected STREAMINFO"); } break; case FLAC__METADATA_TYPE_SEEKTABLE: mSeekTable = &metadata->data.seek_table; break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: if (!mVorbisCommentsValid) { FLAC__StreamMetadata_VorbisComment vorbisComment = metadata->data.vorbis_comment; for (FLAC__uint32 i = 0; i < vorbisComment.num_comments; ++i) { FLAC__StreamMetadata_VorbisComment_Entry vorbisCommentEntry = vorbisComment.comments[i]; if (vorbisCommentEntry.entry != NULL) { std::string comment( reinterpret_cast(vorbisCommentEntry.entry), vorbisCommentEntry.length); mVorbisComments.push_back(comment); } } mVorbisCommentsValid = true; } else { ALOGE("FLACParser::metadataCallback unexpected VORBISCOMMENT"); } break; case FLAC__METADATA_TYPE_PICTURE: { const FLAC__StreamMetadata_Picture *parsedPicture = &metadata->data.picture; FlacPicture picture; picture.mimeType.assign(std::string(parsedPicture->mime_type)); picture.description.assign( std::string((char *)parsedPicture->description)); picture.data.assign(parsedPicture->data, parsedPicture->data + parsedPicture->data_length); picture.width = parsedPicture->width; picture.height = parsedPicture->height; picture.depth = parsedPicture->depth; picture.colors = parsedPicture->colors; picture.type = parsedPicture->type; mPictures.push_back(picture); mPicturesValid = true; break; } default: ALOGE("FLACParser::metadataCallback unexpected type %u", metadata->type); break; } } void FLACParser::errorCallback(FLAC__StreamDecoderErrorStatus status) { ALOGE("FLACParser::errorCallback status=%d", status); mErrorStatus = status; } // Copy samples from FLAC native 32-bit non-interleaved to // correct bit-depth (non-zero padded), interleaved. // These are candidates for optimization if needed. static void copyToByteArrayBigEndian(int8_t *dst, const int *const *src, unsigned bytesPerSample, unsigned nSamples, unsigned nChannels) { for (unsigned i = 0; i < nSamples; ++i) { for (unsigned c = 0; c < nChannels; ++c) { // point to the first byte of the source address // and then skip the first few bytes (most significant bytes) // depending on the bit depth const int8_t *byteSrc = reinterpret_cast(&src[c][i]) + 4 - bytesPerSample; memcpy(dst, byteSrc, bytesPerSample); dst = dst + bytesPerSample; } } } static void copyToByteArrayLittleEndian(int8_t *dst, const int *const *src, unsigned bytesPerSample, unsigned nSamples, unsigned nChannels) { for (unsigned i = 0; i < nSamples; ++i) { for (unsigned c = 0; c < nChannels; ++c) { // with little endian, the most significant bytes will be at the end // copy the bytes in little endian will remove the most significant byte // so we are good here. memcpy(dst, &(src[c][i]), bytesPerSample); dst = dst + bytesPerSample; } } } static void copyTrespass(int8_t * /* dst */, const int *const * /* src */, unsigned /* bytesPerSample */, unsigned /* nSamples */, unsigned /* nChannels */) { TRESPASS(); } // FLACParser FLACParser::FLACParser(DataSource *source) : mDataSource(source), mCopy(copyTrespass), mDecoder(NULL), mCurrentPos(0LL), mEOF(false), mStreamInfoValid(false), mSeekTable(NULL), firstFrameOffset(0LL), mVorbisCommentsValid(false), mPicturesValid(false), mWriteRequested(false), mWriteCompleted(false), mWriteBuffer(NULL), mErrorStatus((FLAC__StreamDecoderErrorStatus)-1) { ALOGV("FLACParser::FLACParser"); memset(&mStreamInfo, 0, sizeof(mStreamInfo)); memset(&mWriteHeader, 0, sizeof(mWriteHeader)); } FLACParser::~FLACParser() { ALOGV("FLACParser::~FLACParser"); if (mDecoder != NULL) { FLAC__stream_decoder_delete(mDecoder); mDecoder = NULL; } } bool FLACParser::init() { // setup libFLAC parser mDecoder = FLAC__stream_decoder_new(); if (mDecoder == NULL) { // The new should succeed, since probably all it does is a malloc // that always succeeds in Android. But to avoid dependence on the // libFLAC internals, we check and log here. ALOGE("new failed"); return false; } FLAC__stream_decoder_set_md5_checking(mDecoder, false); FLAC__stream_decoder_set_metadata_ignore_all(mDecoder); FLAC__stream_decoder_set_metadata_respond(mDecoder, FLAC__METADATA_TYPE_STREAMINFO); FLAC__stream_decoder_set_metadata_respond(mDecoder, FLAC__METADATA_TYPE_SEEKTABLE); FLAC__stream_decoder_set_metadata_respond(mDecoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); FLAC__stream_decoder_set_metadata_respond(mDecoder, FLAC__METADATA_TYPE_PICTURE); FLAC__StreamDecoderInitStatus initStatus; initStatus = FLAC__stream_decoder_init_stream( mDecoder, read_callback, seek_callback, tell_callback, length_callback, eof_callback, write_callback, metadata_callback, error_callback, reinterpret_cast(this)); if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) { // A failure here probably indicates a programming error and so is // unlikely to happen. But we check and log here similarly to above. ALOGE("init_stream failed %d", initStatus); return false; } return true; } bool FLACParser::decodeMetadata() { // parse all metadata if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) { ALOGE("metadata decoding failed"); return false; } // store first frame offset FLAC__stream_decoder_get_decode_position(mDecoder, &firstFrameOffset); if (mStreamInfoValid) { // check channel count if (getChannels() == 0 || getChannels() > 8) { ALOGE("unsupported channel count %u", getChannels()); return false; } // check bit depth switch (getBitsPerSample()) { case 8: case 16: case 24: case 32: break; default: ALOGE("unsupported bits per sample %u", getBitsPerSample()); return false; } // configure the appropriate copy function based on device endianness. if (isBigEndian()) { mCopy = copyToByteArrayBigEndian; } else { mCopy = copyToByteArrayLittleEndian; } } else { ALOGE("missing STREAMINFO"); return false; } return true; } size_t FLACParser::readBuffer(void *output, size_t output_size) { mWriteRequested = true; mWriteCompleted = false; if (!FLAC__stream_decoder_process_single(mDecoder)) { ALOGE("FLACParser::readBuffer process_single failed. Status: %s", getDecoderStateString()); return -1; } if (!mWriteCompleted) { if (FLAC__stream_decoder_get_state(mDecoder) != FLAC__STREAM_DECODER_END_OF_STREAM) { ALOGE("FLACParser::readBuffer write did not complete. Status: %s", getDecoderStateString()); } return -1; } // verify that block header keeps the promises made by STREAMINFO unsigned blocksize = mWriteHeader.blocksize; if (blocksize == 0 || blocksize > getMaxBlockSize()) { ALOGE("FLACParser::readBuffer write invalid blocksize %u", blocksize); return -1; } if (mWriteHeader.sample_rate != getSampleRate() || mWriteHeader.channels != getChannels() || mWriteHeader.bits_per_sample != getBitsPerSample()) { ALOGE( "FLACParser::readBuffer write changed parameters mid-stream: %d/%d/%d " "-> %d/%d/%d", getSampleRate(), getChannels(), getBitsPerSample(), mWriteHeader.sample_rate, mWriteHeader.channels, mWriteHeader.bits_per_sample); return -1; } unsigned bytesPerSample = getBitsPerSample() >> 3; size_t bufferSize = blocksize * getChannels() * bytesPerSample; if (bufferSize > output_size) { ALOGE( "FLACParser::readBuffer not enough space in output buffer " "%zu < %zu", output_size, bufferSize); return -1; } // copy PCM from FLAC write buffer to our media buffer, with interleaving. (*mCopy)(reinterpret_cast(output), mWriteBuffer, bytesPerSample, blocksize, getChannels()); // fill in buffer metadata CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); return bufferSize; } bool FLACParser::getSeekPositions(int64_t timeUs, std::array &result) { if (!mSeekTable) { return false; } unsigned sampleRate = getSampleRate(); int64_t totalSamples = getTotalSamples(); int64_t targetSampleNumber = (timeUs * sampleRate) / 1000000LL; if (targetSampleNumber >= totalSamples) { targetSampleNumber = totalSamples - 1; } FLAC__StreamMetadata_SeekPoint *points = mSeekTable->points; unsigned length = mSeekTable->num_points; for (unsigned i = length; i != 0; i--) { int64_t sampleNumber = points[i - 1].sample_number; if (sampleNumber == -1) { // placeholder continue; } if (sampleNumber <= targetSampleNumber) { result[0] = (sampleNumber * 1000000LL) / sampleRate; result[1] = firstFrameOffset + points[i - 1].stream_offset; if (sampleNumber == targetSampleNumber || i >= length || points[i].sample_number == -1) { // placeholder // exact seek, or no following non-placeholder seek point result[2] = result[0]; result[3] = result[1]; } else { result[2] = (points[i].sample_number * 1000000LL) / sampleRate; result[3] = firstFrameOffset + points[i].stream_offset; } return true; } } result[0] = 0; result[1] = firstFrameOffset; result[2] = 0; result[3] = firstFrameOffset; return true; }