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

Commit 069715b6 authored by Gloria Wang's avatar Gloria Wang
Browse files

- Support comfort noise in AMRExtractor

- Support duration and seeking in AMRExtractor for different bit rates

Bug 2530101

Change-Id: I12beffea73cea0ec056f0e0cf51a4a8d46d897b8
parent a66cf878
Loading
Loading
Loading
Loading
+88 −37
Original line number Diff line number Diff line
@@ -35,8 +35,9 @@ class AMRSource : public MediaSource {
public:
    AMRSource(const sp<DataSource> &source,
              const sp<MetaData> &meta,
              size_t frameSize,
              bool isWide);
              bool isWide,
              const off64_t *offset_table,
              size_t offset_table_length);

    virtual status_t start(MetaData *params = NULL);
    virtual status_t stop();
@@ -52,7 +53,6 @@ protected:
private:
    sp<DataSource> mDataSource;
    sp<MetaData> mMeta;
    size_t mFrameSize;
    bool mIsWide;

    off64_t mOffset;
@@ -60,6 +60,9 @@ private:
    bool mStarted;
    MediaBufferGroup *mGroup;

    off64_t mOffsetTable[OFFSET_TABLE_LEN];
    size_t mOffsetTableLength;

    AMRSource(const AMRSource &);
    AMRSource &operator=(const AMRSource &);
};
@@ -67,13 +70,25 @@ private:
////////////////////////////////////////////////////////////////////////////////

static size_t getFrameSize(bool isWide, unsigned FT) {
    static const size_t kFrameSizeNB[8] = {
        95, 103, 118, 134, 148, 159, 204, 244
    static const size_t kFrameSizeNB[16] = {
        95, 103, 118, 134, 148, 159, 204, 244,
        39, 43, 38, 37, // SID
        0, 0, 0, // future use
        0 // no data
    };
    static const size_t kFrameSizeWB[9] = {
        132, 177, 253, 285, 317, 365, 397, 461, 477
    static const size_t kFrameSizeWB[16] = {
        132, 177, 253, 285, 317, 365, 397, 461, 477,
        40, // SID
        0, 0, 0, 0, // future use
        0, // speech lost
        0 // no data
    };

    if (FT > 15 || (isWide && FT > 9 && FT < 14) || (!isWide && FT > 11 && FT < 15)) {
        LOGE("illegal AMR frame type %d", FT);
        return 0;
    }

    size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT];

    // Round up bits to bytes and add 1 for the header byte.
@@ -82,9 +97,26 @@ static size_t getFrameSize(bool isWide, unsigned FT) {
    return frameSize;
}

static status_t getFrameSizeByOffset(const sp<DataSource> &source,
        off64_t offset, bool isWide, size_t *frameSize) {
    uint8_t header;
    if (source->readAt(offset, &header, 1) < 1) {
        return ERROR_IO;
    }

    unsigned FT = (header >> 3) & 0x0f;

    *frameSize = getFrameSize(isWide, FT);
    if (*frameSize == 0) {
        return ERROR_MALFORMED;
    }
    return OK;
}

AMRExtractor::AMRExtractor(const sp<DataSource> &source)
    : mDataSource(source),
      mInitCheck(NO_INIT) {
      mInitCheck(NO_INIT),
      mOffsetTableLength(0) {
    String8 mimeType;
    float confidence;
    if (!SniffAMR(mDataSource, &mimeType, &confidence, NULL)) {
@@ -101,25 +133,29 @@ AMRExtractor::AMRExtractor(const sp<DataSource> &source)
    mMeta->setInt32(kKeyChannelCount, 1);
    mMeta->setInt32(kKeySampleRate, mIsWide ? 16000 : 8000);

    size_t offset = mIsWide ? 9 : 6;
    uint8_t header;
    if (mDataSource->readAt(offset, &header, 1) != 1) {
        return;
    }

    unsigned FT = (header >> 3) & 0x0f;
    off64_t offset = mIsWide ? 9 : 6;
    off64_t streamSize;
    size_t frameSize, numFrames = 0;
    int64_t duration = 0;

    if (FT > 8 || (!mIsWide && FT > 7)) {
    if (mDataSource->getSize(&streamSize) == OK) {
         while (offset < streamSize) {
            if (getFrameSizeByOffset(source, offset, mIsWide, &frameSize) != OK) {
                return;
            }

    mFrameSize = getFrameSize(mIsWide, FT);
            if ((numFrames % 50 == 0) && (numFrames / 50 < OFFSET_TABLE_LEN)) {
                CHECK_EQ(mOffsetTableLength, numFrames / 50);
                mOffsetTable[mOffsetTableLength] = offset - (mIsWide ? 9: 6);
                mOffsetTableLength ++;
            }

    off64_t streamSize;
    if (mDataSource->getSize(&streamSize) == OK) {
        off64_t numFrames = streamSize / mFrameSize;
            offset += frameSize;
            duration += 20000;  // Each frame is 20ms
            numFrames ++;
        }

        mMeta->setInt64(kKeyDuration, 20000ll * numFrames);
        mMeta->setInt64(kKeyDuration, duration);
    }

    mInitCheck = OK;
@@ -149,7 +185,8 @@ sp<MediaSource> AMRExtractor::getTrack(size_t index) {
        return NULL;
    }

    return new AMRSource(mDataSource, mMeta, mFrameSize, mIsWide);
    return new AMRSource(mDataSource, mMeta, mIsWide,
            mOffsetTable, mOffsetTableLength);
}

sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
@@ -164,15 +201,18 @@ sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {

AMRSource::AMRSource(
        const sp<DataSource> &source, const sp<MetaData> &meta,
        size_t frameSize, bool isWide)
        bool isWide, const off64_t *offset_table, size_t offset_table_length)
    : mDataSource(source),
      mMeta(meta),
      mFrameSize(frameSize),
      mIsWide(isWide),
      mOffset(mIsWide ? 9 : 6),
      mCurrentTimeUs(0),
      mStarted(false),
      mGroup(NULL) {
      mGroup(NULL),
      mOffsetTableLength(offset_table_length) {
    if (mOffsetTableLength > 0 && mOffsetTableLength <= OFFSET_TABLE_LEN) {
        memcpy ((char*)mOffsetTable, (char*)offset_table, sizeof(off64_t) * mOffsetTableLength);
    }
}

AMRSource::~AMRSource() {
@@ -214,9 +254,25 @@ status_t AMRSource::read(
    int64_t seekTimeUs;
    ReadOptions::SeekMode mode;
    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
        size_t size;
        int64_t seekFrame = seekTimeUs / 20000ll;  // 20ms per frame.
        mCurrentTimeUs = seekFrame * 20000ll;
        mOffset = seekFrame * mFrameSize + (mIsWide ? 9 : 6);

        int index = seekFrame / 50;
        if (index >= mOffsetTableLength) {
            index = mOffsetTableLength - 1;
        }

        mOffset = mOffsetTable[index] + (mIsWide ? 9 : 6);

        for (int i = 0; i< seekFrame - index * 50; i++) {
            status_t err;
            if ((err = getFrameSizeByOffset(mDataSource, mOffset,
                            mIsWide, &size)) != OK) {
                return err;
            }
            mOffset += size;
        }
    }

    uint8_t header;
@@ -236,16 +292,11 @@ status_t AMRSource::read(

    unsigned FT = (header >> 3) & 0x0f;

    if (FT > 8 || (!mIsWide && FT > 7)) {

        LOGE("illegal AMR frame type %d", FT);

    size_t frameSize = getFrameSize(mIsWide, FT);
    if (frameSize == 0) {
        return ERROR_MALFORMED;
    }

    size_t frameSize = getFrameSize(mIsWide, FT);
    CHECK_EQ(frameSize, mFrameSize);

    MediaBuffer *buffer;
    status_t err = mGroup->acquire_buffer(&buffer);
    if (err != OK) {
+4 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ namespace android {

struct AMessage;
class String8;
#define OFFSET_TABLE_LEN    300

class AMRExtractor : public MediaExtractor {
public:
@@ -42,9 +43,11 @@ private:
    sp<DataSource> mDataSource;
    sp<MetaData> mMeta;
    status_t mInitCheck;
    size_t mFrameSize;
    bool mIsWide;

    off64_t mOffsetTable[OFFSET_TABLE_LEN]; //5 min
    size_t mOffsetTableLength;

    AMRExtractor(const AMRExtractor &);
    AMRExtractor &operator=(const AMRExtractor &);
};