Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b674bbd authored by Ari Hausman-Cohen's avatar Ari Hausman-Cohen Committed by Andy Hung
Browse files

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
parent c74fafab
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -8,12 +8,14 @@ cc_library_shared {
    ],
    ],


    shared_libs: [
    shared_libs: [
        "libbinder",
        "liblog",
        "liblog",
        "libmediaextractor",
        "libmediaextractor",
        "libmediandk",
        "libmediandk",
    ],
    ],


    static_libs: [
    static_libs: [
        "libaudioutils",
        "libFLAC",
        "libFLAC",
        "libstagefright_foundation",
        "libstagefright_foundation",
        "libstagefright_metadatautils",
        "libstagefright_metadatautils",
+76 −130
Original line number Original line Diff line number Diff line
@@ -24,6 +24,8 @@
// libFLAC parser
// libFLAC parser
#include "FLAC/stream_decoder.h"
#include "FLAC/stream_decoder.h"


#include <audio_utils/primitives.h>
#include <binder/IPCThreadState.h> // for IPCThreadState
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/NdkMediaFormat.h>
#include <media/NdkMediaFormat.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -35,9 +37,20 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/MediaBufferBase.h>
#include <media/stagefright/MediaBufferBase.h>
#include <private/android_filesystem_config.h> // for AID_MEDIA
#include <system/audio.h>


namespace android {
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 FLACParser;


class FLACSource : public MediaTrackHelperV2 {
class FLACSource : public MediaTrackHelperV2 {
@@ -45,7 +58,8 @@ class FLACSource : public MediaTrackHelperV2 {
public:
public:
    FLACSource(
    FLACSource(
            DataSourceHelper *dataSource,
            DataSourceHelper *dataSource,
            AMediaFormat *meta);
            AMediaFormat *meta,
            bool outputFloat);


    virtual media_status_t start();
    virtual media_status_t start();
    virtual media_status_t stop();
    virtual media_status_t stop();
@@ -60,6 +74,7 @@ protected:
private:
private:
    DataSourceHelper *mDataSource;
    DataSourceHelper *mDataSource;
    AMediaFormat *mTrackMetadata;
    AMediaFormat *mTrackMetadata;
    const bool mOutputFloat;
    FLACParser *mParser;
    FLACParser *mParser;
    bool mInitCheck;
    bool mInitCheck;
    bool mStarted;
    bool mStarted;
@@ -76,11 +91,12 @@ class FLACParser {


public:
public:
    enum {
    enum {
        kMaxChannels = 8,
        kMaxChannels = FCC_8,
    };
    };


    explicit FLACParser(
    explicit FLACParser(
        DataSourceHelper *dataSource,
        DataSourceHelper *dataSource,
        bool outputFloat,
        // If metadata pointers aren't provided, we don't fill them
        // If metadata pointers aren't provided, we don't fill them
        AMediaFormat *fileMetadata = 0,
        AMediaFormat *fileMetadata = 0,
        AMediaFormat *trackMetadata = 0);
        AMediaFormat *trackMetadata = 0);
@@ -120,6 +136,7 @@ public:


private:
private:
    DataSourceHelper *mDataSource;
    DataSourceHelper *mDataSource;
    const bool mOutputFloat;
    AMediaFormat *mFileMetadata;
    AMediaFormat *mFileMetadata;
    AMediaFormat *mTrackMetadata;
    AMediaFormat *mTrackMetadata;
    bool mInitCheck;
    bool mInitCheck;
@@ -170,6 +187,7 @@ private:
            const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
            const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
    void metadataCallback(const FLAC__StreamMetadata *metadata);
    void metadataCallback(const FLAC__StreamMetadata *metadata);
    void errorCallback(FLAC__StreamDecoderErrorStatus status);
    void errorCallback(FLAC__StreamDecoderErrorStatus status);
    size_t getOutputSampleSize() const { return mOutputFloat ? sizeof(float) : sizeof(int16_t); }


    // FLAC parser callbacks as C-callable functions
    // FLAC parser callbacks as C-callable functions
    static FLAC__StreamDecoderReadStatus read_callback(
    static FLAC__StreamDecoderReadStatus read_callback(
@@ -381,122 +399,51 @@ void FLACParser::errorCallback(FLAC__StreamDecoderErrorStatus status)
    mErrorStatus = 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 16-bit signed
// or 32-bit float interleaved.
// These are candidates for optimization if needed.
// These are candidates for optimization if needed.

static void copyTo16Signed(
static void copyMono8(
        short *dst,
        int16_t *dst,
        const int *const *src,
        const int * src[FLACParser::kMaxChannels],
        unsigned nSamples,
        unsigned nSamples,
        unsigned /* nChannels */) {
        unsigned nChannels,
    for (unsigned i = 0; i < nSamples; ++i) {
        unsigned bitsPerSample) {
        *dst++ = src[0][i] << 8;
    const unsigned leftShift = 16 - bitsPerSample;
    }
}

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)
{
    for (unsigned i = 0; i < nSamples; ++i) {
    for (unsigned i = 0; i < nSamples; ++i) {
        for (unsigned c = 0; c < nChannels; ++c) {
        for (unsigned c = 0; c < nChannels; ++c) {
            *dst++ = src[c][i] << 8;
            *dst++ = src[c][i] << leftShift;
        }
        }
    }
    }
}
}


static void copyMono16(
static void copyToFloat(
        int16_t *dst,
        float *dst,
        const int * src[FLACParser::kMaxChannels],
        const int *const *src,
        unsigned nSamples,
        unsigned nSamples,
        unsigned /* nChannels */) {
        unsigned nChannels,
    for (unsigned i = 0; i < nSamples; ++i) {
        unsigned bitsPerSample) {
        *dst++ = src[0][i];
    const unsigned leftShift = 32 - bitsPerSample;
    }
}

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)
{
    for (unsigned i = 0; i < nSamples; ++i) {
    for (unsigned i = 0; i < nSamples; ++i) {
        for (unsigned c = 0; c < nChannels; ++c) {
        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::FLACParser(
FLACParser::FLACParser(
        DataSourceHelper *dataSource,
        DataSourceHelper *dataSource,
        bool outputFloat,
        AMediaFormat *fileMetadata,
        AMediaFormat *fileMetadata,
        AMediaFormat *trackMetadata)
        AMediaFormat *trackMetadata)
    : mDataSource(dataSource),
    : mDataSource(dataSource),
      mOutputFloat(outputFloat),
      mFileMetadata(fileMetadata),
      mFileMetadata(fileMetadata),
      mTrackMetadata(trackMetadata),
      mTrackMetadata(trackMetadata),
      mInitCheck(false),
      mInitCheck(false),
      mMaxBufferSize(0),
      mMaxBufferSize(0),
      mGroup(NULL),
      mGroup(NULL),
      mCopy(copyTrespass),
      mDecoder(NULL),
      mDecoder(NULL),
      mCurrentPos(0LL),
      mCurrentPos(0LL),
      mEOF(false),
      mEOF(false),
@@ -590,29 +537,6 @@ status_t FLACParser::init()
            ALOGE("unsupported sample rate %u", getSampleRate());
            ALOGE("unsupported sample rate %u", getSampleRate());
            return NO_INIT;
            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
        // populate track metadata
        if (mTrackMetadata != 0) {
        if (mTrackMetadata != 0) {
            AMediaFormat_setString(mTrackMetadata,
            AMediaFormat_setString(mTrackMetadata,
@@ -623,8 +547,6 @@ status_t FLACParser::init()
                    AMEDIAFORMAT_KEY_SAMPLE_RATE, getSampleRate());
                    AMEDIAFORMAT_KEY_SAMPLE_RATE, getSampleRate());
            AMediaFormat_setInt32(mTrackMetadata,
            AMediaFormat_setInt32(mTrackMetadata,
                    AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, getBitsPerSample());
                    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
            // sample rate is non-zero, so division by zero not possible
            AMediaFormat_setInt64(mTrackMetadata,
            AMediaFormat_setInt64(mTrackMetadata,
                    AMEDIAFORMAT_KEY_DURATION, (getTotalSamples() * 1000000LL) / getSampleRate());
                    AMEDIAFORMAT_KEY_DURATION, (getTotalSamples() * 1000000LL) / getSampleRate());
@@ -644,7 +566,7 @@ void FLACParser::allocateBuffers()
{
{
    CHECK(mGroup == NULL);
    CHECK(mGroup == NULL);
    mGroup = new MediaBufferGroup;
    mGroup = new MediaBufferGroup;
    mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(int16_t);
    mMaxBufferSize = getMaxBlockSize() * getChannels() * getOutputSampleSize();
    mGroup->add_buffer(MediaBufferBase::Create(mMaxBufferSize));
    mGroup->add_buffer(MediaBufferBase::Create(mMaxBufferSize));
}
}


@@ -697,12 +619,24 @@ MediaBufferBase *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)
    if (err != OK) {
    if (err != OK) {
        return NULL;
        return NULL;
    }
    }
    size_t bufferSize = blocksize * getChannels() * sizeof(int16_t);
    const size_t bufferSize = blocksize * getChannels() * getOutputSampleSize();
    CHECK(bufferSize <= mMaxBufferSize);
    CHECK(bufferSize <= mMaxBufferSize);
    int16_t *data = (int16_t *) buffer->data();
    buffer->set_range(0, bufferSize);
    buffer->set_range(0, bufferSize);
    // copy PCM from FLAC write buffer to our media buffer, with interleaving
    // 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
    // fill in buffer metadata
    CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
    CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
    FLAC__uint64 sampleNumber = mWriteHeader.number.sample_number;
    FLAC__uint64 sampleNumber = mWriteHeader.number.sample_number;
@@ -716,17 +650,16 @@ MediaBufferBase *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)


FLACSource::FLACSource(
FLACSource::FLACSource(
        DataSourceHelper *dataSource,
        DataSourceHelper *dataSource,
        AMediaFormat *trackMetadata)
        AMediaFormat *trackMetadata,
        bool outputFloat)
    : mDataSource(dataSource),
    : mDataSource(dataSource),
      mTrackMetadata(trackMetadata),
      mTrackMetadata(trackMetadata),
      mParser(0),
      mOutputFloat(outputFloat),
      mInitCheck(false),
      mParser(new FLACParser(mDataSource, outputFloat)),
      mInitCheck(mParser->initCheck()),
      mStarted(false)
      mStarted(false)
{
{
    ALOGV("FLACSource::FLACSource");
    ALOGV("FLACSource::FLACSource");
    // re-use the same track metadata passed into constructor from FLACExtractor
    mParser = new FLACParser(mDataSource);
    mInitCheck  = mParser->initCheck();
}
}


FLACSource::~FLACSource()
FLACSource::~FLACSource()
@@ -762,7 +695,12 @@ media_status_t FLACSource::stop()


media_status_t FLACSource::getFormat(AMediaFormat *meta)
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(
media_status_t FLACSource::read(
@@ -804,7 +742,7 @@ FLACExtractor::FLACExtractor(
    // FLACParser will fill in the metadata for us
    // FLACParser will fill in the metadata for us
    mFileMetadata = AMediaFormat_new();
    mFileMetadata = AMediaFormat_new();
    mTrackMetadata = AMediaFormat_new();
    mTrackMetadata = AMediaFormat_new();
    mParser = new FLACParser(mDataSource, mFileMetadata, mTrackMetadata);
    mParser = new FLACParser(mDataSource, false /* outputFloat */, mFileMetadata, mTrackMetadata);
    mInitCheck = mParser->initCheck();
    mInitCheck = mParser->initCheck();
}
}


@@ -827,7 +765,9 @@ MediaTrackHelperV2 *FLACExtractor::getTrack(size_t index)
    if (mInitCheck != OK || index > 0) {
    if (mInitCheck != OK || index > 0) {
        return NULL;
        return NULL;
    }
    }
    return new FLACSource(mDataSource, mTrackMetadata);

    return new FLACSource(
            mDataSource, mTrackMetadata, shouldExtractorOutputFloat(mParser->getBitsPerSample()));
}
}


media_status_t FLACExtractor::getTrackMetaData(
media_status_t FLACExtractor::getTrackMetaData(
@@ -836,7 +776,13 @@ media_status_t FLACExtractor::getTrackMetaData(
    if (mInitCheck != OK || index > 0) {
    if (mInitCheck != OK || index > 0) {
        return AMEDIA_ERROR_UNKNOWN;
        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)
media_status_t FLACExtractor::getMetaData(AMediaFormat *meta)
+2 −0
Original line number Original line Diff line number Diff line
@@ -7,12 +7,14 @@ cc_library_shared {
    ],
    ],


    shared_libs: [
    shared_libs: [
        "libbinder",
        "liblog",
        "liblog",
        "libmediaextractor",
        "libmediaextractor",
        "libmediandk",
        "libmediandk",
    ],
    ],


    static_libs: [
    static_libs: [
        "libaudioutils",
        "libfifo",
        "libfifo",
        "libstagefright_foundation",
        "libstagefright_foundation",
    ],
    ],
+91 −52
Original line number Original line Diff line number Diff line
@@ -21,19 +21,33 @@
#include "WAVExtractor.h"
#include "WAVExtractor.h"


#include <audio_utils/primitives.h>
#include <audio_utils/primitives.h>
#include <binder/IPCThreadState.h> // for IPCThreadState
#include <media/DataSourceBase.h>
#include <media/DataSourceBase.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaData.h>
#include <private/android_filesystem_config.h> // for AID_MEDIA
#include <system/audio.h>
#include <utils/String8.h>
#include <utils/String8.h>
#include <cutils/bitops.h>
#include <cutils/bitops.h>


#define CHANNEL_MASK_USE_CHANNEL_ORDER 0
#define CHANNEL_MASK_USE_CHANNEL_ORDER 0


// NOTE: This code assumes the device processor is little endian.

namespace android {
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 {
enum {
    WAVE_FORMAT_PCM        = 0x0001,
    WAVE_FORMAT_PCM        = 0x0001,
    WAVE_FORMAT_IEEE_FLOAT = 0x0003,
    WAVE_FORMAT_IEEE_FLOAT = 0x0003,
@@ -59,7 +73,7 @@ struct WAVSource : public MediaTrackHelperV2 {
            DataSourceHelper *dataSource,
            DataSourceHelper *dataSource,
            AMediaFormat *meta,
            AMediaFormat *meta,
            uint16_t waveFormat,
            uint16_t waveFormat,
            int32_t bitsPerSample,
            bool outputFloat,
            off64_t offset, size_t size);
            off64_t offset, size_t size);


    virtual media_status_t start();
    virtual media_status_t start();
@@ -80,6 +94,7 @@ private:
    DataSourceHelper *mDataSource;
    DataSourceHelper *mDataSource;
    AMediaFormat *mMeta;
    AMediaFormat *mMeta;
    uint16_t mWaveFormat;
    uint16_t mWaveFormat;
    const bool mOutputFloat;
    int32_t mSampleRate;
    int32_t mSampleRate;
    int32_t mNumChannels;
    int32_t mNumChannels;
    int32_t mBitsPerSample;
    int32_t mBitsPerSample;
@@ -126,7 +141,7 @@ MediaTrackHelperV2 *WAVExtractor::getTrack(size_t index) {


    return new WAVSource(
    return new WAVSource(
            mDataSource, mTrackMeta,
            mDataSource, mTrackMeta,
            mWaveFormat, mBitsPerSample, mDataOffset, mDataSize);
            mWaveFormat, shouldExtractorOutputFloat(mBitsPerSample), mDataOffset, mDataSize);
}
}


media_status_t WAVExtractor::getTrackMetaData(
media_status_t WAVExtractor::getTrackMetaData(
@@ -136,7 +151,13 @@ media_status_t WAVExtractor::getTrackMetaData(
        return AMEDIA_ERROR_UNKNOWN;
        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() {
status_t WAVExtractor::init() {
@@ -199,13 +220,13 @@ status_t WAVExtractor::init() {


            mNumChannels = U16_LE_AT(&formatSpec[2]);
            mNumChannels = U16_LE_AT(&formatSpec[2]);


            if (mNumChannels < 1 || mNumChannels > 8) {
            if (mNumChannels < 1 || mNumChannels > FCC_8) {
                ALOGE("Unsupported number of channels (%d)", mNumChannels);
                ALOGE("Unsupported number of channels (%d)", mNumChannels);
                return AMEDIA_ERROR_UNSUPPORTED;
                return AMEDIA_ERROR_UNSUPPORTED;
            }
            }


            if (mWaveFormat != WAVE_FORMAT_EXTENSIBLE) {
            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",
                    ALOGW("More than 2 channels (%d) in non-WAVE_EXT, unknown channel mask",
                            mNumChannels);
                            mNumChannels);
                }
                }
@@ -312,9 +333,6 @@ status_t WAVExtractor::init() {
                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_MASK, mChannelMask);
                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_MASK, mChannelMask);
                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mSampleRate);
                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mSampleRate);
                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, mBitsPerSample);
                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, mBitsPerSample);
                AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_PCM_ENCODING,
                        kAudioEncodingPcm16bit);

                int64_t durationUs = 0;
                int64_t durationUs = 0;
                if (mWaveFormat == WAVE_FORMAT_MSGSM) {
                if (mWaveFormat == WAVE_FORMAT_MSGSM) {
                    // 65 bytes decode to 320 8kHz samples
                    // 65 bytes decode to 320 8kHz samples
@@ -353,22 +371,19 @@ WAVSource::WAVSource(
        DataSourceHelper *dataSource,
        DataSourceHelper *dataSource,
        AMediaFormat *meta,
        AMediaFormat *meta,
        uint16_t waveFormat,
        uint16_t waveFormat,
        int32_t bitsPerSample,
        bool outputFloat,
        off64_t offset, size_t size)
        off64_t offset, size_t size)
    : mDataSource(dataSource),
    : mDataSource(dataSource),
      mMeta(meta),
      mMeta(meta),
      mWaveFormat(waveFormat),
      mWaveFormat(waveFormat),
      mSampleRate(0),
      mOutputFloat(outputFloat),
      mNumChannels(0),
      mBitsPerSample(bitsPerSample),
      mOffset(offset),
      mOffset(offset),
      mSize(size),
      mSize(size),
      mStarted(false),
      mStarted(false),
      mGroup(NULL) {
      mGroup(NULL) {
    CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate));
    CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate));
    CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mNumChannels));
    CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mNumChannels));

    CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, &mBitsPerSample));
    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, kMaxFrameSize);
}
}


WAVSource::~WAVSource() {
WAVSource::~WAVSource() {
@@ -385,11 +400,6 @@ media_status_t WAVSource::start() {
    // some WAV files may have large audio buffers that use shared memory transfer.
    // some WAV files may have large audio buffers that use shared memory transfer.
    mGroup = new MediaBufferGroup(4 /* buffers */, kMaxFrameSize);
    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;
    mCurrentPos = mOffset;


    mStarted = true;
    mStarted = true;
@@ -413,7 +423,13 @@ media_status_t WAVSource::stop() {
media_status_t WAVSource::getFormat(AMediaFormat *meta) {
media_status_t WAVSource::getFormat(AMediaFormat *meta) {
    ALOGV("WAVSource::getFormat");
    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(
media_status_t WAVSource::read(
@@ -449,12 +465,16 @@ media_status_t WAVSource::read(
        return AMEDIA_ERROR_UNKNOWN;
        return AMEDIA_ERROR_UNKNOWN;
    }
    }


    // make sure that maxBytesToRead is multiple of 3, in 24-bit case
    // maxBytesToRead may be reduced so that in-place data conversion will fit in buffer size.
    size_t maxBytesToRead =
    const size_t bufferSize = buffer->size();
        mBitsPerSample == 8 ? kMaxFrameSize / 2 : 
    size_t maxBytesToRead;
        (mBitsPerSample == 24 ? 3*(kMaxFrameSize/3): kMaxFrameSize);
    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)
        (mCurrentPos - mOffset >= (off64_t)mSize)
            ? 0 : mSize - (mCurrentPos - mOffset);
            ? 0 : mSize - (mCurrentPos - mOffset);


@@ -490,38 +510,57 @@ media_status_t WAVSource::read(


    // TODO: add capability to return data as float PCM instead of 16 bit PCM.
    // TODO: add capability to return data as float PCM instead of 16 bit PCM.
    if (mWaveFormat == WAVE_FORMAT_PCM) {
    if (mWaveFormat == WAVE_FORMAT_PCM) {
        if (mBitsPerSample == 8) {
        if (mOutputFloat) {
            // Convert 8-bit unsigned samples to 16-bit signed.
            float *fdest = (float *)buffer->data();

            switch (mBitsPerSample) {
            // Create new buffer with 2 byte wide samples
            case 8: {
            MediaBufferBase *tmp;
                buffer->set_range(0, 4 * n);
            CHECK_EQ(mGroup->acquire_buffer(&tmp), (status_t)OK);
                memcpy_to_float_from_u8(fdest, (const uint8_t *)buffer->data(), n);
            tmp->set_range(0, 2 * n);
            } break;

            case 16: {
            memcpy_to_i16_from_u8((int16_t *)tmp->data(), (const uint8_t *)buffer->data(), n);
                const size_t numSamples = n / 2;
            buffer->release();
                buffer->set_range(0, 4 * numSamples);
            buffer = tmp;
                memcpy_to_float_from_i16(fdest, (const int16_t *)buffer->data(), numSamples);
        } else if (mBitsPerSample == 24) {
            } break;
            // Convert 24-bit signed samples to 16-bit signed in place
            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;
                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);
                buffer->set_range(0, 2 * numSamples);
        }  else if (mBitsPerSample == 32) {
                memcpy_to_i16_from_p24(idest, (const uint8_t *)buffer->data(), numSamples);
            // Convert 32-bit signed samples to 16-bit signed in place
            } break;
            case 32: {
                const size_t numSamples = n / 4;
                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);
                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) {
    } else if (mWaveFormat == WAVE_FORMAT_IEEE_FLOAT) {
        if (mBitsPerSample == 32) {
        if (!mOutputFloat) { // mBitsPerSample == 32
            // Convert 32-bit float samples to 16-bit signed in place
            int16_t *idest = (int16_t *)buffer->data();
            const size_t numSamples = n / 4;
            const size_t numSamples = n / 4;

            memcpy_to_i16_from_float(idest, (const float *)buffer->data(), numSamples);
            memcpy_to_i16_from_float((int16_t *)buffer->data(), (const float *)buffer->data(), numSamples);
            buffer->set_range(0, 2 * 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;
    int64_t timeStampUs = 0;
+24 −4
Original line number Original line Diff line number Diff line
@@ -26,6 +26,8 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/Utils.h>
@@ -87,6 +89,20 @@ const NuPlayer::Renderer::PcmInfo NuPlayer::Renderer::AUDIO_PCMINFO_INITIALIZER
// static
// static
const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
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(
NuPlayer::Renderer::Renderer(
        const sp<MediaPlayerBase::AudioSink> &sink,
        const sp<MediaPlayerBase::AudioSink> &sink,
        const sp<MediaClock> &mediaClock,
        const sp<MediaClock> &mediaClock,
@@ -1877,8 +1893,13 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
    int32_t sampleRate;
    int32_t sampleRate;
    CHECK(format->findInt32("sample-rate", &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()) {
    if (offloadingAudio()) {
        audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
        AString mime;
        AString mime;
        CHECK(format->findString("mime", &mime));
        CHECK(format->findString("mime", &mime));
        status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str());
        status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str());
@@ -1980,7 +2001,7 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
        const PcmInfo info = {
        const PcmInfo info = {
                (audio_channel_mask_t)channelMask,
                (audio_channel_mask_t)channelMask,
                (audio_output_flags_t)pcmFlags,
                (audio_output_flags_t)pcmFlags,
                AUDIO_FORMAT_PCM_16_BIT, // TODO: change to audioFormat
                audioFormat,
                numChannels,
                numChannels,
                sampleRate
                sampleRate
        };
        };
@@ -2019,7 +2040,7 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
                    sampleRate,
                    sampleRate,
                    numChannels,
                    numChannels,
                    (audio_channel_mask_t)channelMask,
                    (audio_channel_mask_t)channelMask,
                    AUDIO_FORMAT_PCM_16_BIT,
                    audioFormat,
                    0 /* bufferCount - unused */,
                    0 /* bufferCount - unused */,
                    mUseAudioCallback ? &NuPlayer::Renderer::AudioSinkCallback : NULL,
                    mUseAudioCallback ? &NuPlayer::Renderer::AudioSinkCallback : NULL,
                    mUseAudioCallback ? this : NULL,
                    mUseAudioCallback ? this : NULL,
@@ -2077,4 +2098,3 @@ void NuPlayer::Renderer::onChangeAudioFormat(
}
}


}  // namespace android
}  // namespace android