blob: e74410d1b04c71e704f45fed7d93341a51172503 [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MEDIA_BUFFER_H_
#define MEDIA_BUFFER_H_
#include <atomic>
#include <list>
#include <media/stagefright/foundation/MediaBufferBase.h>
#include <pthread.h>
#include <binder/MemoryDealer.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
namespace android {
struct ABuffer;
class GraphicBuffer;
class MediaBuffer;
class MediaBufferObserver;
class MetaData;
class MediaBufferObserver {
public:
MediaBufferObserver() {}
virtual ~MediaBufferObserver() {}
virtual void signalBufferReturned(MediaBuffer *buffer) = 0;
private:
MediaBufferObserver(const MediaBufferObserver &);
MediaBufferObserver &operator=(const MediaBufferObserver &);
};
class MediaBuffer : public MediaBufferBase {
public:
// allocations larger than or equal to this will use shared memory.
static const size_t kSharedMemThreshold = 64 * 1024;
// The underlying data remains the responsibility of the caller!
MediaBuffer(void *data, size_t size);
explicit MediaBuffer(size_t size);
explicit MediaBuffer(const sp<GraphicBuffer>& graphicBuffer);
explicit 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;
}
// If MediaBufferGroup is set, decrement the local reference count;
// if the local reference count drops to 0, return the buffer to the
// associated MediaBufferGroup.
//
// If no MediaBufferGroup is set, the local reference count must be zero
// when called, whereupon the MediaBuffer is deleted.
virtual void release();
// Increments the local reference count.
// Use only when MediaBufferGroup is set.
virtual void add_ref();
void *data() const;
size_t size() const;
size_t range_offset() const;
size_t range_length() const;
void set_range(size_t offset, size_t length);
sp<GraphicBuffer> graphicBuffer() const;
sp<MetaData> meta_data();
// Clears meta data and resets the range to the full extent.
void reset();
void setObserver(MediaBufferObserver *group);
// Returns a clone of this MediaBuffer increasing its reference count.
// The clone references the same data but has its own range and
// MetaData.
MediaBuffer *clone();
// sum of localRefcount() and remoteRefcount()
int refcount() const {
return localRefcount() + remoteRefcount();
}
int localRefcount() const {
return mRefCount;
}
int remoteRefcount() const {
if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
int32_t remoteRefcount =
reinterpret_cast<SharedControl *>(mMemory->pointer())->getRemoteRefcount();
// Sanity check so that remoteRefCount() is non-negative.
return remoteRefcount >= 0 ? remoteRefcount : 0; // do not allow corrupted data.
}
// returns old value
int addRemoteRefcount(int32_t value) {
if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
return reinterpret_cast<SharedControl *>(mMemory->pointer())->addRemoteRefcount(value);
}
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();
}
// Sticky on enabling of shared memory MediaBuffers. By default we don't use
// shared memory for MediaBuffers, but we enable this for those processes
// that export MediaBuffers.
static void useSharedMemory() {
std::atomic_store_explicit(
&mUseSharedMemory, (int_least32_t)1, std::memory_order_seq_cst);
}
protected:
// 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;
friend class BnMediaSource;
friend class BpMediaSource;
// For use by OMXDecoder, reference count must be 1, drop reference
// count to 0 without signalling the observer.
void claim();
MediaBufferObserver *mObserver;
int mRefCount;
void *mData;
size_t mSize, mRangeOffset, mRangeLength;
sp<GraphicBuffer> mGraphicBuffer;
sp<ABuffer> mBuffer;
bool mOwnsData;
sp<MetaData> mMetaData;
MediaBuffer *mOriginal;
static std::atomic_int_least32_t mUseSharedMemory;
MediaBuffer(const MediaBuffer &);
MediaBuffer &operator=(const MediaBuffer &);
// SharedControl block at the start of IMemory.
struct SharedControl {
enum {
FLAG_DEAD_OBJECT = (1 << 0),
};
// returns old value
inline int32_t addRemoteRefcount(int32_t value) {
return std::atomic_fetch_add_explicit(
&mRemoteRefcount, (int_least32_t)value, std::memory_order_seq_cst);
}
inline int32_t getRemoteRefcount() const {
return std::atomic_load_explicit(&mRemoteRefcount, std::memory_order_seq_cst);
}
inline void setRemoteRefcount(int32_t value) {
std::atomic_store_explicit(
&mRemoteRefcount, (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(
&mRemoteRefcount, (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 mRemoteRefcount;
int32_t unused[6] __attribute__((__unused__)); // additional buffer space
};
inline SharedControl *getSharedControl() const {
return reinterpret_cast<SharedControl *>(mMemory->pointer());
}
};
} // namespace android
#endif // MEDIA_BUFFER_H_