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

Commit aef112a9 authored by Marco Nelissen's avatar Marco Nelissen
Browse files

Fix Ogg extractor and Vorbis decoder

Ignore empty packets, and only set the "valid page samples" property
for the last page.

Bug: 167535700
Test: CTS, test file from bug
Change-Id: Ic82b476996dabbede2767dc067a3162658d2e34c
parent c7f2011c
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -359,6 +359,10 @@ void C2SoftVorbisDec::process(
    }
    memcpy(&numPageFrames, data + inSize - sizeof(numPageFrames), sizeof(numPageFrames));
    inSize -= sizeof(numPageFrames);
    if (inSize == 0) {
        // empty buffer, ignore
        return;
    }
    if (numPageFrames >= 0) {
        mNumFramesLeftOnPage = numPageFrames;
    }
@@ -409,7 +413,7 @@ void C2SoftVorbisDec::process(
                mState,  reinterpret_cast<int16_t *> (wView.data()),
                kMaxNumSamplesPerChannel);
        if (numFrames < 0) {
            ALOGD("vorbis_dsp_pcmout returned %d", numFrames);
            ALOGD("vorbis_dsp_pcmout returned %d frames", numFrames);
            numFrames = 0;
        }
    }
+27 −9
Original line number Diff line number Diff line
@@ -43,6 +43,9 @@ extern "C" {
    long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op);
}

static constexpr int OGG_PAGE_FLAG_CONTINUED_PACKET = 1;
static constexpr int OGG_PAGE_FLAG_END_OF_STREAM = 4;

namespace android {

struct OggSource : public MediaTrackHelper {
@@ -297,7 +300,8 @@ media_status_t OggSource::read(
    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, 1);

    *out = packet;
    ALOGV("returning buffer %p", packet);
    ALOGV("returning buffer %p, size %zu, length %zu",
          packet, packet->size(), packet->range_length());
    return AMEDIA_OK;
}

@@ -358,10 +362,10 @@ status_t MyOggExtractor::findNextPage(

        if (!memcmp(signature, "OggS", 4)) {
            if (*pageOffset > startOffset) {
                ALOGV("skipped %lld bytes of junk to reach next frame",
                     (long long)(*pageOffset - startOffset));
                ALOGV("skipped %lld bytes of junk at %lld to reach next frame",
                     (long long)(*pageOffset - startOffset), (long long)(startOffset));
            }

            ALOGV("found frame at %lld", (long long)(*pageOffset));
            return OK;
        }

@@ -629,7 +633,8 @@ media_status_t MyOpusExtractor::readNextPacket(MediaBufferHelper **out) {
    // Calculate timestamps by accumulating durations starting from the first sample of a page;
    // We assume that we only seek to page boundaries.
    AMediaFormat *meta = (*out)->meta_data();
    if (AMediaFormat_getInt32(meta, AMEDIAFORMAT_KEY_VALID_SAMPLES, &currentPageSamples)) {
    if (AMediaFormat_getInt32(meta, AMEDIAFORMAT_KEY_VALID_SAMPLES, &currentPageSamples) &&
            (mCurrentPage.mFlags & OGG_PAGE_FLAG_END_OF_STREAM)) {
        // first packet in page
        if (mOffset == mFirstDataOffset) {
            currentPageSamples -= mStartGranulePosition;
@@ -812,6 +817,7 @@ media_status_t MyOggExtractor::_readNextPacket(MediaBufferHelper **out, bool cal
            }
            buffer = tmp;

            ALOGV("reading %zu bytes @ %zu", packetSize, size_t(dataOffset));
            ssize_t n = mSource->readAt(
                    dataOffset,
                    (uint8_t *)buffer->data() + buffer->range_length(),
@@ -830,8 +836,9 @@ media_status_t MyOggExtractor::_readNextPacket(MediaBufferHelper **out, bool cal

            if (gotFullPacket) {
                // We've just read the entire packet.
                ALOGV("got full packet, size %zu", fullSize);

                if (mFirstPacketInPage) {
                if (mFirstPacketInPage && (mCurrentPage.mFlags & OGG_PAGE_FLAG_END_OF_STREAM)) {
                    AMediaFormat *meta = buffer->meta_data();
                    AMediaFormat_setInt32(
                            meta, AMEDIAFORMAT_KEY_VALID_SAMPLES, mCurrentPageSamples);
@@ -864,6 +871,9 @@ media_status_t MyOggExtractor::_readNextPacket(MediaBufferHelper **out, bool cal
            }

            // fall through, the buffer now contains the start of the packet.
            ALOGV("have start of packet, getting rest");
        } else {
            ALOGV("moving to next page");
        }

        CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments);
@@ -899,9 +909,10 @@ media_status_t MyOggExtractor::_readNextPacket(MediaBufferHelper **out, bool cal
        mNextLaceIndex = 0;

        if (buffer != NULL) {
            if ((mCurrentPage.mFlags & 1) == 0) {
            if ((mCurrentPage.mFlags & OGG_PAGE_FLAG_CONTINUED_PACKET) == 0) {
                // This page does not continue the packet, i.e. the packet
                // is already complete.
                ALOGV("packet was already complete?!");

                if (timeUs >= 0) {
                    AMediaFormat *meta = buffer->meta_data();
@@ -909,8 +920,10 @@ media_status_t MyOggExtractor::_readNextPacket(MediaBufferHelper **out, bool cal
                }

                AMediaFormat *meta = buffer->meta_data();
                if (mCurrentPage.mFlags & OGG_PAGE_FLAG_END_OF_STREAM) {
                    AMediaFormat_setInt32(
                            meta, AMEDIAFORMAT_KEY_VALID_SAMPLES, mCurrentPageSamples);
                }
                mFirstPacketInPage = false;

                *out = buffer;
@@ -929,6 +942,7 @@ status_t MyOggExtractor::init() {
    for (size_t i = 0; i < mNumHeaders; ++i) {
        // ignore timestamp for configuration packets
        if ((err = _readNextPacket(&packet, /* calcVorbisTimestamp = */ false)) != AMEDIA_OK) {
            ALOGV("readNextPacket failed");
            return err;
        }
        ALOGV("read packet of size %zu\n", packet->range_length());
@@ -1008,6 +1022,10 @@ int32_t MyOggExtractor::getPacketBlockSize(MediaBufferHelper *buffer) {

    size_t size = buffer->range_length();

    if (size == 0) {
        return 0;
    }

    ogg_buffer buf;
    buf.data = (uint8_t *)data;
    buf.size = size;