Merge "media.c2 aidl: Add AHardwareBuffer based C2Allocator" into main am: 8b4488192d am: 12f558e0f4 am: f9d066f6c0 am: 8564cfb796 am: ee56c2625d
Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/2753212
Change-Id: I579fb13e88ab646890ed8f16b5053d2967c0fd24
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 9064eb9..107ce89 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -246,6 +246,130 @@
}
};
+class C2HandleAhwb : public C2Handle {
+private:
+ // TODO: remove extradata and use AHardwareBuffer directly.
+ struct ExtraData {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint32_t usage_lo;
+ uint32_t usage_hi;
+ uint32_t stride;
+ uint32_t origId_lo;
+ uint32_t origId_hi;
+ uint32_t magic;
+ };
+
+ enum {
+ NUM_INTS = sizeof(ExtraData) / sizeof(int),
+ };
+ const static uint32_t MAGIC = '\xc2hw\x00';
+
+ static
+ const ExtraData* GetExtraData(const C2Handle *const handle) {
+ if (handle == nullptr
+ || native_handle_is_invalid(handle)
+ || handle->numInts < NUM_INTS) {
+ return nullptr;
+ }
+ return reinterpret_cast<const ExtraData*>(
+ &handle->data[handle->numFds + handle->numInts - NUM_INTS]);
+ }
+
+ static
+ ExtraData *GetExtraData(C2Handle *const handle) {
+ return const_cast<ExtraData *>(GetExtraData(const_cast<const C2Handle *const>(handle)));
+ }
+
+public:
+ void getOrigId(uint64_t *origId) const {
+ const ExtraData *ed = GetExtraData(this);
+ *origId = unsigned(ed->origId_lo) | uint64_t(unsigned(ed->origId_hi)) << 32;
+ }
+
+ static bool IsValid(const C2Handle *const o) {
+ if (o == nullptr) { // null handle is always valid
+ return true;
+ }
+ const ExtraData *xd = GetExtraData(o);
+ // we cannot validate width/height/format/usage without accessing gralloc driver
+ return xd != nullptr && xd->magic == MAGIC;
+ }
+
+ static C2HandleAhwb* WrapAndMoveNativeHandle(
+ const native_handle_t *const handle,
+ uint32_t width, uint32_t height, uint32_t format, uint64_t usage,
+ uint32_t stride, uint64_t origId) {
+ //CHECK(handle != nullptr);
+ if (native_handle_is_invalid(handle) || handle->numInts >
+ int((INT_MAX - handle->version) / sizeof(int)) - NUM_INTS - handle->numFds) {
+ return nullptr;
+ }
+ ExtraData xd = {
+ width, height, format, uint32_t(usage & 0xFFFFFFFF), uint32_t(usage >> 32),
+ stride, uint32_t(origId & 0xFFFFFFFF), uint32_t(origId >> 32), MAGIC
+ };
+ native_handle_t *res = native_handle_create(handle->numFds, handle->numInts + NUM_INTS);
+ if (res != nullptr) {
+ memcpy(&res->data, &handle->data, sizeof(int) * (handle->numFds + handle->numInts));
+ *GetExtraData(res) = xd;
+ }
+ return reinterpret_cast<C2HandleAhwb *>(res);
+ }
+
+ static C2HandleAhwb* WrapNativeHandle(
+ const native_handle_t *const handle,
+ uint32_t width, uint32_t height, uint32_t format, uint64_t usage,
+ uint32_t stride, uint64_t origId) {
+ if (handle == nullptr) {
+ return nullptr;
+ }
+ native_handle_t *clone = native_handle_clone(handle);
+ if (clone == nullptr) {
+ return nullptr;
+ }
+ C2HandleAhwb *res = WrapAndMoveNativeHandle(
+ clone, width, height, format, usage, stride, origId);
+ if (res == nullptr) {
+ native_handle_close(clone);
+ }
+ native_handle_delete(clone);
+ return res;
+ }
+
+ static native_handle_t* UnwrapNativeHandle(
+ const C2Handle *const handle) {
+ const ExtraData *xd = GetExtraData(handle);
+ if (xd == nullptr || xd->magic != MAGIC) {
+ return nullptr;
+ }
+ native_handle_t *res = native_handle_create(handle->numFds, handle->numInts - NUM_INTS);
+ if (res != nullptr) {
+ memcpy(&res->data, &handle->data, sizeof(int) * (res->numFds + res->numInts));
+ }
+ return res;
+ }
+
+ static const C2HandleAhwb* Import(
+ const C2Handle *const handle,
+ uint32_t *width, uint32_t *height, uint32_t *format,
+ uint64_t *usage, uint32_t *stride,
+ uint64_t *origId) {
+ const ExtraData *xd = GetExtraData(handle);
+ if (xd == nullptr) {
+ return nullptr;
+ }
+ *width = xd->width;
+ *height = xd->height;
+ *format = xd->format;
+ *usage = xd->usage_lo | (uint64_t(xd->usage_hi) << 32);
+ *stride = xd->stride;
+ *origId = xd->origId_lo | (uint64_t(xd->origId_hi) << 32);
+ return reinterpret_cast<const C2HandleAhwb *>(handle);
+ }
+};
+
static
c2_status_t Gralloc4Mapper_lock(native_handle_t *handle, uint64_t usage, const Rect& bounds,
C2PlanarLayout *layout, uint8_t **addr) {
@@ -797,6 +921,7 @@
}
+
class C2AllocationGralloc : public C2GraphicAllocation {
public:
virtual ~C2AllocationGralloc() override;
@@ -863,7 +988,7 @@
C2AllocationGralloc::~C2AllocationGralloc() {
if (mBuffer && mLocked) {
- // implementation ignores addresss and rect
+ // implementation ignores address and rect
uint8_t* addr[C2PlanarLayout::MAX_NUM_PLANES] = {};
unmap(addr, C2Rect(), nullptr);
}
@@ -1124,4 +1249,321 @@
return C2HandleGralloc::IsValid(o);
}
+
+native_handle_t *UnwrapNativeCodec2AhwbHandle(const C2Handle *const handle) {
+ return C2HandleAhwb::UnwrapNativeHandle(handle);
+}
+
+C2Handle *WrapNativeCodec2AhwbHandle(
+ const native_handle_t *const handle,
+ uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride,
+ uint64_t origId) {
+ return C2HandleAhwb::WrapNativeHandle(handle, width, height, format, usage, stride,
+ origId);
+}
+
+class C2AllocationAhwb : public C2GraphicAllocation {
+public:
+ virtual ~C2AllocationAhwb() override;
+
+ virtual c2_status_t map(
+ C2Rect c2Rect, C2MemoryUsage usage, C2Fence *fence,
+ C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
+ virtual c2_status_t unmap(
+ uint8_t **addr /* nonnull */, C2Rect rect, C2Fence *fence /* nullable */) override;
+ virtual C2Allocator::id_t getAllocatorId() const override { return mAllocatorId; }
+ virtual const C2Handle *handle() const override { return mLockedHandle ? : mHandle; }
+ virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
+
+ // internal methods
+ // |handle| will be moved.
+
+ C2AllocationAhwb(
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t layerCount,
+ uint64_t grallocUsage, uint32_t stride,
+ const C2HandleAhwb *const handle,
+ C2Allocator::id_t allocatorId);
+ int dup() const;
+ c2_status_t status() const;
+
+private:
+ const uint32_t mWidth;
+ const uint32_t mHeight;
+ const uint32_t mFormat;
+ const uint32_t mLayerCount;
+ const uint64_t mGrallocUsage;
+ const uint32_t mStride;
+ const native_handle_t *mRawHandle;
+ const C2HandleAhwb *mHandle;
+ buffer_handle_t mBuffer;
+ const C2HandleAhwb *mLockedHandle;
+ bool mLocked;
+ C2Allocator::id_t mAllocatorId;
+ std::mutex mMappedLock;
+};
+
+C2AllocationAhwb::C2AllocationAhwb(
+ uint32_t width, uint32_t height,
+ uint32_t format, uint32_t layerCount,
+ uint64_t grallocUsage, uint32_t stride,
+ const C2HandleAhwb *const handle,
+ C2Allocator::id_t allocatorId)
+ : C2GraphicAllocation(width, height),
+ mWidth(width),
+ mHeight(height),
+ mFormat(format),
+ mLayerCount(layerCount),
+ mGrallocUsage(grallocUsage),
+ mStride(stride),
+ mRawHandle(C2HandleAhwb::UnwrapNativeHandle(handle)),
+ mHandle(handle),
+ mBuffer(nullptr),
+ mLockedHandle(nullptr),
+ mLocked(false),
+ mAllocatorId(allocatorId) {
+}
+
+C2AllocationAhwb::~C2AllocationAhwb() {
+ if (mBuffer && mLocked) {
+ // implementation ignores address and rect
+ uint8_t* addr[C2PlanarLayout::MAX_NUM_PLANES] = {};
+ unmap(addr, C2Rect(), nullptr);
+ }
+ if (mBuffer) {
+ status_t err = GraphicBufferMapper::get().freeBuffer(mBuffer);
+ if (err) {
+ ALOGE("failed transaction: freeBuffer");
+ }
+ }
+ if (mRawHandle) {
+ native_handle_close(
+ const_cast<native_handle_t *>(
+ reinterpret_cast<const native_handle_t *>(mRawHandle)));
+ native_handle_delete(
+ const_cast<native_handle_t *>(
+ reinterpret_cast<const native_handle_t *>(mRawHandle)));
+ }
+ if (mHandle) {
+ native_handle_delete(
+ const_cast<native_handle_t *>(reinterpret_cast<const native_handle_t *>(mHandle)));
+ }
+ if (mLockedHandle) {
+ native_handle_delete(
+ const_cast<native_handle_t *>(
+ reinterpret_cast<const native_handle_t *>(mLockedHandle)));
+ }
+}
+
+c2_status_t C2AllocationAhwb::map(
+ C2Rect c2Rect, C2MemoryUsage usage, C2Fence *fence,
+ C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+ const Rect rect{(int32_t)c2Rect.left, (int32_t)c2Rect.top,
+ (int32_t)(c2Rect.left + c2Rect.width) /* right */,
+ (int32_t)(c2Rect.top + c2Rect.height) /* bottom */};
+
+ uint64_t grallocUsage = static_cast<C2AndroidMemoryUsage>(usage).asGrallocUsage();
+ ALOGV("mapping buffer with usage %#llx => %#llx",
+ (long long)usage.expected, (long long)grallocUsage);
+
+ // TODO
+ (void)fence;
+
+ std::lock_guard<std::mutex> lock(mMappedLock);
+ if (mBuffer && mLocked) {
+ ALOGD("already mapped");
+ return C2_DUPLICATE;
+ }
+ if (!layout || !addr) {
+ ALOGD("wrong param");
+ return C2_BAD_VALUE;
+ }
+
+ if (!mBuffer) {
+ // TODO: libui/libgui dependency removal (b/214400477)
+ status_t err = GraphicBufferMapper::get().importBuffer(
+ mRawHandle, mWidth, mHeight, mLayerCount,
+ mFormat, mGrallocUsage, mStride, &mBuffer);
+ if (err) {
+ ALOGE("failed transaction: importBuffer");
+ return C2_CORRUPTED;
+ }
+ if (mBuffer == nullptr) {
+ ALOGD("importBuffer returned null buffer");
+ return C2_CORRUPTED;
+ }
+ uint64_t origId = 0;
+ if (mHandle) {
+ mHandle->getOrigId(&origId);
+ }
+
+ mLockedHandle = C2HandleAhwb::WrapAndMoveNativeHandle(
+ mBuffer, mWidth, mHeight, mFormat, mGrallocUsage,
+ mStride, origId);
+ }
+
+ c2_status_t ret = PopulatePlaneLayout(
+ mBuffer, rect, mFormat, grallocUsage, mStride, layout, addr);
+ if (ret != C2_OK) {
+ return ret;
+ }
+ mLocked = true;
+
+ HandleInterleavedPlanes(layout, addr);
+
+ ALOGV("C2AllocationGralloc::map: layout: type=%d numPlanes=%d rootPlanes=%d",
+ layout->type, layout->numPlanes, layout->rootPlanes);
+ for (int i = 0; i < layout->numPlanes; ++i) {
+ const C2PlaneInfo &plane = layout->planes[i];
+ ALOGV("C2AllocationGralloc::map: plane[%d]: colInc=%d rowInc=%d rootIx=%u offset=%u",
+ i, plane.colInc, plane.rowInc, plane.rootIx, plane.offset);
+ }
+
+ return C2_OK;
+}
+
+c2_status_t C2AllocationAhwb::unmap(
+ uint8_t **addr, C2Rect rect, C2Fence *fence /* nullable */) {
+ // TODO: check addr and size, use fence
+ (void)addr;
+ (void)rect;
+ (void)fence;
+
+ std::lock_guard<std::mutex> lock(mMappedLock);
+ // TODO: fence
+ status_t err = GraphicBufferMapper::get().unlock(mBuffer);
+ if (err) {
+ ALOGE("failed transaction: unlock");
+ return C2_CORRUPTED;
+ }
+
+ mLocked = false;
+ return C2_OK;
+}
+
+bool C2AllocationAhwb::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
+ return other && other->handle() == handle();
+}
+
+/* ===================================== AHARDWAREBUFFER ALLOCATOR ============================= */
+class C2AllocatorAhwb::Impl {
+public:
+ Impl(id_t id);
+
+ id_t getId() const {
+ return mTraits->id;
+ }
+
+ C2String getName() const {
+ return mTraits->name;
+ }
+
+ std::shared_ptr<const C2Allocator::Traits> getTraits() const {
+ return mTraits;
+ }
+
+ c2_status_t newGraphicAllocation(
+ uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+ std::shared_ptr<C2GraphicAllocation> *allocation);
+
+ c2_status_t priorGraphicAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *allocation);
+
+ c2_status_t status() const { return mInit; }
+
+private:
+ std::shared_ptr<C2Allocator::Traits> mTraits;
+ c2_status_t mInit;
+};
+
+void _UnwrapNativeCodec2AhwbMetadata(
+ const C2Handle *const handle,
+ uint32_t *width, uint32_t *height, uint32_t *format,uint64_t *usage, uint32_t *stride,
+ uint64_t *origId) {
+ (void)C2HandleAhwb::Import(handle, width, height, format, usage, stride, origId);
+}
+
+C2AllocatorAhwb::Impl::Impl(id_t id)
+ : mInit(C2_OK) {
+ // TODO: get this from allocator
+ C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 };
+ Traits traits = { "android.allocator.ahwb", id, C2Allocator::GRAPHIC, minUsage, maxUsage };
+ mTraits = std::make_shared<C2Allocator::Traits>(traits);
+}
+
+c2_status_t C2AllocatorAhwb::Impl::newGraphicAllocation(
+ uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+ std::shared_ptr<C2GraphicAllocation> *allocation) {
+ // TODO: for client side usage
+ // HAL side Ahwb allocation should be done via IGBA currently.
+ (void) width;
+ (void) height;
+ (void) format;
+ (void) usage;
+ (void) allocation;
+ return C2_OMITTED;
+}
+
+c2_status_t C2AllocatorAhwb::Impl::priorGraphicAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *allocation) {
+
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint32_t layerCount = 1;
+ uint64_t grallocUsage;
+ uint32_t stride;
+ uint64_t origId;
+
+ const C2HandleAhwb *ahwbHandle = C2HandleAhwb::Import(
+ handle, &width, &height, &format, &grallocUsage, &stride, &origId);
+ if (ahwbHandle == nullptr) {
+ return C2_BAD_VALUE;
+ }
+
+ allocation->reset(new C2AllocationAhwb(
+ width, height, format, layerCount,
+ grallocUsage, stride, ahwbHandle, mTraits->id));
+ return C2_OK;
+}
+
+C2AllocatorAhwb::C2AllocatorAhwb(id_t id)
+ : mImpl(new Impl(id)) {}
+
+C2AllocatorAhwb::~C2AllocatorAhwb() { delete mImpl; }
+
+C2Allocator::id_t C2AllocatorAhwb::getId() const {
+ return mImpl->getId();
+}
+
+C2String C2AllocatorAhwb::getName() const {
+ return mImpl->getName();
+}
+
+std::shared_ptr<const C2Allocator::Traits> C2AllocatorAhwb::getTraits() const {
+ return mImpl->getTraits();
+}
+
+c2_status_t C2AllocatorAhwb::newGraphicAllocation(
+ uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicAllocation> *allocation) {
+ return mImpl->newGraphicAllocation(width, height, format, usage, allocation);
+}
+
+c2_status_t C2AllocatorAhwb::priorGraphicAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *allocation) {
+ return mImpl->priorGraphicAllocation(handle, allocation);
+}
+
+c2_status_t C2AllocatorAhwb::status() const {
+ return mImpl->status();
+}
+
+// static
+bool C2AllocatorAhwb::CheckHandle(const C2Handle* const o) {
+ return C2HandleAhwb::IsValid(o);
+}
} // namespace android
diff --git a/media/codec2/vndk/include/C2AllocatorGralloc.h b/media/codec2/vndk/include/C2AllocatorGralloc.h
index 4b4a45d..1a34c30 100644
--- a/media/codec2/vndk/include/C2AllocatorGralloc.h
+++ b/media/codec2/vndk/include/C2AllocatorGralloc.h
@@ -70,6 +70,36 @@
uint32_t *width, uint32_t *height, uint32_t *format, uint64_t *usage, uint32_t *stride,
uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot);
+/**
+ * Unwrap the native handle from a Codec2 handle allocated by C2AllocatorAhwb.
+ *
+ * @param handle a handle allocated by C2AllocatorAhwb. This includes handles returned for a
+ * graphic block allocation handle based on an AHardwareBuffer.
+ *
+ * @return a new NON-OWNING native handle that must be deleted using native_handle_delete.
+ */
+native_handle_t *UnwrapNativeCodec2AhwbHandle(const C2Handle *const handle);
+
+/**
+ * Wrap the gralloc handle and metadata based on AHardwareBuffer into Codec2 handle
+ * recognized by C2AllocatorAhwb.
+ *
+ * @return a new NON-OWNING C2Handle that must be closed and deleted using native_handle_close and
+ * native_handle_delete.
+ */
+C2Handle *WrapNativeCodec2AhwbHandle(
+ const native_handle_t *const handle,
+ uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride,
+ uint64_t origId);
+
+/**
+ * \todo Get this from the buffer
+ */
+void _UnwrapNativeCodec2AhwbMetadata(
+ const C2Handle *const handle,
+ uint32_t *width, uint32_t *height, uint32_t *format, uint64_t *usage, uint32_t *stride,
+ uint64_t *origId);
+
class C2AllocatorGralloc : public C2Allocator {
public:
virtual id_t getId() const override;
@@ -104,6 +134,53 @@
Impl *mImpl;
};
+/**
+ * C2Allocator for AHardwareBuffer based allocation.
+ *
+ * C2Allocator interface is based on C2Handle, which is actually wrapped
+ * native_handle_t. This is based on extracted handle from AHardwareBuffer.
+ * Trying to recover an AHardwareBuffer from C2GraphicAllocation created by the
+ * allocator will creates a new AHardwareBuffer with a different unique Id, but
+ * it is identical and will use same memory by the handle.
+ *
+ * C2GraphicAllocation does not have the original AHardwareBuffer. But
+ * C2GraphicBlock and C2ConstGraphicBlock has the original AHardwareBuffer,
+ * which can be sent to the other processes.
+ *
+ * TODO: Bundle AHardwareBuffer for C2GraphicAllocation.
+ * TODO: Add support for C2AllocatorBlob.
+ */
+class C2AllocatorAhwb : public C2Allocator {
+public:
+ virtual id_t getId() const override;
+
+ virtual C2String getName() const override;
+
+ virtual std::shared_ptr<const Traits> getTraits() const override;
+
+ virtual c2_status_t newGraphicAllocation(
+ uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+ virtual c2_status_t priorGraphicAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+ C2AllocatorAhwb(id_t id);
+
+ c2_status_t status() const;
+
+ virtual ~C2AllocatorAhwb() override;
+
+ virtual bool checkHandle(const C2Handle* const o) const override { return CheckHandle(o); }
+
+ static bool CheckHandle(const C2Handle* const o);
+
+private:
+ class Impl;
+ Impl *mImpl;
+};
+
} // namespace android
#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_