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

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

stagefright: Codec2 VNDK Buffers

Implement C2Buffer & C2BufferData classes

Bug: 30262321
Test: codec2_test
Change-Id: I0c579c9d5b83cb8ff74bb36d8555347a172cfe42
parent d103cd2a
Loading
Loading
Loading
Loading
+11 −7
Original line number Diff line number Diff line
@@ -767,10 +767,10 @@ struct C2Rect {
    uint32_t mWidth;
    uint32_t mHeight;

    inline C2Rect(uint32_t width, uint32_t height)
    constexpr inline C2Rect(uint32_t width, uint32_t height)
        : C2Rect(width, height, 0, 0) { }

    inline C2Rect(uint32_t width, uint32_t height, uint32_t left, uint32_t top)
    constexpr inline C2Rect(uint32_t width, uint32_t height, uint32_t left, uint32_t top)
        : mLeft(left), mTop(top), mWidth(width), mHeight(height) { }

    // utility methods
@@ -1167,7 +1167,8 @@ private:

protected:
    // no public constructor
    // C2BufferData(const std::shared_ptr<const Impl> &impl) : mImpl(impl) {}
    explicit C2BufferData(const std::list<C2ConstLinearBlock> &blocks);
    explicit C2BufferData(const std::list<C2ConstGraphicBlock> &blocks);
};

/**
@@ -1223,7 +1224,7 @@ public:
     * \retval C2_NO_MEMORY not enough memory to register for this callback
     * \retval C2_CORRUPTED an unknown error prevented the registration (unexpected)
     */
    C2Error registerOnDestroyNotify(OnDestroyNotify *onDestroyNotify, void *arg = nullptr);
    C2Error registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg = nullptr);

    /**
     * Unregisters a previously registered pre-destroy notification.
@@ -1235,7 +1236,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 *args = nullptr);
    C2Error unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify);

    ///@}

@@ -1271,14 +1272,17 @@ public:
     * \return true iff there is a metadata with the parameter type attached to this buffer.
     */
    bool hasInfo(C2Param::Type index) const;
    std::shared_ptr<C2Info> removeInfo(C2Param::Type index) const;
    std::shared_ptr<C2Info> removeInfo(C2Param::Type index);
    ///@}

protected:
    // no public constructor
    inline C2Buffer() = default;
    explicit C2Buffer(const std::list<C2ConstLinearBlock> &blocks);
    explicit C2Buffer(const std::list<C2ConstGraphicBlock> &blocks);

private:
    class Impl;
    std::shared_ptr<Impl> mImpl;
//    Type _mType;
};

+173 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <C2Buffer.h>
#include <C2BufferPriv.h>
#include <C2ParamDef.h>

#include <system/graphics.h>

@@ -354,4 +355,176 @@ TEST_F(C2BufferTest, GraphicBlockAllocatorTest) {
    ASSERT_TRUE(verifyPlane({ 0, 0, kWidth / 4, kHeight }, vInfo, cv, 0));
}

class BufferData : public C2BufferData {
public:
    explicit BufferData(const std::list<C2ConstLinearBlock> &blocks) : C2BufferData(blocks) {}
    explicit BufferData(const std::list<C2ConstGraphicBlock> &blocks) : C2BufferData(blocks) {}
};

class Buffer : public C2Buffer {
public:
    explicit Buffer(const std::list<C2ConstLinearBlock> &blocks) : C2Buffer(blocks) {}
    explicit Buffer(const std::list<C2ConstGraphicBlock> &blocks) : C2Buffer(blocks) {}
};

