Move Codec2-related code from hardware/google/av
Test: None
Bug: 112362730
Change-Id: Ie2f8ff431d65c40333f267ab9877d47089adeea4
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
new file mode 100644
index 0000000..cabe7ee
--- /dev/null
+++ b/media/codec2/vndk/Android.bp
@@ -0,0 +1,105 @@
+cc_library_headers {
+ name: "libstagefright_codec2_internal",
+
+ export_include_dirs: [
+ "internal",
+ ],
+
+ // TODO: Remove this when this module is moved back to frameworks/av.
+ vendor_available: true,
+}
+
+// !!!DO NOT DEPEND ON THIS SHARED LIBRARY DIRECTLY!!!
+// use libstagefright_codec2-impl-defaults instead
+cc_library_shared {
+ name: "libstagefright_codec2_vndk",
+ vendor_available: true,
+
+ srcs: [
+ "C2AllocatorIon.cpp",
+ "C2AllocatorGralloc.cpp",
+ "C2Buffer.cpp",
+ "C2Config.cpp",
+ "C2PlatformStorePluginLoader.cpp",
+ "C2Store.cpp",
+ "platform/C2BqBuffer.cpp",
+ "util/C2Debug.cpp",
+ "util/C2InterfaceHelper.cpp",
+ "util/C2InterfaceUtils.cpp",
+ "util/C2ParamUtils.cpp",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ export_shared_lib_headers: [
+ "libbase",
+ "android.hardware.media.bufferpool@1.0",
+ ],
+
+ local_include_dirs: [
+ "internal",
+ ],
+
+ include_dirs: [
+ "frameworks/native/include/media/hardware",
+ "hardware/google/av/codec2/include",
+ ],
+
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.media.bufferpool@1.0",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libdl",
+ "libhardware",
+ "libhidlbase",
+ "libion",
+ "libfmq",
+ "liblog",
+ "libstagefright_bufferqueue_helper",
+ "libstagefright_foundation",
+ "libstagefright_bufferpool@1.0",
+ "libui",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
+
+// public dependency for implementing Codec 2 components
+cc_defaults {
+ name: "libstagefright_codec2-impl-defaults",
+
+ shared_libs: [
+ "libbase", // for C2_LOG
+ "liblog", // for ALOG
+ "libstagefright_codec2",
+ "libstagefright_codec2_vndk",
+ "libutils",
+ ],
+}
+
+// public dependency for implementing Codec 2 framework utilities
+// THIS IS ONLY FOR FRAMEWORK USE ONLY
+cc_defaults {
+ name: "libstagefright_codec2-internal-defaults",
+ defaults: ["libstagefright_codec2-impl-defaults"],
+
+ shared_libs: [
+ "libcutils", // for properties
+ ],
+
+ // TODO: separate internal headers so they can be exposed here
+}
+
+subdirs = [
+ "bufferpool",
+]
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
new file mode 100644
index 0000000..22e8d84
--- /dev/null
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -0,0 +1,743 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2AllocatorGralloc"
+#include <utils/Log.h>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <cutils/native_handle.h>
+#include <hardware/gralloc.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2Buffer.h>
+#include <C2PlatformSupport.h>
+
+namespace android {
+
+namespace {
+ enum : uint64_t {
+ /**
+ * Usage mask that is passed through from gralloc to Codec 2.0 usage.
+ */
+ PASSTHROUGH_USAGE_MASK =
+ ~(GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_PROTECTED)
+ };
+
+ // verify that passthrough mask is within the platform mask
+ static_assert((~C2MemoryUsage::PLATFORM_MASK & PASSTHROUGH_USAGE_MASK) == 0, "");
+}
+
+C2MemoryUsage C2AndroidMemoryUsage::FromGrallocUsage(uint64_t usage) {
+ // gralloc does not support WRITE_PROTECTED
+ return C2MemoryUsage(
+ ((usage & GRALLOC_USAGE_SW_READ_MASK) ? C2MemoryUsage::CPU_READ : 0) |
+ ((usage & GRALLOC_USAGE_SW_WRITE_MASK) ? C2MemoryUsage::CPU_WRITE : 0) |
+ ((usage & GRALLOC_USAGE_PROTECTED) ? C2MemoryUsage::READ_PROTECTED : 0) |
+ (usage & PASSTHROUGH_USAGE_MASK));
+}
+
+uint64_t C2AndroidMemoryUsage::asGrallocUsage() const {
+ // gralloc does not support WRITE_PROTECTED
+ return (((expected & C2MemoryUsage::CPU_READ) ? GRALLOC_USAGE_SW_READ_OFTEN : 0) |
+ ((expected & C2MemoryUsage::CPU_WRITE) ? GRALLOC_USAGE_SW_WRITE_OFTEN : 0) |
+ ((expected & C2MemoryUsage::READ_PROTECTED) ? GRALLOC_USAGE_PROTECTED : 0) |
+ (expected & PASSTHROUGH_USAGE_MASK));
+}
+
+using ::android::hardware::graphics::allocator::V2_0::IAllocator;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+using ::android::hardware::graphics::mapper::V2_0::Error;
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_vec;
+
+namespace {
+
+struct BufferDescriptorInfo {
+ IMapper::BufferDescriptorInfo mapperInfo;
+ uint32_t stride;
+};
+
+}
+
+/* ===================================== GRALLOC ALLOCATION ==================================== */
+static c2_status_t maperr2error(Error maperr) {
+ switch (maperr) {
+ case Error::NONE: return C2_OK;
+ case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
+ case Error::BAD_BUFFER: return C2_BAD_VALUE;
+ case Error::BAD_VALUE: return C2_BAD_VALUE;
+ case Error::NO_RESOURCES: return C2_NO_MEMORY;
+ case Error::UNSUPPORTED: return C2_CANNOT_DO;
+ }
+ return C2_CORRUPTED;
+}
+
+static
+bool native_handle_is_invalid(const native_handle_t *const handle) {
+ // perform basic validation of a native handle
+ if (handle == nullptr) {
+ // null handle is considered valid
+ return false;
+ }
+ return ((size_t)handle->version != sizeof(native_handle_t) ||
+ handle->numFds < 0 ||
+ handle->numInts < 0 ||
+ // for sanity assume handles must occupy less memory than INT_MAX bytes
+ handle->numFds > int((INT_MAX - handle->version) / sizeof(int)) - handle->numInts);
+}
+
+class C2HandleGralloc : public C2Handle {
+private:
+ struct ExtraData {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint32_t usage_lo;
+ uint32_t usage_hi;
+ uint32_t stride;
+ uint32_t generation;
+ uint32_t igbp_id_lo;
+ uint32_t igbp_id_hi;
+ uint32_t igbp_slot;
+ uint32_t magic;
+ };
+
+ enum {
+ NUM_INTS = sizeof(ExtraData) / sizeof(int),
+ };
+ const static uint32_t MAGIC = '\xc2gr\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 getIgbpData(uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) const {
+ const ExtraData *ed = getExtraData(this);
+ *generation = ed->generation;
+ *igbp_id = unsigned(ed->igbp_id_lo) | uint64_t(unsigned(ed->igbp_id_hi)) << 32;
+ *igbp_slot = ed->igbp_slot;
+ }
+
+ 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 C2HandleGralloc* WrapNativeHandle(
+ const native_handle_t *const handle,
+ uint32_t width, uint32_t height, uint32_t format, uint64_t usage,
+ uint32_t stride, uint32_t generation, uint64_t igbp_id = 0, uint32_t igbp_slot = 0) {
+ //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, generation, uint32_t(igbp_id & 0xFFFFFFFF), uint32_t(igbp_id >> 32),
+ igbp_slot, 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<C2HandleGralloc *>(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 native_handle_t* UnwrapNativeHandle(
+ const C2Handle *const handle,
+ uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) {
+ const ExtraData *xd = getExtraData(handle);
+ if (xd == nullptr || xd->magic != MAGIC) {
+ return nullptr;
+ }
+ *generation = xd->generation;
+ *igbp_id = unsigned(xd->igbp_id_lo) | uint64_t(unsigned(xd->igbp_id_hi)) << 32;
+ *igbp_slot = xd->igbp_slot;
+ 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 C2HandleGralloc* Import(
+ const C2Handle *const handle,
+ 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) {
+ 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;
+ *generation = xd->generation;
+ *igbp_id = xd->igbp_id_lo | (uint64_t(xd->igbp_id_hi) << 32);
+ *igbp_slot = xd->igbp_slot;
+ return reinterpret_cast<const C2HandleGralloc *>(handle);
+ }
+};
+
+native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle) {
+ return C2HandleGralloc::UnwrapNativeHandle(handle);
+}
+
+native_handle_t *UnwrapNativeCodec2GrallocHandle(
+ const C2Handle *const handle,
+ uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) {
+ return C2HandleGralloc::UnwrapNativeHandle(handle, generation, igbp_id, igbp_slot);
+}
+
+C2Handle *WrapNativeCodec2GrallocHandle(
+ const native_handle_t *const handle,
+ 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) {
+ return C2HandleGralloc::WrapNativeHandle(handle, width, height, format, usage, stride,
+ generation, igbp_id, igbp_slot);
+}
+
+class C2AllocationGralloc : public C2GraphicAllocation {
+public:
+ virtual ~C2AllocationGralloc() override;
+
+ virtual c2_status_t map(
+ C2Rect rect, 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.
+ C2AllocationGralloc(
+ const BufferDescriptorInfo &info,
+ const sp<IMapper> &mapper,
+ hidl_handle &hidlHandle,
+ const C2HandleGralloc *const handle,
+ C2Allocator::id_t allocatorId);
+ int dup() const;
+ c2_status_t status() const;
+
+private:
+ const BufferDescriptorInfo mInfo;
+ const sp<IMapper> mMapper;
+ const hidl_handle mHidlHandle;
+ const C2HandleGralloc *mHandle;
+ buffer_handle_t mBuffer;
+ const C2HandleGralloc *mLockedHandle;
+ bool mLocked;
+ C2Allocator::id_t mAllocatorId;
+ std::mutex mMappedLock;
+};
+
+C2AllocationGralloc::C2AllocationGralloc(
+ const BufferDescriptorInfo &info,
+ const sp<IMapper> &mapper,
+ hidl_handle &hidlHandle,
+ const C2HandleGralloc *const handle,
+ C2Allocator::id_t allocatorId)
+ : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height),
+ mInfo(info),
+ mMapper(mapper),
+ mHidlHandle(std::move(hidlHandle)),
+ mHandle(handle),
+ mBuffer(nullptr),
+ mLockedHandle(nullptr),
+ mLocked(false),
+ mAllocatorId(allocatorId) {
+}
+
+C2AllocationGralloc::~C2AllocationGralloc() {
+ if (!mBuffer) {
+ return;
+ }
+ if (mLocked) {
+ // implementation ignores addresss and rect
+ uint8_t* addr[C2PlanarLayout::MAX_NUM_PLANES] = {};
+ unmap(addr, C2Rect(), nullptr);
+ }
+ mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
+ native_handle_delete(const_cast<native_handle_t*>(
+ reinterpret_cast<const native_handle_t*>(mHandle)));
+}
+
+c2_status_t C2AllocationGralloc::map(
+ C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
+ C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+ 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;
+ }
+
+ c2_status_t err = C2_OK;
+ if (!mBuffer) {
+ mMapper->importBuffer(
+ mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
+ err = maperr2error(maperr);
+ if (err == C2_OK) {
+ mBuffer = static_cast<buffer_handle_t>(buffer);
+ }
+ });
+ if (err != C2_OK) {
+ ALOGD("importBuffer failed: %d", err);
+ return err;
+ }
+ if (mBuffer == nullptr) {
+ ALOGD("importBuffer returned null buffer");
+ return C2_CORRUPTED;
+ }
+ uint32_t generation = 0;
+ uint64_t igbp_id = 0;
+ uint32_t igbp_slot = 0;
+ if (mHandle) {
+ mHandle->getIgbpData(&generation, &igbp_id, &igbp_slot);
+ }
+ mLockedHandle = C2HandleGralloc::WrapNativeHandle(
+ mBuffer, mInfo.mapperInfo.width, mInfo.mapperInfo.height,
+ (uint32_t)mInfo.mapperInfo.format, mInfo.mapperInfo.usage, mInfo.stride,
+ generation, igbp_id, igbp_slot);
+ }
+
+ // UGLY HACK: assume YCbCr 4:2:0 8-bit format (and lockable via lockYCbCr) if we don't
+ // recognize the format
+ PixelFormat format = mInfo.mapperInfo.format;
+ if (format != PixelFormat::RGBA_8888 && format != PixelFormat::RGBX_8888) {
+ format = PixelFormat::YCBCR_420_888;
+ }
+
+ switch (format) {
+ case PixelFormat::YCBCR_420_888:
+ case PixelFormat::YV12: {
+ YCbCrLayout ycbcrLayout;
+ mMapper->lockYCbCr(
+ const_cast<native_handle_t *>(mBuffer), grallocUsage,
+ { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height },
+ // TODO: fence
+ hidl_handle(),
+ [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
+ err = maperr2error(maperr);
+ if (err == C2_OK) {
+ ycbcrLayout = mapLayout;
+ }
+ });
+ if (err != C2_OK) {
+ ALOGD("lockYCbCr failed: %d", err);
+ return err;
+ }
+ addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
+ addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
+ addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
+ layout->type = C2PlanarLayout::TYPE_YUV;
+ layout->numPlanes = 3;
+ layout->rootPlanes = 3;
+ layout->planes[C2PlanarLayout::PLANE_Y] = {
+ C2PlaneInfo::CHANNEL_Y, // channel
+ 1, // colInc
+ (int32_t)ycbcrLayout.yStride, // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_Y, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_U] = {
+ C2PlaneInfo::CHANNEL_CB, // channel
+ (int32_t)ycbcrLayout.chromaStep, // colInc
+ (int32_t)ycbcrLayout.cStride, // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_U, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_V] = {
+ C2PlaneInfo::CHANNEL_CR, // channel
+ (int32_t)ycbcrLayout.chromaStep, // colInc
+ (int32_t)ycbcrLayout.cStride, // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_V, // rootIx
+ 0, // offset
+ };
+ // handle interleaved formats
+ intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
+ if (uvOffset > 0 && uvOffset < (intptr_t)ycbcrLayout.chromaStep) {
+ layout->rootPlanes = 2;
+ layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
+ layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
+ } else if (uvOffset < 0 && uvOffset > -(intptr_t)ycbcrLayout.chromaStep) {
+ layout->rootPlanes = 2;
+ layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
+ layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
+ }
+ break;
+ }
+
+ case PixelFormat::RGBA_8888:
+ // TODO: alpha channel
+ // fall-through
+ case PixelFormat::RGBX_8888: {
+ void *pointer = nullptr;
+ mMapper->lock(
+ const_cast<native_handle_t *>(mBuffer),
+ grallocUsage,
+ { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height },
+ // TODO: fence
+ hidl_handle(),
+ [&err, &pointer](const auto &maperr, const auto &mapPointer) {
+ err = maperr2error(maperr);
+ if (err == C2_OK) {
+ pointer = mapPointer;
+ }
+ });
+ if (err != C2_OK) {
+ ALOGD("lock failed: %d", err);
+ return err;
+ }
+ addr[C2PlanarLayout::PLANE_R] = (uint8_t *)pointer;
+ addr[C2PlanarLayout::PLANE_G] = (uint8_t *)pointer + 1;
+ addr[C2PlanarLayout::PLANE_B] = (uint8_t *)pointer + 2;
+ layout->type = C2PlanarLayout::TYPE_RGB;
+ layout->numPlanes = 3;
+ layout->rootPlanes = 1;
+ layout->planes[C2PlanarLayout::PLANE_R] = {
+ C2PlaneInfo::CHANNEL_R, // channel
+ 4, // colInc
+ 4 * (int32_t)mInfo.stride, // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_R, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_G] = {
+ C2PlaneInfo::CHANNEL_G, // channel
+ 4, // colInc
+ 4 * (int32_t)mInfo.stride, // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_R, // rootIx
+ 1, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_B] = {
+ C2PlaneInfo::CHANNEL_B, // channel
+ 4, // colInc
+ 4 * (int32_t)mInfo.stride, // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_R, // rootIx
+ 2, // offset
+ };
+ break;
+ }
+ default: {
+ ALOGD("unsupported pixel format: %d", mInfo.mapperInfo.format);
+ return C2_OMITTED;
+ }
+ }
+ mLocked = true;
+
+ return C2_OK;
+}
+
+c2_status_t C2AllocationGralloc::unmap(
+ uint8_t **addr, C2Rect rect, C2Fence *fence /* nullable */) {
+ // TODO: check addr and size, use fence
+ (void)addr;
+ (void)rect;
+
+ std::lock_guard<std::mutex> lock(mMappedLock);
+ c2_status_t err = C2_OK;
+ mMapper->unlock(
+ const_cast<native_handle_t *>(mBuffer),
+ [&err, &fence](const auto &maperr, const auto &releaseFence) {
+ // TODO
+ (void) fence;
+ (void) releaseFence;
+ err = maperr2error(maperr);
+ if (err == C2_OK) {
+ // TODO: fence
+ }
+ });
+ if (err == C2_OK) {
+ mLocked = false;
+ }
+ return err;
+}
+
+bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
+ return other && other->handle() == handle();
+}
+
+/* ===================================== GRALLOC ALLOCATOR ==================================== */
+class C2AllocatorGralloc::Impl {
+public:
+ Impl(id_t id, bool bufferQueue);
+
+ 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;
+ sp<IAllocator> mAllocator;
+ sp<IMapper> mMapper;
+ const bool mBufferQueue;
+};
+
+void _UnwrapNativeCodec2GrallocMetadata(
+ const C2Handle *const handle,
+ 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) {
+ (void)C2HandleGralloc::Import(handle, width, height, format, usage, stride,
+ generation, igbp_id, igbp_slot);
+}
+
+C2AllocatorGralloc::Impl::Impl(id_t id, bool bufferQueue)
+ : mInit(C2_OK), mBufferQueue(bufferQueue) {
+ // TODO: get this from allocator
+ C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 };
+ Traits traits = { "android.allocator.gralloc", id, C2Allocator::GRAPHIC, minUsage, maxUsage };
+ mTraits = std::make_shared<C2Allocator::Traits>(traits);
+
+ // gralloc allocator is a singleton, so all objects share a global service
+ mAllocator = IAllocator::getService();
+ mMapper = IMapper::getService();
+ if (mAllocator == nullptr || mMapper == nullptr) {
+ mInit = C2_CORRUPTED;
+ }
+}
+
+c2_status_t C2AllocatorGralloc::Impl::newGraphicAllocation(
+ uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+ std::shared_ptr<C2GraphicAllocation> *allocation) {
+ uint64_t grallocUsage = static_cast<C2AndroidMemoryUsage>(usage).asGrallocUsage();
+ ALOGV("allocating buffer with usage %#llx => %#llx",
+ (long long)usage.expected, (long long)grallocUsage);
+
+ BufferDescriptorInfo info = {
+ {
+ width,
+ height,
+ 1u, // layerCount
+ (PixelFormat)format,
+ grallocUsage,
+ },
+ 0u, // stride placeholder
+ };
+ c2_status_t err = C2_OK;
+ BufferDescriptor desc;
+ mMapper->createDescriptor(
+ info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) {
+ err = maperr2error(maperr);
+ if (err == C2_OK) {
+ desc = descriptor;
+ }
+ });
+ if (err != C2_OK) {
+ return err;
+ }
+
+ // IAllocator shares IMapper error codes.
+ hidl_handle buffer;
+ mAllocator->allocate(
+ desc,
+ 1u,
+ [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) {
+ err = maperr2error(maperr);
+ if (err != C2_OK) {
+ return;
+ }
+ if (buffers.size() != 1u) {
+ err = C2_CORRUPTED;
+ return;
+ }
+ info.stride = stride;
+ buffer = std::move(buffers[0]);
+ });
+ if (err != C2_OK) {
+ return err;
+ }
+
+
+ allocation->reset(new C2AllocationGralloc(
+ info, mMapper, buffer,
+ C2HandleGralloc::WrapNativeHandle(
+ buffer.getNativeHandle(),
+ info.mapperInfo.width, info.mapperInfo.height,
+ (uint32_t)info.mapperInfo.format, info.mapperInfo.usage, info.stride,
+ 0, 0, mBufferQueue ? ~0 : 0),
+ mTraits->id));
+ return C2_OK;
+}
+
+c2_status_t C2AllocatorGralloc::Impl::priorGraphicAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *allocation) {
+ BufferDescriptorInfo info;
+ info.mapperInfo.layerCount = 1u;
+ uint32_t generation;
+ uint64_t igbp_id;
+ uint32_t igbp_slot;
+ const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
+ handle,
+ &info.mapperInfo.width, &info.mapperInfo.height,
+ (uint32_t *)&info.mapperInfo.format, (uint64_t *)&info.mapperInfo.usage, &info.stride,
+ &generation, &igbp_id, &igbp_slot);
+ if (grallocHandle == nullptr) {
+ return C2_BAD_VALUE;
+ }
+
+ hidl_handle hidlHandle;
+ hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true);
+
+ allocation->reset(new C2AllocationGralloc(info, mMapper, hidlHandle, grallocHandle, mTraits->id));
+ return C2_OK;
+}
+
+C2AllocatorGralloc::C2AllocatorGralloc(id_t id, bool bufferQueue)
+ : mImpl(new Impl(id, bufferQueue)) {}
+
+C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
+
+C2Allocator::id_t C2AllocatorGralloc::getId() const {
+ return mImpl->getId();
+}
+
+C2String C2AllocatorGralloc::getName() const {
+ return mImpl->getName();
+}
+
+std::shared_ptr<const C2Allocator::Traits> C2AllocatorGralloc::getTraits() const {
+ return mImpl->getTraits();
+}
+
+c2_status_t C2AllocatorGralloc::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 C2AllocatorGralloc::priorGraphicAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *allocation) {
+ return mImpl->priorGraphicAllocation(handle, allocation);
+}
+
+c2_status_t C2AllocatorGralloc::status() const {
+ return mImpl->status();
+}
+
+bool C2AllocatorGralloc::isValid(const C2Handle* const o) {
+ return C2HandleGralloc::isValid(o);
+}
+
+} // namespace android
diff --git a/media/codec2/vndk/C2AllocatorIon.cpp b/media/codec2/vndk/C2AllocatorIon.cpp
new file mode 100644
index 0000000..736aac5
--- /dev/null
+++ b/media/codec2/vndk/C2AllocatorIon.cpp
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2AllocatorIon"
+#include <utils/Log.h>
+
+#include <list>
+
+#include <ion/ion.h>
+#include <sys/mman.h>
+#include <unistd.h> // getpagesize, size_t, close, dup
+
+#include <C2AllocatorIon.h>
+#include <C2Buffer.h>
+#include <C2Debug.h>
+#include <C2ErrnoUtils.h>
+
+namespace android {
+
+namespace {
+ constexpr size_t USAGE_LRU_CACHE_SIZE = 1024;
+}
+
+/* size_t <=> int(lo), int(hi) conversions */
+constexpr inline int size2intLo(size_t s) {
+ return int(s & 0xFFFFFFFF);
+}
+
+constexpr inline int size2intHi(size_t s) {
+ // cast to uint64_t as size_t may be 32 bits wide
+ return int((uint64_t(s) >> 32) & 0xFFFFFFFF);
+}
+
+constexpr inline size_t ints2size(int intLo, int intHi) {
+ // convert in 2 stages to 64 bits as intHi may be negative
+ return size_t(unsigned(intLo)) | size_t(uint64_t(unsigned(intHi)) << 32);
+}
+
+/* ========================================= ION HANDLE ======================================== */
+/**
+ * ION handle
+ *
+ * There can be only a sole ion client per process, this is captured in the ion fd that is passed
+ * to the constructor, but this should be managed by the ion buffer allocator/mapper.
+ *
+ * ion uses ion_user_handle_t for buffers. We don't store this in the native handle as
+ * it requires an ion_free to decref. Instead, we share the buffer to get an fd that also holds
+ * a refcount.
+ *
+ * This handle will not capture mapped fd-s as updating that would require a global mutex.
+ */
+
+struct C2HandleIon : public C2Handle {
+ // ion handle owns ionFd(!) and bufferFd
+ C2HandleIon(int bufferFd, size_t size)
+ : C2Handle(cHeader),
+ mFds{ bufferFd },
+ mInts{ int(size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } { }
+
+ static bool isValid(const C2Handle * const o);
+
+ int bufferFd() const { return mFds.mBuffer; }
+ size_t size() const {
+ return size_t(unsigned(mInts.mSizeLo))
+ | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
+ }
+
+protected:
+ struct {
+ int mBuffer; // shared ion buffer
+ } mFds;
+ struct {
+ int mSizeLo; // low 32-bits of size
+ int mSizeHi; // high 32-bits of size
+ int mMagic;
+ } mInts;
+
+private:
+ typedef C2HandleIon _type;
+ enum {
+ kMagic = '\xc2io\x00',
+ numFds = sizeof(mFds) / sizeof(int),
+ numInts = sizeof(mInts) / sizeof(int),
+ version = sizeof(C2Handle)
+ };
+ //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
+ const static C2Handle cHeader;
+};
+
+const C2Handle C2HandleIon::cHeader = {
+ C2HandleIon::version,
+ C2HandleIon::numFds,
+ C2HandleIon::numInts,
+ {}
+};
+
+// static
+bool C2HandleIon::isValid(const C2Handle * const o) {
+ if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
+ return false;
+ }
+ const C2HandleIon *other = static_cast<const C2HandleIon*>(o);
+ return other->mInts.mMagic == kMagic;
+}
+
+// TODO: is the dup of an ion fd identical to ion_share?
+
+/* ======================================= ION ALLOCATION ====================================== */
+class C2AllocationIon : public C2LinearAllocation {
+public:
+ /* Interface methods */
+ virtual c2_status_t map(
+ size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence,
+ void **addr /* nonnull */) override;
+ virtual c2_status_t unmap(void *addr, size_t size, C2Fence *fenceFd) override;
+ virtual ~C2AllocationIon() override;
+ virtual const C2Handle *handle() const override;
+ virtual id_t getAllocatorId() const override;
+ virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const override;
+
+ // internal methods
+ C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id);
+ C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id);
+
+ c2_status_t status() const;
+
+protected:
+ class Impl;
+ Impl *mImpl;
+
+ // TODO: we could make this encapsulate shared_ptr and copiable
+ C2_DO_NOT_COPY(C2AllocationIon);
+};
+
+class C2AllocationIon::Impl {
+private:
+ /**
+ * Constructs an ion allocation.
+ *
+ * \note We always create an ion allocation, even if the allocation or import fails
+ * so that we can capture the error.
+ *
+ * \param ionFd ion client (ownership transferred to created object)
+ * \param capacity size of allocation
+ * \param bufferFd buffer handle (ownership transferred to created object). Must be
+ * invalid if err is not 0.
+ * \param buffer ion buffer user handle (ownership transferred to created object). Must be
+ * 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)
+ : mIonFd(ionFd),
+ mHandle(bufferFd, capacity),
+ mBuffer(buffer),
+ mId(id),
+ mInit(c2_map_errno<ENOMEM, EACCES, EINVAL>(err)),
+ mMapFd(-1) {
+ if (mInit != C2_OK) {
+ // close ionFd now on error
+ if (mIonFd >= 0) {
+ close(mIonFd);
+ mIonFd = -1;
+ }
+ // C2_CHECK(bufferFd < 0);
+ // C2_CHECK(buffer < 0);
+ }
+ }
+
+public:
+ /**
+ * Constructs an ion allocation by importing a shared buffer fd.
+ *
+ * \param ionFd ion client (ownership transferred to created object)
+ * \param capacity size of allocation
+ * \param bufferFd buffer handle (ownership transferred to created object)
+ *
+ * \return created ion allocation (implementation) which may be invalid if the
+ * import failed.
+ */
+ 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);
+ }
+
+ /**
+ * Constructs an ion allocation by allocating an ion buffer.
+ *
+ * \param ionFd ion client (ownership transferred to created object)
+ * \param size size of allocation
+ * \param align desired alignment of allocation
+ * \param heapMask mask of heaps considered
+ * \param flags ion allocation flags
+ *
+ * \return created ion allocation (implementation) which may be invalid if the
+ * allocation failed.
+ */
+ static Impl *Alloc(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id) {
+ int bufferFd = -1;
+ ion_user_handle_t buffer = -1;
+ size_t alignedSize = align == 0 ? size : (size + align - 1) & ~(align - 1);
+ int ret = ion_alloc(ionFd, alignedSize, align, heapMask, flags, &buffer);
+ ALOGV("ion_alloc(ionFd = %d, size = %zu, align = %zu, prot = %d, flags = %d) "
+ "returned (%d) ; buffer = %d",
+ ionFd, alignedSize, align, heapMask, flags, ret, buffer);
+ if (ret == 0) {
+ // get buffer fd for native handle constructor
+ ret = ion_share(ionFd, buffer, &bufferFd);
+ if (ret != 0) {
+ ion_free(ionFd, buffer);
+ buffer = -1;
+ }
+ }
+ return new Impl(ionFd, alignedSize, bufferFd, buffer, id, ret);
+ }
+
+ c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
+ (void)fence; // TODO: wait for fence
+ *addr = nullptr;
+ if (!mMappings.empty()) {
+ ALOGV("multiple map");
+ // TODO: technically we should return DUPLICATE here, but our block views don't
+ // actually unmap, so we end up remapping an ion buffer multiple times.
+ //
+ // return C2_DUPLICATE;
+ }
+ if (size == 0) {
+ return C2_BAD_VALUE;
+ }
+
+ int prot = PROT_NONE;
+ int flags = MAP_SHARED;
+ if (usage.expected & C2MemoryUsage::CPU_READ) {
+ prot |= PROT_READ;
+ }
+ if (usage.expected & C2MemoryUsage::CPU_WRITE) {
+ prot |= PROT_WRITE;
+ }
+
+ size_t alignmentBytes = offset % PAGE_SIZE;
+ size_t mapOffset = offset - alignmentBytes;
+ size_t mapSize = size + alignmentBytes;
+ Mapping map = { nullptr, alignmentBytes, mapSize };
+
+ c2_status_t err = C2_OK;
+ if (mMapFd == -1) {
+ int ret = ion_map(mIonFd, mBuffer, mapSize, prot,
+ flags, mapOffset, (unsigned char**)&map.addr, &mMapFd);
+ ALOGV("ion_map(ionFd = %d, handle = %d, size = %zu, prot = %d, flags = %d, "
+ "offset = %zu) returned (%d)",
+ mIonFd, mBuffer, mapSize, prot, flags, mapOffset, ret);
+ if (ret) {
+ mMapFd = -1;
+ map.addr = *addr = nullptr;
+ err = c2_map_errno<EINVAL>(-ret);
+ } else {
+ *addr = (uint8_t *)map.addr + alignmentBytes;
+ }
+ } else {
+ map.addr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
+ ALOGV("mmap(size = %zu, prot = %d, flags = %d, mapFd = %d, offset = %zu) "
+ "returned (%d)",
+ mapSize, prot, flags, mMapFd, mapOffset, errno);
+ if (map.addr == MAP_FAILED) {
+ map.addr = *addr = nullptr;
+ err = c2_map_errno<EINVAL>(errno);
+ } else {
+ *addr = (uint8_t *)map.addr + alignmentBytes;
+ }
+ }
+ if (map.addr) {
+ mMappings.push_back(map);
+ }
+ return err;
+ }
+
+ c2_status_t unmap(void *addr, size_t size, C2Fence *fence) {
+ if (mMapFd < 0 || mMappings.empty()) {
+ ALOGD("tried to unmap unmapped buffer");
+ return C2_NOT_FOUND;
+ }
+ for (auto it = mMappings.begin(); it != mMappings.end(); ++it) {
+ if (addr != (uint8_t *)it->addr + it->alignmentBytes ||
+ size + it->alignmentBytes != it->size) {
+ continue;
+ }
+ int err = munmap(it->addr, it->size);
+ if (err != 0) {
+ ALOGD("munmap failed");
+ return c2_map_errno<EINVAL>(errno);
+ }
+ if (fence) {
+ *fence = C2Fence(); // not using fences
+ }
+ (void)mMappings.erase(it);
+ ALOGV("successfully unmapped: %d", mBuffer);
+ return C2_OK;
+ }
+ ALOGD("unmap failed to find specified map");
+ return C2_BAD_VALUE;
+ }
+
+ ~Impl() {
+ if (!mMappings.empty()) {
+ ALOGD("Dangling mappings!");
+ for (const Mapping &map : mMappings) {
+ (void)munmap(map.addr, map.size);
+ }
+ }
+ if (mMapFd >= 0) {
+ close(mMapFd);
+ mMapFd = -1;
+ }
+ if (mInit == C2_OK) {
+ (void)ion_free(mIonFd, mBuffer);
+ native_handle_close(&mHandle);
+ }
+ if (mIonFd >= 0) {
+ close(mIonFd);
+ }
+ }
+
+ c2_status_t status() const {
+ return mInit;
+ }
+
+ const C2Handle *handle() const {
+ return &mHandle;
+ }
+
+ C2Allocator::id_t getAllocatorId() const {
+ return mId;
+ }
+
+ ion_user_handle_t ionHandle() const {
+ return mBuffer;
+ }
+
+private:
+ int mIonFd;
+ C2HandleIon mHandle;
+ ion_user_handle_t mBuffer;
+ C2Allocator::id_t mId;
+ c2_status_t mInit;
+ int mMapFd; // only one for now
+ struct Mapping {
+ void *addr;
+ size_t alignmentBytes;
+ size_t size;
+ };
+ std::list<Mapping> mMappings;
+};
+
+c2_status_t C2AllocationIon::map(
+ size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
+ return mImpl->map(offset, size, usage, fence, addr);
+}
+
+c2_status_t C2AllocationIon::unmap(void *addr, size_t size, C2Fence *fence) {
+ return mImpl->unmap(addr, size, fence);
+}
+
+c2_status_t C2AllocationIon::status() const {
+ return mImpl->status();
+}
+
+C2Allocator::id_t C2AllocationIon::getAllocatorId() const {
+ return mImpl->getAllocatorId();
+}
+
+bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
+ if (!other || other->getAllocatorId() != getAllocatorId()) {
+ return false;
+ }
+ // get user handle to compare objects
+ std::shared_ptr<C2AllocationIon> otherAsIon = std::static_pointer_cast<C2AllocationIon>(other);
+ return mImpl->ionHandle() == otherAsIon->mImpl->ionHandle();
+}
+
+const C2Handle *C2AllocationIon::handle() const {
+ return mImpl->handle();
+}
+
+C2AllocationIon::~C2AllocationIon() {
+ delete mImpl;
+}
+
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align,
+ unsigned heapMask, unsigned flags, C2Allocator::id_t id)
+ : C2LinearAllocation(size),
+ mImpl(Impl::Alloc(ionFd, size, align, heapMask, flags, id)) { }
+
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id)
+ : C2LinearAllocation(size),
+ mImpl(Impl::Import(ionFd, size, shareFd, id)) { }
+
+/* ======================================= ION ALLOCATOR ====================================== */
+C2AllocatorIon::C2AllocatorIon(id_t id)
+ : mInit(C2_OK),
+ mIonFd(ion_open()) {
+ if (mIonFd < 0) {
+ switch (errno) {
+ case ENOENT: mInit = C2_OMITTED; break;
+ default: mInit = c2_map_errno<EACCES>(errno); break;
+ }
+ } else {
+ C2MemoryUsage minUsage = { 0, 0 };
+ C2MemoryUsage maxUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+ Traits traits = { "android.allocator.ion", id, LINEAR, minUsage, maxUsage };
+ mTraits = std::make_shared<Traits>(traits);
+ mBlockSize = ::getpagesize();
+ }
+}
+
+C2AllocatorIon::~C2AllocatorIon() {
+ if (mInit == C2_OK) {
+ ion_close(mIonFd);
+ }
+}
+
+C2Allocator::id_t C2AllocatorIon::getId() const {
+ std::lock_guard<std::mutex> lock(mUsageMapperLock);
+ return mTraits->id;
+}
+
+C2String C2AllocatorIon::getName() const {
+ std::lock_guard<std::mutex> lock(mUsageMapperLock);
+ return mTraits->name;
+}
+
+std::shared_ptr<const C2Allocator::Traits> C2AllocatorIon::getTraits() const {
+ std::lock_guard<std::mutex> lock(mUsageMapperLock);
+ return mTraits;
+}
+
+void C2AllocatorIon::setUsageMapper(
+ const UsageMapperFn &mapper, uint64_t minUsage, uint64_t maxUsage, uint64_t blockSize) {
+ std::lock_guard<std::mutex> lock(mUsageMapperLock);
+ mUsageMapperCache.clear();
+ mUsageMapperLru.clear();
+ mUsageMapper = mapper;
+ Traits traits = {
+ mTraits->name, mTraits->id, LINEAR,
+ C2MemoryUsage(minUsage), C2MemoryUsage(maxUsage)
+ };
+ mTraits = std::make_shared<Traits>(traits);
+ mBlockSize = blockSize;
+}
+
+std::size_t C2AllocatorIon::MapperKeyHash::operator()(const MapperKey &k) const {
+ return std::hash<uint64_t>{}(k.first) ^ std::hash<size_t>{}(k.second);
+}
+
+c2_status_t C2AllocatorIon::mapUsage(
+ C2MemoryUsage usage, size_t capacity, size_t *align, unsigned *heapMask, unsigned *flags) {
+ std::lock_guard<std::mutex> lock(mUsageMapperLock);
+ c2_status_t res = C2_OK;
+ // align capacity
+ capacity = (capacity + mBlockSize - 1) & ~(mBlockSize - 1);
+ MapperKey key = std::make_pair(usage.expected, capacity);
+ auto entry = mUsageMapperCache.find(key);
+ if (entry == mUsageMapperCache.end()) {
+ if (mUsageMapper) {
+ res = mUsageMapper(usage, capacity, align, heapMask, flags);
+ } else {
+ *align = 0; // TODO make this 1
+ *heapMask = ~0; // default mask
+ *flags = 0; // default flags
+ res = C2_NO_INIT;
+ }
+ // add usage to cache
+ MapperValue value = std::make_tuple(*align, *heapMask, *flags, res);
+ mUsageMapperLru.emplace_front(key, value);
+ mUsageMapperCache.emplace(std::make_pair(key, mUsageMapperLru.begin()));
+ if (mUsageMapperCache.size() > USAGE_LRU_CACHE_SIZE) {
+ // remove LRU entry
+ MapperKey lruKey = mUsageMapperLru.front().first;
+ mUsageMapperCache.erase(lruKey);
+ mUsageMapperLru.pop_back();
+ }
+ } else {
+ // move entry to MRU
+ mUsageMapperLru.splice(mUsageMapperLru.begin(), mUsageMapperLru, entry->second);
+ const MapperValue &value = entry->second->second;
+ std::tie(*align, *heapMask, *flags, res) = value;
+ }
+ return res;
+}
+
+c2_status_t C2AllocatorIon::newLinearAllocation(
+ uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation> *allocation) {
+ if (allocation == nullptr) {
+ return C2_BAD_VALUE;
+ }
+
+ allocation->reset();
+ if (mInit != C2_OK) {
+ return mInit;
+ }
+
+ size_t align = 0;
+ unsigned heapMask = ~0;
+ unsigned flags = 0;
+ c2_status_t ret = mapUsage(usage, capacity, &align, &heapMask, &flags);
+ if (ret && ret != C2_NO_INIT) {
+ return ret;
+ }
+
+ std::shared_ptr<C2AllocationIon> alloc
+ = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, mTraits->id);
+ ret = alloc->status();
+ if (ret == C2_OK) {
+ *allocation = alloc;
+ }
+ return ret;
+}
+
+c2_status_t C2AllocatorIon::priorLinearAllocation(
+ const C2Handle *handle, std::shared_ptr<C2LinearAllocation> *allocation) {
+ *allocation = nullptr;
+ if (mInit != C2_OK) {
+ return mInit;
+ }
+
+ if (!C2HandleIon::isValid(handle)) {
+ return C2_BAD_VALUE;
+ }
+
+ // TODO: get capacity and validate it
+ const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
+ std::shared_ptr<C2AllocationIon> alloc
+ = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), mTraits->id);
+ c2_status_t ret = alloc->status();
+ if (ret == C2_OK) {
+ *allocation = alloc;
+ native_handle_delete(const_cast<native_handle_t*>(
+ reinterpret_cast<const native_handle_t*>(handle)));
+ }
+ return ret;
+}
+
+bool C2AllocatorIon::isValid(const C2Handle* const o) {
+ return C2HandleIon::isValid(o);
+}
+
+} // namespace android
+
diff --git a/media/codec2/vndk/C2Buffer.cpp b/media/codec2/vndk/C2Buffer.cpp
new file mode 100644
index 0000000..47366ca
--- /dev/null
+++ b/media/codec2/vndk/C2Buffer.cpp
@@ -0,0 +1,1304 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2Buffer"
+#include <utils/Log.h>
+
+#include <list>
+#include <map>
+#include <mutex>
+
+#include <C2AllocatorIon.h>
+#include <C2AllocatorGralloc.h>
+#include <C2BufferPriv.h>
+#include <C2BlockInternal.h>
+#include <bufferpool/ClientManager.h>
+
+namespace {
+
+using android::C2AllocatorGralloc;
+using android::C2AllocatorIon;
+using android::hardware::media::bufferpool::BufferPoolData;
+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;
+using android::hardware::media::bufferpool::V1_0::implementation::INVALID_CONNECTIONID;
+
+// This anonymous namespace contains the helper classes that allow our implementation to create
+// block/buffer objects.
+//
+// Inherit from the parent, share with the friend.
+class ReadViewBuddy : public C2ReadView {
+ using C2ReadView::C2ReadView;
+ friend class ::C2ConstLinearBlock;
+};
+
+class WriteViewBuddy : public C2WriteView {
+ using C2WriteView::C2WriteView;
+ friend class ::C2LinearBlock;
+};
+
+class ConstLinearBlockBuddy : public C2ConstLinearBlock {
+ using C2ConstLinearBlock::C2ConstLinearBlock;
+ friend class ::C2LinearBlock;
+};
+
+class LinearBlockBuddy : public C2LinearBlock {
+ using C2LinearBlock::C2LinearBlock;
+ friend class ::C2BasicLinearBlockPool;
+};
+
+class AcquirableReadViewBuddy : public C2Acquirable<C2ReadView> {
+ using C2Acquirable::C2Acquirable;
+ friend class ::C2ConstLinearBlock;
+};
+
+class AcquirableWriteViewBuddy : public C2Acquirable<C2WriteView> {
+ using C2Acquirable::C2Acquirable;
+ friend class ::C2LinearBlock;
+};
+
+class GraphicViewBuddy : public C2GraphicView {
+ using C2GraphicView::C2GraphicView;
+ friend class ::C2ConstGraphicBlock;
+ friend class ::C2GraphicBlock;
+};
+
+class AcquirableConstGraphicViewBuddy : public C2Acquirable<const C2GraphicView> {
+ using C2Acquirable::C2Acquirable;
+ friend class ::C2ConstGraphicBlock;
+};
+
+class AcquirableGraphicViewBuddy : public C2Acquirable<C2GraphicView> {
+ using C2Acquirable::C2Acquirable;
+ friend class ::C2GraphicBlock;
+};
+
+class ConstGraphicBlockBuddy : public C2ConstGraphicBlock {
+ using C2ConstGraphicBlock::C2ConstGraphicBlock;
+ friend class ::C2GraphicBlock;
+};
+
+class GraphicBlockBuddy : public C2GraphicBlock {
+ using C2GraphicBlock::C2GraphicBlock;
+ friend class ::C2BasicGraphicBlockPool;
+};
+
+class BufferDataBuddy : public C2BufferData {
+ using C2BufferData::C2BufferData;
+ friend class ::C2Buffer;
+};
+
+} // namespace
+
+/* ========================================== 1D BLOCK ========================================= */
+
+/**
+ * This class is the base class for all 1D block and view implementations.
+ *
+ * This is basically just a placeholder for the underlying 1D allocation and the range of the
+ * alloted portion to this block. There is also a placeholder for a blockpool data.
+ */
+class C2_HIDE _C2Block1DImpl : public _C2LinearRangeAspect {
+public:
+ _C2Block1DImpl(const std::shared_ptr<C2LinearAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
+ size_t offset = 0, size_t size = ~(size_t)0)
+ : _C2LinearRangeAspect(alloc.get(), offset, size),
+ mAllocation(alloc),
+ mPoolData(poolData) { }
+
+ _C2Block1DImpl(const _C2Block1DImpl &other, size_t offset = 0, size_t size = ~(size_t)0)
+ : _C2LinearRangeAspect(&other, offset, size),
+ mAllocation(other.mAllocation),
+ mPoolData(other.mPoolData) { }
+
+ /** returns pool data */
+ std::shared_ptr<_C2BlockPoolData> poolData() const {
+ return mPoolData;
+ }
+
+ /** returns native handle */
+ const C2Handle *handle() const {
+ return mAllocation ? mAllocation->handle() : nullptr;
+ }
+
+ /** returns the allocator's ID */
+ C2Allocator::id_t getAllocatorId() const {
+ // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
+ return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
+ }
+
+ std::shared_ptr<C2LinearAllocation> getAllocation() const {
+ return mAllocation;
+ }
+
+private:
+ std::shared_ptr<C2LinearAllocation> mAllocation;
+ std::shared_ptr<_C2BlockPoolData> mPoolData;
+};
+
+/**
+ * This class contains the mapped data pointer, and the potential error.
+ *
+ * range is the mapped range of the underlying allocation (which is part of the allotted
+ * range).
+ */
+class C2_HIDE _C2MappedBlock1DImpl : public _C2Block1DImpl {
+public:
+ _C2MappedBlock1DImpl(const _C2Block1DImpl &block, uint8_t *data,
+ size_t offset = 0, size_t size = ~(size_t)0)
+ : _C2Block1DImpl(block, offset, size), mData(data), mError(C2_OK) { }
+
+ _C2MappedBlock1DImpl(c2_status_t error)
+ : _C2Block1DImpl(nullptr), mData(nullptr), mError(error) {
+ // CHECK(error != C2_OK);
+ }
+
+ const uint8_t *data() const {
+ return mData;
+ }
+
+ uint8_t *data() {
+ return mData;
+ }
+
+ c2_status_t error() const {
+ return mError;
+ }
+
+private:
+ uint8_t *mData;
+ c2_status_t mError;
+};
+
+/**
+ * Block implementation.
+ */
+class C2Block1D::Impl : public _C2Block1DImpl {
+ using _C2Block1DImpl::_C2Block1DImpl;
+};
+
+const C2Handle *C2Block1D::handle() const {
+ return mImpl->handle();
+};
+
+C2Allocator::id_t C2Block1D::getAllocatorId() const {
+ return mImpl->getAllocatorId();
+};
+
+C2Block1D::C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
+ // always clamp subrange to parent (impl) range for safety
+ : _C2LinearRangeAspect(impl.get(), range.offset(), range.size()), mImpl(impl) {
+}
+
+/**
+ * Read view implementation.
+ *
+ * range of Impl is the mapped range of the underlying allocation (which is part of the allotted
+ * range). range of View is 0 to capacity() (not represented as an actual range). This maps to a
+ * subrange of Impl range starting at mImpl->offset() + _mOffset.
+ */
+class C2ReadView::Impl : public _C2MappedBlock1DImpl {
+ using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
+};
+
+C2ReadView::C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size)
+ : _C2LinearCapacityAspect(C2LinearCapacity(impl->size()).range(offset, size).size()),
+ mImpl(impl),
+ mOffset(C2LinearCapacity(impl->size()).range(offset, size).offset()) { }
+
+C2ReadView::C2ReadView(c2_status_t error)
+ : _C2LinearCapacityAspect(0u), mImpl(std::make_shared<Impl>(error)), mOffset(0u) {
+ // CHECK(error != C2_OK);
+}
+
+const uint8_t *C2ReadView::data() const {
+ return mImpl->error() ? nullptr : mImpl->data() + mOffset;
+}
+
+c2_status_t C2ReadView::error() const {
+ return mImpl->error();
+}
+
+C2ReadView C2ReadView::subView(size_t offset, size_t size) const {
+ C2LinearRange subRange(*this, offset, size);
+ return C2ReadView(mImpl, mOffset + subRange.offset(), subRange.size());
+}
+
+/**
+ * Write view implementation.
+ */
+class C2WriteView::Impl : public _C2MappedBlock1DImpl {
+ using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
+};
+
+C2WriteView::C2WriteView(std::shared_ptr<Impl> impl)
+// UGLY: _C2LinearRangeAspect requires a bona-fide object for capacity to prevent spoofing, so
+// this is what we have to do.
+// TODO: use childRange
+ : _C2EditableLinearRangeAspect(std::make_unique<C2LinearCapacity>(impl->size()).get()), mImpl(impl) { }
+
+C2WriteView::C2WriteView(c2_status_t error)
+ : _C2EditableLinearRangeAspect(nullptr), mImpl(std::make_shared<Impl>(error)) {}
+
+uint8_t *C2WriteView::base() { return mImpl->data(); }
+
+uint8_t *C2WriteView::data() { return mImpl->data() + offset(); }
+
+c2_status_t C2WriteView::error() const { return mImpl->error(); }
+
+/**
+ * Const linear block implementation.
+ */
+C2ConstLinearBlock::C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence fence)
+ : C2Block1D(impl, range), mFence(fence) { }
+
+C2Acquirable<C2ReadView> C2ConstLinearBlock::map() const {
+ void *base = nullptr;
+ uint32_t len = size();
+ c2_status_t error = mImpl->getAllocation()->map(
+ offset(), len, { C2MemoryUsage::CPU_READ, 0 }, nullptr, &base);
+ // TODO: wait on fence
+ if (error == C2_OK) {
+ std::shared_ptr<ReadViewBuddy::Impl> rvi = std::shared_ptr<ReadViewBuddy::Impl>(
+ new ReadViewBuddy::Impl(*mImpl, (uint8_t *)base, offset(), len),
+ [base, len](ReadViewBuddy::Impl *i) {
+ (void)i->getAllocation()->unmap(base, len, nullptr);
+ delete i;
+ });
+ return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(rvi, 0, len));
+ } else {
+ return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(error));
+ }
+}
+
+C2ConstLinearBlock C2ConstLinearBlock::subBlock(size_t offset_, size_t size_) const {
+ C2LinearRange subRange(*mImpl, offset_, size_);
+ return C2ConstLinearBlock(mImpl, subRange, mFence);
+}
+
+/**
+ * Linear block implementation.
+ */
+C2LinearBlock::C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
+ : C2Block1D(impl, range) { }
+
+C2Acquirable<C2WriteView> C2LinearBlock::map() {
+ void *base = nullptr;
+ uint32_t len = size();
+ c2_status_t error = mImpl->getAllocation()->map(
+ offset(), len, { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, nullptr, &base);
+ // TODO: wait on fence
+ if (error == C2_OK) {
+ std::shared_ptr<WriteViewBuddy::Impl> rvi = std::shared_ptr<WriteViewBuddy::Impl>(
+ new WriteViewBuddy::Impl(*mImpl, (uint8_t *)base, 0, len),
+ [base, len](WriteViewBuddy::Impl *i) {
+ (void)i->getAllocation()->unmap(base, len, nullptr);
+ delete i;
+ });
+ return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(rvi));
+ } else {
+ return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(error));
+ }
+}
+
+C2ConstLinearBlock C2LinearBlock::share(size_t offset_, size_t size_, C2Fence fence) {
+ return ConstLinearBlockBuddy(mImpl, C2LinearRange(*this, offset_, size_), fence);
+}
+
+C2BasicLinearBlockPool::C2BasicLinearBlockPool(
+ const std::shared_ptr<C2Allocator> &allocator)
+ : mAllocator(allocator) { }
+
+c2_status_t C2BasicLinearBlockPool::fetchLinearBlock(
+ uint32_t capacity,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+ block->reset();
+
+ std::shared_ptr<C2LinearAllocation> alloc;
+ c2_status_t err = mAllocator->newLinearAllocation(capacity, usage, &alloc);
+ if (err != C2_OK) {
+ return err;
+ }
+
+ *block = _C2BlockFactory::CreateLinearBlock(alloc);
+
+ return C2_OK;
+}
+
+struct C2_HIDE C2PooledBlockPoolData : _C2BlockPoolData {
+
+ virtual type_t getType() const override {
+ return TYPE_BUFFERPOOL;
+ }
+
+ void getBufferPoolData(std::shared_ptr<BufferPoolData> *data) const {
+ *data = mData;
+ }
+
+ C2PooledBlockPoolData(const std::shared_ptr<BufferPoolData> &data) : mData(data) {}
+
+ virtual ~C2PooledBlockPoolData() override {}
+
+private:
+ std::shared_ptr<BufferPoolData> mData;
+};
+
+bool _C2BlockFactory::GetBufferPoolData(
+ const std::shared_ptr<const _C2BlockPoolData> &data,
+ std::shared_ptr<BufferPoolData> *bufferPoolData) {
+ if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERPOOL) {
+ const std::shared_ptr<const C2PooledBlockPoolData> poolData =
+ std::static_pointer_cast<const C2PooledBlockPoolData>(data);
+ poolData->getBufferPoolData(bufferPoolData);
+ return true;
+ }
+ return false;
+}
+
+std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
+ const std::shared_ptr<C2LinearAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
+ std::shared_ptr<C2Block1D::Impl> impl =
+ std::make_shared<C2Block1D::Impl>(alloc, data, offset, size);
+ return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
+}
+
+std::shared_ptr<_C2BlockPoolData> _C2BlockFactory::GetLinearBlockPoolData(
+ const C2Block1D &block) {
+ if (block.mImpl) {
+ return block.mImpl->poolData();
+ }
+ return nullptr;
+}
+
+std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
+ const C2Handle *handle) {
+ // TODO: get proper allocator? and mutex?
+ static std::unique_ptr<C2AllocatorIon> sAllocator = std::make_unique<C2AllocatorIon>(0);
+
+ std::shared_ptr<C2LinearAllocation> alloc;
+ if (C2AllocatorIon::isValid(handle)) {
+ c2_status_t err = sAllocator->priorLinearAllocation(handle, &alloc);
+ if (err == C2_OK) {
+ std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(alloc);
+ return block;
+ }
+ }
+ return nullptr;
+}
+
+std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
+ const C2Handle *cHandle, const std::shared_ptr<BufferPoolData> &data) {
+ // TODO: get proper allocator? and mutex?
+ static std::unique_ptr<C2AllocatorIon> sAllocator = std::make_unique<C2AllocatorIon>(0);
+
+ std::shared_ptr<C2LinearAllocation> alloc;
+ if (C2AllocatorIon::isValid(cHandle)) {
+ native_handle_t *handle = native_handle_clone(cHandle);
+ if (handle) {
+ c2_status_t err = sAllocator->priorLinearAllocation(handle, &alloc);
+ const std::shared_ptr<C2PooledBlockPoolData> poolData =
+ std::make_shared<C2PooledBlockPoolData>(data);
+ if (err == C2_OK && poolData) {
+ // TODO: config params?
+ std::shared_ptr<C2LinearBlock> block =
+ _C2BlockFactory::CreateLinearBlock(alloc, poolData);
+ return block;
+ }
+ }
+ }
+ return nullptr;
+};
+
+/**
+ * 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> ¶ms,
+ std::shared_ptr<BufferPoolAllocation> *alloc,
+ size_t *allocSize) 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;
+};
+
+struct GraphicAllocationDtor {
+ GraphicAllocationDtor(const std::shared_ptr<C2GraphicAllocation> &alloc)
+ : mAllocation(alloc) {}
+
+ void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+
+ const std::shared_ptr<C2GraphicAllocation> mAllocation;
+};
+
+ResultStatus _C2BufferPoolAllocator::allocate(
+ const std::vector<uint8_t> ¶ms,
+ std::shared_ptr<BufferPoolAllocation> *alloc,
+ size_t *allocSize) {
+ AllocParams c2Params;
+ memcpy(&c2Params, params.data(), std::min(sizeof(AllocParams), params.size()));
+ c2_status_t status = C2_BAD_VALUE;
+ switch(c2Params.data.allocType) {
+ case ALLOC_NONE:
+ break;
+ case ALLOC_LINEAR: {
+ std::shared_ptr<C2LinearAllocation> c2Linear;
+ 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) {
+ *allocSize = (size_t)c2Params.data.params[0];
+ return ResultStatus::OK;
+ }
+ delete ptr;
+ }
+ return ResultStatus::NO_MEMORY;
+ }
+ break;
+ }
+ case ALLOC_GRAPHIC: {
+ std::shared_ptr<C2GraphicAllocation> c2Graphic;
+ status = mAllocator->newGraphicAllocation(
+ c2Params.data.params[0],
+ c2Params.data.params[1],
+ c2Params.data.params[2],
+ c2Params.data.usage, &c2Graphic);
+ if (status == C2_OK && c2Graphic) {
+ BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Graphic->handle());
+ if (ptr) {
+ *alloc = std::shared_ptr<BufferPoolAllocation>(
+ ptr, GraphicAllocationDtor(c2Graphic));
+ if (*alloc) {
+ *allocSize = c2Params.data.params[0] * c2Params.data.params[1];
+ return ResultStatus::OK;
+ }
+ delete ptr;
+ }
+ return ResultStatus::NO_MEMORY;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+bool _C2BufferPoolAllocator::compatible(
+ const std::vector<uint8_t> &newParams,
+ const std::vector<uint8_t> &oldParams) {
+ AllocParams newAlloc;
+ AllocParams oldAlloc;
+ memcpy(&newAlloc, newParams.data(), std::min(sizeof(AllocParams), newParams.size()));
+ memcpy(&oldAlloc, oldParams.data(), std::min(sizeof(AllocParams), oldParams.size()));
+
+ // TODO: support not exact matching. e.g) newCapacity < oldCapacity
+ if (newAlloc.data.allocType == oldAlloc.data.allocType &&
+ newAlloc.data.usage.expected == oldAlloc.data.usage.expected) {
+ for (int i = 0; i < kMaxIntParams; ++i) {
+ if (newAlloc.data.params[i] != oldAlloc.data.params[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, ¶ms);
+ std::shared_ptr<BufferPoolData> bufferPoolData;
+ native_handle_t *cHandle = nullptr;
+ ResultStatus status = mBufferPoolManager->allocate(
+ mConnectionId, params, &cHandle, &bufferPoolData);
+ if (status == ResultStatus::OK) {
+ native_handle_t *handle = native_handle_clone(cHandle);
+ if (handle) {
+ std::shared_ptr<C2LinearAllocation> alloc;
+ std::shared_ptr<C2PooledBlockPoolData> poolData =
+ std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
+ c2_status_t err = mAllocator->priorLinearAllocation(handle, &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;
+ }
+
+ c2_status_t fetchGraphicBlock(
+ uint32_t width, uint32_t height, uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block) {
+ block->reset();
+ if (mInit != C2_OK) {
+ return mInit;
+ }
+ std::vector<uint8_t> params;
+ mAllocator->getGraphicParams(width, height, format, usage, ¶ms);
+ std::shared_ptr<BufferPoolData> bufferPoolData;
+ native_handle_t *cHandle = nullptr;
+ ResultStatus status = mBufferPoolManager->allocate(
+ mConnectionId, params, &cHandle, &bufferPoolData);
+ if (status == ResultStatus::OK) {
+ native_handle_t *handle = native_handle_clone(cHandle);
+ if (handle) {
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ std::shared_ptr<C2PooledBlockPoolData> poolData =
+ std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
+ c2_status_t err = mAllocator->priorGraphicAllocation(
+ handle, &alloc);
+ if (err == C2_OK && poolData && alloc) {
+ *block = _C2BlockFactory::CreateGraphicBlock(
+ alloc, poolData, C2Rect(width, height));
+ if (*block) {
+ return C2_OK;
+ }
+ }
+ }
+ return C2_NO_MEMORY;
+ }
+ if (status == ResultStatus::NO_MEMORY) {
+ return C2_NO_MEMORY;
+ }
+ return C2_CORRUPTED;
+ }
+
+ ConnectionId getConnectionId() {
+ return mInit != C2_OK ? INVALID_CONNECTIONID : mConnectionId;
+ }
+
+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;
+}
+
+c2_status_t C2PooledBlockPool::fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block) {
+ if (mImpl) {
+ return mImpl->fetchGraphicBlock(width, height, format, usage, block);
+ }
+ return C2_CORRUPTED;
+}
+
+int64_t C2PooledBlockPool::getConnectionId() {
+ if (mImpl) {
+ return mImpl->getConnectionId();
+ }
+ return 0;
+}
+
+/* ========================================== 2D BLOCK ========================================= */
+
+/**
+ * Implementation that is shared between all 2D blocks and views.
+ *
+ * For blocks' Impl's crop is always the allotted crop, even if it is a sub block.
+ *
+ * For views' Impl's crop is the mapped portion - which for now is always the
+ * allotted crop.
+ */
+class C2_HIDE _C2Block2DImpl : public _C2PlanarSectionAspect {
+public:
+ /**
+ * Impl's crop is always the or part of the allotted crop of the allocation.
+ */
+ _C2Block2DImpl(const std::shared_ptr<C2GraphicAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
+ const C2Rect &allottedCrop = C2Rect(~0u, ~0u))
+ : _C2PlanarSectionAspect(alloc.get(), allottedCrop),
+ mAllocation(alloc),
+ mPoolData(poolData) { }
+
+ virtual ~_C2Block2DImpl() = default;
+
+ /** returns pool data */
+ std::shared_ptr<_C2BlockPoolData> poolData() const {
+ return mPoolData;
+ }
+
+ /** returns native handle */
+ const C2Handle *handle() const {
+ return mAllocation ? mAllocation->handle() : nullptr;
+ }
+
+ /** returns the allocator's ID */
+ C2Allocator::id_t getAllocatorId() const {
+ // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
+ return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
+ }
+
+ std::shared_ptr<C2GraphicAllocation> getAllocation() const {
+ return mAllocation;
+ }
+
+private:
+ std::shared_ptr<C2GraphicAllocation> mAllocation;
+ std::shared_ptr<_C2BlockPoolData> mPoolData;
+};
+
+class C2_HIDE _C2MappingBlock2DImpl
+ : public _C2Block2DImpl, public std::enable_shared_from_this<_C2MappingBlock2DImpl> {
+public:
+ using _C2Block2DImpl::_C2Block2DImpl;
+
+ virtual ~_C2MappingBlock2DImpl() override = default;
+
+ /**
+ * This class contains the mapped data pointer, and the potential error.
+ */
+ struct Mapped {
+ private:
+ friend class _C2MappingBlock2DImpl;
+
+ Mapped(const std::shared_ptr<_C2Block2DImpl> &impl, bool writable, C2Fence *fence __unused)
+ : mImpl(impl), mWritable(writable) {
+ memset(mData, 0, sizeof(mData));
+ const C2Rect crop = mImpl->crop();
+ // gralloc requires mapping the whole region of interest as we cannot
+ // map multiple regions
+ mError = mImpl->getAllocation()->map(
+ crop,
+ { C2MemoryUsage::CPU_READ, writable ? C2MemoryUsage::CPU_WRITE : 0 },
+ nullptr,
+ &mLayout,
+ mData);
+ if (mError != C2_OK) {
+ memset(&mLayout, 0, sizeof(mLayout));
+ memset(mData, 0, sizeof(mData));
+ memset(mOffsetData, 0, sizeof(mData));
+ } else {
+ // TODO: validate plane layout and
+ // adjust data pointers to the crop region's top left corner.
+ // fail if it is not on a subsampling boundary
+ for (size_t planeIx = 0; planeIx < mLayout.numPlanes; ++planeIx) {
+ const uint32_t colSampling = mLayout.planes[planeIx].colSampling;
+ const uint32_t rowSampling = mLayout.planes[planeIx].rowSampling;
+ if (crop.left % colSampling || crop.right() % colSampling
+ || crop.top % rowSampling || crop.bottom() % rowSampling) {
+ // cannot calculate data pointer
+ mImpl->getAllocation()->unmap(mData, crop, nullptr);
+ memset(&mLayout, 0, sizeof(mLayout));
+ memset(mData, 0, sizeof(mData));
+ memset(mOffsetData, 0, sizeof(mData));
+ mError = C2_BAD_VALUE;
+ return;
+ }
+ mOffsetData[planeIx] =
+ mData[planeIx] + (ssize_t)crop.left * mLayout.planes[planeIx].colInc
+ + (ssize_t)crop.top * mLayout.planes[planeIx].rowInc;
+ }
+ }
+ }
+
+ explicit Mapped(c2_status_t error)
+ : mImpl(nullptr), mWritable(false), mError(error) {
+ // CHECK(error != C2_OK);
+ memset(&mLayout, 0, sizeof(mLayout));
+ memset(mData, 0, sizeof(mData));
+ memset(mOffsetData, 0, sizeof(mData));
+ }
+
+ public:
+ ~Mapped() {
+ if (mData[0] != nullptr) {
+ mImpl->getAllocation()->unmap(mData, mImpl->crop(), nullptr);
+ }
+ }
+
+ /** returns mapping status */
+ c2_status_t error() const { return mError; }
+
+ /** returns data pointer */
+ uint8_t *const *data() const { return mOffsetData; }
+
+ /** returns the plane layout */
+ C2PlanarLayout layout() const { return mLayout; }
+
+ /** returns whether the mapping is writable */
+ bool writable() const { return mWritable; }
+
+ private:
+ const std::shared_ptr<_C2Block2DImpl> mImpl;
+ bool mWritable;
+ c2_status_t mError;
+ uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
+ uint8_t *mOffsetData[C2PlanarLayout::MAX_NUM_PLANES];
+ C2PlanarLayout mLayout;
+ };
+
+ /**
+ * Maps the allotted region.
+ *
+ * If already mapped and it is currently in use, returns the existing mapping.
+ * If fence is provided, an acquire fence is stored there.
+ */
+ std::shared_ptr<Mapped> map(bool writable, C2Fence *fence) {
+ std::lock_guard<std::mutex> lock(mMappedLock);
+ std::shared_ptr<Mapped> existing = mMapped.lock();
+ if (!existing) {
+ existing = std::shared_ptr<Mapped>(new Mapped(shared_from_this(), writable, fence));
+ mMapped = existing;
+ } else {
+ // if we mapped the region read-only, we cannot remap it read-write
+ if (writable && !existing->writable()) {
+ existing = std::shared_ptr<Mapped>(new Mapped(C2_CANNOT_DO));
+ }
+ if (fence != nullptr) {
+ *fence = C2Fence();
+ }
+ }
+ return existing;
+ }
+
+private:
+ std::weak_ptr<Mapped> mMapped;
+ std::mutex mMappedLock;
+};
+
+class C2_HIDE _C2MappedBlock2DImpl : public _C2Block2DImpl {
+public:
+ _C2MappedBlock2DImpl(const _C2Block2DImpl &impl,
+ std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping)
+ : _C2Block2DImpl(impl), mMapping(mapping) {
+ }
+
+ virtual ~_C2MappedBlock2DImpl() override = default;
+
+ std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping() const { return mMapping; }
+
+private:
+ std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mMapping;
+};
+
+/**
+ * Block implementation.
+ */
+class C2Block2D::Impl : public _C2MappingBlock2DImpl {
+public:
+ using _C2MappingBlock2DImpl::_C2MappingBlock2DImpl;
+ virtual ~Impl() override = default;
+};
+
+const C2Handle *C2Block2D::handle() const {
+ return mImpl->handle();
+}
+
+C2Allocator::id_t C2Block2D::getAllocatorId() const {
+ return mImpl->getAllocatorId();
+}
+
+C2Block2D::C2Block2D(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
+ // always clamp subsection to parent (impl) crop for safety
+ : _C2PlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
+}
+
+/**
+ * Graphic view implementation.
+ *
+ * range of Impl is the mapped range of the underlying allocation. range of View is the current
+ * crop.
+ */
+class C2GraphicView::Impl : public _C2MappedBlock2DImpl {
+public:
+ using _C2MappedBlock2DImpl::_C2MappedBlock2DImpl;
+ virtual ~Impl() override = default;
+};
+
+C2GraphicView::C2GraphicView(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
+ : _C2EditablePlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
+}
+
+const uint8_t *const *C2GraphicView::data() const {
+ return mImpl->mapping()->data();
+}
+
+uint8_t *const *C2GraphicView::data() {
+ return mImpl->mapping()->data();
+}
+
+const C2PlanarLayout C2GraphicView::layout() const {
+ return mImpl->mapping()->layout();
+}
+
+const C2GraphicView C2GraphicView::subView(const C2Rect &rect) const {
+ return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
+}
+
+C2GraphicView C2GraphicView::subView(const C2Rect &rect) {
+ return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
+}
+
+c2_status_t C2GraphicView::error() const {
+ return mImpl->mapping()->error();
+}
+
+/**
+ * Const graphic block implementation.
+ */
+C2ConstGraphicBlock::C2ConstGraphicBlock(
+ std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion, C2Fence fence)
+ : C2Block2D(impl, section), mFence(fence) { }
+
+C2Acquirable<const C2GraphicView> C2ConstGraphicBlock::map() const {
+ C2Fence fence;
+ std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
+ mImpl->map(false /* writable */, &fence);
+ std::shared_ptr<GraphicViewBuddy::Impl> gvi =
+ std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
+ return AcquirableConstGraphicViewBuddy(
+ mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
+}
+
+C2ConstGraphicBlock C2ConstGraphicBlock::subBlock(const C2Rect &rect) const {
+ return C2ConstGraphicBlock(mImpl, C2PlanarSection(*mImpl, crop().intersect(rect)), mFence);
+}
+
+/**
+ * Graphic block implementation.
+ */
+C2GraphicBlock::C2GraphicBlock(
+ std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
+ : C2Block2D(impl, section) { }
+
+C2Acquirable<C2GraphicView> C2GraphicBlock::map() {
+ C2Fence fence;
+ std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
+ mImpl->map(true /* writable */, &fence);
+ std::shared_ptr<GraphicViewBuddy::Impl> gvi =
+ std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
+ return AcquirableGraphicViewBuddy(
+ mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
+}
+
+C2ConstGraphicBlock C2GraphicBlock::share(const C2Rect &crop, C2Fence fence) {
+ return ConstGraphicBlockBuddy(mImpl, C2PlanarSection(*mImpl, crop), fence);
+}
+
+/**
+ * Basic block pool implementations.
+ */
+C2BasicGraphicBlockPool::C2BasicGraphicBlockPool(
+ const std::shared_ptr<C2Allocator> &allocator)
+ : mAllocator(allocator) {}
+
+c2_status_t C2BasicGraphicBlockPool::fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+ block->reset();
+
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ c2_status_t err = mAllocator->newGraphicAllocation(width, height, format, usage, &alloc);
+ if (err != C2_OK) {
+ return err;
+ }
+
+ *block = _C2BlockFactory::CreateGraphicBlock(alloc);
+
+ return C2_OK;
+}
+
+std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
+ const std::shared_ptr<C2GraphicAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &data, const C2Rect &allottedCrop) {
+ std::shared_ptr<C2Block2D::Impl> impl =
+ std::make_shared<C2Block2D::Impl>(alloc, data, allottedCrop);
+ return std::shared_ptr<C2GraphicBlock>(new C2GraphicBlock(impl, *impl));
+}
+
+std::shared_ptr<_C2BlockPoolData> _C2BlockFactory::GetGraphicBlockPoolData(
+ const C2Block2D &block) {
+ if (block.mImpl) {
+ return block.mImpl->poolData();
+ }
+ return nullptr;
+}
+
+std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
+ const C2Handle *cHandle,
+ const std::shared_ptr<BufferPoolData> &data) {
+ // TODO: get proper allocator? and mutex?
+ static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
+
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ if (C2AllocatorGralloc::isValid(cHandle)) {
+ native_handle_t *handle = native_handle_clone(cHandle);
+ if (handle) {
+ c2_status_t err = sAllocator->priorGraphicAllocation(handle, &alloc);
+ const std::shared_ptr<C2PooledBlockPoolData> poolData =
+ std::make_shared<C2PooledBlockPoolData>(data);
+ if (err == C2_OK && poolData) {
+ // TODO: config setup?
+ std::shared_ptr<C2GraphicBlock> block =
+ _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
+ return block;
+ }
+ }
+ }
+ return nullptr;
+};
+
+
+/* ========================================== BUFFER ========================================= */
+
+class C2BufferData::Impl {
+public:
+ explicit Impl(const std::vector<C2ConstLinearBlock> &blocks)
+ : mType(blocks.size() == 1 ? LINEAR : LINEAR_CHUNKS),
+ mLinearBlocks(blocks) {
+ }
+
+ explicit Impl(const std::vector<C2ConstGraphicBlock> &blocks)
+ : mType(blocks.size() == 1 ? GRAPHIC : GRAPHIC_CHUNKS),
+ mGraphicBlocks(blocks) {
+ }
+
+ type_t type() const { return mType; }
+ const std::vector<C2ConstLinearBlock> &linearBlocks() const { return mLinearBlocks; }
+ const std::vector<C2ConstGraphicBlock> &graphicBlocks() const { return mGraphicBlocks; }
+
+private:
+ type_t mType;
+ std::vector<C2ConstLinearBlock> mLinearBlocks;
+ std::vector<C2ConstGraphicBlock> mGraphicBlocks;
+};
+
+C2BufferData::C2BufferData(const std::vector<C2ConstLinearBlock> &blocks) : mImpl(new Impl(blocks)) {}
+C2BufferData::C2BufferData(const std::vector<C2ConstGraphicBlock> &blocks) : mImpl(new Impl(blocks)) {}
+
+C2BufferData::type_t C2BufferData::type() const { return mImpl->type(); }
+
+const std::vector<C2ConstLinearBlock> C2BufferData::linearBlocks() const {
+ return mImpl->linearBlocks();
+}
+
+const std::vector<C2ConstGraphicBlock> C2BufferData::graphicBlocks() const {
+ return mImpl->graphicBlocks();
+}
+
+class C2Buffer::Impl {
+public:
+ Impl(C2Buffer *thiz, const std::vector<C2ConstLinearBlock> &blocks)
+ : mThis(thiz), mData(blocks) {}
+ Impl(C2Buffer *thiz, const std::vector<C2ConstGraphicBlock> &blocks)
+ : mThis(thiz), mData(blocks) {}
+
+ ~Impl() {
+ for (const auto &pair : mNotify) {
+ pair.first(mThis, pair.second);
+ }
+ }
+
+ const C2BufferData &data() const { return mData; }
+
+ c2_status_t registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
+ 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;
+ }
+
+ c2_status_t unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
+ 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_NOT_FOUND;
+ }
+ mNotify.erase(it);
+ return C2_OK;
+ }
+
+ std::vector<std::shared_ptr<const C2Info>> info() const {
+ std::vector<std::shared_ptr<const C2Info>> result(mInfos.size());
+ std::transform(
+ mInfos.begin(), mInfos.end(), result.begin(),
+ [] (const auto &elem) { return elem.second; });
+ return result;
+ }
+
+ c2_status_t 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->coreIndex());
+ (void) mInfos.insert({ info->coreIndex(), info });
+ return C2_OK;
+ }
+
+ bool hasInfo(C2Param::Type index) const {
+ return mInfos.count(index.coreIndex()) > 0;
+ }
+
+ std::shared_ptr<const C2Info> getInfo(C2Param::Type index) const {
+ auto it = mInfos.find(index.coreIndex());
+ if (it == mInfos.end()) {
+ return nullptr;
+ }
+ return std::const_pointer_cast<const C2Info>(it->second);
+ }
+
+ std::shared_ptr<C2Info> removeInfo(C2Param::Type index) {
+ auto it = mInfos.find(index.coreIndex());
+ if (it == mInfos.end()) {
+ return nullptr;
+ }
+ std::shared_ptr<C2Info> ret = it->second;
+ (void) mInfos.erase(it);
+ return ret;
+ }
+
+private:
+ C2Buffer * const mThis;
+ BufferDataBuddy mData;
+ std::map<C2Param::CoreIndex, std::shared_ptr<C2Info>> mInfos;
+ std::list<std::pair<OnDestroyNotify, void *>> mNotify;
+};
+
+C2Buffer::C2Buffer(const std::vector<C2ConstLinearBlock> &blocks)
+ : mImpl(new Impl(this, blocks)) {}
+
+C2Buffer::C2Buffer(const std::vector<C2ConstGraphicBlock> &blocks)
+ : mImpl(new Impl(this, blocks)) {}
+
+const C2BufferData C2Buffer::data() const { return mImpl->data(); }
+
+c2_status_t C2Buffer::registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
+ return mImpl->registerOnDestroyNotify(onDestroyNotify, arg);
+}
+
+c2_status_t C2Buffer::unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg) {
+ return mImpl->unregisterOnDestroyNotify(onDestroyNotify, arg);
+}
+
+const std::vector<std::shared_ptr<const C2Info>> C2Buffer::info() const {
+ return mImpl->info();
+}
+
+c2_status_t 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<const C2Info> C2Buffer::getInfo(C2Param::Type index) const {
+ return mImpl->getInfo(index);
+}
+
+std::shared_ptr<C2Info> C2Buffer::removeInfo(C2Param::Type index) {
+ return mImpl->removeInfo(index);
+}
+
+// static
+std::shared_ptr<C2Buffer> C2Buffer::CreateLinearBuffer(const C2ConstLinearBlock &block) {
+ return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
+}
+
+// static
+std::shared_ptr<C2Buffer> C2Buffer::CreateGraphicBuffer(const C2ConstGraphicBlock &block) {
+ return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
+}
+
diff --git a/media/codec2/vndk/C2Config.cpp b/media/codec2/vndk/C2Config.cpp
new file mode 100644
index 0000000..da12903
--- /dev/null
+++ b/media/codec2/vndk/C2Config.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2Config"
+#include <utils/Log.h>
+
+/**
+ * Define and initialize global config field descriptors in this cpp file
+ */
+#define __C2_GENERATE_GLOBAL_VARS__
+#include <C2Config.h>
+
+DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(C2Config::profile_t, ({
+ { "unused", C2Config::PROFILE_UNUSED },
+ { "aac-lc", C2Config::PROFILE_AAC_LC },
+ { "aac-main", C2Config::PROFILE_AAC_MAIN },
+ { "aac-ssr", C2Config::PROFILE_AAC_SSR },
+ { "aac-ltp", C2Config::PROFILE_AAC_LTP },
+ { "aac-he", C2Config::PROFILE_AAC_HE },
+ { "aac-scalable", C2Config::PROFILE_AAC_SCALABLE },
+ { "aac-er-lc", C2Config::PROFILE_AAC_ER_LC },
+ { "aac-er-scalable", C2Config::PROFILE_AAC_ER_SCALABLE },
+ { "aac-ld", C2Config::PROFILE_AAC_LD },
+ { "aac-he-ps", C2Config::PROFILE_AAC_HE_PS },
+ { "aac-eld", C2Config::PROFILE_AAC_ELD },
+ { "aac-xhe", C2Config::PROFILE_AAC_XHE },
+ { "mp2v-simple", C2Config::PROFILE_MP2V_SIMPLE },
+ { "mp2v-main", C2Config::PROFILE_MP2V_MAIN },
+ { "mp2v-snr-scalable", C2Config::PROFILE_MP2V_SNR_SCALABLE },
+ { "mp2v-spatially-scalable", C2Config::PROFILE_MP2V_SPATIALLY_SCALABLE },
+ { "mp2v-high", C2Config::PROFILE_MP2V_HIGH },
+ { "mp2v-422", C2Config::PROFILE_MP2V_422 },
+ { "mp2v-multiview", C2Config::PROFILE_MP2V_MULTIVIEW },
+ { "h263-baseline", C2Config::PROFILE_H263_BASELINE },
+ { "h263-h320", C2Config::PROFILE_H263_H320 },
+ { "h263-v1bc", C2Config::PROFILE_H263_V1BC },
+ { "h263-iswv2", C2Config::PROFILE_H263_ISWV2 },
+ { "h263-iswv3", C2Config::PROFILE_H263_ISWV3 },
+ { "h263-high-compression", C2Config::PROFILE_H263_HIGH_COMPRESSION },
+ { "h263-internet", C2Config::PROFILE_H263_INTERNET },
+ { "h263-interlace", C2Config::PROFILE_H263_INTERLACE },
+ { "h263-high-latency", C2Config::PROFILE_H263_HIGH_LATENCY },
+ { "mp4v-simple", C2Config::PROFILE_MP4V_SIMPLE },
+ { "mp4v-simple-scalable", C2Config::PROFILE_MP4V_SIMPLE_SCALABLE },
+ { "mp4v-core", C2Config::PROFILE_MP4V_CORE },
+ { "mp4v-main", C2Config::PROFILE_MP4V_MAIN },
+ { "mp4v-nbit", C2Config::PROFILE_MP4V_NBIT },
+ { "mp4v-arts", C2Config::PROFILE_MP4V_ARTS },
+ { "mp4v-core-scalable", C2Config::PROFILE_MP4V_CORE_SCALABLE },
+ { "mp4v-ace", C2Config::PROFILE_MP4V_ACE },
+ { "mp4v-advanced-core", C2Config::PROFILE_MP4V_ADVANCED_CORE },
+ { "mp4v-simple-studio", C2Config::PROFILE_MP4V_SIMPLE_STUDIO },
+ { "mp4v-core-studio", C2Config::PROFILE_MP4V_CORE_STUDIO },
+ { "mp4v-advanced-simple", C2Config::PROFILE_MP4V_ADVANCED_SIMPLE },
+ { "mp4v-fgs", C2Config::PROFILE_MP4V_FGS },
+ { "avc-baseline", C2Config::PROFILE_AVC_BASELINE },
+ { "avc-constrained-baseline", C2Config::PROFILE_AVC_CONSTRAINED_BASELINE },
+ { "avc-main", C2Config::PROFILE_AVC_MAIN },
+ { "avc-extended", C2Config::PROFILE_AVC_EXTENDED },
+ { "avc-high", C2Config::PROFILE_AVC_HIGH },
+ { "avc-progressive-high", C2Config::PROFILE_AVC_PROGRESSIVE_HIGH },
+ { "avc-constrained-high", C2Config::PROFILE_AVC_CONSTRAINED_HIGH },
+ { "avc-high-10", C2Config::PROFILE_AVC_HIGH_10 },
+ { "avc-progressive-high-10", C2Config::PROFILE_AVC_PROGRESSIVE_HIGH_10 },
+ { "avc-high-422", C2Config::PROFILE_AVC_HIGH_422 },
+ { "avc-high-444-predictive", C2Config::PROFILE_AVC_HIGH_444_PREDICTIVE },
+ { "avc-high-10-intra", C2Config::PROFILE_AVC_HIGH_10_INTRA },
+ { "avc-high-422-intra", C2Config::PROFILE_AVC_HIGH_422_INTRA },
+ { "avc-high-444-intra", C2Config::PROFILE_AVC_HIGH_444_INTRA },
+ { "avc-cavlc-444-intra", C2Config::PROFILE_AVC_CAVLC_444_INTRA },
+ { "avc-scalable-baseline", C2Config::PROFILE_AVC_SCALABLE_BASELINE },
+ { "avc-scalable-constrained-baseline", C2Config::PROFILE_AVC_SCALABLE_CONSTRAINED_BASELINE },
+ { "avc-scalable-high", C2Config::PROFILE_AVC_SCALABLE_HIGH },
+ { "avc-scalable-constrained-high", C2Config::PROFILE_AVC_SCALABLE_CONSTRAINED_HIGH },
+ { "avc-scalable-high-intra", C2Config::PROFILE_AVC_SCALABLE_HIGH_INTRA },
+ { "avc-multiview-high", C2Config::PROFILE_AVC_MULTIVIEW_HIGH },
+ { "avc-stereo-high", C2Config::PROFILE_AVC_STEREO_HIGH },
+ { "avc-mfc-high", C2Config::PROFILE_AVC_MFC_HIGH },
+ { "avc-multiview-depth-high", C2Config::PROFILE_AVC_MULTIVIEW_DEPTH_HIGH },
+ { "avc-mfc-depth-high", C2Config::PROFILE_AVC_MFC_DEPTH_HIGH },
+ { "avc-enhanced-multiview-depth-high", C2Config::PROFILE_AVC_ENHANCED_MULTIVIEW_DEPTH_HIGH },
+ { "hevc-main", C2Config::PROFILE_HEVC_MAIN },
+ { "hevc-main-10", C2Config::PROFILE_HEVC_MAIN_10 },
+ { "hevc-main-still", C2Config::PROFILE_HEVC_MAIN_STILL },
+ { "hevc-mono", C2Config::PROFILE_HEVC_MONO },
+ { "hevc-mono-12", C2Config::PROFILE_HEVC_MONO_12 },
+ { "hevc-mono-16", C2Config::PROFILE_HEVC_MONO_16 },
+ { "hevc-main-12", C2Config::PROFILE_HEVC_MAIN_12 },
+ { "hevc-main-422-10", C2Config::PROFILE_HEVC_MAIN_422_10 },
+ { "hevc-main-422-12", C2Config::PROFILE_HEVC_MAIN_422_12 },
+ { "hevc-main-444", C2Config::PROFILE_HEVC_MAIN_444 },
+ { "hevc-main-444-10", C2Config::PROFILE_HEVC_MAIN_444_10 },
+ { "hevc-main-444-12", C2Config::PROFILE_HEVC_MAIN_444_12 },
+ { "hevc-main-intra", C2Config::PROFILE_HEVC_MAIN_INTRA },
+ { "hevc-main-10-intra", C2Config::PROFILE_HEVC_MAIN_10_INTRA },
+ { "hevc-main-12-intra", C2Config::PROFILE_HEVC_MAIN_12_INTRA },
+ { "hevc-main-422-10-intra", C2Config::PROFILE_HEVC_MAIN_422_10_INTRA },
+ { "hevc-main-422-12-intra", C2Config::PROFILE_HEVC_MAIN_422_12_INTRA },
+ { "hevc-main-444-intra", C2Config::PROFILE_HEVC_MAIN_444_INTRA },
+ { "hevc-main-444-10-intra", C2Config::PROFILE_HEVC_MAIN_444_10_INTRA },
+ { "hevc-main-444-12-intra", C2Config::PROFILE_HEVC_MAIN_444_12_INTRA },
+ { "hevc-main-444-16-intra", C2Config::PROFILE_HEVC_MAIN_444_16_INTRA },
+ { "hevc-main-444-still", C2Config::PROFILE_HEVC_MAIN_444_STILL },
+ { "hevc-main-444-16-still", C2Config::PROFILE_HEVC_MAIN_444_16_STILL },
+ { "hevc-high-444", C2Config::PROFILE_HEVC_HIGH_444 },
+ { "hevc-high-444-10", C2Config::PROFILE_HEVC_HIGH_444_10 },
+ { "hevc-high-444-14", C2Config::PROFILE_HEVC_HIGH_444_14 },
+ { "hevc-high-444-16-intra", C2Config::PROFILE_HEVC_HIGH_444_16_INTRA },
+ { "hevc-sx-main", C2Config::PROFILE_HEVC_SX_MAIN },
+ { "hevc-sx-main-10", C2Config::PROFILE_HEVC_SX_MAIN_10 },
+ { "hevc-sx-main-444", C2Config::PROFILE_HEVC_SX_MAIN_444 },
+ { "hevc-sx-main-444-10", C2Config::PROFILE_HEVC_SX_MAIN_444_10 },
+ { "hevc-sx-high-444", C2Config::PROFILE_HEVC_SX_HIGH_444 },
+ { "hevc-sx-high-444-10", C2Config::PROFILE_HEVC_SX_HIGH_444_10 },
+ { "hevc-sx-high-444-14", C2Config::PROFILE_HEVC_SX_HIGH_444_14 },
+ { "hevc-multiview-main", C2Config::PROFILE_HEVC_MULTIVIEW_MAIN },
+ { "hevc-scalable-main", C2Config::PROFILE_HEVC_SCALABLE_MAIN },
+ { "hevc-scalable-main-10", C2Config::PROFILE_HEVC_SCALABLE_MAIN_10 },
+ { "hevc-scalable-mono", C2Config::PROFILE_HEVC_SCALABLE_MONO },
+ { "hevc-scalable-mono-12", C2Config::PROFILE_HEVC_SCALABLE_MONO_12 },
+ { "hevc-scalable-mono-16", C2Config::PROFILE_HEVC_SCALABLE_MONO_16 },
+ { "hevc-scalable-main-444", C2Config::PROFILE_HEVC_SCALABLE_MAIN_444 },
+ { "hevc-3d-main", C2Config::PROFILE_HEVC_3D_MAIN },
+ { "vp9-0", C2Config::PROFILE_VP9_0 },
+ { "vp9-1", C2Config::PROFILE_VP9_1 },
+ { "vp9-2", C2Config::PROFILE_VP9_2 },
+ { "vp9-3", C2Config::PROFILE_VP9_3 },
+}))
+
+DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(C2Config::level_t, ({
+ { "unused", C2Config::LEVEL_UNUSED },
+ { "mp2v-low", C2Config::LEVEL_MP2V_LOW },
+ { "mp2v-main", C2Config::LEVEL_MP2V_MAIN },
+ { "mp2v-high-1440", C2Config::LEVEL_MP2V_HIGH_1440 },
+ { "mp2v-high", C2Config::LEVEL_MP2V_HIGH },
+ { "mp2v-highp", C2Config::LEVEL_MP2V_HIGHP },
+ { "h263-10", C2Config::LEVEL_H263_10 },
+ { "h263-20", C2Config::LEVEL_H263_20 },
+ { "h263-30", C2Config::LEVEL_H263_30 },
+ { "h263-40", C2Config::LEVEL_H263_40 },
+ { "h263-45", C2Config::LEVEL_H263_45 },
+ { "h263-50", C2Config::LEVEL_H263_50 },
+ { "h263-60", C2Config::LEVEL_H263_60 },
+ { "h263-70", C2Config::LEVEL_H263_70 },
+ { "mp4v-0", C2Config::LEVEL_MP4V_0 },
+ { "mp4v-0b", C2Config::LEVEL_MP4V_0B },
+ { "mp4v-1", C2Config::LEVEL_MP4V_1 },
+ { "mp4v-2", C2Config::LEVEL_MP4V_2 },
+ { "mp4v-3", C2Config::LEVEL_MP4V_3 },
+ { "mp4v-3b", C2Config::LEVEL_MP4V_3B },
+ { "mp4v-4", C2Config::LEVEL_MP4V_4 },
+ { "mp4v-4a", C2Config::LEVEL_MP4V_4A },
+ { "mp4v-5", C2Config::LEVEL_MP4V_5 },
+ { "mp4v-6", C2Config::LEVEL_MP4V_6 },
+ { "avc-1", C2Config::LEVEL_AVC_1 },
+ { "avc-1b", C2Config::LEVEL_AVC_1B },
+ { "avc-1.1", C2Config::LEVEL_AVC_1_1 },
+ { "avc-1.2", C2Config::LEVEL_AVC_1_2 },
+ { "avc-1.3", C2Config::LEVEL_AVC_1_3 },
+ { "avc-2", C2Config::LEVEL_AVC_2 },
+ { "avc-2.1", C2Config::LEVEL_AVC_2_1 },
+ { "avc-2.2", C2Config::LEVEL_AVC_2_2 },
+ { "avc-3", C2Config::LEVEL_AVC_3 },
+ { "avc-3.1", C2Config::LEVEL_AVC_3_1 },
+ { "avc-3.2", C2Config::LEVEL_AVC_3_2 },
+ { "avc-4", C2Config::LEVEL_AVC_4 },
+ { "avc-4.1", C2Config::LEVEL_AVC_4_1 },
+ { "avc-4.2", C2Config::LEVEL_AVC_4_2 },
+ { "avc-5", C2Config::LEVEL_AVC_5 },
+ { "avc-5.1", C2Config::LEVEL_AVC_5_1 },
+ { "avc-5.2", C2Config::LEVEL_AVC_5_2 },
+ { "hevc-main-1", C2Config::LEVEL_HEVC_MAIN_1 },
+ { "hevc-main-2", C2Config::LEVEL_HEVC_MAIN_2 },
+ { "hevc-main-2.1", C2Config::LEVEL_HEVC_MAIN_2_1 },
+ { "hevc-main-3", C2Config::LEVEL_HEVC_MAIN_3 },
+ { "hevc-main-3.1", C2Config::LEVEL_HEVC_MAIN_3_1 },
+ { "hevc-main-4", C2Config::LEVEL_HEVC_MAIN_4 },
+ { "hevc-main-4.1", C2Config::LEVEL_HEVC_MAIN_4_1 },
+ { "hevc-main-5", C2Config::LEVEL_HEVC_MAIN_5 },
+ { "hevc-main-5.1", C2Config::LEVEL_HEVC_MAIN_5_1 },
+ { "hevc-main-5.2", C2Config::LEVEL_HEVC_MAIN_5_2 },
+ { "hevc-main-6", C2Config::LEVEL_HEVC_MAIN_6 },
+ { "hevc-main-6.1", C2Config::LEVEL_HEVC_MAIN_6_1 },
+ { "hevc-main-6.2", C2Config::LEVEL_HEVC_MAIN_6_2 },
+ { "hevc-high-4", C2Config::LEVEL_HEVC_HIGH_4 },
+ { "hevc-high-4.1", C2Config::LEVEL_HEVC_HIGH_4_1 },
+ { "hevc-high-5", C2Config::LEVEL_HEVC_HIGH_5 },
+ { "hevc-high-5.1", C2Config::LEVEL_HEVC_HIGH_5_1 },
+ { "hevc-high-5.2", C2Config::LEVEL_HEVC_HIGH_5_2 },
+ { "hevc-high-6", C2Config::LEVEL_HEVC_HIGH_6 },
+ { "hevc-high-6.1", C2Config::LEVEL_HEVC_HIGH_6_1 },
+ { "hevc-high-6.2", C2Config::LEVEL_HEVC_HIGH_6_2 },
+ { "vp9-1", C2Config::LEVEL_VP9_1 },
+ { "vp9-1.1", C2Config::LEVEL_VP9_1_1 },
+ { "vp9-2", C2Config::LEVEL_VP9_2 },
+ { "vp9-2.1", C2Config::LEVEL_VP9_2_1 },
+ { "vp9-3", C2Config::LEVEL_VP9_3 },
+ { "vp9-3.1", C2Config::LEVEL_VP9_3_1 },
+ { "vp9-4", C2Config::LEVEL_VP9_4 },
+ { "vp9-4.1", C2Config::LEVEL_VP9_4_1 },
+ { "vp9-5", C2Config::LEVEL_VP9_5 },
+ { "vp9-5.1", C2Config::LEVEL_VP9_5_1 },
+ { "vp9-5.2", C2Config::LEVEL_VP9_5_2 },
+ { "vp9-6", C2Config::LEVEL_VP9_6 },
+ { "vp9-6.1", C2Config::LEVEL_VP9_6_1 },
+ { "vp9-6.2", C2Config::LEVEL_VP9_6_2 },
+}))
+
+DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(C2BufferData::type_t, ({
+ { "invalid", C2BufferData::INVALID },
+ { "linear", C2BufferData::LINEAR },
+ { "linear-chunks", C2BufferData::LINEAR_CHUNKS },
+ { "graphic", C2BufferData::GRAPHIC },
+ { "graphic-chunks", C2BufferData::GRAPHIC_CHUNKS },
+}))
+
+
diff --git a/media/codec2/vndk/C2PlatformStorePluginLoader.cpp b/media/codec2/vndk/C2PlatformStorePluginLoader.cpp
new file mode 100644
index 0000000..7a460f4
--- /dev/null
+++ b/media/codec2/vndk/C2PlatformStorePluginLoader.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2PlatformStorePluginLoader"
+
+#include <dlfcn.h>
+
+#include <utils/Log.h>
+
+#include "C2PlatformStorePluginLoader.h"
+
+/* static */ android::Mutex C2PlatformStorePluginLoader::sMutex;
+/* static */ std::unique_ptr<C2PlatformStorePluginLoader> C2PlatformStorePluginLoader::sInstance;
+
+C2PlatformStorePluginLoader::C2PlatformStorePluginLoader(const char *libPath)
+ : mCreateBlockPool(nullptr) {
+ mLibHandle = dlopen(libPath, RTLD_NOW | RTLD_NODELETE);
+ if (mLibHandle == nullptr) {
+ ALOGD("Failed to load library: %s (%s)", libPath, dlerror());
+ return;
+ }
+ mCreateBlockPool = (CreateBlockPoolFunc)dlsym(mLibHandle, "CreateBlockPool");
+ if (mCreateBlockPool == nullptr) {
+ ALOGD("Failed to find symbol: CreateBlockPool (%s)", dlerror());
+ }
+ mCreateAllocator = (CreateAllocatorFunc)dlsym(mLibHandle, "CreateAllocator");
+ if (mCreateAllocator == nullptr) {
+ ALOGD("Failed to find symbol: CreateAllocator (%s)", dlerror());
+ }
+}
+
+C2PlatformStorePluginLoader::~C2PlatformStorePluginLoader() {
+ if (mLibHandle != nullptr) {
+ ALOGV("Closing handle");
+ dlclose(mLibHandle);
+ }
+}
+
+c2_status_t C2PlatformStorePluginLoader::createBlockPool(
+ ::C2Allocator::id_t allocatorId, ::C2BlockPool::local_id_t blockPoolId,
+ std::shared_ptr<C2BlockPool>* pool) {
+ if (mCreateBlockPool == nullptr) {
+ ALOGD("Handle or CreateBlockPool symbol is null");
+ return C2_NOT_FOUND;
+ }
+
+ std::shared_ptr<::C2BlockPool> ptr(mCreateBlockPool(allocatorId, blockPoolId));
+ if (ptr) {
+ *pool = ptr;
+ return C2_OK;
+ }
+ ALOGD("Failed to CreateBlockPool by allocator id: %u", allocatorId);
+ return C2_BAD_INDEX;
+}
+
+c2_status_t C2PlatformStorePluginLoader::createAllocator(
+ ::C2Allocator::id_t allocatorId, std::shared_ptr<C2Allocator>* const allocator) {
+ if (mCreateAllocator == nullptr) {
+ ALOGD("Handle or CreateAllocator symbol is null");
+ return C2_NOT_FOUND;
+ }
+
+ c2_status_t res = C2_CORRUPTED;
+ allocator->reset(mCreateAllocator(allocatorId, &res));
+ if (res != C2_OK) {
+ ALOGD("Failed to CreateAllocator by id: %u, res: %d", allocatorId, res);
+ allocator->reset();
+ return res;
+ }
+ return C2_OK;
+}
+
+// static
+const std::unique_ptr<C2PlatformStorePluginLoader>& C2PlatformStorePluginLoader::GetInstance() {
+ android::Mutex::Autolock _l(sMutex);
+ if (!sInstance) {
+ ALOGV("Loading library");
+ sInstance.reset(new C2PlatformStorePluginLoader("libstagefright_ccodec_ext.so"));
+ }
+ return sInstance;
+}
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
new file mode 100644
index 0000000..33019ed
--- /dev/null
+++ b/media/codec2/vndk/C2Store.cpp
@@ -0,0 +1,974 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "C2Store"
+#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2AllocatorIon.h>
+#include <C2BufferPriv.h>
+#include <C2BqBufferPriv.h>
+#include <C2Component.h>
+#include <C2Config.h>
+#include <C2PlatformStorePluginLoader.h>
+#include <C2PlatformSupport.h>
+#include <util/C2InterfaceHelper.h>
+
+#include <dlfcn.h>
+#include <unistd.h> // getpagesize
+
+#include <map>
+#include <memory>
+#include <mutex>
+
+namespace android {
+
+/**
+ * Returns the preferred component store in this process to access its interface.
+ */
+std::shared_ptr<C2ComponentStore> GetPreferredCodec2ComponentStore();
+
+/**
+ * The platform allocator store provides basic allocator-types for the framework based on ion and
+ * gralloc. Allocators are not meant to be updatable.
+ *
+ * \todo Provide allocator based on ashmem
+ * \todo Move ion allocation into its HIDL or provide some mapping from memory usage to ion flags
+ * \todo Make this allocator store extendable
+ */
+class C2PlatformAllocatorStoreImpl : public C2PlatformAllocatorStore {
+public:
+ C2PlatformAllocatorStoreImpl();
+
+ virtual c2_status_t fetchAllocator(
+ id_t id, std::shared_ptr<C2Allocator> *const allocator) override;
+
+ virtual std::vector<std::shared_ptr<const C2Allocator::Traits>> listAllocators_nb()
+ const override {
+ return std::vector<std::shared_ptr<const C2Allocator::Traits>>(); /// \todo
+ }
+
+ virtual C2String getName() const override {
+ return "android.allocator-store";
+ }
+
+ void setComponentStore(std::shared_ptr<C2ComponentStore> store);
+
+ ~C2PlatformAllocatorStoreImpl() override = default;
+
+private:
+ /// returns a shared-singleton ion allocator
+ std::shared_ptr<C2Allocator> fetchIonAllocator();
+
+ /// returns a shared-singleton gralloc allocator
+ std::shared_ptr<C2Allocator> fetchGrallocAllocator();
+
+ /// returns a shared-singleton bufferqueue supporting gralloc allocator
+ std::shared_ptr<C2Allocator> fetchBufferQueueAllocator();
+
+ /// component store to use
+ std::mutex _mComponentStoreSetLock; // protects the entire updating _mComponentStore and its
+ // dependencies
+ std::mutex _mComponentStoreReadLock; // must protect only read/write of _mComponentStore
+ std::shared_ptr<C2ComponentStore> _mComponentStore;
+};
+
+C2PlatformAllocatorStoreImpl::C2PlatformAllocatorStoreImpl() {
+}
+
+c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator(
+ id_t id, std::shared_ptr<C2Allocator> *const allocator) {
+ allocator->reset();
+ switch (id) {
+ // TODO: should we implement a generic registry for all, and use that?
+ case C2PlatformAllocatorStore::ION:
+ case C2AllocatorStore::DEFAULT_LINEAR:
+ *allocator = fetchIonAllocator();
+ break;
+
+ case C2PlatformAllocatorStore::GRALLOC:
+ case C2AllocatorStore::DEFAULT_GRAPHIC:
+ *allocator = fetchGrallocAllocator();
+ break;
+
+ case C2PlatformAllocatorStore::BUFFERQUEUE:
+ *allocator = fetchBufferQueueAllocator();
+ break;
+
+ default:
+ // Try to create allocator from platform store plugins.
+ c2_status_t res =
+ C2PlatformStorePluginLoader::GetInstance()->createAllocator(id, allocator);
+ if (res != C2_OK) {
+ return res;
+ }
+ break;
+ }
+ if (*allocator == nullptr) {
+ return C2_NO_MEMORY;
+ }
+ return C2_OK;
+}
+
+namespace {
+
+std::mutex gIonAllocatorMutex;
+std::weak_ptr<C2AllocatorIon> gIonAllocator;
+
+void UseComponentStoreForIonAllocator(
+ const std::shared_ptr<C2AllocatorIon> allocator,
+ std::shared_ptr<C2ComponentStore> store) {
+ C2AllocatorIon::UsageMapperFn mapper;
+ uint64_t minUsage = 0;
+ uint64_t maxUsage = C2MemoryUsage(C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE).expected;
+ size_t blockSize = getpagesize();
+
+ // query min and max usage as well as block size via supported values
+ C2StoreIonUsageInfo usageInfo;
+ std::vector<C2FieldSupportedValuesQuery> query = {
+ C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.usage)),
+ C2FieldSupportedValuesQuery::Possible(C2ParamField::Make(usageInfo, usageInfo.capacity)),
+ };
+ c2_status_t res = store->querySupportedValues_sm(query);
+ if (res == C2_OK) {
+ if (query[0].status == C2_OK) {
+ const C2FieldSupportedValues &fsv = query[0].values;
+ if (fsv.type == C2FieldSupportedValues::FLAGS && !fsv.values.empty()) {
+ minUsage = fsv.values[0].u64;
+ maxUsage = 0;
+ for (C2Value::Primitive v : fsv.values) {
+ maxUsage |= v.u64;
+ }
+ }
+ }
+ if (query[1].status == C2_OK) {
+ const C2FieldSupportedValues &fsv = query[1].values;
+ if (fsv.type == C2FieldSupportedValues::RANGE && fsv.range.step.u32 > 0) {
+ blockSize = fsv.range.step.u32;
+ }
+ }
+
+ mapper = [store](C2MemoryUsage usage, size_t capacity,
+ size_t *align, unsigned *heapMask, unsigned *flags) -> c2_status_t {
+ if (capacity > UINT32_MAX) {
+ return C2_BAD_VALUE;
+ }
+ C2StoreIonUsageInfo usageInfo = { usage.expected, capacity };
+ std::vector<std::unique_ptr<C2SettingResult>> failures; // TODO: remove
+ c2_status_t res = store->config_sm({&usageInfo}, &failures);
+ if (res == C2_OK) {
+ *align = usageInfo.minAlignment;
+ *heapMask = usageInfo.heapMask;
+ *flags = usageInfo.allocFlags;
+ }
+ return res;
+ };
+ }
+
+ allocator->setUsageMapper(mapper, minUsage, maxUsage, blockSize);
+}
+
+}
+
+void C2PlatformAllocatorStoreImpl::setComponentStore(std::shared_ptr<C2ComponentStore> store) {
+ // technically this set lock is not needed, but is here for safety in case we add more
+ // getter orders
+ std::lock_guard<std::mutex> lock(_mComponentStoreSetLock);
+ {
+ std::lock_guard<std::mutex> lock(_mComponentStoreReadLock);
+ _mComponentStore = store;
+ }
+ std::shared_ptr<C2AllocatorIon> allocator;
+ {
+ std::lock_guard<std::mutex> lock(gIonAllocatorMutex);
+ allocator = gIonAllocator.lock();
+ }
+ if (allocator) {
+ UseComponentStoreForIonAllocator(allocator, store);
+ }
+}
+
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchIonAllocator() {
+ std::lock_guard<std::mutex> lock(gIonAllocatorMutex);
+ std::shared_ptr<C2AllocatorIon> allocator = gIonAllocator.lock();
+ if (allocator == nullptr) {
+ std::shared_ptr<C2ComponentStore> componentStore;
+ {
+ std::lock_guard<std::mutex> lock(_mComponentStoreReadLock);
+ componentStore = _mComponentStore;
+ }
+ allocator = std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
+ UseComponentStoreForIonAllocator(allocator, componentStore);
+ gIonAllocator = allocator;
+ }
+ return allocator;
+}
+
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() {
+ static std::mutex mutex;
+ static std::weak_ptr<C2Allocator> grallocAllocator;
+ std::lock_guard<std::mutex> lock(mutex);
+ std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
+ if (allocator == nullptr) {
+ allocator = std::make_shared<C2AllocatorGralloc>(C2PlatformAllocatorStore::GRALLOC);
+ grallocAllocator = allocator;
+ }
+ return allocator;
+}
+
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchBufferQueueAllocator() {
+ static std::mutex mutex;
+ static std::weak_ptr<C2Allocator> grallocAllocator;
+ std::lock_guard<std::mutex> lock(mutex);
+ std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
+ if (allocator == nullptr) {
+ allocator = std::make_shared<C2AllocatorGralloc>(
+ C2PlatformAllocatorStore::BUFFERQUEUE, true);
+ grallocAllocator = allocator;
+ }
+ return allocator;
+}
+
+namespace {
+ std::mutex gPreferredComponentStoreMutex;
+ std::shared_ptr<C2ComponentStore> gPreferredComponentStore;
+
+ std::mutex gPlatformAllocatorStoreMutex;
+ std::weak_ptr<C2PlatformAllocatorStoreImpl> gPlatformAllocatorStore;
+}
+
+std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
+ std::lock_guard<std::mutex> lock(gPlatformAllocatorStoreMutex);
+ std::shared_ptr<C2PlatformAllocatorStoreImpl> store = gPlatformAllocatorStore.lock();
+ if (store == nullptr) {
+ store = std::make_shared<C2PlatformAllocatorStoreImpl>();
+ store->setComponentStore(GetPreferredCodec2ComponentStore());
+ gPlatformAllocatorStore = store;
+ }
+ return store;
+}
+
+void SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> componentStore) {
+ static std::mutex mutex;
+ std::lock_guard<std::mutex> lock(mutex); // don't interleve set-s
+
+ // update preferred store
+ {
+ std::lock_guard<std::mutex> lock(gPreferredComponentStoreMutex);
+ gPreferredComponentStore = componentStore;
+ }
+
+ // update platform allocator's store as well if it is alive
+ std::shared_ptr<C2PlatformAllocatorStoreImpl> allocatorStore;
+ {
+ std::lock_guard<std::mutex> lock(gPlatformAllocatorStoreMutex);
+ allocatorStore = gPlatformAllocatorStore.lock();
+ }
+ if (allocatorStore) {
+ allocatorStore->setComponentStore(componentStore);
+ }
+}
+
+std::shared_ptr<C2ComponentStore> GetPreferredCodec2ComponentStore() {
+ std::lock_guard<std::mutex> lock(gPreferredComponentStoreMutex);
+ return gPreferredComponentStore ? gPreferredComponentStore : GetCodec2PlatformComponentStore();
+}
+
+namespace {
+
+class _C2BlockPoolCache {
+public:
+ _C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {}
+
+ c2_status_t _createBlockPool(
+ C2PlatformAllocatorStore::id_t allocatorId,
+ std::shared_ptr<const C2Component> component,
+ C2BlockPool::local_id_t poolId,
+ std::shared_ptr<C2BlockPool> *pool) {
+ std::shared_ptr<C2AllocatorStore> allocatorStore =
+ GetCodec2PlatformAllocatorStore();
+ std::shared_ptr<C2Allocator> allocator;
+ c2_status_t res = C2_NOT_FOUND;
+
+ switch(allocatorId) {
+ case C2PlatformAllocatorStore::ION:
+ case C2AllocatorStore::DEFAULT_LINEAR:
+ res = allocatorStore->fetchAllocator(
+ C2AllocatorStore::DEFAULT_LINEAR, &allocator);
+ if (res == C2_OK) {
+ std::shared_ptr<C2BlockPool> ptr =
+ std::make_shared<C2PooledBlockPool>(
+ allocator, poolId);
+ *pool = ptr;
+ mBlockPools[poolId] = ptr;
+ mComponents[poolId] = component;
+ }
+ break;
+ case C2PlatformAllocatorStore::GRALLOC:
+ case C2AllocatorStore::DEFAULT_GRAPHIC:
+ res = allocatorStore->fetchAllocator(
+ C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
+ if (res == C2_OK) {
+ std::shared_ptr<C2BlockPool> ptr =
+ std::make_shared<C2PooledBlockPool>(allocator, poolId);
+ *pool = ptr;
+ mBlockPools[poolId] = ptr;
+ mComponents[poolId] = component;
+ }
+ break;
+ case C2PlatformAllocatorStore::BUFFERQUEUE:
+ res = allocatorStore->fetchAllocator(
+ C2PlatformAllocatorStore::BUFFERQUEUE, &allocator);
+ if (res == C2_OK) {
+ std::shared_ptr<C2BlockPool> ptr =
+ std::make_shared<C2BufferQueueBlockPool>(
+ allocator, poolId);
+ *pool = ptr;
+ mBlockPools[poolId] = ptr;
+ mComponents[poolId] = component;
+ }
+ break;
+ default:
+ // Try to create block pool from platform store plugins.
+ std::shared_ptr<C2BlockPool> ptr;
+ res = C2PlatformStorePluginLoader::GetInstance()->createBlockPool(
+ allocatorId, poolId, &ptr);
+ if (res == C2_OK) {
+ *pool = ptr;
+ mBlockPools[poolId] = ptr;
+ mComponents[poolId] = component;
+ }
+ break;
+ }
+ return res;
+ }
+
+ c2_status_t createBlockPool(
+ C2PlatformAllocatorStore::id_t allocatorId,
+ std::shared_ptr<const C2Component> component,
+ std::shared_ptr<C2BlockPool> *pool) {
+ return _createBlockPool(allocatorId, component, mBlockPoolSeqId++, pool);
+ }
+
+ bool getBlockPool(
+ C2BlockPool::local_id_t blockPoolId,
+ std::shared_ptr<const C2Component> component,
+ std::shared_ptr<C2BlockPool> *pool) {
+ // TODO: use one iterator for multiple blockpool type scalability.
+ std::shared_ptr<C2BlockPool> ptr;
+ auto it = mBlockPools.find(blockPoolId);
+ if (it != mBlockPools.end()) {
+ ptr = it->second.lock();
+ if (!ptr) {
+ mBlockPools.erase(it);
+ mComponents.erase(blockPoolId);
+ } else {
+ auto found = mComponents.find(blockPoolId);
+ if (component == found->second.lock()) {
+ *pool = ptr;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+private:
+ C2BlockPool::local_id_t mBlockPoolSeqId;
+
+ std::map<C2BlockPool::local_id_t, std::weak_ptr<C2BlockPool>> mBlockPools;
+ std::map<C2BlockPool::local_id_t, std::weak_ptr<const C2Component>> mComponents;
+};
+
+static std::unique_ptr<_C2BlockPoolCache> sBlockPoolCache =
+ std::make_unique<_C2BlockPoolCache>();
+static std::mutex sBlockPoolCacheMutex;
+
+} // anynymous namespace
+
+c2_status_t GetCodec2BlockPool(
+ C2BlockPool::local_id_t id, std::shared_ptr<const C2Component> component,
+ std::shared_ptr<C2BlockPool> *pool) {
+ pool->reset();
+ std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
+ std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
+ std::shared_ptr<C2Allocator> allocator;
+ c2_status_t res = C2_NOT_FOUND;
+
+ if (id >= C2BlockPool::PLATFORM_START) {
+ if (sBlockPoolCache->getBlockPool(id, component, pool)) {
+ return C2_OK;
+ }
+ }
+
+ switch (id) {
+ case C2BlockPool::BASIC_LINEAR:
+ res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
+ if (res == C2_OK) {
+ *pool = std::make_shared<C2BasicLinearBlockPool>(allocator);
+ }
+ break;
+ case C2BlockPool::BASIC_GRAPHIC:
+ res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
+ if (res == C2_OK) {
+ *pool = std::make_shared<C2BasicGraphicBlockPool>(allocator);
+ }
+ break;
+ // TODO: remove this. this is temporary
+ case C2BlockPool::PLATFORM_START:
+ res = sBlockPoolCache->_createBlockPool(
+ C2PlatformAllocatorStore::BUFFERQUEUE, component, id, pool);
+ break;
+ default:
+ break;
+ }
+ return res;
+}
+
+c2_status_t CreateCodec2BlockPool(
+ C2PlatformAllocatorStore::id_t allocatorId,
+ std::shared_ptr<const C2Component> component,
+ std::shared_ptr<C2BlockPool> *pool) {
+ pool->reset();
+
+ std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
+ return sBlockPoolCache->createBlockPool(allocatorId, component, pool);
+}
+
+class C2PlatformComponentStore : public C2ComponentStore {
+public:
+ virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override;
+ virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override;
+ virtual C2String getName() const override;
+ virtual c2_status_t querySupportedValues_sm(
+ std::vector<C2FieldSupportedValuesQuery> &fields) const override;
+ virtual c2_status_t querySupportedParams_nb(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const override;
+ virtual c2_status_t query_sm(
+ const std::vector<C2Param*> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ std::vector<std::unique_ptr<C2Param>> *const heapParams) const override;
+ virtual c2_status_t createInterface(
+ C2String name, std::shared_ptr<C2ComponentInterface> *const interface) override;
+ virtual c2_status_t createComponent(
+ C2String name, std::shared_ptr<C2Component> *const component) override;
+ virtual c2_status_t copyBuffer(
+ std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) override;
+ virtual c2_status_t config_sm(
+ const std::vector<C2Param*> ¶ms,
+ std::vector<std::unique_ptr<C2SettingResult>> *const failures) override;
+ C2PlatformComponentStore();
+
+ virtual ~C2PlatformComponentStore() override = default;
+
+private:
+
+ /**
+ * An object encapsulating a loaded component module.
+ *
+ * \todo provide a way to add traits to known components here to avoid loading the .so-s
+ * for listComponents
+ */
+ struct ComponentModule : public C2ComponentFactory,
+ public std::enable_shared_from_this<ComponentModule> {
+ virtual c2_status_t createComponent(
+ c2_node_id_t id, std::shared_ptr<C2Component> *component,
+ ComponentDeleter deleter = std::default_delete<C2Component>()) override;
+ virtual c2_status_t createInterface(
+ c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
+ InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) override;
+
+ /**
+ * \returns the traits of the component in this module.
+ */
+ std::shared_ptr<const C2Component::Traits> getTraits();
+
+ /**
+ * Creates an uninitialized component module.
+ *
+ * \param name[in] component name.
+ *
+ * \note Only used by ComponentLoader.
+ */
+ ComponentModule()
+ : mInit(C2_NO_INIT),
+ mLibHandle(nullptr),
+ createFactory(nullptr),
+ destroyFactory(nullptr),
+ mComponentFactory(nullptr) {
+ }
+
+ /**
+ * Initializes a component module with a given library path. Must be called exactly once.
+ *
+ * \note Only used by ComponentLoader.
+ *
+ * \param alias[in] module alias
+ * \param libPath[in] library path
+ *
+ * \retval C2_OK the component module has been successfully loaded
+ * \retval C2_NO_MEMORY not enough memory to loading the component module
+ * \retval C2_NOT_FOUND could not locate the component module
+ * \retval C2_CORRUPTED the component module could not be loaded (unexpected)
+ * \retval C2_REFUSED permission denied to load the component module (unexpected)
+ * \retval C2_TIMED_OUT could not load the module within the time limit (unexpected)
+ */
+ c2_status_t init(std::string alias, std::string libPath);
+
+ virtual ~ComponentModule() override;
+
+ protected:
+ std::recursive_mutex mLock; ///< lock protecting mTraits
+ std::shared_ptr<C2Component::Traits> mTraits; ///< cached component traits
+
+ c2_status_t mInit; ///< initialization result
+
+ void *mLibHandle; ///< loaded library handle
+ C2ComponentFactory::CreateCodec2FactoryFunc createFactory; ///< loaded create function
+ C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory; ///< loaded destroy function
+ C2ComponentFactory *mComponentFactory; ///< loaded/created component factory
+ };
+
+ /**
+ * An object encapsulating a loadable component module.
+ *
+ * \todo make this also work for enumerations
+ */
+ struct ComponentLoader {
+ /**
+ * Load the component module.
+ *
+ * This method simply returns the component module if it is already currently loaded, or
+ * attempts to load it if it is not.
+ *
+ * \param module[out] pointer to the shared pointer where the loaded module shall be stored.
+ * This will be nullptr on error.
+ *
+ * \retval C2_OK the component module has been successfully loaded
+ * \retval C2_NO_MEMORY not enough memory to loading the component module
+ * \retval C2_NOT_FOUND could not locate the component module
+ * \retval C2_CORRUPTED the component module could not be loaded
+ * \retval C2_REFUSED permission denied to load the component module
+ */
+ c2_status_t fetchModule(std::shared_ptr<ComponentModule> *module) {
+ c2_status_t res = C2_OK;
+ std::lock_guard<std::mutex> lock(mMutex);
+ std::shared_ptr<ComponentModule> localModule = mModule.lock();
+ if (localModule == nullptr) {
+ localModule = std::make_shared<ComponentModule>();
+ res = localModule->init(mAlias, mLibPath);
+ if (res == C2_OK) {
+ mModule = localModule;
+ }
+ }
+ *module = localModule;
+ return res;
+ }
+
+ /**
+ * Creates a component loader for a specific library path (or name).
+ */
+ ComponentLoader(std::string alias, std::string libPath)
+ : mAlias(alias), mLibPath(libPath) {}
+
+ private:
+ std::mutex mMutex; ///< mutex guarding the module
+ std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
+ std::string mAlias; ///< component alias
+ std::string mLibPath; ///< library path
+ };
+
+ struct Interface : public C2InterfaceHelper {
+ std::shared_ptr<C2StoreIonUsageInfo> mIonUsageInfo;
+
+ Interface(std::shared_ptr<C2ReflectorHelper> reflector)
+ : C2InterfaceHelper(reflector) {
+ setDerivedInstance(this);
+
+ struct Setter {
+ static C2R setIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
+ me.set().heapMask = ~0;
+ me.set().allocFlags = 0;
+ me.set().minAlignment = 0;
+ return C2R::Ok();
+ }
+ };
+
+ addParameter(
+ DefineParam(mIonUsageInfo, "ion-usage")
+ .withDefault(new C2StoreIonUsageInfo())
+ .withFields({
+ C2F(mIonUsageInfo, usage).flags({C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}),
+ C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024),
+ C2F(mIonUsageInfo, heapMask).any(),
+ C2F(mIonUsageInfo, allocFlags).flags({}),
+ C2F(mIonUsageInfo, minAlignment).equalTo(0)
+ })
+ .withSetter(Setter::setIonUsage)
+ .build());
+ }
+ };
+
+ /**
+ * Retrieves the component loader for a component.
+ *
+ * \return a non-ref-holding pointer to the component loader.
+ *
+ * \retval C2_OK the component loader has been successfully retrieved
+ * \retval C2_NO_MEMORY not enough memory to locate the component loader
+ * \retval C2_NOT_FOUND could not locate the component to be loaded
+ * \retval C2_CORRUPTED the component loader could not be identified due to some modules being
+ * corrupted (this can happen if the name does not refer to an already
+ * identified component but some components could not be loaded due to
+ * bad library)
+ * \retval C2_REFUSED permission denied to find the component loader for the named component
+ * (this can happen if the name does not refer to an already identified
+ * component but some components could not be loaded due to lack of
+ * permissions)
+ */
+ c2_status_t findComponent(C2String name, ComponentLoader **loader);
+
+ std::map<C2String, ComponentLoader> mComponents; ///< map of name -> components
+ std::vector<C2String> mComponentsList; ///< list of components
+ std::shared_ptr<C2ReflectorHelper> mReflector;
+ Interface mInterface;
+};
+
+c2_status_t C2PlatformComponentStore::ComponentModule::init(
+ std::string alias, std::string libPath) {
+ ALOGV("in %s", __func__);
+ ALOGV("loading dll");
+ mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
+ if (mLibHandle == nullptr) {
+ // could be access/symbol or simply not being there
+ ALOGD("could not dlopen %s: %s", libPath.c_str(), dlerror());
+ mInit = C2_CORRUPTED;
+ } else {
+ createFactory =
+ (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
+ destroyFactory =
+ (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");
+
+ mComponentFactory = createFactory();
+ if (mComponentFactory == nullptr) {
+ ALOGD("could not create factory in %s", libPath.c_str());
+ mInit = C2_NO_MEMORY;
+ } else {
+ mInit = C2_OK;
+ }
+ }
+ if (mInit != C2_OK) {
+ return mInit;
+ }
+
+ std::shared_ptr<C2ComponentInterface> intf;
+ c2_status_t res = createInterface(0, &intf);
+ if (res != C2_OK) {
+ ALOGD("failed to create interface: %d", res);
+ return mInit;
+ }
+
+ std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
+ if (traits) {
+ if (alias != intf->getName()) {
+ ALOGV("%s is alias to %s", alias.c_str(), intf->getName().c_str());
+ }
+ traits->name = alias;
+ // TODO: get this from interface properly.
+ bool encoder = (traits->name.find("encoder") != std::string::npos);
+ uint32_t mediaTypeIndex = encoder ? C2PortMimeConfig::output::PARAM_TYPE
+ : C2PortMimeConfig::input::PARAM_TYPE;
+ std::vector<std::unique_ptr<C2Param>> params;
+ res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, ¶ms);
+ if (res != C2_OK) {
+ ALOGD("failed to query interface: %d", res);
+ return mInit;
+ }
+ if (params.size() != 1u) {
+ ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
+ return mInit;
+ }
+ C2PortMimeConfig *mediaTypeConfig = (C2PortMimeConfig *)(params[0].get());
+ if (mediaTypeConfig == nullptr) {
+ ALOGD("failed to query media type");
+ return mInit;
+ }
+ traits->mediaType = mediaTypeConfig->m.value;
+ // TODO: get this properly.
+ traits->rank = 0x200;
+
+ // TODO: define these values properly
+ bool decoder = (traits->name.find("decoder") != std::string::npos);
+ traits->kind =
+ decoder ? C2Component::KIND_DECODER :
+ encoder ? C2Component::KIND_ENCODER :
+ C2Component::KIND_OTHER;
+ if (strncmp(traits->mediaType.c_str(), "audio/", 6) == 0) {
+ traits->domain = C2Component::DOMAIN_AUDIO;
+ } else if (strncmp(traits->mediaType.c_str(), "video/", 6) == 0) {
+ traits->domain = C2Component::DOMAIN_VIDEO;
+ } else if (strncmp(traits->mediaType.c_str(), "image/", 6) == 0) {
+ traits->domain = C2Component::DOMAIN_IMAGE;
+ } else {
+ traits->domain = C2Component::DOMAIN_OTHER;
+ }
+ }
+ mTraits = traits;
+
+ return mInit;
+}
+
+C2PlatformComponentStore::ComponentModule::~ComponentModule() {
+ ALOGV("in %s", __func__);
+ if (destroyFactory && mComponentFactory) {
+ destroyFactory(mComponentFactory);
+ }
+ if (mLibHandle) {
+ ALOGV("unloading dll");
+ dlclose(mLibHandle);
+ }
+}
+
+c2_status_t C2PlatformComponentStore::ComponentModule::createInterface(
+ c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
+ std::function<void(::C2ComponentInterface*)> deleter) {
+ interface->reset();
+ if (mInit != C2_OK) {
+ return mInit;
+ }
+ std::shared_ptr<ComponentModule> module = shared_from_this();
+ c2_status_t res = mComponentFactory->createInterface(
+ id, interface, [module, deleter](C2ComponentInterface *p) mutable {
+ // capture module so that we ensure we still have it while deleting interface
+ deleter(p); // delete interface first
+ module.reset(); // remove module ref (not technically needed)
+ });
+ return res;
+}
+
+c2_status_t C2PlatformComponentStore::ComponentModule::createComponent(
+ c2_node_id_t id, std::shared_ptr<C2Component> *component,
+ std::function<void(::C2Component*)> deleter) {
+ component->reset();
+ if (mInit != C2_OK) {
+ return mInit;
+ }
+ std::shared_ptr<ComponentModule> module = shared_from_this();
+ c2_status_t res = mComponentFactory->createComponent(
+ id, component, [module, deleter](C2Component *p) mutable {
+ // capture module so that we ensure we still have it while deleting component
+ deleter(p); // delete component first
+ module.reset(); // remove module ref (not technically needed)
+ });
+ return res;
+}
+
+std::shared_ptr<const C2Component::Traits> C2PlatformComponentStore::ComponentModule::getTraits() {
+ std::unique_lock<std::recursive_mutex> lock(mLock);
+ return mTraits;
+}
+
+C2PlatformComponentStore::C2PlatformComponentStore()
+ : mReflector(std::make_shared<C2ReflectorHelper>()),
+ mInterface(mReflector) {
+
+ auto emplace = [this](const char *alias, const char *libPath) {
+ // ComponentLoader is neither copiable nor movable, so it must be
+ // constructed in-place. Now ComponentLoader takes two arguments in
+ // constructor, so we need to use piecewise_construct to achieve this
+ // behavior.
+ mComponents.emplace(
+ std::piecewise_construct,
+ std::forward_as_tuple(alias),
+ std::forward_as_tuple(alias, libPath));
+ mComponentsList.emplace_back(alias);
+ };
+ // TODO: move this also into a .so so it can be updated
+ emplace("c2.android.avc.decoder", "libstagefright_soft_c2avcdec.so");
+ emplace("c2.android.avc.encoder", "libstagefright_soft_c2avcenc.so");
+ emplace("c2.android.aac.decoder", "libstagefright_soft_c2aacdec.so");
+ emplace("c2.android.aac.encoder", "libstagefright_soft_c2aacenc.so");
+ emplace("c2.android.amrnb.decoder", "libstagefright_soft_c2amrnbdec.so");
+ emplace("c2.android.amrnb.encoder", "libstagefright_soft_c2amrnbenc.so");
+ emplace("c2.android.amrwb.decoder", "libstagefright_soft_c2amrwbdec.so");
+ emplace("c2.android.amrwb.encoder", "libstagefright_soft_c2amrwbenc.so");
+ emplace("c2.android.hevc.decoder", "libstagefright_soft_c2hevcdec.so");
+ emplace("c2.android.g711.alaw.decoder", "libstagefright_soft_c2g711alawdec.so");
+ emplace("c2.android.g711.mlaw.decoder", "libstagefright_soft_c2g711mlawdec.so");
+ emplace("c2.android.mpeg2.decoder", "libstagefright_soft_c2mpeg2dec.so");
+ emplace("c2.android.h263.decoder", "libstagefright_soft_c2h263dec.so");
+ emplace("c2.android.h263.encoder", "libstagefright_soft_c2h263enc.so");
+ emplace("c2.android.mpeg4.decoder", "libstagefright_soft_c2mpeg4dec.so");
+ emplace("c2.android.mpeg4.encoder", "libstagefright_soft_c2mpeg4enc.so");
+ emplace("c2.android.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
+ emplace("c2.android.vorbis.decoder", "libstagefright_soft_c2vorbisdec.so");
+ emplace("c2.android.opus.decoder", "libstagefright_soft_c2opusdec.so");
+ emplace("c2.android.vp8.decoder", "libstagefright_soft_c2vp8dec.so");
+ emplace("c2.android.vp9.decoder", "libstagefright_soft_c2vp9dec.so");
+ emplace("c2.android.vp8.encoder", "libstagefright_soft_c2vp8enc.so");
+ emplace("c2.android.vp9.encoder", "libstagefright_soft_c2vp9enc.so");
+ emplace("c2.android.raw.decoder", "libstagefright_soft_c2rawdec.so");
+ emplace("c2.android.flac.decoder", "libstagefright_soft_c2flacdec.so");
+ emplace("c2.android.flac.encoder", "libstagefright_soft_c2flacenc.so");
+ emplace("c2.android.gsm.decoder", "libstagefright_soft_c2gsmdec.so");
+ emplace("c2.android.xaac.decoder", "libstagefright_soft_c2xaacdec.so");
+
+ // "Aliases"
+ // TODO: use aliases proper from C2Component::Traits
+ emplace("OMX.google.h264.decoder", "libstagefright_soft_c2avcdec.so");
+ emplace("OMX.google.h264.encoder", "libstagefright_soft_c2avcenc.so");
+ emplace("OMX.google.aac.decoder", "libstagefright_soft_c2aacdec.so");
+ emplace("OMX.google.aac.encoder", "libstagefright_soft_c2aacenc.so");
+ emplace("OMX.google.amrnb.decoder", "libstagefright_soft_c2amrnbdec.so");
+ emplace("OMX.google.amrnb.encoder", "libstagefright_soft_c2amrnbenc.so");
+ emplace("OMX.google.amrwb.decoder", "libstagefright_soft_c2amrwbdec.so");
+ emplace("OMX.google.amrwb.encoder", "libstagefright_soft_c2amrwbenc.so");
+ emplace("OMX.google.hevc.decoder", "libstagefright_soft_c2hevcdec.so");
+ emplace("OMX.google.g711.alaw.decoder", "libstagefright_soft_c2g711alawdec.so");
+ emplace("OMX.google.g711.mlaw.decoder", "libstagefright_soft_c2g711mlawdec.so");
+ emplace("OMX.google.mpeg2.decoder", "libstagefright_soft_c2mpeg2dec.so");
+ emplace("OMX.google.h263.decoder", "libstagefright_soft_c2h263dec.so");
+ emplace("OMX.google.h263.encoder", "libstagefright_soft_c2h263enc.so");
+ emplace("OMX.google.mpeg4.decoder", "libstagefright_soft_c2mpeg4dec.so");
+ emplace("OMX.google.mpeg4.encoder", "libstagefright_soft_c2mpeg4enc.so");
+ emplace("OMX.google.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
+ emplace("OMX.google.vorbis.decoder", "libstagefright_soft_c2vorbisdec.so");
+ emplace("OMX.google.opus.decoder", "libstagefright_soft_c2opusdec.so");
+ emplace("OMX.google.vp8.decoder", "libstagefright_soft_c2vp8dec.so");
+ emplace("OMX.google.vp9.decoder", "libstagefright_soft_c2vp9dec.so");
+ emplace("OMX.google.vp8.encoder", "libstagefright_soft_c2vp8enc.so");
+ emplace("OMX.google.vp9.encoder", "libstagefright_soft_c2vp9enc.so");
+ emplace("OMX.google.raw.decoder", "libstagefright_soft_c2rawdec.so");
+ emplace("OMX.google.flac.decoder", "libstagefright_soft_c2flacdec.so");
+ emplace("OMX.google.flac.encoder", "libstagefright_soft_c2flacenc.so");
+ emplace("OMX.google.gsm.decoder", "libstagefright_soft_c2gsmdec.so");
+ emplace("OMX.google.xaac.decoder", "libstagefright_soft_c2xaacdec.so");
+}
+
+c2_status_t C2PlatformComponentStore::copyBuffer(
+ std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) {
+ (void)src;
+ (void)dst;
+ return C2_OMITTED;
+}
+
+c2_status_t C2PlatformComponentStore::query_sm(
+ const std::vector<C2Param*> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
+ return mInterface.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
+}
+
+c2_status_t C2PlatformComponentStore::config_sm(
+ const std::vector<C2Param*> ¶ms,
+ std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
+ return mInterface.config(params, C2_MAY_BLOCK, failures);
+}
+
+std::vector<std::shared_ptr<const C2Component::Traits>> C2PlatformComponentStore::listComponents() {
+ // This method SHALL return within 500ms.
+ std::vector<std::shared_ptr<const C2Component::Traits>> list;
+ for (const C2String &alias : mComponentsList) {
+ ComponentLoader &loader = mComponents.at(alias);
+ std::shared_ptr<ComponentModule> module;
+ c2_status_t res = loader.fetchModule(&module);
+ if (res == C2_OK) {
+ std::shared_ptr<const C2Component::Traits> traits = module->getTraits();
+ if (traits) {
+ list.push_back(traits);
+ }
+ }
+ }
+ return list;
+}
+
+c2_status_t C2PlatformComponentStore::findComponent(C2String name, ComponentLoader **loader) {
+ *loader = nullptr;
+ auto pos = mComponents.find(name);
+ // TODO: check aliases
+ if (pos == mComponents.end()) {
+ return C2_NOT_FOUND;
+ }
+ *loader = &pos->second;
+ return C2_OK;
+}
+
+c2_status_t C2PlatformComponentStore::createComponent(
+ C2String name, std::shared_ptr<C2Component> *const component) {
+ // This method SHALL return within 100ms.
+ component->reset();
+ ComponentLoader *loader;
+ c2_status_t res = findComponent(name, &loader);
+ if (res == C2_OK) {
+ std::shared_ptr<ComponentModule> module;
+ res = loader->fetchModule(&module);
+ if (res == C2_OK) {
+ // TODO: get a unique node ID
+ res = module->createComponent(0, component);
+ }
+ }
+ return res;
+}
+
+c2_status_t C2PlatformComponentStore::createInterface(
+ C2String name, std::shared_ptr<C2ComponentInterface> *const interface) {
+ // This method SHALL return within 100ms.
+ interface->reset();
+ ComponentLoader *loader;
+ c2_status_t res = findComponent(name, &loader);
+ if (res == C2_OK) {
+ std::shared_ptr<ComponentModule> module;
+ res = loader->fetchModule(&module);
+ if (res == C2_OK) {
+ // TODO: get a unique node ID
+ res = module->createInterface(0, interface);
+ }
+ }
+ return res;
+}
+
+c2_status_t C2PlatformComponentStore::querySupportedParams_nb(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
+ return mInterface.querySupportedParams(params);
+}
+
+c2_status_t C2PlatformComponentStore::querySupportedValues_sm(
+ std::vector<C2FieldSupportedValuesQuery> &fields) const {
+ return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
+}
+
+C2String C2PlatformComponentStore::getName() const {
+ return "android.componentStore.platform";
+}
+
+std::shared_ptr<C2ParamReflector> C2PlatformComponentStore::getParamReflector() const {
+ return mReflector;
+}
+
+std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore() {
+ static std::mutex mutex;
+ static std::weak_ptr<C2ComponentStore> platformStore;
+ std::lock_guard<std::mutex> lock(mutex);
+ std::shared_ptr<C2ComponentStore> store = platformStore.lock();
+ if (store == nullptr) {
+ store = std::make_shared<C2PlatformComponentStore>();
+ platformStore = store;
+ }
+ return store;
+}
+
+} // namespace android
diff --git a/media/codec2/vndk/include/C2AllocatorGralloc.h b/media/codec2/vndk/include/C2AllocatorGralloc.h
new file mode 100644
index 0000000..05d989e
--- /dev/null
+++ b/media/codec2/vndk/include/C2AllocatorGralloc.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+
+namespace android {
+
+/**
+ * Unwrap the native handle from a Codec2 handle allocated by C2AllocatorGralloc.
+ *
+ * @param handle a handle allocated by C2AllocatorGralloc. This includes handles returned for a
+ * graphic block allocation handle returned.
+ *
+ * @return a new NON-OWNING native handle that must be deleted using native_handle_delete.
+ */
+native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle);
+
+/**
+ * Wrap the gralloc handle and metadata into Codec2 handle recognized by
+ * C2AllocatorGralloc.
+ *
+ * @return a new NON-OWNING C2Handle that must be deleted using native_handle_delete.
+ */
+C2Handle *WrapNativeCodec2GrallocHandle(
+ const native_handle_t *const handle,
+ uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride,
+ uint32_t generation = 0, uint64_t igbp_id = 0, uint32_t igbp_slot = 0);
+
+/**
+ * \todo Get this from the buffer
+ */
+void _UnwrapNativeCodec2GrallocMetadata(
+ const C2Handle *const handle,
+ 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);
+
+class C2AllocatorGralloc : 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;
+
+ C2AllocatorGralloc(id_t id, bool bufferQueue = false);
+
+ c2_status_t status() const;
+
+ virtual ~C2AllocatorGralloc() override;
+
+ static bool isValid(const C2Handle* const o);
+
+private:
+ class Impl;
+ Impl *mImpl;
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
diff --git a/media/codec2/vndk/include/C2AllocatorIon.h b/media/codec2/vndk/include/C2AllocatorIon.h
new file mode 100644
index 0000000..1b2051f
--- /dev/null
+++ b/media/codec2/vndk/include/C2AllocatorIon.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
+
+#include <functional>
+#include <list>
+#include <mutex>
+#include <tuple>
+#include <unordered_map>
+
+#include <C2Buffer.h>
+
+namespace android {
+
+class C2AllocatorIon : public C2Allocator {
+public:
+ // Usage mapper function used by the allocator
+ // (usage, capacity) => (align, heapMask, flags)
+ //
+ // capacity is aligned to the default block-size (defaults to page size) to reduce caching
+ // overhead
+ typedef std::function<c2_status_t(C2MemoryUsage, size_t,
+ /* => */ size_t*, unsigned*, unsigned*)> UsageMapperFn;
+
+ virtual id_t getId() const override;
+
+ virtual C2String getName() const override;
+
+ virtual std::shared_ptr<const Traits> getTraits() const override;
+
+ virtual c2_status_t newLinearAllocation(
+ uint32_t capacity, C2MemoryUsage usage,
+ std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+ virtual c2_status_t priorLinearAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+ C2AllocatorIon(id_t id);
+
+ virtual c2_status_t status() const { return mInit; }
+
+ virtual ~C2AllocatorIon() override;
+
+ static bool isValid(const C2Handle* const o);
+
+ /**
+ * Updates the usage mapper for subsequent new allocations, as well as the supported
+ * minimum and maximum usage masks and default block-size to use for the mapper.
+ *
+ * \param mapper this method is called to map Codec 2.0 buffer usage to ion flags
+ * required by the ion device
+ * \param minUsage minimum buffer usage required for supported allocations (defaults to 0)
+ * \param maxUsage maximum buffer usage supported by the ion allocator (defaults to SW_READ
+ * | SW_WRITE)
+ * \param blockSize alignment used prior to calling |mapper| for the buffer capacity.
+ * This also helps reduce the size of cache required for caching mapper results.
+ * (defaults to the page size)
+ */
+ void setUsageMapper(
+ const UsageMapperFn &mapper, uint64_t minUsage, uint64_t maxUsage, uint64_t blockSize);
+
+private:
+ c2_status_t mapUsage(C2MemoryUsage usage, size_t size,
+ /* => */ size_t *align, unsigned *heapMask, unsigned *flags);
+
+ c2_status_t mInit;
+ int mIonFd;
+
+ // this locks mTraits, mBlockSize, mUsageMapper, mUsageMapperLru and mUsageMapperCache
+ mutable std::mutex mUsageMapperLock;
+ std::shared_ptr<const Traits> mTraits;
+ size_t mBlockSize;
+ UsageMapperFn mUsageMapper;
+ typedef std::pair<uint64_t, size_t> MapperKey;
+ struct MapperKeyHash {
+ std::size_t operator()(const MapperKey &) const;
+ };
+ typedef std::tuple<size_t, unsigned, unsigned, c2_status_t> MapperValue;
+ typedef std::pair<MapperKey, MapperValue> MapperKeyValue;
+ typedef std::list<MapperKeyValue>::iterator MapperKeyValuePointer;
+ std::list<MapperKeyValue> mUsageMapperLru;
+ std::unordered_map<MapperKey, MapperKeyValuePointer, MapperKeyHash> mUsageMapperCache;
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
diff --git a/media/codec2/vndk/include/C2BqBufferPriv.h b/media/codec2/vndk/include/C2BqBufferPriv.h
new file mode 100644
index 0000000..9271a71
--- /dev/null
+++ b/media/codec2/vndk/include/C2BqBufferPriv.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_BQ_BUFFER_PRIV_H_
+#define STAGEFRIGHT_CODEC2_BQ_BUFFER_PRIV_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+
+class C2BufferQueueBlockPool : public C2BlockPool {
+public:
+ C2BufferQueueBlockPool(const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId);
+
+ virtual ~C2BufferQueueBlockPool() override;
+
+ virtual C2Allocator::id_t getAllocatorId() const override {
+ return mAllocator->getId();
+ };
+
+ virtual local_id_t getLocalId() const override {
+ return mLocalId;
+ };
+
+ virtual c2_status_t fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */) override;
+
+ typedef std::function<void(uint64_t producer, int32_t slot, int64_t nsecs)> OnRenderCallback;
+
+ /**
+ * Sets render callback.
+ *
+ * \param renderCallbak callback to call for all dequeue buffer.
+ */
+ virtual void setRenderCallback(const OnRenderCallback &renderCallback = OnRenderCallback());
+
+ /**
+ * Configures an IGBP in order to create blocks. A newly created block is
+ * dequeued from the configured IGBP. Unique Id of IGBP and the slot number of
+ * blocks are passed via native_handle. Managing IGBP is responsibility of caller.
+ * When IGBP is not configured, block will be created via allocator.
+ * Since zero is not used for Unique Id of IGBP, if IGBP is not configured or producer
+ * is configured as nullptr, unique id which is bundled in native_handle is zero.
+ *
+ * \param producer the IGBP, which will be used to fetch blocks
+ */
+ virtual void configureProducer(const android::sp<android::HGraphicBufferProducer> &producer);
+
+private:
+ const std::shared_ptr<C2Allocator> mAllocator;
+ const local_id_t mLocalId;
+
+ class Impl;
+ std::shared_ptr<Impl> mImpl;
+
+ friend struct C2BufferQueueBlockPoolData;
+};
+
+#endif // STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
diff --git a/media/codec2/vndk/include/C2BufferPriv.h b/media/codec2/vndk/include/C2BufferPriv.h
new file mode 100644
index 0000000..d0b9152
--- /dev/null
+++ b/media/codec2/vndk/include/C2BufferPriv.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
+#define STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+#include <android/hardware/media/bufferpool/1.0/IAccessor.h>
+
+class C2BasicLinearBlockPool : public C2BlockPool {
+public:
+ explicit C2BasicLinearBlockPool(const std::shared_ptr<C2Allocator> &allocator);
+
+ virtual ~C2BasicLinearBlockPool() override = default;
+
+ virtual C2Allocator::id_t getAllocatorId() const override {
+ return mAllocator->getId();
+ }
+
+ virtual local_id_t getLocalId() const override {
+ return BASIC_LINEAR;
+ }
+
+ virtual c2_status_t fetchLinearBlock(
+ uint32_t capacity,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2LinearBlock> *block /* nonnull */) override;
+
+ // TODO: fetchCircularBlock
+
+private:
+ const std::shared_ptr<C2Allocator> mAllocator;
+};
+
+class C2BasicGraphicBlockPool : public C2BlockPool {
+public:
+ explicit C2BasicGraphicBlockPool(const std::shared_ptr<C2Allocator> &allocator);
+
+ virtual ~C2BasicGraphicBlockPool() override = default;
+
+ virtual C2Allocator::id_t getAllocatorId() const override {
+ return mAllocator->getId();
+ }
+
+ virtual local_id_t getLocalId() const override {
+ return BASIC_GRAPHIC;
+ }
+
+ virtual c2_status_t fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */) override;
+
+private:
+ 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;
+
+ virtual c2_status_t fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block) override;
+
+ /**
+ * Retrieves the connection Id for underlying bufferpool
+ */
+ int64_t getConnectionId();
+
+ /**
+ * Retrieves the accessor which is used by underlying bufferpool. (It can be
+ * passed to receiving process.)
+ *
+ * \param accessor IAccessor will be written to this out parameter.
+ *
+ * \return true IAcessor is writen successfully.
+ * \return false IAccessor is not written.
+ */
+ bool getAccessor(android::sp<android::hardware::media::bufferpool::V1_0::IAccessor> *accessor);
+
+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/codec2/vndk/include/C2ComponentFactory.h b/media/codec2/vndk/include/C2ComponentFactory.h
new file mode 100644
index 0000000..f6d8b98
--- /dev/null
+++ b/media/codec2/vndk/include/C2ComponentFactory.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
+#define STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
+
+#include <C2Component.h>
+
+#include <functional>
+#include <memory>
+
+/**
+ * Component factory object that enables to create a component and/or interface from a dynamically
+ * linked library. This is needed because the component/interfaces are managed objects, but we
+ * cannot safely create a managed object and pass it in C.
+ *
+ * Components/interfaces typically inherit from std::enable_shared_from_this, but C requires
+ * passing simple pointer, and shared_ptr constructor needs to know the class to be constructed
+ * derives from enable_shared_from_this.
+ *
+ */
+class C2ComponentFactory {
+public:
+ typedef std::function<void(::C2Component*)> ComponentDeleter;
+ typedef std::function<void(::C2ComponentInterface*)> InterfaceDeleter;
+
+ /**
+ * Creates a component.
+ *
+ * This method SHALL return within 100ms.
+ *
+ * \param id component ID for the created component
+ * \param component shared pointer where the created component is stored. Cleared on
+ * failure and updated on success.
+ *
+ * \retval C2_OK the component was created successfully
+ * \retval C2_TIMED_OUT could not create the component within the time limit (unexpected)
+ * \retval C2_CORRUPTED some unknown error prevented the creation of the component (unexpected)
+ *
+ * \retval C2_NO_MEMORY not enough memory to create the component
+ */
+ virtual c2_status_t createComponent(
+ c2_node_id_t id, std::shared_ptr<C2Component>* const component,
+ ComponentDeleter deleter = std::default_delete<C2Component>()) = 0;
+
+ /**
+ * Creates a component interface.
+ *
+ * This method SHALL return within 100ms.
+ *
+ * \param id component interface ID for the created interface
+ * \param interface shared pointer where the created interface is stored. Cleared on
+ * failure and updated on success.
+ *
+ * \retval C2_OK the component interface was created successfully
+ * \retval C2_TIMED_OUT could not create the component interface within the time limit
+ * (unexpected)
+ * \retval C2_CORRUPTED some unknown error prevented the creation of the component interface
+ * (unexpected)
+ *
+ * \retval C2_NO_MEMORY not enough memory to create the component interface
+ */
+ virtual c2_status_t createInterface(
+ c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
+ InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) = 0;
+
+ virtual ~C2ComponentFactory() = default;
+
+ typedef ::C2ComponentFactory* (*CreateCodec2FactoryFunc)(void);
+ typedef void (*DestroyCodec2FactoryFunc)(::C2ComponentFactory*);
+};
+
+
+#endif // STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
diff --git a/media/codec2/vndk/include/C2Debug.h b/media/codec2/vndk/include/C2Debug.h
new file mode 100644
index 0000000..af1cdab
--- /dev/null
+++ b/media/codec2/vndk/include/C2Debug.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2UTILS_DEBUG_H_
+#define C2UTILS_DEBUG_H_
+
+#include <util/C2Debug-log.h>
+
+// To allow arbitrary ordering of C2Debug.h and API headers and to keep debug utilities separately
+// from the API definitions, we provide API header specific debug headers.
+#ifdef C2PARAM_H_
+#include <util/C2Debug-param.h>
+#endif
+
+#endif // C2UTILS_DEBUG_H_
diff --git a/media/codec2/vndk/include/C2ErrnoUtils.h b/media/codec2/vndk/include/C2ErrnoUtils.h
new file mode 100644
index 0000000..5b995f6
--- /dev/null
+++ b/media/codec2/vndk/include/C2ErrnoUtils.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+#define STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+
+#include <errno.h>
+#include <C2.h>
+
+// standard ERRNO mappings
+template<int N> constexpr c2_status_t _c2_errno2status_impl();
+template<> constexpr c2_status_t _c2_errno2status_impl<0>() { return C2_OK; }
+template<> constexpr c2_status_t _c2_errno2status_impl<EINVAL>() { return C2_BAD_VALUE; }
+template<> constexpr c2_status_t _c2_errno2status_impl<EACCES>() { return C2_REFUSED; }
+template<> constexpr c2_status_t _c2_errno2status_impl<EPERM>() { return C2_REFUSED; }
+template<> constexpr c2_status_t _c2_errno2status_impl<ENOMEM>() { return C2_NO_MEMORY; }
+
+// map standard errno-s to the equivalent c2_status_t
+template<int... N> struct _c2_map_errno_impl;
+template<int E, int ... N> struct _c2_map_errno_impl<E, N...> {
+ static c2_status_t map(int result) {
+ if (result == E) {
+ return _c2_errno2status_impl <E>();
+ } else {
+ return _c2_map_errno_impl<N...>::map(result);
+ }
+ }
+};
+template<> struct _c2_map_errno_impl<> {
+ static c2_status_t map(int result) {
+ return result == 0 ? C2_OK : C2_CORRUPTED;
+ }
+};
+
+template<int... N>
+c2_status_t c2_map_errno(int result) {
+ return _c2_map_errno_impl<N...>::map(result);
+}
+
+#endif // STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+
diff --git a/media/codec2/vndk/include/C2PlatformStorePluginLoader.h b/media/codec2/vndk/include/C2PlatformStorePluginLoader.h
new file mode 100644
index 0000000..4c10643
--- /dev/null
+++ b/media/codec2/vndk/include/C2PlatformStorePluginLoader.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_C2_PLATFORM_STORE_PLUGIN_LOADER_H_
+
+#define STAGEFRIGHT_C2_PLATFORM_STORE_PLUGIN_LOADER_H_
+
+#include <memory>
+
+#include <utils/Mutex.h>
+
+#include <C2.h>
+#include <C2Buffer.h>
+
+/**
+ * Extern C interface for creating block pool from platform store extension.
+ *
+ * \param alloctorId the ID of the backing allocator type.
+ * \parem blockPoolId the ID of created block pool.
+ *
+ * \return pointer of created C2BlockPool, nullptr on error.
+ */
+typedef ::C2BlockPool* (*CreateBlockPoolFunc)(::C2Allocator::id_t, ::C2BlockPool::local_id_t);
+
+/**
+ * Extern C interface for creating allocator from platform store extension.
+ *
+ * \param alloctorId the ID of the allocator to create.
+ * \param status the returned status from creating allocator.
+ *
+ * \return pointer of created C2Allocator, nullptr on error.
+ */
+typedef ::C2Allocator* (*CreateAllocatorFunc)(::C2Allocator::id_t, ::c2_status_t*);
+
+class C2PlatformStorePluginLoader {
+public:
+ static const std::unique_ptr<C2PlatformStorePluginLoader>& GetInstance();
+ ~C2PlatformStorePluginLoader();
+
+ /**
+ * Creates block pool from platform store extension.
+ *
+ * \param alloctorId the ID of the backing allocator type.
+ * \param blockPoolId the ID of created block pool.
+ * \param pool shared pointer where the created block pool is stored.
+ *
+ * \retval C2_OK the block pool was created successfully.
+ * \retval C2_NOT_FOUND the extension symbol was not found.
+ * \retval C2_BAD_INDEX the input allocatorId is not defined in platform store extension.
+ */
+ c2_status_t createBlockPool(::C2Allocator::id_t allocatorId,
+ ::C2BlockPool::local_id_t blockPoolId,
+ std::shared_ptr<C2BlockPool>* pool);
+
+ /**
+ * Creates allocator from platform store extension.
+ *
+ * Note that this allocator is not created as shared singleton as C2AllocatorStore does, because
+ * C interface only allows raw pointer transmission for extension.
+ *
+ * \param alloctorId the ID of the allocator to create.
+ * \param allocator shared pointer where the created allocator is stored.
+ *
+ * \retval C2_OK the allocator was created successfully.
+ * \retval C2_TIMED_OUT could not create the allocator within the time limit (unexpected)
+ * \retval C2_CORRUPTED some unknown error prevented the creation of the allocator (unexpected)
+ * \retval C2_NOT_FOUND the extension symbol was not found.
+ * \retval C2_BAD_INDEX the input allocatorId is not defined in platform store extension.
+ * \retval C2_NO_MEMORY not enough memory to create the allocator
+ */
+ c2_status_t createAllocator(::C2Allocator::id_t allocatorId,
+ std::shared_ptr<C2Allocator>* const allocator);
+
+private:
+ explicit C2PlatformStorePluginLoader(const char *libPath);
+
+ static android::Mutex sMutex;
+ static std::unique_ptr<C2PlatformStorePluginLoader> sInstance;
+
+ void *mLibHandle;
+ CreateBlockPoolFunc mCreateBlockPool;
+ CreateAllocatorFunc mCreateAllocator;
+};
+
+#endif // STAGEFRIGHT_C2_PLATFORM_STORE_PLUGIN_LOADER_H_
diff --git a/media/codec2/vndk/include/C2PlatformSupport.h b/media/codec2/vndk/include/C2PlatformSupport.h
new file mode 100644
index 0000000..f31282c
--- /dev/null
+++ b/media/codec2/vndk/include/C2PlatformSupport.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
+#define STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
+
+#include <C2Component.h>
+#include <C2ComponentFactory.h>
+
+#include <memory>
+
+namespace android {
+
+/**
+ * Returns the platform allocator store.
+ * \retval nullptr if the platform allocator store could not be obtained
+ */
+std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore();
+
+/**
+ * Platform allocator store IDs
+ */
+class C2PlatformAllocatorStore : public C2AllocatorStore {
+public:
+ enum : id_t {
+ /**
+ * ID of the ion backed platform allocator.
+ *
+ * C2Handle consists of:
+ * fd shared ion buffer handle
+ * int size (lo 32 bits)
+ * int size (hi 32 bits)
+ * int magic '\xc2io\x00'
+ */
+ ION = PLATFORM_START,
+
+ /**
+ * ID of the gralloc backed platform allocator.
+ *
+ * C2Handle layout is not public. Use C2AllocatorGralloc::UnwrapNativeCodec2GrallocHandle
+ * to get the underlying gralloc handle from a C2Handle, and WrapNativeCodec2GrallocHandle
+ * to create a C2Handle from a gralloc handle - for C2Allocator::priorAllocation.
+ */
+ GRALLOC,
+
+ /**
+ * ID of the bufferqueue backed platform allocator.
+ *
+ * C2Handle layout is not public. Use C2AllocatorGralloc::UnwrapNativeCodec2GrallocHandle
+ * to get the underlying handle from a C2Handle, and WrapNativeCodec2GrallocHandle
+ * to create a C2Handle from a handle - for C2Allocator::priorAllocation.
+ */
+ BUFFERQUEUE,
+
+ /**
+ * ID of indicating the end of platform allocator definition.
+ *
+ * \note always put this macro in the last place.
+ *
+ * Extended platform store plugin should use this macro as the start ID of its own allocator
+ * types.
+ */
+ PLATFORM_END,
+ };
+};
+
+/**
+ * Retrieves a block pool for a component.
+ *
+ * \param id the local ID of the block pool
+ * \param component the component using the block pool (must be non-null)
+ * \param pool pointer to where the obtained block pool shall be stored 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 block pool does not exist
+ * \retval C2_NO_MEMORY not enough memory to fetch the block pool (this return value is only
+ * possible for basic pools)
+ * \retval C2_TIMED_OUT the operation timed out (this return value is only possible for basic pools)
+ * \retval C2_REFUSED no permission to complete any required allocation (this return value is only
+ * possible for basic pools)
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected,
+ * this return value is only possible for basic pools)
+ */
+c2_status_t GetCodec2BlockPool(
+ C2BlockPool::local_id_t id, std::shared_ptr<const C2Component> component,
+ 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
+ */
+std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore();
+
+/**
+ * Sets the preferred component store in this process for the sole purpose of accessing its
+ * interface. If this is not called, the default IComponentStore HAL (if exists) is the preferred
+ * store for this purpose. If the default IComponentStore HAL is not present, the platform
+ * component store is used.
+ */
+void SetPreferredCodec2ComponentStore(std::shared_ptr<C2ComponentStore> store);
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
diff --git a/media/codec2/vndk/include/android-C2Debug-log.h b/media/codec2/vndk/include/android-C2Debug-log.h
new file mode 100644
index 0000000..5910228
--- /dev/null
+++ b/media/codec2/vndk/include/android-C2Debug-log.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2UTILS_ANDROID_DEBUG_LOG_H_
+#define C2UTILS_ANDROID_DEBUG_LOG_H_
+
+/*
+ * Android provides logging and debug macros. Redefine them with C2 prefix and add support for
+ * opting out of verbose logs.
+ */
+
+#ifdef C2_LOG_TAG
+#define LOG_TAG C2_LOG_TAG
+#endif
+
+#include <android-base/logging.h>
+
+#ifdef C2_LOG_VERBOSE
+#define C2_LOG(LEVEL) LOG(::android::base::LEVEL)
+#else
+/**
+ * Use as follows:
+ *
+ * #define C2_LOG_TAG "tag"
+ * //#define C2_LOG_VERBOSE // enable verbose logs in this file
+ * #include <C2Debug.h>
+ *
+ * C2_LOG(DEBUG) << expr ...;
+ *
+ * Log levels are: VERBOSE, DEBUG, INFO, WARNING, ERROR, FATAL (aborts).
+ *
+ * No endl is required.
+ */
+#define C2_LOG(LEVEL) \
+ (::android::base::LEVEL != ::android::base::VERBOSE) && LOG(::android::base::LEVEL)
+#endif
+
+#define C2_CHECK CHECK
+#define C2_CHECK_LT CHECK_LT
+#define C2_CHECK_LE CHECK_LE
+#define C2_CHECK_EQ CHECK_EQ
+#define C2_CHECK_GE CHECK_GE
+#define C2_CHECK_GT CHECK_GT
+#define C2_CHECK_NE CHECK_NE
+
+#define C2_DCHECK DCHECK
+#define C2_DCHECK_LT DCHECK_LT
+#define C2_DCHECK_LE DCHECK_LE
+#define C2_DCHECK_EQ DCHECK_EQ
+#define C2_DCHECK_GE DCHECK_GE
+#define C2_DCHECK_GT DCHECK_GT
+#define C2_DCHECK_NE DCHECK_NE
+
+#endif // C2UTILS_ANDROID_DEBUG_LOG_H_
diff --git a/media/codec2/vndk/include/util/C2Debug-base.h b/media/codec2/vndk/include/util/C2Debug-base.h
new file mode 100644
index 0000000..a040e42
--- /dev/null
+++ b/media/codec2/vndk/include/util/C2Debug-base.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2UTILS_DEBUG_BASE_H_
+#define C2UTILS_DEBUG_BASE_H_
+
+#include <iostream>
+
+/**
+ * Debug print utilities for Codec 2.0 base objects.
+ */
+
+#define C2_DECLARE_AS_STRING_AND_DEFINE_STREAM_OUT(type) \
+const char *asString(type i, const char *def = "??"); \
+inline std::ostream& operator<<(std::ostream& os, const type &i) { \
+ return os << asString(i); \
+}
+
+C2_DECLARE_AS_STRING_AND_DEFINE_STREAM_OUT(c2_status_t)
+
+
+#endif // C2UTILS_DEBUG_BASE_H_
+
diff --git a/media/codec2/vndk/include/util/C2Debug-interface.h b/media/codec2/vndk/include/util/C2Debug-interface.h
new file mode 100644
index 0000000..3f31875
--- /dev/null
+++ b/media/codec2/vndk/include/util/C2Debug-interface.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2UTILS_DEBUG_INTERFACE_H_
+#define C2UTILS_DEBUG_INTERFACE_H_
+
+#include <util/C2Debug-base.h>
+#include <util/C2InterfaceUtils.h>
+
+#include <iostream>
+
+template<typename T>
+std::ostream& operator<<(std::ostream& os, const C2SupportedRange<T> &i);
+
+template<typename T>
+std::ostream& operator<<(std::ostream& os, const C2SupportedValueSet<T> &i);
+
+template<typename T>
+std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<T> &i);
+
+#endif // C2UTILS_DEBUG_INTERFACE_H_
diff --git a/media/codec2/vndk/include/util/C2Debug-log.h b/media/codec2/vndk/include/util/C2Debug-log.h
new file mode 100644
index 0000000..195c4c1
--- /dev/null
+++ b/media/codec2/vndk/include/util/C2Debug-log.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2UTILS_DEBUG_LOG_H_
+#define C2UTILS_DEBUG_LOG_H_
+
+// Platform specific debug utilities
+#ifdef __ANDROID__
+#include <android-C2Debug-log.h>
+#else
+// TODO: implement base debug utils
+#endif
+
+#endif // C2UTILS_DEBUG_LOG_H_
diff --git a/media/codec2/vndk/include/util/C2Debug-param.h b/media/codec2/vndk/include/util/C2Debug-param.h
new file mode 100644
index 0000000..e1c1de0
--- /dev/null
+++ b/media/codec2/vndk/include/util/C2Debug-param.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2UTILS_DEBUG_PARAM_H_
+#define C2UTILS_DEBUG_PARAM_H_
+
+#include <C2Param.h>
+#include <util/C2Debug-base.h>
+
+#include <iostream>
+
+/**
+ * Debug/print declarations for objects defined in C2Param.h
+ */
+C2_DECLARE_AS_STRING_AND_DEFINE_STREAM_OUT(C2FieldDescriptor::type_t)
+
+std::ostream& operator<<(std::ostream& os, const C2Param::CoreIndex &i);
+std::ostream& operator<<(std::ostream& os, const C2Param::Type &i);
+std::ostream& operator<<(std::ostream& os, const C2Param::Index &i);
+std::ostream& operator<<(std::ostream& os, const _C2FieldId &i);
+std::ostream& operator<<(std::ostream& os, const C2FieldDescriptor &i);
+std::ostream& operator<<(std::ostream& os, const C2ParamField &i);
+
+#endif // C2UTILS_DEBUG_PARAM_H_
diff --git a/media/codec2/vndk/include/util/C2InterfaceHelper.h b/media/codec2/vndk/include/util/C2InterfaceHelper.h
new file mode 100644
index 0000000..bfb43af
--- /dev/null
+++ b/media/codec2/vndk/include/util/C2InterfaceHelper.h
@@ -0,0 +1,752 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2UTILS_INTERFACE_HELPER_H_
+#define C2UTILS_INTERFACE_HELPER_H_
+
+#include <C2Component.h>
+#include <util/C2InterfaceUtils.h>
+
+#include <map>
+#include <mutex>
+#include <vector>
+
+#include <stddef.h>
+
+/**
+ * Interface Helper
+ */
+using C2R = C2SettingResultsBuilder;
+
+template<typename T, bool E=std::is_enum<T>::value>
+struct _c2_reduce_enum_to_underlying_type {
+ typedef T type;
+};
+
+template<typename T>
+struct _c2_reduce_enum_to_underlying_type<T, true> {
+ typedef typename std::underlying_type<T>::type type;
+};
+
+/**
+ * Helper class to implement parameter reflectors. This class is dynamic and is designed to be
+ * shared by multiple interfaces. This allows interfaces to add structure descriptors as needed.
+ */
+class C2ReflectorHelper : public C2ParamReflector {
+public:
+ C2ReflectorHelper() = default;
+ virtual ~C2ReflectorHelper() = default;
+ virtual std::unique_ptr<C2StructDescriptor> describe(
+ C2Param::CoreIndex paramIndex) const override;
+
+ /**
+ * Adds support for describing the given parameters.
+ *
+ * \param Params types of codec 2.0 structs (or parameters) to describe
+ */
+ template<typename... Params>
+ C2_INLINE void addStructDescriptors() {
+ std::vector<C2StructDescriptor> structs;
+ addStructDescriptors(structs, (_Tuple<Params...> *)nullptr);
+ }
+
+ /**
+ * Adds support for describing a specific struct.
+ *
+ * \param strukt descriptor for the struct that will be moved out.
+ */
+ void addStructDescriptor(C2StructDescriptor &&strukt);
+
+private:
+ template<typename... Params>
+ class C2_HIDE _Tuple { };
+
+ /**
+ * Adds support for describing the given descriptors.
+ *
+ * \param structs List of structure descriptors to add support for
+ */
+ void addStructDescriptors(
+ std::vector<C2StructDescriptor> &structs, _Tuple<> *);
+
+ /**
+ * Utility method that adds support for describing the given descriptors in a recursive manner
+ * one structure at a time using a list of structure descriptors temporary.
+ *
+ * \param T the type of codec 2.0 struct to describe
+ * \param Params rest of the structs
+ * \param structs Temporary list of structure descriptors used to optimize the operation.
+ */
+ template<typename T, typename... Params>
+ C2_INLINE void addStructDescriptors(
+ std::vector<C2StructDescriptor> &structs, _Tuple<T, Params...> *) {
+ structs.emplace_back((T*)nullptr);
+ addStructDescriptors(structs, (_Tuple<Params...> *)nullptr);
+ }
+
+ mutable std::mutex _mMutex;
+ std::map<C2Param::CoreIndex, const C2StructDescriptor> _mStructs; ///< descriptors
+};
+
+/**
+ * Utility class that implements the codec 2.0 interface API-s for some parameters.
+ *
+ * This class must be subclassed.
+ */
+class C2InterfaceHelper {
+public:
+ /**
+ * Returns the base offset of a field at |offset| that could be part of an array or part of a
+ * sub-structure.
+ *
+ * This method does not do field size verification, e.g. if offset if obtained from a structure,
+ * it will not stop at the structure boundary - this is okay, as we just want the base offset
+ * here, which is the same.
+ */
+ static
+ size_t GetBaseOffset(const std::shared_ptr<C2ParamReflector> &reflector,
+ C2Param::CoreIndex index, size_t offset);
+
+ /**
+ * The interface helper class uses references to std::shared_ptr<T> config parameters.
+ * Internally, these need to be generalized to std::shared_ptr<C2Param> refs, but the cast is
+ * not allowed (as these are references). As such, this class never returns pointer to the
+ * shared_ptrs.
+ */
+ struct ParamRef {
+ template<typename T, typename enable=
+ typename std::enable_if<std::is_convertible<T, C2Param>::value>::type>
+ inline C2_HIDE ParamRef(std::shared_ptr<T> ¶m)
+ : _mRef(reinterpret_cast<std::shared_ptr<C2Param>*>(¶m)) { }
+
+ // used by comparison operator for containers
+ operator std::shared_ptr<C2Param> *() const { return _mRef; }
+
+ /**
+ * Returns a shared pointer to the parameter.
+ */
+ std::shared_ptr<C2Param> get() const { return *_mRef; }
+
+ private:
+ std::shared_ptr<C2Param> *_mRef;
+ };
+
+ /**
+ * Field helper.
+ *
+ * Contains additional information for the field: possible values, and currently supported
+ * values.
+ */
+ class FieldHelper {
+ public:
+ /**
+ * Creates helper for a field with given possible values.
+ *
+ * \param param parameter reference. The parameter does not have to be initialized at this
+ * point.
+ * \param field field identifier
+ * \param values possible values for the field
+ */
+ FieldHelper(const ParamRef ¶m, const _C2FieldId &field,
+ std::unique_ptr<C2FieldSupportedValues> &&values);
+
+ /**
+ * Creates a param-field identifier for this field. This method is called after the
+ * underlying parameter has been initialized.
+ *
+ * \aram index
+ *
+ * @return C2ParamField
+ */
+ C2ParamField makeParamField(C2Param::Index index) const;
+
+ /**
+ * Sets the currently supported values for this field.
+ *
+ * \param values currently supported values that will be moved out
+ */
+ void setSupportedValues(std::unique_ptr<C2FieldSupportedValues> &&values);
+
+ /**
+ * Gets the currently supported values for this field. This defaults to the possible values
+ * if currently supported values were never set.
+ */
+ const C2FieldSupportedValues *getSupportedValues() const;
+
+ /**
+ * Gets the possible values for this field.
+ */
+ const C2FieldSupportedValues *getPossibleValues() const;
+
+ protected:
+ // TODO: move to impl for safety
+ ParamRef mParam;
+ _C2FieldId mFieldId;
+ std::unique_ptr<C2FieldSupportedValues> mPossible;
+ std::unique_ptr<C2FieldSupportedValues> mSupported; ///< if different from possible
+ };
+
+ template<typename T>
+ struct C2_HIDE Param;
+ class ParamHelper;
+
+ /**
+ * Factory is an interface to get the parameter helpers from a std::shared_ptr<T> &.
+ */
+ class Factory {
+ // \todo this may be already in ParamHelper
+ virtual std::shared_ptr<C2ParamReflector> getReflector() const = 0;
+
+ virtual std::shared_ptr<ParamHelper> getParamHelper(const ParamRef ¶m) const = 0;
+
+ public:
+ virtual ~Factory() = default;
+
+ template<typename T>
+ Param<T> get(std::shared_ptr<T> ¶m, std::shared_ptr<T> altValue = nullptr) const {
+ return Param<T>(getParamHelper(ParamRef(param)),
+ altValue == nullptr ? param : altValue,
+ getReflector());
+ }
+ };
+
+ /**
+ * Typed field helper.
+ */
+ template<typename T>
+ struct Field {
+ /**
+ * Constructor.
+ *
+ * \param helper helper for this field
+ * \param index parameter index (this is needed as it is not available during parameter
+ * construction) \todo remove
+ */
+ Field(std::shared_ptr<FieldHelper> helper, C2Param::Index index);
+
+ bool supportsAtAll(T value) const {
+ return C2FieldSupportedValuesHelper<T>(*_mHelper->getPossibleValues()).supports(value);
+ }
+
+ bool supportsNow(T value) const {
+ return C2FieldSupportedValuesHelper<T>(*_mHelper->getSupportedValues()).supports(value);
+ }
+
+ /**
+ * Creates a conflict resolution suggestion builder for this field.
+ */
+ C2ParamFieldValuesBuilder<T> shouldBe() const;
+
+ /**
+ * Creates a currently supported values builder for this field. This is only supported
+ * for non-const fields to disallow setting supported values for dependencies.
+ */
+ C2ParamFieldValuesBuilder<T> mustBe();
+
+ operator C2ParamField() const {
+ return _mField;
+ }
+
+ // TODO
+ C2R validatePossible(const T &value __unused) const {
+ /// TODO
+ return C2R::Ok();
+ }
+
+ private:
+ std::shared_ptr<FieldHelper> _mHelper;
+ C2ParamField _mField;
+ };
+
+ class ParamHelper {
+ public:
+ ParamHelper(ParamRef param, C2StringLiteral name, C2StructDescriptor &&);
+ ParamHelper(ParamHelper &&);
+ ~ParamHelper();
+
+ /**
+ * Finds a field descriptor.
+ */
+ std::shared_ptr<FieldHelper> findField(size_t baseOffs, size_t baseSize) const;
+
+ /// returns the parameter ref for this parameter
+ const ParamRef ref() const;
+
+ /// returns the current value of this parameter as modifiable. The constness of this
+ /// object determines the constness of the returned value.
+ std::shared_ptr<C2Param> value();
+
+ /// returns the current value of this parameter as const
+ std::shared_ptr<const C2Param> value() const;
+
+ /**
+ * Performs a configuration change request for this parameter.
+ *
+ * \param value the value that is being assigned to this parameter.
+ * This could be pointing to the current value of the
+ * parameter. This must not change.
+ * \param mayBlock whether blocking is allowed
+ * \param endValue the resulting value
+ * \param factory parameter factory (to access dependencies)
+ * \param failures vector of failures to append any failures from this
+ * operation
+ *
+ * \retval C2_OK configuration was successful
+ * \retval C2_BAD_VALUE value is incorrect (TBD)
+ * \retval C2_NO_MEMORY not enough memory to perform the assignment
+ * \retval C2_TIMED_OUT configuration timed out
+ * \retval C2_BLOCKING configuration requires blocking to be allowed
+ * \retval C2_CORRUPTED interface is corrupted
+ */
+ c2_status_t trySet(
+ const C2Param *value, bool mayBlock,
+ bool *changed,
+ Factory &factory,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures);
+
+ /// returns parameter indices that depend on this parameter
+ const std::vector<C2Param::Index> getDownDependencies() const;
+
+ /// adds a dependent parameter
+ void addDownDependency(C2Param::Index index);
+
+ /// returns that parameter refs for parameters that depend on this
+ const std::vector<ParamRef> getDependenciesAsRefs() const;
+
+ /// returns and moves out stored struct descriptor
+ C2StructDescriptor retrieveStructDescriptor();
+
+ /// returns the name of this parameter
+ C2String name() const;
+
+ /// returns the index of this parameter
+ C2Param::Index index() const;
+
+ /// returns the parameter descriptor
+ std::shared_ptr<const C2ParamDescriptor> getDescriptor() const;
+
+ /**
+ * Validates param helper.
+ *
+ * For now, this fills field info for const params.
+ *
+ * \retval C2_CORRUPTED the parameter cannot be added as such
+ */
+ c2_status_t validate(const std::shared_ptr<C2ParamReflector> &reflector);
+
+ protected:
+ typedef C2ParamDescriptor::attrib_t attrib_t;
+ attrib_t& attrib();
+
+ /// sets the default value of this parameter
+ void setDefaultValue(std::shared_ptr<C2Param> default_);
+
+ /// sets the setter method
+ void setSetter(std::function<C2R(const C2Param *, bool, bool *, Factory &)> setter);
+
+ /// sets the getter method
+ void setGetter(std::function<std::shared_ptr<C2Param>(bool)> getter);
+
+ /// sets the dependencies
+ void setDependencies(std::vector<C2Param::Index> indices, std::vector<ParamRef> refs);
+
+ /// sets the fields and their supported values
+ void setFields(std::vector<C2ParamFieldValues> &&fields);
+
+ /// build this into a final ParamHelper object
+ std::shared_ptr<ParamHelper> build();
+
+ class Impl;
+ std::unique_ptr<Impl> mImpl;
+ };
+
+ /**
+ * Typed parameter helper. This provides access to members as well as field helpers.
+ */
+ template<typename T>
+ struct C2_HIDE Param {
+ Param(
+ std::shared_ptr<ParamHelper> helper, std::shared_ptr<T> ¶m,
+ std::shared_ptr<C2ParamReflector> reflector)
+ : v(*param.get()),
+ _mTypedParam(param),
+ _mHelper(helper),
+ _mReflector(reflector) { }
+
+ template<typename S>
+ using FieldType = Field<
+ typename _c2_reduce_enum_to_underlying_type<
+ typename std::remove_const<
+ typename std::remove_extent<S>::type>::type>::type>;
+
+ template<typename S>
+ FieldType<S> F(S &field) {
+ size_t offs = (uintptr_t)&field - (uintptr_t)&get();
+ // this must fall either within sizeof(T) + FLEX_SIZE or param->size()
+ // size_t size = sizeof(field);
+ // mParam may be null
+ size_t baseSize = sizeof(typename std::remove_extent<S>::type);
+ size_t baseOffs = GetBaseOffset(
+ _mReflector, T::CORE_INDEX, offs - sizeof(C2Param));
+ if (~baseOffs == 0) {
+ // C2_LOG(FATAL) << "unknown field at offset " << offs << " size " << sizeof(S)
+ // << " base-size " << baseSize;
+ // __builtin_trap();
+ } else {
+ baseOffs += sizeof(C2Param);
+ }
+
+ std::shared_ptr<FieldHelper> helper = _mHelper->findField(baseOffs, baseSize);
+ return FieldType<S>(helper, _mTypedParam->index());
+ }
+
+ // const Param have const Fields; however, remove const from S
+ template<typename S>
+ const FieldType<S> F(S &field) const {
+ return const_cast<const FieldType<S>>(const_cast<Param *>(this)->F(field));
+ }
+
+ /// Returns a const ref value of this const param.
+ const T &get() const {
+ return *_mTypedParam.get();
+ }
+
+ /// Returns a modifiable ref value of this non-const param.
+ T &set() {
+ return *_mTypedParam.get();
+ }
+
+ /// Const-reference to the value.s
+ T const &v;
+
+ private:
+ std::shared_ptr<T> _mTypedParam;
+ std::shared_ptr<ParamHelper> _mHelper;
+ std::shared_ptr<C2ParamReflector> _mReflector;
+ };
+
+ template<typename T>
+ using C2P = Param<T>;
+
+ /**
+ * Templated move builder class for a parameter helper.
+ */
+ template<typename T>
+ class C2_HIDE ParamBuilder : private ParamHelper {
+ public:
+ /** Construct the parameter builder from minimal info required. */
+ ParamBuilder(std::shared_ptr<T> ¶m, C2StringLiteral name)
+ : ParamHelper(param, name, C2StructDescriptor((T*)nullptr)),
+ mTypedParam(¶m) {
+ attrib() = attrib_t::IS_PERSISTENT;
+ }
+
+ /** Makes this parameter required. */
+ inline ParamBuilder &required() {
+ attrib() |= attrib_t::IS_REQUIRED;
+ return *this;
+ }
+
+ /** Makes this parameter transient (not persistent). */
+ inline ParamBuilder &transient() {
+ attrib() &= ~attrib_t::IS_PERSISTENT;
+ return *this;
+ }
+
+ /** Makes this parameter hidden (not exposed in JAVA API). */
+ inline ParamBuilder &hidden() {
+ attrib() |= attrib_t::IS_HIDDEN;
+ return *this;
+ }
+
+ /** Makes this parameter internal (not exposed to query/settings). */
+ inline ParamBuilder &internal() {
+ attrib() |= attrib_t::IS_INTERNAL;
+ return *this;
+ }
+
+ /** Adds default value. Must be added exactly once. */
+ inline ParamBuilder &withDefault(std::shared_ptr<T> default_) {
+ // CHECK(!mDefaultValue);
+ // WARN_IF(!default_); // could be nullptr if OOM
+ // technically, this could be in the parent
+ *mTypedParam = std::shared_ptr<T>(T::From(C2Param::Copy(*default_).release()));
+ setDefaultValue(default_);
+ std::shared_ptr<T> *typedParam = mTypedParam;
+ setGetter([typedParam](bool) -> std::shared_ptr<C2Param> {
+ return std::static_pointer_cast<C2Param>(*typedParam);
+ });
+ return *this;
+ }
+
+ /** Adds default value. Must be added exactly once. */
+ inline ParamBuilder &withDefault(T *default_) {
+ return withDefault(std::shared_ptr<T>(default_));
+ }
+
+ /** Adds all fields to this parameter with their possible values. */
+ inline ParamBuilder &withFields(std::vector<C2ParamFieldValues> &&fields_) {
+ setFields(std::move(fields_));
+ return *this;
+ }
+
+ /**
+ * Adds a constant value (also as default). Must be added exactly once.
+ *
+ * Const parameters by definition have no dependencies.
+ */
+ inline ParamBuilder &withConstValue(std::shared_ptr<T> default_) {
+ attrib() |= attrib_t::IS_CONST;
+ setSetter([default_](
+ const C2Param *value, bool mayBlock __unused, bool *changed, Factory &) -> C2R {
+ *changed = false;
+ const T *typedValue = T::From(value);
+ if (typedValue == nullptr) {
+ return C2R::Corrupted(); // TODO BadValue/Invalid. This should not happen here.
+ }
+ if (*typedValue != *default_) {
+ return C2R::Corrupted(); // TODO ReadOnly(*default_);
+ }
+ *changed = false;
+ return C2R::Ok();
+ });
+ return withDefault(default_);
+ }
+
+ /** Adds constant value (also as default). Must be added exactly once. */
+ inline ParamBuilder &withConstValue(T *default_) {
+ return withConstValue(std::shared_ptr<T>(default_));
+ }
+
+ /**
+ * Use a strict setter.
+ *
+ * \param fn strict setter
+ * \param deps dependencies (references)
+ */
+ template<typename ... Deps>
+ inline ParamBuilder &withSetter(
+ C2R (*fn)(bool, const C2P<T> &, C2P<T> &, const C2P<Deps> &...),
+ std::shared_ptr<Deps>& ... deps) {
+ attrib() |= attrib_t::IS_STRICT;
+ std::shared_ptr<T> *typedParam = mTypedParam;
+ setSetter([typedParam, fn, &deps...](
+ const C2Param *value, bool mayBlock, bool *changed, Factory &factory) -> C2R {
+ *changed = false;
+ const T *typedValue = T::From(value);
+ if (typedValue == nullptr) {
+ return C2R::Corrupted(); // TODO BadValue/Invalid. This should not happen here.
+ }
+ // Do copy-on-change for parameters in this helper so change can be detected by
+ // a change of the pointer. Do this by working on a proposed value.
+ std::shared_ptr<T> proposedValue =
+ std::shared_ptr<T>(T::From(C2Param::Copy(*value).release()));
+ if (proposedValue == nullptr) {
+ return C2R::NoMemory(value->index());
+ }
+ C2P<T> oldValue = factory.get(*typedParam);
+ // Get a parameter helper with value pointing to proposedValue
+ C2P<T> helper = factory.get(*typedParam, proposedValue);
+ C2R result = fn(mayBlock, oldValue, helper, factory.get(deps)...);
+
+ // If value changed, copy result to current value
+ if (helper.get() != *typedParam->get()) {
+ *typedParam = proposedValue;
+ *changed = true;
+ }
+ return result;
+ });
+ setDependencies(std::vector<C2Param::Index>{ deps->index()... },
+ std::vector<ParamRef>{ ParamRef(deps)... });
+ return *this;
+ }
+
+ /**
+ * Use a non-strict setter.
+ *
+ * \param fn non-strict setter
+ * \param deps dependencies (references)
+ */
+ template<typename ... Deps>
+ inline ParamBuilder &withSetter(
+ C2R (*fn)(bool, C2P<T> &, const C2P<Deps> &...), std::shared_ptr<Deps>& ... deps) {
+ std::shared_ptr<T> *typedParam = mTypedParam;
+ setSetter([typedParam, fn, &deps...](
+ const C2Param *value, bool mayBlock, bool *changed, Factory &factory) -> C2R {
+ *changed = false;
+ const T *typedValue = T::From(value);
+ if (typedValue == nullptr) {
+ return C2R::Corrupted(); // TODO BadValue/Invalid. This should not happen here.
+ }
+ // Do copy-on-change for parameters in this helper so change can be detected by
+ // a change of the pointer. Do this by working on a proposed value.
+ std::shared_ptr<T> proposedValue =
+ std::shared_ptr<T>(T::From(C2Param::Copy(*value).release()));
+ if (proposedValue == nullptr) {
+ return C2R::NoMemory(value->index());
+ }
+ // Get a parameter helper with value pointing to proposedValue
+ C2P<T> helper = factory.get(*typedParam, proposedValue);
+ C2R result = fn(mayBlock, helper, factory.get(deps)...);
+
+ // If value changed, copy result to current value
+ if (helper.get() != *typedParam->get()) {
+ *typedParam = proposedValue;
+ *changed = true;
+ }
+ return result;
+ });
+ setDependencies(std::vector<C2Param::Index>{ deps->index()... },
+ std::vector<ParamRef>{ ParamRef(deps)... });
+ return *this;
+ }
+
+ /**
+ * Marks this a calculated (read-only) field.
+ *
+ * \param fn non-strict setter (calculator)
+ * \param deps dependencies (references)
+ */
+ template<typename ... Deps>
+ inline ParamBuilder &calculatedAs(
+ C2R (*fn)(bool, C2P<T> &, const C2P<Deps> &...), std::shared_ptr<Deps>& ... deps) {
+ attrib() |= attrib_t::IS_READ_ONLY;
+ return withSetter(fn, std::forward<decltype(deps)>(deps)...);
+ }
+
+ inline std::shared_ptr<ParamHelper> build() {
+ return ParamHelper::build();
+ }
+
+ protected:
+ std::shared_ptr<T> *mTypedParam;
+ };
+
+ template<typename T>
+ static ParamBuilder<T> DefineParam(std::shared_ptr<T> ¶m, C2StringLiteral name) {
+ return ParamBuilder<T>(param, name);
+ }
+
+public:
+ c2_status_t query(
+ const std::vector<C2Param*> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const;
+
+ /**
+ * Helper implementing config calls as well as other configuration updates.
+ *
+ * This method is virtual, so implementations may provide wrappers around it (and perform
+ * actions just before and after a configuration).
+ *
+ * \param params
+ * \param mayBlock
+ * \param failures
+ * \param updateParams if true, the updated parameter values are copied back into the arguments
+ * passed in |params|
+ * \param changes pointed to a vector to receive settings with their values changed. If not
+ * null, settings with their values changed are added to this.
+ * \return result from config
+ */
+ virtual c2_status_t config(
+ const std::vector<C2Param*> ¶ms, c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures,
+ bool updateParams = true,
+ std::vector<std::shared_ptr<C2Param>> *changes = nullptr);
+
+ c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const;
+
+ c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock) const;
+
+ std::shared_ptr<C2ReflectorHelper> getReflector() {
+ return mReflector;
+ }
+
+ typedef std::unique_lock<std::mutex> Lock;
+
+ /**
+ * Locks the interface and returns a lock. This lock must be unlocked or released without
+ * calling any other blocking call.
+ */
+ Lock lock() const;
+
+private:
+ void setInterfaceAddressBounds(uintptr_t start, uintptr_t end) {
+ // TODO: exclude this helper
+ (void)start;
+ (void)end;
+ }
+
+protected:
+ mutable std::mutex mMutex;
+ std::shared_ptr<C2ReflectorHelper> mReflector;
+ struct FactoryImpl;
+ std::shared_ptr<FactoryImpl> _mFactory;
+
+ C2InterfaceHelper(std::shared_ptr<C2ReflectorHelper> reflector);
+
+ /**
+ * Adds a parameter to this interface.
+ * \note This method CHECKs.
+ *
+ * \param param parameter to add.
+ */
+ void addParameter(std::shared_ptr<ParamHelper> param);
+
+ /**
+ * Returns the dependency index for a parameter.
+ *
+ * \param ix the index of the parameter
+ */
+ size_t getDependencyIndex_l(C2Param::Index ix) const;
+
+ virtual ~C2InterfaceHelper() = default;
+
+ /**
+ * Sets subclass instance's address and size.
+ *
+ * \todo allow subclass to specify parameter address range directly (e.g. do not assume that
+ * they are local to the subclass instance)
+ *
+ * \param T type of the derived instance
+ * \param instance pointer to the derived instance
+ */
+ template<typename T>
+ inline C2_HIDE void setDerivedInstance(T *instance) {
+ setInterfaceAddressBounds((uintptr_t)instance, (uintptr_t)(instance + 1));
+ }
+
+ C2_DO_NOT_COPY(C2InterfaceHelper);
+};
+
+/**
+ * Creates a C2ParamFieldValuesBuilder class for a field of a parameter
+ *
+ * \param spParam a configuration parameter in an interface class subclassed from C2InterfaceHelper.
+ * \param field a field of such parameter
+ */
+#define C2F(spParam, field) \
+ C2ParamFieldValuesBuilder< \
+ typename _c2_reduce_enum_to_underlying_type< \
+ typename std::remove_reference< \
+ typename std::remove_extent< \
+ decltype(spParam->field)>::type>::type>::type>( \
+ C2ParamField(spParam.get(), &spParam->field))
+
+#endif // C2UTILS_INTERFACE_HELPER_H_
diff --git a/media/codec2/vndk/include/util/C2InterfaceUtils.h b/media/codec2/vndk/include/util/C2InterfaceUtils.h
new file mode 100644
index 0000000..e9037e5
--- /dev/null
+++ b/media/codec2/vndk/include/util/C2InterfaceUtils.h
@@ -0,0 +1,1135 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2UTILS_INTERFACE_UTILS_H_
+#define C2UTILS_INTERFACE_UTILS_H_
+
+#include <C2Param.h>
+#include <C2Work.h>
+
+#include <cmath>
+#include <iterator>
+#include <limits>
+#include <type_traits>
+
+/**
+ * Helper class to map underlying types to C2Value types as well as to print field values. This is
+ * generally the same as simply the underlying type except for characters (STRING) and bytes (BLOB).
+ */
+template<typename T>
+struct C2_HIDE _C2FieldValueHelper {
+ typedef T ValueType;
+ inline static std::ostream& put(std::ostream &os, const C2Value::Primitive &p) {
+ return os << p.ref<T>();
+ }
+};
+
+template<>
+struct C2_HIDE _C2FieldValueHelper<uint8_t> {
+ typedef uint32_t ValueType;
+ static std::ostream& put(std::ostream &os, const C2Value::Primitive &p);
+};
+
+template<>
+struct C2_HIDE _C2FieldValueHelper<char> {
+ typedef int32_t ValueType;
+ static std::ostream& put(std::ostream &os, const C2Value::Primitive &p);
+};
+
+/**
+ * Supported value range utility for a field of a given type.
+ *
+ * This mimics C2FieldSupportedValue for RANGE type.
+ */
+template<typename T>
+class C2SupportedRange {
+ typedef typename _C2FieldValueHelper<T>::ValueType ValueType;
+
+//private:
+ constexpr static T MIN_VALUE = std::numeric_limits<T>::min();
+ constexpr static T MAX_VALUE = std::numeric_limits<T>::max();
+ constexpr static T MIN_STEP = std::is_floating_point<T>::value ? 0 : 1;
+
+public:
+ /**
+ * Constructs an empty range with no supported values.
+ *
+ * \note This is a specializated supported range representation that is only used for
+ * this object - it is equivalent to the EMPTY type in C2FieldSupportedValues.
+ */
+ inline static constexpr C2SupportedRange<T> None() {
+ return C2SupportedRange(MAX_VALUE, MIN_VALUE);
+ }
+
+ /**
+ * Constructs a range with all values supported.
+ */
+ inline static constexpr C2SupportedRange<T> Any() {
+ return C2SupportedRange(MIN_VALUE, MAX_VALUE);
+ }
+
+ /**
+ * Constructs a range with a single supported value.
+ *
+ * \param value the sole supported value
+ */
+ inline static constexpr C2SupportedRange<T> EqualTo(T value) {
+ return C2SupportedRange(value, value);
+ }
+
+ /**
+ * Constructs a range with supported values greater than a given value.
+ *
+ * \param value the given value
+ */
+ inline static C2SupportedRange<T> GreaterThan(T value) {
+ return (value == MAX_VALUE ? None() :
+ std::is_floating_point<T>::value ?
+ C2SupportedRange(std::nextafter(value, MAX_VALUE), MAX_VALUE) :
+ C2SupportedRange(value + MIN_STEP, MAX_VALUE));
+ }
+
+ /**
+ * Constructs a range with supported values greater than or equal to a given value.
+ *
+ * \param value the given value
+ */
+ inline static constexpr C2SupportedRange<T> GreaterThanOrEqualTo(T value) {
+ return C2SupportedRange(value, MAX_VALUE);
+ }
+
+ /**
+ * Constructs a range with supported values greater than or equal to (aka not less than) a given
+ * value.
+ *
+ * \param value the given value
+ */
+ inline static constexpr C2SupportedRange<T> NotLessThan(T value) {
+ return GreaterThanOrEqualTo(value);
+ }
+
+ /**
+ * Constructs a range with supported values less than or equal to a given value.
+ *
+ * \param value the given value
+ */
+ inline static constexpr C2SupportedRange<T> LessThanOrEqualTo(T value) {
+ return C2SupportedRange(MIN_VALUE, value);
+ }
+
+ /**
+ * Constructs a range with supported values less than or equal to (aka not greater than) a given
+ * value.
+ *
+ * \param value the given value
+ */
+ inline static constexpr C2SupportedRange<T> NotGreaterThan(T value) {
+ return LessThanOrEqualTo(value);
+ }
+
+ /**
+ * Constructs a range with supported values less than a given value.
+ *
+ * \param value the given value
+ */
+ inline static C2SupportedRange<T> LessThan(T value) {
+ return (value == MIN_VALUE ? None() :
+ std::is_floating_point<T>::value ?
+ C2SupportedRange(MIN_VALUE, std::nextafter(value, MIN_VALUE)) :
+ C2SupportedRange(MIN_VALUE, value - MIN_STEP));
+ }
+
+ /**
+ * Constructs a continuous or arithmetic range between two values.
+ *
+ * \param min the lower value
+ * \param max the higher value (if this is lower than |min| the range will be empty)
+ * \param step the step of the arithmetic range. (If this is 0 for floating point types or 1 for
+ * integer types, the constructed range is continuous)
+ */
+ inline static constexpr
+ C2SupportedRange<T> InRange(T min, T max, T step = MIN_STEP) {
+ return C2SupportedRange(min, max, step);
+ }
+
+ /**
+ * Constructs a range over a geometric series between two values.
+ *
+ * \param min the lower bound of the range. This value is always part of the constructed range
+ * as long as it is not greater than |max|.
+ * \param max the upper bound of the range. This value is only part of the constructed
+ * range if it is part of the geometric series.
+ * \param num the numerator of the geometric series.
+ * \param denom the denominator of the geometric series.
+ */
+ inline static constexpr
+ C2SupportedRange<T> InSeries(T min, T max, T num, T denom) {
+ return C2SupportedRange(min, max, 0, num, denom);
+ }
+
+ /**
+ * Constructs a range over a multiply-accumulate series between two values.
+ *
+ * \param min the lower bound of the range. This value is always part of the constructed range
+ * as long as it is not greater than |max|.
+ * \param max the upper bound of the range. This value is only part of the constructed
+ * range if it is part of the series.
+ * \param step the accumulator of the multiply-accumulate series
+ * \param num the numerator of the multiply-accumulate series.
+ * \param denom the denominator of the multiply-accumulate series.
+ */
+ inline static constexpr
+ C2SupportedRange<T> InMacSeries(T min, T max, T step, T num, T denom) {
+ return C2SupportedRange(min, max, step, num, denom);
+ }
+
+ /**
+ * Constructs a range from a generic C2FieldSupportedValues object. This will be an empty
+ * range if the supported values are not of RANGE type.
+ *
+ * \param values the supported values object
+ */
+ C2SupportedRange(const C2FieldSupportedValues &values);
+
+ /**
+ * Returns whether this range is empty.
+ */
+ inline constexpr bool isEmpty() const {
+ return _mMin > _mMax;
+ }
+
+ /**
+ * Returns whether this range is valid.
+ *
+ * Ranges are valid if they are continuous or monotonic.
+ */
+ inline constexpr bool isValid() const {
+ // TODO: handle overflow or negative series
+ return _mDenom > 0 && _mNum >= _mDenom && _mMin * (_mDenom - _mNum) < _mStep * _mDenom;
+ }
+
+ /**
+ * Returns whether a value is part of this range.
+ *
+ * \param value the value to check.
+ */
+ bool contains(T value) const;
+
+ /**
+ * Returns a new range that is the intersection of this range and another, if it is
+ * representable as a range object.
+ *
+ * \param limit the other range
+ */
+ C2SupportedRange<T> limitedTo(const C2SupportedRange<T> &limit) const;
+
+ /**
+ * Converts this object to a C2FieldSupportedValues object.
+ */
+ inline operator C2FieldSupportedValues() const {
+ return C2FieldSupportedValues(_mMin, _mMax, _mStep, _mNum, _mDenom);
+ }
+
+ /**
+ * Returns the lower bound and starting point of this range.
+ */
+ inline C2_HIDE constexpr T min() const { return _mMin; }
+
+ /**
+ * Returns the upper bound of this range.
+ */
+ inline C2_HIDE constexpr T max() const { return _mMax; }
+
+ /**
+ * Returns the step of this range.
+ */
+ inline C2_HIDE constexpr T step() const { return _mStep; }
+
+ /**
+ * Returns the numerator of this range.
+ */
+ inline C2_HIDE constexpr T num() const { return _mNum; }
+
+ /**
+ * Returns the denominator of this range.
+ */
+ inline C2_HIDE constexpr T denom() const { return _mDenom; }
+
+private:
+ /**
+ * Returns whether x[i...] is all values between _mMin and _mMax.
+ */
+ inline C2_HIDE constexpr bool isSimpleRange() const {
+ return _mStep == MIN_STEP && _mNum == 1 && _mDenom == 1;
+ }
+
+ /**
+ * Returns whether x[i...] is defined as such:
+ * x[i + 1] = x[i] + _mStep, where _mStep > 0 and _mMin <= x[i] <= _mMax
+ */
+ inline C2_HIDE constexpr bool isArithmeticSeries() const {
+ return _mStep > MIN_STEP && _mNum == 1 && _mDenom == 1;
+ }
+
+ /**
+ * Returns whether x[i...] is defined as such:
+ * x[i] = x[0] * (_mNum / _mDenom) ^ i (with rounding), where _mNum > _mDenom > 0 and x[0] > 0
+ */
+ inline C2_HIDE constexpr bool isGeometricSeries() const {
+ return _mMin > 0 && _mStep == 0 && _mNum > _mDenom && _mDenom > 0;
+ }
+
+ /**
+ * Returns whether x[i...] is defined as such:
+ * x[i + 1] = x[i] * _mNum / _mDenom + _mStep (with rounding), while x[i + 1] > x[i], where
+ * _mStep != 0, _mDenom > 0 and _mNum > 0
+ */
+ inline C2_HIDE constexpr bool isMacSeries() const {
+ return _mStep != 0 && _mNum > 0 && _mDenom > 0;
+ }
+
+ /**
+ * Constructs an arithmetic or continuous range.
+ *
+ * \param min the lower value
+ * \param max the higher value (if this is lower than |min| the range will be empty)
+ * \param step the step of the arithmetic range. (If this is 0 for floating point types or 1 for
+ * integer types, the constructed range is continuous)
+ */
+ constexpr C2_HIDE C2SupportedRange(T min, T max, T step = T(std::is_floating_point<T>::value ? 0 : 1))
+ : _mMin(min), _mMax(max), _mStep(step), _mNum(1), _mDenom(1) { }
+
+ /**
+ * Constructs a range over a geomertic sor multiply-accumulate series.
+ *
+ * \param min the lower bound of the range. This value is always part of the constructed range
+ * as long as it is not greater than |max|.
+ * \param max the upper bound of the range. This value is only part of the constructed
+ * range if it is part of the geometric series.
+ * \param step the accumulator of the multiply-accumulate series. This is 0 for a pure geometric
+ * series
+ * \param num the numerator of the geometric series.
+ * \param denom the denominator of the geometric series.
+ */
+ constexpr C2_HIDE C2SupportedRange(T min, T max, T step, T num, T den)
+ : _mMin(min), _mMax(max), _mStep(step), _mNum(num), _mDenom(den) { }
+
+ T _mMin; ///< lower bound and starting point
+ T _mMax; ///< upper bound
+ T _mStep; ///< step of an arithmetic series (0 if continuous floating point range)
+ T _mNum; ///< numerator of a geometric series
+ T _mDenom; ///< denominator of a geometric series
+};
+
+/**
+ * Ordered supported flag set for a field of a given type.
+ */
+template<typename T>
+class C2SupportedFlags {
+ typedef typename _C2FieldValueHelper<T>::ValueType ValueType;
+
+public:
+ /**
+ * Constructs an empty flag set.
+ *
+ * \note This is a specializated supported flags representation that is only used for
+ * this object - it is equivalent to the EMPTY type in C2FieldSupportedValues.
+ */
+ static inline C2SupportedFlags<T> None() {
+ return C2SupportedFlags(std::initializer_list<C2Value::Primitive>());
+ }
+
+ /**
+ * Constructs a flags set of given flags.
+ *
+ * \param flags the ordered set of flags as an initializer list.
+ * \param min minimum set of flags to be set.
+ */
+ static inline C2SupportedFlags<T> Flags(const std::initializer_list<T> flags, T min = T(0)) {
+ return C2SupportedFlags(min, flags);
+ }
+
+ /**
+ * Constructs a flags set of given flags.
+ *
+ * \param flags the ordered set of flags.
+ * \param min minimum set of flags to be set.
+ */
+ static inline C2SupportedFlags<T> Flags(const std::vector<T> &flags, T min = T(0)) {
+ return C2SupportedFlags(min, flags);
+ }
+
+ /**
+ * Constructs a flag set from a generic C2FieldSupportedValues object. This will be an empty
+ * set if the supported values are not of FLAGS type.
+ *
+ * \param values the supported values object
+ */
+ C2SupportedFlags<T>(const C2FieldSupportedValues &values) {
+ if (values.type == C2FieldSupportedValues::FLAGS) {
+ _mValues.insert(_mValues.end(), values.values.begin(), values.values.end());
+ }
+ }
+
+ /**
+ * Returns whether this set is empty.
+ */
+ constexpr bool isEmpty() const {
+ return _mValues.empty();
+ }
+
+ /**
+ * Returns whether a value is part of this set.
+ *
+ * \param value the value to check.
+ */
+ bool contains(T value) const;
+
+ /**
+ * Returns a new flag set that is the intersection of this set and another.
+ *
+ * \param limit the other value set
+ */
+ C2SupportedFlags<T> limitedTo(const C2SupportedFlags<T> &limit) const;
+
+ /**
+ * Converts this object to a C2FieldSupportedValues object.
+ */
+ operator C2FieldSupportedValues() const {
+ return C2FieldSupportedValues(!isEmpty() /* flags */, _mValues);
+ }
+
+ /**
+ * Returns the ordered set of flags of this object.
+ */
+ const std::vector<T> flags() const;
+
+ /**
+ * Returns the minimum set of flags for this object.
+ */
+ T min() const;
+
+ /**
+ * Clears this supported value set.
+ */
+ inline void clear() {
+ _mValues.clear();
+ }
+
+private:
+ /**
+ * Constructs a flag set directly from an internal representation.
+ *
+ * \param values a vector containing the minimum flag set followed by the set of flags
+ */
+ C2SupportedFlags(std::vector<C2Value::Primitive> &&values)
+ : _mValues(values) {
+ }
+
+ /**
+ * Constructs a flag set from a set of flags and a minimum flag set.
+ *
+ * \param flags the set
+ */
+ C2SupportedFlags(T min, const std::vector<T> &flags) {
+ _mValues.emplace_back(min);
+ for (T elem : flags) {
+ _mValues.emplace_back(elem);
+ }
+ }
+
+ /**
+ * Constructs a flag set from a set of initializer list values and a minimum flag set
+ *
+ * \param flags the set
+ */
+ C2SupportedFlags(T min, const std::initializer_list<T> flags) {
+ _mValues.emplace_back(min);
+ for (T elem : flags) {
+ _mValues.emplace_back(elem);
+ }
+ }
+
+ std::vector<C2Value::Primitive> _mValues; ///< the minimum flag set followed by the set of flags
+};
+
+/**
+ * Ordered supported value set for a field of a given type.
+ */
+template<typename T>
+class C2SupportedValueSet {
+ typedef typename _C2FieldValueHelper<T>::ValueType ValueType;
+
+public:
+ /**
+ * Constructs an empty value set.
+ *
+ * \note This is a specializated supported range representation that is only used for
+ * this object - it is equivalent to the EMPTY type in C2FieldSupportedValues.
+ */
+ static inline C2SupportedValueSet<T> None() {
+ return C2SupportedValueSet({ });
+ }
+
+ /**
+ * Constructs a value set of given values.
+ *
+ * \param values the ordered set of values as an initializer list.
+ */
+ static inline C2SupportedValueSet<T> OneOf(const std::initializer_list<T> values) {
+ return C2SupportedValueSet(values);
+ }
+
+ /**
+ * Constructs a value set of given values.
+ *
+ * \param values the ordered set of values.
+ */
+ static inline C2SupportedValueSet<T> OneOf(const std::vector<T> &values) {
+ return C2SupportedValueSet(values);
+ }
+
+ /**
+ * Constructs a value set from a generic C2FieldSupportedValues object. This will be an empty
+ * set if the supported values are not of VALUES type.
+ *
+ * \param values the supported values object
+ */
+ C2SupportedValueSet<T>(const C2FieldSupportedValues &values) {
+ if (values.type == C2FieldSupportedValues::VALUES) {
+ _mValues.insert(_mValues.end(), values.values.begin(), values.values.end());
+ }
+ }
+
+ /**
+ * Returns whether this range is empty.
+ */
+ constexpr bool isEmpty() const {
+ return _mValues.empty();
+ }
+
+ /**
+ * Returns whether a value is part of this set.
+ *
+ * \param value the value to check.
+ */
+ bool contains(T value) const;
+
+ /**
+ * Returns a new value set that is the intersection of this set and another.
+ *
+ * \param limit the other value set
+ */
+ C2SupportedValueSet<T> limitedTo(const C2SupportedValueSet<T> &limit) const;
+
+ /**
+ * Returns a new value set that is the intersection of this set and a value range.
+ *
+ * \param limit the other range
+ */
+ C2SupportedValueSet<T> limitedTo(const C2SupportedRange<T> &limit) const;
+
+ /**
+ * Returns a new value set that is the intersection of this set and a flag set.
+ *
+ * \param limit the other flag set
+ */
+ C2SupportedValueSet<T> limitedTo(const C2SupportedFlags<T> &limit) const;
+
+ /**
+ * Converts this object to a C2FieldSupportedValues object.
+ */
+ operator C2FieldSupportedValues() const {
+ return C2FieldSupportedValues(false /* flags */, _mValues);
+ }
+
+ /**
+ * Returns the ordered set of values of this object.
+ */
+ const std::vector<T> values() const;
+
+ /**
+ * Clears this supported value set.
+ */
+ inline void clear() {
+ _mValues.clear();
+ }
+
+private:
+ /**
+ * Constructs a value set from a set of C2Value::Primitive values.
+ *
+ * \param values the set
+ */
+ C2SupportedValueSet(std::vector<C2Value::Primitive> &&values)
+ : _mValues(values) {
+ }
+
+ /**
+ * Constructs a value set from a set of values.
+ *
+ * \param values the set
+ */
+ C2SupportedValueSet(const std::vector<T> &values) {
+ for (T elem : values) {
+ _mValues.emplace_back(elem);
+ }
+ }
+
+ /**
+ * Constructs a value set from a set of initializer list values
+ *
+ * \param values the set
+ */
+ C2SupportedValueSet(const std::initializer_list<T> values) {
+ for (T elem : values) {
+ _mValues.emplace_back(elem);
+ }
+ }
+
+ std::vector<C2Value::Primitive> _mValues; ///< the supported set of values
+};
+
+/**
+ * Helper class to handle C2FieldSupporteValues object for fields of various types.
+ */
+template<typename T>
+class C2FieldSupportedValuesHelper;
+
+// templated operator must be predeclared for friend declaration
+template<typename T>
+std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<T> &i);
+
+template<typename T>
+class C2FieldSupportedValuesHelper {
+public:
+ /**
+ * Creates a helper for a specific type from a generic C2FieldSupportedValues struct.
+ */
+ C2FieldSupportedValuesHelper(const C2FieldSupportedValues &values);
+
+ // TRICKY: needed for std::unique_ptr<Impl> declaration
+ ~C2FieldSupportedValuesHelper();
+
+ // support copy constructor/operator
+ C2FieldSupportedValuesHelper(const C2FieldSupportedValuesHelper &);
+ C2FieldSupportedValuesHelper& operator=(const C2FieldSupportedValuesHelper &);
+
+ bool supports(T value) const;
+
+private:
+ // use pimpl as implementation may change in the future
+ struct Impl;
+ std::unique_ptr<Impl> _mImpl;
+
+ friend std::ostream& operator<< <T>(std::ostream& os, const C2FieldSupportedValuesHelper<T> &i);
+ //friend std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper &i);
+};
+
+/**
+ * Builder for supported values for a field of a given type.
+ *
+ * This builder can be used to successively restrict the supported values for a field. Upon
+ * creation, there are no supported values specified - which for this builder means that all
+ * values are supported.
+ */
+template<typename T>
+class C2ParamFieldValuesBuilder {
+public:
+ /**
+ * Creates a builder with no defined values - but implicitly any value allowed.
+ */
+ C2ParamFieldValuesBuilder(const C2ParamField &field);
+
+ /**
+ * Get C2ParamFieldValues from this builder.
+ */
+ operator C2ParamFieldValues() const;
+
+ /**
+ * Define the supported values as the currently supported values of this builder.
+ */
+ C2ParamFieldValuesBuilder<T> &any();
+
+ /**
+ * Restrict (and thus define) the supported values to none.
+ *
+ * \note This really should not be used from the builder as all params must have supported
+ * values, but is here in case this is really the case.
+ */
+ C2ParamFieldValuesBuilder<T> &none();
+
+ /**
+ * Restrict (and thus define) the supported values to |value| alone.
+ */
+ C2ParamFieldValuesBuilder<T> &equalTo(T value);
+
+ /**
+ * Restrict (and thus define) the supported values to values greater than |value|.
+ */
+ inline C2ParamFieldValuesBuilder<T> &greaterThan(T value) {
+ return limitTo(C2SupportedRange<T>::GreaterThan(value));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to values greater than or equal to |value|.
+ */
+ C2ParamFieldValuesBuilder<T> &greaterThanOrEqualTo(T value) {
+ return limitTo(C2SupportedRange<T>::GreaterThanOrEqualTo(value));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to values greater than or equal to |value|.
+ */
+ C2ParamFieldValuesBuilder<T> ¬LessThan(T value) {
+ return limitTo(C2SupportedRange<T>::NotLessThan(value));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to values less than or equal to |value|.
+ */
+ C2ParamFieldValuesBuilder<T> &lessThanOrEqualTo(T value) {
+ return limitTo(C2SupportedRange<T>::LessThanOrEqualTo(value));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to values less than or equal to |value|.
+ */
+ C2ParamFieldValuesBuilder<T> ¬GreaterThan(T value) {
+ return limitTo(C2SupportedRange<T>::NotGreaterThan(value));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to values less than |value|.
+ */
+ C2ParamFieldValuesBuilder<T> &lessThan(T value) {
+ return limitTo(C2SupportedRange<T>::LessThan(value));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to values in the range of [ |min|, |max| ]
+ * with optional |step|.
+ */
+ C2ParamFieldValuesBuilder<T> &inRange(
+ T min, T max, T step = std::is_floating_point<T>::value ? T(0) : T(1)) {
+ return limitTo(C2SupportedRange<T>::InRange(min, max, step));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to values in the geometric series starting
+ * from |min| with factor |num| / |denom|, not greater than |max|.
+ */
+ C2ParamFieldValuesBuilder<T> &inSeries(T min, T max, T num, T denom) {
+ return limitTo(C2SupportedRange<T>::InSeries(min, max, num, denom));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to values in the multiply-accumulate series
+ * starting from |min| with factor |num| / |denom| and |step|, not greater than |max|.
+ */
+ C2ParamFieldValuesBuilder<T> &inMacSeries(T min, T max, T step, T num, T denom) {
+ return limitTo(C2SupportedRange<T>::InMacSeries(min, max, step, num, denom));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to values in |values|.
+ */
+ C2ParamFieldValuesBuilder<T> &oneOf(const std::initializer_list<T> values) {
+ return limitTo(C2SupportedValueSet<T>::OneOf(values));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to values in |values|.
+ */
+ C2ParamFieldValuesBuilder<T> &oneOf(const std::vector<T> &values) {
+ return limitTo(C2SupportedValueSet<T>::OneOf(values));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to flags in |flags| with at least |min|
+ * set.
+ */
+ C2ParamFieldValuesBuilder<T> &flags(const std::vector<T> &flags, T min = T(0)) {
+ return limitTo(C2SupportedFlags<T>::Flags(flags, min));
+ }
+
+ /**
+ * Restrict (and thus define) the supported values to flags in |values| with at least |min|
+ * set.
+ */
+ C2ParamFieldValuesBuilder<T> &flags(const std::initializer_list<T> flags, T min = T(0)) {
+ return limitTo(C2SupportedFlags<T>::Flags(flags, min));
+ }
+
+ virtual ~C2ParamFieldValuesBuilder();
+
+ // support copy constructor/operator
+ C2ParamFieldValuesBuilder(const C2ParamFieldValuesBuilder &);
+ C2ParamFieldValuesBuilder& operator=(const C2ParamFieldValuesBuilder &);
+
+private:
+ /**
+ * Restrict (and thus define) the supported values to a value set.
+ */
+ C2ParamFieldValuesBuilder<T> &limitTo(const C2SupportedValueSet<T> &limit);
+
+ /**
+ * Restrict (and thus define) the supported values to a value set.
+ */
+ C2ParamFieldValuesBuilder<T> &limitTo(const C2SupportedFlags<T> &limit);
+
+ /**
+ * Restrict (and thus define) the supported values to a range.
+ */
+ C2ParamFieldValuesBuilder<T> &limitTo(const C2SupportedRange<T> &limit);
+
+ struct Impl;
+ std::unique_ptr<Impl> _mImpl;
+};
+
+/**
+ * Builder for a list of setting conflicts.
+ */
+class C2SettingConflictsBuilder {
+public:
+ /**
+ * Creates an empty list of setting conflicts.
+ */
+ C2SettingConflictsBuilder();
+
+ /**
+ * Creates a list containing a single setting conflict.
+ */
+ C2SettingConflictsBuilder(C2ParamFieldValues &&conflict);
+
+ /**
+ * Adds a conflict to the current list of conflicts and returns this
+ */
+ C2SettingConflictsBuilder& with(C2ParamFieldValues &&conflict);
+
+ /**
+ * Gets the current list of conflicts (and moves them out of this builder.)
+ * (this is why it is not const)
+ */
+ std::vector<C2ParamFieldValues> retrieveConflicts();
+
+ /**
+ * Returns whether the current list is empty.
+ */
+ inline bool empty() const { return _mConflicts.empty(); }
+
+ inline operator bool() const { return empty(); }
+
+private:
+ std::vector<C2ParamFieldValues> _mConflicts;
+};
+
+/**
+ * Setting result builder for a parameter.
+ */
+struct C2SettingResultBuilder {
+ /**
+ * Creates a read-only setting result failure.
+ *
+ * This does not take FSV as only the current value of the field is supported.
+ */
+ static C2SettingResult ReadOnly(const C2ParamField ¶m);
+
+ /**
+ * Creates a bad-value or infoinformational bad-value setting result failure.
+ *
+ * This does not take FSV as the value is outside of the possible values. As such, there are no
+ * conflicts for this case either.
+ */
+ static C2SettingResult BadValue(const C2ParamField ¶mField, bool isInfo = false);
+
+ /**
+ * Creates a conflict (or informational conflict) setting result failure.
+ *
+ * This takes FSV so use paramFieldValues and optional conflicts.
+ */
+ static C2SettingResult Conflict(
+ C2ParamFieldValues &¶mFieldValues, C2SettingConflictsBuilder &conflicts,
+ bool isInfo = false);
+
+ // TODO: retrieve results
+
+
+private:
+ C2ParamField _mParamField;
+ C2SettingResult _mResult;
+
+ C2SettingResultBuilder(const C2SettingResultBuilder &) = delete;
+};
+
+/**
+ * Setting results (PLURAL) builder.
+ *
+ * Setting results contain a failure status along with a list of failing fields or params.
+ */
+struct C2SettingResultsBuilder {
+ C2SettingResultsBuilder(const C2SettingResultsBuilder&) = delete;
+ C2SettingResultsBuilder(C2SettingResultsBuilder&&) = default;
+ C2SettingResultsBuilder &operator=(C2SettingResultsBuilder&&) = default;
+
+ /** \returns (default) successful result with no details. */
+ inline static C2SettingResultsBuilder Ok() {
+ return C2SettingResultsBuilder(C2_OK);
+ }
+
+ /** \returns Interface is in bad state, with no further details. */
+ inline static C2SettingResultsBuilder BadState() {
+ return C2SettingResultsBuilder(C2_BAD_STATE);
+ }
+
+ /** \returns Interface connection timed out, with no further details. */
+ inline static C2SettingResultsBuilder TimedOut() {
+ return C2SettingResultsBuilder(C2_TIMED_OUT);
+ }
+
+ /** \returns Interface connection is corrupted, with no further details. */
+ inline static C2SettingResultsBuilder Corrupted() {
+ return C2SettingResultsBuilder(C2_CORRUPTED);
+ }
+
+ inline static C2SettingResultsBuilder NoMemory(C2Param::Index index_ __unused) {
+ // TODO: try to add failure result
+ return C2SettingResultsBuilder(C2_NO_MEMORY);
+ }
+
+ // TODO: this should not be a constructor
+ /** Creates a builder with a single bad value setting result. */
+ C2SettingResultsBuilder(C2SettingResult &&result);
+
+ /** Combines this results with other results. */
+ C2SettingResultsBuilder plus(C2SettingResultsBuilder&& results);
+
+ /** Retrieve (get and move out) failures and return the failure status. */
+ c2_status_t retrieveFailures(std::vector<std::unique_ptr<C2SettingResult>>* const failures);
+
+private:
+ /** Setting results based on a single status. This is used when actual setting could not be
+ * attempted to get a single C2SettingResult, or when a setting succeeded without
+ * 'complaints'. */
+ C2SettingResultsBuilder(c2_status_t status);
+ // status must be one of OK, BAD_STATE, TIMED_OUT, CORRUPTED or NO_MEMORY
+ // mainly: BLOCKING, BAD_INDEX, BAD_VALUE and NO_MEMORY requires a setting attempt, but
+ // NO_MEMORY may not allow us to create a results structure.
+
+ /**
+ * One of OK, BAD_INDEX, BAD_VALUE, BAD_STATE, NO_MEMORY, TIMED_OUT, BLOCKING or CORRUPTED.
+ */
+ c2_status_t _mStatus __unused;
+
+ /**
+ * Vector of individual setting result details.
+ */
+ std::vector<std::unique_ptr<C2SettingResult>> _mResults;
+};
+
+/**
+ * Utility class to enumerate fields of parameters.
+ */
+struct C2FieldUtils {
+ struct _Inspector;
+
+ /**
+ * An extended field descriptor object with structural information (lineage back to the root of
+ * the param).
+ */
+ struct Info {
+ typedef C2FieldDescriptor::type_t type_t; ///< field type
+ typedef C2FieldDescriptor::NamedValuesType NamedValuesType; ///< named values list type
+
+ /// returns the name of the field
+ C2String name() const;
+
+ /// returns the type of this field
+ type_t type() const;
+
+ /**
+ * Returns the defined name-value pairings for this field. The returned reference is
+ * only valid during the validity of this object
+ */
+ const NamedValuesType &namedValues() const;
+
+ /**
+ * The index of this field. E.g. param.field or param.field[0] has an index of 0, and
+ * param.struct[2].field[3] has an index of 3.
+ */
+ size_t index() const;
+
+ /// returns the length of the field in case it is an array. Returns 0 for
+ /// T[] arrays if this info comes from a C2Param::Index object, and the currently used
+ /// extent if it comes from a C2Param object. Returns 1 for T[1] arrays as well as if the
+ /// field is not an array.
+ size_t extent() const;
+
+ /**
+ * The (structural) depth of this field. E.g. param.field or param.field[0] has a depth of
+ * 0, and param.struct.field or param.struct[0].field[0] has a depth of 1.
+ */
+ size_t depth() const;
+
+ /**
+ * Returns the offset of this field in the parameter in bytes.
+ */
+ size_t offset() const;
+
+ /**
+ * Returns the size of this field in bytes.
+ */
+ size_t size() const;
+
+ /**
+ * The offset of this field's array. E.g. for param.struct[2].field[3] this is the offset
+ * of its smallest sibling: param.struct[2].field[0].
+ */
+ size_t arrayOffset() const;
+
+ /**
+ * Returns the size of this field's array. This is equivalent to extent() * size()
+ */
+ size_t arraySize() const;
+
+ /**
+ * The offset of the base field. The base field is a cousin of the current field where
+ * all indices are 0. E.g. the the base field for param.struct[2].field[3] is
+ * param.struct[0].field[0]. Base fields are used to specify supported values for
+ * all cousin fields.
+ */
+ size_t baseFieldOffset() const;
+
+ /**
+ * Returns whether this field is an arithmetic (integral, counter or float) field.
+ */
+ bool isArithmetic() const;
+
+ /**
+ * Returns whether this field can have a flexible extent. extent() returns the current
+ * extent.
+ */
+ bool isFlexible() const;
+
+ /// returns whether this info is valid
+ inline bool isValid() const { return _mImpl != nullptr; }
+
+ /// returns the info for the parent of this field, or an invalid Info object if it has no
+ /// parents
+ Info parent() const;
+
+ /// returns whether this info is valid
+ inline operator bool() const { return isValid(); }
+
+ struct Impl;
+ Info(std::shared_ptr<Impl>);
+
+ private:
+ std::shared_ptr<Impl> _mImpl;
+ friend struct _Inspector;
+ };
+
+ /**
+ * An (input) iterator object over fields using Info objects.
+ */
+ struct Iterator {
+ typedef Info const value_type;
+ typedef ptrdiff_t difference_type;
+ typedef Info const * pointer;
+ typedef Info const reference;
+ typedef std::input_iterator_tag iterator_category;
+
+ /// return Info at current position
+ virtual reference operator*() const;
+
+ /// move to the next field
+ virtual Iterator& operator++();
+
+ virtual bool operator==(const Iterator &) const;
+ inline bool operator!=(const Iterator &other) const { return !operator==(other); }
+
+ virtual ~Iterator() = default;
+
+ struct Impl;
+ Iterator(std::shared_ptr<Impl>);
+
+ protected:
+ std::shared_ptr<Impl> mImpl;
+ };
+
+ /**
+ * An (input) iterable object representing a list of fields.
+ */
+ struct List {
+ /// returns an iterator to the beginning of the list
+ virtual Iterator begin() const;
+
+ /// returns an iterator to the end of the list
+ virtual Iterator end() const;
+
+ virtual ~List() = default;
+
+ struct Impl;
+ List(std::shared_ptr<Impl>);
+
+ protected:
+ std::shared_ptr<Impl> mImpl;
+ };
+
+ /**
+ * Enumerates all (base) fields at index 0 of the parameter. The order of iteration is the
+ * following:
+ * Fields of a structure are enumerated in field order. However, sub-fields of a structure
+ * are enumerated directly after the structure field, and prior to sibling fields.
+ *
+ * In essence the order of enumeration is first by increasing offset, then by decreasing size.
+ *
+ * \param param parameter to enumerate its fields
+ * \param reflector parameter reflector used for enumeration
+ *
+ * \return an iterable object
+ */
+ static List enumerateFields(
+ const C2Param ¶m,
+ const std::shared_ptr<C2ParamReflector> &reflector);
+
+ /**
+ * Enumerates all cousin fields up to depth - level for a field. If level is 0, it enumerates
+ * only the field. For level 1, it enumerates all fields in its current array (which may be
+ * itself if extent is 1). The order of iteration is by increasing field offset.
+ */
+ static List enumerateCousins(
+ const Info &field,
+ uint32_t level = ~0);
+
+ /**
+ * Locates the field in a parameter and returns a list of 2 elements - the most-specific field
+ * array of the parameter that contains the entire field. If the field is not a valid field
+ * specifier for this parameter (e.g. it is outside the bounds of the parameter), it returns
+ * an empty list.
+ */
+ static std::vector<Info> locateField(
+ const C2Param ¶m, const _C2FieldId &field,
+ const std::shared_ptr<C2ParamReflector> &reflector);
+
+ static std::vector<Info> locateField(
+ const C2ParamField &pf, const std::shared_ptr<C2ParamReflector> &reflector);
+
+};
+
+#include <util/C2Debug-interface.h>
+
+#endif // C2UTILS_INTERFACE_UTILS_H_
diff --git a/media/codec2/vndk/include/util/C2ParamUtils.h b/media/codec2/vndk/include/util/C2ParamUtils.h
new file mode 100644
index 0000000..b51bd94
--- /dev/null
+++ b/media/codec2/vndk/include/util/C2ParamUtils.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2UTILS_PARAM_UTILS_H_
+#define C2UTILS_PARAM_UTILS_H_
+
+#include <utility>
+#include <vector>
+
+/** \file
+ * Utilities for parameter handling to be used by Codec2 implementations.
+ */
+
+/// \cond INTERNAL
+
+struct C2Param;
+
+class C2ParamUtils {
+ friend class C2UtilTest_ParamUtilsTest_Test;
+
+public:
+
+ /// safe(r) parsing from parameter blob
+ static
+ C2Param *ParseFirst(const uint8_t *blob, size_t size);
+};
+
+/// \endcond
+
+#endif // C2UTILS_PARAM_UTILS_H_
+
diff --git a/media/codec2/vndk/internal/C2BlockInternal.h b/media/codec2/vndk/internal/C2BlockInternal.h
new file mode 100644
index 0000000..2abf3ac
--- /dev/null
+++ b/media/codec2/vndk/internal/C2BlockInternal.h
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+#define ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+
+#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+
+#include <C2Buffer.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+
+struct BufferPoolData;
+
+}
+}
+}
+}
+
+/**
+ * Stores informations from C2BlockPool implementations which are required by C2Block.
+ */
+struct C2_HIDE _C2BlockPoolData {
+ enum type_t : int {
+ TYPE_BUFFERPOOL = 0,
+ TYPE_BUFFERQUEUE,
+ };
+
+ virtual type_t getType() const = 0;
+
+protected:
+ _C2BlockPoolData() = default;
+
+ virtual ~_C2BlockPoolData() = default;
+};
+
+struct C2BufferQueueBlockPoolData;
+
+/**
+ * Internal only interface for creating blocks by block pool/buffer passing implementations.
+ *
+ * \todo this must be hidden
+ */
+struct _C2BlockFactory {
+ /**
+ * Create a linear block from an allocation for an allotted range.
+ *
+ * \param alloc parent allocation
+ * \param data blockpool data
+ * \param offset allotted range offset
+ * \param size allotted size
+ *
+ * \return shared pointer to the linear block. nullptr if there was not enough memory to
+ * create this block.
+ */
+ static
+ std::shared_ptr<C2LinearBlock> CreateLinearBlock(
+ const std::shared_ptr<C2LinearAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
+ size_t offset = 0,
+ size_t size = ~(size_t)0);
+
+ /**
+ * Create a graphic block from an allocation for an allotted section.
+ *
+ * \param alloc parent allocation
+ * \param data blockpool data
+ * \param crop allotted crop region
+ *
+ * \return shared pointer to the graphic block. nullptr if there was not enough memory to
+ * create this block.
+ */
+ static
+ std::shared_ptr<C2GraphicBlock> CreateGraphicBlock(
+ const std::shared_ptr<C2GraphicAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
+ const C2Rect &allottedCrop = C2Rect(~0u, ~0u));
+
+ /**
+ * Return a block pool data from 1D block.
+ *
+ * \param shared pointer to the 1D block which is already created.
+ */
+ static
+ std::shared_ptr<_C2BlockPoolData> GetLinearBlockPoolData(
+ const C2Block1D& block);
+
+ /**
+ * Return a block pool data from 2D block.
+ *
+ * \param shared pointer to the 2D block which is already created.
+ */
+ static
+ std::shared_ptr<_C2BlockPoolData> GetGraphicBlockPoolData(
+ const C2Block2D& block);
+
+ /**
+ * Create a linear block from the received native handle.
+ *
+ * \param handle native handle to a linear block
+ *
+ * \return shared pointer to the linear block. nullptr if there was not enough memory to
+ * create this block.
+ */
+ static
+ std::shared_ptr<C2LinearBlock> CreateLinearBlock(
+ const C2Handle *handle);
+
+ /**
+ * Create a graphic block from the received native handle.
+ *
+ * \param handle native handle to a graphic block
+ *
+ * \return shared pointer to the graphic block. nullptr if there was not enough memory to
+ * create this block.
+ */
+ static
+ std::shared_ptr<C2GraphicBlock> CreateGraphicBlock(
+ const C2Handle *handle);
+
+ /**
+ * Create a linear block from the received bufferpool data.
+ *
+ * \param data bufferpool data to a linear block
+ *
+ * \return shared pointer to the linear block. nullptr if there was not enough memory to
+ * create this block.
+ */
+ static
+ std::shared_ptr<C2LinearBlock> CreateLinearBlock(
+ const C2Handle *handle,
+ const std::shared_ptr<android::hardware::media::bufferpool::BufferPoolData> &data);
+
+ /**
+ * Create a graphic block from the received bufferpool data.
+ *
+ * \param data bufferpool data to a graphic block
+ *
+ * \return shared pointer to the graphic block. nullptr if there was not enough memory to
+ * create this block.
+ */
+ static
+ std::shared_ptr<C2GraphicBlock> CreateGraphicBlock(
+ const C2Handle *handle,
+ const std::shared_ptr<android::hardware::media::bufferpool::BufferPoolData> &data);
+
+ /**
+ * Get bufferpool data from the blockpool data.
+ *
+ * \param poolData blockpool data
+ * \param bufferPoolData pointer to bufferpool data where the bufferpool
+ * data is stored.
+ *
+ * \return {\code true} when there is valid bufferpool data, {\code false} otherwise.
+ */
+ static
+ bool GetBufferPoolData(
+ const std::shared_ptr<const _C2BlockPoolData> &poolData,
+ std::shared_ptr<android::hardware::media::bufferpool::BufferPoolData> *bufferPoolData);
+
+ /*
+ * Life Cycle Management of BufferQueue-Based Blocks
+ * =================================================
+ *
+ * A block that is created by a bufferqueue-based blockpool requires some
+ * special treatment when it is destroyed. In particular, if the block
+ * corresponds to a held (dequeued/attached) GraphicBuffer in a slot of a
+ * bufferqueue, its destruction should trigger a call to
+ * IGraphicBufferProducer::cancelBuffer(). On the other hand, if the
+ * GraphicBuffer is not held, i.e., if it has been queued or detached,
+ * cancelBuffer() should not be called upon the destruction of the block.
+ *
+ * _C2BlockPoolData created by a bufferqueue-based blockpool includes two
+ * main pieces of information:
+ * - "held" status: Whether cancelBuffer() should be called upon
+ * destruction of the block.
+ * - bufferqueue assignment: The quadruple (igbp, generation, bqId,
+ * bqSlot), where igbp is the IGraphicBufferProducer instance of the
+ * bufferqueue, generation is the latest generation number, of the
+ * bufferqueue, bqId is the globally unique id of the bufferqueue, and
+ * bqSlot is the slot in the bufferqueue.
+ *
+ * igbp is the instance of IGraphicBufferProducer on which cancelBuffer()
+ * will be called if "held" status is true when the block is destroyed.
+ * (bqSlot is an input to cancelBuffer().) However, only generation, bqId
+ * and bqSlot are retained when a block is transferred from one process to
+ * another. It is the responsibility of both the sending and receiving
+ * processes to maintain consistency of "held" status and igbp. Below are
+ * functions provided for this purpose:
+ *
+ * - GetBufferQueueData(): Returns generation, bqId and bqSlot.
+ * - HoldBlockFromBufferQueue(): Sets "held" status to true.
+ * - YieldBlockToBufferQueue(): Sets "held" status to false.
+ * - AssignBlockToBufferQueue(): Sets the bufferqueue assignment and
+ * "held" status.
+ *
+ * All these functions operate on _C2BlockPoolData, which can be obtained by
+ * calling GetGraphicBlockPoolData().
+ *
+ * HoldBlockFromBufferQueue() will mark the block as held, while
+ * YieldBlockToBufferQueue() will do the opposite. These two functions do
+ * not modify the bufferqueue assignment, so it is not wrong to call
+ * HoldBlockFromBufferQueue() after YieldBlockToBufferQueue() if it can be
+ * guaranteed that the block is not destroyed during the period between the
+ * two calls.
+ *
+ * AssingBlockToBufferQueue() has a "held" status as an optional argument.
+ * The default value is true.
+ *
+ * Maintaining Consistency with IGraphicBufferProducer Operations
+ * ==============================================================
+ *
+ * dequeueBuffer()
+ * - This function is called by the blockpool. It should not be called
+ * manually. The blockpool will automatically generate the correct
+ * information for _C2BlockPoolData, with "held" status set to true.
+ *
+ * queueBuffer()
+ * - After queueBuffer() is called, YieldBlockToBufferQueue() should be
+ * called.
+ *
+ * attachBuffer()
+ * - After attachBuffer() is called, AssignBlockToBufferQueue() should be
+ * called with "held" status set to true.
+ *
+ * detachBuffer()
+ * - After detachBuffer() is called, HoldBlockFromBufferQueue() should be
+ * called.
+ */
+
+ /**
+ * Get bufferqueue data from the blockpool data.
+ *
+ * Calling this function with \p generation set to nullptr will return
+ * whether the block comes from a bufferqueue-based blockpool, but will not
+ * fill in the values for \p generation, \p bqId or \p bqSlot.
+ *
+ * \param[in] poolData blockpool data.
+ * \param[out] generation Generation number attached to the buffer.
+ * \param[out] bqId Id of the bufferqueue owning the buffer (block).
+ * \param[out] bqSlot Slot number of the buffer.
+ *
+ * \return \c true when there is valid bufferqueue data;
+ * \c false otherwise.
+ */
+ static
+ bool GetBufferQueueData(
+ const std::shared_ptr<_C2BlockPoolData>& poolData,
+ uint32_t* generation = nullptr,
+ uint64_t* bqId = nullptr,
+ int32_t* bqSlot = nullptr);
+
+ /**
+ * Set bufferqueue assignment and "held" status to a block created by a
+ * bufferqueue-based blockpool.
+ *
+ * \param poolData blockpool data associated to the block.
+ * \param igbp \c IGraphicBufferProducer instance from the designated
+ * bufferqueue.
+ * \param generation Generation number that the buffer belongs to.
+ * \param bqId Id of the bufferqueue that will own the buffer (block).
+ * \param bqSlot Slot number of the buffer.
+ * \param held Whether the block is held. This "held" status can be
+ * changed later by calling YieldBlockToBufferQueue() or
+ * HoldBlockFromBufferQueue().
+ *
+ * \return \c true if \p poolData is valid bufferqueue data;
+ * \c false otherwise.
+ *
+ * Note: \p generation should match the latest generation number set on the
+ * bufferqueue, and \p bqId should match the unique id for the bufferqueue
+ * (obtainable by calling igbp->getUniqueId()).
+ */
+ static
+ bool AssignBlockToBufferQueue(
+ const std::shared_ptr<_C2BlockPoolData>& poolData,
+ const ::android::sp<::android::hardware::graphics::bufferqueue::
+ V1_0::IGraphicBufferProducer>& igbp,
+ uint32_t generation,
+ uint64_t bqId,
+ int32_t bqSlot,
+ bool held = true);
+
+ /**
+ * Hold a block from the designated bufferqueue. This causes the destruction
+ * of the block to trigger a call to cancelBuffer().
+ *
+ * This function assumes that \p poolData comes from a bufferqueue-based
+ * block. It does not check if that is the case.
+ *
+ * \param poolData blockpool data associated to the block.
+ * \param igbp \c IGraphicBufferProducer instance to be assigned to the
+ * block. This is not needed when the block is local.
+ *
+ * \return The previous held status.
+ */
+ static
+ bool HoldBlockFromBufferQueue(
+ const std::shared_ptr<_C2BlockPoolData>& poolData,
+ const ::android::sp<::android::hardware::graphics::bufferqueue::
+ V1_0::IGraphicBufferProducer>& igbp = nullptr);
+
+ /**
+ * Yield a block to the designated bufferqueue. This causes the destruction
+ * of the block not to trigger a call to cancelBuffer();
+ *
+ * This function assumes that \p poolData comes from a bufferqueue-based
+ * block. It does not check if that is the case.
+ *
+ * \param poolData blockpool data associated to the block.
+ *
+ * \return The previous held status.
+ */
+ static
+ bool YieldBlockToBufferQueue(
+ const std::shared_ptr<_C2BlockPoolData>& poolData);
+
+};
+
+#endif // ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+
diff --git a/media/codec2/vndk/internal/C2ParamInternal.h b/media/codec2/vndk/internal/C2ParamInternal.h
new file mode 100644
index 0000000..24a8f27
--- /dev/null
+++ b/media/codec2/vndk/internal/C2ParamInternal.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_STAGEFRIGHT_C2PARAM_INTERNAL_H_
+#define ANDROID_STAGEFRIGHT_C2PARAM_INTERNAL_H_
+
+#include <C2Param.h>
+
+struct C2_HIDE _C2ParamInspector {
+ inline static uint32_t GetOffset(const C2FieldDescriptor &fd) {
+ return fd._mFieldId._mOffset;
+ }
+
+ inline static void SetOffset(C2FieldDescriptor &fd, uint32_t offset) {
+ fd._mFieldId._mOffset = offset;
+ }
+
+ inline static uint32_t GetEndOffset(const C2FieldDescriptor &fd, uint32_t paramSize = 0) {
+ uint32_t endOffset = fd._mFieldId._mOffset + fd._mExtent * fd._mFieldId._mSize;
+ /// for flex parameters return paramSize if given
+ return fd._mExtent ? endOffset : std::max(endOffset, paramSize);
+ }
+
+ inline static uint32_t GetSize(const C2FieldDescriptor &fd) {
+ return fd._mFieldId._mSize;
+ }
+
+ inline static uint32_t GetIndex(const C2ParamField &pf) {
+ return pf._mIndex;
+ }
+
+ inline static uint32_t GetOffset(const C2ParamField &pf) {
+ return pf._mFieldId._mOffset;
+ }
+
+ inline static uint32_t GetSize(const C2ParamField &pf) {
+ return pf._mFieldId._mSize;
+ }
+
+ inline static uint32_t GetOffset(const _C2FieldId &f) {
+ return f._mOffset;
+ }
+
+ inline static uint32_t GetSize(const _C2FieldId &f) {
+ return f._mSize;
+ }
+
+ inline static _C2FieldId GetField(const C2FieldDescriptor &fd) {
+ return fd._mFieldId;
+ }
+
+ inline static uint32_t GetAttrib(const C2ParamDescriptor &pd) {
+ return pd._mAttrib;
+ }
+
+ inline static _C2FieldId GetField(const C2ParamField &pf) {
+ return pf._mFieldId;
+ }
+
+ inline static
+ C2ParamField CreateParamField(C2Param::Index index, uint32_t offset, uint32_t size) {
+ return C2ParamField(index, offset, size);
+ }
+
+ inline static
+ C2ParamField CreateParamField(C2Param::Index index, _C2FieldId field) {
+ return C2ParamField(index, field._mOffset, field._mSize);
+ }
+
+ inline static
+ void TrimParam(C2Param *param, uint32_t newSize) {
+ if (param && *param && param->size() > newSize && newSize >= sizeof(C2Param)) {
+ param->_mSize = newSize;
+ }
+ }
+
+ inline static void AddNamedValues(
+ C2FieldDescriptor &fd, C2FieldDescriptor::NamedValuesType &&namedValues) {
+ fd._mNamedValues = std::move(namedValues);
+ }
+
+ inline static
+ C2StructDescriptor CreateStructDescriptor(C2Param::CoreIndex index,
+ std::vector<C2FieldDescriptor> &&fields) {
+ return C2StructDescriptor(index, std::move(fields));
+ }
+
+ inline static
+ C2FieldDescriptor OffsetFieldDescriptor(const C2FieldDescriptor &fd, size_t offset) {
+ return C2FieldDescriptor(fd, offset);
+ }
+
+ // expose attributes
+ typedef C2ParamDescriptor::attrib_t attrib_t;
+};
+
+#endif // ANDROID_STAGEFRIGHT_C2PARAM_INTERNAL_H_
+
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
new file mode 100644
index 0000000..7a26035
--- /dev/null
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -0,0 +1,494 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2BqBuffer"
+#include <utils/Log.h>
+
+#include <gui/BufferQueueDefs.h>
+#include <list>
+#include <map>
+#include <mutex>
+
+#include <C2AllocatorGralloc.h>
+#include <C2BqBufferPriv.h>
+#include <C2BlockInternal.h>
+
+using ::android::AnwBuffer;
+using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS;
+using ::android::C2AllocatorGralloc;
+using ::android::C2AndroidMemoryUsage;
+using ::android::Fence;
+using ::android::GraphicBuffer;
+using ::android::HGraphicBufferProducer;
+using ::android::IGraphicBufferProducer;
+using ::android::hidl_handle;
+using ::android::sp;
+using ::android::status_t;
+using ::android::wp;
+
+using ::android::hardware::Return;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+struct C2BufferQueueBlockPoolData : public _C2BlockPoolData {
+
+ bool held;
+ bool local;
+ uint32_t generation;
+ uint64_t bqId;
+ int32_t bqSlot;
+ sp<HGraphicBufferProducer> igbp;
+ std::shared_ptr<C2BufferQueueBlockPool::Impl> localPool;
+
+ virtual type_t getType() const override {
+ return TYPE_BUFFERQUEUE;
+ }
+
+ // Create a remote BlockPoolData.
+ C2BufferQueueBlockPoolData(
+ uint32_t generation, uint64_t bqId, int32_t bqSlot,
+ const sp<HGraphicBufferProducer>& producer = nullptr);
+
+ // Create a local BlockPoolData.
+ C2BufferQueueBlockPoolData(
+ uint32_t generation, uint64_t bqId, int32_t bqSlot,
+ const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool);
+
+ virtual ~C2BufferQueueBlockPoolData() override;
+
+};
+
+bool _C2BlockFactory::GetBufferQueueData(
+ const std::shared_ptr<_C2BlockPoolData>& data,
+ uint32_t* generation, uint64_t* bqId, int32_t* bqSlot) {
+ if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERQUEUE) {
+ if (generation) {
+ const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
+ std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
+ *generation = poolData->generation;
+ if (bqId) {
+ *bqId = poolData->bqId;
+ }
+ if (bqSlot) {
+ *bqSlot = poolData->bqSlot;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool _C2BlockFactory::AssignBlockToBufferQueue(
+ const std::shared_ptr<_C2BlockPoolData>& data,
+ const sp<HGraphicBufferProducer>& igbp,
+ uint32_t generation,
+ uint64_t bqId,
+ int32_t bqSlot,
+ bool held) {
+ if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERQUEUE) {
+ const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
+ std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
+ poolData->igbp = igbp;
+ poolData->generation = generation;
+ poolData->bqId = bqId;
+ poolData->bqSlot = bqSlot;
+ poolData->held = held;
+ return true;
+ }
+ return false;
+}
+
+bool _C2BlockFactory::HoldBlockFromBufferQueue(
+ const std::shared_ptr<_C2BlockPoolData>& data,
+ const sp<HGraphicBufferProducer>& igbp) {
+ const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
+ std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
+ if (!poolData->local) {
+ poolData->igbp = igbp;
+ }
+ if (poolData->held) {
+ poolData->held = true;
+ return false;
+ }
+ poolData->held = true;
+ return true;
+}
+
+bool _C2BlockFactory::YieldBlockToBufferQueue(
+ const std::shared_ptr<_C2BlockPoolData>& data) {
+ const std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
+ std::static_pointer_cast<C2BufferQueueBlockPoolData>(data);
+ if (!poolData->held) {
+ poolData->held = false;
+ return false;
+ }
+ poolData->held = false;
+ return true;
+}
+
+std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
+ const C2Handle *handle) {
+ // TODO: get proper allocator? and mutex?
+ static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
+
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ if (C2AllocatorGralloc::isValid(handle)) {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint64_t usage;
+ uint32_t stride;
+ uint32_t generation;
+ uint64_t bqId;
+ uint32_t bqSlot;
+ android::_UnwrapNativeCodec2GrallocMetadata(
+ handle, &width, &height, &format, &usage, &stride, &generation, &bqId, &bqSlot);
+ c2_status_t err = sAllocator->priorGraphicAllocation(handle, &alloc);
+ if (err == C2_OK) {
+ std::shared_ptr<C2GraphicBlock> block;
+ if (bqId || bqSlot) {
+ // BQBBP
+ std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
+ std::make_shared<C2BufferQueueBlockPoolData>(generation,
+ bqId,
+ (int32_t)bqSlot);
+ block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
+ } else {
+ block = _C2BlockFactory::CreateGraphicBlock(alloc);
+ }
+ return block;
+ }
+ }
+ return nullptr;
+}
+
+class C2BufferQueueBlockPool::Impl
+ : public std::enable_shared_from_this<C2BufferQueueBlockPool::Impl> {
+private:
+ c2_status_t fetchFromIgbp_l(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+ // We have an IGBP now.
+ sp<Fence> fence = new Fence();
+ C2AndroidMemoryUsage androidUsage = usage;
+ status_t status;
+ PixelFormat pixelFormat = static_cast<PixelFormat>(format);
+ int slot;
+ ALOGV("tries to dequeue buffer");
+ Return<void> transStatus = mProducer->dequeueBuffer(
+ width, height, pixelFormat, androidUsage.asGrallocUsage(), true,
+ [&status, &slot, &fence](
+ int32_t tStatus, int32_t tSlot, hidl_handle const& tFence,
+ HGraphicBufferProducer::FrameEventHistoryDelta const& tTs) {
+ status = tStatus;
+ slot = tSlot;
+ if (!android::conversion::convertTo(fence.get(), tFence) &&
+ status == android::NO_ERROR) {
+ status = android::BAD_VALUE;
+ }
+ (void) tTs;
+ });
+ // dequeueBuffer returns flag.
+ if (!transStatus.isOk() || status < android::OK) {
+ ALOGD("cannot dequeue buffer %d", status);
+ if (transStatus.isOk() && status == android::INVALID_OPERATION) {
+ // Too many buffer dequeued. retrying after some time is required.
+ return C2_TIMED_OUT;
+ } else {
+ return C2_BAD_VALUE;
+ }
+ }
+ ALOGV("dequeued a buffer successfully");
+ native_handle_t* nh = nullptr;
+ hidl_handle fenceHandle;
+ if (fence) {
+ android::conversion::wrapAs(&fenceHandle, &nh, *fence);
+ }
+ if (fence) {
+ static constexpr int kFenceWaitTimeMs = 10;
+
+ status_t status = fence->wait(kFenceWaitTimeMs);
+ if (status == -ETIME) {
+ // fence is not signalled yet.
+ (void)mProducer->cancelBuffer(slot, fenceHandle).isOk();
+ return C2_TIMED_OUT;
+ }
+ if (status != android::NO_ERROR) {
+ ALOGD("buffer fence wait error %d", status);
+ (void)mProducer->cancelBuffer(slot, fenceHandle).isOk();
+ return C2_BAD_VALUE;
+ } else if (mRenderCallback) {
+ nsecs_t signalTime = fence->getSignalTime();
+ if (signalTime >= 0 && signalTime < INT64_MAX) {
+ mRenderCallback(mProducerId, slot, signalTime);
+ } else {
+ ALOGV("got fence signal time of %lld", (long long)signalTime);
+ }
+ }
+ }
+
+ sp<GraphicBuffer> &slotBuffer = mBuffers[slot];
+ if (status & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION || !slotBuffer) {
+ if (!slotBuffer) {
+ slotBuffer = new GraphicBuffer();
+ }
+ // N.B. This assumes requestBuffer# returns an existing allocation
+ // instead of a new allocation.
+ Return<void> transStatus = mProducer->requestBuffer(
+ slot,
+ [&status, &slotBuffer](int32_t tStatus, AnwBuffer const& tBuffer){
+ status = tStatus;
+ if (!android::conversion::convertTo(slotBuffer.get(), tBuffer) &&
+ status == android::NO_ERROR) {
+ status = android::BAD_VALUE;
+ }
+ });
+
+ if (!transStatus.isOk()) {
+ return C2_BAD_VALUE;
+ } else if (status != android::NO_ERROR) {
+ slotBuffer.clear();
+ (void)mProducer->cancelBuffer(slot, fenceHandle).isOk();
+ return C2_BAD_VALUE;
+ }
+ }
+ if (slotBuffer) {
+ native_handle_t *grallocHandle = native_handle_clone(slotBuffer->handle);
+
+ if (grallocHandle) {
+ ALOGV("buffer wraps %llu %d", (unsigned long long)mProducerId, slot);
+ C2Handle *c2Handle = android::WrapNativeCodec2GrallocHandle(
+ grallocHandle,
+ slotBuffer->width,
+ slotBuffer->height,
+ slotBuffer->format,
+ slotBuffer->usage,
+ slotBuffer->stride,
+ slotBuffer->getGenerationNumber(),
+ mProducerId, slot);
+ if (c2Handle) {
+ // Moved everything to c2Handle.
+ native_handle_delete(grallocHandle);
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc);
+ if (err != C2_OK) {
+ return err;
+ }
+ std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
+ std::make_shared<C2BufferQueueBlockPoolData>(
+ slotBuffer->getGenerationNumber(),
+ mProducerId, slot, shared_from_this());
+ *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
+ return C2_OK;
+ }
+ native_handle_close(grallocHandle);
+ native_handle_delete(grallocHandle);
+ }
+ // Block was not created. call requestBuffer# again next time.
+ slotBuffer.clear();
+ (void)mProducer->cancelBuffer(slot, fenceHandle).isOk();
+ }
+ return C2_BAD_VALUE;
+ }
+
+public:
+ Impl(const std::shared_ptr<C2Allocator> &allocator)
+ : mInit(C2_OK), mProducerId(0), mAllocator(allocator) {
+ }
+
+ ~Impl() {
+ bool noInit = false;
+ for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
+ if (!noInit && mProducer) {
+ Return<int32_t> transResult =
+ mProducer->detachBuffer(static_cast<int32_t>(i));
+ noInit = !transResult.isOk() ||
+ static_cast<int32_t>(transResult) == android::NO_INIT;
+ }
+ mBuffers[i].clear();
+ }
+ }
+
+ c2_status_t fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+ block->reset();
+ if (mInit != C2_OK) {
+ return mInit;
+ }
+
+ static int kMaxIgbpRetry = 20; // TODO: small number can cause crash in releasing.
+ static int kMaxIgbpRetryDelayUs = 10000;
+
+ int curTry = 0;
+
+ while (curTry++ < kMaxIgbpRetry) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ // TODO: return C2_NO_INIT
+ if (mProducerId == 0) {
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ c2_status_t err = mAllocator->newGraphicAllocation(
+ width, height, format, usage, &alloc);
+ if (err != C2_OK) {
+ return err;
+ }
+ std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
+ std::make_shared<C2BufferQueueBlockPoolData>(
+ 0, (uint64_t)0, ~0, shared_from_this());
+ // TODO: config?
+ *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
+ ALOGV("allocated a buffer successfully");
+
+ return C2_OK;
+ }
+ c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block);
+ if (status == C2_TIMED_OUT) {
+ lock.unlock();
+ ::usleep(kMaxIgbpRetryDelayUs);
+ continue;
+ }
+ return status;
+ }
+ return C2_TIMED_OUT;
+ }
+
+ void setRenderCallback(const OnRenderCallback &renderCallback) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mRenderCallback = renderCallback;
+ }
+
+ void configureProducer(const sp<HGraphicBufferProducer> &producer) {
+ int32_t status = android::OK;
+ uint64_t producerId = 0;
+ if (producer) {
+ Return<void> transStatus = producer->getUniqueId(
+ [&status, &producerId](int32_t tStatus, int64_t tProducerId) {
+ status = tStatus;
+ producerId = tProducerId;
+ });
+ if (!transStatus.isOk()) {
+ ALOGD("configureProducer -- failed to connect to the producer");
+ return;
+ }
+ }
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ bool noInit = false;
+ for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
+ if (!noInit && mProducer) {
+ Return<int32_t> transResult =
+ mProducer->detachBuffer(static_cast<int32_t>(i));
+ noInit = !transResult.isOk() ||
+ static_cast<int32_t>(transResult) == android::NO_INIT;
+ }
+ mBuffers[i].clear();
+ }
+ if (producer && status == android::OK) {
+ mProducer = producer;
+ mProducerId = producerId;
+ } else {
+ mProducer = nullptr;
+ mProducerId = 0;
+ }
+ }
+ }
+
+private:
+ friend struct C2BufferQueueBlockPoolData;
+
+ void cancel(uint64_t igbp_id, int32_t igbp_slot) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (igbp_id == mProducerId && mProducer) {
+ (void)mProducer->cancelBuffer(igbp_slot, nullptr).isOk();
+ }
+ }
+
+ c2_status_t mInit;
+ uint64_t mProducerId;
+ OnRenderCallback mRenderCallback;
+
+ const std::shared_ptr<C2Allocator> mAllocator;
+
+ std::mutex mMutex;
+ sp<HGraphicBufferProducer> mProducer;
+
+ sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS];
+};
+
+C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
+ uint32_t generation, uint64_t bqId, int32_t bqSlot,
+ const sp<HGraphicBufferProducer>& producer) :
+ held(producer && bqId != 0), local(false),
+ generation(generation), bqId(bqId), bqSlot(bqSlot),
+ igbp(producer),
+ localPool() {
+}
+
+C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
+ uint32_t generation, uint64_t bqId, int32_t bqSlot,
+ const std::shared_ptr<C2BufferQueueBlockPool::Impl>& pool) :
+ held(true), local(true),
+ generation(generation), bqId(bqId), bqSlot(bqSlot),
+ igbp(pool ? pool->mProducer : nullptr),
+ localPool(pool) {
+}
+
+C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() {
+ if (!held || bqId == 0) {
+ return;
+ }
+ if (local && localPool) {
+ localPool->cancel(bqId, bqSlot);
+ } else if (igbp) {
+ igbp->cancelBuffer(bqSlot, nullptr);
+ }
+}
+
+C2BufferQueueBlockPool::C2BufferQueueBlockPool(
+ const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
+ : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
+
+C2BufferQueueBlockPool::~C2BufferQueueBlockPool() {}
+
+c2_status_t C2BufferQueueBlockPool::fetchGraphicBlock(
+ uint32_t width,
+ uint32_t height,
+ uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+ if (mImpl) {
+ return mImpl->fetchGraphicBlock(width, height, format, usage, block);
+ }
+ return C2_CORRUPTED;
+}
+
+void C2BufferQueueBlockPool::configureProducer(const sp<HGraphicBufferProducer> &producer) {
+ if (mImpl) {
+ mImpl->configureProducer(producer);
+ }
+}
+
+void C2BufferQueueBlockPool::setRenderCallback(const OnRenderCallback &renderCallback) {
+ if (mImpl) {
+ mImpl->setRenderCallback(renderCallback);
+ }
+}
diff --git a/media/codec2/vndk/util/C2Debug.cpp b/media/codec2/vndk/util/C2Debug.cpp
new file mode 100644
index 0000000..b4aa719
--- /dev/null
+++ b/media/codec2/vndk/util/C2Debug.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <C2ParamInternal.h>
+#include <util/C2Debug-interface.h>
+#include <util/C2Debug-param.h>
+#include <util/C2InterfaceUtils.h>
+
+#include <iostream>
+
+#include <android-base/stringprintf.h>
+
+using android::base::StringPrintf;
+
+/* -------------------------------- asString -------------------------------- */
+
+const char *asString(c2_status_t i, const char *def) {
+ switch (i) {
+ case C2_OK: return "OK";
+ case C2_BAD_VALUE: return "BAD_VALUE";
+ case C2_BAD_INDEX: return "BAD_INDEX";
+ case C2_CANNOT_DO: return "CANNOT_DO";
+ case C2_DUPLICATE: return "DUPLICATE";
+ case C2_NOT_FOUND: return "NOT_FOUND";
+ case C2_BAD_STATE: return "BAD_STATE";
+ case C2_BLOCKING: return "BLOCKING";
+ case C2_CANCELED: return "CANCELED";
+ case C2_NO_MEMORY: return "NO_MEMORY";
+ case C2_REFUSED: return "REFUSED";
+ case C2_TIMED_OUT: return "TIMED_OUT";
+ case C2_OMITTED: return "OMITTED";
+ case C2_CORRUPTED: return "CORRUPTED";
+ case C2_NO_INIT: return "NO_INIT";
+ default: return def;
+ }
+}
+
+const char *asString(C2FieldDescriptor::type_t i, const char *def) {
+ switch (i) {
+ case C2FieldDescriptor::BLOB: return "u8";
+ case C2FieldDescriptor::CNTR32: return "c32";
+ case C2FieldDescriptor::CNTR64: return "c64";
+ case C2FieldDescriptor::FLOAT: return "fp";
+ case C2FieldDescriptor::INT32: return "i32";
+ case C2FieldDescriptor::INT64: return "i64";
+ case C2FieldDescriptor::STRING: return "chr";
+ case C2FieldDescriptor::UINT32: return "u32";
+ case C2FieldDescriptor::UINT64: return "u64";
+ default: return (i & C2FieldDescriptor::STRUCT_FLAG) ? "struct" : def;
+ }
+}
+
+/* ------------------------------ C2ParamField ------------------------------ */
+
+static std::string attribParamCoreIndex(const C2Param::CoreIndex &i) {
+ return StringPrintf("%c%c%03x",
+ i.isFlexible() ? 'F' : '-',
+ i.isVendor() ? 'V' : '-',
+ i.coreIndex());
+}
+
+static std::string attribParamIndex(
+ const C2Param::Type &i, bool addStream, unsigned streamId) {
+ std::string v = StringPrintf("%c%c",
+ i.forInput() ? 'I' : i.forOutput() ? 'O' : '-',
+ i.forStream() ? 'S' : i.forPort() ? 'P' : 'G');
+ if (addStream) {
+ if (i.forStream()) {
+ v += StringPrintf("%02d", streamId);
+ } else {
+ v += "--";
+ }
+ }
+
+ return v
+ + StringPrintf("%c ",
+ i.kind() == C2Param::STRUCT ? 'S' :
+ i.kind() == C2Param::INFO ? 'i' :
+ i.kind() == C2Param::TUNING ? 't' :
+ i.kind() == C2Param::SETTING ? 's' :
+ i.kind() == C2Param::NONE ? '-' : '?')
+ + attribParamCoreIndex(i);
+}
+
+std::ostream& operator<<(std::ostream& os, const C2Param::CoreIndex &i) {
+ return os << "Param::CoreIndex(" << attribParamCoreIndex(i) << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, const C2Param::Type &i) {
+ return os << StringPrintf("Param::Type(%08x: ", i.type())
+ << attribParamIndex(i, false, 0) << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, const C2Param::Index &i) {
+ return os << StringPrintf("Param::Index(%08x: ", (uint32_t)i)
+ << attribParamIndex(i, true, i.stream()) << ")";
+}
+
+static std::string attribFieldId(const _C2FieldId &i) {
+ return StringPrintf("Field(@%02x+%02x)",
+ _C2ParamInspector::GetOffset(i),
+ _C2ParamInspector::GetSize(i));
+}
+
+
+std::ostream& operator<<(std::ostream& os, const _C2FieldId &i) {
+ return os << "<" << attribFieldId(i) << ">";
+}
+
+
+std::ostream& operator<<(std::ostream& os, const C2FieldDescriptor &i) {
+ os << attribFieldId(_C2ParamInspector::GetField(i)) << " ";
+ if (i.namedValues().size()) {
+ os << "enum ";
+ }
+ return os << asString(i.type()) << " " << i.name()
+ << StringPrintf("[%zu]", i.extent());
+}
+
+
+std::ostream& operator<<(std::ostream& os, const C2ParamField &i) {
+ os << "<" << C2Param::Index(_C2ParamInspector::GetIndex(i))
+ << StringPrintf("::Field(@%02x+%02x)>",
+ _C2ParamInspector::GetOffset(i),
+ _C2ParamInspector::GetSize(i));
+ return os;
+}
+
+
+/* -------------------------- _C2FieldValueHelper -------------------------- */
+
+std::ostream& _C2FieldValueHelper<char>::put(std::ostream &os, const C2Value::Primitive &p) {
+ if (isprint(p.i32)) {
+ return os << StringPrintf("'%c'", p.i32);
+ } else {
+ return os << StringPrintf("'\\x%02x'", (uint32_t)p.i32);
+ }
+}
+
+std::ostream& _C2FieldValueHelper<uint8_t>::put(std::ostream &os, const C2Value::Primitive &p) {
+ return os << StringPrintf("0x%02x", p.u32);
+}
+
+/* ---------------------- C2FieldSupportedValuesHelper ---------------------- */
+
+template<typename T>
+std::ostream& operator<<(std::ostream &os, const c2_cntr_t<T> &v) {
+ return os << "ctr(" << v.peeku() << ")";
+}
+
+template<typename T>
+std::ostream& operator<<(std::ostream& os, const C2SupportedRange<T> &i) {
+ os << "Range(";
+ _C2FieldValueHelper<T>::put(os, i.min());
+ os << "..";
+ _C2FieldValueHelper<T>::put(os, i.max());
+ os << " *= " << i.num() << " /= " << i.denom() << " += " << i.step() << ")";
+ return os;
+}
+template std::ostream& operator<<(std::ostream& os, const C2SupportedRange<char> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedRange<uint8_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedRange<int32_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedRange<uint32_t> &i);
+//template std::ostream& operator<<(std::ostream& os, const C2SupportedRange<c2_cntr32_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedRange<int64_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedRange<uint64_t> &i);
+//template std::ostream& operator<<(std::ostream& os, const C2SupportedRange<c2_cntr64_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedRange<float> &i);
+
+template<typename T>
+std::ostream& operator<<(std::ostream& os, const C2SupportedFlags<T> &i) {
+ os << "Flags[";
+ if (!i.isEmpty()) {
+ os << "min=";
+ _C2FieldValueHelper<T>::put(os, i.min());
+ }
+ bool comma = false;
+ for (const T &v : i.flags()) {
+ if (comma) {
+ os << ", ";
+ }
+ _C2FieldValueHelper<T>::put(os, v);
+ comma = true;
+ }
+ os << "]";
+ return os;
+}
+template std::ostream& operator<<(std::ostream& os, const C2SupportedFlags<char> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedFlags<uint8_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedFlags<int32_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedFlags<uint32_t> &i);
+//template std::ostream& operator<<(std::ostream& os, const C2SupportedFlags<c2_cntr32_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedFlags<int64_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedFlags<uint64_t> &i);
+//template std::ostream& operator<<(std::ostream& os, const C2SupportedFlags<c2_cntr64_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedFlags<float> &i);
+
+template<typename T>
+std::ostream& operator<<(std::ostream& os, const C2SupportedValueSet<T> &i) {
+ os << "Values[";
+ bool comma = false;
+ for (const T &v : i.values()) {
+ if (comma) {
+ os << ", ";
+ }
+ _C2FieldValueHelper<T>::put(os, v);
+ comma = true;
+ }
+ os << "]";
+ return os;
+}
+template std::ostream& operator<<(std::ostream& os, const C2SupportedValueSet<char> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedValueSet<uint8_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedValueSet<int32_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedValueSet<uint32_t> &i);
+//template std::ostream& operator<<(std::ostream& os, const C2SupportedValueSet<c2_cntr32_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedValueSet<int64_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedValueSet<uint64_t> &i);
+//template std::ostream& operator<<(std::ostream& os, const C2SupportedValueSet<c2_cntr64_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2SupportedValueSet<float> &i);
+
+template<typename T>
+struct C2FieldSupportedValuesHelper<T>::Impl {
+ Impl(const C2FieldSupportedValues &values);
+
+private:
+ typedef typename _C2FieldValueHelper<T>::ValueType ValueType;
+ C2FieldSupportedValues::type_t _mType;
+ C2SupportedRange<ValueType> _mRange;
+ C2SupportedValueSet<ValueType> _mValues;
+ C2SupportedFlags<ValueType> _mFlags;
+
+public:
+// friend std::ostream& operator<< <T>(std::ostream& os, const C2FieldSupportedValuesHelper<T>::Impl &i);
+// friend std::ostream& operator<<(std::ostream& os, const Impl &i);
+ std::ostream& streamOut(std::ostream& os) const;
+};
+
+template<typename T>
+std::ostream& C2FieldSupportedValuesHelper<T>::Impl::streamOut(std::ostream& os) const {
+ if (_mType == C2FieldSupportedValues::RANGE) {
+ os << _mRange;
+ } else if (_mType == C2FieldSupportedValues::VALUES) {
+ os << _mValues;
+ } else if (_mType == C2FieldSupportedValues::FLAGS) {
+ os << _mFlags;
+ } else {
+ os << "Unknown FSV type: " << (uint32_t)_mType;
+ }
+ return os;
+}
+
+template<typename T>
+std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<T> &i) {
+ return i._mImpl->streamOut(os);
+}
+template std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<char> &i);
+template std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<uint8_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<int32_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<uint32_t> &i);
+//template std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<c2_cntr32_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<int64_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<uint64_t> &i);
+//template std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<c2_cntr64_t> &i);
+template std::ostream& operator<<(std::ostream& os, const C2FieldSupportedValuesHelper<float> &i);
+
diff --git a/media/codec2/vndk/util/C2InterfaceHelper.cpp b/media/codec2/vndk/util/C2InterfaceHelper.cpp
new file mode 100644
index 0000000..e447fbe
--- /dev/null
+++ b/media/codec2/vndk/util/C2InterfaceHelper.cpp
@@ -0,0 +1,841 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <C2Debug.h>
+#include <C2ParamInternal.h>
+#include <util/C2InterfaceHelper.h>
+
+#include <android-base/stringprintf.h>
+
+using ::android::base::StringPrintf;
+
+/* --------------------------------- ReflectorHelper --------------------------------- */
+
+void C2ReflectorHelper::addStructDescriptors(
+ std::vector<C2StructDescriptor> &structs, _Tuple<> *) {
+ std::lock_guard<std::mutex> lock(_mMutex);
+ for (C2StructDescriptor &strukt : structs) {
+ // TODO: check if structure descriptions conflict with existing ones
+ addStructDescriptor(std::move(strukt));
+ }
+}
+
+std::unique_ptr<C2StructDescriptor>
+C2ReflectorHelper::describe(C2Param::CoreIndex paramIndex) const {
+ std::lock_guard<std::mutex> lock(_mMutex);
+ auto it = _mStructs.find(paramIndex);
+ if (it == _mStructs.end()) {
+ return nullptr;
+ } else {
+ return std::make_unique<C2StructDescriptor>(it->second);
+ }
+};
+
+void C2ReflectorHelper::addStructDescriptor(C2StructDescriptor &&strukt) {
+ if (_mStructs.find(strukt.coreIndex()) != _mStructs.end()) {
+ // already added
+ // TODO: validate that descriptor matches stored descriptor
+ }
+ // validate that all struct fields are known to this reflector
+ for (const C2FieldDescriptor &fd : strukt) {
+ if (fd.type() & C2FieldDescriptor::STRUCT_FLAG) {
+ C2Param::CoreIndex coreIndex = fd.type() &~ C2FieldDescriptor::STRUCT_FLAG;
+ if (_mStructs.find(coreIndex) == _mStructs.end()) {
+ C2_LOG(INFO) << "missing struct descriptor #" << coreIndex << " for field "
+ << fd.name() << " of struct #" << strukt.coreIndex();
+ }
+ }
+ }
+ _mStructs.emplace(strukt.coreIndex(), strukt);
+}
+
+
+/* ---------------------------- ParamHelper ---------------------------- */
+
+class C2InterfaceHelper::ParamHelper::Impl {
+public:
+ Impl(ParamRef param, C2StringLiteral name, C2StructDescriptor &&strukt)
+ : mParam(param), mName(name), _mStruct(strukt) { }
+
+ Impl(Impl&&) = default;
+
+ void addDownDependency(C2Param::Index index) {
+ mDownDependencies.push_back(index);
+ }
+
+ C2InterfaceHelper::ParamHelper::attrib_t& attrib() {
+ return mAttrib;
+ }
+
+ void build() {
+ // move dependencies into descriptor
+ mDescriptor = std::make_shared<C2ParamDescriptor>(
+ index(), (C2ParamDescriptor::attrib_t)mAttrib,
+ std::move(mName), std::move(mDependencies));
+ }
+
+ void createFieldsAndSupportedValues(const std::shared_ptr<C2ParamReflector> &reflector) {
+ for (const C2FieldUtils::Info &f :
+ C2FieldUtils::enumerateFields(*mDefaultValue, reflector)) {
+ if (!f.isArithmetic()) {
+ continue;
+ }
+ std::unique_ptr<C2FieldSupportedValues> fsvPointer;
+
+ // create a breakable structure
+ do {
+ C2FieldSupportedValues fsv;
+ switch (f.type()) {
+ case C2FieldDescriptor::INT32: fsv = C2SupportedRange<int32_t>::Any(); break;
+ case C2FieldDescriptor::UINT32: fsv = C2SupportedRange<uint32_t>::Any(); break;
+ case C2FieldDescriptor::INT64: fsv = C2SupportedRange<int64_t>::Any(); break;
+ case C2FieldDescriptor::UINT64: fsv = C2SupportedRange<uint64_t>::Any(); break;
+ case C2FieldDescriptor::FLOAT: fsv = C2SupportedRange<float>::Any(); break;
+ case C2FieldDescriptor::BLOB: fsv = C2SupportedRange<uint8_t>::Any(); break;
+ case C2FieldDescriptor::STRING: fsv = C2SupportedRange<char>::Any(); break;
+ default:
+ continue; // break out of do {} while
+ }
+ fsvPointer = std::make_unique<C2FieldSupportedValues>(fsv);
+ } while (false);
+
+ mFields.emplace_hint(
+ mFields.end(),
+ _C2FieldId(f.offset(), f.size()),
+ std::make_shared<FieldHelper>(
+ mParam, _C2FieldId(f.offset(), f.size()), std::move(fsvPointer)));
+ }
+ }
+
+ /**
+ * Finds a field descriptor.
+ */
+ std::shared_ptr<FieldHelper> findField(size_t baseOffs, size_t baseSize) const {
+ auto it = mFields.find(_C2FieldId(baseOffs, baseSize));
+ if (it == mFields.end()) {
+ return nullptr;
+ }
+ return it->second;
+ }
+
+ const std::vector<ParamRef> getDependenciesAsRefs() const {
+ return mDependenciesAsRefs;
+ }
+
+ std::shared_ptr<const C2ParamDescriptor> getDescriptor() const {
+ return mDescriptor;
+ }
+
+ const std::vector<C2Param::Index> getDownDependencies() const {
+ return mDownDependencies;
+ }
+
+ C2Param::Index index() const {
+ if (!mDefaultValue) {
+ fprintf(stderr, "%s missing default value\n", mName.c_str());
+ }
+ return mDefaultValue->index();
+ }
+
+ C2String name() const {
+ return mName;
+ }
+
+ const ParamRef ref() const {
+ return mParam;
+ }
+
+ C2StructDescriptor retrieveStructDescriptor() {
+ return std::move(_mStruct);
+ }
+
+ void setDefaultValue(std::shared_ptr<C2Param> default_) {
+ mDefaultValue = default_;
+ }
+
+ void setDependencies(std::vector<C2Param::Index> indices, std::vector<ParamRef> refs) {
+ mDependencies = indices;
+ mDependenciesAsRefs = refs;
+ }
+
+ void setFields(std::vector<C2ParamFieldValues> &&fields) {
+ // do not allow adding fields multiple times, or to const values
+ if (!mFields.empty()) {
+ C2_LOG(FATAL) << "Trying to add fields to param " << mName << " multiple times";
+ } else if (mAttrib & attrib_t::IS_CONST) {
+ C2_LOG(FATAL) << "Trying to add fields to const param " << mName;
+ }
+
+ for (C2ParamFieldValues &pfv : fields) {
+ mFields.emplace_hint(
+ mFields.end(),
+ // _C2FieldId constructor
+ _C2ParamInspector::GetField(pfv.paramOrField),
+ // Field constructor
+ std::make_shared<FieldHelper>(mParam,
+ _C2ParamInspector::GetField(pfv.paramOrField),
+ std::move(pfv.values)));
+ }
+ }
+
+ void setGetter(std::function<std::shared_ptr<C2Param>(bool)> getter) {
+ mGetter = getter;
+ }
+
+ void setSetter(std::function<C2R(const C2Param *, bool, bool *, Factory &)> setter) {
+ mSetter = setter;
+ }
+
+ c2_status_t trySet(
+ const C2Param *value, bool mayBlock, bool *changed, Factory &f,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+ C2R result = mSetter(value, mayBlock, changed, f);
+ return result.retrieveFailures(failures);
+ }
+
+ c2_status_t validate(const std::shared_ptr<C2ParamReflector> &reflector) {
+ if (!mSetter && mFields.empty()) {
+ C2_LOG(WARNING) << "Param " << mName << " has no setter, making it const";
+ // dependencies are empty in this case
+ mAttrib |= attrib_t::IS_CONST;
+ } else if (!mSetter) {
+ C2_LOG(FATAL) << "Param " << mName << " has no setter";
+ }
+
+ if (mAttrib & attrib_t::IS_CONST) {
+ createFieldsAndSupportedValues(reflector);
+ } else {
+ // TODO: update default based on setter and verify that FSV covers the values
+ }
+
+ if (mFields.empty()) {
+ C2_LOG(FATAL) << "Param " << mName << " has no fields";
+ }
+
+ return C2_OK;
+ }
+
+ std::shared_ptr<C2Param> value() {
+ return mParam.get();
+ }
+
+ std::shared_ptr<const C2Param> value() const {
+ return mParam.get();
+ }
+
+private:
+ typedef _C2ParamInspector::attrib_t attrib_t;
+ ParamRef mParam;
+ C2String mName;
+ C2StructDescriptor _mStruct;
+ std::shared_ptr<C2Param> mDefaultValue;
+ attrib_t mAttrib;
+ std::function<C2R(const C2Param *, bool, bool *, Factory &)> mSetter;
+ std::function<std::shared_ptr<C2Param>(bool)> mGetter;
+ std::vector<C2Param::Index> mDependencies;
+ std::vector<ParamRef> mDependenciesAsRefs;
+ std::vector<C2Param::Index> mDownDependencies; // TODO: this does not work for stream dependencies
+ std::map<_C2FieldId, std::shared_ptr<FieldHelper>> mFields;
+ std::shared_ptr<C2ParamDescriptor> mDescriptor;
+};
+
+C2InterfaceHelper::ParamHelper::ParamHelper(
+ ParamRef param, C2StringLiteral name, C2StructDescriptor &&strukt)
+ : mImpl(std::make_unique<C2InterfaceHelper::ParamHelper::Impl>(
+ param, name, std::move(strukt))) { }
+
+C2InterfaceHelper::ParamHelper::ParamHelper(C2InterfaceHelper::ParamHelper &&) = default;
+
+C2InterfaceHelper::ParamHelper::~ParamHelper() = default;
+
+void C2InterfaceHelper::ParamHelper::addDownDependency(C2Param::Index index) {
+ return mImpl->addDownDependency(index);
+}
+
+C2InterfaceHelper::ParamHelper::attrib_t& C2InterfaceHelper::ParamHelper::attrib() {
+ return mImpl->attrib();
+}
+
+std::shared_ptr<C2InterfaceHelper::ParamHelper> C2InterfaceHelper::ParamHelper::build() {
+ mImpl->build();
+ return std::make_shared<C2InterfaceHelper::ParamHelper>(std::move(*this));
+}
+
+std::shared_ptr<C2InterfaceHelper::FieldHelper>
+C2InterfaceHelper::ParamHelper::findField(size_t baseOffs, size_t baseSize) const {
+ return mImpl->findField(baseOffs, baseSize);
+}
+
+const std::vector<C2InterfaceHelper::ParamRef>
+C2InterfaceHelper::ParamHelper::getDependenciesAsRefs() const {
+ return mImpl->getDependenciesAsRefs();
+}
+
+std::shared_ptr<const C2ParamDescriptor>
+C2InterfaceHelper::ParamHelper::getDescriptor() const {
+ return mImpl->getDescriptor();
+}
+
+const std::vector<C2Param::Index> C2InterfaceHelper::ParamHelper::getDownDependencies() const {
+ return mImpl->getDownDependencies();
+}
+
+C2Param::Index C2InterfaceHelper::ParamHelper::index() const {
+ return mImpl->index();
+}
+
+C2String C2InterfaceHelper::ParamHelper::name() const {
+ return mImpl->name();
+}
+
+const C2InterfaceHelper::ParamRef C2InterfaceHelper::ParamHelper::ref() const {
+ return mImpl->ref();
+}
+
+C2StructDescriptor C2InterfaceHelper::ParamHelper::retrieveStructDescriptor() {
+ return mImpl->retrieveStructDescriptor();
+}
+
+void C2InterfaceHelper::ParamHelper::setDefaultValue(std::shared_ptr<C2Param> default_) {
+ mImpl->setDefaultValue(default_);
+}
+
+void C2InterfaceHelper::ParamHelper::setDependencies(
+ std::vector<C2Param::Index> indices, std::vector<ParamRef> refs) {
+ mImpl->setDependencies(indices, refs);
+}
+
+void C2InterfaceHelper::ParamHelper::setFields(std::vector<C2ParamFieldValues> &&fields) {
+ return mImpl->setFields(std::move(fields));
+}
+
+void C2InterfaceHelper::ParamHelper::setGetter(
+ std::function<std::shared_ptr<C2Param>(bool)> getter) {
+ mImpl->setGetter(getter);
+}
+
+void C2InterfaceHelper::ParamHelper::setSetter(
+ std::function<C2R(const C2Param *, bool, bool *, Factory &)> setter) {
+ mImpl->setSetter(setter);
+}
+
+c2_status_t C2InterfaceHelper::ParamHelper::trySet(
+ const C2Param *value, bool mayBlock, bool *changed, Factory &f,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+ return mImpl->trySet(value, mayBlock, changed, f, failures);
+}
+
+c2_status_t C2InterfaceHelper::ParamHelper::validate(
+ const std::shared_ptr<C2ParamReflector> &reflector) {
+ return mImpl->validate(reflector);
+}
+
+std::shared_ptr<C2Param> C2InterfaceHelper::ParamHelper::value() {
+ return mImpl->value();
+}
+
+std::shared_ptr<const C2Param> C2InterfaceHelper::ParamHelper::value() const {
+ return mImpl->value();
+}
+
+/* ---------------------------- FieldHelper ---------------------------- */
+
+C2ParamField C2InterfaceHelper::FieldHelper::makeParamField(C2Param::Index index) const {
+ return _C2ParamInspector::CreateParamField(index, mFieldId);
+}
+
+C2InterfaceHelper::FieldHelper::FieldHelper(const ParamRef ¶m, const _C2FieldId &field,
+ std::unique_ptr<C2FieldSupportedValues> &&values)
+ : mParam(param),
+ mFieldId(field),
+ mPossible(std::move(values)) {
+ C2_LOG(VERBOSE) << "Creating field helper " << field << " "
+ << C2FieldSupportedValuesHelper<uint32_t>(*mPossible);
+}
+
+void C2InterfaceHelper::FieldHelper::setSupportedValues(
+ std::unique_ptr<C2FieldSupportedValues> &&values) {
+ mSupported = std::move(values);
+}
+
+const C2FieldSupportedValues *C2InterfaceHelper::FieldHelper::getSupportedValues() const {
+ return (mSupported ? mSupported : mPossible).get();
+}
+
+const C2FieldSupportedValues *C2InterfaceHelper::FieldHelper::getPossibleValues() const {
+ return mPossible.get();
+}
+
+
+/* ---------------------------- Field ---------------------------- */
+
+/**
+ * Wrapper around field-supported-values builder that gets stored in the
+ * field helper when the builder goes out of scope.
+ */
+template<typename T>
+struct SupportedValuesBuilder : C2ParamFieldValuesBuilder<T> {
+ SupportedValuesBuilder(
+ C2ParamField &field, std::shared_ptr<C2InterfaceHelper::FieldHelper> helper)
+ : C2ParamFieldValuesBuilder<T>(field), _mHelper(helper), _mField(field) {
+ }
+
+ /**
+ * Save builder values on destruction.
+ */
+ virtual ~SupportedValuesBuilder() override {
+ _mHelper->setSupportedValues(std::move(C2ParamFieldValues(*this).values));
+ }
+
+private:
+ std::shared_ptr<C2InterfaceHelper::FieldHelper> _mHelper;
+ C2ParamField _mField;
+};
+
+
+template<typename T>
+C2ParamFieldValuesBuilder<T> C2InterfaceHelper::Field<T>::shouldBe() const {
+ return C2ParamFieldValuesBuilder<T>(_mField);
+}
+
+template<typename T>
+C2ParamFieldValuesBuilder<T> C2InterfaceHelper::Field<T>::mustBe() {
+ return SupportedValuesBuilder<T>(_mField, _mHelper);
+}
+
+/*
+template<typename T> C2SettingResultsBuilder C2InterfaceHelper::Field<T>::validatePossible(T &value)
+const {
+ /// TODO
+ return C2SettingResultsBuilder::Ok();
+}
+*/
+
+template<typename T>
+C2InterfaceHelper::Field<T>::Field(std::shared_ptr<FieldHelper> helper, C2Param::Index index)
+ : _mHelper(helper), _mField(helper->makeParamField(index)) { }
+
+template struct C2InterfaceHelper::Field<uint8_t>;
+template struct C2InterfaceHelper::Field<char>;
+template struct C2InterfaceHelper::Field<int32_t>;
+template struct C2InterfaceHelper::Field<uint32_t>;
+//template struct C2InterfaceHelper::Field<c2_cntr32_t>;
+template struct C2InterfaceHelper::Field<int64_t>;
+template struct C2InterfaceHelper::Field<uint64_t>;
+//template struct C2InterfaceHelper::Field<c2_cntr64_t>;
+template struct C2InterfaceHelper::Field<float>;
+
+/* --------------------------------- Factory --------------------------------- */
+
+struct C2InterfaceHelper::FactoryImpl : public C2InterfaceHelper::Factory {
+ virtual std::shared_ptr<C2ParamReflector> getReflector() const override {
+ return _mReflector;
+ }
+
+ virtual std::shared_ptr<ParamHelper>
+ getParamHelper(const ParamRef ¶m) const override {
+ return _mParams.find(param)->second;
+ }
+
+public:
+ FactoryImpl(std::shared_ptr<C2ParamReflector> reflector)
+ : _mReflector(reflector) { }
+
+ virtual ~FactoryImpl() = default;
+
+ void addParam(std::shared_ptr<ParamHelper> param) {
+ _mParams.insert({ param->ref(), param });
+ _mIndexToHelper.insert({param->index(), param});
+
+ // add down-dependencies (and validate dependencies as a result)
+ size_t ix = 0;
+ for (const ParamRef &ref : param->getDependenciesAsRefs()) {
+ // dependencies must already be defined
+ if (!_mParams.count(ref)) {
+ C2_LOG(FATAL) << "Parameter " << param->name() << " has a dependency at index "
+ << ix << " that is not yet defined";
+ }
+ _mParams.find(ref)->second->addDownDependency(param->index());
+ ++ix;
+ }
+
+ _mDependencyIndex.emplace(param->index(), _mDependencyIndex.size());
+ }
+
+ std::shared_ptr<ParamHelper> getParam(C2Param::Index ix) const {
+ // TODO: handle streams separately
+ const auto it = _mIndexToHelper.find(ix);
+ if (it == _mIndexToHelper.end()) {
+ return nullptr;
+ }
+ return it->second;
+ }
+
+ /**
+ * TODO: this could return a copy using proper pointer cast.
+ */
+ std::shared_ptr<C2Param> getParamValue(C2Param::Index ix) const {
+ std::shared_ptr<ParamHelper> helper = getParam(ix);
+ return helper ? helper->value() : nullptr;
+ }
+
+ c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
+ for (const auto &it : _mParams) {
+ // TODO: change querySupportedParams signature?
+ params->push_back(
+ std::const_pointer_cast<C2ParamDescriptor>(it.second->getDescriptor()));
+ }
+ // TODO: handle errors
+ return C2_OK;
+ }
+
+ size_t getDependencyIndex(C2Param::Index ix) {
+ // in this version of the helper there is only a single stream so
+ // we can look up directly by index
+ auto it = _mDependencyIndex.find(ix);
+ return it == _mDependencyIndex.end() ? SIZE_MAX : it->second;
+ }
+
+private:
+ std::map<ParamRef, std::shared_ptr<ParamHelper>> _mParams;
+ std::map<C2Param::Index, std::shared_ptr<ParamHelper>> _mIndexToHelper;
+ std::shared_ptr<C2ParamReflector> _mReflector;
+ std::map<C2Param::Index, size_t> _mDependencyIndex;
+};
+
+/* --------------------------------- Helper --------------------------------- */
+
+namespace {
+
+static std::string asString(C2Param *p) {
+ char addr[20];
+ sprintf(addr, "%p:[", p);
+ std::string v = addr;
+ for (size_t i = 0; i < p->size(); ++i) {
+ char d[4];
+ sprintf(d, " %02x", *(((uint8_t *)p) + i));
+ v += d + (i == 0);
+ }
+ return v + "]";
+}
+
+}
+
+C2InterfaceHelper::C2InterfaceHelper(std::shared_ptr<C2ReflectorHelper> reflector)
+ : mReflector(reflector),
+ _mFactory(std::make_shared<FactoryImpl>(reflector)) { }
+
+
+size_t C2InterfaceHelper::GetBaseOffset(const std::shared_ptr<C2ParamReflector> &reflector,
+ C2Param::CoreIndex index, size_t offset) {
+ std::unique_ptr<C2StructDescriptor> param = reflector->describe(index);
+ if (param == nullptr) {
+ return ~(size_t)0; // param structure not described
+ }
+
+ for (const C2FieldDescriptor &field : *param) {
+ size_t fieldOffset = _C2ParamInspector::GetOffset(field);
+ size_t fieldSize = _C2ParamInspector::GetSize(field);
+ size_t fieldExtent = field.extent();
+ if (offset < fieldOffset) {
+ return ~(size_t)0; // not found
+ }
+ if (offset == fieldOffset) {
+ // exact match
+ return offset;
+ }
+ if (field.extent() == 0 || offset < fieldOffset + fieldSize * fieldExtent) {
+ // reduce to first element in case of array
+ offset = fieldOffset + (offset - fieldOffset) % fieldSize;
+ if (field.type() >= C2FieldDescriptor::STRUCT_FLAG) {
+ // this offset is within a field
+ offset = GetBaseOffset(
+ reflector, field.type() & ~C2FieldDescriptor::STRUCT_FLAG,
+ offset - fieldOffset);
+ return ~offset ? fieldOffset + offset : offset;
+ }
+ }
+ }
+ return ~(size_t)0; // not found
+}
+
+void C2InterfaceHelper::addParameter(std::shared_ptr<ParamHelper> param) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mReflector->addStructDescriptor(param->retrieveStructDescriptor());
+ c2_status_t err = param->validate(mReflector);
+ if (err != C2_CORRUPTED) {
+ _mFactory->addParam(param);
+
+ // run setter to ensure correct values
+ bool changed = false;
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ (void)param->trySet(param->value().get(), C2_MAY_BLOCK, &changed, *_mFactory, &failures);
+ }
+}
+
+c2_status_t C2InterfaceHelper::config(
+ const std::vector<C2Param*> ¶ms, c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures, bool updateParams,
+ std::vector<std::shared_ptr<C2Param>> *changes __unused /* TODO */) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ bool paramWasInvalid = false; // TODO is this the same as bad value?
+ bool paramNotFound = false;
+ bool paramBadValue = false;
+ bool paramNoMemory = false;
+ bool paramBlocking = false;
+ bool paramTimedOut = false;
+ bool paramCorrupted = false;
+
+ // dependencies
+ // down dependencies are marked dirty, but params set are not immediately
+ // marked dirty (unless they become down dependency) so that we can
+ // avoid setting them if they did not change
+
+ // TODO: there could be multiple indices for the same dependency index
+ // { depIx, paramIx } may be a suitable key
+ std::map<size_t, std::pair<C2Param::Index, bool>> dependencies;
+
+ // we cannot determine the last valid parameter, so add an extra
+ // loop iteration after the last parameter
+ for (size_t p_ix = 0; p_ix <= params.size(); ++p_ix) {
+ C2Param *p = nullptr;
+ C2Param::Index paramIx = 0u;
+ size_t paramDepIx = SIZE_MAX;
+ bool last = p_ix == params.size();
+ if (!last) {
+ p = params[p_ix];
+ if (!*p) {
+ paramWasInvalid = true;
+ p->invalidate();
+ continue;
+ }
+
+ paramIx = p->index();
+ paramDepIx = getDependencyIndex_l(paramIx);
+ if (paramDepIx == SIZE_MAX) {
+ // unsupported parameter
+ paramNotFound = true;
+ continue;
+ }
+
+ //
+ // first insert - mark not dirty
+ // it may have been marked dirty by a dependency update
+ // this does not overrwrite(!)
+ (void)dependencies.insert({ paramDepIx, { paramIx, false /* dirty */ }});
+ auto it = dependencies.find(paramDepIx);
+ C2_LOG(VERBOSE) << "marking dependency for setting at #" << paramDepIx << ": "
+ << it->second.first << ", update "
+ << (it->second.second ? "always (dirty)" : "only if changed");
+ } else {
+ // process any remaining dependencies
+ if (dependencies.empty()) {
+ continue;
+ }
+ C2_LOG(VERBOSE) << "handling dirty down dependencies after last setting";
+ }
+
+ // process any dirtied down-dependencies until the next param
+ while (dependencies.size() && dependencies.begin()->first <= paramDepIx) {
+ auto min = dependencies.begin();
+ C2Param::Index ix = min->second.first;
+ bool dirty = min->second.second;
+ dependencies.erase(min);
+
+ std::shared_ptr<ParamHelper> param = _mFactory->getParam(ix);
+ C2_LOG(VERBOSE) << "old value " << asString(param->value().get());
+ if (!last) {
+ C2_LOG(VERBOSE) << "new value " << asString(p);
+ }
+ if (!last && !dirty && ix == paramIx && *param->value() == *p) {
+ // no change in value - and dependencies were not updated
+ // no need to update
+ C2_LOG(VERBOSE) << "ignoring setting unchanged param " << ix;
+ continue;
+ }
+
+ // apply setting
+ bool changed = false;
+ C2_LOG(VERBOSE) << "setting param " << ix;
+ std::shared_ptr<C2Param> oldValue = param->value();
+ c2_status_t res = param->trySet(
+ (!last && paramIx == ix) ? p : param->value().get(), mayBlock,
+ &changed, *_mFactory, failures);
+ std::shared_ptr<C2Param> newValue = param->value();
+ C2_CHECK_EQ(oldValue == newValue, *oldValue == *newValue);
+ switch (res) {
+ case C2_OK: break;
+ case C2_BAD_VALUE: paramBadValue = true; break;
+ case C2_NO_MEMORY: paramNoMemory = true; break;
+ case C2_TIMED_OUT: paramTimedOut = true; break;
+ case C2_BLOCKING: paramBlocking = true; break;
+ case C2_CORRUPTED: paramCorrupted = true; break;
+ default: ;// TODO fatal
+ }
+
+ // copy back result for configured values (or invalidate if it does not fit or match)
+ if (updateParams && !last && paramIx == ix) {
+ if (!p->updateFrom(*param->value())) {
+ p->invalidate();
+ }
+ }
+
+ // compare ptrs as params are copy on write
+ if (changed) {
+ C2_LOG(VERBOSE) << "param " << ix << " value changed";
+ // value changed update down-dependencies and mark them dirty
+ for (const C2Param::Index ix : param->getDownDependencies()) {
+ C2_LOG(VERBOSE) << 1;
+ auto insert_res = dependencies.insert(
+ { getDependencyIndex_l(ix), { ix, true /* dirty */ }});
+ if (!insert_res.second) {
+ (*insert_res.first).second.second = true; // mark dirty
+ }
+
+ auto it = dependencies.find(getDependencyIndex_l(ix));
+ C2_CHECK(it->second.second);
+ C2_LOG(VERBOSE) << "marking down dependencies to update at #"
+ << getDependencyIndex_l(ix) << ": " << it->second.first;
+ }
+ }
+ }
+ }
+
+ return (paramCorrupted ? C2_CORRUPTED :
+ paramBlocking ? C2_BLOCKING :
+ paramTimedOut ? C2_TIMED_OUT :
+ paramNoMemory ? C2_NO_MEMORY :
+ (paramBadValue || paramWasInvalid) ? C2_BAD_VALUE :
+ paramNotFound ? C2_BAD_INDEX : C2_OK);
+}
+
+size_t C2InterfaceHelper::getDependencyIndex_l(C2Param::Index ix) const {
+ return _mFactory->getDependencyIndex(ix);
+}
+
+c2_status_t C2InterfaceHelper::query(
+ const std::vector<C2Param*> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ c2_blocking_t mayBlock __unused /* TODO */,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ bool paramWasInvalid = false;
+ bool paramNotFound = false;
+ bool paramDidNotFit = false;
+ bool paramNoMemory = false;
+
+ for (C2Param* const p : stackParams) {
+ if (!*p) {
+ paramWasInvalid = true;
+ p->invalidate();
+ } else {
+ std::shared_ptr<C2Param> value = _mFactory->getParamValue(p->index());
+ if (!value) {
+ paramNotFound = true;
+ p->invalidate();
+ } else if (!p->updateFrom(*value)) {
+ paramDidNotFit = true;
+ p->invalidate();
+ }
+ }
+ }
+
+ for (const C2Param::Index ix : heapParamIndices) {
+ std::shared_ptr<C2Param> value = _mFactory->getParamValue(ix);
+ if (value) {
+ std::unique_ptr<C2Param> p = C2Param::Copy(*value);
+ if (p != nullptr) {
+ heapParams->push_back(std::move(p));
+ } else {
+ paramNoMemory = true;
+ }
+ } else {
+ paramNotFound = true;
+ }
+ }
+
+ return paramNoMemory ? C2_NO_MEMORY :
+ paramNotFound ? C2_BAD_INDEX :
+ // the following errors are not marked in the return value
+ paramDidNotFit ? C2_OK :
+ paramWasInvalid ? C2_OK : C2_OK;
+}
+
+c2_status_t C2InterfaceHelper::querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return _mFactory->querySupportedParams(params);
+}
+
+
+c2_status_t C2InterfaceHelper::querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock __unused) const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ for (C2FieldSupportedValuesQuery &query : fields) {
+ C2_LOG(VERBOSE) << "querying field " << query.field();
+ C2Param::Index ix = _C2ParamInspector::GetIndex(query.field());
+ std::shared_ptr<ParamHelper> param = _mFactory->getParam(ix);
+ if (!param) {
+ C2_LOG(VERBOSE) << "bad param";
+ query.status = C2_BAD_INDEX;
+ continue;
+ }
+ size_t offs = GetBaseOffset(
+ mReflector, ix,
+ _C2ParamInspector::GetOffset(query.field()) - sizeof(C2Param));
+ if (~offs == 0) {
+ C2_LOG(VERBOSE) << "field could not be found";
+ query.status = C2_NOT_FOUND;
+ continue;
+ }
+ offs += sizeof(C2Param);
+ C2_LOG(VERBOSE) << "field resolved to "
+ << StringPrintf("@%02zx+%02x", offs, _C2ParamInspector::GetSize(query.field()));
+ std::shared_ptr<FieldHelper> field =
+ param->findField(offs, _C2ParamInspector::GetSize(query.field()));
+ if (!field) {
+ C2_LOG(VERBOSE) << "bad field";
+ query.status = C2_NOT_FOUND;
+ continue;
+ }
+
+ const C2FieldSupportedValues *values = nullptr;
+ switch (query.type()) {
+ case C2FieldSupportedValuesQuery::CURRENT:
+ values = field->getSupportedValues();
+ break;
+ case C2FieldSupportedValuesQuery::POSSIBLE:
+ values = field->getPossibleValues();
+ break;
+ default:
+ C2_LOG(VERBOSE) << "bad query type: " << query.type();
+ query.status = C2_BAD_VALUE;
+ }
+ if (values) {
+ query.values = *values;
+ query.status = C2_OK;
+ } else {
+ C2_LOG(DEBUG) << "no values published by component";
+ query.status = C2_CORRUPTED;
+ }
+ }
+ return C2_OK;
+}
+
+std::unique_lock<std::mutex> C2InterfaceHelper::lock() const {
+ return std::unique_lock<std::mutex>(mMutex);
+}
diff --git a/media/codec2/vndk/util/C2InterfaceUtils.cpp b/media/codec2/vndk/util/C2InterfaceUtils.cpp
new file mode 100644
index 0000000..61ec911
--- /dev/null
+++ b/media/codec2/vndk/util/C2InterfaceUtils.cpp
@@ -0,0 +1,1292 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#pragma clang diagnostic ignored "-Wunused-variable"
+#pragma clang diagnostic ignored "-Wunused-value"
+
+#define C2_LOG_VERBOSE
+
+#include <C2Debug.h>
+#include <C2Param.h>
+#include <C2ParamDef.h>
+#include <C2ParamInternal.h>
+#include <util/C2InterfaceUtils.h>
+
+#include <cmath>
+#include <limits>
+#include <map>
+#include <type_traits>
+
+#include <android-base/stringprintf.h>
+
+std::ostream& operator<<(std::ostream& os, const _C2FieldId &i);
+
+std::ostream& operator<<(std::ostream& os, const C2ParamField &i);
+
+/* ---------------------------- C2SupportedRange ---------------------------- */
+
+/**
+ * Helper class for supported values range calculations.
+ */
+template<typename T, bool FP=std::is_floating_point<T>::value>
+struct _C2TypedSupportedRangeHelper {
+ /**
+ * type of range size: a - b if a >= b and a and b are of type T
+ */
+ typedef typename std::make_unsigned<T>::type DiffType;
+
+ /**
+ * calculate (high - low) mod step
+ */
+ static DiffType mod(T low, T high, T step) {
+ return DiffType(high - low) % DiffType(step);
+ }
+};
+
+template<typename T>
+struct _C2TypedSupportedRangeHelper<T, true> {
+ typedef T DiffType;
+
+ static DiffType mod(T low, T high, T step) {
+ return fmod(high - low, step);
+ }
+};
+
+template<typename T>
+C2SupportedRange<T>::C2SupportedRange(const C2FieldSupportedValues &values) {
+ if (values.type == C2FieldSupportedValues::RANGE) {
+ _mMin = values.range.min.ref<ValueType>();
+ _mMax = values.range.max.ref<ValueType>();
+ _mStep = values.range.step.ref<ValueType>();
+ _mNum = values.range.num.ref<ValueType>();
+ _mDenom = values.range.denom.ref<ValueType>();
+ } else {
+ _mMin = MAX_VALUE;
+ _mMax = MIN_VALUE;
+ _mStep = MIN_STEP;
+ _mNum = 0;
+ _mDenom = 0;
+ }
+}
+
+template<typename T>
+bool C2SupportedRange<T>::contains(T value) const {
+ // value must fall between min and max
+ if (value < _mMin || value > _mMax) {
+ return false;
+ }
+ // simple ranges contain all values between min and max
+ if (isSimpleRange()) {
+ return true;
+ }
+ // min is always part of the range
+ if (value == _mMin) {
+ return true;
+ }
+ // stepped ranges require (val - min) % step to be zero
+ if (isArithmeticSeries()) {
+ return _C2TypedSupportedRangeHelper<T>::mod(_mMin, value, _mStep) == 0;
+ }
+ // pure geometric series require (val / min) to be integer multiple of (num/denom)
+ if (isGeometricSeries()) {
+ if (value <= 0) {
+ return false;
+ }
+ double log2base = log2(_mNum / _mDenom);
+ double power = llround(log2(value / double(_mMin)) / log2base);
+ // TODO: validate that result falls within precision (other than round)
+ return value == T(_mMin * pow(_mNum / _mDenom, power) + MIN_STEP / 2);
+ }
+ // multiply-accumulate series require validating by walking through the series
+ if (isMacSeries()) {
+ double lastValue = _mMin;
+ double base = _mNum / _mDenom;
+ while (true) {
+ // this cast is safe as _mMin <= lastValue <= _mMax
+ if (T(lastValue + MIN_STEP / 2) == value) {
+ return true;
+ }
+ double nextValue = fma(lastValue, base, _mStep);
+ if (nextValue <= lastValue || nextValue > _mMax) {
+ return false; // series is no longer monotonic or within range
+ }
+ lastValue = nextValue;
+ };
+ }
+ // if we are here, this must be an invalid range
+ return false;
+}
+
+template<typename T>
+C2SupportedRange<T> C2SupportedRange<T>::limitedTo(const C2SupportedRange<T> &limit) const {
+ // TODO - this only works for simple ranges
+ return C2SupportedRange(std::max(_mMin, limit._mMin), std::min(_mMax, limit._mMax),
+ std::max(_mStep, limit._mStep));
+}
+
+template class C2SupportedRange<uint8_t>;
+template class C2SupportedRange<char>;
+template class C2SupportedRange<int32_t>;
+template class C2SupportedRange<uint32_t>;
+//template class C2SupportedRange<c2_cntr32_t>;
+template class C2SupportedRange<int64_t>;
+template class C2SupportedRange<uint64_t>;
+//template class C2SupportedRange<c2_cntr64_t>;
+template class C2SupportedRange<float>;
+
+/* -------------------------- C2SupportedFlags -------------------------- */
+
+/**
+ * Ordered supported flag set for a field of a given type.
+ */
+// float flags are not supported, but define a few methods to support generic supported values code
+template<>
+bool C2SupportedFlags<float>::contains(float value) const {
+ return false;
+}
+
+template<>
+const std::vector<float> C2SupportedFlags<float>::flags() const {
+ return std::vector<float>();
+}
+
+template<>
+C2SupportedFlags<float> C2SupportedFlags<float>::limitedTo(const C2SupportedFlags<float> &limit) const {
+ std::vector<C2Value::Primitive> values;
+ return C2SupportedFlags(std::move(values));
+}
+
+template<>
+float C2SupportedFlags<float>::min() const {
+ return 0;
+}
+
+template<typename T>
+bool C2SupportedFlags<T>::contains(T value) const {
+ // value must contain the minimal mask
+ T minMask = min();
+ if (~value & minMask) {
+ return false;
+ }
+ value &= ~minMask;
+ // otherwise, remove flags from value and see if we arrive at 0
+ for (const C2Value::Primitive &v : _mValues) {
+ if (value == 0) {
+ break;
+ }
+ if ((~value & v.ref<ValueType>()) == 0) {
+ value &= ~v.ref<ValueType>();
+ }
+ }
+ return value == 0;
+}
+
+template<typename T>
+const std::vector<T> C2SupportedFlags<T>::flags() const {
+ std::vector<T> vals(c2_max(_mValues.size(), 1u) - 1);
+ if (!_mValues.empty()) {
+ std::transform(_mValues.cbegin() + 1, _mValues.cend(), vals.begin(),
+ [](const C2Value::Primitive &p)->T {
+ return p.ref<ValueType>();
+ });
+ }
+ return vals;
+}
+
+template<typename T>
+C2SupportedFlags<T> C2SupportedFlags<T>::limitedTo(const C2SupportedFlags<T> &limit) const {
+ std::vector<C2Value::Primitive> values = _mValues; // make a copy
+ T minMask = min() | limit.min();
+ // minimum mask must be covered by both this and other
+ if (limit.contains(minMask) && contains(minMask)) {
+ values[0] = minMask;
+ // keep only flags that are covered by limit
+ std::remove_if(values.begin(), values.end(), [&limit, minMask](const C2Value::Primitive &v) -> bool {
+ T value = v.ref<ValueType>() | minMask;
+ return value == minMask || !limit.contains(value); });
+ // we also need to do it vice versa
+ for (const C2Value::Primitive &v : _mValues) {
+ T value = v.ref<ValueType>() | minMask;
+ if (value != minMask && contains(value)) {
+ values.emplace_back((ValueType)value);
+ }
+ }
+ }
+ return C2SupportedFlags(std::move(values));
+}
+
+template<typename T>
+T C2SupportedFlags<T>::min() const {
+ if (!_mValues.empty()) {
+ return _mValues.front().template ref<ValueType>();
+ } else {
+ return T(0);
+ }
+}
+
+template class C2SupportedFlags<uint8_t>;
+template class C2SupportedFlags<char>;
+template class C2SupportedFlags<int32_t>;
+template class C2SupportedFlags<uint32_t>;
+//template class C2SupportedFlags<c2_cntr32_t>;
+template class C2SupportedFlags<int64_t>;
+template class C2SupportedFlags<uint64_t>;
+//template class C2SupportedFlags<c2_cntr64_t>;
+
+/* -------------------------- C2SupportedValueSet -------------------------- */
+
+/**
+ * Ordered supported value set for a field of a given type.
+ */
+template<typename T>
+bool C2SupportedValueSet<T>::contains(T value) const {
+ return std::find_if(_mValues.cbegin(), _mValues.cend(),
+ [value](const C2Value::Primitive &p) -> bool {
+ return value == p.ref<ValueType>();
+ }) != _mValues.cend();
+}
+
+template<typename T>
+C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedValueSet<T> &limit) const {
+ std::vector<C2Value::Primitive> values = _mValues; // make a copy
+ std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
+ return !limit.contains(v.ref<ValueType>()); });
+ return C2SupportedValueSet(std::move(values));
+}
+
+template<typename T>
+C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedRange<T> &limit) const {
+ std::vector<C2Value::Primitive> values = _mValues; // make a copy
+ std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
+ return !limit.contains(v.ref<ValueType>()); });
+ return C2SupportedValueSet(std::move(values));
+}
+
+template<typename T>
+C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedFlags<T> &limit) const {
+ std::vector<C2Value::Primitive> values = _mValues; // make a copy
+ std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
+ return !limit.contains(v.ref<ValueType>()); });
+ return C2SupportedValueSet(std::move(values));
+}
+
+template<typename T>
+const std::vector<T> C2SupportedValueSet<T>::values() const {
+ std::vector<T> vals(_mValues.size());
+ std::transform(_mValues.cbegin(), _mValues.cend(), vals.begin(), [](const C2Value::Primitive &p) -> T {
+ return p.ref<ValueType>();
+ });
+ return vals;
+}
+
+template class C2SupportedValueSet<uint8_t>;
+template class C2SupportedValueSet<char>;
+template class C2SupportedValueSet<int32_t>;
+template class C2SupportedValueSet<uint32_t>;
+//template class C2SupportedValueSet<c2_cntr32_t>;
+template class C2SupportedValueSet<int64_t>;
+template class C2SupportedValueSet<uint64_t>;
+//template class C2SupportedValueSet<c2_cntr64_t>;
+template class C2SupportedValueSet<float>;
+
+/* ---------------------- C2FieldSupportedValuesHelper ---------------------- */
+
+template<typename T>
+struct C2FieldSupportedValuesHelper<T>::Impl {
+ Impl(const C2FieldSupportedValues &values)
+ : _mType(values.type),
+ _mRange(values),
+ _mValues(values),
+ _mFlags(values) { }
+
+ bool supports(T value) const;
+
+private:
+ typedef typename _C2FieldValueHelper<T>::ValueType ValueType;
+ C2FieldSupportedValues::type_t _mType;
+ C2SupportedRange<ValueType> _mRange;
+ C2SupportedValueSet<ValueType> _mValues;
+ C2SupportedValueSet<ValueType> _mFlags;
+
+// friend std::ostream& operator<< <T>(std::ostream& os, const C2FieldSupportedValuesHelper<T>::Impl &i);
+// friend std::ostream& operator<<(std::ostream& os, const Impl &i);
+ std::ostream& streamOut(std::ostream& os) const;
+};
+
+template<typename T>
+bool C2FieldSupportedValuesHelper<T>::Impl::supports(T value) const {
+ switch (_mType) {
+ case C2FieldSupportedValues::RANGE: return _mRange.contains(value);
+ case C2FieldSupportedValues::VALUES: return _mValues.contains(value);
+ case C2FieldSupportedValues::FLAGS: return _mFlags.contains(value);
+ default: return false;
+ }
+}
+
+template<typename T>
+C2FieldSupportedValuesHelper<T>::C2FieldSupportedValuesHelper(const C2FieldSupportedValues &values)
+ : _mImpl(std::make_unique<C2FieldSupportedValuesHelper<T>::Impl>(values)) { }
+
+template<typename T>
+C2FieldSupportedValuesHelper<T>::~C2FieldSupportedValuesHelper() = default;
+
+template<typename T>
+bool C2FieldSupportedValuesHelper<T>::supports(T value) const {
+ return _mImpl->supports(value);
+}
+
+template class C2FieldSupportedValuesHelper<uint8_t>;
+template class C2FieldSupportedValuesHelper<char>;
+template class C2FieldSupportedValuesHelper<int32_t>;
+template class C2FieldSupportedValuesHelper<uint32_t>;
+//template class C2FieldSupportedValuesHelper<c2_cntr32_t>;
+template class C2FieldSupportedValuesHelper<int64_t>;
+template class C2FieldSupportedValuesHelper<uint64_t>;
+//template class C2FieldSupportedValuesHelper<c2_cntr64_t>;
+template class C2FieldSupportedValuesHelper<float>;
+
+/* ----------------------- C2ParamFieldValuesBuilder ----------------------- */
+
+template<typename T>
+struct C2ParamFieldValuesBuilder<T>::Impl {
+ Impl(const C2ParamField &field)
+ : _mParamField(field),
+ _mType(type_t::RANGE),
+ _mDefined(false),
+ _mRange(C2SupportedRange<T>::Any()),
+ _mValues(C2SupportedValueSet<T>::None()),
+ _mFlags(C2SupportedFlags<T>::None()) { }
+
+ /**
+ * Get C2ParamFieldValues from this builder.
+ */
+ operator C2ParamFieldValues() const {
+ if (!_mDefined) {
+ return C2ParamFieldValues(_mParamField);
+ }
+ switch (_mType) {
+ case type_t::EMPTY:
+ case type_t::VALUES:
+ return C2ParamFieldValues(_mParamField, (C2FieldSupportedValues)_mValues);
+ case type_t::RANGE:
+ return C2ParamFieldValues(_mParamField, (C2FieldSupportedValues)_mRange);
+ case type_t::FLAGS:
+ return C2ParamFieldValues(_mParamField, (C2FieldSupportedValues)_mFlags);
+ default:
+ // TRESPASS
+ // should never get here
+ return C2ParamFieldValues(_mParamField);
+ }
+ }
+
+ /** Define the supported values as the currently supported values of this builder. */
+ void any() {
+ _mDefined = true;
+ }
+
+ /** Restrict (and thus define) the supported values to none. */
+ void none() {
+ _mDefined = true;
+ _mType = type_t::VALUES;
+ _mValues.clear();
+ }
+
+ /** Restrict (and thus define) the supported values to |value| alone. */
+ void equalTo(T value) {
+ return limitTo(C2SupportedValueSet<T>::OneOf({value}));
+ }
+
+ /** Restrict (and thus define) the supported values to a value set. */
+ void limitTo(const C2SupportedValueSet<T> &limit) {
+ if (!_mDefined) {
+ C2_LOG(VERBOSE) << "NA.limitTo(" << C2FieldSupportedValuesHelper<T>(limit) << ")";
+
+ // shortcut for first limit applied
+ _mDefined = true;
+ _mValues = limit;
+ _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES;
+ } else {
+ switch (_mType) {
+ case type_t::EMPTY:
+ case type_t::VALUES:
+ C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mValues) << ").limitTo("
+ << C2FieldSupportedValuesHelper<T>(limit) << ")";
+
+ _mValues = _mValues.limitedTo(limit);
+ _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES;
+ break;
+ case type_t::RANGE:
+ C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mRange) << ").limitTo("
+ << C2FieldSupportedValuesHelper<T>(limit) << ")";
+
+ _mValues = limit.limitedTo(_mRange);
+ _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES;
+ break;
+ case type_t::FLAGS:
+ C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mRange) << ").limitTo("
+ << C2FieldSupportedValuesHelper<T>(limit) << ")";
+
+ _mValues = limit.limitedTo(_mFlags);
+ _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES;
+ break;
+ default:
+ C2_LOG(FATAL); // should not be here
+ }
+ // TODO: support flags
+ }
+ C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mValues);
+ }
+
+ /** Restrict (and thus define) the supported values to a flag set. */
+ void limitTo(const C2SupportedFlags<T> &limit) {
+ if (!_mDefined) {
+ C2_LOG(VERBOSE) << "NA.limitTo(" << C2FieldSupportedValuesHelper<T>(limit) << ")";
+
+ // shortcut for first limit applied
+ _mDefined = true;
+ _mFlags = limit;
+ _mType = _mFlags.isEmpty() ? type_t::EMPTY : type_t::FLAGS;
+ } else {
+ switch (_mType) {
+ case type_t::EMPTY:
+ case type_t::VALUES:
+ C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mValues) << ").limitTo("
+ << C2FieldSupportedValuesHelper<T>(limit) << ")";
+
+ _mValues = _mValues.limitedTo(limit);
+ _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES;
+ C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mValues);
+ break;
+ case type_t::FLAGS:
+ C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mFlags) << ").limitTo("
+ << C2FieldSupportedValuesHelper<T>(limit) << ")";
+
+ _mFlags = _mFlags.limitedTo(limit);
+ _mType = _mFlags.isEmpty() ? type_t::EMPTY : type_t::FLAGS;
+ C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mFlags);
+ break;
+ case type_t::RANGE:
+ C2_LOG(FATAL) << "limiting ranges to flags is not supported";
+ _mType = type_t::EMPTY;
+ break;
+ default:
+ C2_LOG(FATAL); // should not be here
+ }
+ }
+ }
+
+ void limitTo(const C2SupportedRange<T> &limit) {
+ if (!_mDefined) {
+ C2_LOG(VERBOSE) << "NA.limitTo(" << C2FieldSupportedValuesHelper<T>(limit) << ")";
+
+ // shortcut for first limit applied
+ _mDefined = true;
+ _mRange = limit;
+ _mType = _mRange.isEmpty() ? type_t::EMPTY : type_t::RANGE;
+ C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mRange);
+ } else {
+ switch (_mType) {
+ case type_t::EMPTY:
+ case type_t::VALUES:
+ C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mValues) << ").limitTo("
+ << C2FieldSupportedValuesHelper<T>(limit) << ")";
+ _mValues = _mValues.limitedTo(limit);
+ _mType = _mValues.isEmpty() ? type_t::EMPTY : type_t::VALUES;
+ C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mValues);
+ break;
+ case type_t::FLAGS:
+ C2_LOG(FATAL) << "limiting flags to ranges is not supported";
+ _mType = type_t::EMPTY;
+ break;
+ case type_t::RANGE:
+ C2_LOG(VERBOSE) << "(" << C2FieldSupportedValuesHelper<T>(_mRange) << ").limitTo("
+ << C2FieldSupportedValuesHelper<T>(limit) << ")";
+ _mRange = _mRange.limitedTo(limit);
+ C2_DCHECK(_mValues.isEmpty());
+ _mType = _mRange.isEmpty() ? type_t::EMPTY : type_t::RANGE;
+ C2_LOG(VERBOSE) << " = " << _mType << ":" << C2FieldSupportedValuesHelper<T>(_mRange);
+ break;
+ default:
+ C2_LOG(FATAL); // should not be here
+ }
+ }
+ }
+
+private:
+ void instantiate() __unused {
+ (void)_mValues.values(); // instantiate non-const values()
+ }
+
+ void instantiate() const __unused {
+ (void)_mValues.values(); // instantiate const values()
+ }
+
+ typedef C2FieldSupportedValues::type_t type_t;
+
+ C2ParamField _mParamField;
+ type_t _mType;
+ bool _mDefined;
+ C2SupportedRange<T> _mRange;
+ C2SupportedValueSet<T> _mValues;
+ C2SupportedFlags<T> _mFlags;
+
+};
+
+template<typename T>
+C2ParamFieldValuesBuilder<T>::operator C2ParamFieldValues() const {
+ return (C2ParamFieldValues)(*_mImpl.get());
+}
+
+template<typename T>
+C2ParamFieldValuesBuilder<T>::C2ParamFieldValuesBuilder(const C2ParamField &field)
+ : _mImpl(std::make_unique<C2ParamFieldValuesBuilder<T>::Impl>(field)) { }
+
+template<typename T>
+C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::any() {
+ _mImpl->any();
+ return *this;
+}
+
+template<typename T>
+C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::none() {
+ _mImpl->none();
+ return *this;
+}
+
+template<typename T>
+C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::equalTo(T value) {
+ _mImpl->equalTo(value);
+ return *this;
+}
+
+template<typename T>
+C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::limitTo(const C2SupportedValueSet<T> &limit) {
+ _mImpl->limitTo(limit);
+ return *this;
+}
+
+template<typename T>
+C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::limitTo(const C2SupportedFlags<T> &limit) {
+ _mImpl->limitTo(limit);
+ return *this;
+}
+
+template<typename T>
+C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::limitTo(const C2SupportedRange<T> &limit) {
+ _mImpl->limitTo(limit);
+ return *this;
+}
+
+template<typename T>
+C2ParamFieldValuesBuilder<T>::C2ParamFieldValuesBuilder(const C2ParamFieldValuesBuilder<T> &other)
+ : _mImpl(std::make_unique<C2ParamFieldValuesBuilder<T>::Impl>(*other._mImpl.get())) { }
+
+template<typename T>
+C2ParamFieldValuesBuilder<T> &C2ParamFieldValuesBuilder<T>::operator=(
+ const C2ParamFieldValuesBuilder<T> &other) {
+ _mImpl = std::make_unique<C2ParamFieldValuesBuilder<T>::Impl>(*other._mImpl.get());
+ return *this;
+}
+
+template<typename T>
+C2ParamFieldValuesBuilder<T>::~C2ParamFieldValuesBuilder() = default;
+
+template class C2ParamFieldValuesBuilder<uint8_t>;
+template class C2ParamFieldValuesBuilder<char>;
+template class C2ParamFieldValuesBuilder<int32_t>;
+template class C2ParamFieldValuesBuilder<uint32_t>;
+//template class C2ParamFieldValuesBuilder<c2_cntr32_t>;
+template class C2ParamFieldValuesBuilder<int64_t>;
+template class C2ParamFieldValuesBuilder<uint64_t>;
+//template class C2ParamFieldValuesBuilder<c2_cntr64_t>;
+template class C2ParamFieldValuesBuilder<float>;
+
+/* ------------------------- C2SettingResultBuilder ------------------------- */
+
+C2SettingConflictsBuilder::C2SettingConflictsBuilder() : _mConflicts() { }
+
+C2SettingConflictsBuilder::C2SettingConflictsBuilder(C2ParamFieldValues &&conflict) {
+ _mConflicts.emplace_back(std::move(conflict));
+}
+
+C2SettingConflictsBuilder& C2SettingConflictsBuilder::with(C2ParamFieldValues &&conflict) {
+ _mConflicts.emplace_back(std::move(conflict));
+ return *this;
+}
+
+std::vector<C2ParamFieldValues> C2SettingConflictsBuilder::retrieveConflicts() {
+ return std::move(_mConflicts);
+}
+
+/* ------------------------- C2SettingResult/sBuilder ------------------------- */
+
+C2SettingResult C2SettingResultBuilder::ReadOnly(const C2ParamField ¶m) {
+ return C2SettingResult { C2SettingResult::READ_ONLY, { param }, { } };
+}
+
+C2SettingResult C2SettingResultBuilder::BadValue(const C2ParamField ¶mField, bool isInfo) {
+ return { isInfo ? C2SettingResult::INFO_BAD_VALUE : C2SettingResult::BAD_VALUE,
+ { paramField }, { } };
+}
+
+C2SettingResult C2SettingResultBuilder::Conflict(
+ C2ParamFieldValues &¶mFieldValues, C2SettingConflictsBuilder &conflicts, bool isInfo) {
+ C2_CHECK(!conflicts.empty());
+ if (isInfo) {
+ return C2SettingResult {
+ C2SettingResult::INFO_CONFLICT,
+ std::move(paramFieldValues), conflicts.retrieveConflicts()
+ };
+ } else {
+ return C2SettingResult {
+ C2SettingResult::CONFLICT,
+ std::move(paramFieldValues), conflicts.retrieveConflicts()
+ };
+ }
+}
+
+C2SettingResultsBuilder::C2SettingResultsBuilder(C2SettingResult &&result)
+ : _mStatus(C2_BAD_VALUE) {
+ _mResults.emplace_back(new C2SettingResult(std::move(result)));
+}
+
+C2SettingResultsBuilder C2SettingResultsBuilder::plus(C2SettingResultsBuilder&& results) {
+ for (std::unique_ptr<C2SettingResult> &r : results._mResults) {
+ _mResults.emplace_back(std::move(r));
+ }
+ results._mResults.clear();
+ // TODO: mStatus
+ return std::move(*this);
+}
+
+c2_status_t C2SettingResultsBuilder::retrieveFailures(
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+ for (std::unique_ptr<C2SettingResult> &r : _mResults) {
+ failures->emplace_back(std::move(r));
+ }
+ _mResults.clear();
+ return _mStatus;
+}
+
+C2SettingResultsBuilder::C2SettingResultsBuilder(c2_status_t status) : _mStatus(status) {
+ // status must be one of OK, BAD_STATE, TIMED_OUT or CORRUPTED
+ // mainly: BLOCKING, BAD_INDEX, BAD_VALUE and NO_MEMORY requires a setting attempt
+}
+
+#pragma clang diagnostic pop
+
+/* ------------------------- C2FieldUtils ------------------------- */
+
+struct C2_HIDE C2FieldUtils::_Inspector {
+ /// returns the implementation object
+ inline static std::shared_ptr<Info::Impl> GetImpl(const Info &info) {
+ return info._mImpl;
+ }
+};
+
+/* ------------------------- C2FieldUtils::Info ------------------------- */
+
+struct C2_HIDE C2FieldUtils::Info::Impl {
+ C2FieldDescriptor field;
+ std::shared_ptr<Impl> parent;
+ uint32_t index;
+ uint32_t depth;
+ uint32_t baseFieldOffset;
+ uint32_t arrayOffset;
+ uint32_t usedExtent;
+
+ /// creates a copy of this object including copies of its parent chain
+ Impl clone() const;
+
+ /// creates a copy of a shared pointer to an object
+ static std::shared_ptr<Impl> Clone(const std::shared_ptr<Impl> &);
+
+ Impl(const C2FieldDescriptor &field_, std::shared_ptr<Impl> parent_,
+ uint32_t index_, uint32_t depth_, uint32_t baseFieldOffset_,
+ uint32_t arrayOffset_, uint32_t usedExtent_)
+ : field(field_), parent(parent_), index(index_), depth(depth_),
+ baseFieldOffset(baseFieldOffset_), arrayOffset(arrayOffset_), usedExtent(usedExtent_) { }
+};
+
+std::shared_ptr<C2FieldUtils::Info::Impl> C2FieldUtils::Info::Impl::Clone(const std::shared_ptr<Impl> &info) {
+ if (info) {
+ return std::make_shared<Impl>(info->clone());
+ }
+ return nullptr;
+}
+
+C2FieldUtils::Info::Impl C2FieldUtils::Info::Impl::clone() const {
+ Impl res = Impl(*this);
+ res.parent = Clone(res.parent);
+ return res;
+}
+
+C2FieldUtils::Info::Info(std::shared_ptr<Impl> impl)
+ : _mImpl(impl) { }
+
+size_t C2FieldUtils::Info::arrayOffset() const {
+ return _mImpl->arrayOffset;
+}
+
+size_t C2FieldUtils::Info::arraySize() const {
+ return extent() * size();
+}
+
+size_t C2FieldUtils::Info::baseFieldOffset() const {
+ return _mImpl->baseFieldOffset;
+};
+
+size_t C2FieldUtils::Info::depth() const {
+ return _mImpl->depth;
+}
+
+size_t C2FieldUtils::Info::extent() const {
+ return _mImpl->usedExtent;
+}
+
+size_t C2FieldUtils::Info::index() const {
+ return _mImpl->index;
+}
+
+bool C2FieldUtils::Info::isArithmetic() const {
+ switch (_mImpl->field.type()) {
+ case C2FieldDescriptor::BLOB:
+ case C2FieldDescriptor::CNTR32:
+ case C2FieldDescriptor::CNTR64:
+ case C2FieldDescriptor::FLOAT:
+ case C2FieldDescriptor::INT32:
+ case C2FieldDescriptor::INT64:
+ case C2FieldDescriptor::STRING:
+ case C2FieldDescriptor::UINT32:
+ case C2FieldDescriptor::UINT64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool C2FieldUtils::Info::isFlexible() const {
+ return _mImpl->field.extent() == 0;
+}
+
+C2String C2FieldUtils::Info::name() const {
+ return _mImpl->field.name();
+}
+
+const C2FieldUtils::Info::NamedValuesType &C2FieldUtils::Info::namedValues() const {
+ return _mImpl->field.namedValues();
+}
+
+size_t C2FieldUtils::Info::offset() const {
+ return _C2ParamInspector::GetOffset(_mImpl->field);
+}
+
+C2FieldUtils::Info C2FieldUtils::Info::parent() const {
+ return Info(_mImpl->parent);
+};
+
+size_t C2FieldUtils::Info::size() const {
+ return _C2ParamInspector::GetSize(_mImpl->field);
+}
+
+C2FieldUtils::Info::type_t C2FieldUtils::Info::type() const {
+ return _mImpl->field.type();
+}
+
+/* ------------------------- C2FieldUtils::Iterator ------------------------- */
+
+struct C2_HIDE C2FieldUtils::Iterator::Impl : public _C2ParamInspector {
+ Impl() = default;
+
+ virtual ~Impl() = default;
+
+ /// implements object equality
+ virtual bool equals(const std::shared_ptr<Impl> &other) const {
+ return other != nullptr && mHead == other->mHead;
+ };
+
+ /// returns the info pointed to by this iterator
+ virtual value_type get() const {
+ return Info(mHead);
+ }
+
+ /// increments this iterator
+ virtual void increment() {
+ // note: this cannot be abstract as we instantiate this for List::end(). increment to end()
+ // instead.
+ mHead.reset();
+ }
+
+protected:
+ Impl(std::shared_ptr<C2FieldUtils::Info::Impl> head)
+ : mHead(head) { }
+
+ std::shared_ptr<Info::Impl> mHead; ///< current field
+};
+
+C2FieldUtils::Iterator::Iterator(std::shared_ptr<Impl> impl)
+ : mImpl(impl) { }
+
+C2FieldUtils::Iterator::value_type C2FieldUtils::Iterator::operator*() const {
+ return mImpl->get();
+}
+
+C2FieldUtils::Iterator& C2FieldUtils::Iterator::operator++() {
+ mImpl->increment();
+ return *this;
+}
+
+bool C2FieldUtils::Iterator::operator==(const Iterator &other) const {
+ return mImpl->equals(other.mImpl);
+}
+
+/* ------------------------- C2FieldUtils::List ------------------------- */
+
+struct C2_HIDE C2FieldUtils::List::Impl {
+ virtual std::shared_ptr<Iterator::Impl> begin() const = 0;
+
+ /// returns an iterator to the end of the list
+ virtual std::shared_ptr<Iterator::Impl> end() const {
+ return std::make_shared<Iterator::Impl>();
+ }
+
+ virtual ~Impl() = default;
+};
+
+C2FieldUtils::List::List(std::shared_ptr<Impl> impl)
+ : mImpl(impl) { }
+
+C2FieldUtils::Iterator C2FieldUtils::List::begin() const {
+ return C2FieldUtils::Iterator(mImpl->begin());
+}
+
+C2FieldUtils::Iterator C2FieldUtils::List::end() const {
+ return C2FieldUtils::Iterator(mImpl->end());
+}
+
+/* ------------------------- C2FieldUtils::enumerateFields ------------------------- */
+
+namespace {
+
+/**
+ * Iterator base class helper that allows descending into the field hierarchy.
+ */
+struct C2FieldUtilsFieldsIteratorHelper : public C2FieldUtils::Iterator::Impl {
+ virtual ~C2FieldUtilsFieldsIteratorHelper() override = default;
+
+ /// returns the base-field's offset of the parent field (or the param offset if no parent)
+ static inline uint32_t GetParentBaseFieldOffset(
+ const std::shared_ptr<C2FieldUtils::Info::Impl> parent) {
+ return parent == nullptr ? sizeof(C2Param) : parent->baseFieldOffset;
+ }
+
+ /// returns the offset of the parent field (or the param)
+ static inline uint32_t GetParentOffset(const std::shared_ptr<C2FieldUtils::Info::Impl> parent) {
+ return parent == nullptr ? sizeof(C2Param) : GetOffset(parent->field);
+ }
+
+protected:
+ C2FieldUtilsFieldsIteratorHelper(
+ std::shared_ptr<C2ParamReflector> reflector,
+ uint32_t paramSize,
+ std::shared_ptr<C2FieldUtils::Info::Impl> head = nullptr)
+ : C2FieldUtils::Iterator::Impl(head),
+ mParamSize(paramSize),
+ mReflector(reflector) { }
+
+ /// returns a leaf info object at a specific index for a child field
+ std::shared_ptr<C2FieldUtils::Info::Impl> makeLeaf(
+ const C2FieldDescriptor &field, uint32_t index) {
+ uint32_t parentOffset = GetParentOffset(mHead);
+ uint32_t arrayOffset = parentOffset + GetOffset(field);
+ uint32_t usedExtent = field.extent() ? :
+ (std::max(arrayOffset, mParamSize) - arrayOffset) / GetSize(field);
+
+ return std::make_shared<C2FieldUtils::Info::Impl>(
+ OffsetFieldDescriptor(field, parentOffset + index * GetSize(field)),
+ mHead /* parent */, index, mHead == nullptr ? 0 : mHead->depth + 1,
+ GetParentBaseFieldOffset(mHead) + GetOffset(field),
+ arrayOffset, usedExtent);
+ }
+
+ /// returns whether this struct index have been traversed to get to this field
+ bool visited(C2Param::CoreIndex index) const {
+ for (const std::shared_ptr<C2StructDescriptor> &sd : mHistory) {
+ if (sd->coreIndex() == index) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ uint32_t mParamSize;
+ std::shared_ptr<C2ParamReflector> mReflector;
+ std::vector<std::shared_ptr<C2StructDescriptor>> mHistory; // structure types visited
+};
+
+/**
+ * Iterator implementing enumerateFields() that visits each base field.
+ */
+struct C2FieldUtilsFieldsIterator : public C2FieldUtilsFieldsIteratorHelper {
+ /// enumerate base fields of a parameter
+ C2FieldUtilsFieldsIterator(const C2Param ¶m, std::shared_ptr<C2ParamReflector> reflector)
+ : C2FieldUtilsFieldsIteratorHelper(reflector, param.size()) {
+ descendInto(param.coreIndex());
+ }
+
+ /// enumerate base fields of a field
+ C2FieldUtilsFieldsIterator(std::shared_ptr<C2FieldUtilsFieldsIterator> impl)
+ : C2FieldUtilsFieldsIteratorHelper(impl->mReflector, impl->mParamSize, impl->mHead) {
+ mHistory = impl->mHistory;
+ if (mHead->field.type() & C2FieldDescriptor::STRUCT_FLAG) {
+ C2Param::CoreIndex index = { mHead->field.type() &~C2FieldDescriptor::STRUCT_FLAG };
+ if (!visited(index)) {
+ descendInto(index);
+ }
+ }
+ }
+
+ virtual ~C2FieldUtilsFieldsIterator() override = default;
+
+ /// Increments this iterator by visiting each base field.
+ virtual void increment() override {
+ // don't go past end
+ if (mHead == nullptr || _mFields.empty()) {
+ return;
+ }
+
+ // descend into structures
+ if (mHead->field.type() & C2FieldDescriptor::STRUCT_FLAG) {
+ C2Param::CoreIndex index = { mHead->field.type() &~C2FieldDescriptor::STRUCT_FLAG };
+ // do not recurse into the same structs
+ if (!visited(index) && descendInto(index)) {
+ return;
+ }
+ }
+
+ // ascend after the last field in the current struct
+ while (!mHistory.empty() && _mFields.back() == mHistory.back()->end()) {
+ mHead = mHead->parent;
+ mHistory.pop_back();
+ _mFields.pop_back();
+ }
+
+ // done if history is now empty
+ if (_mFields.empty()) {
+ // we could be traversing a sub-tree so clear head
+ mHead.reset();
+ return;
+ }
+
+ // move to the next field in the current struct
+ C2StructDescriptor::field_iterator next = _mFields.back();
+ mHead->field = OffsetFieldDescriptor(*next, GetParentOffset(mHead->parent));
+ mHead->index = 0; // reset index just in case for correctness
+ mHead->baseFieldOffset = GetParentBaseFieldOffset(mHead->parent) + GetOffset(*next);
+ mHead->arrayOffset = GetOffset(mHead->field);
+ mHead->usedExtent = mHead->field.extent() ? :
+ (std::max(mHead->arrayOffset, mParamSize) - mHead->arrayOffset)
+ / GetSize(mHead->field);
+ ++_mFields.back();
+ }
+
+private:
+ /// If the current field is a known, valid (untraversed) structure, it modifies this iterator
+ /// to point to the first field of the structure and returns true. Otherwise, it does not
+ /// modify this iterator and returns false.
+ bool descendInto(C2Param::CoreIndex index) {
+ std::unique_ptr<C2StructDescriptor> descUnique = mReflector->describe(index);
+ // descend into known structs (as long as they have at least one field)
+ if (descUnique && descUnique->begin() != descUnique->end()) {
+ std::shared_ptr<C2StructDescriptor> desc(std::move(descUnique));
+ mHistory.emplace_back(desc);
+ C2StructDescriptor::field_iterator first = desc->begin();
+ mHead = makeLeaf(*first, 0 /* index */);
+ _mFields.emplace_back(++first);
+ return true;
+ }
+ return false;
+ }
+
+ /// next field pointers for each depth.
+ /// note: _mFields may be shorted than mHistory, if iterating at a depth
+ std::vector<C2StructDescriptor::field_iterator> _mFields;
+};
+
+/**
+ * Iterable implementing enumerateFields().
+ */
+struct C2FieldUtilsFieldIterable : public C2FieldUtils::List::Impl {
+ /// returns an iterator to the beginning of the list
+ virtual std::shared_ptr<C2FieldUtils::Iterator::Impl> begin() const override {
+ return std::make_shared<C2FieldUtilsFieldsIterator>(*_mParam, _mReflector);
+ };
+
+ C2FieldUtilsFieldIterable(const C2Param ¶m, std::shared_ptr<C2ParamReflector> reflector)
+ : _mParam(¶m), _mReflector(reflector) { }
+
+private:
+ const C2Param *_mParam;
+ std::shared_ptr<C2ParamReflector> _mReflector;
+};
+
+}
+
+C2FieldUtils::List C2FieldUtils::enumerateFields(
+ const C2Param ¶m, const std::shared_ptr<C2ParamReflector> &reflector) {
+ return C2FieldUtils::List(std::make_shared<C2FieldUtilsFieldIterable>(param, reflector));
+}
+
+/* ------------------------- C2FieldUtils::enumerate siblings ------------------------- */
+
+namespace {
+
+struct C2FieldUtilsCousinsIterator : public C2FieldUtils::Iterator::Impl {
+ C2FieldUtilsCousinsIterator(
+ const std::shared_ptr<C2FieldUtils::Info::Impl> &info, size_t level)
+ // clone info chain as this iterator will change it
+ : C2FieldUtils::Iterator::Impl(C2FieldUtils::Info::Impl::Clone(info)) {
+ if (level == 0) {
+ return;
+ }
+
+ // store parent chain (up to level) for quick access
+ std::shared_ptr<C2FieldUtils::Info::Impl> node = mHead;
+ size_t ix = 0;
+ for (; ix < level && node; ++ix) {
+ node->index = 0;
+ _mPath.emplace_back(node);
+ node = node->parent;
+ }
+ setupPath(ix);
+ }
+
+ virtual ~C2FieldUtilsCousinsIterator() override = default;
+
+ /// Increments this iterator by visiting each index.
+ virtual void increment() override {
+ size_t ix = 0;
+ while (ix < _mPath.size()) {
+ if (++_mPath[ix]->index < _mPath[ix]->usedExtent) {
+ setupPath(ix + 1);
+ return;
+ }
+ _mPath[ix++]->index = 0;
+ }
+ mHead.reset();
+ }
+
+private:
+ /// adjusts field offsets along the path up to the specific level - 1.
+ /// This in-fact has to be done down the path from parent to child as child fields must
+ /// fall within parent fields.
+ void setupPath(size_t level) {
+ C2_CHECK_LE(level, _mPath.size());
+ uint32_t oldArrayOffset = level ? _mPath[level - 1]->arrayOffset : 0 /* unused */;
+ while (level) {
+ --level;
+ C2FieldUtils::Info::Impl &path = *_mPath[level];
+ uint32_t size = GetSize(path.field);
+ uint32_t offset = path.arrayOffset + size * path.index;
+ SetOffset(path.field, offset);
+ if (level) {
+ // reset child's array offset to fall within current index, but hold onto the
+ // original value of the arrayOffset so that we can adjust subsequent children.
+ // This is because the modulo is only defined within the current array.
+ uint32_t childArrayOffset =
+ offset + (_mPath[level - 1]->arrayOffset - oldArrayOffset) % size;
+ oldArrayOffset = _mPath[level - 1]->arrayOffset;
+ _mPath[level - 1]->arrayOffset = childArrayOffset;
+ }
+ }
+ }
+
+ std::vector<std::shared_ptr<C2FieldUtils::Info::Impl>> _mPath;
+};
+
+/**
+ * Iterable implementing enumerateFields().
+ */
+struct C2FieldUtilsCousinsIterable : public C2FieldUtils::List::Impl {
+ /// returns an iterator to the beginning of the list
+ virtual std::shared_ptr<C2FieldUtils::Iterator::Impl> begin() const override {
+ return std::make_shared<C2FieldUtilsCousinsIterator>(_mHead, _mLevel);
+ };
+
+ C2FieldUtilsCousinsIterable(const C2FieldUtils::Info &field, uint32_t level)
+ : _mHead(C2FieldUtils::_Inspector::GetImpl(field)), _mLevel(level) { }
+
+private:
+ std::shared_ptr<C2FieldUtils::Info::Impl> _mHead;
+ size_t _mLevel;
+};
+
+}
+
+C2FieldUtils::List C2FieldUtils::enumerateCousins(const C2FieldUtils::Info &field, uint32_t level) {
+ return C2FieldUtils::List(std::make_shared<C2FieldUtilsCousinsIterable>(field, level));
+}
+
+/* ------------------------- C2FieldUtils::locateField ------------------------- */
+
+namespace {
+
+/**
+ * Iterator implementing locateField().
+ */
+struct C2FieldUtilsFieldLocator : public C2FieldUtilsFieldsIteratorHelper {
+ C2FieldUtilsFieldLocator(
+ C2Param::CoreIndex index, const _C2FieldId &field, uint32_t paramSize,
+ std::shared_ptr<C2ParamReflector> reflector)
+ : C2FieldUtilsFieldsIteratorHelper(reflector, paramSize),
+ _mField(field) {
+ while (descendInto(index)) {
+ if ((mHead->field.type() & C2FieldDescriptor::STRUCT_FLAG) == 0) {
+ break;
+ }
+ index = C2Param::CoreIndex(mHead->field.type() &~ C2FieldDescriptor::STRUCT_FLAG);
+ }
+ }
+
+ void increment() {
+ mHead = _mTail;
+ _mTail = nullptr;
+ }
+
+private:
+ /// If the current field is a known, valid (untraversed) structure, it modifies this iterator
+ /// to point to the field at the beginning/end of the given field of the structure and returns
+ /// true. Otherwise, including if no such field exists in the structure, it does not modify this
+ /// iterator and returns false.
+ bool descendInto(C2Param::CoreIndex index) {
+ // check that the boundaries of the field to be located are still within the same parent
+ // field
+ if (mHead != _mTail) {
+ return false;
+ }
+
+ std::unique_ptr<C2StructDescriptor> descUnique = mReflector->describe(index);
+ // descend into known structs (as long as they have at least one field)
+ if (descUnique && descUnique->begin() != descUnique->end()) {
+ std::shared_ptr<C2StructDescriptor> desc(std::move(descUnique));
+ mHistory.emplace_back(desc);
+
+ uint32_t parentOffset = GetParentOffset(mHead);
+
+ // locate field using a dummy field descriptor
+ C2FieldDescriptor dummy = {
+ C2FieldDescriptor::BLOB, 1 /* extent */, "name",
+ GetOffset(_mField) - parentOffset, GetSize(_mField)
+ };
+
+ // locate first field where offset is greater than dummy offset (which is one past)
+ auto it = std::upper_bound(
+ desc->cbegin(), desc->cend(), dummy,
+ [](const C2FieldDescriptor &a, const C2FieldDescriptor &b) -> bool {
+ return _C2ParamInspector::GetOffset(a) < _C2ParamInspector::GetOffset(b);
+ });
+ if (it == desc->begin()) {
+ // field is prior to first field
+ return false;
+ }
+ --it;
+ const C2FieldDescriptor &field = *it;
+
+ // check that dummy end-offset is within this field
+ uint32_t structSize = std::max(mParamSize, parentOffset) - parentOffset;
+ if (GetEndOffset(dummy) > GetEndOffset(field, structSize)) {
+ return false;
+ }
+
+ uint32_t startIndex = (GetOffset(dummy) - GetOffset(field)) / GetSize(field);
+ uint32_t endIndex =
+ (GetEndOffset(dummy) - GetOffset(field) + GetSize(field) - 1) / GetSize(field);
+ if (endIndex > startIndex) {
+ // Field size could be zero, in which case end index is still on start index.
+ // However, for all other cases, endIndex was rounded up to the next index, so
+ // decrement it.
+ --endIndex;
+ }
+ std::shared_ptr<C2FieldUtils::Info::Impl> startLeaf =
+ makeLeaf(field, startIndex);
+ if (endIndex == startIndex) {
+ _mTail = startLeaf;
+ mHead = startLeaf;
+ } else {
+ _mTail = makeLeaf(field, endIndex);
+ mHead = startLeaf;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ _C2FieldId _mField;
+ std::shared_ptr<C2FieldUtils::Info::Impl> _mTail;
+};
+
+/**
+ * Iterable implementing locateField().
+ */
+struct C2FieldUtilsFieldLocation : public C2FieldUtils::List::Impl {
+ /// returns an iterator to the beginning of the list
+ virtual std::shared_ptr<C2FieldUtils::Iterator::Impl> begin() const override {
+ return std::make_shared<C2FieldUtilsFieldLocator>(
+ _mIndex, _mField, _mParamSize, _mReflector);
+ };
+
+ C2FieldUtilsFieldLocation(
+ const C2ParamField &pf, std::shared_ptr<C2ParamReflector> reflector)
+ : _mIndex(C2Param::CoreIndex(_C2ParamInspector::GetIndex(pf))),
+ _mField(_C2ParamInspector::GetField(pf)),
+ _mParamSize(0),
+ _mReflector(reflector) { }
+
+
+ C2FieldUtilsFieldLocation(
+ const C2Param ¶m, const _C2FieldId &field,
+ std::shared_ptr<C2ParamReflector> reflector)
+ : _mIndex(param.coreIndex()),
+ _mField(field),
+ _mParamSize(param.size()),
+ _mReflector(reflector) { }
+
+private:
+ C2Param::CoreIndex _mIndex;
+ _C2FieldId _mField;
+ uint32_t _mParamSize;
+ std::shared_ptr<C2ParamReflector> _mReflector;
+};
+
+}
+
+std::vector<C2FieldUtils::Info> C2FieldUtils::locateField(
+ const C2ParamField &pf, const std::shared_ptr<C2ParamReflector> &reflector) {
+ C2FieldUtils::List location = { std::make_shared<C2FieldUtilsFieldLocation>(pf, reflector) };
+ return std::vector<Info>(location.begin(), location.end());
+}
+
+std::vector<C2FieldUtils::Info> C2FieldUtils::locateField(
+ const C2Param ¶m, const _C2FieldId &field,
+ const std::shared_ptr<C2ParamReflector> &reflector) {
+ C2FieldUtils::List location = {
+ std::make_shared<C2FieldUtilsFieldLocation>(param, field, reflector)
+ };
+ return std::vector<Info>(location.begin(), location.end());
+}
+
diff --git a/media/codec2/vndk/util/C2ParamUtils.cpp b/media/codec2/vndk/util/C2ParamUtils.cpp
new file mode 100644
index 0000000..80573d8
--- /dev/null
+++ b/media/codec2/vndk/util/C2ParamUtils.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define __C2_GENERATE_GLOBAL_VARS__ // to be able to implement the methods defined
+#include <C2Enum.h>
+#include <util/C2Debug-log.h>
+#include <util/C2ParamUtils.h>
+
+#include <utility>
+#include <vector>
+
+/** \file
+ * Utilities for parameter handling to be used by Codec2 implementations.
+ */
+
+/// \cond INTERNAL
+
+/* ---------------------------- UTILITIES FOR ENUMERATION REFLECTION ---------------------------- */
+
+static size_t countLeadingUnderscores(C2StringLiteral a) {
+ size_t i = 0;
+ while (a[i] == '_') {
+ ++i;
+ }
+ return i;
+}
+
+static size_t countMatching(C2StringLiteral a, const C2String &b) {
+ for (size_t i = 0; i < b.size(); ++i) {
+ if (!a[i] || a[i] != b[i]) {
+ return i;
+ }
+ }
+ return b.size();
+}
+
+// ABCDef => abc-def
+// ABCD2ef => abcd2-ef // 0
+// ABCD2Ef => ancd2-ef // -1
+// AbcDef => abc-def // -1
+// Abc2Def => abc-2def
+// Abc2def => abc-2-def
+// _Yo => _yo
+// _yo => _yo
+// C2_yo => c2-yo
+// C2__yo => c2-yo
+
+//static
+C2String _C2EnumUtils::camelCaseToDashed(C2String name) {
+ enum {
+ kNone = '.',
+ kLower = 'a',
+ kUpper = 'A',
+ kDigit = '1',
+ kDash = '-',
+ kUnderscore = '_',
+ } type = kNone;
+ size_t word_start = 0;
+ for (size_t ix = 0; ix < name.size(); ++ix) {
+ C2_LOG(VERBOSE) << name.substr(0, word_start) << "|"
+ << name.substr(word_start, ix - word_start) << "["
+ << name.substr(ix, 1) << "]" << name.substr(ix + 1)
+ << ": " << (char)type;
+ if (isupper(name[ix])) {
+ if (type == kLower) {
+ name.insert(ix++, 1, '-');
+ word_start = ix;
+ }
+ name[ix] = tolower(name[ix]);
+ type = kUpper;
+ } else if (islower(name[ix])) {
+ if (type == kDigit && ix > 0) {
+ name.insert(ix++, 1, '-');
+ word_start = ix;
+ } else if (type == kUpper && ix > word_start + 1) {
+ name.insert(ix++ - 1, 1, '-');
+ word_start = ix - 1;
+ }
+ type = kLower;
+ } else if (isdigit(name[ix])) {
+ if (type == kLower) {
+ name.insert(ix++, 1, '-');
+ word_start = ix;
+ }
+ type = kDigit;
+ } else if (name[ix] == '_') {
+ if (type == kDash) {
+ name.erase(ix--, 1);
+ } else if (type != kNone && type != kUnderscore) {
+ name[ix] = '-';
+ type = kDash;
+ word_start = ix + 1;
+ } else {
+ type = kUnderscore;
+ word_start = ix + 1;
+ }
+ } else {
+ name.resize(ix);
+ }
+ }
+ C2_LOG(VERBOSE) << "=> " << name;
+ return name;
+}
+
+//static
+std::vector<C2String> _C2EnumUtils::sanitizeEnumValueNames(
+ const std::vector<C2StringLiteral> names,
+ C2StringLiteral _prefix) {
+ std::vector<C2String> sanitizedNames;
+ C2String prefix;
+ size_t extraUnderscores = 0;
+ bool first = true;
+ if (_prefix) {
+ extraUnderscores = countLeadingUnderscores(_prefix);
+ prefix = _prefix + extraUnderscores;
+ first = false;
+ C2_LOG(VERBOSE) << "prefix:" << prefix << ", underscores:" << extraUnderscores;
+ }
+
+ // calculate prefix and minimum leading underscores
+ for (C2StringLiteral s : names) {
+ C2_LOG(VERBOSE) << s;
+ size_t underscores = countLeadingUnderscores(s);
+ if (first) {
+ extraUnderscores = underscores;
+ prefix = s + underscores;
+ first = false;
+ } else {
+ size_t matching = countMatching(
+ s + underscores,
+ prefix);
+ prefix.resize(matching);
+ extraUnderscores = std::min(underscores, extraUnderscores);
+ }
+ C2_LOG(VERBOSE) << "prefix:" << prefix << ", underscores:" << extraUnderscores;
+ if (prefix.size() == 0 && extraUnderscores == 0) {
+ break;
+ }
+ }
+
+ // we swallow the first underscore after upper case prefixes
+ bool upperCasePrefix = true;
+ for (size_t i = 0; i < prefix.size(); ++i) {
+ if (islower(prefix[i])) {
+ upperCasePrefix = false;
+ break;
+ }
+ }
+
+ for (C2StringLiteral s : names) {
+ size_t underscores = countLeadingUnderscores(s);
+ C2String sanitized = C2String(s, underscores - extraUnderscores);
+ sanitized.append(s + prefix.size() + underscores +
+ (upperCasePrefix && s[prefix.size() + underscores] == '_'));
+ sanitizedNames.push_back(camelCaseToDashed(sanitized));
+ }
+
+ for (C2String s : sanitizedNames) {
+ C2_LOG(VERBOSE) << s;
+ }
+
+ return sanitizedNames;
+}
+
+//static
+std::vector<C2String> _C2EnumUtils::parseEnumValuesFromString(C2StringLiteral value) {
+ std::vector<C2String> foundNames;
+ size_t pos = 0, len = strlen(value);
+ do {
+ size_t endPos = strcspn(value + pos, " ,=") + pos;
+ if (endPos > pos) {
+ foundNames.emplace_back(value + pos, endPos - pos);
+ }
+ if (value[endPos] && value[endPos] != ',') {
+ endPos += strcspn(value + endPos, ",");
+ }
+ pos = strspn(value + endPos, " ,") + endPos;
+ } while (pos < len);
+ return foundNames;
+}
+
+/// safe(r) parsing from parameter blob
+//static
+C2Param *C2ParamUtils::ParseFirst(const uint8_t *blob, size_t size) {
+ // _mSize must fit into size, but really C2Param must also to be a valid param
+ if (size < sizeof(C2Param)) {
+ return nullptr;
+ }
+ // _mSize must match length
+ C2Param *param = (C2Param*)blob;
+ if (param->size() > size) {
+ return nullptr;
+ }
+ return param;
+}
+