diff options
author | Chris Watkins <watk@google.com> | 2015-04-07 10:01:15 -0700 |
---|---|---|
committer | Chris Watkins <watk@google.com> | 2015-04-20 10:14:19 -0700 |
commit | da7e453e1d1c77959822cf9602ddfed1c50be445 (patch) | |
tree | 2fed02646af0da50bcfc5deb5c86167c06ddfdd2 /media | |
parent | ee4e1b1a63758941460ae79a064249d3a5189443 (diff) | |
download | frameworks_av-da7e453e1d1c77959822cf9602ddfed1c50be445.zip frameworks_av-da7e453e1d1c77959822cf9602ddfed1c50be445.tar.gz frameworks_av-da7e453e1d1c77959822cf9602ddfed1c50be445.tar.bz2 |
stagefright: add a 2kb cache for CallbackDataSource.
Without a cache the mediaserver does a lot of small reads which result
in round trips through binder and jni to the app MediaDataSource.
On a Nexus 5 I measured time to first frame from MediaPlayer for
1) 1350kbps h264, and 2) 20480kbps vp8. Without a cache, MediaDataSource
was ~250ms slower than an fd. With a 2kb cache it's 30ms slower for (1)
and 70ms slower for (2).
Change-Id: If1e811db7b853c4f79430603318d4744ac30acb9
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/CallbackDataSource.cpp | 52 | ||||
-rw-r--r-- | media/libstagefright/DataSource.cpp | 2 | ||||
-rw-r--r-- | media/libstagefright/include/CallbackDataSource.h | 30 |
3 files changed, 80 insertions, 4 deletions
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp index 2e0745f..41f0175 100644 --- a/media/libstagefright/CallbackDataSource.cpp +++ b/media/libstagefright/CallbackDataSource.cpp @@ -70,9 +70,10 @@ ssize_t CallbackDataSource::readAt(off64_t offset, void* data, size_t size) { if (numRead == 0) { return totalNumRead; } - // Sanity check. - CHECK((size_t)numRead <= numToRead && numRead >= 0 && - (size_t)numRead <= bufferSize); + if ((size_t)numRead > numToRead) { + return ERROR_OUT_OF_RANGE; + } + CHECK(numRead >= 0 && (size_t)numRead <= bufferSize); memcpy(((uint8_t*)data) + totalNumRead, mMemory->pointer(), numRead); numLeft -= numRead; totalNumRead += numRead; @@ -94,4 +95,49 @@ status_t CallbackDataSource::getSize(off64_t *size) { return OK; } +TinyCacheSource::TinyCacheSource(const sp<DataSource>& source) + : mSource(source), mCachedOffset(0), mCachedSize(0) { +} + +status_t TinyCacheSource::initCheck() const { + return mSource->initCheck(); +} + +ssize_t TinyCacheSource::readAt(off64_t offset, void* data, size_t size) { + if (size >= kCacheSize) { + return mSource->readAt(offset, data, size); + } + + // Check if the cache satisfies the read. + if (offset >= mCachedOffset && offset + size <= mCachedOffset + mCachedSize) { + memcpy(data, &mCache[offset - mCachedOffset], size); + return size; + } + + // Fill the cache and copy to the caller. + const ssize_t numRead = mSource->readAt(offset, mCache, kCacheSize); + if (numRead <= 0) { + return numRead; + } + if ((size_t)numRead > kCacheSize) { + return ERROR_OUT_OF_RANGE; + } + + mCachedSize = numRead; + mCachedOffset = offset; + CHECK(mCachedSize <= kCacheSize && mCachedOffset >= 0); + const size_t numToReturn = std::min(size, (size_t)numRead); + memcpy(data, mCache, numToReturn); + + return numToReturn; +} + +status_t TinyCacheSource::getSize(off64_t *size) { + return mSource->getSize(size); +} + +uint32_t TinyCacheSource::flags() { + return mSource->flags(); +} + } // namespace android diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 6a89154..75ef288 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -283,7 +283,7 @@ sp<DataSource> DataSource::CreateMediaHTTP(const sp<IMediaHTTPService> &httpServ } sp<DataSource> DataSource::CreateFromIDataSource(const sp<IDataSource> &source) { - return new CallbackDataSource(source); + return new TinyCacheSource(new CallbackDataSource(source)); } String8 DataSource::getMIMEType() const { diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h index 678eb2e..1a21dd3 100644 --- a/media/libstagefright/include/CallbackDataSource.h +++ b/media/libstagefright/include/CallbackDataSource.h @@ -44,6 +44,36 @@ private: DISALLOW_EVIL_CONSTRUCTORS(CallbackDataSource); }; + +// A caching DataSource that wraps a CallbackDataSource. For reads smaller +// than kCacheSize it will read up to kCacheSize ahead and cache it. +// This reduces the number of binder round trips to the IDataSource and has a significant +// impact on time taken for filetype sniffing and metadata extraction. +class TinyCacheSource : public DataSource { +public: + TinyCacheSource(const sp<DataSource>& source); + + virtual status_t initCheck() const; + virtual ssize_t readAt(off64_t offset, void* data, size_t size); + virtual status_t getSize(off64_t* size); + virtual uint32_t flags(); + +private: + // 2kb comes from experimenting with the time-to-first-frame from a MediaPlayer + // with an in-memory MediaDataSource source on a Nexus 5. Beyond 2kb there was + // no improvement. + enum { + kCacheSize = 2048, + }; + + sp<DataSource> mSource; + uint8_t mCache[kCacheSize]; + off64_t mCachedOffset; + size_t mCachedSize; + + DISALLOW_EVIL_CONSTRUCTORS(TinyCacheSource); +}; + }; // namespace android #endif // ANDROID_CALLBACKDATASOURCE_H |