Loading include/media/IMediaSource.h +96 −10 Original line number Diff line number Diff line Loading @@ -18,14 +18,17 @@ #define IMEDIA_SOURCE_BASE_H_ #include <map> #include <binder/IInterface.h> #include <binder/IMemory.h> #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaErrors.h> namespace android { struct MediaSource; class MetaData; class MediaBuffer; class MediaBufferGroup; class IMediaSource : public IInterface { Loading Loading @@ -56,7 +59,7 @@ public: // a) not request a seek // b) not be late, i.e. lateness_us = 0 struct ReadOptions { enum SeekMode { enum SeekMode : int32_t { SEEK_PREVIOUS_SYNC, SEEK_NEXT_SYNC, SEEK_CLOSEST_SYNC, Loading @@ -72,6 +75,7 @@ public: void clearSeekTo(); bool getSeekTo(int64_t *time_us, SeekMode *mode) const; // TODO: remove this if unused. void setLateBy(int64_t lateness_us); int64_t getLateBy() const; Loading @@ -79,6 +83,11 @@ public: void clearNonBlocking(); bool getNonBlocking() const; // Used to clear all non-persistent options for multiple buffer reads. void clearNonPersistent() { clearSeekTo(); } private: enum Options { kSeekTo_Option = 1, Loading @@ -98,21 +107,26 @@ public: // A result of INFO_FORMAT_CHANGED indicates that the format of this // MediaSource has changed mid-stream, the client can continue reading // but should be prepared for buffers of the new configuration. // // TODO: consider removing read() in favor of readMultiple(). virtual status_t read( MediaBuffer **buffer, const ReadOptions *options = NULL) = 0; // Returns a vector of new buffers of data. The vector size could be // <= |maxNumBuffers|. Used for buffers with small size // since all buffer data are passed back by binder, not shared memory. // Returns a vector of new buffers of data, where the new buffers are added // to the end of the vector. // Call blocks until an error is encountered, or the end of the stream is // reached, or format change is hit, or |kMaxNumReadMultiple| buffers have // been read. // End of stream is signalled by a result of ERROR_END_OF_STREAM. // End of stream is signaled by a result of ERROR_END_OF_STREAM. // A result of INFO_FORMAT_CHANGED indicates that the format of this // MediaSource has changed mid-stream, the client can continue reading // but should be prepared for buffers of the new configuration. // // ReadOptions may be specified. Persistent options apply to all reads; // non-persistent options (e.g. seek) apply only to the first read. virtual status_t readMultiple( Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1) = 0; Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1, const ReadOptions *options = nullptr) = 0; // Returns true if |readMultiple| is supported, otherwise false. virtual bool supportReadMultiple() = 0; Loading Loading @@ -148,20 +162,92 @@ public: } virtual status_t readMultiple( Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */) { Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */, const ReadOptions * /* options = nullptr */) { return ERROR_UNSUPPORTED; } virtual bool supportReadMultiple() { return false; } static const size_t kBinderMediaBuffers = 4; // buffers managed by BnMediaSource protected: virtual ~BnMediaSource(); private: MediaBufferGroup *mGroup; }; uint32_t mBuffersSinceStop; // Buffer tracking variable std::unique_ptr<MediaBufferGroup> mGroup; // To prevent marshalling IMemory with each read transaction, we cache the IMemory pointer // into a map. // // This is converted into an index, which is used to identify the associated memory // on the receiving side. We hold a reference to the IMemory here to ensure it doesn't // change underneath us. struct IndexCache { IndexCache() : mIndex(0) { } // Returns the index of the IMemory stored in cache or 0 if not found. uint64_t lookup(const sp<IMemory> &mem) { auto p = mMemoryToIndex.find(mem.get()); if (p == mMemoryToIndex.end()) { return 0; } if (MediaBuffer::isDeadObject(p->second.first)) { // this object's dead ALOGW("Attempting to lookup a dead IMemory"); (void)mMemoryToIndex.erase(p); return 0; } ALOGW_IF(p->second.first.get() != mem.get(), "Mismatched buffers without reset"); return p->second.second; } // Returns the index of the IMemory stored in the index cache. uint64_t insert(const sp<IMemory> &mem) { auto p = mMemoryToIndex.find(mem.get()); if (p == mMemoryToIndex.end()) { if (mIndex == UINT64_MAX) { ALOGE("Index overflow"); mIndex = 1; // skip overflow condition and hope for the best } else { ++mIndex; } (void)mMemoryToIndex.emplace(// C++11 mem.get(), std::make_pair(mem, mIndex)) std::piecewise_construct, std::forward_as_tuple(mem.get()), std::forward_as_tuple(mem, mIndex)); return mIndex; } ALOGW("IMemory already inserted into cache"); return p->second.second; } void reset() { mMemoryToIndex.clear(); mIndex = 0; } void gc() { for (auto it = mMemoryToIndex.begin(); it != mMemoryToIndex.end(); ) { if (MediaBuffer::isDeadObject(it->second.first)) { it = mMemoryToIndex.erase(it); } else { ++it; } } } private: uint64_t mIndex; // C++14 unordered_map erase on iterator is stable; C++11 has no guarantee. // Could key on uintptr_t instead of IMemory * std::map<IMemory *, std::pair<sp<IMemory>, uint64_t>> mMemoryToIndex; } mIndexCache; }; } // namespace android Loading include/media/stagefright/MediaBuffer.h +92 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ #define MEDIA_BUFFER_H_ #include <atomic> #include <list> #include <media/stagefright/foundation/MediaBufferBase.h> #include <pthread.h> Loading Loading @@ -60,6 +62,12 @@ public: MediaBuffer(const sp<ABuffer> &buffer); MediaBuffer(const sp<IMemory> &mem) : MediaBuffer((uint8_t *)mem->pointer() + sizeof(SharedControl), mem->size()) { // delegate and override mMemory mMemory = mem; } // Decrements the reference count and returns the buffer to its // associated MediaBufferGroup if the reference count drops to 0. virtual void release(); Loading Loading @@ -91,9 +99,44 @@ public: int refcount() const; bool isDeadObject() const { return isDeadObject(mMemory); } static bool isDeadObject(const sp<IMemory> &memory) { if (memory.get() == nullptr || memory->pointer() == nullptr) return false; return reinterpret_cast<SharedControl *>(memory->pointer())->isDeadObject(); } protected: // MediaBuffer remote releases are handled through a // pending release count variable stored in a SharedControl block // at the start of the IMemory. // Returns old value of pending release count. inline int32_t addPendingRelease(int32_t value) { return getSharedControl()->addPendingRelease(value); } // Issues all pending releases (works in parallel). // Assumes there is a MediaBufferObserver. inline void resolvePendingRelease() { if (mMemory.get() == nullptr) return; while (addPendingRelease(-1) > 0) { release(); } addPendingRelease(1); } // true if MediaBuffer is observed (part of a MediaBufferGroup). inline bool isObserved() const { return mObserver != nullptr; } virtual ~MediaBuffer(); sp<IMemory> mMemory; private: friend class MediaBufferGroup; friend class OMXDecoder; Loading @@ -105,7 +148,6 @@ private: void claim(); MediaBufferObserver *mObserver; MediaBuffer *mNextBuffer; int mRefCount; void *mData; Loading @@ -119,12 +161,57 @@ private: MediaBuffer *mOriginal; void setNextBuffer(MediaBuffer *buffer); MediaBuffer *nextBuffer(); MediaBuffer(const MediaBuffer &); MediaBuffer &operator=(const MediaBuffer &); sp<IMemory> mMemory; // SharedControl block at the start of IMemory. struct SharedControl { enum { FLAG_DEAD_OBJECT = (1 << 0), }; // returns old value inline int32_t addPendingRelease(int32_t value) { return std::atomic_fetch_add_explicit( &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst); } inline int32_t getPendingRelease() const { return std::atomic_load_explicit(&mPendingRelease, std::memory_order_seq_cst); } inline void setPendingRelease(int32_t value) { std::atomic_store_explicit( &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst); } inline bool isDeadObject() const { return (std::atomic_load_explicit( &mFlags, std::memory_order_seq_cst) & FLAG_DEAD_OBJECT) != 0; } inline void setDeadObject() { (void)std::atomic_fetch_or_explicit( &mFlags, (int_least32_t)FLAG_DEAD_OBJECT, std::memory_order_seq_cst); } inline void clear() { std::atomic_store_explicit( &mFlags, (int_least32_t)0, std::memory_order_seq_cst); std::atomic_store_explicit( &mPendingRelease, (int_least32_t)0, std::memory_order_seq_cst); } private: // Caution: atomic_int_fast32_t is 64 bits on LP64. std::atomic_int_least32_t mFlags; std::atomic_int_least32_t mPendingRelease; int32_t unused[6]; // additional buffer space }; inline SharedControl *getSharedControl() const { return reinterpret_cast<SharedControl *>(mMemory->pointer()); } }; } // namespace android Loading include/media/stagefright/MediaBufferGroup.h +8 −3 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ class MetaData; class MediaBufferGroup : public MediaBufferObserver { public: MediaBufferGroup(); MediaBufferGroup(size_t growthLimit = 0); ~MediaBufferGroup(); void add_buffer(MediaBuffer *buffer); Loading @@ -45,6 +45,11 @@ public: status_t acquire_buffer( MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0); size_t buffers() const { return mBuffers.size(); } // freeBuffers is the number of free buffers allowed to remain. void gc(size_t freeBuffers = 0); protected: virtual void signalBufferReturned(MediaBuffer *buffer); Loading @@ -53,8 +58,8 @@ private: Mutex mLock; Condition mCondition; MediaBuffer *mFirstBuffer, *mLastBuffer; size_t mGrowthLimit; // Do not automatically grow group larger than this. std::list<MediaBuffer *> mBuffers; MediaBufferGroup(const MediaBufferGroup &); MediaBufferGroup &operator=(const MediaBufferGroup &); Loading media/libmedia/IMediaSource.cpp +201 −196 File changed.Preview size limit exceeded, changes collapsed. Show changes media/libmediaplayerservice/nuplayer/GenericSource.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -1444,7 +1444,7 @@ void NuPlayer::GenericSource::readBuffer( } } options.clearSeekTo(); options.clearNonPersistent(); size_t id = 0; size_t count = mediaBuffers.size(); Loading Loading
include/media/IMediaSource.h +96 −10 Original line number Diff line number Diff line Loading @@ -18,14 +18,17 @@ #define IMEDIA_SOURCE_BASE_H_ #include <map> #include <binder/IInterface.h> #include <binder/IMemory.h> #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaErrors.h> namespace android { struct MediaSource; class MetaData; class MediaBuffer; class MediaBufferGroup; class IMediaSource : public IInterface { Loading Loading @@ -56,7 +59,7 @@ public: // a) not request a seek // b) not be late, i.e. lateness_us = 0 struct ReadOptions { enum SeekMode { enum SeekMode : int32_t { SEEK_PREVIOUS_SYNC, SEEK_NEXT_SYNC, SEEK_CLOSEST_SYNC, Loading @@ -72,6 +75,7 @@ public: void clearSeekTo(); bool getSeekTo(int64_t *time_us, SeekMode *mode) const; // TODO: remove this if unused. void setLateBy(int64_t lateness_us); int64_t getLateBy() const; Loading @@ -79,6 +83,11 @@ public: void clearNonBlocking(); bool getNonBlocking() const; // Used to clear all non-persistent options for multiple buffer reads. void clearNonPersistent() { clearSeekTo(); } private: enum Options { kSeekTo_Option = 1, Loading @@ -98,21 +107,26 @@ public: // A result of INFO_FORMAT_CHANGED indicates that the format of this // MediaSource has changed mid-stream, the client can continue reading // but should be prepared for buffers of the new configuration. // // TODO: consider removing read() in favor of readMultiple(). virtual status_t read( MediaBuffer **buffer, const ReadOptions *options = NULL) = 0; // Returns a vector of new buffers of data. The vector size could be // <= |maxNumBuffers|. Used for buffers with small size // since all buffer data are passed back by binder, not shared memory. // Returns a vector of new buffers of data, where the new buffers are added // to the end of the vector. // Call blocks until an error is encountered, or the end of the stream is // reached, or format change is hit, or |kMaxNumReadMultiple| buffers have // been read. // End of stream is signalled by a result of ERROR_END_OF_STREAM. // End of stream is signaled by a result of ERROR_END_OF_STREAM. // A result of INFO_FORMAT_CHANGED indicates that the format of this // MediaSource has changed mid-stream, the client can continue reading // but should be prepared for buffers of the new configuration. // // ReadOptions may be specified. Persistent options apply to all reads; // non-persistent options (e.g. seek) apply only to the first read. virtual status_t readMultiple( Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1) = 0; Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1, const ReadOptions *options = nullptr) = 0; // Returns true if |readMultiple| is supported, otherwise false. virtual bool supportReadMultiple() = 0; Loading Loading @@ -148,20 +162,92 @@ public: } virtual status_t readMultiple( Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */) { Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */, const ReadOptions * /* options = nullptr */) { return ERROR_UNSUPPORTED; } virtual bool supportReadMultiple() { return false; } static const size_t kBinderMediaBuffers = 4; // buffers managed by BnMediaSource protected: virtual ~BnMediaSource(); private: MediaBufferGroup *mGroup; }; uint32_t mBuffersSinceStop; // Buffer tracking variable std::unique_ptr<MediaBufferGroup> mGroup; // To prevent marshalling IMemory with each read transaction, we cache the IMemory pointer // into a map. // // This is converted into an index, which is used to identify the associated memory // on the receiving side. We hold a reference to the IMemory here to ensure it doesn't // change underneath us. struct IndexCache { IndexCache() : mIndex(0) { } // Returns the index of the IMemory stored in cache or 0 if not found. uint64_t lookup(const sp<IMemory> &mem) { auto p = mMemoryToIndex.find(mem.get()); if (p == mMemoryToIndex.end()) { return 0; } if (MediaBuffer::isDeadObject(p->second.first)) { // this object's dead ALOGW("Attempting to lookup a dead IMemory"); (void)mMemoryToIndex.erase(p); return 0; } ALOGW_IF(p->second.first.get() != mem.get(), "Mismatched buffers without reset"); return p->second.second; } // Returns the index of the IMemory stored in the index cache. uint64_t insert(const sp<IMemory> &mem) { auto p = mMemoryToIndex.find(mem.get()); if (p == mMemoryToIndex.end()) { if (mIndex == UINT64_MAX) { ALOGE("Index overflow"); mIndex = 1; // skip overflow condition and hope for the best } else { ++mIndex; } (void)mMemoryToIndex.emplace(// C++11 mem.get(), std::make_pair(mem, mIndex)) std::piecewise_construct, std::forward_as_tuple(mem.get()), std::forward_as_tuple(mem, mIndex)); return mIndex; } ALOGW("IMemory already inserted into cache"); return p->second.second; } void reset() { mMemoryToIndex.clear(); mIndex = 0; } void gc() { for (auto it = mMemoryToIndex.begin(); it != mMemoryToIndex.end(); ) { if (MediaBuffer::isDeadObject(it->second.first)) { it = mMemoryToIndex.erase(it); } else { ++it; } } } private: uint64_t mIndex; // C++14 unordered_map erase on iterator is stable; C++11 has no guarantee. // Could key on uintptr_t instead of IMemory * std::map<IMemory *, std::pair<sp<IMemory>, uint64_t>> mMemoryToIndex; } mIndexCache; }; } // namespace android Loading
include/media/stagefright/MediaBuffer.h +92 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ #define MEDIA_BUFFER_H_ #include <atomic> #include <list> #include <media/stagefright/foundation/MediaBufferBase.h> #include <pthread.h> Loading Loading @@ -60,6 +62,12 @@ public: MediaBuffer(const sp<ABuffer> &buffer); MediaBuffer(const sp<IMemory> &mem) : MediaBuffer((uint8_t *)mem->pointer() + sizeof(SharedControl), mem->size()) { // delegate and override mMemory mMemory = mem; } // Decrements the reference count and returns the buffer to its // associated MediaBufferGroup if the reference count drops to 0. virtual void release(); Loading Loading @@ -91,9 +99,44 @@ public: int refcount() const; bool isDeadObject() const { return isDeadObject(mMemory); } static bool isDeadObject(const sp<IMemory> &memory) { if (memory.get() == nullptr || memory->pointer() == nullptr) return false; return reinterpret_cast<SharedControl *>(memory->pointer())->isDeadObject(); } protected: // MediaBuffer remote releases are handled through a // pending release count variable stored in a SharedControl block // at the start of the IMemory. // Returns old value of pending release count. inline int32_t addPendingRelease(int32_t value) { return getSharedControl()->addPendingRelease(value); } // Issues all pending releases (works in parallel). // Assumes there is a MediaBufferObserver. inline void resolvePendingRelease() { if (mMemory.get() == nullptr) return; while (addPendingRelease(-1) > 0) { release(); } addPendingRelease(1); } // true if MediaBuffer is observed (part of a MediaBufferGroup). inline bool isObserved() const { return mObserver != nullptr; } virtual ~MediaBuffer(); sp<IMemory> mMemory; private: friend class MediaBufferGroup; friend class OMXDecoder; Loading @@ -105,7 +148,6 @@ private: void claim(); MediaBufferObserver *mObserver; MediaBuffer *mNextBuffer; int mRefCount; void *mData; Loading @@ -119,12 +161,57 @@ private: MediaBuffer *mOriginal; void setNextBuffer(MediaBuffer *buffer); MediaBuffer *nextBuffer(); MediaBuffer(const MediaBuffer &); MediaBuffer &operator=(const MediaBuffer &); sp<IMemory> mMemory; // SharedControl block at the start of IMemory. struct SharedControl { enum { FLAG_DEAD_OBJECT = (1 << 0), }; // returns old value inline int32_t addPendingRelease(int32_t value) { return std::atomic_fetch_add_explicit( &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst); } inline int32_t getPendingRelease() const { return std::atomic_load_explicit(&mPendingRelease, std::memory_order_seq_cst); } inline void setPendingRelease(int32_t value) { std::atomic_store_explicit( &mPendingRelease, (int_least32_t)value, std::memory_order_seq_cst); } inline bool isDeadObject() const { return (std::atomic_load_explicit( &mFlags, std::memory_order_seq_cst) & FLAG_DEAD_OBJECT) != 0; } inline void setDeadObject() { (void)std::atomic_fetch_or_explicit( &mFlags, (int_least32_t)FLAG_DEAD_OBJECT, std::memory_order_seq_cst); } inline void clear() { std::atomic_store_explicit( &mFlags, (int_least32_t)0, std::memory_order_seq_cst); std::atomic_store_explicit( &mPendingRelease, (int_least32_t)0, std::memory_order_seq_cst); } private: // Caution: atomic_int_fast32_t is 64 bits on LP64. std::atomic_int_least32_t mFlags; std::atomic_int_least32_t mPendingRelease; int32_t unused[6]; // additional buffer space }; inline SharedControl *getSharedControl() const { return reinterpret_cast<SharedControl *>(mMemory->pointer()); } }; } // namespace android Loading
include/media/stagefright/MediaBufferGroup.h +8 −3 Original line number Diff line number Diff line Loading @@ -29,7 +29,7 @@ class MetaData; class MediaBufferGroup : public MediaBufferObserver { public: MediaBufferGroup(); MediaBufferGroup(size_t growthLimit = 0); ~MediaBufferGroup(); void add_buffer(MediaBuffer *buffer); Loading @@ -45,6 +45,11 @@ public: status_t acquire_buffer( MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0); size_t buffers() const { return mBuffers.size(); } // freeBuffers is the number of free buffers allowed to remain. void gc(size_t freeBuffers = 0); protected: virtual void signalBufferReturned(MediaBuffer *buffer); Loading @@ -53,8 +58,8 @@ private: Mutex mLock; Condition mCondition; MediaBuffer *mFirstBuffer, *mLastBuffer; size_t mGrowthLimit; // Do not automatically grow group larger than this. std::list<MediaBuffer *> mBuffers; MediaBufferGroup(const MediaBufferGroup &); MediaBufferGroup &operator=(const MediaBufferGroup &); Loading
media/libmedia/IMediaSource.cpp +201 −196 File changed.Preview size limit exceeded, changes collapsed. Show changes
media/libmediaplayerservice/nuplayer/GenericSource.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -1444,7 +1444,7 @@ void NuPlayer::GenericSource::readBuffer( } } options.clearSeekTo(); options.clearNonPersistent(); size_t id = 0; size_t count = mediaBuffers.size(); Loading