Support float WAV & FLAC extraction
Previously all WAV/FLAC files were extracted as 16 bit data.
Changes this so that 24/32 bit are extracted as float data
to maintain the higher quality.
Note: Update for master branch supersedes iot branches.
Bug: 63770882
Bug: 110480091
Test: Used media player to play 24 bit, 32 bit, and float wav files, plus 16 bit and 24 bit FLAC files,
ensured data went through successfully without loss of quality
Change-Id: Ic09bd2fe994bbf3ed8441549904712c534030c96
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index eda7b61..15feb4b 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -8,12 +8,14 @@
],
shared_libs: [
+ "libbinder",
"liblog",
"libmediaextractor",
"libmediandk",
],
static_libs: [
+ "libaudioutils",
"libFLAC",
"libstagefright_foundation",
"libstagefright_metadatautils",
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index be6d9fd..432486e 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -24,6 +24,8 @@
// libFLAC parser
#include "FLAC/stream_decoder.h"
+#include <audio_utils/primitives.h>
+#include <binder/IPCThreadState.h> // for IPCThreadState
#include <media/MediaExtractorPluginApi.h>
#include <media/NdkMediaFormat.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -35,9 +37,20 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/MediaBufferBase.h>
+#include <private/android_filesystem_config.h> // for AID_MEDIA
+#include <system/audio.h>
namespace android {
+// MediaServer is capable of handling float extractor output, but general processes
+// may not be able to do so.
+// TODO: Improve API to set extractor float output.
+// (Note: duplicated with WAVExtractor.cpp)
+static inline bool shouldExtractorOutputFloat(int bitsPerSample)
+{
+ return bitsPerSample > 16 && IPCThreadState::self()->getCallingUid() == AID_MEDIA;
+}
+
class FLACParser;
class FLACSource : public MediaTrackHelperV2 {
@@ -45,7 +58,8 @@
public:
FLACSource(
DataSourceHelper *dataSource,
- AMediaFormat *meta);
+ AMediaFormat *meta,
+ bool outputFloat);
virtual media_status_t start();
virtual media_status_t stop();
@@ -60,6 +74,7 @@
private:
DataSourceHelper *mDataSource;
AMediaFormat *mTrackMetadata;
+ const bool mOutputFloat;
FLACParser *mParser;
bool mInitCheck;
bool mStarted;
@@ -76,11 +91,12 @@
public:
enum {
- kMaxChannels = 8,
+ kMaxChannels = FCC_8,
};
explicit FLACParser(
DataSourceHelper *dataSource,
+ bool outputFloat,
// If metadata pointers aren't provided, we don't fill them
AMediaFormat *fileMetadata = 0,
AMediaFormat *trackMetadata = 0);
@@ -120,6 +136,7 @@
private:
DataSourceHelper *mDataSource;
+ const bool mOutputFloat;
AMediaFormat *mFileMetadata;
AMediaFormat *mTrackMetadata;
bool mInitCheck;
@@ -170,6 +187,7 @@
const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
void metadataCallback(const FLAC__StreamMetadata *metadata);
void errorCallback(FLAC__StreamDecoderErrorStatus status);
+ size_t getOutputSampleSize() const { return mOutputFloat ? sizeof(float) : sizeof(int16_t); }
// FLAC parser callbacks as C-callable functions
static FLAC__StreamDecoderReadStatus read_callback(
@@ -381,122 +399,51 @@
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 16-bit signed
+// or 32-bit float interleaved.
// These are candidates for optimization if needed.
-
-static void copyMono8(
- int16_t *dst,
- const int * src[FLACParser::kMaxChannels],
+static void copyTo16Signed(
+ short *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 * src[FLACParser::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(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
-{
+ unsigned nChannels,
+ unsigned bitsPerSample) {
+ const unsigned leftShift = 16 - bitsPerSample;
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
- *dst++ = src[c][i] << 8;
+ *dst++ = src[c][i] << leftShift;
}
}
}
-static void copyMono16(
- int16_t *dst,
- const int * src[FLACParser::kMaxChannels],
+static void copyToFloat(
+ float *dst,
+ const int *const *src,
unsigned nSamples,
- unsigned /* nChannels */) {
- for (unsigned i = 0; i < nSamples; ++i) {
- *dst++ = src[0][i];
- }
-}
-
-static void copyStereo16(
- int16_t *dst,
- const int * src[FLACParser::kMaxChannels],
- 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 * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
-{
+ unsigned nChannels,
+ unsigned bitsPerSample) {
+ const unsigned leftShift = 32 - bitsPerSample;
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
- *dst++ = src[c][i];
+ *dst++ = float_from_i32(src[c][i] << leftShift);
}
}
}
-// 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
-
-static void copyMono24(
- int16_t *dst,
- const int * src[FLACParser::kMaxChannels],
- unsigned nSamples,
- unsigned /* nChannels */) {
- for (unsigned i = 0; i < nSamples; ++i) {
- *dst++ = src[0][i] >> 8;
- }
-}
-
-static void copyStereo24(
- int16_t *dst,
- const int * src[FLACParser::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(int16_t *dst, const int * src[FLACParser::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 copyTrespass(
- int16_t * /* dst */,
- const int *[FLACParser::kMaxChannels] /* src */,
- unsigned /* nSamples */,
- unsigned /* nChannels */) {
- TRESPASS();
-}
-
// FLACParser
FLACParser::FLACParser(
DataSourceHelper *dataSource,
+ bool outputFloat,
AMediaFormat *fileMetadata,
AMediaFormat *trackMetadata)
: mDataSource(dataSource),
+ mOutputFloat(outputFloat),
mFileMetadata(fileMetadata),
mTrackMetadata(trackMetadata),
mInitCheck(false),
mMaxBufferSize(0),
mGroup(NULL),
- mCopy(copyTrespass),
mDecoder(NULL),
mCurrentPos(0LL),
mEOF(false),
@@ -590,29 +537,6 @@
ALOGE("unsupported sample rate %u", getSampleRate());
return NO_INIT;
}
- // configure the appropriate copy function, defaulting to trespass
- static const struct {
- unsigned mChannels;
- unsigned mBitsPerSample;
- void (*mCopy)(int16_t *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 (unsigned i = 0; i < sizeof(table)/sizeof(table[0]); ++i) {
- if (table[i].mChannels >= getChannels() &&
- table[i].mBitsPerSample == getBitsPerSample()) {
- mCopy = table[i].mCopy;
- break;
- }
- }
// populate track metadata
if (mTrackMetadata != 0) {
AMediaFormat_setString(mTrackMetadata,
@@ -623,8 +547,6 @@
AMEDIAFORMAT_KEY_SAMPLE_RATE, getSampleRate());
AMediaFormat_setInt32(mTrackMetadata,
AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, getBitsPerSample());
- AMediaFormat_setInt32(mTrackMetadata,
- AMEDIAFORMAT_KEY_PCM_ENCODING, kAudioEncodingPcm16bit);
// sample rate is non-zero, so division by zero not possible
AMediaFormat_setInt64(mTrackMetadata,
AMEDIAFORMAT_KEY_DURATION, (getTotalSamples() * 1000000LL) / getSampleRate());
@@ -644,7 +566,7 @@
{
CHECK(mGroup == NULL);
mGroup = new MediaBufferGroup;
- mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(int16_t);
+ mMaxBufferSize = getMaxBlockSize() * getChannels() * getOutputSampleSize();
mGroup->add_buffer(MediaBufferBase::Create(mMaxBufferSize));
}
@@ -697,12 +619,24 @@
if (err != OK) {
return NULL;
}
- size_t bufferSize = blocksize * getChannels() * sizeof(int16_t);
+ const size_t bufferSize = blocksize * getChannels() * getOutputSampleSize();
CHECK(bufferSize <= mMaxBufferSize);
- int16_t *data = (int16_t *) buffer->data();
buffer->set_range(0, bufferSize);
// copy PCM from FLAC write buffer to our media buffer, with interleaving
- (*mCopy)(data, mWriteBuffer, blocksize, getChannels());
+ const unsigned bitsPerSample = getBitsPerSample();
+ if (mOutputFloat) {
+ copyToFloat(reinterpret_cast<float*>(buffer->data()),
+ mWriteBuffer,
+ blocksize,
+ getChannels(),
+ bitsPerSample);
+ } else {
+ copyTo16Signed(reinterpret_cast<short*>(buffer->data()),
+ mWriteBuffer,
+ blocksize,
+ getChannels(),
+ bitsPerSample);
+ }
// fill in buffer metadata
CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
FLAC__uint64 sampleNumber = mWriteHeader.number.sample_number;
@@ -716,17 +650,16 @@
FLACSource::FLACSource(
DataSourceHelper *dataSource,
- AMediaFormat *trackMetadata)
+ AMediaFormat *trackMetadata,
+ bool outputFloat)
: mDataSource(dataSource),
mTrackMetadata(trackMetadata),
- mParser(0),
- mInitCheck(false),
+ mOutputFloat(outputFloat),
+ mParser(new FLACParser(mDataSource, outputFloat)),
+ mInitCheck(mParser->initCheck()),
mStarted(false)
{
ALOGV("FLACSource::FLACSource");
- // re-use the same track metadata passed into constructor from FLACExtractor
- mParser = new FLACParser(mDataSource);
- mInitCheck = mParser->initCheck();
}
FLACSource::~FLACSource()
@@ -762,7 +695,12 @@
media_status_t FLACSource::getFormat(AMediaFormat *meta)
{
- return AMediaFormat_copy(meta, mTrackMetadata);
+ const media_status_t status = AMediaFormat_copy(meta, mTrackMetadata);
+ if (status == OK) {
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_PCM_ENCODING,
+ mOutputFloat ? kAudioEncodingPcmFloat : kAudioEncodingPcm16bit);
+ }
+ return status;
}
media_status_t FLACSource::read(
@@ -804,7 +742,7 @@
// FLACParser will fill in the metadata for us
mFileMetadata = AMediaFormat_new();
mTrackMetadata = AMediaFormat_new();
- mParser = new FLACParser(mDataSource, mFileMetadata, mTrackMetadata);
+ mParser = new FLACParser(mDataSource, false /* outputFloat */, mFileMetadata, mTrackMetadata);
mInitCheck = mParser->initCheck();
}
@@ -827,7 +765,9 @@
if (mInitCheck != OK || index > 0) {
return NULL;
}
- return new FLACSource(mDataSource, mTrackMetadata);
+
+ return new FLACSource(
+ mDataSource, mTrackMetadata, shouldExtractorOutputFloat(mParser->getBitsPerSample()));
}
media_status_t FLACExtractor::getTrackMetaData(
@@ -836,7 +776,13 @@
if (mInitCheck != OK || index > 0) {
return AMEDIA_ERROR_UNKNOWN;
}
- return AMediaFormat_copy(meta, mTrackMetadata);
+ const media_status_t status = AMediaFormat_copy(meta, mTrackMetadata);
+ if (status == OK) {
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_PCM_ENCODING,
+ shouldExtractorOutputFloat(mParser->getBitsPerSample())
+ ? kAudioEncodingPcmFloat : kAudioEncodingPcm16bit);
+ }
+ return status;
}
media_status_t FLACExtractor::getMetaData(AMediaFormat *meta)
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index d8b4144..fdc05a8 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -7,12 +7,14 @@
],
shared_libs: [
+ "libbinder",
"liblog",
"libmediaextractor",
"libmediandk",
],
static_libs: [
+ "libaudioutils",
"libfifo",
"libstagefright_foundation",
],
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index ddc7031..12fa7c9 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -21,19 +21,33 @@
#include "WAVExtractor.h"
#include <audio_utils/primitives.h>
+#include <binder/IPCThreadState.h> // for IPCThreadState
#include <media/DataSourceBase.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
+#include <private/android_filesystem_config.h> // for AID_MEDIA
+#include <system/audio.h>
#include <utils/String8.h>
#include <cutils/bitops.h>
#define CHANNEL_MASK_USE_CHANNEL_ORDER 0
+// NOTE: This code assumes the device processor is little endian.
+
namespace android {
+// MediaServer is capable of handling float extractor output, but general processes
+// may not be able to do so.
+// TODO: Improve API to set extractor float output.
+// (Note: duplicated with FLACExtractor.cpp)
+static inline bool shouldExtractorOutputFloat(int bitsPerSample)
+{
+ return bitsPerSample > 16 && IPCThreadState::self()->getCallingUid() == AID_MEDIA;
+}
+
enum {
WAVE_FORMAT_PCM = 0x0001,
WAVE_FORMAT_IEEE_FLOAT = 0x0003,
@@ -59,7 +73,7 @@
DataSourceHelper *dataSource,
AMediaFormat *meta,
uint16_t waveFormat,
- int32_t bitsPerSample,
+ bool outputFloat,
off64_t offset, size_t size);
virtual media_status_t start();
@@ -80,6 +94,7 @@
DataSourceHelper *mDataSource;
AMediaFormat *mMeta;
uint16_t mWaveFormat;
+ const bool mOutputFloat;
int32_t mSampleRate;
int32_t mNumChannels;
int32_t mBitsPerSample;
@@ -126,7 +141,7 @@
return new WAVSource(
mDataSource, mTrackMeta,
- mWaveFormat, mBitsPerSample, mDataOffset, mDataSize);
+ mWaveFormat, shouldExtractorOutputFloat(mBitsPerSample), mDataOffset, mDataSize);
}
media_status_t WAVExtractor::getTrackMetaData(
@@ -136,7 +151,13 @@
return AMEDIA_ERROR_UNKNOWN;
}
- return AMediaFormat_copy(meta, mTrackMeta);
+ const media_status_t status = AMediaFormat_copy(meta, mTrackMeta);
+ if (status == OK) {
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_PCM_ENCODING,
+ shouldExtractorOutputFloat(mBitsPerSample)
+ ? kAudioEncodingPcmFloat : kAudioEncodingPcm16bit);
+ }
+ return status;
}
status_t WAVExtractor::init() {
@@ -199,13 +220,13 @@
mNumChannels = U16_LE_AT(&formatSpec[2]);
- if (mNumChannels < 1 || mNumChannels > 8) {
+ if (mNumChannels < 1 || mNumChannels > FCC_8) {
ALOGE("Unsupported number of channels (%d)", mNumChannels);
return AMEDIA_ERROR_UNSUPPORTED;
}
if (mWaveFormat != WAVE_FORMAT_EXTENSIBLE) {
- if (mNumChannels != 1 && mNumChannels != 2) {
+ if (mNumChannels != 1 && mNumChannels != FCC_2) {
ALOGW("More than 2 channels (%d) in non-WAVE_EXT, unknown channel mask",
mNumChannels);
}
@@ -312,9 +333,6 @@
AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_MASK, mChannelMask);
AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mSampleRate);
AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, mBitsPerSample);
- AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_PCM_ENCODING,
- kAudioEncodingPcm16bit);
-
int64_t durationUs = 0;
if (mWaveFormat == WAVE_FORMAT_MSGSM) {
// 65 bytes decode to 320 8kHz samples
@@ -353,22 +371,19 @@
DataSourceHelper *dataSource,
AMediaFormat *meta,
uint16_t waveFormat,
- int32_t bitsPerSample,
+ bool outputFloat,
off64_t offset, size_t size)
: mDataSource(dataSource),
mMeta(meta),
mWaveFormat(waveFormat),
- mSampleRate(0),
- mNumChannels(0),
- mBitsPerSample(bitsPerSample),
+ mOutputFloat(outputFloat),
mOffset(offset),
mSize(size),
mStarted(false),
mGroup(NULL) {
CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate));
CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mNumChannels));
-
- AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, kMaxFrameSize);
+ CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, &mBitsPerSample));
}
WAVSource::~WAVSource() {
@@ -385,11 +400,6 @@
// some WAV files may have large audio buffers that use shared memory transfer.
mGroup = new MediaBufferGroup(4 /* buffers */, kMaxFrameSize);
- if (mBitsPerSample == 8) {
- // As a temporary buffer for 8->16 bit conversion.
- mGroup->add_buffer(MediaBufferBase::Create(kMaxFrameSize));
- }
-
mCurrentPos = mOffset;
mStarted = true;
@@ -413,7 +423,13 @@
media_status_t WAVSource::getFormat(AMediaFormat *meta) {
ALOGV("WAVSource::getFormat");
- return AMediaFormat_copy(meta, mMeta);
+ const media_status_t status = AMediaFormat_copy(meta, mMeta);
+ if (status == OK) {
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, kMaxFrameSize);
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_PCM_ENCODING,
+ mOutputFloat ? kAudioEncodingPcmFloat : kAudioEncodingPcm16bit);
+ }
+ return status;
}
media_status_t WAVSource::read(
@@ -449,12 +465,16 @@
return AMEDIA_ERROR_UNKNOWN;
}
- // make sure that maxBytesToRead is multiple of 3, in 24-bit case
- size_t maxBytesToRead =
- mBitsPerSample == 8 ? kMaxFrameSize / 2 :
- (mBitsPerSample == 24 ? 3*(kMaxFrameSize/3): kMaxFrameSize);
+ // maxBytesToRead may be reduced so that in-place data conversion will fit in buffer size.
+ const size_t bufferSize = buffer->size();
+ size_t maxBytesToRead;
+ if (mOutputFloat) { // destination is float at 4 bytes per sample, source may be less.
+ maxBytesToRead = (mBitsPerSample / 8) * (bufferSize / 4);
+ } else { // destination is int16_t at 2 bytes per sample, only source of 8 bits is less.
+ maxBytesToRead = mBitsPerSample == 8 ? bufferSize / 2 : bufferSize;
+ }
- size_t maxBytesAvailable =
+ const size_t maxBytesAvailable =
(mCurrentPos - mOffset >= (off64_t)mSize)
? 0 : mSize - (mCurrentPos - mOffset);
@@ -490,38 +510,57 @@
// TODO: add capability to return data as float PCM instead of 16 bit PCM.
if (mWaveFormat == WAVE_FORMAT_PCM) {
- if (mBitsPerSample == 8) {
- // Convert 8-bit unsigned samples to 16-bit signed.
-
- // Create new buffer with 2 byte wide samples
- MediaBufferBase *tmp;
- CHECK_EQ(mGroup->acquire_buffer(&tmp), (status_t)OK);
- tmp->set_range(0, 2 * n);
-
- memcpy_to_i16_from_u8((int16_t *)tmp->data(), (const uint8_t *)buffer->data(), n);
- buffer->release();
- buffer = tmp;
- } else if (mBitsPerSample == 24) {
- // Convert 24-bit signed samples to 16-bit signed in place
- const size_t numSamples = n / 3;
-
- memcpy_to_i16_from_p24((int16_t *)buffer->data(), (const uint8_t *)buffer->data(), numSamples);
- buffer->set_range(0, 2 * numSamples);
- } else if (mBitsPerSample == 32) {
- // Convert 32-bit signed samples to 16-bit signed in place
- const size_t numSamples = n / 4;
-
- memcpy_to_i16_from_i32((int16_t *)buffer->data(), (const int32_t *)buffer->data(), numSamples);
- buffer->set_range(0, 2 * numSamples);
+ if (mOutputFloat) {
+ float *fdest = (float *)buffer->data();
+ switch (mBitsPerSample) {
+ case 8: {
+ buffer->set_range(0, 4 * n);
+ memcpy_to_float_from_u8(fdest, (const uint8_t *)buffer->data(), n);
+ } break;
+ case 16: {
+ const size_t numSamples = n / 2;
+ buffer->set_range(0, 4 * numSamples);
+ memcpy_to_float_from_i16(fdest, (const int16_t *)buffer->data(), numSamples);
+ } break;
+ case 24: {
+ const size_t numSamples = n / 3;
+ buffer->set_range(0, 4 * numSamples);
+ memcpy_to_float_from_p24(fdest, (const uint8_t *)buffer->data(), numSamples);
+ } break;
+ case 32: { // buffer range is correct
+ const size_t numSamples = n / 4;
+ memcpy_to_float_from_i32(fdest, (const int32_t *)buffer->data(), numSamples);
+ } break;
+ }
+ } else {
+ int16_t *idest = (int16_t *)buffer->data();
+ switch (mBitsPerSample) {
+ case 8: {
+ buffer->set_range(0, 2 * n);
+ memcpy_to_i16_from_u8(idest, (const uint8_t *)buffer->data(), n);
+ } break;
+ case 16:
+ break; // no translation needed
+ case 24: {
+ const size_t numSamples = n / 3;
+ buffer->set_range(0, 2 * numSamples);
+ memcpy_to_i16_from_p24(idest, (const uint8_t *)buffer->data(), numSamples);
+ } break;
+ case 32: {
+ const size_t numSamples = n / 4;
+ buffer->set_range(0, 2 * numSamples);
+ memcpy_to_i16_from_i32(idest, (const int32_t *)buffer->data(), numSamples);
+ } break;
+ }
}
} else if (mWaveFormat == WAVE_FORMAT_IEEE_FLOAT) {
- if (mBitsPerSample == 32) {
- // Convert 32-bit float samples to 16-bit signed in place
+ if (!mOutputFloat) { // mBitsPerSample == 32
+ int16_t *idest = (int16_t *)buffer->data();
const size_t numSamples = n / 4;
-
- memcpy_to_i16_from_float((int16_t *)buffer->data(), (const float *)buffer->data(), numSamples);
+ memcpy_to_i16_from_float(idest, (const float *)buffer->data(), numSamples);
buffer->set_range(0, 2 * numSamples);
}
+ // Note: if output encoding is float, no need to convert if source is float.
}
int64_t timeStampUs = 0;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 57a0198..b258332 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -26,6 +26,8 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/MediaClock.h>
+#include <media/stagefright/MediaCodecConstants.h>
+#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
@@ -87,6 +89,20 @@
// static
const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
+static audio_format_t constexpr audioFormatFromEncoding(int32_t pcmEncoding) {
+ switch (pcmEncoding) {
+ case kAudioEncodingPcmFloat:
+ return AUDIO_FORMAT_PCM_FLOAT;
+ case kAudioEncodingPcm16bit:
+ return AUDIO_FORMAT_PCM_16_BIT;
+ case kAudioEncodingPcm8bit:
+ return AUDIO_FORMAT_PCM_8_BIT; // TODO: do we want to support this?
+ default:
+ ALOGE("%s: Invalid encoding: %d", __func__, pcmEncoding);
+ return AUDIO_FORMAT_INVALID;
+ }
+}
+
NuPlayer::Renderer::Renderer(
const sp<MediaPlayerBase::AudioSink> &sink,
const sp<MediaClock> &mediaClock,
@@ -1877,8 +1893,13 @@
int32_t sampleRate;
CHECK(format->findInt32("sample-rate", &sampleRate));
+ // read pcm encoding from MediaCodec output format, if available
+ int32_t pcmEncoding;
+ audio_format_t audioFormat =
+ format->findInt32(KEY_PCM_ENCODING, &pcmEncoding) ?
+ audioFormatFromEncoding(pcmEncoding) : AUDIO_FORMAT_PCM_16_BIT;
+
if (offloadingAudio()) {
- audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
AString mime;
CHECK(format->findString("mime", &mime));
status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str());
@@ -1980,7 +2001,7 @@
const PcmInfo info = {
(audio_channel_mask_t)channelMask,
(audio_output_flags_t)pcmFlags,
- AUDIO_FORMAT_PCM_16_BIT, // TODO: change to audioFormat
+ audioFormat,
numChannels,
sampleRate
};
@@ -2019,7 +2040,7 @@
sampleRate,
numChannels,
(audio_channel_mask_t)channelMask,
- AUDIO_FORMAT_PCM_16_BIT,
+ audioFormat,
0 /* bufferCount - unused */,
mUseAudioCallback ? &NuPlayer::Renderer::AudioSinkCallback : NULL,
mUseAudioCallback ? this : NULL,
@@ -2077,4 +2098,3 @@
}
} // namespace android
-