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

Unverified Commit b2c7134f authored by Steve Kondik's avatar Steve Kondik Committed by Michael Bestas
Browse files

stagefright: Improve FLAC and WAV support for 24-bit

 * Forward-port changes from CM11
 * Add PCM encoding helpers
 * Remove truncation support as AudioFlinger handles
   rebuffering in case it can't go to the hardware.

Change-Id: Iad30d04ee051050e444c3d665fa8bb7a1cfef348
parent e63dde07
Loading
Loading
Loading
Loading
+36 −1
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@

#define MEDIA_DEFS_H_

#include <stdint.h>

namespace android {

extern const char *MEDIA_MIMETYPE_IMAGE_JPEG;
@@ -94,12 +96,45 @@ extern const char *MEDIA_MIMETYPE_DATA_TIMED_ID3;
// frameworks/base/media/java/android/media/AudioFormat.java. Unfortunately,
// they are not defined in frameworks/av, so defining them here.
enum AudioEncoding {
    kAudioEncodingInvalid = 0,
    kAudioEncodingPcm16bit = 2,
    kAudioEncodingPcm8bit = 3,
    kAudioEncodingPcmFloat = 4,
    kAudioEncodingPcm24bitPacked = 100,
    kAudioEncodingPcm24bitPacked = 200,
    kAudioEncodingPcm32bit = 201,
};

static AudioEncoding bitsToAudioEncoding(int32_t bits) {
    switch (bits) {
        case 8:
            return kAudioEncodingPcm8bit;
        case 16:
            return kAudioEncodingPcm16bit;
        case 24:
            return kAudioEncodingPcm24bitPacked;
        case 32:
            return kAudioEncodingPcmFloat;
    }
    return kAudioEncodingInvalid;
}

static int32_t audioEncodingToBits(AudioEncoding encoding) {
    switch (encoding) {
        case kAudioEncodingInvalid:
            return 0;
        case kAudioEncodingPcm8bit:
            return 8;
        case kAudioEncodingPcm16bit:
            return 16;
        case kAudioEncodingPcm24bitPacked:
            return 24;
        case kAudioEncodingPcmFloat:
        case kAudioEncodingPcm32bit:
            return 32;
    }
    return 0;
}

}  // namespace android

#include <media/stagefright/ExtendedMediaDefs.h>
+54 −130
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>

#include <system/audio.h>

