From affa99c52957685f5a5652ab5254b92e729651c7 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Thu, 28 Jan 2010 14:27:37 -0800 Subject: [PATCH] For mpeg4 files streamed through HTTP, cache the entire sampletable metadata chunk in memory if possible. related-to-bug: 2295438 --- media/libstagefright/HTTPDataSource.cpp | 3 + media/libstagefright/MPEG4Extractor.cpp | 119 ++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp index 5564886fd664..e1ddfef836be 100644 --- a/media/libstagefright/HTTPDataSource.cpp +++ b/media/libstagefright/HTTPDataSource.cpp @@ -274,6 +274,9 @@ ssize_t HTTPDataSource::readAt(off_t offset, void *data, size_t size) { ssize_t contentLength = 0; if (mFirstRequest || offset != mBufferOffset + mBufferLength) { if (!mFirstRequest) { + LOGV("new range offset=%ld (old=%ld)", + offset, mBufferOffset + mBufferLength); + mHttp->disconnect(); } mFirstRequest = false; diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index ed12b6d6748c..5370c394d390 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 &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 mSource; + off_t mCachedOffset; + size_t mCachedSize; + uint8_t *mCache; + + void clearCache(); + + MPEG4DataSource(const MPEG4DataSource &); + MPEG4DataSource &operator=(const MPEG4DataSource &); +}; + +MPEG4DataSource::MPEG4DataSource(const sp &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 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) { -- 2.11.0