Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d103cd2a authored by Wonsik Kim's avatar Wonsik Kim
Browse files

stagefright: Codec2 VNDK 2D

Implement gralloc-based 2D buffers.

Bug: 30262321
Test: codec2_test
Change-Id: I7457cb713ed839372585418d7ccdd33a792e94eb
parent d8bf46bc
Loading
Loading
Loading
Loading
+63 −10
Original line number Diff line number Diff line
@@ -921,29 +921,51 @@ class _C2PlanarSection : public _C2PlanarCapacityAspect {
public:
    // crop can be an empty rect, does not have to line up with subsampling
    // NOTE: we do not support floating-point crop
    inline const C2Rect crop() { return mCrop; }
    inline const C2Rect crop() const { return mCrop; }

    /**
     *  Sets crop to crop intersected with [(0,0) .. (width, height)]
     */
    inline void setCrop_be(const C2Rect &crop);
    inline void setCrop_be(const C2Rect &crop) {
        mCrop.mLeft = std::min(width(), crop.mLeft);
        mCrop.mTop = std::min(height(), crop.mTop);
        // It's guaranteed that mCrop.mLeft <= width() && mCrop.mTop <= height()
        mCrop.mWidth = std::min(width() - mCrop.mLeft, crop.mWidth);
        mCrop.mHeight = std::min(height() - mCrop.mTop, crop.mHeight);
    }

    /**
     * If crop is within the dimensions of this object, it sets crop to it.
     *
     * \return true iff crop is within the dimensions of this object
     */
    inline bool setCrop(const C2Rect &crop);
    inline bool setCrop(const C2Rect &crop) {
        if (width() < crop.mWidth || height() < crop.mHeight
                || width() - crop.mWidth < crop.mLeft || height() - crop.mHeight < crop.mTop) {
            return false;
        }
        mCrop = crop;
        return true;
    }

protected:
    inline _C2PlanarSection(const _C2PlanarCapacityAspect *parent)
        : _C2PlanarCapacityAspect(parent), mCrop(width(), height()) {}

private:
    C2Rect mCrop;
/// @}
};

class C2GraphicAllocation;

class C2Block2D : public _C2PlanarSection {
public:
    const C2Handle *handle() const;

protected:
    C2Block2D(const std::shared_ptr<C2GraphicAllocation> &alloc);

private:
    class Impl;
    std::shared_ptr<Impl> mImpl;
@@ -961,14 +983,25 @@ private:
class C2GraphicView : public _C2PlanarSection {
public:
    /**
     * \return pointer to the start of the block or nullptr on error.
     * \return array of pointers to the start of the planes or nullptr on error.
     * Regardless of crop rect, they always point to the top-left corner of
     * each plane.  Access outside of the crop rect results in an undefined
     * behavior.
     */
    const uint8_t *data() const;
    const uint8_t *const *data() const;

    /**
     * \return pointer to the start of the block or nullptr on error.
     * \return array of pointers to the start of the planes or nullptr on error.
     * Regardless of crop rect, they always point to the top-left corner of
     * each plane.  Access outside of the crop rect results in an undefined
     * behavior.
     */
    uint8_t *data();
    uint8_t *const *data();

    /**
     * \return layout of the graphic block to interpret the returned data.
     */
    const C2PlaneLayout layout() const;

    /**
     * Returns a section of this view.
@@ -985,6 +1018,13 @@ public:
     */
    C2Error error() const;

protected:
    C2GraphicView(
            const _C2PlanarCapacityAspect *parent,
            uint8_t *const *data,
            const C2PlaneLayout& layout);
    explicit C2GraphicView(C2Error error);

private:
    class Impl;
    std::shared_ptr<Impl> mImpl;
@@ -1022,7 +1062,12 @@ public:
     */
    C2Fence fence() const { return mFence; }

protected:
    C2ConstGraphicBlock(const std::shared_ptr<C2GraphicAllocation> &alloc, C2Fence fence);

private:
    class Impl;
    std::shared_ptr<Impl> mImpl;
    C2Fence mFence;
};

@@ -1050,6 +1095,13 @@ public:
     *    The block shall be modified only until firing the event for the fence.
     */
    C2ConstGraphicBlock share(const C2Rect &crop, C2Fence fence);

protected:
    explicit C2GraphicBlock(const std::shared_ptr<C2GraphicAllocation> &alloc);

private:
    class Impl;
    std::shared_ptr<Impl> mImpl;
};

/// @}
@@ -1183,7 +1235,7 @@ public:
     * \retval C2_NOT_FOUND the notification was not found
     * \retval C2_CORRUPTED an unknown error prevented the registration (unexpected)
     */
    C2Error unregisterOnDestroyNotify(OnDestroyNotify *onDestroyNotify, void *arg = nullptr);
    C2Error unregisterOnDestroyNotify(OnDestroyNotify *onDestroyNotify, void *args = nullptr);

    ///@}