TEST_F(C2BufferTest, BufferDataTest) {
    std::shared_ptr<C2BlockAllocator> linearBlockAllocator(makeLinearBlockAllocator());
    std::shared_ptr<C2BlockAllocator> graphicBlockAllocator(makeGraphicBlockAllocator());

    constexpr uint32_t kWidth1 = 320;
    constexpr uint32_t kHeight1 = 240;
    constexpr C2Rect kCrop1(kWidth1, kHeight1);
    constexpr uint32_t kWidth2 = 176;
    constexpr uint32_t kHeight2 = 144;
    constexpr C2Rect kCrop2(kWidth2, kHeight2);
    constexpr size_t kCapacity1 = 1024u;
    constexpr size_t kCapacity2 = 2048u;

    std::shared_ptr<C2LinearBlock> linearBlock1;
    std::shared_ptr<C2LinearBlock> linearBlock2;
    ASSERT_EQ(C2_OK, linearBlockAllocator->allocateLinearBlock(
            kCapacity1,
            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
            &linearBlock1));
    ASSERT_EQ(C2_OK, linearBlockAllocator->allocateLinearBlock(
            kCapacity2,
            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
            &linearBlock2));
    std::shared_ptr<C2GraphicBlock> graphicBlock1;
    std::shared_ptr<C2GraphicBlock> graphicBlock2;
    ASSERT_EQ(C2_OK, graphicBlockAllocator->allocateGraphicBlock(
            kWidth1,
            kHeight1,
            HAL_PIXEL_FORMAT_YCBCR_420_888,
            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
            &graphicBlock1));
    ASSERT_EQ(C2_OK, graphicBlockAllocator->allocateGraphicBlock(
            kWidth2,
            kHeight2,
            HAL_PIXEL_FORMAT_YCBCR_420_888,
            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
            &graphicBlock2));

    std::shared_ptr<C2BufferData> data(new BufferData({ linearBlock1->share(0, kCapacity1, C2Fence()) }));
    EXPECT_EQ(C2BufferData::LINEAR, data->type());
    ASSERT_EQ(1u, data->linearBlocks().size());
    EXPECT_EQ(linearBlock1->handle(), data->linearBlocks().front().handle());
    EXPECT_TRUE(data->graphicBlocks().empty());

    data.reset(new BufferData({
        linearBlock1->share(0, kCapacity1, C2Fence()),
        linearBlock2->share(0, kCapacity2, C2Fence()),
    }));
    EXPECT_EQ(C2BufferData::LINEAR_CHUNKS, data->type());
    ASSERT_EQ(2u, data->linearBlocks().size());
    EXPECT_EQ(linearBlock1->handle(), data->linearBlocks().front().handle());
    EXPECT_EQ(linearBlock2->handle(), data->linearBlocks().back().handle());
    EXPECT_TRUE(data->graphicBlocks().empty());

    data.reset(new BufferData({ graphicBlock1->share(kCrop1, C2Fence()) }));
    EXPECT_EQ(C2BufferData::GRAPHIC, data->type());
    ASSERT_EQ(1u, data->graphicBlocks().size());
    EXPECT_EQ(graphicBlock1->handle(), data->graphicBlocks().front().handle());
    EXPECT_TRUE(data->linearBlocks().empty());

    data.reset(new BufferData({
        graphicBlock1->share(kCrop1, C2Fence()),
        graphicBlock2->share(kCrop2, C2Fence()),
    }));
    EXPECT_EQ(C2BufferData::GRAPHIC_CHUNKS, data->type());
    ASSERT_EQ(2u, data->graphicBlocks().size());
    EXPECT_EQ(graphicBlock1->handle(), data->graphicBlocks().front().handle());
    EXPECT_EQ(graphicBlock2->handle(), data->graphicBlocks().back().handle());
    EXPECT_TRUE(data->linearBlocks().empty());
}

void DestroyCallback(const C2Buffer * /* buf */, void *arg) {
    std::function<void(void)> *cb = (std::function<void(void)> *)arg;
    (*cb)();
}

enum : uint32_t {
    kParamIndexNumber1,
    kParamIndexNumber2,
};

typedef C2GlobalParam<C2Info, C2Int32Value, kParamIndexNumber1> C2Number1Info;
typedef C2GlobalParam<C2Info, C2Int32Value, kParamIndexNumber2> C2Number2Info;

