diff options
author | Andreas Huber <andih@google.com> | 2010-01-28 14:27:37 -0800 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2010-01-28 14:27:37 -0800 |
commit | 50a9976892316c033cd90d522ecbfcc8e3c0eb9b (patch) | |
tree | de656510c2e5203cbee3229e1bafc7f9f0fc9440 /media/libstagefright/MPEG4Extractor.cpp | |
parent | 5561ccf4a8db88a2e44eac1b3ed13b4ff53a7f20 (diff) | |
download | frameworks_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.cpp | 119 |
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) { |