Merge "Enable pooled C2BlockPool" into pi-dev
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
index 449c6aa..5ce49d9 100644
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ b/media/libstagefright/CCodecBufferChannel.cpp
@@ -760,19 +760,18 @@
 
         ALOGV("graphic = %s", graphic ? "true" : "false");
         std::shared_ptr<C2BlockPool> pool;
-        err = GetCodec2BlockPool(
-                graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR,
-                component,
-                &pool);
+        if (graphic) {
+            err = GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, component, &pool);
+        } else {
+            err = CreateCodec2BlockPool(C2PlatformAllocatorStore::ION,
+                                        component, &pool);
+        }
+
         if (err == C2_OK) {
             (*buffers)->setPool(pool);
         } else {
             // TODO: error
         }
-        // TODO: remove once we switch to proper buffer pool.
-        if (!graphic) {
-            *buffers = (*buffers)->toArrayMode();
-        }
     }
 
     {
diff --git a/media/libstagefright/codec2/SimpleC2Component.cpp b/media/libstagefright/codec2/SimpleC2Component.cpp
index 333cfeb..0753b08 100644
--- a/media/libstagefright/codec2/SimpleC2Component.cpp
+++ b/media/libstagefright/codec2/SimpleC2Component.cpp
@@ -302,12 +302,15 @@
             if (err != C2_OK) {
                 return err;
             }
-            err = GetCodec2BlockPool(
-                    (outputFormat.value == C2FormatVideo)
-                    ? C2BlockPool::BASIC_GRAPHIC
-                    : C2BlockPool::BASIC_LINEAR,
-                    shared_from_this(),
-                    &mOutputBlockPool);
+            if (outputFormat.value == C2FormatVideo) {
+                err = GetCodec2BlockPool(
+                        C2BlockPool::BASIC_GRAPHIC,
+                        shared_from_this(), &mOutputBlockPool);
+            } else {
+                err = CreateCodec2BlockPool(
+                        C2PlatformAllocatorStore::ION,
+                        shared_from_this(), &mOutputBlockPool);
+            }
             if (err != C2_OK) {
                 return err;
             }
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index 0da3398..f389abc 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -232,7 +232,8 @@
 class C2BufferTest : public ::testing::Test {
 public:
     C2BufferTest()
-        : mLinearAllocator(std::make_shared<C2AllocatorIon>('i')),
+        : mBlockPoolId(C2BlockPool::PLATFORM_START),
+          mLinearAllocator(std::make_shared<C2AllocatorIon>('i')),
           mSize(0u),
           mAddr(nullptr),
           mGraphicAllocator(std::make_shared<C2AllocatorGralloc>('g')) {
@@ -281,7 +282,7 @@
     }
 
     std::shared_ptr<C2BlockPool> makeLinearBlockPool() {
-        return std::make_shared<C2BasicLinearBlockPool>(mLinearAllocator);
+        return std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
     }
 
     void allocateGraphic(uint32_t width, uint32_t height) {
@@ -328,6 +329,7 @@
     }
 
 private:
+    C2BlockPool::local_id_t mBlockPoolId;
     std::shared_ptr<C2Allocator> mLinearAllocator;
     std::shared_ptr<C2LinearAllocation> mLinearAllocation;
     size_t mSize;
diff --git a/media/libstagefright/codec2/vndk/Android.bp b/media/libstagefright/codec2/vndk/Android.bp
index 47afd42..95e7c39 100644
--- a/media/libstagefright/codec2/vndk/Android.bp
+++ b/media/libstagefright/codec2/vndk/Android.bp
@@ -39,14 +39,17 @@
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.media.bufferpool@1.0",
         "libbinder",
         "libcutils",
         "libdl",
         "libhardware",
         "libhidlbase",
         "libion",
+        "libfmq",
         "liblog",
         "libstagefright_foundation",
+        "libstagefright_bufferpool@1.0",
         "libui",
         "libutils",
     ],
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
index fda8fe4..664c09e 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -150,6 +150,7 @@
      * so that we can capture the error.
      *
      * \param ionFd     ion client (ownership transferred to created object)
+     * \param owned     whehter native_handle_t is owned by an allocation or not.
      * \param capacity  size of allocation
      * \param bufferFd  buffer handle (ownership transferred to created object). Must be
      *                  invalid if err is not 0.
@@ -157,8 +158,9 @@
      *                  invalid if err is not 0.
      * \param err       errno during buffer allocation or import
      */
-    Impl(int ionFd, size_t capacity, int bufferFd, ion_user_handle_t buffer, C2Allocator::id_t id, int err)
+    Impl(int ionFd, bool owned, size_t capacity, int bufferFd, ion_user_handle_t buffer, C2Allocator::id_t id, int err)
         : mIonFd(ionFd),
+          mHandleOwned(owned),
           mHandle(bufferFd, capacity),
           mBuffer(buffer),
           mId(id),
@@ -189,7 +191,7 @@
     static Impl *Import(int ionFd, size_t capacity, int bufferFd, C2Allocator::id_t id) {
         ion_user_handle_t buffer = -1;
         int ret = ion_import(ionFd, bufferFd, &buffer);
-        return new Impl(ionFd, capacity, bufferFd, buffer, id, ret);
+        return new Impl(ionFd, false, capacity, bufferFd, buffer, id, ret);
     }
 
     /**
@@ -216,7 +218,7 @@
                 buffer = -1;
             }
         }
-        return new Impl(ionFd, size, bufferFd, buffer, id, ret);
+        return new Impl(ionFd, true, size, bufferFd, buffer, id, ret);
     }
 
     c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
@@ -313,7 +315,9 @@
         if (mIonFd >= 0) {
             close(mIonFd);
         }
-        native_handle_close(&mHandle);
+        if (mHandleOwned) {
+            native_handle_close(&mHandle);
+        }
     }
 
     c2_status_t status() const {
@@ -334,6 +338,7 @@
 
 private:
     int mIonFd;
+    bool mHandleOwned;
     C2HandleIon mHandle;
     ion_user_handle_t mBuffer;
     C2Allocator::id_t mId;
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index dc765f5..91b21c2 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -25,8 +25,16 @@
 #include <C2BufferPriv.h>
 #include <C2BlockInternal.h>
 
+#include <ClientManager.h>
+
 namespace {
 
+using android::hardware::media::bufferpool::V1_0::ResultStatus;
+using android::hardware::media::bufferpool::V1_0::implementation::BufferPoolAllocation;
+using android::hardware::media::bufferpool::V1_0::implementation::BufferPoolAllocator;
+using android::hardware::media::bufferpool::V1_0::implementation::ClientManager;
+using android::hardware::media::bufferpool::V1_0::implementation::ConnectionId;
+
 // This anonymous namespace contains the helper classes that allow our implementation to create
 // block/buffer objects.
 //
@@ -341,6 +349,257 @@
     return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
 }
 
+/**
+ * Wrapped C2Allocator which is injected to buffer pool on behalf of
+ * C2BlockPool.
+ */
+class _C2BufferPoolAllocator : public BufferPoolAllocator {
+public:
+    _C2BufferPoolAllocator(const std::shared_ptr<C2Allocator> &allocator)
+        : mAllocator(allocator) {}
+
+    ~_C2BufferPoolAllocator() override {}
+
+    ResultStatus allocate(const std::vector<uint8_t> &params,
+                          std::shared_ptr<BufferPoolAllocation> *alloc) override;
+
+    bool compatible(const std::vector<uint8_t> &newParams,
+                    const std::vector<uint8_t> &oldParams) override;
+
+    // Methods for codec2 component (C2BlockPool).
+    /**
+     * Transforms linear allocation parameters for C2Allocator to parameters
+     * for buffer pool.
+     *
+     * @param capacity      size of linear allocation
+     * @param usage         memory usage pattern for linear allocation
+     * @param params        allocation parameters for buffer pool
+     */
+    void getLinearParams(uint32_t capacity, C2MemoryUsage usage,
+                         std::vector<uint8_t> *params);
+
+    /**
+     * Transforms graphic allocation parameters for C2Allocator to parameters
+     * for buffer pool.
+     *
+     * @param width         width of graphic allocation
+     * @param height        height of graphic allocation
+     * @param format        color format of graphic allocation
+     * @param params        allocation parameter for buffer pool
+     */
+    void getGraphicParams(uint32_t width, uint32_t height,
+                          uint32_t format, C2MemoryUsage usage,
+                          std::vector<uint8_t> *params);
+
+    /**
+     * Transforms an existing native handle to an C2LinearAllcation.
+     * Wrapper to C2Allocator#priorLinearAllocation
+     */
+    c2_status_t priorLinearAllocation(
+            const C2Handle *handle,
+            std::shared_ptr<C2LinearAllocation> *c2Allocation);
+
+    /**
+     * Transforms an existing native handle to an C2GraphicAllcation.
+     * Wrapper to C2Allocator#priorGraphicAllocation
+     */
+    c2_status_t priorGraphicAllocation(
+            const C2Handle *handle,
+            std::shared_ptr<C2GraphicAllocation> *c2Allocation);
+
+private:
+    static constexpr int kMaxIntParams = 5; // large enough number;
+
+    enum AllocType : uint8_t {
+        ALLOC_NONE = 0,
+
+        ALLOC_LINEAR,
+        ALLOC_GRAPHIC,
+    };
+
+    union AllocParams {
+        struct {
+            AllocType allocType;
+            C2MemoryUsage usage;
+            uint32_t params[kMaxIntParams];
+        } data;
+        uint8_t array[0];
+
+        AllocParams() : data{ALLOC_NONE, {0, 0}, {0}} {}
+        AllocParams(C2MemoryUsage usage, uint32_t capacity)
+            : data{ALLOC_LINEAR, usage, {[0] = capacity}} {}
+        AllocParams(
+                C2MemoryUsage usage,
+                uint32_t width, uint32_t height, uint32_t format)
+                : data{ALLOC_GRAPHIC, usage, {width, height, format}} {}
+    };
+
+    const std::shared_ptr<C2Allocator> mAllocator;
+};
+
+struct LinearAllocationDtor {
+    LinearAllocationDtor(const std::shared_ptr<C2LinearAllocation> &alloc)
+        : mAllocation(alloc) {}
+
+    void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+
+    const std::shared_ptr<C2LinearAllocation> mAllocation;
+};
+
+ResultStatus _C2BufferPoolAllocator::allocate(
+        const std::vector<uint8_t>  &params,
+        std::shared_ptr<BufferPoolAllocation> *alloc) {
+    AllocParams c2Params;
+    memcpy(&c2Params, params.data(), std::min(sizeof(AllocParams), params.size()));
+    std::shared_ptr<C2LinearAllocation> c2Linear;
+    c2_status_t status = C2_BAD_VALUE;
+    switch(c2Params.data.allocType) {
+        case ALLOC_NONE:
+            break;
+        case ALLOC_LINEAR:
+            status = mAllocator->newLinearAllocation(
+                    c2Params.data.params[0], c2Params.data.usage, &c2Linear);
+            if (status == C2_OK && c2Linear) {
+                BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Linear->handle());
+                if (ptr) {
+                    *alloc = std::shared_ptr<BufferPoolAllocation>(
+                            ptr, LinearAllocationDtor(c2Linear));
+                    if (*alloc) {
+                        return ResultStatus::OK;
+                    }
+                    delete ptr;
+                }
+                return ResultStatus::NO_MEMORY;
+            }
+            break;
+        case ALLOC_GRAPHIC:
+            // TODO
+            break;
+        default:
+            break;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+bool _C2BufferPoolAllocator::compatible(
+        const std::vector<uint8_t>  &newParams,
+        const std::vector<uint8_t>  &oldParams) {
+    size_t newSize = newParams.size();
+    size_t oldSize = oldParams.size();
+
+    // TODO: support not exact matching. e.g) newCapacity < oldCapacity
+    if (newSize == oldSize) {
+        for (size_t i = 0; i < newSize; ++i) {
+            if (newParams[i] != oldParams[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+    return false;
+}
+
+void _C2BufferPoolAllocator::getLinearParams(
+        uint32_t capacity, C2MemoryUsage usage, std::vector<uint8_t> *params) {
+    AllocParams c2Params(usage, capacity);
+    params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
+}
+
+void _C2BufferPoolAllocator::getGraphicParams(
+        uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+        std::vector<uint8_t> *params) {
+    AllocParams c2Params(usage, width, height, format);
+    params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
+}
+
+c2_status_t _C2BufferPoolAllocator::priorLinearAllocation(
+        const C2Handle *handle,
+        std::shared_ptr<C2LinearAllocation> *c2Allocation) {
+    return mAllocator->priorLinearAllocation(handle, c2Allocation);
+}
+
+c2_status_t _C2BufferPoolAllocator::priorGraphicAllocation(
+        const C2Handle *handle,
+        std::shared_ptr<C2GraphicAllocation> *c2Allocation) {
+    return mAllocator->priorGraphicAllocation(handle, c2Allocation);
+}
+
+class C2PooledBlockPool::Impl {
+public:
+    Impl(const std::shared_ptr<C2Allocator> &allocator)
+            : mInit(C2_OK),
+              mBufferPoolManager(ClientManager::getInstance()),
+              mAllocator(std::make_shared<_C2BufferPoolAllocator>(allocator)) {
+        if (mAllocator && mBufferPoolManager) {
+            if (mBufferPoolManager->create(
+                    mAllocator, &mConnectionId) == ResultStatus::OK) {
+                return;
+            }
+        }
+        mInit = C2_NO_INIT;
+    }
+
+    ~Impl() {
+        if (mInit == C2_OK) {
+            mBufferPoolManager->close(mConnectionId);
+        }
+    }
+
+    c2_status_t fetchLinearBlock(
+            uint32_t capacity, C2MemoryUsage usage,
+            std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+        block->reset();
+        if (mInit != C2_OK) {
+            return mInit;
+        }
+        std::vector<uint8_t> params;
+        mAllocator->getLinearParams(capacity, usage, &params);
+        std::shared_ptr<_C2BlockPoolData> poolData;
+        ResultStatus status = mBufferPoolManager->allocate(
+                mConnectionId, params, &poolData);
+        if (status == ResultStatus::OK) {
+            std::shared_ptr<C2LinearAllocation> alloc;
+            c2_status_t err = mAllocator->priorLinearAllocation(
+                    poolData->mHandle, &alloc);
+            if (err == C2_OK && poolData && alloc) {
+                *block = _C2BlockFactory::CreateLinearBlock(
+                        alloc, poolData, 0, capacity);
+                if (*block) {
+                    return C2_OK;
+                }
+            }
+            return C2_NO_MEMORY;
+        }
+        if (status == ResultStatus::NO_MEMORY) {
+            return C2_NO_MEMORY;
+        }
+        return C2_CORRUPTED;
+    }
+
+private:
+    c2_status_t mInit;
+    const android::sp<ClientManager> mBufferPoolManager;
+    ConnectionId mConnectionId; // locally
+    const std::shared_ptr<_C2BufferPoolAllocator> mAllocator;
+};
+
+C2PooledBlockPool::C2PooledBlockPool(
+        const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
+        : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
+
+C2PooledBlockPool::~C2PooledBlockPool() {
+}
+
+c2_status_t C2PooledBlockPool::fetchLinearBlock(
+        uint32_t capacity,
+        C2MemoryUsage usage,
+        std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+    if (mImpl) {
+        return mImpl->fetchLinearBlock(capacity, usage, block);
+    }
+    return C2_CORRUPTED;
+}
+
 /* ========================================== 2D BLOCK ========================================= */
 
 /**
diff --git a/media/libstagefright/codec2/vndk/C2Store.cpp b/media/libstagefright/codec2/vndk/C2Store.cpp
index 216a897..6f752ae 100644
--- a/media/libstagefright/codec2/vndk/C2Store.cpp
+++ b/media/libstagefright/codec2/vndk/C2Store.cpp
@@ -152,6 +152,39 @@
     return res;
 }
 
+c2_status_t CreateCodec2BlockPool(
+        C2PlatformAllocatorStore::id_t allocatorId,
+        std::shared_ptr<const C2Component> component,
+        std::shared_ptr<C2BlockPool> *pool) {
+    pool->reset();
+    if (!component) {
+        return C2_BAD_VALUE;
+    }
+    // TODO: support caching block pool along with GetCodec2BlockPool.
+    static std::atomic_int sBlockPoolId(C2BlockPool::PLATFORM_START);
+    std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
+    std::shared_ptr<C2Allocator> allocator;
+    c2_status_t res = C2_NOT_FOUND;
+
+    switch (allocatorId) {
+    case C2PlatformAllocatorStore::ION:
+        res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
+        if (res == C2_OK) {
+            *pool = std::make_shared<C2PooledBlockPool>(allocator, sBlockPoolId++);
+            if (!*pool) {
+                res = C2_NO_MEMORY;
+            }
+        }
+        break;
+    case C2PlatformAllocatorStore::GRALLOC:
+        // TODO: support gralloc
+        break;
+    default:
+        break;
+    }
+    return res;
+}
+
 class C2PlatformComponentStore : public C2ComponentStore {
 public:
     virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override;
diff --git a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
index 977cf7b..211c13a 100644
--- a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
+++ b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
@@ -71,4 +71,32 @@
     const std::shared_ptr<C2Allocator> mAllocator;
 };
 
+class C2PooledBlockPool : public C2BlockPool {
+public:
+    C2PooledBlockPool(const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId);
+
+    virtual ~C2PooledBlockPool() override;
+
+    virtual C2Allocator::id_t getAllocatorId() const override {
+        return mAllocator->getId();
+    }
+
+    virtual local_id_t getLocalId() const override {
+        return mLocalId;
+    }
+
+    virtual c2_status_t fetchLinearBlock(
+            uint32_t capacity,
+            C2MemoryUsage usage,
+            std::shared_ptr<C2LinearBlock> *block /* nonnull */) override;
+
+    // TODO: fetchGraphicBlock, fetchCircularBlock
+private:
+    const std::shared_ptr<C2Allocator> mAllocator;
+    const local_id_t mLocalId;
+
+    class Impl;
+    std::unique_ptr<Impl> mImpl;
+};
+
 #endif // STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
index afa51ee..211ee0c 100644
--- a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
+++ b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
@@ -82,6 +82,23 @@
         std::shared_ptr<C2BlockPool> *pool);
 
 /**
+ * Creates a block pool.
+ * \param allocatorId  the allocator ID which is used to allocate blocks
+ * \param component     the component using the block pool (must be non-null)
+ * \param pool          pointer to where the created block pool shall be store on success.
+ *                      nullptr will be stored here on failure
+ *
+ * \retval C2_OK        the operation was successful
+ * \retval C2_BAD_VALUE the component is null
+ * \retval C2_NOT_FOUND if the allocator does not exist
+ * \retval C2_NO_MEMORY not enough memory to create a block pool
+ */
+c2_status_t CreateCodec2BlockPool(
+        C2PlatformAllocatorStore::id_t allocatorId,
+        std::shared_ptr<const C2Component> component,
+        std::shared_ptr<C2BlockPool> *pool);
+
+/**
  * Returns the platform component store.
  * \retval nullptr if the platform component store could not be obtained
  */
diff --git a/media/libstagefright/codecs/cmds/codec2.cpp b/media/libstagefright/codecs/cmds/codec2.cpp
index 0ec1a77..5558bcf 100644
--- a/media/libstagefright/codecs/cmds/codec2.cpp
+++ b/media/libstagefright/codecs/cmds/codec2.cpp
@@ -93,6 +93,8 @@
 
     sp<IProducerListener> mProducerListener;
 
+    std::atomic_int mLinearPoolId;
+
     std::shared_ptr<C2Allocator> mAllocIon;
     std::shared_ptr<C2BlockPool> mLinearPool;
 
@@ -137,12 +139,13 @@
 SimplePlayer::SimplePlayer()
     : mListener(new Listener(this)),
       mProducerListener(new DummyProducerListener),
+      mLinearPoolId(C2BlockPool::PLATFORM_START),
       mComposerClient(new SurfaceComposerClient) {
     CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
 
     std::shared_ptr<C2AllocatorStore> store = GetCodec2PlatformAllocatorStore();
     CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mAllocIon), C2_OK);
-    mLinearPool = std::make_shared<C2BasicLinearBlockPool>(mAllocIon);
+    mLinearPool = std::make_shared<C2PooledBlockPool>(mAllocIon, mLinearPoolId++);
 
     mControl = mComposerClient->createSurface(
             String8("A Surface"),
@@ -284,7 +287,7 @@
     });
 
     long numFrames = 0;
-    mLinearPool.reset(new C2BasicLinearBlockPool(mAllocIon));
+    mLinearPool.reset(new C2PooledBlockPool(mAllocIon, mLinearPoolId++));
 
     for (;;) {
         size_t size = 0u;