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

Commit cc88ea00 authored by Riaz Rahaman's avatar Riaz Rahaman Committed by Arne Coucheron
Browse files

libstagefright: Enable multi bitrate support in AMR Parser

Added support in AMR Parser to play clips with variable bit rate

Change-Id: If28f17678a49c09845f6a53b0205c90ccc3a8a4d

Conflicts:

	media/libstagefright/AMRExtractor.cpp
parent 4c3c2ecc
Loading
Loading
Loading
Loading
+158 −22
Original line number Diff line number Diff line
@@ -36,7 +36,9 @@ public:
    AMRSource(const sp<DataSource> &source,
              const sp<MetaData> &meta,
              size_t frameSize,
              bool isWide);
              bool isWide,
              List<AMRFrameTableEntry> mAMRFrameTableEntries,
              uint64_t mTotalFrames);

    virtual status_t start(MetaData *params = NULL);
    virtual status_t stop();
@@ -52,6 +54,9 @@ protected:
private:
    sp<DataSource> mDataSource;
    sp<MetaData> mMeta;
    uint64_t mTotalFrames;
    List<AMRFrameTableEntry> mAMRFrameTableEntries;

    size_t mFrameSize;
    bool mIsWide;

@@ -65,20 +70,46 @@ private:
};

////////////////////////////////////////////////////////////////////////////////

#define MAX_AMRMODE 16
static size_t getFrameSize(bool isWide, unsigned FT) {
    static const size_t kFrameSizeNB[8] = {
        95, 103, 118, 134, 148, 159, 204, 244
//RFC 4867
    static const size_t kFrameSizeNB[MAX_AMRMODE] = { 13      // AMR 4.75 Kbps
          , 14        // AMR 5.15 Kbps
          , 16        // AMR 5.90 Kbps
          , 18        // AMR 6.70 Kbps
          , 20        // AMR 7.40 Kbps
          , 21        // AMR 7.95 Kbps
          , 27        // AMR 10.2 Kbps
          , 32        // AMR 12.2 Kbps
          , 6     // GsmAmr comfort noise
          , 7     // Gsm-Efr comfort noise
          , 6     // IS-641 comfort noise
          , 6     // Pdc-Efr comfort noise
          , 1     // future use; 0 length but set to 1 to skip the frame type byte
          , 1     // future use; 0 length but set to 1 to skip the frame type byte
          , 1     // future use; 0 length but set to 1 to skip the frame type byte
          , 1     // AMR Frame No Data
    };
    static const size_t kFrameSizeWB[9] = {
        132, 177, 253, 285, 317, 365, 397, 461, 477
    static const size_t kFrameSizeWB[MAX_AMRMODE] = { 18      // AMR-WB 6.60 Kbps
          , 24        // AMR-WB 8.85 Kbps
          , 33        // AMR-WB 12.65 Kbps
          , 37        // AMR-WB 14.25 Kbps
          , 41        // AMR-WB 15.85 Kbps
          , 47        // AMR-WB 18.25 Kbps
          , 51        // AMR-WB 19.85 Kbps
          , 59        // AMR-WB 23.05 Kbps
          , 61        // AMR-WB 23.85 Kbps
          , 6     // AMR-WB SID
          , 1
          , 1
          , 1
          , 1
          , 1     // WBAMR Frame No Data
          , 1     // WBAMR Frame No Data
    };

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

    // Round up bits to bytes and add 1 for the header byte.
    frameSize = (frameSize + 7) / 8 + 1;

    return frameSize;
}

@@ -101,27 +132,101 @@ AMRExtractor::AMRExtractor(const sp<DataSource> &source)
    mMeta->setInt32(kKeyChannelCount, 1);
    mMeta->setInt32(kKeySampleRate, mIsWide ? 16000 : 8000);

    size_t offset = mIsWide ? 9 : 6;
    off_t offset = mIsWide ? 9 : 6;

    uint32_t mFrmNumber;

    //add first sample entry mIsWide ? 9 : 6;
    {
       AMRFrameTableEntry amrframetableentry(1, offset, 0);
       mAMRFrameTableEntries.push_back(amrframetableentry);
    }

    ssize_t n = 0;
    mFrmNumber = 0;
    mTotalFrames = 0;
    uint8_t header;
    if (mDataSource->readAt(offset, &header, 1) != 1) {

    n = mDataSource->readAt(offset, &header, 1);

    if (header & 0x83) {
          LOGE("padding bits must be 0, header is 0x%02x", header);
          return;
    }

    if(n<1){
        LOGE("AMRxtractor: header incorrect");
        return;
    }

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

    if (FT > 8 || (!mIsWide && FT > 7)) {
    if (FT > MAX_AMRMODE || (!mIsWide && FT > MAX_AMRMODE)) {
        LOGE("UnSupported AMR FrameType(%d) ERROR",FT);
        return;
    }

    mFrameSize = getFrameSize(mIsWide, FT);

    off_t streamSize;
    if (mDataSource->getSize(&streamSize) == OK) {
        off_t numFrames = streamSize / mFrameSize;
    size_t framesize = mFrameSize;
    size_t numframes = 1;
    size_t framerate = FT;

    mFrmNumber++;
    offset = offset+mFrameSize;

        mMeta->setInt64(kKeyDuration, 20000ll * numFrames);
    while(n)
    {
        n = mDataSource->readAt(offset, &header, 1);

        if(n<1){
           LOGI("EOF reached");
           break;
        }

        if (header & 0x83) {
        LOGE("padding bits must be 0, header is 0x%02x", header);
        return; //ERROR_MALFORMED;
        }

        unsigned FT = (header >> 3) & 0x0f;
        if (FT > MAX_AMRMODE) {
            LOGE("UnSupported AMR FrameType(%d) ERROR",FT);
            return;
        }

        mFrameSize = getFrameSize(mIsWide, FT);
        size_t framesize1 = mFrameSize;
        size_t framerate1 = FT;

        mFrmNumber++;
        offset = offset+mFrameSize;

        if(framerate1 != framerate)
        {
           /* When framerate is different then we store the chunk back on the
            * list
            */
           AMRFrameTableEntry amrframetableentry(numframes, framesize, framerate);
           mAMRFrameTableEntries.push_back(amrframetableentry);

           framesize = framesize1;
           framerate = framerate1;
           numframes = 1;
        }
        else
           numframes++;
    }

    {
       AMRFrameTableEntry amrframetableentry(numframes, framesize, framerate);
       mAMRFrameTableEntries.push_back(amrframetableentry);
       mTotalFrames = mFrmNumber;
    }

    uint32_t numFrames = mFrmNumber;
    int64_t duration = 20000ll * ((int64_t)numFrames+1);
    mMeta->setInt64(kKeyDuration, duration);
    mInitCheck = OK;
}

@@ -149,7 +254,7 @@ sp<MediaSource> AMRExtractor::getTrack(size_t index) {
        return NULL;
    }

    return new AMRSource(mDataSource, mMeta, mFrameSize, mIsWide);
    return new AMRSource(mDataSource, mMeta, mFrameSize, mIsWide, mAMRFrameTableEntries, mTotalFrames);
}

sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
@@ -164,9 +269,12 @@ 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)
        size_t frameSize, bool isWide, List<AMRFrameTableEntry> AMRFrameTableEntries,
        uint64_t TotalFrames)
    : mDataSource(source),
      mMeta(meta),
      mTotalFrames(TotalFrames),
      mAMRFrameTableEntries(AMRFrameTableEntries),
      mFrameSize(frameSize),
      mIsWide(isWide),
      mOffset(mIsWide ? 9 : 6),
@@ -187,6 +295,7 @@ status_t AMRSource::start(MetaData *params) {
    mOffset = mIsWide ? 9 : 6;
    mCurrentTimeUs = 0;
    mGroup = new MediaBufferGroup;
    //if crash observed during playback then the size needs to be increased
    mGroup->add_buffer(new MediaBuffer(128));
    mStarted = true;

@@ -214,9 +323,37 @@ status_t AMRSource::read(
    int64_t seekTimeUs;
    ReadOptions::SeekMode mode;
    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
        int64_t seekFrame = seekTimeUs / 20000ll;  // 20ms per frame.
        uint64_t seekFrame = seekTimeUs / 20000ll;  // 20ms per frame.
        mCurrentTimeUs = seekFrame * 20000ll;
        mOffset = seekFrame * mFrameSize + (mIsWide ? 9 : 6);
        uint32_t framesize=0;
        uint64_t offset = 0, numframes = 0;
        seekFrame = seekFrame + 1; //why seekframe+1, since the array starts from zero
        LOGI("seekframe %lld", seekFrame);
        for (List<AMRFrameTableEntry>::iterator it = mAMRFrameTableEntries.begin();
               it != mAMRFrameTableEntries.end(); ++it) {

             numframes = it->mNumFrames;
             framesize = it->mFrameSize;
             if(seekFrame >= mTotalFrames)
             {
               LOGE("seek beyond EOF");
               return ERROR_OUT_OF_RANGE;
             }

             if(seekFrame > numframes)
             {
               offset = offset + (numframes * framesize);
               seekFrame = seekFrame - numframes;
               LOGV("> offset %lld seekFrame %lld numframes %lld framesize %d", offset, seekFrame, numframes, framesize);
             }
             else
             {
               offset = offset + (seekFrame * framesize);
               LOGV("!> offset %lld numframes %lld framesize %d", offset, numframes, framesize);
               break;
             }
        }
        mOffset = offset;
    }

    uint8_t header;
@@ -236,7 +373,7 @@ status_t AMRSource::read(

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

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

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

@@ -244,7 +381,6 @@ status_t AMRSource::read(
    }

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

    MediaBuffer *buffer;
    status_t err = mGroup->acquire_buffer(&buffer);
+16 −5
Original line number Diff line number Diff line
@@ -116,15 +116,26 @@ sp<MetaData> AMRWBDecoder::getFormat() {
}

static size_t getFrameSize(unsigned FT) {
    static const size_t kFrameSizeWB[9] = {
        132, 177, 253, 285, 317, 365, 397, 461, 477
    static const size_t kFrameSizeWB[16] = { 18      // AMR-WB 6.60 Kbps
          , 24        // AMR-WB 8.85 Kbps
          , 33        // AMR-WB 12.65 Kbps
          , 37        // AMR-WB 14.25 Kbps
          , 41        // AMR-WB 15.85 Kbps
          , 47        // AMR-WB 18.25 Kbps
          , 51        // AMR-WB 19.85 Kbps
          , 59        // AMR-WB 23.05 Kbps
          , 61        // AMR-WB 23.85 Kbps
          , 6     // AMR-WB SID
          , 1
          , 1
          , 1
          , 1
          , 1     // WBAMR Frame No Data
          , 1     // WBAMR Frame No Data
    };

    size_t frameSize = kFrameSizeWB[FT];

    // Round up bits to bytes and add 1 for the header byte.
    frameSize = (frameSize + 7) / 8 + 1;

    return frameSize;
}

+14 −2
Original line number Diff line number Diff line
@@ -19,11 +19,22 @@
#define AMR_EXTRACTOR_H_

#include <media/stagefright/MediaExtractor.h>

#include <utils/List.h>
namespace android {

struct AMessage;
class String8;
struct AMRFrameTableEntry {

   AMRFrameTableEntry(uint32_t numframes, uint32_t framesize, uint32_t framerate)
      : mNumFrames(numframes),
      mFrameSize(framesize),
      mFrameRate(framerate) {}

   uint64_t mNumFrames;
   uint32_t mFrameSize;
   uint32_t mFrameRate;
};

class AMRExtractor : public MediaExtractor {
public:
@@ -44,7 +55,8 @@ private:
    status_t mInitCheck;
    size_t mFrameSize;
    bool mIsWide;

    uint64_t mTotalFrames;
    List<AMRFrameTableEntry> mAMRFrameTableEntries;
    AMRExtractor(const AMRExtractor &);
    AMRExtractor &operator=(const AMRExtractor &);
};