TEST_F(C2BufferTest, BufferTest) {
    std::shared_ptr<C2BlockAllocator> alloc(makeLinearBlockAllocator());
    constexpr size_t kCapacity = 1024u;
    std::shared_ptr<C2LinearBlock> block;

    ASSERT_EQ(C2_OK, alloc->allocateLinearBlock(
            kCapacity,
            { C2MemoryUsage::kSoftwareRead, C2MemoryUsage::kSoftwareWrite },
            &block));

    std::atomic_bool destroyed(false);
    std::function<void(void)> arg = [&destroyed](){ destroyed = true; };

    std::shared_ptr<C2Buffer> buffer(new Buffer( { block->share(0, kCapacity, C2Fence()) }));
    ASSERT_EQ(C2_OK, buffer->registerOnDestroyNotify(&DestroyCallback, &arg));
    EXPECT_FALSE(destroyed);
    ASSERT_EQ(C2_DUPLICATE, buffer->registerOnDestroyNotify(&DestroyCallback, &arg));
    buffer.reset();
    EXPECT_TRUE(destroyed);

    buffer.reset(new Buffer( { block->share(0, kCapacity, C2Fence()) }));
    destroyed = false;
    ASSERT_EQ(C2_OK, buffer->registerOnDestroyNotify(&DestroyCallback, &arg));
    EXPECT_FALSE(destroyed);
    ASSERT_EQ(C2_OK, buffer->unregisterOnDestroyNotify(&DestroyCallback));
    EXPECT_FALSE(destroyed);
    ASSERT_EQ(C2_NOT_FOUND, buffer->unregisterOnDestroyNotify(&DestroyCallback));
    buffer.reset();
    EXPECT_FALSE(destroyed);

    std::shared_ptr<C2Info> info1(new C2Number1Info(1));
    std::shared_ptr<C2Info> info2(new C2Number2Info(2));
    buffer.reset(new Buffer( { block->share(0, kCapacity, C2Fence()) }));
    EXPECT_TRUE(buffer->infos().empty());
    EXPECT_FALSE(buffer->hasInfo(info1->type()));
    EXPECT_FALSE(buffer->hasInfo(info2->type()));

    ASSERT_EQ(C2_OK, buffer->setInfo(info1));
    EXPECT_EQ(1u, buffer->infos().size());
    EXPECT_EQ(*info1, *buffer->infos().front());
    EXPECT_TRUE(buffer->hasInfo(info1->type()));
    EXPECT_FALSE(buffer->hasInfo(info2->type()));

    ASSERT_EQ(C2_OK, buffer->setInfo(info2));
    EXPECT_EQ(2u, buffer->infos().size());
    EXPECT_TRUE(buffer->hasInfo(info1->type()));
    EXPECT_TRUE(buffer->hasInfo(info2->type()));

    std::shared_ptr<C2Info> removed = buffer->removeInfo(info1->type());
    ASSERT_TRUE(removed);
    EXPECT_EQ(*removed, *info1);
    EXPECT_EQ(1u, buffer->infos().size());
    EXPECT_EQ(*info2, *buffer->infos().front());
    EXPECT_FALSE(buffer->hasInfo(info1->type()));
    EXPECT_TRUE(buffer->hasInfo(info2->type()));

    removed = buffer->removeInfo(info1->type());
    ASSERT_FALSE(removed);
    EXPECT_EQ(1u, buffer->infos().size());
    EXPECT_FALSE(buffer->hasInfo(info1->type()));
    EXPECT_TRUE(buffer->hasInfo(info2->type()));

    std::shared_ptr<C2Info> info3(new C2Number2Info(3));
    ASSERT_EQ(C2_OK, buffer->setInfo(info3));
    EXPECT_EQ(1u, buffer->infos().size());
    EXPECT_FALSE(buffer->hasInfo(info1->type()));
    EXPECT_TRUE(buffer->hasInfo(info2->type()));

    removed = buffer->removeInfo(info2->type());
    ASSERT_TRUE(removed);
    EXPECT_EQ(*info3, *removed);
    EXPECT_TRUE(buffer->infos().empty());
    EXPECT_FALSE(buffer->hasInfo(info1->type()));
    EXPECT_FALSE(buffer->hasInfo(info2->type()));
}

} // namespace android
+146 −0
Original line number Diff line number Diff line
@@ -1284,4 +1284,150 @@ C2Error C2DefaultGraphicBlockAllocator::allocateGraphicBlock(
    return C2_OK;
}

/* ========================================== BUFFER ========================================= */

class C2BufferData::Impl {
public:
    explicit Impl(const std::list<C2ConstLinearBlock> &blocks)
        : mType(blocks.size() == 1 ? LINEAR : LINEAR_CHUNKS),
          mLinearBlocks(blocks) {
    }

    explicit Impl(const std::list<C2ConstGraphicBlock> &blocks)
        : mType(blocks.size() == 1 ? GRAPHIC : GRAPHIC_CHUNKS),
          mGraphicBlocks(blocks) {
    }

    Type type() const { return mType; }
    const std::list<C2ConstLinearBlock> &linearBlocks() const { return mLinearBlocks; }
    const std::list<C2ConstGraphicBlock> &graphicBlocks() const { return mGraphicBlocks; }

private:
    Type mType;
    std::list<C2ConstLinearBlock> mLinearBlocks;
    std::list<C2ConstGraphicBlock> mGraphicBlocks;
};

