CCodec: move Buffers out into a separate file
Seperate Buffers out before we add complex logic to them. Also add
missing documentation.
Bug: 130223947
Test: builds
Change-Id: I8f992cb36499401ee2c6d729aa52f3888a7bcea5
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index d1fa920..00e0c16 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -56,1398 +56,10 @@
using CasStatus = hardware::cas::V1_0::Status;
-/**
- * Base class for representation of buffers at one port.
- */
-class CCodecBufferChannel::Buffers {
-public:
- Buffers(const char *componentName, const char *name = "Buffers")
- : mComponentName(componentName),
- mChannelName(std::string(componentName) + ":" + name),
- mName(mChannelName.c_str()) {
- }
- virtual ~Buffers() = default;
-
- /**
- * Set format for MediaCodec-facing buffers.
- */
- void setFormat(const sp<AMessage> &format) {
- CHECK(format != nullptr);
- mFormat = format;
- }
-
- /**
- * Return a copy of current format.
- */
- sp<AMessage> dupFormat() {
- return mFormat != nullptr ? mFormat->dup() : nullptr;
- }
-
- /**
- * Returns true if the buffers are operating under array mode.
- */
- virtual bool isArrayMode() const { return false; }
-
- /**
- * Fills the vector with MediaCodecBuffer's if in array mode; otherwise,
- * no-op.
- */
- virtual void getArray(Vector<sp<MediaCodecBuffer>> *) const {}
-
- /**
- * Return number of buffers the client owns.
- */
- virtual size_t numClientBuffers() const = 0;
-
- void handleImageData(const sp<Codec2Buffer> &buffer) {
- sp<ABuffer> imageDataCandidate = buffer->getImageData();
- if (imageDataCandidate == nullptr) {
- return;
- }
- sp<ABuffer> imageData;
- if (!mFormat->findBuffer("image-data", &imageData)
- || imageDataCandidate->size() != imageData->size()
- || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
- ALOGD("[%s] updating image-data", mName);
- sp<AMessage> newFormat = dupFormat();
- newFormat->setBuffer("image-data", imageDataCandidate);
- MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
- if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
- int32_t stride = img->mPlane[0].mRowInc;
- newFormat->setInt32(KEY_STRIDE, stride);
- ALOGD("[%s] updating stride = %d", mName, stride);
- if (img->mNumPlanes > 1 && stride > 0) {
- int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
- newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
- ALOGD("[%s] updating vstride = %d", mName, vstride);
- }
- }
- setFormat(newFormat);
- buffer->setFormat(newFormat);
- }
- }
-
-protected:
- std::string mComponentName; ///< name of component for debugging
- std::string mChannelName; ///< name of channel for debugging
- const char *mName; ///< C-string version of channel name
- // Format to be used for creating MediaCodec-facing buffers.
- sp<AMessage> mFormat;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(Buffers);
-};
-
-class CCodecBufferChannel::InputBuffers : public CCodecBufferChannel::Buffers {
-public:
- InputBuffers(const char *componentName, const char *name = "Input[]")
- : Buffers(componentName, name) { }
- virtual ~InputBuffers() = default;
-
- /**
- * Set a block pool to obtain input memory blocks.
- */
- void setPool(const std::shared_ptr<C2BlockPool> &pool) { mPool = pool; }
-
- /**
- * Get a new MediaCodecBuffer for input and its corresponding index.
- * Returns false if no new buffer can be obtained at the moment.
- */
- virtual bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) = 0;
-
- /**
- * Release the buffer obtained from requestNewBuffer() and get the
- * associated C2Buffer object back. Returns true if the buffer was on file
- * and released successfully.
- */
- virtual bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer,
- std::shared_ptr<C2Buffer> *c2buffer,
- bool release) = 0;
-
- /**
- * Release the buffer that is no longer used by the codec process. Return
- * true if and only if the buffer was on file and released successfully.
- */
- virtual bool expireComponentBuffer(
- const std::shared_ptr<C2Buffer> &c2buffer) = 0;
-
- /**
- * Flush internal state. After this call, no index or buffer previously
- * returned from requestNewBuffer() is valid.
- */
- virtual void flush() = 0;
-
- /**
- * Return array-backed version of input buffers. The returned object
- * shall retain the internal state so that it will honor index and
- * buffer from previous calls of requestNewBuffer().
- */
- virtual std::unique_ptr<InputBuffers> toArrayMode(size_t size) = 0;
-
-protected:
- // Pool to obtain blocks for input buffers.
- std::shared_ptr<C2BlockPool> mPool;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(InputBuffers);
-};
-
-class CCodecBufferChannel::OutputBuffers : public CCodecBufferChannel::Buffers {
-public:
- OutputBuffers(const char *componentName, const char *name = "Output")
- : Buffers(componentName, name) { }
- virtual ~OutputBuffers() = default;
-
- /**
- * Register output C2Buffer from the component and obtain corresponding
- * index and MediaCodecBuffer object. Returns false if registration
- * fails.
- */
- virtual status_t registerBuffer(
- const std::shared_ptr<C2Buffer> &buffer,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) = 0;
-
- /**
- * Register codec specific data as a buffer to be consistent with
- * MediaCodec behavior.
- */
- virtual status_t registerCsd(
- const C2StreamInitDataInfo::output * /* csd */,
- size_t * /* index */,
- sp<MediaCodecBuffer> * /* clientBuffer */) = 0;
-
- /**
- * Release the buffer obtained from registerBuffer() and get the
- * associated C2Buffer object back. Returns true if the buffer was on file
- * and released successfully.
- */
- virtual bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0;
-
- /**
- * Flush internal state. After this call, no index or buffer previously
- * returned from registerBuffer() is valid.
- */
- virtual void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) = 0;
-
- /**
- * Return array-backed version of output buffers. The returned object
- * shall retain the internal state so that it will honor index and
- * buffer from previous calls of registerBuffer().
- */
- virtual std::unique_ptr<OutputBuffers> toArrayMode(size_t size) = 0;
-
- /**
- * Initialize SkipCutBuffer object.
- */
- void initSkipCutBuffer(
- int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
- CHECK(mSkipCutBuffer == nullptr);
- mDelay = delay;
- mPadding = padding;
- mSampleRate = sampleRate;
- setSkipCutBuffer(delay, padding, channelCount);
- }
-
- /**
- * Update the SkipCutBuffer object. No-op if it's never initialized.
- */
- void updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
- if (mSkipCutBuffer == nullptr) {
- return;
- }
- int32_t delay = mDelay;
- int32_t padding = mPadding;
- if (sampleRate != mSampleRate) {
- delay = ((int64_t)delay * sampleRate) / mSampleRate;
- padding = ((int64_t)padding * sampleRate) / mSampleRate;
- }
- setSkipCutBuffer(delay, padding, channelCount);
- }
-
- /**
- * Submit buffer to SkipCutBuffer object, if initialized.
- */
- void submit(const sp<MediaCodecBuffer> &buffer) {
- if (mSkipCutBuffer != nullptr) {
- mSkipCutBuffer->submit(buffer);
- }
- }
-
- /**
- * Transfer SkipCutBuffer object to the other Buffers object.
- */
- void transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
- mSkipCutBuffer = scb;
- }
-
-protected:
- sp<SkipCutBuffer> mSkipCutBuffer;
-
-private:
- int32_t mDelay;
- int32_t mPadding;
- int32_t mSampleRate;
-
- void setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) {
- if (mSkipCutBuffer != nullptr) {
- size_t prevSize = mSkipCutBuffer->size();
- if (prevSize != 0u) {
- ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
- }
- }
- mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount);
- }
-
- DISALLOW_EVIL_CONSTRUCTORS(OutputBuffers);
-};
-
namespace {
-const static size_t kSmoothnessFactor = 4;
-const static size_t kRenderingDepth = 3;
-const static size_t kLinearBufferSize = 1048576;
-// This can fit 4K RGBA frame, and most likely client won't need more than this.
-const static size_t kMaxLinearBufferSize = 3840 * 2160 * 4;
-
-/**
- * Simple local buffer pool backed by std::vector.
- */
-class LocalBufferPool : public std::enable_shared_from_this<LocalBufferPool> {
-public:
- /**
- * Create a new LocalBufferPool object.
- *
- * \param poolCapacity max total size of buffers managed by this pool.
- *
- * \return a newly created pool object.
- */
- static std::shared_ptr<LocalBufferPool> Create(size_t poolCapacity) {
- return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
- }
-
- /**
- * Return an ABuffer object whose size is at least |capacity|.
- *
- * \param capacity requested capacity
- * \return nullptr if the pool capacity is reached
- * an ABuffer object otherwise.
- */
- sp<ABuffer> newBuffer(size_t capacity) {
- Mutex::Autolock lock(mMutex);
- auto it = std::find_if(
- mPool.begin(), mPool.end(),
- [capacity](const std::vector<uint8_t> &vec) {
- return vec.capacity() >= capacity;
- });
- if (it != mPool.end()) {
- sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
- mPool.erase(it);
- return buffer;
- }
- if (mUsedSize + capacity > mPoolCapacity) {
- while (!mPool.empty()) {
- mUsedSize -= mPool.back().capacity();
- mPool.pop_back();
- }
- if (mUsedSize + capacity > mPoolCapacity) {
- ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
- mUsedSize, capacity, mPoolCapacity);
- return nullptr;
- }
- }
- std::vector<uint8_t> vec(capacity);
- mUsedSize += vec.capacity();
- return new VectorBuffer(std::move(vec), shared_from_this());
- }
-
-private:
- /**
- * ABuffer backed by std::vector.
- */
- class VectorBuffer : public ::android::ABuffer {
- public:
- /**
- * Construct a VectorBuffer by taking the ownership of supplied vector.
- *
- * \param vec backing vector of the buffer. this object takes
- * ownership at construction.
- * \param pool a LocalBufferPool object to return the vector at
- * destruction.
- */
- VectorBuffer(std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
- : ABuffer(vec.data(), vec.capacity()),
- mVec(std::move(vec)),
- mPool(pool) {
- }
-
- ~VectorBuffer() override {
- std::shared_ptr<LocalBufferPool> pool = mPool.lock();
- if (pool) {
- // If pool is alive, return the vector back to the pool so that
- // it can be recycled.
- pool->returnVector(std::move(mVec));
- }
- }
-
- private:
- std::vector<uint8_t> mVec;
- std::weak_ptr<LocalBufferPool> mPool;
- };
-
- Mutex mMutex;
- size_t mPoolCapacity;
- size_t mUsedSize;
- std::list<std::vector<uint8_t>> mPool;
-
- /**
- * Private constructor to prevent constructing non-managed LocalBufferPool.
- */
- explicit LocalBufferPool(size_t poolCapacity)
- : mPoolCapacity(poolCapacity), mUsedSize(0) {
- }
-
- /**
- * Take back the ownership of vec from the destructed VectorBuffer and put
- * it in front of the pool.
- */
- void returnVector(std::vector<uint8_t> &&vec) {
- Mutex::Autolock lock(mMutex);
- mPool.push_front(std::move(vec));
- }
-
- DISALLOW_EVIL_CONSTRUCTORS(LocalBufferPool);
-};
-
-sp<GraphicBlockBuffer> AllocateGraphicBuffer(
- const std::shared_ptr<C2BlockPool> &pool,
- const sp<AMessage> &format,
- uint32_t pixelFormat,
- const C2MemoryUsage &usage,
- const std::shared_ptr<LocalBufferPool> &localBufferPool) {
- int32_t width, height;
- if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
- ALOGD("format lacks width or height");
- return nullptr;
- }
-
- std::shared_ptr<C2GraphicBlock> block;
- c2_status_t err = pool->fetchGraphicBlock(
- width, height, pixelFormat, usage, &block);
- if (err != C2_OK) {
- ALOGD("fetch graphic block failed: %d", err);
- return nullptr;
- }
-
- return GraphicBlockBuffer::Allocate(
- format,
- block,
- [localBufferPool](size_t capacity) {
- return localBufferPool->newBuffer(capacity);
- });
-}
-
-class BuffersArrayImpl;
-
-/**
- * Flexible buffer slots implementation.
- */
-class FlexBuffersImpl {
-public:
- FlexBuffersImpl(const char *name)
- : mImplName(std::string(name) + ".Impl"),
- mName(mImplName.c_str()) { }
-
- /**
- * Assign an empty slot for a buffer and return the index. If there's no
- * empty slot, just add one at the end and return it.
- *
- * \param buffer[in] a new buffer to assign a slot.
- * \return index of the assigned slot.
- */
- size_t assignSlot(const sp<Codec2Buffer> &buffer) {
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- if (mBuffers[i].clientBuffer == nullptr
- && mBuffers[i].compBuffer.expired()) {
- mBuffers[i].clientBuffer = buffer;
- return i;
- }
- }
- mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
- return mBuffers.size() - 1;
- }
-
- /**
- * Release the slot from the client, and get the C2Buffer object back from
- * the previously assigned buffer. Note that the slot is not completely free
- * until the returned C2Buffer object is freed.
- *
- * \param buffer[in] the buffer previously assigned a slot.
- * \param c2buffer[in,out] pointer to C2Buffer to be populated. Ignored
- * if null.
- * \return true if the buffer is successfully released from a slot
- * false otherwise
- */
- bool releaseSlot(
- const sp<MediaCodecBuffer> &buffer,
- std::shared_ptr<C2Buffer> *c2buffer,
- bool release) {
- sp<Codec2Buffer> clientBuffer;
- size_t index = mBuffers.size();
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- if (mBuffers[i].clientBuffer == buffer) {
- clientBuffer = mBuffers[i].clientBuffer;
- if (release) {
- mBuffers[i].clientBuffer.clear();
- }
- index = i;
- break;
- }
- }
- if (clientBuffer == nullptr) {
- ALOGV("[%s] %s: No matching buffer found", mName, __func__);
- return false;
- }
- std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
- if (!result) {
- result = clientBuffer->asC2Buffer();
- mBuffers[index].compBuffer = result;
- }
- if (c2buffer) {
- *c2buffer = result;
- }
- return true;
- }
-
- bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- std::shared_ptr<C2Buffer> compBuffer =
- mBuffers[i].compBuffer.lock();
- if (!compBuffer || compBuffer != c2buffer) {
- continue;
- }
- mBuffers[i].compBuffer.reset();
- ALOGV("[%s] codec released buffer #%zu", mName, i);
- return true;
- }
- ALOGV("[%s] codec released an unknown buffer", mName);
- return false;
- }
-
- void flush() {
- ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
- mBuffers.clear();
- }
-
- size_t numClientBuffers() const {
- return std::count_if(
- mBuffers.begin(), mBuffers.end(),
- [](const Entry &entry) {
- return (entry.clientBuffer != nullptr);
- });
- }
-
-private:
- friend class BuffersArrayImpl;
-
- std::string mImplName; ///< name for debugging
- const char *mName; ///< C-string version of name
-
- struct Entry {
- sp<Codec2Buffer> clientBuffer;
- std::weak_ptr<C2Buffer> compBuffer;
- };
- std::vector<Entry> mBuffers;
-};
-
-/**
- * Static buffer slots implementation based on a fixed-size array.
- */
-class BuffersArrayImpl {
-public:
- BuffersArrayImpl()
- : mImplName("BuffersArrayImpl"),
- mName(mImplName.c_str()) { }
-
- /**
- * Initialize buffer array from the original |impl|. The buffers known by
- * the client is preserved, and the empty slots are populated so that the
- * array size is at least |minSize|.
- *
- * \param impl[in] FlexBuffersImpl object used so far.
- * \param minSize[in] minimum size of the buffer array.
- * \param allocate[in] function to allocate a client buffer for an empty slot.
- */
- void initialize(
- const FlexBuffersImpl &impl,
- size_t minSize,
- std::function<sp<Codec2Buffer>()> allocate) {
- mImplName = impl.mImplName + "[N]";
- mName = mImplName.c_str();
- for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
- sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
- bool ownedByClient = (clientBuffer != nullptr);
- if (!ownedByClient) {
- clientBuffer = allocate();
- }
- mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
- }
- ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
- for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
- mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
- }
- }
-
- /**
- * Grab a buffer from the underlying array which matches the criteria.
- *
- * \param index[out] index of the slot.
- * \param buffer[out] the matching buffer.
- * \param match[in] a function to test whether the buffer matches the
- * criteria or not.
- * \return OK if successful,
- * WOULD_BLOCK if slots are being used,
- * NO_MEMORY if no slot matches the criteria, even though it's
- * available
- */
- status_t grabBuffer(
- size_t *index,
- sp<Codec2Buffer> *buffer,
- std::function<bool(const sp<Codec2Buffer> &)> match =
- [](const sp<Codec2Buffer> &) { return true; }) {
- // allBuffersDontMatch remains true if all buffers are available but
- // match() returns false for every buffer.
- bool allBuffersDontMatch = true;
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
- if (match(mBuffers[i].clientBuffer)) {
- mBuffers[i].ownedByClient = true;
- *buffer = mBuffers[i].clientBuffer;
- (*buffer)->meta()->clear();
- (*buffer)->setRange(0, (*buffer)->capacity());
- *index = i;
- return OK;
- }
- } else {
- allBuffersDontMatch = false;
- }
- }
- return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
- }
-
- /**
- * Return the buffer from the client, and get the C2Buffer object back from
- * the buffer. Note that the slot is not completely free until the returned
- * C2Buffer object is freed.
- *
- * \param buffer[in] the buffer previously grabbed.
- * \param c2buffer[in,out] pointer to C2Buffer to be populated. Ignored
- * if null.
- * \return true if the buffer is successfully returned
- * false otherwise
- */
- bool returnBuffer(
- const sp<MediaCodecBuffer> &buffer,
- std::shared_ptr<C2Buffer> *c2buffer,
- bool release) {
- sp<Codec2Buffer> clientBuffer;
- size_t index = mBuffers.size();
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- if (mBuffers[i].clientBuffer == buffer) {
- if (!mBuffers[i].ownedByClient) {
- ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu", mName, i);
- }
- clientBuffer = mBuffers[i].clientBuffer;
- if (release) {
- mBuffers[i].ownedByClient = false;
- }
- index = i;
- break;
- }
- }
- if (clientBuffer == nullptr) {
- ALOGV("[%s] %s: No matching buffer found", mName, __func__);
- return false;
- }
- ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
- std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
- if (!result) {
- result = clientBuffer->asC2Buffer();
- mBuffers[index].compBuffer = result;
- }
- if (c2buffer) {
- *c2buffer = result;
- }
- return true;
- }
-
- bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- std::shared_ptr<C2Buffer> compBuffer =
- mBuffers[i].compBuffer.lock();
- if (!compBuffer) {
- continue;
- }
- if (c2buffer == compBuffer) {
- if (mBuffers[i].ownedByClient) {
- // This should not happen.
- ALOGD("[%s] codec released a buffer owned by client "
- "(index %zu)", mName, i);
- }
- mBuffers[i].compBuffer.reset();
- ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
- return true;
- }
- }
- ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
- return false;
- }
-
- /**
- * Populate |array| with the underlying buffer array.
- *
- * \param array[out] an array to be filled with the underlying buffer array.
- */
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const {
- array->clear();
- for (const Entry &entry : mBuffers) {
- array->push(entry.clientBuffer);
- }
- }
-
- /**
- * The client abandoned all known buffers, so reclaim the ownership.
- */
- void flush() {
- for (Entry &entry : mBuffers) {
- entry.ownedByClient = false;
- }
- }
-
- void realloc(std::function<sp<Codec2Buffer>()> alloc) {
- size_t size = mBuffers.size();
- mBuffers.clear();
- for (size_t i = 0; i < size; ++i) {
- mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
- }
- }
-
- size_t numClientBuffers() const {
- return std::count_if(
- mBuffers.begin(), mBuffers.end(),
- [](const Entry &entry) {
- return entry.ownedByClient;
- });
- }
-
-private:
- std::string mImplName; ///< name for debugging
- const char *mName; ///< C-string version of name
-
- struct Entry {
- const sp<Codec2Buffer> clientBuffer;
- std::weak_ptr<C2Buffer> compBuffer;
- bool ownedByClient;
- };
- std::vector<Entry> mBuffers;
-};
-
-class InputBuffersArray : public CCodecBufferChannel::InputBuffers {
-public:
- InputBuffersArray(const char *componentName, const char *name = "Input[N]")
- : InputBuffers(componentName, name) { }
- ~InputBuffersArray() override = default;
-
- void initialize(
- const FlexBuffersImpl &impl,
- size_t minSize,
- std::function<sp<Codec2Buffer>()> allocate) {
- mImpl.initialize(impl, minSize, allocate);
- }
-
- bool isArrayMode() const final { return true; }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
- size_t) final {
- return nullptr;
- }
-
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
- mImpl.getArray(array);
- }
-
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- sp<Codec2Buffer> c2Buffer;
- status_t err = mImpl.grabBuffer(index, &c2Buffer);
- if (err == OK) {
- c2Buffer->setFormat(mFormat);
- handleImageData(c2Buffer);
- *buffer = c2Buffer;
- return true;
- }
- return false;
- }
-
- bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer,
- std::shared_ptr<C2Buffer> *c2buffer,
- bool release) override {
- return mImpl.returnBuffer(buffer, c2buffer, release);
- }
-
- bool expireComponentBuffer(
- const std::shared_ptr<C2Buffer> &c2buffer) override {
- return mImpl.expireComponentBuffer(c2buffer);
- }
-
- void flush() override {
- mImpl.flush();
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
-private:
- BuffersArrayImpl mImpl;
-};
-
-class LinearInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
- LinearInputBuffers(const char *componentName, const char *name = "1D-Input")
- : InputBuffers(componentName, name),
- mImpl(mName) { }
-
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- int32_t capacity = kLinearBufferSize;
- (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
- if ((size_t)capacity > kMaxLinearBufferSize) {
- ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
- capacity = kMaxLinearBufferSize;
- }
- // TODO: proper max input size
- // TODO: read usage from intf
- sp<Codec2Buffer> newBuffer = alloc((size_t)capacity);
- if (newBuffer == nullptr) {
- return false;
- }
- *index = mImpl.assignSlot(newBuffer);
- *buffer = newBuffer;
- return true;
- }
-
- bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer,
- std::shared_ptr<C2Buffer> *c2buffer,
- bool release) override {
- return mImpl.releaseSlot(buffer, c2buffer, release);
- }
-
- bool expireComponentBuffer(
- const std::shared_ptr<C2Buffer> &c2buffer) override {
- return mImpl.expireComponentBuffer(c2buffer);
- }
-
- void flush() override {
- // This is no-op by default unless we're in array mode where we need to keep
- // track of the flushed work.
- mImpl.flush();
- }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
- size_t size) final {
- int32_t capacity = kLinearBufferSize;
- (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
- if ((size_t)capacity > kMaxLinearBufferSize) {
- ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
- capacity = kMaxLinearBufferSize;
- }
- // TODO: proper max input size
- // TODO: read usage from intf
- std::unique_ptr<InputBuffersArray> array(
- new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
- array->setPool(mPool);
- array->setFormat(mFormat);
- array->initialize(
- mImpl,
- size,
- [this, capacity] () -> sp<Codec2Buffer> { return alloc(capacity); });
- return std::move(array);
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
- virtual sp<Codec2Buffer> alloc(size_t size) {
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- std::shared_ptr<C2LinearBlock> block;
-
- c2_status_t err = mPool->fetchLinearBlock(size, usage, &block);
- if (err != C2_OK) {
- return nullptr;
- }
-
- return LinearBlockBuffer::Allocate(mFormat, block);
- }
-
-private:
- FlexBuffersImpl mImpl;
-};
-
-class EncryptedLinearInputBuffers : public LinearInputBuffers {
-public:
- EncryptedLinearInputBuffers(
- bool secure,
- const sp<MemoryDealer> &dealer,
- const sp<ICrypto> &crypto,
- int32_t heapSeqNum,
- size_t capacity,
- size_t numInputSlots,
- const char *componentName, const char *name = "EncryptedInput")
- : LinearInputBuffers(componentName, name),
- mUsage({0, 0}),
- mDealer(dealer),
- mCrypto(crypto),
- mHeapSeqNum(heapSeqNum) {
- if (secure) {
- mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
- } else {
- mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- }
- for (size_t i = 0; i < numInputSlots; ++i) {
- sp<IMemory> memory = mDealer->allocate(capacity);
- if (memory == nullptr) {
- ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated", mName, i);
- break;
- }
- mMemoryVector.push_back({std::weak_ptr<C2LinearBlock>(), memory});
- }
- }
-
- ~EncryptedLinearInputBuffers() override {
- }
-
- sp<Codec2Buffer> alloc(size_t size) override {
- sp<IMemory> memory;
- size_t slot = 0;
- for (; slot < mMemoryVector.size(); ++slot) {
- if (mMemoryVector[slot].block.expired()) {
- memory = mMemoryVector[slot].memory;
- break;
- }
- }
- if (memory == nullptr) {
- return nullptr;
- }
-
- std::shared_ptr<C2LinearBlock> block;
- c2_status_t err = mPool->fetchLinearBlock(size, mUsage, &block);
- if (err != C2_OK || block == nullptr) {
- return nullptr;
- }
-
- mMemoryVector[slot].block = block;
- return new EncryptedLinearBlockBuffer(mFormat, block, memory, mHeapSeqNum);
- }
-
-private:
- C2MemoryUsage mUsage;
- sp<MemoryDealer> mDealer;
- sp<ICrypto> mCrypto;
- int32_t mHeapSeqNum;
- struct Entry {
- std::weak_ptr<C2LinearBlock> block;
- sp<IMemory> memory;
- };
- std::vector<Entry> mMemoryVector;
-};
-
-class GraphicMetadataInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
- GraphicMetadataInputBuffers(const char *componentName, const char *name = "2D-MetaInput")
- : InputBuffers(componentName, name),
- mImpl(mName),
- mStore(GetCodec2PlatformAllocatorStore()) { }
- ~GraphicMetadataInputBuffers() override = default;
-
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- std::shared_ptr<C2Allocator> alloc;
- c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
- if (err != C2_OK) {
- return false;
- }
- sp<GraphicMetadataBuffer> newBuffer = new GraphicMetadataBuffer(mFormat, alloc);
- if (newBuffer == nullptr) {
- return false;
- }
- *index = mImpl.assignSlot(newBuffer);
- *buffer = newBuffer;
- return true;
- }
-
- bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer,
- std::shared_ptr<C2Buffer> *c2buffer,
- bool release) override {
- return mImpl.releaseSlot(buffer, c2buffer, release);
- }
-
- bool expireComponentBuffer(
- const std::shared_ptr<C2Buffer> &c2buffer) override {
- return mImpl.expireComponentBuffer(c2buffer);
- }
-
- void flush() override {
- // This is no-op by default unless we're in array mode where we need to keep
- // track of the flushed work.
- }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
- size_t size) final {
- std::shared_ptr<C2Allocator> alloc;
- c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
- if (err != C2_OK) {
- return nullptr;
- }
- std::unique_ptr<InputBuffersArray> array(
- new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
- array->setPool(mPool);
- array->setFormat(mFormat);
- array->initialize(
- mImpl,
- size,
- [format = mFormat, alloc]() -> sp<Codec2Buffer> {
- return new GraphicMetadataBuffer(format, alloc);
- });
- return std::move(array);
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
-private:
- FlexBuffersImpl mImpl;
- std::shared_ptr<C2AllocatorStore> mStore;
-};
-
-class GraphicInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
- GraphicInputBuffers(
- size_t numInputSlots, const char *componentName, const char *name = "2D-BB-Input")
- : InputBuffers(componentName, name),
- mImpl(mName),
- mLocalBufferPool(LocalBufferPool::Create(
- kMaxLinearBufferSize * numInputSlots)) { }
- ~GraphicInputBuffers() override = default;
-
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- // TODO: proper max input size
- // TODO: read usage from intf
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- sp<GraphicBlockBuffer> newBuffer = AllocateGraphicBuffer(
- mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
- if (newBuffer == nullptr) {
- return false;
- }
- *index = mImpl.assignSlot(newBuffer);
- handleImageData(newBuffer);
- *buffer = newBuffer;
- return true;
- }
-
- bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer,
- std::shared_ptr<C2Buffer> *c2buffer,
- bool release) override {
- return mImpl.releaseSlot(buffer, c2buffer, release);
- }
-
- bool expireComponentBuffer(
- const std::shared_ptr<C2Buffer> &c2buffer) override {
- return mImpl.expireComponentBuffer(c2buffer);
- }
-
- void flush() override {
- // This is no-op by default unless we're in array mode where we need to keep
- // track of the flushed work.
- }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
- size_t size) final {
- std::unique_ptr<InputBuffersArray> array(
- new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
- array->setPool(mPool);
- array->setFormat(mFormat);
- array->initialize(
- mImpl,
- size,
- [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- return AllocateGraphicBuffer(
- pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
- });
- return std::move(array);
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
-private:
- FlexBuffersImpl mImpl;
- std::shared_ptr<LocalBufferPool> mLocalBufferPool;
-};
-
-class DummyInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
- DummyInputBuffers(const char *componentName, const char *name = "2D-Input")
- : InputBuffers(componentName, name) { }
-
- bool requestNewBuffer(size_t *, sp<MediaCodecBuffer> *) override {
- return false;
- }
-
- bool releaseBuffer(
- const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *, bool) override {
- return false;
- }
-
- bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &) override {
- return false;
- }
- void flush() override {
- }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
- size_t) final {
- return nullptr;
- }
-
- bool isArrayMode() const final { return true; }
-
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
- array->clear();
- }
-
- size_t numClientBuffers() const final {
- return 0u;
- }
-};
-
-class OutputBuffersArray : public CCodecBufferChannel::OutputBuffers {
-public:
- OutputBuffersArray(const char *componentName, const char *name = "Output[N]")
- : OutputBuffers(componentName, name) { }
- ~OutputBuffersArray() override = default;
-
- void initialize(
- const FlexBuffersImpl &impl,
- size_t minSize,
- std::function<sp<Codec2Buffer>()> allocate) {
- mImpl.initialize(impl, minSize, allocate);
- }
-
- bool isArrayMode() const final { return true; }
-
- std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode(
- size_t) final {
- return nullptr;
- }
-
- status_t registerBuffer(
- const std::shared_ptr<C2Buffer> &buffer,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) final {
- sp<Codec2Buffer> c2Buffer;
- status_t err = mImpl.grabBuffer(
- index,
- &c2Buffer,
- [buffer](const sp<Codec2Buffer> &clientBuffer) {
- return clientBuffer->canCopy(buffer);
- });
- if (err == WOULD_BLOCK) {
- ALOGV("[%s] buffers temporarily not available", mName);
- return err;
- } else if (err != OK) {
- ALOGD("[%s] grabBuffer failed: %d", mName, err);
- return err;
- }
- c2Buffer->setFormat(mFormat);
- if (!c2Buffer->copy(buffer)) {
- ALOGD("[%s] copy buffer failed", mName);
- return WOULD_BLOCK;
- }
- submit(c2Buffer);
- handleImageData(c2Buffer);
- *clientBuffer = c2Buffer;
- ALOGV("[%s] grabbed buffer %zu", mName, *index);
- return OK;
- }
-
- status_t registerCsd(
- const C2StreamInitDataInfo::output *csd,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) final {
- sp<Codec2Buffer> c2Buffer;
- status_t err = mImpl.grabBuffer(
- index,
- &c2Buffer,
- [csd](const sp<Codec2Buffer> &clientBuffer) {
- return clientBuffer->base() != nullptr
- && clientBuffer->capacity() >= csd->flexCount();
- });
- if (err != OK) {
- return err;
- }
- memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
- c2Buffer->setRange(0, csd->flexCount());
- c2Buffer->setFormat(mFormat);
- *clientBuffer = c2Buffer;
- return OK;
- }
-
- bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.returnBuffer(buffer, c2buffer, true);
- }
-
- void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
- (void)flushedWork;
- mImpl.flush();
- if (mSkipCutBuffer != nullptr) {
- mSkipCutBuffer->clear();
- }
- }
-
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
- mImpl.getArray(array);
- }
-
- void realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
- std::function<sp<Codec2Buffer>()> alloc;
- switch (c2buffer->data().type()) {
- case C2BufferData::LINEAR: {
- uint32_t size = kLinearBufferSize;
- const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
- if (block.size() < kMaxLinearBufferSize / 2) {
- size = block.size() * 2;
- } else {
- size = kMaxLinearBufferSize;
- }
- alloc = [format = mFormat, size] {
- return new LocalLinearBuffer(format, new ABuffer(size));
- };
- break;
- }
-
- // TODO: add support
- case C2BufferData::GRAPHIC: FALLTHROUGH_INTENDED;
-
- case C2BufferData::INVALID: FALLTHROUGH_INTENDED;
- case C2BufferData::LINEAR_CHUNKS: FALLTHROUGH_INTENDED;
- case C2BufferData::GRAPHIC_CHUNKS: FALLTHROUGH_INTENDED;
- default:
- ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
- return;
- }
- mImpl.realloc(alloc);
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
-private:
- BuffersArrayImpl mImpl;
-};
-
-class FlexOutputBuffers : public CCodecBufferChannel::OutputBuffers {
-public:
- FlexOutputBuffers(const char *componentName, const char *name = "Output[]")
- : OutputBuffers(componentName, name),
- mImpl(mName) { }
-
- status_t registerBuffer(
- const std::shared_ptr<C2Buffer> &buffer,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) override {
- sp<Codec2Buffer> newBuffer = wrap(buffer);
- if (newBuffer == nullptr) {
- return NO_MEMORY;
- }
- newBuffer->setFormat(mFormat);
- *index = mImpl.assignSlot(newBuffer);
- handleImageData(newBuffer);
- *clientBuffer = newBuffer;
- ALOGV("[%s] registered buffer %zu", mName, *index);
- return OK;
- }
-
- status_t registerCsd(
- const C2StreamInitDataInfo::output *csd,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) final {
- sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
- mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
- *index = mImpl.assignSlot(newBuffer);
- *clientBuffer = newBuffer;
- return OK;
- }
-
- bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer,
- std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.releaseSlot(buffer, c2buffer, true);
- }
-
- void flush(
- const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
- (void) flushedWork;
- // This is no-op by default unless we're in array mode where we need to keep
- // track of the flushed work.
- }
-
- std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode(
- size_t size) override {
- std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
- array->setFormat(mFormat);
- array->transferSkipCutBuffer(mSkipCutBuffer);
- array->initialize(
- mImpl,
- size,
- [this]() { return allocateArrayBuffer(); });
- return std::move(array);
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
- /**
- * Return an appropriate Codec2Buffer object for the type of buffers.
- *
- * \param buffer C2Buffer object to wrap.
- *
- * \return appropriate Codec2Buffer object to wrap |buffer|.
- */
- virtual sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) = 0;
-
- /**
- * Return an appropriate Codec2Buffer object for the type of buffers, to be
- * used as an empty array buffer.
- *
- * \return appropriate Codec2Buffer object which can copy() from C2Buffers.
- */
- virtual sp<Codec2Buffer> allocateArrayBuffer() = 0;
-
-private:
- FlexBuffersImpl mImpl;
-};
-
-class LinearOutputBuffers : public FlexOutputBuffers {
-public:
- LinearOutputBuffers(const char *componentName, const char *name = "1D-Output")
- : FlexOutputBuffers(componentName, name) { }
-
- void flush(
- const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
- if (mSkipCutBuffer != nullptr) {
- mSkipCutBuffer->clear();
- }
- FlexOutputBuffers::flush(flushedWork);
- }
-
- sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
- if (buffer == nullptr) {
- ALOGV("[%s] using a dummy buffer", mName);
- return new LocalLinearBuffer(mFormat, new ABuffer(0));
- }
- if (buffer->data().type() != C2BufferData::LINEAR) {
- ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
- // We expect linear output buffers from the component.
- return nullptr;
- }
- if (buffer->data().linearBlocks().size() != 1u) {
- ALOGV("[%s] no linear buffers", mName);
- // We expect one and only one linear block from the component.
- return nullptr;
- }
- sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
- if (clientBuffer == nullptr) {
- ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
- return nullptr;
- }
- submit(clientBuffer);
- return clientBuffer;
- }
-
- sp<Codec2Buffer> allocateArrayBuffer() override {
- // TODO: proper max output size
- return new LocalLinearBuffer(mFormat, new ABuffer(kLinearBufferSize));
- }
-};
-
-class GraphicOutputBuffers : public FlexOutputBuffers {
-public:
- GraphicOutputBuffers(const char *componentName, const char *name = "2D-Output")
- : FlexOutputBuffers(componentName, name) { }
-
- sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
- return new DummyContainerBuffer(mFormat, buffer);
- }
-
- sp<Codec2Buffer> allocateArrayBuffer() override {
- return new DummyContainerBuffer(mFormat);
- }
-};
-
-class RawGraphicOutputBuffers : public FlexOutputBuffers {
-public:
- RawGraphicOutputBuffers(
- size_t numOutputSlots, const char *componentName, const char *name = "2D-BB-Output")
- : FlexOutputBuffers(componentName, name),
- mLocalBufferPool(LocalBufferPool::Create(
- kMaxLinearBufferSize * numOutputSlots)) { }
- ~RawGraphicOutputBuffers() override = default;
-
- sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
- if (buffer == nullptr) {
- sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
- mFormat,
- [lbp = mLocalBufferPool](size_t capacity) {
- return lbp->newBuffer(capacity);
- });
- if (c2buffer == nullptr) {
- ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
- return nullptr;
- }
- c2buffer->setRange(0, 0);
- return c2buffer;
- } else {
- return ConstGraphicBlockBuffer::Allocate(
- mFormat,
- buffer,
- [lbp = mLocalBufferPool](size_t capacity) {
- return lbp->newBuffer(capacity);
- });
- }
- }
-
- sp<Codec2Buffer> allocateArrayBuffer() override {
- return ConstGraphicBlockBuffer::AllocateEmpty(
- mFormat,
- [lbp = mLocalBufferPool](size_t capacity) {
- return lbp->newBuffer(capacity);
- });
- }
-
-private:
- std::shared_ptr<LocalBufferPool> mLocalBufferPool;
-};
+constexpr size_t kSmoothnessFactor = 4;
+constexpr size_t kRenderingDepth = 3;
} // namespace