diff options
-rw-r--r-- | include/media/stagefright/MetaData.h | 2 | ||||
-rw-r--r-- | media/libstagefright/OggExtractor.cpp | 77 | ||||
-rw-r--r-- | media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp | 18 | ||||
-rw-r--r-- | media/libstagefright/include/VorbisDecoder.h | 1 |
4 files changed, 98 insertions, 0 deletions
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index 1594e31..ab2f11d 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -95,6 +95,8 @@ enum { // Ogg files can be tagged to be automatically looping... kKeyAutoLoop = 'autL', // bool (int32_t) + + kKeyValidSamples = 'valD', // int32_t }; enum { diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index 7a8cf32..43938b2 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -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; diff --git a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp index 53f0638..703b41e 100644 --- a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp +++ b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp @@ -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); diff --git a/media/libstagefright/include/VorbisDecoder.h b/media/libstagefright/include/VorbisDecoder.h index e9a488a..13e8b77 100644 --- a/media/libstagefright/include/VorbisDecoder.h +++ b/media/libstagefright/include/VorbisDecoder.h @@ -55,6 +55,7 @@ private: int32_t mSampleRate; int64_t mAnchorTimeUs; int64_t mNumFramesOutput; + int32_t mNumFramesLeftOnPage; vorbis_dsp_state *mState; vorbis_info *mVi; |