Remove the resampling to 16bit step from FlacDecoder.

Currently FlacDecoder/FlacExtractor always perform resampling to 16bit. In some
case (with 24bit audio), this might lower the audio quality if the system
supports 24bit audio.
Since AudioTrack implementation supports resampling, we will remove the
resampling step, and return an output with the same bits-per-sample as the original stream.
User can choose to re-sample to 16bit in AudioTrack if necessary.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=167494350
This commit is contained in:
hoangtc 2017-09-04 06:55:07 -07:00 committed by Oliver Woodman
parent bab2ce817e
commit 0d86f4475c
5 changed files with 57 additions and 95 deletions

View File

@ -38,7 +38,7 @@ NDK_PATH="<path to Android NDK>"
```
cd "${FLAC_EXT_PATH}/jni" && \
curl http://downloads.xiph.org/releases/flac/flac-1.3.1.tar.xz | tar xJ && \
curl https://ftp.osuosl.org/pub/xiph/releases/flac/flac-1.3.1.tar.xz | tar xJ && \
mv flac-1.3.1 flac
```

View File

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.ext.flac;
import static com.google.android.exoplayer2.util.Util.getPcmEncoding;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.extractor.Extractor;
@ -122,10 +124,20 @@ public final class FlacExtractor implements Extractor {
}
});
Format mediaFormat = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_RAW, null,
streamInfo.bitRate(), Format.NO_VALUE, streamInfo.channels, streamInfo.sampleRate,
C.ENCODING_PCM_16BIT, null, null, 0, null);
Format mediaFormat =
Format.createAudioSampleFormat(
null,
MimeTypes.AUDIO_RAW,
null,
streamInfo.bitRate(),
Format.NO_VALUE,
streamInfo.channels,
streamInfo.sampleRate,
getPcmEncoding(streamInfo.bitsPerSample),
null,
null,
0,
null);
trackOutput.format(mediaFormat);
outputBuffer = new ParsableByteArray(streamInfo.maxDecodedFrameSize());

View File

@ -42,6 +42,9 @@
#define CHECK(x) \
if (!(x)) ALOGE("Check failed: %s ", #x)
const int endian = 1;
#define isBigEndian() (*(reinterpret_cast<const char *>(&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.
@ -180,85 +183,42 @@ void FLACParser::errorCallback(FLAC__StreamDecoderErrorStatus status) {
mErrorStatus = status;
}
// Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved.
// 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 copyMono8(int16_t *dst, const int *const *src, unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][i] << 8;
}
}
static void copyStereo8(int16_t *dst, const int *const *src, unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][i] << 8;
*dst++ = src[1][i] << 8;
}
}
static void copyMultiCh8(int16_t *dst, const int *const *src, unsigned nSamples,
unsigned nChannels) {
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) {
*dst++ = src[c][i] << 8;
// 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<const int8_t *>(&src[c][i]) + 4 - bytesPerSample;
memcpy(dst, byteSrc, bytesPerSample);
dst = dst + bytesPerSample;
}
}
}
static void copyMono16(int16_t *dst, const int *const *src, unsigned nSamples,
unsigned /* nChannels */) {
static void copyToByteArrayLittleEndian(int8_t *dst, const int *const *src,
unsigned bytesPerSample,
unsigned nSamples, unsigned nChannels) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][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 copyStereo16(int16_t *dst, const int *const *src, unsigned nSamples,
static void copyTrespass(int8_t * /* dst */, const int *const * /* src */,
unsigned /* bytesPerSample */, unsigned /* nSamples */,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][i];
*dst++ = src[1][i];
}
}
static void copyMultiCh16(int16_t *dst, const int *const *src,
unsigned nSamples, unsigned nChannels) {
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
*dst++ = src[c][i];
}
}
}
// 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
static void copyMono24(int16_t *dst, const int *const *src, unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][i] >> 8;
}
}
static void copyStereo24(int16_t *dst, const int *const *src, unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
*dst++ = src[0][i] >> 8;
*dst++ = src[1][i] >> 8;
}
}
static void copyMultiCh24(int16_t *dst, const int *const *src,
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 copyTrespass(int16_t * /* dst */, const int *const * /* src */,
unsigned /* nSamples */, unsigned /* nChannels */) {
TRESPASS();
}
@ -340,6 +300,7 @@ bool FLACParser::decodeMetadata() {
case 8:
case 16:
case 24:
case 32:
break;
default:
ALOGE("unsupported bits per sample %u", getBitsPerSample());
@ -363,23 +324,11 @@ bool FLACParser::decodeMetadata() {
ALOGE("unsupported sample rate %u", getSampleRate());
return false;
}
// configure the appropriate copy function, defaulting to trespass
static const struct {
unsigned mChannels;
unsigned mBitsPerSample;
void (*mCopy)(int16_t *dst, const int *const *src, 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 (unsigned i = 0; i < sizeof(table) / sizeof(table[0]); ++i) {
if (table[i].mChannels >= getChannels() &&
table[i].mBitsPerSample == getBitsPerSample()) {
mCopy = table[i].mCopy;
break;
}
// configure the appropriate copy function based on device endianness.
if (isBigEndian()) {
mCopy = copyToByteArrayBigEndian;
} else {
mCopy = copyToByteArrayLittleEndian;
}
} else {
ALOGE("missing STREAMINFO");
@ -424,7 +373,8 @@ size_t FLACParser::readBuffer(void *output, size_t output_size) {
return -1;
}
size_t bufferSize = blocksize * getChannels() * sizeof(int16_t);
unsigned bytesPerSample = getBitsPerSample() >> 3;
size_t bufferSize = blocksize * getChannels() * bytesPerSample;
if (bufferSize > output_size) {
ALOGE(
"FLACParser::readBuffer not enough space in output buffer "
@ -434,8 +384,8 @@ size_t FLACParser::readBuffer(void *output, size_t output_size) {
}
// copy PCM from FLAC write buffer to our media buffer, with interleaving.
(*mCopy)(reinterpret_cast<int16_t *>(output), mWriteBuffer, blocksize,
getChannels());
(*mCopy)(reinterpret_cast<int8_t *>(output), mWriteBuffer, bytesPerSample,
blocksize, getChannels());
// fill in buffer metadata
CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);

View File

@ -86,8 +86,8 @@ class FLACParser {
private:
DataSource *mDataSource;
void (*mCopy)(int16_t *dst, const int *const *src, unsigned nSamples,
unsigned nChannels);
void (*mCopy)(int8_t *dst, const int *const *src, unsigned bytesPerSample,
unsigned nSamples, unsigned nChannels);
// handle to underlying libFLAC parser
FLAC__StreamDecoder *mDecoder;

View File

@ -65,7 +65,7 @@ public final class FlacStreamInfo {
}
public int maxDecodedFrameSize() {
return maxBlockSize * channels * 2;
return maxBlockSize * channels * (bitsPerSample / 8);
}
public int bitRate() {