namespace android {

class FLACParser;
@@ -72,6 +74,8 @@ private:

class FLACParser : public RefBase {

friend class FLACSource;

public:
    FLACParser(
        const sp<DataSource> &dataSource,
@@ -103,6 +107,8 @@ public:
    // media buffers
    void allocateBuffers();
    void releaseBuffers();
    void copyBuffer(short *dst, const int *const *src, unsigned nSamples);

    MediaBuffer *readBuffer() {
        return readBuffer(false, 0LL);
    }
@@ -113,6 +119,7 @@ public:
protected:
    virtual ~FLACParser();


private:
    sp<DataSource> mDataSource;
    sp<MetaData> mFileMetadata;
@@ -122,7 +129,6 @@ private:
    // media buffers
    size_t mMaxBufferSize;
    MediaBufferGroup *mGroup;
    void (*mCopy)(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels);

    // handle to underlying libFLAC parser
    FLAC__StreamDecoder *mDecoder;
@@ -139,7 +145,7 @@ private:
    bool mWriteRequested;
    bool mWriteCompleted;
    FLAC__FrameHeader mWriteHeader;
    const FLAC__int32 * const *mWriteBuffer;
    const FLAC__int32 * mWriteBuffer[FLAC__MAX_CHANNELS];

    // most recent error reported by libFLAC parser
    FLAC__StreamDecoderErrorStatus mErrorStatus;
@@ -323,7 +329,9 @@ FLAC__StreamDecoderWriteStatus FLACParser::writeCallback(
        mWriteRequested = false;
        // FLAC parser doesn't free or realloc buffer until next frame or finish
        mWriteHeader = frame->header;
        mWriteBuffer = buffer;
        for(unsigned channel = 0; channel < frame->header.channels; channel++) {
            mWriteBuffer[channel] = buffer[channel];
        }
        mWriteCompleted = true;
        return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
    } else {
@@ -377,108 +385,40 @@ void FLACParser::errorCallback(FLAC__StreamDecoderErrorStatus status)
    mErrorStatus = status;
}

// Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved.
// These are candidates for optimization if needed.

static void copyMono8(
        short *dst,
        const int *const *src,
        unsigned nSamples,
        unsigned /* nChannels */) {
    for (unsigned i = 0; i < nSamples; ++i) {
        *dst++ = src[0][i] << 8;
    }
}

static void copyStereo8(
        short *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(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
void FLACParser::copyBuffer(short *dst, const int *const *src, unsigned nSamples)
{
    unsigned int nChannels = getChannels();
    unsigned int nBits = getBitsPerSample();
    switch (nBits) {
        case 8:
            for (unsigned i = 0; i < nSamples; ++i) {
                for (unsigned c = 0; c < nChannels; ++c) {
                    *dst++ = src[c][i] << 8;
                }
            }
}

static void copyMono16(
        short *dst,
        const int *const *src,
        unsigned nSamples,
        unsigned /* nChannels */) {
    for (unsigned i = 0; i < nSamples; ++i) {
        *dst++ = src[0][i];
    }
}

static void copyStereo16(
        short *dst,
        const int *const *src,
        unsigned nSamples,
        unsigned /* nChannels */) {
    for (unsigned i = 0; i < nSamples; ++i) {
        *dst++ = src[0][i];
        *dst++ = src[1][i];
    }
}

static void copyMultiCh16(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
{
            break;
        case 16:
            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(
        short *dst,
        const int *const *src,
        unsigned nSamples,
        unsigned /* nChannels */) {
    for (unsigned i = 0; i < nSamples; ++i) {
        *dst++ = src[0][i] >> 8;
    }
}

static void copyStereo24(
        short *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(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
            break;
        case 24:
        case 32:
        {
            int32_t *out = (int32_t *)dst;
            for (unsigned i = 0; i < nSamples; ++i) {
                for (unsigned c = 0; c < nChannels; ++c) {
            *dst++ = src[c][i] >> 8;
                    *out++ = src[c][i] << 8;
                }
            }
            break;
        }

static void copyTrespass(
        short * /* dst */,
        const int *const * /* src */,
        unsigned /* nSamples */,
        unsigned /* nChannels */) {
        default:
            TRESPASS();
    }
}

// FLACParser

@@ -492,14 +432,12 @@ FLACParser::FLACParser(
      mInitCheck(false),
      mMaxBufferSize(0),
      mGroup(NULL),
      mCopy(copyTrespass),
      mDecoder(NULL),
      mCurrentPos(0LL),
      mEOF(false),
      mStreamInfoValid(false),
      mWriteRequested(false),
      mWriteCompleted(false),
      mWriteBuffer(NULL),
      mErrorStatus((FLAC__StreamDecoderErrorStatus) -1)
{
    ALOGV("FLACParser::FLACParser");
@@ -571,6 +509,8 @@ status_t FLACParser::init()
        }
        // check sample rate
        switch (getSampleRate()) {
        case   100:
        case  1000:
        case  8000:
        case 11025:
        case 12000:
@@ -578,38 +518,18 @@ status_t FLACParser::init()
        case 22050:
        case 24000:
        case 32000:
        case 42000:
        case 44100:
        case 46000:
        case 48000:
        case 88200:
        case 96000:
        case 192000:
            break;
        default:
            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)(short *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;
            }
        }
        // populate track metadata
        if (mTrackMetadata != 0) {
            mTrackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
@@ -619,6 +539,7 @@ status_t FLACParser::init()
            // sample rate is non-zero, so division by zero not possible
            mTrackMetadata->setInt64(kKeyDuration,
                    (getTotalSamples() * 1000000LL) / getSampleRate());
            mTrackMetadata->setInt32(kKeyPcmEncoding, bitsToAudioEncoding(getBitsPerSample()));
        }
    } else {
        ALOGE("missing STREAMINFO");
@@ -634,7 +555,9 @@ void FLACParser::allocateBuffers()
{
    CHECK(mGroup == NULL);
    mGroup = new MediaBufferGroup;
    mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(short);
    // allocate enough to hold 24-bits (packed in 32 bits)
    unsigned int bytesPerSample = getBitsPerSample() > 16 ? 4 : 2;
    mMaxBufferSize = getMaxBlockSize() * getChannels() * bytesPerSample;
    mGroup->add_buffer(new MediaBuffer(mMaxBufferSize));
}

@@ -687,12 +610,12 @@ MediaBuffer *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)
    if (err != OK) {
        return NULL;
    }
    size_t bufferSize = blocksize * getChannels() * sizeof(short);
    size_t bufferSize = blocksize * getChannels() * (getBitsPerSample() > 16 ? 4 : 2);
    CHECK(bufferSize <= mMaxBufferSize);
    short *data = (short *) buffer->data();
    buffer->set_range(0, bufferSize);
    // copy PCM from FLAC write buffer to our media buffer, with interleaving
    (*mCopy)(data, mWriteBuffer, blocksize, getChannels());
    copyBuffer(data, (const FLAC__int32 * const *)(&mWriteBuffer), blocksize);
    // fill in buffer metadata
    CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
    FLAC__uint64 sampleNumber = mWriteHeader.number.sample_number;
@@ -727,9 +650,10 @@ FLACSource::~FLACSource()

status_t FLACSource::start(MetaData * /* params */)
{
    CHECK(!mStarted);

    ALOGV("FLACSource::start");

    CHECK(!mStarted);
    mParser->allocateBuffers();
    mStarted = true;

+39 −18
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
#include <cutils/bitops.h>
#include <system/audio.h>

#define CHANNEL_MASK_USE_CHANNEL_ORDER 0

@@ -291,6 +292,12 @@ status_t WAVExtractor::init() {
                    case WAVE_FORMAT_IEEE_FLOAT:
                        mTrackMeta->setCString(
                                kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
                        if (mWaveFormat == WAVE_FORMAT_IEEE_FLOAT) {
                            mTrackMeta->setInt32(kKeyPcmEncoding, kAudioEncodingPcmFloat);
                        } else {
                            mTrackMeta->setInt32(kKeyPcmEncoding,
                                    bitsToAudioEncoding(mBitsPerSample));
                        }
                        break;
                    case WAVE_FORMAT_ALAW:
                        mTrackMeta->setCString(
@@ -375,15 +382,16 @@ WAVSource::~WAVSource() {
}

status_t WAVSource::start(MetaData * /* params */) {
    ALOGV("WAVSource::start");

    CHECK(!mStarted);
    if (mStarted) {
        return OK;
    }

    // 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.
    if (mBitsPerSample == 8 || mBitsPerSample == 24) {
        // As a temporary buffer for 8->16/24->32 bit conversion.
        mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
    }

@@ -447,9 +455,15 @@ status_t WAVSource::read(
    }

    // 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);
    size_t maxBytesToRead;
    if(8 == mBitsPerSample)
        maxBytesToRead = kMaxFrameSize / 2;
    else if (24 == mBitsPerSample) {
        maxBytesToRead = 3*(kMaxFrameSize/4);
    } else
        maxBytesToRead = kMaxFrameSize;
    ALOGV("%s mBitsPerSample %d, kMaxFrameSize %zu, ",
          __func__, mBitsPerSample, kMaxFrameSize);

    size_t maxBytesAvailable =
        (mCurrentPos - mOffset >= (off64_t)mSize)
@@ -499,17 +513,24 @@ status_t WAVSource::read(
            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);
            // Padding done here to convert to 32-bit samples
            MediaBuffer *tmp;
            CHECK_EQ(mGroup->acquire_buffer(&tmp), (status_t)OK);
            ssize_t numBytes = buffer->range_length() / 3;
            tmp->set_range(0, 4 * numBytes);
            int8_t *dst = (int8_t *)tmp->data();
            const uint8_t *src = (const uint8_t *)buffer->data();
            ALOGV("numBytes = %zu", numBytes);
            while(numBytes-- > 0) {
               *dst++ = 0x0;
               *dst++ = src[0];
               *dst++ = src[1];
               *dst++ = src[2];
               src += 3;
            }
            buffer->release();
            buffer = tmp;
            ALOGV("length = %zu", buffer->range_length());
        }
    } else if (mWaveFormat == WAVE_FORMAT_IEEE_FLOAT) {
        if (mBitsPerSample == 32) {