C2BufferData::C2BufferData(const std::list<C2ConstLinearBlock> &blocks) : mImpl(new Impl(blocks)) {}
C2BufferData::C2BufferData(const std::list<C2ConstGraphicBlock> &blocks) : mImpl(new Impl(blocks)) {}

C2BufferData::Type C2BufferData::type() const { return mImpl->type(); }

const std::list<C2ConstLinearBlock> C2BufferData::linearBlocks() const {
    return mImpl->linearBlocks();
}

const std::list<C2ConstGraphicBlock> C2BufferData::graphicBlocks() const {
    return mImpl->graphicBlocks();
}

class C2Buffer::Impl {
public:
    Impl(C2Buffer *thiz, const std::list<C2ConstLinearBlock> &blocks)
        : mThis(thiz), mData(blocks) {}
    Impl(C2Buffer *thiz, const std::list<C2ConstGraphicBlock> &blocks)
        : mThis(thiz), mData(blocks) {}

    ~Impl() {
        for (const auto &pair : mNotify) {
            pair.first(mThis, pair.second);
        }
    }

    const C2BufferData &data() const { return mData; }

    C2Error registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg = nullptr) {
        auto it = std::find_if(
                mNotify.begin(), mNotify.end(),
                [onDestroyNotify, arg] (const auto &pair) {
                    return pair.first == onDestroyNotify && pair.second == arg;
                });
        if (it != mNotify.end()) {
            return C2_DUPLICATE;
        }
        mNotify.emplace_back(onDestroyNotify, arg);
        return C2_OK;
    }

    C2Error unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify) {
        auto it = std::find_if(
                mNotify.begin(), mNotify.end(),
                [onDestroyNotify] (const auto &pair) {
                    return pair.first == onDestroyNotify;
                });
        if (it == mNotify.end()) {
            return C2_NOT_FOUND;
        }
        mNotify.erase(it);
        return C2_OK;
    }

    std::list<std::shared_ptr<const C2Info>> infos() const {
        std::list<std::shared_ptr<const C2Info>> result(mInfos.size());
        std::transform(
                mInfos.begin(), mInfos.end(), result.begin(),
                [] (const auto &elem) { return elem.second; });
        return result;
    }

    C2Error setInfo(const std::shared_ptr<C2Info> &info) {
        // To "update" you need to erase the existing one if any, and then insert.
        (void) mInfos.erase(info->type());
        (void) mInfos.insert({ info->type(), info });
        return C2_OK;
    }

    bool hasInfo(C2Param::Type index) const {
        return mInfos.count(index.type()) > 0;
    }

    std::shared_ptr<C2Info> removeInfo(C2Param::Type index) {
        auto it = mInfos.find(index.type());
        if (it == mInfos.end()) {
            return nullptr;
        }
        std::shared_ptr<C2Info> ret = it->second;
        (void) mInfos.erase(it);
        return ret;
    }

private:
    C2Buffer * const mThis;
    C2DefaultBufferData mData;
    std::map<uint32_t, std::shared_ptr<C2Info>> mInfos;
    std::list<std::pair<OnDestroyNotify, void *>> mNotify;
};

C2Buffer::C2Buffer(const std::list<C2ConstLinearBlock> &blocks)
    : mImpl(new Impl(this, blocks)) {}

C2Buffer::C2Buffer(const std::list<C2ConstGraphicBlock> &blocks)
    : mImpl(new Impl(this, blocks)) {}

const C2BufferData C2Buffer::data() const { return mImpl->data(); }

C2Error C2Buffer::registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
    return mImpl->registerOnDestroyNotify(onDestroyNotify, arg);
}

C2Error C2Buffer::unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify) {
    return mImpl->unregisterOnDestroyNotify(onDestroyNotify);
}

const std::list<std::shared_ptr<const C2Info>> C2Buffer::infos() const {
    return mImpl->infos();
}

C2Error C2Buffer::setInfo(const std::shared_ptr<C2Info> &info) {
    return mImpl->setInfo(info);
}

bool C2Buffer::hasInfo(C2Param::Type index) const {
    return mImpl->hasInfo(index);
}

std::shared_ptr<C2Info> C2Buffer::removeInfo(C2Param::Type index) {
    return mImpl->removeInfo(index);
}

} // namespace android