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

Commit bc5bd012 authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge changes I46c5cfe4,Ic09bd2fe

* changes:
  MediaExtractor: Update to use ndk binder
  Support float WAV & FLAC extraction
parents ab536abb fcc4e616
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -8,12 +8,14 @@ cc_library_shared {
    ],

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

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

#include <android/binder_ibinder.h> // for AIBinder_getCallingUid
#include <audio_utils/primitives.h>
#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 && AIBinder_getCallingUid() == AID_MEDIA;
}

class FLACParser;

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

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

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 @@ public:

private:
    DataSourceHelper *mDataSource;
    const bool mOutputFloat;
    AMediaFormat *mFileMetadata;
    AMediaFormat *mTrackMetadata;
    bool mInitCheck;
@@ -170,6 +187,7 @@ private:
            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 @@ 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 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 @@ status_t FLACParser::init()
            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 @@ status_t FLACParser::init()
                    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 @@ void FLACParser::allocateBuffers()
{
    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 @@ MediaBufferBase *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)
    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 @@ MediaBufferBase *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)

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::stop()

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 @@ FLACExtractor::FLACExtractor(
    // 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 @@ MediaTrackHelperV2 *FLACExtractor::getTrack(size_t index)
    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 @@ media_status_t FLACExtractor::getTrackMetaData(
    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)
+2 −0
Original line number Diff line number Diff line
@@ -7,12 +7,14 @@ cc_library_shared {
    ],

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

    static_libs: [
        "libaudioutils",
        "libfifo",
        "libstagefright_foundation",
    ],
+91 −52
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@

#include "WAVExtractor.h"

#include <android/binder_ibinder.h> // for AIBinder_getCallingUid
#include <audio_utils/primitives.h>
#include <media/DataSourceBase.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -27,13 +28,26 @@
#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 && AIBinder_getCallingUid() == AID_MEDIA;
}

enum {
    WAVE_FORMAT_PCM        = 0x0001,
    WAVE_FORMAT_IEEE_FLOAT = 0x0003,
@@ -59,7 +73,7 @@ struct WAVSource : public MediaTrackHelperV2 {
            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 @@ private:
    DataSourceHelper *mDataSource;
    AMediaFormat *mMeta;
    uint16_t mWaveFormat;
    const bool mOutputFloat;
    int32_t mSampleRate;
    int32_t mNumChannels;
    int32_t mBitsPerSample;
@@ -126,7 +141,7 @@ MediaTrackHelperV2 *WAVExtractor::getTrack(size_t index) {

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

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

            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 @@ status_t WAVExtractor::init() {
                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 @@ WAVSource::WAVSource(
        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 @@ media_status_t WAVSource::start() {
    // 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::stop() {
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 @@ media_status_t WAVSource::read(
        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 @@ media_status_t WAVSource::read(

    // 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
        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;

            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
                memcpy_to_i16_from_p24(idest, (const uint8_t *)buffer->data(), numSamples);
            } break;
            case 32: {
                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);
                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;
+24 −4
Original line number Diff line number Diff line
@@ -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 @@ const NuPlayer::Renderer::PcmInfo NuPlayer::Renderer::AUDIO_PCMINFO_INITIALIZER
// 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 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
    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 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
        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 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
                    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 @@ void NuPlayer::Renderer::onChangeAudioFormat(
}

}  // namespace android