@@ -1451,10 +1503,11 @@ public:
    /**
     * Returns true if this is the same allocation as |other|.
     */
    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) = 0;
    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const = 0;

protected:
    virtual ~C2GraphicAllocation();
    using _C2PlanarCapacityAspect::_C2PlanarCapacityAspect;
    virtual ~C2GraphicAllocation() = default;
};

/**
+2 −4
Original line number Diff line number Diff line
@@ -19,8 +19,8 @@ cc_test {
    ],

    shared_libs: [
        "libcutils",
        "liblog",
        "android.hardware.graphics.allocator@2.0",
        "android.hardware.graphics.mapper@2.0",
        "libcutils",
        "libhidlbase",
        "libion",
@@ -58,8 +58,6 @@ cc_test {
    ],

    shared_libs: [
        "libcutils",
        "liblog",
        "libcutils",
        "libhidlbase",
        "libion",
+214 −21
Original line number Diff line number Diff line
@@ -26,27 +26,28 @@ namespace android {
class C2BufferTest : public ::testing::Test {
public:
    C2BufferTest()
        : mAllocator(std::make_shared<C2AllocatorIon>()),
        : mLinearAllocator(std::make_shared<C2AllocatorIon>()),
          mSize(0u),
          mAddr(nullptr) {
          mAddr(nullptr),
          mGraphicAllocator(std::make_shared<C2AllocatorGralloc>()) {
    }

    ~C2BufferTest() = default;

    void allocate(size_t capacity) {
        C2Error err = mAllocator->allocateLinearBuffer(
    void allocateLinear(size_t capacity) {
        C2Error err = mLinearAllocator->allocateLinearBuffer(
                capacity,
                { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
                &mAllocation);
                &mLinearAllocation);
        if (err != C2_OK) {
            mAllocation.reset();
            mLinearAllocation.reset();
            FAIL() << "C2Allocator::allocateLinearBuffer() failed: " << err;
        }
    }

    void map(size_t offset, size_t size, uint8_t **addr) {
        ASSERT_TRUE(mAllocation);
        C2Error err = mAllocation->map(
    void mapLinear(size_t offset, size_t size, uint8_t **addr) {
        ASSERT_TRUE(mLinearAllocation);
        C2Error err = mLinearAllocation->map(
                offset,
                size,
                { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
@@ -62,45 +63,89 @@ public:
        *addr = (uint8_t *)mAddr;
    }

    void unmap() {
        ASSERT_TRUE(mAllocation);
    void unmapLinear() {
        ASSERT_TRUE(mLinearAllocation);
        ASSERT_NE(nullptr, mAddr);
        ASSERT_NE(0u, mSize);

        // TODO: fence
        ASSERT_EQ(C2_OK, mAllocation->unmap(mAddr, mSize, nullptr));
        ASSERT_EQ(C2_OK, mLinearAllocation->unmap(mAddr, mSize, nullptr));
        mSize = 0u;
        mAddr = nullptr;
    }

    std::shared_ptr<C2BlockAllocator> makeBlockAllocator() {
        return std::make_shared<C2DefaultBlockAllocator>(mAllocator);
    std::shared_ptr<C2BlockAllocator> makeLinearBlockAllocator() {
        return std::make_shared<C2DefaultBlockAllocator>(mLinearAllocator);
    }

    void allocateGraphic(uint32_t width, uint32_t height) {
        C2Error err = mGraphicAllocator->allocateGraphicBuffer(
                width,
                height,
                HAL_PIXEL_FORMAT_YCBCR_420_888,
                { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
                &mGraphicAllocation);
        if (err != C2_OK) {
            mGraphicAllocation.reset();
            FAIL() << "C2Allocator::allocateLinearBuffer() failed: " << err;
        }
    }

    void mapGraphic(C2Rect rect, C2PlaneLayout *layout, uint8_t **addr) {
        ASSERT_TRUE(mGraphicAllocation);
        C2Error err = mGraphicAllocation->map(
                rect,
                { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
                // TODO: fence
                nullptr,
                layout,
                addr);
        if (err != C2_OK) {
            addr[C2PlaneLayout::Y] = nullptr;
            addr[C2PlaneLayout::U] = nullptr;
            addr[C2PlaneLayout::V] = nullptr;
            FAIL() << "C2GraphicAllocation::map() failed: " << err;
        }
    }

    void unmapGraphic() {
        ASSERT_TRUE(mGraphicAllocation);

        // TODO: fence
        ASSERT_EQ(C2_OK, mGraphicAllocation->unmap(nullptr));
    }

    std::shared_ptr<C2BlockAllocator> makeGraphicBlockAllocator() {
        return std::make_shared<C2DefaultGraphicBlockAllocator>(mGraphicAllocator);
    }

private:
    std::shared_ptr<C2Allocator> mAllocator;
    std::shared_ptr<C2LinearAllocation> mAllocation;
    std::shared_ptr<C2Allocator> mLinearAllocator;
    std::shared_ptr<C2LinearAllocation> mLinearAllocation;
    size_t mSize;
    void *mAddr;

    std::shared_ptr<C2Allocator> mGraphicAllocator;
    std::shared_ptr<C2GraphicAllocation> mGraphicAllocation;
};

TEST_F(C2BufferTest, LinearAllocationTest) {
    constexpr size_t kCapacity = 1024u * 1024u;

    allocate(kCapacity);
    allocateLinear(kCapacity);

    uint8_t *addr = nullptr;
    map(0u, kCapacity, &addr);
    mapLinear(0u, kCapacity, &addr);
    ASSERT_NE(nullptr, addr);

    for (size_t i = 0; i < kCapacity; ++i) {
        addr[i] = i % 100u;
    }

    unmap();
    unmapLinear();
    addr = nullptr;

    map(kCapacity / 3, kCapacity / 3, &addr);
    mapLinear(kCapacity / 3, kCapacity / 3, &addr);
    ASSERT_NE(nullptr, addr);
    for (size_t i = 0; i < kCapacity / 3; ++i) {
        ASSERT_EQ((i + kCapacity / 3) % 100, addr[i]) << " at i = " << i;
@@ -110,7 +155,7 @@ TEST_F(C2BufferTest, LinearAllocationTest) {
TEST_F(C2BufferTest, BlockAllocatorTest) {
    constexpr size_t kCapacity = 1024u * 1024u;

    std::shared_ptr<C2BlockAllocator> blockAllocator(makeBlockAllocator());
    std::shared_ptr<C2BlockAllocator> blockAllocator(makeLinearBlockAllocator());

    std::shared_ptr<C2LinearBlock> block;
    ASSERT_EQ(C2_OK, blockAllocator->allocateLinearBlock(
@@ -161,4 +206,152 @@ TEST_F(C2BufferTest, BlockAllocatorTest) {
    }
}

void fillPlane(const C2Rect rect, const C2PlaneInfo info, uint8_t *addr, uint8_t value) {
    for (uint32_t row = 0; row < rect.mHeight / info.mVertSubsampling; ++row) {
        int32_t rowOffset = (row + rect.mTop / info.mVertSubsampling) * info.mRowInc;
        for (uint32_t col = 0; col < rect.mWidth / info.mHorizSubsampling; ++col) {
            int32_t colOffset = (col + rect.mLeft / info.mHorizSubsampling) * info.mColInc;
            addr[rowOffset + colOffset] = value;
        }
    }
}

bool verifyPlane(const C2Rect rect, const C2PlaneInfo info, const uint8_t *addr, uint8_t value) {
    for (uint32_t row = 0; row < rect.mHeight / info.mVertSubsampling; ++row) {
        int32_t rowOffset = (row + rect.mTop / info.mVertSubsampling) * info.mRowInc;
        for (uint32_t col = 0; col < rect.mWidth / info.mHorizSubsampling; ++col) {
            int32_t colOffset = (col + rect.mLeft / info.mHorizSubsampling) * info.mColInc;
            if (addr[rowOffset + colOffset] != value) {
                return false;
            }
        }
    }
    return true;
}

TEST_F(C2BufferTest, GraphicAllocationTest) {
    constexpr uint32_t kWidth = 320;
    constexpr uint32_t kHeight = 240;

    allocateGraphic(kWidth, kHeight);

    uint8_t *addr[C2PlaneLayout::MAX_NUM_PLANES];
    C2Rect rect{ 0, 0, kWidth, kHeight };
    C2PlaneLayout layout;
    mapGraphic(rect, &layout, addr);
    ASSERT_NE(nullptr, addr[C2PlaneLayout::Y]);
    ASSERT_NE(nullptr, addr[C2PlaneLayout::U]);
    ASSERT_NE(nullptr, addr[C2PlaneLayout::V]);

    uint8_t *y = addr[C2PlaneLayout::Y];
    C2PlaneInfo yInfo = layout.mPlanes[C2PlaneLayout::Y];
    uint8_t *u = addr[C2PlaneLayout::U];
    C2PlaneInfo uInfo = layout.mPlanes[C2PlaneLayout::U];
    uint8_t *v = addr[C2PlaneLayout::V];
    C2PlaneInfo vInfo = layout.mPlanes[C2PlaneLayout::V];

    fillPlane(rect, yInfo, y, 0);
    fillPlane(rect, uInfo, u, 0);
    fillPlane(rect, vInfo, v, 0);
    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, y, 0x12);
    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, u, 0x34);
    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, v, 0x56);

    unmapGraphic();

    mapGraphic(rect, &layout, addr);
    ASSERT_NE(nullptr, addr[C2PlaneLayout::Y]);
    ASSERT_NE(nullptr, addr[C2PlaneLayout::U]);
    ASSERT_NE(nullptr, addr[C2PlaneLayout::V]);

    y = addr[C2PlaneLayout::Y];
    yInfo = layout.mPlanes[C2PlaneLayout::Y];
    u = addr[C2PlaneLayout::U];
    uInfo = layout.mPlanes[C2PlaneLayout::U];
    v = addr[C2PlaneLayout::V];
    vInfo = layout.mPlanes[C2PlaneLayout::V];

    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, y, 0x12));
    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, u, 0x34));
    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, v, 0x56));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, yInfo, y, 0));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, uInfo, u, 0));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, vInfo, v, 0));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, yInfo, y, 0));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, uInfo, u, 0));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, vInfo, v, 0));
}

TEST_F(C2BufferTest, GraphicBlockAllocatorTest) {
    constexpr uint32_t kWidth = 320;
    constexpr uint32_t kHeight = 240;

    std::shared_ptr<C2BlockAllocator> blockAllocator(makeGraphicBlockAllocator());

    std::shared_ptr<C2GraphicBlock> block;
    ASSERT_EQ(C2_OK, blockAllocator->allocateGraphicBlock(
            kWidth,
            kHeight,
            HAL_PIXEL_FORMAT_YCBCR_420_888,
            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
            &block));
    ASSERT_TRUE(block);

    C2Acquirable<C2GraphicView> graphicViewHolder = block->map();
    C2GraphicView graphicView = graphicViewHolder.get();
    ASSERT_EQ(C2_OK, graphicView.error());
    ASSERT_EQ(kWidth, graphicView.width());
    ASSERT_EQ(kHeight, graphicView.height());

    uint8_t *const *data = graphicView.data();
    C2PlaneLayout layout = graphicView.layout();
    ASSERT_NE(nullptr, data);

    uint8_t *y = data[C2PlaneLayout::Y];
    C2PlaneInfo yInfo = layout.mPlanes[C2PlaneLayout::Y];
    uint8_t *u = data[C2PlaneLayout::U];
    C2PlaneInfo uInfo = layout.mPlanes[C2PlaneLayout::U];
    uint8_t *v = data[C2PlaneLayout::V];
    C2PlaneInfo vInfo = layout.mPlanes[C2PlaneLayout::V];

    fillPlane({ 0, 0, kWidth, kHeight }, yInfo, y, 0);
    fillPlane({ 0, 0, kWidth, kHeight }, uInfo, u, 0);
    fillPlane({ 0, 0, kWidth, kHeight }, vInfo, v, 0);
    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, y, 0x12);
    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, u, 0x34);
    fillPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, v, 0x56);

    C2Fence fence;
    C2ConstGraphicBlock constBlock = block->share(
            { 0, 0, kWidth, kHeight }, fence);
    block.reset();

    C2Acquirable<const C2GraphicView> constViewHolder = constBlock.map();
    const C2GraphicView constGraphicView = constViewHolder.get();
    ASSERT_EQ(C2_OK, constGraphicView.error());
    ASSERT_EQ(kWidth, constGraphicView.width());
    ASSERT_EQ(kHeight, constGraphicView.height());

    const uint8_t *const *constData = constGraphicView.data();
    layout = graphicView.layout();
    ASSERT_NE(nullptr, constData);

    const uint8_t *cy = constData[C2PlaneLayout::Y];
    yInfo = layout.mPlanes[C2PlaneLayout::Y];
    const uint8_t *cu = constData[C2PlaneLayout::U];
    uInfo = layout.mPlanes[C2PlaneLayout::U];
    const uint8_t *cv = constData[C2PlaneLayout::V];
    vInfo = layout.mPlanes[C2PlaneLayout::V];

    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, yInfo, cy, 0x12));
    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, uInfo, cu, 0x34));
    ASSERT_TRUE(verifyPlane({ kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2 }, vInfo, cv, 0x56));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, yInfo, cy, 0));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, uInfo, cu, 0));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth, kHeight / 4 }, vInfo, cv, 0));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, yInfo, cy, 0));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, uInfo, cu, 0));
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, vInfo, cv, 0));
}

} // namespace android
+3 −0
Original line number Diff line number Diff line
@@ -10,6 +10,8 @@ cc_library_static {
    ],

    shared_libs: [
        "android.hardware.graphics.allocator@2.0",
        "android.hardware.graphics.mapper@2.0",
        "libbinder",
        "libcutils",
        "libdl",
@@ -19,6 +21,7 @@ cc_library_static {
        "liblog",
        "libmedia",
        "libstagefright_foundation",
        "libui",
        "libutils",
    ],

+567 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading