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

Commit 38ae220b authored by Andreas Huber's avatar Andreas Huber
Browse files

Vorbis files may have more samples encoded that should be used, i.e. we have...

Vorbis files may have more samples encoded that should be used, i.e. we have to trim samples at the end of the stream. This is crucial for proper looping of some audio files.

related-to-bug: 3036592
Change-Id: Ib142b171c829ed74156c0281d9d4543fcc96c802
parent a16682b5
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -95,6 +95,8 @@ enum {

    // Ogg files can be tagged to be automatically looping...
    kKeyAutoLoop          = 'autL',  // bool (int32_t)

    kKeyValidSamples      = 'valD',  // int32_t
};

enum {
+77 −0
Original line number Diff line number Diff line
@@ -93,7 +93,10 @@ private:
    sp<DataSource> mSource;
    off_t mOffset;
    Page mCurrentPage;
    uint64_t mPrevGranulePosition;
    size_t mCurrentPageSize;
    bool mFirstPacketInPage;
    uint64_t mCurrentPageSamples;
    size_t mNextLaceIndex;

    off_t mFirstDataOffset;
@@ -113,6 +116,8 @@ private:
    void parseFileMetaData();
    void extractAlbumArt(const void *data, size_t size);

    uint64_t findPrevGranulePosition(off_t pageOffset);

    MyVorbisExtractor(const MyVorbisExtractor &);
    MyVorbisExtractor &operator=(const MyVorbisExtractor &);
};
@@ -193,7 +198,10 @@ status_t OggSource::read(
MyVorbisExtractor::MyVorbisExtractor(const sp<DataSource> &source)
    : mSource(source),
      mOffset(0),
      mPrevGranulePosition(0),
      mCurrentPageSize(0),
      mFirstPacketInPage(true),
      mCurrentPageSamples(0),
      mNextLaceIndex(0),
      mFirstDataOffset(-1) {
    mCurrentPage.mNumSegments = 0;
@@ -238,6 +246,52 @@ status_t MyVorbisExtractor::findNextPage(
    }
}

// Given the offset of the "current" page, find the page immediately preceding
// it (if any) and return its granule position.
// To do this we back up from the "current" page's offset until we find any
// page preceding it and then scan forward to just before the current page.
uint64_t MyVorbisExtractor::findPrevGranulePosition(off_t pageOffset) {
    off_t prevPageOffset = 0;
    off_t prevGuess = pageOffset;
    for (;;) {
        if (prevGuess >= 5000) {
            prevGuess -= 5000;
        } else {
            prevGuess = 0;
        }

        LOGV("backing up %ld bytes", pageOffset - prevGuess);

        CHECK_EQ(findNextPage(prevGuess, &prevPageOffset), (status_t)OK);

        if (prevPageOffset < pageOffset || prevGuess == 0) {
            break;
        }
    }

    if (prevPageOffset == pageOffset) {
        // We did not find a page preceding this one.
        return 0;
    }

    LOGV("prevPageOffset at %ld, pageOffset at %ld", prevPageOffset, pageOffset);

    for (;;) {
        Page prevPage;
        ssize_t n = readPage(prevPageOffset, &prevPage);

        if (n <= 0) {
            return 0;
        }

        prevPageOffset += n;

        if (prevPageOffset == pageOffset) {
            return prevPage.mGranulePosition;
        }
    }
}

status_t MyVorbisExtractor::seekToOffset(off_t offset) {
    if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) {
        // Once we know where the actual audio data starts (past the headers)
@@ -252,9 +306,16 @@ status_t MyVorbisExtractor::seekToOffset(off_t offset) {
        return err;
    }

    // We found the page we wanted to seek to, but we'll also need
    // the page preceding it to determine how many valid samples are on
    // this page.
    mPrevGranulePosition = findPrevGranulePosition(pageOffset);

    mOffset = pageOffset;

    mCurrentPageSize = 0;
    mFirstPacketInPage = true;
    mCurrentPageSamples = 0;
    mCurrentPage.mNumSegments = 0;
    mNextLaceIndex = 0;

@@ -399,6 +460,12 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
                    buffer->meta_data()->setInt64(kKeyTime, timeUs);
                }

                if (mFirstPacketInPage) {
                    buffer->meta_data()->setInt32(
                            kKeyValidSamples, mCurrentPageSamples);
                    mFirstPacketInPage = false;
                }

                *out = buffer;

                return OK;
@@ -423,6 +490,12 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
            return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
        }

        mCurrentPageSamples =
            mCurrentPage.mGranulePosition - mPrevGranulePosition;
        mFirstPacketInPage = true;

        mPrevGranulePosition = mCurrentPage.mGranulePosition;

        mCurrentPageSize = n;
        mNextLaceIndex = 0;

@@ -435,6 +508,10 @@ status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
                    buffer->meta_data()->setInt64(kKeyTime, timeUs);
                }

                buffer->meta_data()->setInt32(
                        kKeyValidSamples, mCurrentPageSamples);
                mFirstPacketInPage = false;

                *out = buffer;

                return OK;
+18 −0
Original line number Diff line number Diff line
@@ -14,6 +14,10 @@
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "VorbisDecoder"
#include <utils/Log.h>

#include "VorbisDecoder.h"

#include <media/stagefright/MediaBufferGroup.h>
@@ -108,6 +112,7 @@ status_t VorbisDecoder::start(MetaData *params) {

    mAnchorTimeUs = 0;
    mNumFramesOutput = 0;
    mNumFramesLeftOnPage = 0;
    mStarted = true;

    return OK;
@@ -188,6 +193,13 @@ int VorbisDecoder::decodePacket(MediaBuffer *packet, MediaBuffer *out) {
        }
    }

    if (numFrames > mNumFramesLeftOnPage) {
        LOGV("discarding %d frames at end of page",
             numFrames - mNumFramesLeftOnPage);
        numFrames = mNumFramesLeftOnPage;
    }
    mNumFramesLeftOnPage -= numFrames;

    out->set_range(0, numFrames * sizeof(int16_t) * mNumChannels);

    return numFrames;
@@ -226,6 +238,12 @@ status_t VorbisDecoder::read(
        CHECK(seekTimeUs < 0);
    }

    int32_t numPageSamples;
    if (inputBuffer->meta_data()->findInt32(
                kKeyValidSamples, &numPageSamples)) {
        mNumFramesLeftOnPage = numPageSamples;
    }

    MediaBuffer *outputBuffer;
    CHECK_EQ(mBufferGroup->acquire_buffer(&outputBuffer), OK);

+1 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ private:
    int32_t mSampleRate;
    int64_t mAnchorTimeUs;
    int64_t mNumFramesOutput;
    int32_t mNumFramesLeftOnPage;

    vorbis_dsp_state *mState;
    vorbis_info *mVi;