blob: a2b6ab76a69cd9445c38132354e1b554a3f74f02 [file] [log] [blame]
/*
* Copyright (C) 2017 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "FLACDecoder"
#include <utils/Log.h>
#include "FLACDecoder.h"
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
namespace android {
// These are the corresponding callbacks with C++ calling conventions
FLAC__StreamDecoderReadStatus FLACDecoder::readCallback(
FLAC__byte buffer[], size_t *bytes) {
if (mBuffer == nullptr || mBufferLen == 0) {
*bytes = 0;
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
size_t actual = *bytes;
if (actual > mBufferDataSize - mBufferPos) {
actual = mBufferDataSize - mBufferPos;
}
memcpy(buffer, mBuffer + mBufferPos, actual);
mBufferPos += actual;
*bytes = actual;
return (actual == 0 ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
: FLAC__STREAM_DECODER_READ_STATUS_CONTINUE);
}
FLAC__StreamDecoderWriteStatus FLACDecoder::writeCallback(
const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
{
if (!mWriteRequested) {
ALOGE("writeCallback: unexpected");
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
mWriteRequested = false;
// FLAC decoder doesn't free or realloc buffer until next frame or finish
mWriteHeader = frame->header;
memmove(mWriteBuffer, buffer, sizeof(const FLAC__int32 * const) * getChannels());
mWriteCompleted = true;
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
void FLACDecoder::metadataCallback(const FLAC__StreamMetadata *metadata)
{
switch (metadata->type) {
case FLAC__METADATA_TYPE_STREAMINFO:
{
if (mStreamInfoValid) {
ALOGE("metadataCallback: unexpected STREAMINFO");
} else {
mStreamInfo = metadata->data.stream_info;
mStreamInfoValid = true;
}
break;
}
/* TODO: enable metadata parsing below.
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
{
const FLAC__StreamMetadata_VorbisComment *vc;
vc = &metadata->data.vorbis_comment;
for (FLAC__uint32 i = 0; i < vc->num_comments; ++i) {
FLAC__StreamMetadata_VorbisComment_Entry *vce;
vce = &vc->comments[i];
if (mFileMetadata != 0 && vce->entry != NULL) {
parseVorbisComment(mFileMetadata, (const char *) vce->entry,
vce->length);
}
}
break;
}
case FLAC__METADATA_TYPE_PICTURE:
{
if (mFileMetadata != 0) {
const FLAC__StreamMetadata_Picture *p = &metadata->data.picture;
mFileMetadata->setData(kKeyAlbumArt,
MetaData::TYPE_NONE, p->data, p->data_length);
mFileMetadata->setCString(kKeyAlbumArtMIME, p->mime_type);
}
break;
}
*/
default:
ALOGW("metadataCallback: unexpected type %u", metadata->type);
break;
}
}
void FLACDecoder::errorCallback(FLAC__StreamDecoderErrorStatus status)
{
ALOGE("errorCallback: status=%d", status);
mErrorStatus = status;
}
// Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved.
// These are candidates for optimization if needed.
static void copyMono8(
short *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][i] << 8;
}
}
static void copyStereo8(
short *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][i] << 8;
*dst++ = src[1][i] << 8;
}
}
static void copyMultiCh8(
short *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned nChannels) {
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
*dst++ = src[c][i] << 8;
}
}
}
static void copyMono16(
short *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][i];
}
}
static void copyStereo16(
short *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][i];
*dst++ = src[1][i];
}
}
static void copyMultiCh16(
short *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned nChannels) {
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
*dst++ = src[c][i];
}
}
}
// TODO: 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
static void copyMono24(
short *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][i] >> 8;
}
}
static void copyStereo24(
short *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][i] >> 8;
*dst++ = src[1][i] >> 8;
}
}
static void copyMultiCh24(
short *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned nChannels) {
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
*dst++ = src[c][i] >> 8;
}
}
}
// static
FLACDecoder *FLACDecoder::Create() {
FLACDecoder *decoder = new (std::nothrow) FLACDecoder();
if (decoder == NULL || decoder->init() != OK) {
delete decoder;
return NULL;
}
return decoder;
}
FLACDecoder::FLACDecoder()
: mDecoder(NULL),
mBuffer(NULL),
mBufferLen(0),
mBufferPos(0),
mBufferDataSize(0),
mStreamInfoValid(false),
mWriteRequested(false),
mWriteCompleted(false),
mErrorStatus((FLAC__StreamDecoderErrorStatus) -1),
mCopy(nullptr) {
ALOGV("ctor:");
memset(&mStreamInfo, 0, sizeof(mStreamInfo));
memset(&mWriteHeader, 0, sizeof(mWriteHeader));
memset(&mWriteBuffer, 0, sizeof(mWriteBuffer));
}
FLACDecoder::~FLACDecoder() {
ALOGV("dtor:");
if (mDecoder != NULL) {
FLAC__stream_decoder_delete(mDecoder);
mDecoder = NULL;
}
if (mBuffer != NULL) {
free(mBuffer);
}
}
status_t FLACDecoder::init() {
ALOGV("init:");
// setup libFLAC stream decoder
mDecoder = FLAC__stream_decoder_new();
if (mDecoder == NULL) {
ALOGE("init: failed to create libFLAC stream decoder");
return NO_INIT;
}
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_PICTURE);
FLAC__stream_decoder_set_metadata_respond(
mDecoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
*/
static auto read_callback =
[] (const FLAC__StreamDecoder * /* decoder */,
FLAC__byte buffer[],
size_t *bytes,
void *client_data) -> FLAC__StreamDecoderReadStatus {
return ((FLACDecoder *) client_data)->readCallback(buffer, bytes); };
static auto write_callback =
[] (const FLAC__StreamDecoder * /* decoder */,
const FLAC__Frame *frame,
const FLAC__int32 * const buffer[],
void *client_data) -> FLAC__StreamDecoderWriteStatus {
return ((FLACDecoder *) client_data)->writeCallback(frame, buffer); };
static auto metadata_callback =
[] (const FLAC__StreamDecoder * /* decoder */,
const FLAC__StreamMetadata *metadata,
void *client_data) {
((FLACDecoder *) client_data)->metadataCallback(metadata); };
static auto error_callback =
[] (const FLAC__StreamDecoder * /* decoder */,
FLAC__StreamDecoderErrorStatus status,
void *client_data) {
((FLACDecoder *) client_data)->errorCallback(status); };
FLAC__StreamDecoderInitStatus initStatus =
FLAC__stream_decoder_init_stream(
mDecoder,
read_callback,
NULL /* seek_callback */,
NULL /* tell_callback */,
NULL /* length_callback */,
NULL /* eof_callback */,
write_callback,
metadata_callback,
error_callback,
(void *)this);
if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
ALOGE("init: init_stream failed, returned %d", initStatus);
return NO_INIT;
}
return OK;
}
void FLACDecoder::flush() {
ALOGV("flush:");
mBufferPos = 0;
mBufferDataSize = 0;
mStreamInfoValid = false;
if (!FLAC__stream_decoder_reset(mDecoder)) {
ALOGE("flush: failed to reset FLAC stream decoder");
}
}
status_t FLACDecoder::parseMetadata(const uint8_t *inBuffer, size_t inBufferLen) {
ALOGV("parseMetadata: input size(%zu)", inBufferLen);
//hexdump(inBuffer, inBufferLen);
if (mStreamInfoValid) {
ALOGE("parseMetadata: already have full metadata blocks");
return ERROR_MALFORMED;
}
status_t err = addDataToBuffer(inBuffer, inBufferLen);
if (err != OK) {
ALOGE("parseMetadata: addDataToBuffer returns error %d", err);
return err;
}
if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) {
if (!FLAC__stream_decoder_reset(mDecoder)) {
ALOGE("parseMetadata: failed to reset FLAC stream decoder");
return FAILED_TRANSACTION;
}
mBufferPos = 0;
ALOGV("parseMetadata: do not have full metadata blocks yet");
return WOULD_BLOCK;
}
if (!mStreamInfoValid) {
ALOGE("parseMetadata: missing STREAMINFO");
return ERROR_MALFORMED;
}
// check block size
if (getMaxBlockSize() == 0) {
ALOGE("wrong max blocksize %u", getMaxBlockSize());
mStreamInfoValid = false;
return ERROR_MALFORMED;
}
// check channel count
if (getChannels() == 0 || getChannels() > kMaxChannels) {
ALOGE("unsupported channel count %u", getChannels());
mStreamInfoValid = false;
return ERROR_MALFORMED;
}
// check bit depth
switch (getBitsPerSample()) {
case 8:
case 16:
case 24:
break;
default:
ALOGE("parseMetadata: unsupported bits per sample %u", getBitsPerSample());
mStreamInfoValid = false;
return ERROR_MALFORMED;
}
// configure the appropriate copy function, defaulting to trespass
static const struct {
unsigned mChannels;
unsigned mBitsPerSample;
void (*mCopy)(short *dst, const int * src[kMaxChannels],
unsigned nSamples, unsigned nChannels);
} table[] = {
{ 1, 8, copyMono8 },
{ 2, 8, copyStereo8 },
{ 8, 8, copyMultiCh8 },
{ 1, 16, copyMono16 },
{ 2, 16, copyStereo16 },
{ 8, 16, copyMultiCh16 },
{ 1, 24, copyMono24 },
{ 2, 24, copyStereo24 },
{ 8, 24, copyMultiCh24 },
};
for (const auto &entry : table) {
if (entry.mChannels >= getChannels() &&
entry.mBitsPerSample == getBitsPerSample()) {
mCopy = entry.mCopy;
break;
}
}
// Now we have all metadata blocks.
mBufferPos = 0;
mBufferDataSize = 0;
return OK;
}
status_t FLACDecoder::decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
short *outBuffer, size_t *outBufferLen) {
ALOGV("decodeOneFrame: input size(%zu)", inBufferLen);
if (!mStreamInfoValid) {
ALOGW("decodeOneFrame: no streaminfo metadata block");
}
if (inBufferLen != 0) {
status_t err = addDataToBuffer(inBuffer, inBufferLen);
if (err != OK) {
ALOGW("decodeOneFrame: addDataToBuffer returns error %d", err);
return err;
}
}
mWriteRequested = true;
mWriteCompleted = false;
if (!FLAC__stream_decoder_process_single(mDecoder)) {
ALOGE("decodeOneFrame: process_single failed");
return ERROR_MALFORMED;
}
if (!mWriteCompleted) {
ALOGV("decodeOneFrame: write did not complete");
if (outBufferLen) {
*outBufferLen = 0;
}
return OK;
}
// frame header should be consistent with STREAMINFO
unsigned blocksize = mWriteHeader.blocksize;
if (blocksize == 0 || blocksize > getMaxBlockSize()) {
ALOGE("decodeOneFrame: write invalid blocksize %u", blocksize);
return ERROR_MALFORMED;
}
if (mWriteHeader.sample_rate != getSampleRate() ||
mWriteHeader.channels != getChannels() ||
mWriteHeader.bits_per_sample != getBitsPerSample()) {
ALOGE("decodeOneFrame: parameters are changed mid-stream: %d/%d/%d -> %d/%d/%d",
getSampleRate(), getChannels(), getBitsPerSample(),
mWriteHeader.sample_rate, mWriteHeader.channels, mWriteHeader.bits_per_sample);
return ERROR_MALFORMED;
}
if (mWriteHeader.number_type != FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER) {
ALOGE("decodeOneFrame: number type is %d, expected %d",
mWriteHeader.number_type, FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
return ERROR_MALFORMED;
}
size_t bufferSize = blocksize * getChannels() * sizeof(short);
if (bufferSize > *outBufferLen) {
ALOGW("decodeOneFrame: output buffer holds only partial frame %zu:%zu",
*outBufferLen, bufferSize);
blocksize = *outBufferLen / (getChannels() * sizeof(short));
bufferSize = blocksize * getChannels() * sizeof(short);
}
if (mCopy == nullptr) {
ALOGE("decodeOneFrame: format is not supported: channels(%d), BitsPerSample(%d)",
getChannels(), getBitsPerSample());
return ERROR_UNSUPPORTED;
}
// copy PCM from FLAC write buffer to output buffer, with interleaving
(*mCopy)(outBuffer, mWriteBuffer, blocksize, getChannels());
*outBufferLen = bufferSize;
return OK;
}
status_t FLACDecoder::addDataToBuffer(const uint8_t *inBuffer, size_t inBufferLen) {
// mBufferPos should be no larger than mBufferDataSize
if (inBufferLen > SIZE_MAX - (mBufferDataSize - mBufferPos)) {
ALOGE("addDataToBuffer: input buffer is too large");
return ERROR_MALFORMED;
}
if (inBufferLen > mBufferLen - mBufferDataSize) {
if (mBufferPos > 0) {
memmove(mBuffer, mBuffer + mBufferPos, mBufferDataSize - mBufferPos);
mBufferDataSize -= mBufferPos;
mBufferPos = 0;
}
if (inBufferLen > mBufferLen - mBufferDataSize) {
mBuffer = (uint8_t*)realloc(mBuffer, mBufferDataSize + inBufferLen);
if (mBuffer == nullptr) {
mBufferDataSize = 0;
mBufferLen = 0;
ALOGE("decodeOneFrame: failed to allocate memory for input buffer");
return NO_MEMORY;
}
mBufferLen = mBufferDataSize + inBufferLen;
}
}
memcpy(mBuffer + mBufferDataSize, inBuffer, inBufferLen);
mBufferDataSize += inBufferLen;
return OK;
}
} // namespace android