summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/stagefright/MetaData.h2
-rw-r--r--media/libstagefright/OggExtractor.cpp77
-rw-r--r--media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp18
-rw-r--r--media/libstagefright/include/VorbisDecoder.h1
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;