summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/MPEG4Extractor.cpp
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2010-01-28 14:27:37 -0800
committerAndreas Huber <andih@google.com>2010-01-28 14:27:37 -0800
commit50a9976892316c033cd90d522ecbfcc8e3c0eb9b (patch)
treede656510c2e5203cbee3229e1bafc7f9f0fc9440 /media/libstagefright/MPEG4Extractor.cpp
parent5561ccf4a8db88a2e44eac1b3ed13b4ff53a7f20 (diff)
downloadframeworks_av-50a9976892316c033cd90d522ecbfcc8e3c0eb9b.zip
frameworks_av-50a9976892316c033cd90d522ecbfcc8e3c0eb9b.tar.gz
frameworks_av-50a9976892316c033cd90d522ecbfcc8e3c0eb9b.tar.bz2
For mpeg4 files streamed through HTTP, cache the entire sampletable metadata chunk in memory if possible.
related-to-bug: 2295438
Diffstat (limited to 'media/libstagefright/MPEG4Extractor.cpp')
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp119
1 files changed, 119 insertions, 0 deletions
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index ed12b6d..5370c39 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -84,6 +84,112 @@ private:
MPEG4Source &operator=(const MPEG4Source &);
};
+// This custom data source wraps an existing one and satisfies requests
+// falling entirely within a cached range from the cache while forwarding
+// all remaining requests to the wrapped datasource.
+// This is used to cache the full sampletable metadata for a single track,
+// possibly wrapping multiple times to cover all tracks, i.e.
+// Each MPEG4DataSource caches the sampletable metadata for a single track.
+
+struct MPEG4DataSource : public DataSource {
+ MPEG4DataSource(const sp<DataSource> &source);
+
+ virtual status_t initCheck() const;
+ virtual ssize_t readAt(off_t offset, void *data, size_t size);
+ virtual status_t getSize(off_t *size);
+ virtual uint32_t flags();
+
+ status_t setCachedRange(off_t offset, size_t size);
+
+protected:
+ virtual ~MPEG4DataSource();
+
+private:
+ Mutex mLock;
+
+ sp<DataSource> mSource;
+ off_t mCachedOffset;
+ size_t mCachedSize;
+ uint8_t *mCache;
+
+ void clearCache();
+
+ MPEG4DataSource(const MPEG4DataSource &);
+ MPEG4DataSource &operator=(const MPEG4DataSource &);
+};
+
+MPEG4DataSource::MPEG4DataSource(const sp<DataSource> &source)
+ : mSource(source),
+ mCachedOffset(0),
+ mCachedSize(0),
+ mCache(NULL) {
+}
+
+MPEG4DataSource::~MPEG4DataSource() {
+ clearCache();
+}
+
+void MPEG4DataSource::clearCache() {
+ if (mCache) {
+ free(mCache);
+ mCache = NULL;
+ }
+
+ mCachedOffset = 0;
+ mCachedSize = 0;
+}
+
+status_t MPEG4DataSource::initCheck() const {
+ return mSource->initCheck();
+}
+
+ssize_t MPEG4DataSource::readAt(off_t offset, void *data, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (offset >= mCachedOffset
+ && offset + size <= mCachedOffset + mCachedSize) {
+ memcpy(data, &mCache[offset - mCachedOffset], size);
+ return size;
+ }
+
+ return mSource->readAt(offset, data, size);
+}
+
+status_t MPEG4DataSource::getSize(off_t *size) {
+ return mSource->getSize(size);
+}
+
+uint32_t MPEG4DataSource::flags() {
+ return mSource->flags();
+}
+
+status_t MPEG4DataSource::setCachedRange(off_t offset, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ clearCache();
+
+ mCache = (uint8_t *)malloc(size);
+
+ if (mCache == NULL) {
+ return -ENOMEM;
+ }
+
+ mCachedOffset = offset;
+ mCachedSize = size;
+
+ ssize_t err = mSource->readAt(mCachedOffset, mCache, mCachedSize);
+
+ if (err < (ssize_t)size) {
+ clearCache();
+
+ return ERROR_IO;
+ }
+
+ return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
static void hexdump(const void *_data, size_t size) {
const uint8_t *data = (const uint8_t *)_data;
size_t offset = 0;
@@ -374,6 +480,19 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
case FOURCC('u', 'd', 't', 'a'):
case FOURCC('i', 'l', 's', 't'):
{
+ if (chunk_type == FOURCC('s', 't', 'b', 'l')) {
+ LOGV("sampleTable chunk is %d bytes long.", (size_t)chunk_size);
+
+ if (mDataSource->flags() & DataSource::kWantsPrefetching) {
+ sp<MPEG4DataSource> cachedSource =
+ new MPEG4DataSource(mDataSource);
+
+ if (cachedSource->setCachedRange(*offset, chunk_size) == OK) {
+ mDataSource = cachedSource;
+ }
+ }
+ }
+
off_t stop_offset = *offset + chunk_size;
*offset = data_offset;
while (*offset < stop_offset) {