Move Codec2-related code from hardware/google/av

Test: None
Bug: 112362730
Change-Id: Ie2f8ff431d65c40333f267ab9877d47089adeea4
diff --git a/media/codec2/include/C2.h b/media/codec2/include/C2.h
new file mode 100644
index 0000000..8a55f8d
--- /dev/null
+++ b/media/codec2/include/C2.h
@@ -0,0 +1,552 @@
+/*
+ * 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 C2_H_
+#define C2_H_
+
+#include <errno.h>
+
+#include <string>
+
+/** nanoseconds with arbitrary origin. */
+typedef int64_t c2_nsecs_t;
+
+/** \mainpage Codec2
+ *
+ * Codec2 is a generic frame-based data processing API.
+ *
+ * The media subsystem accesses components via the \ref API.
+ */
+
+/** \ingroup API
+ *
+ * The Codec2 API defines the operation of data processing components and their interaction with
+ * the rest of the system.
+ *
+ * Coding Conventions
+ *
+ * Mitigating Binary Compatibility.
+ *
+ * While full binary compatibility is not a goal of the API (due to our use of STL), we try to
+ * mitigate binary breaks by adhering to the following conventions:
+ *
+ * - at most one vtable with placeholder virtual methods
+ * - all optional/placeholder virtual methods returning a c2_status_t, with C2_OMITTED not requiring
+ *   any update to input/output arguments.
+ * - limiting symbol export of inline methods
+ * - use of pimpl (or shared-pimpl)
+ *
+ * Naming
+ *
+ * - all classes and types prefix with C2
+ * - classes for internal use prefix with _C2
+ * - enum values in global namespace prefix with C2_ all caps
+ * - enum values inside classes have no C2_ prefix as class already has it
+ * - supporting two kinds of enum naming: all-caps and kCamelCase
+ * \todo revisit kCamelCase for param-type
+ *
+ * Aspects
+ *
+ * Aspects define certain common behavior across a group of objects.
+ * - classes whose name matches _C2.*Aspect
+ * - only protected constructors
+ * - no desctructor and copiable
+ * - all methods are inline or static (this is opposite of the interface paradigm where all methods
+ *   are virtual, which would not work due to the at most one vtable rule.)
+ * - only private variables (this prevents subclasses interfering with the aspects.)
+ */
+
+/// \defgroup types Common Types
+/// @{
+
+/**
+ * C2String: basic string implementation
+ */
+typedef std::string C2String;
+
+/**
+ * C2StringLiteral: basic string literal implementation.
+ * \note these are never owned by any object, and can only refer to C string literals.
+ */
+typedef const char *C2StringLiteral;
+
+/**
+ * c2_status_t: status codes used.
+ */
+enum c2_status_t : int32_t {
+/*
+ * Use POSIX errno constants.
+ */
+    C2_OK        = 0,            ///< operation completed successfully
+
+    // bad input
+    C2_BAD_VALUE = EINVAL,       ///< argument has invalid value (user error)
+    C2_BAD_INDEX = ENXIO,        ///< argument uses invalid index (user error)
+    C2_CANNOT_DO = ENOTSUP,      ///< argument/index is valid but not possible
+
+    // bad sequencing of events
+    C2_DUPLICATE = EEXIST,       ///< object already exists
+    C2_NOT_FOUND = ENOENT,       ///< object not found
+    C2_BAD_STATE = EPERM,        ///< operation is not permitted in the current state
+    C2_BLOCKING  = EWOULDBLOCK,  ///< operation would block but blocking is not permitted
+    C2_CANCELED  = EINTR,        ///< operation interrupted/canceled
+
+    // bad environment
+    C2_NO_MEMORY = ENOMEM,       ///< not enough memory to complete operation
+    C2_REFUSED   = EACCES,       ///< missing permission to complete operation
+
+    C2_TIMED_OUT = ETIMEDOUT,    ///< operation did not complete within timeout
+
+    // bad versioning
+    C2_OMITTED   = ENOSYS,       ///< operation is not implemented/supported (optional only)
+
+    // unknown fatal
+    C2_CORRUPTED = EFAULT,       ///< some unexpected error prevented the operation
+    C2_NO_INIT   = ENODEV,       ///< status has not been initialized
+};
+
+/**
+ * Type that describes the desired blocking behavior for variable blocking calls. Blocking in this
+ * API is used in a somewhat modified meaning such that operations that merely update variables
+ * protected by mutexes are still considered "non-blocking" (always used in quotes).
+ */
+enum c2_blocking_t : int32_t {
+    /**
+     * The operation SHALL be "non-blocking". This means that it shall not perform any file
+     * operations, or call/wait on other processes. It may use a protected region as long as the
+     * mutex is never used to protect code that is otherwise "may block".
+     */
+    C2_DONT_BLOCK = false,
+    /**
+     * The operation MAY be temporarily blocking.
+     */
+    C2_MAY_BLOCK = true,
+};
+
+/// @}
+
+/// \defgroup utils Utilities
+/// @{
+
+#define C2_DO_NOT_COPY(type) \
+    type& operator=(const type &) = delete; \
+    type(const type &) = delete; \
+
+#define C2_DEFAULT_MOVE(type) \
+    type& operator=(type &&) = default; \
+    type(type &&) = default; \
+
+#define C2_ALLOW_OVERFLOW __attribute__((no_sanitize("integer")))
+#define C2_CONST    __attribute__((const))
+#define C2_HIDE     __attribute__((visibility("hidden")))
+#define C2_INLINE   inline C2_HIDE
+#define C2_INTERNAL __attribute__((internal_linkage))
+#define C2_PACK     __attribute__((aligned(4)))
+#define C2_PURE     __attribute__((pure))
+
+#define DEFINE_OTHER_COMPARISON_OPERATORS(type) \
+    inline bool operator!=(const type &other) const { return !(*this == other); } \
+    inline bool operator<=(const type &other) const { return (*this == other) || (*this < other); } \
+    inline bool operator>=(const type &other) const { return !(*this < other); } \
+    inline bool operator>(const type &other) const { return !(*this < other) && !(*this == other); }
+
+#define DEFINE_FIELD_BASED_COMPARISON_OPERATORS(type, field) \
+    inline bool operator<(const type &other) const { return field < other.field; } \
+    inline bool operator==(const type &other) const { return field == other.field; } \
+    DEFINE_OTHER_COMPARISON_OPERATORS(type)
+
+#define DEFINE_FIELD_AND_MASK_BASED_COMPARISON_OPERATORS(type, field, mask) \
+    inline bool operator<(const type &other) const { \
+        return (field & mask) < (other.field & (mask)); \
+    } \
+    inline bool operator==(const type &other) const { \
+        return (field & mask) == (other.field & (mask)); \
+    } \
+    DEFINE_OTHER_COMPARISON_OPERATORS(type)
+
+#define DEFINE_ENUM_OPERATORS(etype) \
+    inline constexpr etype operator|(etype a, etype b) { return (etype)(std::underlying_type<etype>::type(a) | std::underlying_type<etype>::type(b)); } \
+    inline constexpr etype &operator|=(etype &a, etype b) { a = (etype)(std::underlying_type<etype>::type(a) | std::underlying_type<etype>::type(b)); return a; } \
+    inline constexpr etype operator&(etype a, etype b) { return (etype)(std::underlying_type<etype>::type(a) & std::underlying_type<etype>::type(b)); } \
+    inline constexpr etype &operator&=(etype &a, etype b) { a = (etype)(std::underlying_type<etype>::type(a) & std::underlying_type<etype>::type(b)); return a; } \
+    inline constexpr etype operator^(etype a, etype b) { return (etype)(std::underlying_type<etype>::type(a) ^ std::underlying_type<etype>::type(b)); } \
+    inline constexpr etype &operator^=(etype &a, etype b) { a = (etype)(std::underlying_type<etype>::type(a) ^ std::underlying_type<etype>::type(b)); return a; } \
+    inline constexpr etype operator~(etype a) { return (etype)(~std::underlying_type<etype>::type(a)); }
+
+template<typename T, typename B>
+class C2_HIDE c2_cntr_t;
+
+/// \cond INTERNAL
+
+/// \defgroup utils_internal
+/// @{
+
+template<typename T>
+struct C2_HIDE _c2_cntr_compat_helper {
+    template<typename U, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
+    C2_ALLOW_OVERFLOW
+    inline static constexpr T get(const U &value) {
+        return T(value);
+    }
+
+    template<typename U, typename E=typename std::enable_if<(sizeof(U) >= sizeof(T))>::type>
+    C2_ALLOW_OVERFLOW
+    inline static constexpr T get(const c2_cntr_t<U, void> &value) {
+        return T(value.mValue);
+    }
+};
+
+/// @}
+
+/// \endcond
+
+/**
+ * Integral counter type.
+ *
+ * This is basically an unsigned integral type that is NEVER checked for overflow/underflow - and
+ * comparison operators are redefined.
+ *
+ * \note Comparison of counter types is not fully transitive, e.g.
+ * it could be that a > b > c but a !> c.
+ * std::less<>, greater<>, less_equal<> and greater_equal<> specializations yield total ordering,
+ * but may not match semantic ordering of the values.
+ *
+ * Technically: counter types represent integer values: A * 2^N + value, where A can be arbitrary.
+ * This makes addition, subtraction, multiplication (as well as bitwise operations) well defined.
+ * However, division is in general not well defined, as the result may depend on A. This is also
+ * true for logical operators and boolean conversion.
+ *
+ * Even though well defined, bitwise operators are not implemented for counter types as they are not
+ * meaningful.
+ */
+template<typename T, typename B=typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type>
+class C2_HIDE c2_cntr_t {
+    using compat = _c2_cntr_compat_helper<T>;
+
+    T mValue;
+    constexpr static T HALF_RANGE = T(~0) ^ (T(~0) >> 1);
+
+    template<typename U>
+    friend struct _c2_cntr_compat_helper;
+public:
+
+    /**
+     * Default constructor. Initialized counter to 0.
+     */
+    inline constexpr c2_cntr_t() : mValue(T(0)) {}
+
+    /**
+     * Construct from a compatible type.
+     */
+    template<typename U>
+    inline constexpr c2_cntr_t(const U &value) : mValue(compat::get(value)) {}
+
+    /**
+     * Peek as underlying signed type.
+     */
+    C2_ALLOW_OVERFLOW
+    inline constexpr typename std::make_signed<T>::type peek() const {
+        return static_cast<typename std::make_signed<T>::type>(mValue);
+    }
+
+    /**
+     * Peek as underlying unsigned type.
+     */
+    inline constexpr T peeku() const {
+        return mValue;
+    }
+
+    /**
+     * Peek as long long - e.g. for printing.
+     */
+    C2_ALLOW_OVERFLOW
+    inline constexpr long long peekll() const {
+        return (long long)mValue;
+    }
+
+    /**
+     * Peek as unsigned long long - e.g. for printing.
+     */
+    C2_ALLOW_OVERFLOW
+    inline constexpr unsigned long long peekull() const {
+        return (unsigned long long)mValue;
+    }
+
+    /**
+     * Convert to a smaller counter type. This is always safe.
+     */
+    template<typename U, typename E=typename std::enable_if<(sizeof(U) < sizeof(T))>::type>
+    inline operator c2_cntr_t<U>() {
+        return c2_cntr_t<U>(mValue);
+    }
+
+    /**
+     * Arithmetic operators
+     */
+
+#define DEFINE_C2_CNTR_BINARY_OP(attrib, op, op_assign) \
+    template<typename U> \
+    attrib inline c2_cntr_t<T>& operator op_assign(const U &value) { \
+        mValue op_assign compat::get(value); \
+        return *this; \
+    } \
+    \
+    template<typename U, typename E=decltype(compat::get(U(0)))> \
+    attrib inline constexpr c2_cntr_t<T> operator op(const U &value) const { \
+        return c2_cntr_t<T>(mValue op compat::get(value)); \
+    } \
+    \
+    template<typename U, typename E=typename std::enable_if<(sizeof(U) < sizeof(T))>::type> \
+    attrib inline constexpr c2_cntr_t<U> operator op(const c2_cntr_t<U> &value) const { \
+        return c2_cntr_t<U>(U(mValue) op value.peeku()); \
+    }
+
+#define DEFINE_C2_CNTR_UNARY_OP(attrib, op) \
+    attrib inline constexpr c2_cntr_t<T> operator op() const { \
+        return c2_cntr_t<T>(op mValue); \
+    }
+
+#define DEFINE_C2_CNTR_CREMENT_OP(attrib, op) \
+    attrib inline c2_cntr_t<T> &operator op() { \
+        op mValue; \
+        return *this; \
+    } \
+    attrib inline c2_cntr_t<T> operator op(int) { \
+        return c2_cntr_t<T, void>(mValue op); \
+    }
+
+    DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, +, +=)
+    DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, -, -=)
+    DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, *, *=)
+
+    DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, -)
+    DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, +)
+
+    DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, ++)
+    DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, --)
+
+    template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
+    C2_ALLOW_OVERFLOW
+    inline constexpr c2_cntr_t<T> operator<<(const U &value) const {
+        return c2_cntr_t<T>(mValue << value);
+    }
+
+    template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
+    C2_ALLOW_OVERFLOW
+    inline c2_cntr_t<T> &operator<<=(const U &value) {
+        mValue <<= value;
+        return *this;
+    }
+
+    /**
+     * Comparison operators
+     */
+    C2_ALLOW_OVERFLOW
+    inline constexpr bool operator<=(const c2_cntr_t<T> &other) const {
+        return T(other.mValue - mValue) < HALF_RANGE;
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr bool operator>=(const c2_cntr_t<T> &other) const {
+        return T(mValue - other.mValue) < HALF_RANGE;
+    }
+
+    inline constexpr bool operator==(const c2_cntr_t<T> &other) const {
+        return mValue == other.mValue;
+    }
+
+    inline constexpr bool operator!=(const c2_cntr_t<T> &other) const {
+        return !(*this == other);
+    }
+
+    inline constexpr bool operator<(const c2_cntr_t<T> &other) const {
+        return *this <= other && *this != other;
+    }
+
+    inline constexpr bool operator>(const c2_cntr_t<T> &other) const {
+        return *this >= other && *this != other;
+    }
+};
+
+template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
+inline constexpr c2_cntr_t<T> operator+(const U &a, const c2_cntr_t<T> &b) {
+    return b + a;
+}
+
+template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
+inline constexpr c2_cntr_t<T> operator-(const U &a, const c2_cntr_t<T> &b) {
+    return c2_cntr_t<T>(a) - b;
+}
+
+template<typename U, typename T, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
+inline constexpr c2_cntr_t<T> operator*(const U &a, const c2_cntr_t<T> &b) {
+    return b * a;
+}
+
+typedef c2_cntr_t<uint32_t> c2_cntr32_t; /** 32-bit counter type */
+typedef c2_cntr_t<uint64_t> c2_cntr64_t; /** 64-bit counter type */
+
+/// \cond INTERNAL
+
+/// \defgroup utils_internal
+/// @{
+
+template<typename... T> struct c2_types;
+
+/** specialization for a single type */
+template<typename T>
+struct c2_types<T> {
+    typedef typename std::decay<T>::type wide_type;
+    typedef wide_type narrow_type;
+    typedef wide_type min_type; // type for min(T...)
+};
+
+/** specialization for two types */
+template<typename T, typename U>
+struct c2_types<T, U> {
+    static_assert(std::is_floating_point<T>::value == std::is_floating_point<U>::value,
+                  "mixing floating point and non-floating point types is disallowed");
+    static_assert(std::is_signed<T>::value == std::is_signed<U>::value,
+                  "mixing signed and unsigned types is disallowed");
+
+    typedef typename std::decay<
+            decltype(true ? std::declval<T>() : std::declval<U>())>::type wide_type;
+    typedef typename std::decay<
+            typename std::conditional<sizeof(T) < sizeof(U), T, U>::type>::type narrow_type;
+    typedef typename std::conditional<
+            std::is_signed<T>::value, wide_type, narrow_type>::type min_type;
+};
+
+/// @}
+
+/// \endcond
+
+/**
+ * Type support utility class. Only supports similar classes, such as:
+ * - all floating point
+ * - all unsigned/all signed
+ * - all pointer
+ */
+template<typename T, typename U, typename... V>
+struct c2_types<T, U, V...> {
+    /** Common type that accommodates all template parameter types. */
+    typedef typename c2_types<typename c2_types<T, U>::wide_type, V...>::wide_type wide_type;
+    /** Narrowest type of the template parameter types. */
+    typedef typename c2_types<typename c2_types<T, U>::narrow_type, V...>::narrow_type narrow_type;
+    /** Type that accommodates the minimum value for any input for the template parameter types. */
+    typedef typename c2_types<typename c2_types<T, U>::min_type, V...>::min_type min_type;
+};
+
+/**
+ *  \ingroup utils_internal
+ * specialization for two values */
+template<typename T, typename U>
+inline constexpr typename c2_types<T, U>::wide_type c2_max(const T a, const U b) {
+    typedef typename c2_types<T, U>::wide_type wide_type;
+    return ({ wide_type a_(a), b_(b); a_ > b_ ? a_ : b_; });
+}
+
+/**
+ * Finds the maximum value of a list of "similarly typed" values.
+ *
+ * This is an extension to std::max where the types do not have to be identical, and the smallest
+ * resulting type is used that accommodates the argument types.
+ *
+ * \note Value types must be similar, e.g. all floating point, all pointers, all signed, or all
+ * unsigned.
+ *
+ * @return the largest of the input arguments.
+ */
+template<typename T, typename U, typename... V>
+constexpr typename c2_types<T, U, V...>::wide_type c2_max(const T a, const U b, const V ... c) {
+    typedef typename c2_types<T, U, V...>::wide_type wide_type;
+    return ({ wide_type a_(a), b_(c2_max(b, c...)); a_ > b_ ? a_ : b_; });
+}
+
+/**
+ *  \ingroup utils_internal
+ * specialization for two values */
+template<typename T, typename U>
+inline constexpr typename c2_types<T, U>::min_type c2_min(const T a, const U b) {
+    typedef typename c2_types<T, U>::wide_type wide_type;
+    return ({
+        wide_type a_(a), b_(b);
+        static_cast<typename c2_types<T, U>::min_type>(a_ < b_ ? a_ : b_);
+    });
+}
+
+/**
+ * Finds the minimum value of a list of "similarly typed" values.
+ *
+ * This is an extension to std::min where the types do not have to be identical, and the smallest
+ * resulting type is used that accommodates the argument types.
+ *
+ * \note Value types must be similar, e.g. all floating point, all pointers, all signed, or all
+ * unsigned.
+ *
+ * @return the smallest of the input arguments.
+ */
+template<typename T, typename U, typename... V>
+constexpr typename c2_types<T, U, V...>::min_type c2_min(const T a, const U b, const V ... c) {
+    typedef typename c2_types<U, V...>::min_type rest_type;
+    typedef typename c2_types<T, rest_type>::wide_type wide_type;
+    return ({
+        wide_type a_(a), b_(c2_min(b, c...));
+        static_cast<typename c2_types<T, rest_type>::min_type>(a_ < b_ ? a_ : b_);
+    });
+}
+
+/**
+ *  \ingroup utils_internal
+ */
+template<typename T, typename U, typename V>
+inline constexpr typename c2_types<T, V>::wide_type c2_clamp(const T a, const U b, const V c) {
+    typedef typename c2_types<T, U, V>::wide_type wide_type;
+    return ({
+        wide_type a_(a), b_(b), c_(c);
+        static_cast<typename c2_types<T, V>::wide_type>(b_ < a_ ? a_ : b_ > c_ ? c_ : b_);
+    });
+}
+
+/// @}
+
+#include <functional>
+template<typename T>
+struct std::less<::c2_cntr_t<T>> {
+    constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
+        return lh.peeku() < rh.peeku();
+    }
+};
+template<typename T>
+struct std::less_equal<::c2_cntr_t<T>> {
+    constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
+        return lh.peeku() <= rh.peeku();
+    }
+};
+template<typename T>
+struct std::greater<::c2_cntr_t<T>> {
+    constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
+        return lh.peeku() > rh.peeku();
+    }
+};
+template<typename T>
+struct std::greater_equal<::c2_cntr_t<T>> {
+    constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
+        return lh.peeku() >= rh.peeku();
+    }
+};
+
+#endif  // C2_H_
diff --git a/media/codec2/include/C2Buffer.h b/media/codec2/include/C2Buffer.h
new file mode 100644
index 0000000..2997f6e
--- /dev/null
+++ b/media/codec2/include/C2Buffer.h
@@ -0,0 +1,2305 @@
+/*
+ * 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 C2BUFFER_H_
+#define C2BUFFER_H_
+
+#include <C2.h>
+#include <C2BufferBase.h>
+#include <C2Param.h> // for C2Info
+
+#include <memory>
+#include <vector>
+
+#ifdef __ANDROID__
+#include <android-C2Buffer.h>
+#else
+
+typedef void* C2Handle;
+
+#endif
+
+/// \defgroup buffer Buffers
+/// @{
+
+/// \defgroup buffer_sync Synchronization
+/// @{
+
+/**
+ * Synchronization is accomplished using event and fence objects.
+ *
+ * These are cross-process extensions of promise/future infrastructure.
+ * Events are analogous to std::promise<void>, whereas fences are to std::shared_future<void>.
+ *
+ * Fences and events are shareable/copyable.
+ *
+ * Fences are used in two scenarios, and all copied instances refer to the same event.
+ * \todo do events need to be copyable or should they be unique?
+ *
+ * acquire sync fence object: signaled when it is safe for the component or client to access
+ * (the contents of) an object.
+ *
+ * release sync fence object: \todo
+ *
+ * Fences can be backed by hardware. Hardware fences are guaranteed to signal NO MATTER WHAT within
+ * a short (platform specific) amount of time; this guarantee is usually less than 15 msecs.
+ */
+
+/**
+ * Fence object used by components and the framework.
+ *
+ * Implements the waiting for an event, analogous to a 'future'.
+ *
+ * To be implemented by vendors if using HW fences.
+ */
+class C2Fence {
+public:
+    /**
+     * Waits for a fence to be signaled with a timeout.
+     *
+     * \todo a mechanism to cancel a wait - for now the only way to do this is to abandon the
+     * event, but fences are shared so canceling a wait will cancel all waits.
+     *
+     * \param timeoutNs           the maximum time to wait in nsecs
+     *
+     * \retval C2_OK            the fence has been signaled
+     * \retval C2_TIMED_OUT     the fence has not been signaled within the timeout
+     * \retval C2_BAD_STATE     the fence has been abandoned without being signaled (it will never
+     *                          be signaled)
+     * \retval C2_REFUSED       no permission to wait for the fence (unexpected - system)
+     * \retval C2_CORRUPTED     some unknown error prevented waiting for the fence (unexpected)
+     */
+    c2_status_t wait(c2_nsecs_t timeoutNs);
+
+    /**
+     * Used to check if this fence is valid (if there is a chance for it to be signaled.)
+     * A fence becomes invalid if the controling event is destroyed without it signaling the fence.
+     *
+     * \return whether this fence is valid
+     */
+    bool valid() const;
+
+    /**
+     * Used to check if this fence has been signaled (is ready).
+     *
+     * \return whether this fence has been signaled
+     */
+    bool ready() const;
+
+    /**
+     * Returns a file descriptor that can be used to wait for this fence in a select system call.
+     * \note The returned file descriptor, if valid, must be closed by the caller.
+     *
+     * This can be used in e.g. poll() system calls. This file becomes readable (POLLIN) when the
+     * fence is signaled, and bad (POLLERR) if the fence is abandoned.
+     *
+     * \return a file descriptor representing this fence (with ownership), or -1 if the fence
+     * has already been signaled (\todo or abandoned).
+     *
+     * \todo this must be compatible with fences used by gralloc
+     */
+    int fd() const;
+
+    /**
+     * Returns whether this fence is a hardware-backed fence.
+     * \return whether this is a hardware fence
+     */
+    bool isHW() const;
+
+    /**
+     * Null-fence. A fence that has fired.
+     */
+    constexpr C2Fence() : mImpl(nullptr) { }
+
+private:
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
+    C2Fence(std::shared_ptr<Impl> impl);
+    friend struct _C2FenceFactory;
+};
+
+/**
+ * Event object used by components and the framework.
+ *
+ * Implements the signaling of an event, analogous to a 'promise'.
+ *
+ * Hardware backed events do not go through this object, and must be exposed directly as fences
+ * by vendors.
+ */
+class C2Event {
+public:
+    /**
+     * Returns a fence for this event.
+     */
+    C2Fence fence() const;
+
+    /**
+     * Signals (all) associated fence(s).
+     * This has no effect no effect if the event was already signaled or abandoned.
+     *
+     * \retval C2_OK            the fence(s) were successfully signaled
+     * \retval C2_BAD_STATE     the fence(s) have already been abandoned or merged (caller error)
+     * \retval C2_DUPLICATE     the fence(s) have already been signaled (caller error)
+     * \retval C2_REFUSED       no permission to signal the fence (unexpected - system)
+     * \retval C2_CORRUPTED     some unknown error prevented signaling the fence(s) (unexpected)
+     */
+    c2_status_t fire();
+
+    /**
+     * Trigger this event from the merging of the supplied fences. This means that it will be
+     * abandoned if any of these fences have been abandoned, and it will be fired if all of these
+     * fences have been signaled.
+     *
+     * \retval C2_OK            the merging was successfully done
+     * \retval C2_NO_MEMORY     not enough memory to perform the merging
+     * \retval C2_DUPLICATE     the fence have already been merged (caller error)
+     * \retval C2_BAD_STATE     the fence have already been signaled or abandoned (caller error)
+     * \retval C2_REFUSED       no permission to merge the fence (unexpected - system)
+     * \retval C2_CORRUPTED     some unknown error prevented merging the fence(s) (unexpected)
+     */
+    c2_status_t merge(std::vector<C2Fence> fences);
+
+    /**
+     * Abandons the event and any associated fence(s).
+     * \note Call this to explicitly abandon an event before it is destructed to avoid a warning.
+     *
+     * This has no effect no effect if the event was already signaled or abandoned.
+     *
+     * \retval C2_OK            the fence(s) were successfully signaled
+     * \retval C2_BAD_STATE     the fence(s) have already been signaled or merged (caller error)
+     * \retval C2_DUPLICATE     the fence(s) have already been abandoned (caller error)
+     * \retval C2_REFUSED       no permission to abandon the fence (unexpected - system)
+     * \retval C2_CORRUPTED     some unknown error prevented signaling the fence(s) (unexpected)
+     */
+    c2_status_t abandon();
+
+private:
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
+};
+
+/// \addtogroup buf_internal Internal
+/// @{
+
+/**
+ * Interface for objects that encapsulate an updatable status value.
+ */
+struct _C2InnateStatus {
+    inline c2_status_t status() const { return mStatus; }
+
+protected:
+    _C2InnateStatus(c2_status_t status) : mStatus(status) { }
+
+    c2_status_t mStatus; // this status is updatable by the object
+};
+
+/// @}
+
+/**
+ * This is a utility template for objects protected by an acquire fence, so that errors during
+ * acquiring the object are propagated to the object itself.
+ */
+template<typename T>
+class C2Acquirable : public C2Fence {
+public:
+    /**
+     * Acquires the object protected by an acquire fence. Any errors during the mapping will be
+     * passed to the object.
+     *
+     * \return acquired object potentially invalidated if waiting for the fence failed.
+     */
+    T get() {
+        // TODO:
+        // wait();
+        return mT;
+    }
+
+protected:
+    C2Acquirable(c2_status_t error, C2Fence fence, T t) : C2Fence(fence), mInitialError(error), mT(t) { }
+
+private:
+    c2_status_t mInitialError;
+    T mT; // TODO: move instead of copy
+};
+
+/// @}
+
+/// \defgroup linear Linear Data Blocks
+/// @{
+
+/**************************************************************************************************
+  LINEAR ASPECTS, BLOCKS AND VIEWS
+**************************************************************************************************/
+
+/**
+ * Basic segment math support.
+ */
+struct C2Segment {
+    uint32_t offset;
+    uint32_t size;
+
+    inline constexpr C2Segment(uint32_t offset_, uint32_t size_)
+        : offset(offset_),
+          size(size_) {
+    }
+
+    inline constexpr bool isEmpty() const {
+        return size == 0;
+    }
+
+    inline constexpr bool isValid() const {
+        return offset <= ~size;
+    }
+
+    inline constexpr operator bool() const {
+        return isValid() && !isEmpty();
+    }
+
+    inline constexpr bool operator!() const {
+        return !bool(*this);
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr bool contains(const C2Segment &other) const {
+        if (!isValid() || !other.isValid()) {
+            return false;
+        } else {
+            return offset <= other.offset
+                    && offset + size >= other.offset + other.size;
+        }
+    }
+
+    inline constexpr bool operator==(const C2Segment &other) const {
+        if (!isValid()) {
+            return !other.isValid();
+        } else {
+            return offset == other.offset && size == other.size;
+        }
+    }
+
+    inline constexpr bool operator!=(const C2Segment &other) const {
+        return !operator==(other);
+    }
+
+    inline constexpr bool operator>=(const C2Segment &other) const {
+        return contains(other);
+    }
+
+    inline constexpr bool operator>(const C2Segment &other) const {
+        return contains(other) && !operator==(other);
+    }
+
+    inline constexpr bool operator<=(const C2Segment &other) const {
+        return other.contains(*this);
+    }
+
+    inline constexpr bool operator<(const C2Segment &other) const {
+        return other.contains(*this) && !operator==(other);
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr uint32_t end() const {
+        return offset + size;
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr C2Segment intersect(const C2Segment &other) const {
+        return C2Segment(c2_max(offset, other.offset),
+                         c2_min(end(), other.end()) - c2_max(offset, other.offset));
+    }
+
+    /** clamps end to offset if it overflows */
+    inline constexpr C2Segment normalize() const {
+        return C2Segment(offset, c2_max(offset, end()) - offset);
+    }
+
+    /** clamps end to max if it overflows */
+    inline constexpr C2Segment saturate() const {
+        return C2Segment(offset, c2_min(size, ~offset));
+    }
+
+};
+
+/**
+ * Common aspect for all objects that have a linear capacity.
+ */
+class _C2LinearCapacityAspect {
+/// \name Linear capacity interface
+/// @{
+public:
+    inline constexpr uint32_t capacity() const { return mCapacity; }
+
+    inline constexpr operator C2Segment() const {
+        return C2Segment(0, mCapacity);
+    }
+
+protected:
+
+#if UINTPTR_MAX == 0xffffffff
+    static_assert(sizeof(size_t) == sizeof(uint32_t), "size_t is too big");
+#else
+    static_assert(sizeof(size_t) > sizeof(uint32_t), "size_t is too small");
+    // explicitly disable construction from size_t
+    inline explicit _C2LinearCapacityAspect(size_t capacity) = delete;
+#endif
+
+    inline explicit constexpr _C2LinearCapacityAspect(uint32_t capacity)
+      : mCapacity(capacity) { }
+
+    inline explicit constexpr _C2LinearCapacityAspect(const _C2LinearCapacityAspect *parent)
+        : mCapacity(parent == nullptr ? 0 : parent->capacity()) { }
+
+private:
+    uint32_t mCapacity;
+/// @}
+};
+
+/**
+ * Aspect for objects that have a linear range inside a linear capacity.
+ *
+ * This class is copiable.
+ */
+class _C2LinearRangeAspect : public _C2LinearCapacityAspect {
+/// \name Linear range interface
+/// @{
+public:
+    inline constexpr uint32_t offset() const { return mOffset; }
+    inline constexpr uint32_t endOffset() const { return mOffset + mSize; }
+    inline constexpr uint32_t size() const { return mSize; }
+
+    inline constexpr operator C2Segment() const {
+        return C2Segment(mOffset, mSize);
+    }
+
+private:
+    // subrange of capacity [0, capacity] & [size, size + offset]
+    inline constexpr _C2LinearRangeAspect(uint32_t capacity_, size_t offset, size_t size)
+        : _C2LinearCapacityAspect(capacity_),
+          mOffset(c2_min(offset, capacity())),
+          mSize(c2_min(size, capacity() - mOffset)) {
+    }
+
+protected:
+    // copy constructor (no error check)
+    inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect &other)
+        : _C2LinearCapacityAspect(other.capacity()),
+          mOffset(other.offset()),
+          mSize(other.size()) {
+    }
+
+    // parent capacity range [0, capacity]
+    inline constexpr explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
+        : _C2LinearCapacityAspect(parent),
+          mOffset(0),
+          mSize(capacity()) {
+    }
+
+    // subrange of parent capacity [0, capacity] & [size, size + offset]
+    inline constexpr _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
+        : _C2LinearCapacityAspect(parent),
+          mOffset(c2_min(offset, capacity())),
+          mSize(c2_min(size, capacity() - mOffset)) {
+    }
+
+    // subsection of the parent's and [offset, offset + size] ranges
+    inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
+        : _C2LinearCapacityAspect(parent),
+          mOffset(c2_min(c2_max(offset, parent == nullptr ? 0 : parent->offset()), capacity())),
+          mSize(std::min(c2_min(size, parent == nullptr ? 0 : parent->size()), capacity() - mOffset)) {
+    }
+
+public:
+    inline constexpr _C2LinearRangeAspect childRange(size_t offset, size_t size) const {
+        return _C2LinearRangeAspect(
+            mSize,
+            c2_min(c2_max(offset, mOffset), capacity()) - mOffset,
+            c2_min(c2_min(size, mSize), capacity() - c2_min(c2_max(offset, mOffset), capacity())));
+    }
+
+    friend class _C2EditableLinearRangeAspect;
+    // invariants 0 <= mOffset <= mOffset + mSize <= capacity()
+    uint32_t mOffset;
+    uint32_t mSize;
+/// @}
+};
+
+/**
+ * Utility class for safe range calculations using size_t-s.
+ */
+class C2LinearRange : public _C2LinearRangeAspect {
+public:
+    inline constexpr C2LinearRange(const _C2LinearCapacityAspect &parent, size_t offset, size_t size)
+        : _C2LinearRangeAspect(&parent, offset, size) { }
+
+    inline constexpr C2LinearRange(const _C2LinearRangeAspect &parent, size_t offset, size_t size)
+        : _C2LinearRangeAspect(&parent, offset, size) { }
+
+    inline constexpr C2LinearRange intersect(size_t offset, size_t size) const {
+        return C2LinearRange(*this, offset, size);
+    }
+};
+
+/**
+ * Utility class for simple and safe capacity and range construction.
+ */
+class C2LinearCapacity : public _C2LinearCapacityAspect {
+public:
+    inline constexpr explicit C2LinearCapacity(size_t capacity)
+        : _C2LinearCapacityAspect(c2_min(capacity, std::numeric_limits<uint32_t>::max())) { }
+
+    inline constexpr C2LinearRange range(size_t offset, size_t size) const {
+        return C2LinearRange(*this, offset, size);
+    }
+};
+
+/**
+ * Aspect for objects that have an editable linear range.
+ *
+ * This class is copiable.
+ */
+class _C2EditableLinearRangeAspect : public _C2LinearRangeAspect {
+    using _C2LinearRangeAspect::_C2LinearRangeAspect;
+
+public:
+/// \name Editable linear range interface
+/// @{
+
+    /**
+     * Sets the offset to |offset|, while trying to keep the end of the buffer unchanged (e.g.
+     * size will grow if offset is decreased, and may shrink if offset is increased.) Returns
+     * true if successful, which is equivalent to if 0 <= |offset| <= capacity().
+     *
+     * Note: setting offset and size will yield different result depending on the order of the
+     * operations. Always set offset first to ensure proper size.
+     */
+    inline bool setOffset(uint32_t offset) {
+        if (offset > capacity()) {
+            return false;
+        }
+
+        if (offset > mOffset + mSize) {
+            mSize = 0;
+        } else {
+            mSize = mOffset + mSize - offset;
+        }
+        mOffset = offset;
+        return true;
+    }
+
+    /**
+     * Sets the size to |size|. Returns true if successful, which is equivalent to
+     * if 0 <= |size| <= capacity() - offset().
+     *
+     * Note: setting offset and size will yield different result depending on the order of the
+     * operations. Always set offset first to ensure proper size.
+     */
+    inline bool setSize(uint32_t size) {
+        if (size > capacity() - mOffset) {
+            return false;
+        } else {
+            mSize = size;
+            return true;
+        }
+    }
+
+    /**
+     * Sets the offset to |offset| with best effort. Same as setOffset() except that offset will
+     * be clamped to the buffer capacity.
+     *
+     * Note: setting offset and size (even using best effort) will yield different result depending
+     * on the order of the operations. Always set offset first to ensure proper size.
+     */
+    inline void setOffset_be(uint32_t offset) {
+        (void)setOffset(c2_min(offset, capacity()));
+    }
+
+    /**
+     * Sets the size to |size| with best effort. Same as setSize() except that the selected region
+     * will be clamped to the buffer capacity (e.g. size is clamped to [0, capacity() - offset()]).
+     *
+     * Note: setting offset and size (even using best effort) will yield different result depending
+     * on the order of the operations. Always set offset first to ensure proper size.
+     */
+    inline void setSize_be(uint32_t size) {
+        mSize = c2_min(size, capacity() - mOffset);
+    }
+/// @}
+};
+
+/**************************************************************************************************
+  ALLOCATIONS
+**************************************************************************************************/
+
+/// \ingroup allocator Allocation and memory placement
+/// @{
+
+class C2LinearAllocation;
+class C2GraphicAllocation;
+
+/**
+ *  Allocators are used by the framework to allocate memory (allocations) for buffers. They can
+ *  support either 1D or 2D allocations.
+ *
+ *  \note In theory they could support both, but in practice, we will use only one or the other.
+ *
+ *  Never constructed on stack.
+ *
+ *  Allocators are provided by vendors.
+ */
+class C2Allocator {
+public:
+    /**
+     * Allocator ID type.
+     */
+    typedef uint32_t id_t;
+    enum : id_t {
+        BAD_ID = 0xBADD, // invalid allocator ID
+    };
+
+    /**
+     * Allocation types. This is a bitmask and is used in C2Allocator::Info
+     * to list the supported allocation types of an allocator.
+     */
+    enum type_t : uint32_t {
+        LINEAR  = 1 << 0, //
+        GRAPHIC = 1 << 1,
+    };
+
+    /**
+     * Information about an allocator.
+     *
+     * Allocators don't have a query API so all queriable information is stored here.
+     */
+    struct Traits {
+        C2String name;              ///< allocator name
+        id_t id;                    ///< allocator ID
+        type_t supportedTypes;      ///< supported allocation types
+        C2MemoryUsage minimumUsage; ///< usage that is minimally required for allocations
+        C2MemoryUsage maximumUsage; ///< usage that is maximally allowed for allocations
+    };
+
+    /**
+     * Returns the unique name of this allocator.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the name of this allocator.
+     * \retval an empty string if there was not enough memory to allocate the actual name.
+     */
+    virtual C2String getName() const = 0;
+
+    /**
+     * Returns a unique ID for this allocator. This ID is used to get this allocator from the
+     * allocator store, and to identify this allocator across all processes.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return a unique ID for this allocator.
+     */
+    virtual id_t getId() const = 0;
+
+    /**
+     * Returns the allocator traits.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * Allocators don't have a full-fledged query API, only this method.
+     *
+     * \return allocator information
+     */
+    virtual std::shared_ptr<const Traits> getTraits() const = 0;
+
+    /**
+     * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
+     * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param capacity      the size of requested allocation (the allocation could be slightly
+     *                      larger, e.g. to account for any system-required alignment)
+     * \param usage         the memory usage info for the requested allocation. \note that the
+     *                      returned allocation may be later used/mapped with different usage.
+     *                      The allocator should layout the buffer to be optimized for this usage,
+     *                      but must support any usage. One exception: protected buffers can
+     *                      only be used in a protected scenario.
+     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
+     *                      will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete the allocation
+     * \retval C2_TIMED_OUT the allocation timed out
+     * \retval C2_REFUSED   no permission to complete the allocation
+     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this allocator does not support 1D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+     */
+    virtual c2_status_t newLinearAllocation(
+            uint32_t capacity __unused, C2MemoryUsage usage __unused,
+            std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * (Re)creates a 1D allocation from a native |handle|. If successful, the allocation is stored
+     * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param handle      the handle for the existing allocation. On success, the allocation will
+     *                    take ownership of |handle|.
+     * \param allocation  pointer to where the allocation shall be stored on success. nullptr
+     *                    will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was recreated successfully
+     * \retval C2_NO_MEMORY not enough memory to recreate the allocation
+     * \retval C2_TIMED_OUT the recreation timed out (unexpected)
+     * \retval C2_REFUSED   no permission to recreate the allocation
+     * \retval C2_BAD_VALUE invalid handle (caller error)
+     * \retval C2_OMITTED   this allocator does not support 1D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+     */
+    virtual c2_status_t priorLinearAllocation(
+            const C2Handle *handle __unused,
+            std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * Allocates a 2D allocation of given |width|, |height|, |format| and |usage|. If successful,
+     * the allocation is stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param width         the width of requested allocation (the allocation could be slightly
+     *                      larger, e.g. to account for any system-required alignment)
+     * \param height        the height of requested allocation (the allocation could be slightly
+     *                      larger, e.g. to account for any system-required alignment)
+     * \param format        the pixel format of requested allocation. This could be a vendor
+     *                      specific format.
+     * \param usage         the memory usage info for the requested allocation. \note that the
+     *                      returned allocation may be later used/mapped with different usage.
+     *                      The allocator should layout the buffer to be optimized for this usage,
+     *                      but must support any usage. One exception: protected buffers can
+     *                      only be used in a protected scenario.
+     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
+     *                      will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete the allocation
+     * \retval C2_TIMED_OUT the allocation timed out
+     * \retval C2_REFUSED   no permission to complete the allocation
+     * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this allocator does not support 2D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+     */
+    virtual c2_status_t newGraphicAllocation(
+            uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
+            C2MemoryUsage usage __unused,
+            std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * (Re)creates a 2D allocation from a native handle.  If successful, the allocation is stored
+     * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param handle      the handle for the existing allocation. On success, the allocation will
+     *                    take ownership of |handle|.
+     * \param allocation  pointer to where the allocation shall be stored on success. nullptr
+     *                    will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was recreated successfully
+     * \retval C2_NO_MEMORY not enough memory to recreate the allocation
+     * \retval C2_TIMED_OUT the recreation timed out (unexpected)
+     * \retval C2_REFUSED   no permission to recreate the allocation
+     * \retval C2_BAD_VALUE invalid handle (caller error)
+     * \retval C2_OMITTED   this allocator does not support 2D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected)
+     */
+    virtual c2_status_t priorGraphicAllocation(
+            const C2Handle *handle __unused,
+            std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+    virtual ~C2Allocator() = default;
+protected:
+    C2Allocator() = default;
+};
+
+/**
+ * \ingroup linear allocator
+ * 1D allocation interface.
+ */
+class C2LinearAllocation : public _C2LinearCapacityAspect {
+public:
+    /**
+     * Maps a portion of an allocation starting from |offset| with |size| into local process memory.
+     * Stores the starting address into |addr|, or NULL if the operation was unsuccessful.
+     * |fence| will contain an acquire sync fence object. If it is already
+     * safe to access the buffer contents, then it will contain an empty (already fired) fence.
+     *
+     * \param offset        starting position of the portion to be mapped (this does not have to
+     *                      be page aligned)
+     * \param size          size of the portion to be mapped (this does not have to be page
+     *                      aligned)
+     * \param usage         the desired usage. \todo this must be kSoftwareRead and/or
+     *                      kSoftwareWrite.
+     * \param fence         a pointer to a fence object if an async mapping is requested. If
+     *                      not-null, and acquire fence will be stored here on success, or empty
+     *                      fence on failure. If null, the mapping will be synchronous.
+     * \param addr          a pointer to where the starting address of the mapped portion will be
+     *                      stored. On failure, nullptr will be stored here.
+     *
+     * \todo Only one portion can be mapped at the same time - this is true for gralloc, but there
+     *       is no need for this for 1D buffers.
+     * \todo Do we need to support sync operation as we could just wait for the fence?
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_REFUSED   no permission to map the portion
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_DUPLICATE if the allocation is already mapped.
+     * \retval C2_NO_MEMORY not enough memory to complete the operation
+     * \retval C2_BAD_VALUE the parameters (offset/size) are invalid or outside the allocation, or
+     *                      the usage flags are invalid (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+     */
+    virtual c2_status_t map(
+            size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence /* nullable */,
+            void **addr /* nonnull */) = 0;
+
+    /**
+     * Unmaps a portion of an allocation at |addr| with |size|. These must be parameters previously
+     * passed to and returned by |map|; otherwise, this operation is a no-op.
+     *
+     * \param addr          starting address of the mapped region
+     * \param size          size of the mapped region
+     * \param fence         a pointer to a fence object if an async unmapping is requested. If
+     *                      not-null, a release fence will be stored here on success, or empty fence
+     *                      on failure. This fence signals when the original allocation contains
+     *                      all changes that happened to the mapped region. If null, the unmapping
+     *                      will be synchronous.
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_NOT_FOUND if the allocation was not mapped previously.
+     * \retval C2_BAD_VALUE the parameters (addr/size) do not correspond to previously mapped
+     *                      regions (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+     * \retval C2_REFUSED   no permission to unmap the portion (unexpected - system)
+     */
+    virtual c2_status_t unmap(void *addr, size_t size, C2Fence *fence /* nullable */) = 0;
+
+    /**
+     * Returns the allocator ID for this allocation. This is useful to put the handle into context.
+     */
+    virtual C2Allocator::id_t getAllocatorId() const = 0;
+
+    /**
+     * Returns a pointer to the allocation handle.
+     */
+    virtual const C2Handle *handle() const = 0;
+
+    /**
+     * Returns true if this is the same allocation as |other|.
+     */
+    virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const = 0;
+
+protected:
+    // \todo should we limit allocation directly?
+    C2LinearAllocation(size_t capacity) : _C2LinearCapacityAspect(c2_min(capacity, UINT32_MAX)) {}
+    virtual ~C2LinearAllocation() = default;
+};
+
+class C2CircularBlock;
+class C2LinearBlock;
+class C2GraphicBlock;
+
+/**
+ *  Block pools are used by components to obtain output buffers in an efficient way. They can
+ *  support either linear (1D), circular (1D) or graphic (2D) blocks.
+ *
+ *  Block pools decouple the recycling of memory/allocations from the components. They are meant to
+ *  be an opaque service (there are no public APIs other than obtaining blocks) provided by the
+ *  platform. Block pools are also meant to decouple allocations from memory used by buffers. This
+ *  is accomplished by allowing pools to allot multiple memory 'blocks' on a single allocation. As
+ *  their name suggest, block pools maintain a pool of memory blocks. When a component asks for
+ *  a memory block, pools will try to return a free memory block already in the pool. If no such
+ *  block exists, they will allocate memory using the backing allocator and allot a block on that
+ *  allocation. When blocks are no longer used in the system, they are recycled back to the block
+ *  pool and are available as free blocks.
+ *
+ *  Never constructed on stack.
+ */
+class C2BlockPool {
+public:
+    /**
+     * Block pool ID type.
+     */
+    typedef uint64_t local_id_t;
+
+    enum : local_id_t {
+        BASIC_LINEAR = 0,  ///< ID of basic (unoptimized) block pool for fetching 1D blocks
+        BASIC_GRAPHIC = 1, ///< ID of basic (unoptimized) block pool for fetching 2D blocks
+        PLATFORM_START = 0x10,
+    };
+
+    /**
+     * Returns the ID for this block pool. This ID is used to get this block pool from the platform.
+     * It is only valid in the current process.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return a local ID for this block pool.
+     */
+    virtual local_id_t getLocalId() const = 0;
+
+    /**
+     * Returns the ID of the backing allocator of this block pool.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the ID of the backing allocator of this block pool.
+     */
+    virtual C2Allocator::id_t getAllocatorId() const = 0;
+
+    /**
+     * Obtains a linear writeable block of given |capacity| and |usage|. If successful, the
+     * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+     *
+     * \param capacity the size of requested block.
+     * \param usage    the memory usage info for the requested block. Returned blocks will be
+     *                 optimized for this usage, but may be used with any usage. One exception:
+     *                 protected blocks/buffers can only be used in a protected scenario.
+     * \param block    pointer to where the obtained block shall be stored on success. nullptr will
+     *                 be stored here on failure
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
+     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this pool does not support linear blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+     */
+    virtual c2_status_t fetchLinearBlock(
+            uint32_t capacity __unused, C2MemoryUsage usage __unused,
+            std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+        *block = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * Obtains a circular writeable block of given |capacity| and |usage|. If successful, the
+     * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+     *
+     * \param capacity the size of requested circular block. (note: the size of the obtained
+     *                 block could be slightly larger, e.g. to accommodate any system-required
+     *                 alignment)
+     * \param usage    the memory usage info for the requested block. Returned blocks will be
+     *                 optimized for this usage, but may be used with any usage. One exception:
+     *                 protected blocks/buffers can only be used in a protected scenario.
+     * \param block    pointer to where the obtained block shall be stored on success. nullptr
+     *                 will be stored here on failure
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
+     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this pool does not support circular blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+     */
+    virtual c2_status_t fetchCircularBlock(
+            uint32_t capacity __unused, C2MemoryUsage usage __unused,
+            std::shared_ptr<C2CircularBlock> *block /* nonnull */) {
+        *block = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * Obtains a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
+     * the block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+     *
+     * \param width  the width of requested block (the obtained block could be slightly larger, e.g.
+     *               to accommodate any system-required alignment)
+     * \param height the height of requested block (the obtained block could be slightly larger,
+     *               e.g. to accommodate any system-required alignment)
+     * \param format the pixel format of requested block. This could be a vendor specific format.
+     * \param usage  the memory usage info for the requested block. Returned blocks will be
+     *               optimized for this usage, but may be used with any usage. One exception:
+     *               protected blocks/buffers can only be used in a protected scenario.
+     * \param block  pointer to where the obtained block shall be stored on success. nullptr
+     *               will be stored here on failure
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
+     * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
+     *                      error)
+     * \retval C2_OMITTED   this pool does not support 2D blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+     */
+    virtual c2_status_t fetchGraphicBlock(
+            uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
+            C2MemoryUsage usage __unused,
+            std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+        *block = nullptr;
+        return C2_OMITTED;
+    }
+
+    virtual ~C2BlockPool() = default;
+protected:
+    C2BlockPool() = default;
+};
+
+/// @}
+
+// ================================================================================================
+//  BLOCKS
+// ================================================================================================
+
+/**
+ * Blocks are sections of allocations. They can be either 1D or 2D.
+ */
+
+class C2LinearAllocation;
+
+/**
+ * A 1D block.
+ *
+ * \note capacity() is not meaningful for users of blocks; instead size() is the capacity of the
+ * usable portion. Use and offset() and size() if accessing the block directly through its handle
+ * to represent the allotted range of the underlying allocation to this block.
+ */
+class C2Block1D : public _C2LinearRangeAspect {
+public:
+    /**
+     * Returns the underlying handle for this allocation.
+     *
+     * \note that the block and its block pool has shared ownership of the handle
+     *       and if all references to the block are released, the underlying block
+     *       allocation may get reused even if a client keeps a clone of this handle.
+     */
+    const C2Handle *handle() const;
+
+    /**
+     * Returns the allocator's ID that created the underlying allocation for this block. This
+     * provides the context for understanding the handle.
+     */
+    C2Allocator::id_t getAllocatorId() const;
+
+protected:
+    class Impl;
+    /** construct a block. */
+    C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range);
+
+    friend struct _C2BlockFactory;
+    std::shared_ptr<Impl> mImpl;
+};
+
+/**
+ * Read view provides read-only access for a linear memory segment.
+ *
+ * This class is copiable.
+ */
+class C2ReadView : public _C2LinearCapacityAspect {
+public:
+    /**
+     * \return pointer to the start of the block or nullptr on error.
+     *         This pointer is only valid during the lifetime of this view or until it is released.
+     */
+    const uint8_t *data() const;
+
+    /**
+     * Returns a portion of this view.
+     *
+     * \param offset  the start offset of the portion. \note This is clamped to the capacity of this
+     *              view.
+     * \param size    the size of the portion. \note This is clamped to the remaining data from offset.
+     *
+     * \return a read view containing a portion of this view
+     */
+    C2ReadView subView(size_t offset, size_t size) const;
+
+    /**
+     * \return error during the creation/mapping of this view.
+     */
+    c2_status_t error() const;
+
+    /**
+     * Releases this view. This sets error to C2_NO_INIT.
+     */
+    //void release();
+
+protected:
+    class Impl;
+    C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size);
+    explicit C2ReadView(c2_status_t error);
+
+private:
+    friend struct _C2BlockFactory;
+    std::shared_ptr<Impl> mImpl;
+    uint32_t mOffset; /**< offset into the linear block backing this read view */
+};
+
+/**
+ * Write view provides read/write access for a linear memory segment.
+ *
+ * This class is copiable. \todo movable only?
+ */
+class C2WriteView : public _C2EditableLinearRangeAspect {
+public:
+    /**
+     * Start of the block.
+     *
+     * \return pointer to the start of the block or nullptr on error.
+     *         This pointer is only valid during the lifetime of this view or until it is released.
+     */
+    uint8_t *base();
+
+    /**
+     * \return pointer to the block at the current offset or nullptr on error.
+     *         This pointer is only valid during the lifetime of this view or until it is released.
+     */
+    uint8_t *data();
+
+    /**
+     * \return error during the creation/mapping of this view.
+     */
+    c2_status_t error() const;
+
+    /**
+     * Releases this view. This sets error to C2_NO_INIT.
+     */
+    //void release();
+
+protected:
+    class Impl;
+    C2WriteView(std::shared_ptr<Impl> impl);
+    explicit C2WriteView(c2_status_t error);
+
+private:
+    friend struct _C2BlockFactory;
+    std::shared_ptr<Impl> mImpl;
+};
+
+/**
+ * A constant (read-only) linear block (portion of an allocation) with an acquire fence.
+ * Blocks are unmapped when created, and can be mapped into a read view on demand.
+ *
+ * This class is copiable and contains a reference to the allocation that it is based on.
+ */
+class C2ConstLinearBlock : public C2Block1D {
+public:
+    /**
+     * Maps this block into memory and returns a read view for it.
+     *
+     * \return a read view for this block.
+     */
+    C2Acquirable<C2ReadView> map() const;
+
+    /**
+     * Returns a portion of this block.
+     *
+     * \param offset  the start offset of the portion. \note This is clamped to the capacity of this
+     *              block.
+     * \param size    the size of the portion. \note This is clamped to the remaining data from offset.
+     *
+     * \return a constant linear block containing a portion of this block
+     */
+    C2ConstLinearBlock subBlock(size_t offset, size_t size) const;
+
+    /**
+     * Returns the acquire fence for this block.
+     *
+     * \return a fence that must be waited on before reading the block.
+     */
+    C2Fence fence() const { return mFence; }
+
+protected:
+    C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence mFence);
+
+private:
+    friend struct _C2BlockFactory;
+    C2Fence mFence;
+};
+
+/**
+ * Linear block is a writeable 1D block. Once written, it can be shared in whole or in parts with
+ * consumers/readers as read-only const linear block(s).
+ */
+class C2LinearBlock : public C2Block1D {
+public:
+    /**
+     * Maps this block into memory and returns a write view for it.
+     *
+     * \return a write view for this block.
+     */
+    C2Acquirable<C2WriteView> map();
+
+    /**
+     * Creates a read-only const linear block for a portion of this block; optionally protected
+     * by an acquire fence. There are two ways to use this:
+     *
+     * 1) share ready block after writing data into the block. In this case no fence shall be
+     *    supplied, and the block shall not be modified after calling this method.
+     * 2) share block metadata before actually (finishing) writing the data into the block. In
+     *    this case a fence must be supplied that will be triggered when the data is written.
+     *    The block shall be modified only until firing the event for the fence.
+     */
+    C2ConstLinearBlock share(size_t offset, size_t size, C2Fence fence);
+
+protected:
+    C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range);
+
+    friend struct _C2BlockFactory;
+};
+
+/// @}
+
+/**************************************************************************************************
+  CIRCULAR BLOCKS AND VIEWS
+**************************************************************************************************/
+
+/// \defgroup circular Circular buffer support
+/// @{
+
+/**
+ * Circular blocks can be used to share data between a writer and a reader (and/or other consumers)-
+ * in a memory-efficient way by reusing a section of memory. Circular blocks are a bit more complex
+ * than single reader/single writer schemes to facilitate block-based consuming of data.
+ *
+ * They can operate in two modes:
+ *
+ * 1) one writer that creates blocks to be consumed (this model can be used by components)
+ *
+ * 2) one writer that writes continuously, and one reader that can creates blocks to be consumed
+ *    by further recipients (this model is used by the framework, and cannot be used by components.)
+ *
+ * Circular blocks have four segments with running pointers:
+ *  - reserved: data reserved and available for the writer
+ *  - committed: data committed by the writer and available to the reader (if present)
+ *  - used: data used by consumers (if present)
+ *  - available: unused data available to be reserved
+ */
+class C2CircularBlock : public C2Block1D {
+    // TODO: add methods
+
+private:
+    size_t mReserved __unused;   // end of reserved section
+    size_t mCommitted __unused;  // end of committed section
+    size_t mUsed __unused;       // end of used section
+    size_t mFree __unused;       // end of free section
+};
+
+class _C2CircularBlockSegment : public _C2LinearCapacityAspect {
+public:
+    /**
+     * Returns the available size for this segment.
+     *
+     * \return currently available size for this segment
+     */
+    size_t available() const;
+
+    /**
+     * Reserve some space for this segment from its current start.
+     *
+     * \param size    desired space in bytes
+     * \param fence   a pointer to an acquire fence. If non-null, the reservation is asynchronous and
+     *              a fence will be stored here that will be signaled when the reservation is
+     *              complete. If null, the reservation is synchronous.
+     *
+     * \retval C2_OK            the space was successfully reserved
+     * \retval C2_NO_MEMORY     the space requested cannot be reserved
+     * \retval C2_TIMED_OUT     the reservation timed out \todo when?
+     * \retval C2_CORRUPTED     some unknown error prevented reserving space. (unexpected)
+     */
+    c2_status_t reserve(size_t size, C2Fence *fence /* nullable */);
+
+    /**
+     * Abandons a portion of this segment. This will move to the beginning of this segment.
+     *
+     * \note This methods is only allowed if this segment is producing blocks.
+     *
+     * \param size    number of bytes to abandon
+     *
+     * \retval C2_OK            the data was successfully abandoned
+     * \retval C2_TIMED_OUT     the operation timed out (unexpected)
+     * \retval C2_CORRUPTED     some unknown error prevented abandoning the data (unexpected)
+     */
+    c2_status_t abandon(size_t size);
+
+    /**
+     * Share a portion as block(s) with consumers (these are moved to the used section).
+     *
+     * \note This methods is only allowed if this segment is producing blocks.
+     * \note Share does not move the beginning of the segment. (\todo add abandon/offset?)
+     *
+     * \param size    number of bytes to share
+     * \param fence   fence to be used for the section
+     * \param blocks  vector where the blocks of the section are appended to
+     *
+     * \retval C2_OK            the portion was successfully shared
+     * \retval C2_NO_MEMORY     not enough memory to share the portion
+     * \retval C2_TIMED_OUT     the operation timed out (unexpected)
+     * \retval C2_CORRUPTED     some unknown error prevented sharing the data (unexpected)
+     */
+    c2_status_t share(size_t size, C2Fence fence, std::vector<C2ConstLinearBlock> &blocks);
+
+    /**
+     * Returns the beginning offset of this segment from the start of this circular block.
+     *
+     * @return beginning offset
+     */
+    size_t begin();
+
+    /**
+     * Returns the end offset of this segment from the start of this circular block.
+     *
+     * @return end offset
+     */
+    size_t end();
+};
+
+/**
+ * A circular write-view is a dynamic mapped view for a segment of a circular block. Care must be
+ * taken when using this view so that only the section owned by the segment is modified.
+ */
+class C2CircularWriteView : public _C2LinearCapacityAspect {
+public:
+    /**
+     * Start of the circular block.
+     * \note the segment does not own this pointer.
+     *
+     * \return pointer to the start of the circular block or nullptr on error.
+     */
+    uint8_t *base();
+
+    /**
+     * \return error during the creation/mapping of this view.
+     */
+    c2_status_t error() const;
+};
+
+/**
+ * The writer of a circular buffer.
+ *
+ * Can commit data to a reader (not supported for components) OR share data blocks directly with a
+ * consumer.
+ *
+ * If a component supports outputting data into circular buffers, it must allocate a circular
+ * block and use a circular writer.
+ */
+class C2CircularWriter : public _C2CircularBlockSegment {
+public:
+    /**
+     * Commits a portion of this segment to the next segment. This moves the beginning of the
+     * segment.
+     *
+     * \param size    number of bytes to commit to the next segment
+     * \param fence   fence used for the commit (the fence must signal before the data is committed)
+     */
+    c2_status_t commit(size_t size, C2Fence fence);
+
+    /**
+     * Maps this block into memory and returns a write view for it.
+     *
+     * \return a write view for this block.
+     */
+    C2Acquirable<C2CircularWriteView> map();
+};
+
+/// @}
+
+/// \defgroup graphic Graphic Data Blocks
+/// @{
+
+/**
+ * C2Rect: rectangle type with non-negative coordinates.
+ *
+ * \note This struct has public fields without getters/setters. All methods are inline.
+ */
+struct C2Rect {
+// public:
+    uint32_t width;
+    uint32_t height;
+    uint32_t left;
+    uint32_t top;
+
+    constexpr inline C2Rect()
+        : C2Rect(0, 0, 0, 0) { }
+
+    constexpr inline C2Rect(uint32_t width_, uint32_t height_)
+        : C2Rect(width_, height_, 0, 0) { }
+
+    constexpr C2Rect inline at(uint32_t left_, uint32_t top_) const {
+        return C2Rect(width, height, left_, top_);
+    }
+
+    // utility methods
+
+    inline constexpr bool isEmpty() const {
+        return width == 0 || height == 0;
+    }
+
+    inline constexpr bool isValid() const {
+        return left <= ~width && top <= ~height;
+    }
+
+    inline constexpr operator bool() const {
+        return isValid() && !isEmpty();
+    }
+
+    inline constexpr bool operator!() const {
+        return !bool(*this);
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr bool contains(const C2Rect &other) const {
+        if (!isValid() || !other.isValid()) {
+            return false;
+        } else {
+            return left <= other.left && top <= other.top
+                    && left + width >= other.left + other.width
+                    && top + height >= other.top + other.height;
+        }
+    }
+
+    inline constexpr bool operator==(const C2Rect &other) const {
+        if (!isValid()) {
+            return !other.isValid();
+        } else {
+            return left == other.left && top == other.top
+                    && width == other.width && height == other.height;
+        }
+    }
+
+    inline constexpr bool operator!=(const C2Rect &other) const {
+        return !operator==(other);
+    }
+
+    inline constexpr bool operator>=(const C2Rect &other) const {
+        return contains(other);
+    }
+
+    inline constexpr bool operator>(const C2Rect &other) const {
+        return contains(other) && !operator==(other);
+    }
+
+    inline constexpr bool operator<=(const C2Rect &other) const {
+        return other.contains(*this);
+    }
+
+    inline constexpr bool operator<(const C2Rect &other) const {
+        return other.contains(*this) && !operator==(other);
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr uint32_t right() const {
+        return left + width;
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr uint32_t bottom() const {
+        return top + height;
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr C2Rect intersect(const C2Rect &other) const {
+        return C2Rect(c2_min(right(), other.right()) - c2_max(left, other.left),
+                      c2_min(bottom(), other.bottom()) - c2_max(top, other.top),
+                      c2_max(left, other.left),
+                      c2_max(top, other.top));
+    }
+
+    /** clamps right and bottom to top, left if they overflow */
+    inline constexpr C2Rect normalize() const {
+        return C2Rect(c2_max(left, right()) - left, c2_max(top, bottom()) - top, left, top);
+    }
+
+private:
+    /// note: potentially unusual argument order
+    constexpr inline C2Rect(uint32_t width_, uint32_t height_, uint32_t left_, uint32_t top_)
+        : width(width_),
+          height(height_),
+          left(left_),
+          top(top_) { }
+};
+
+/**
+ * Interface for objects that have a width and height (planar capacity).
+ */
+class _C2PlanarCapacityAspect {
+/// \name Planar capacity interface
+/// @{
+public:
+    inline constexpr uint32_t width() const { return _mWidth; }
+    inline constexpr uint32_t height() const { return _mHeight; }
+
+    inline constexpr operator C2Rect() const {
+        return C2Rect(_mWidth, _mHeight);
+    }
+
+protected:
+    inline constexpr _C2PlanarCapacityAspect(uint32_t width, uint32_t height)
+      : _mWidth(width), _mHeight(height) { }
+
+    inline explicit constexpr _C2PlanarCapacityAspect(const _C2PlanarCapacityAspect *parent)
+        : _mWidth(parent == nullptr ? 0 : parent->width()),
+          _mHeight(parent == nullptr ? 0 : parent->height()) { }
+
+private:
+    uint32_t _mWidth;
+    uint32_t _mHeight;
+/// @}
+};
+
+/**
+ * C2PlaneInfo: information on the layout of a singe flexible plane.
+ *
+ * Public fields without getters/setters.
+ */
+struct C2PlaneInfo {
+//public:
+    enum channel_t : uint32_t {
+        CHANNEL_Y,  ///< luma
+        CHANNEL_R,  ///< red
+        CHANNEL_G,  ///< green
+        CHANNEL_B,  ///< blue
+        CHANNEL_A,  ///< alpha
+        CHANNEL_CR, ///< Cr
+        CHANNEL_CB, ///< Cb
+    } channel;
+
+    int32_t colInc;       ///< column increment in bytes. may be negative
+    int32_t rowInc;       ///< row increment in bytes. may be negative
+
+    uint32_t colSampling; ///< subsampling compared to width (must be a power of 2)
+    uint32_t rowSampling; ///< subsampling compared to height (must be a power of 2)
+
+    uint32_t allocatedDepth; ///< size of each sample (must be a multiple of 8)
+    uint32_t bitDepth;       ///< significant bits per sample
+    /**
+     * the right shift of the significant bits in the sample. E.g. if a 10-bit significant
+     * value is laid out in a 16-bit allocation aligned to LSB (values 0-1023), rightShift
+     * would be 0 as the 16-bit value read from the sample does not need to be right shifted
+     * and can be used as is (after applying a 10-bit mask of 0x3FF).
+     *
+     * +--------+--------+
+     * |      VV|VVVVVVVV|
+     * +--------+--------+
+     *  15     8 7      0
+     *
+     * If the value is laid out aligned to MSB, rightShift would be 6, as the value read
+     * from the allocated sample must be right-shifted by 6 to get the actual sample value.
+     *
+     * +--------+--------+
+     * |VVVVVVVV|VV      |
+     * +--------+--------+
+     *  15     8 7      0
+     */
+    uint32_t rightShift;
+
+    enum endianness_t : uint32_t {
+        NATIVE,
+        LITTLE_END, // LITTLE_ENDIAN is reserved macro
+        BIG_END,    // BIG_ENDIAN is a reserved macro
+    } endianness; ///< endianness of the samples
+
+    /**
+     * The following two fields define the relation between multiple planes. If multiple planes are
+     * interleaved, they share a root plane (whichever plane's start address is the lowest), and
+     * |offset| is the offset of this plane inside the root plane (in bytes). |rootIx| is the index
+     * of the root plane. If a plane is independent, rootIx is its index and offset is 0.
+     */
+    uint32_t rootIx; ///< index of the root plane
+    uint32_t offset; ///< offset of this plane inside of the root plane
+
+    inline constexpr ssize_t minOffset(uint32_t width, uint32_t height) const {
+        ssize_t offs = 0;
+        if (width > 0 && colInc < 0) {
+            offs += colInc * (ssize_t)(width - 1);
+        }
+        if (height > 0 && rowInc < 0) {
+            offs += rowInc * (ssize_t)(height - 1);
+        }
+        return offs;
+    }
+
+    inline constexpr ssize_t maxOffset(uint32_t width, uint32_t height) const {
+        ssize_t offs = (allocatedDepth + 7) >> 3;
+        if (width > 0 && colInc > 0) {
+            offs += colInc * (ssize_t)(width - 1);
+        }
+        if (height > 0 && rowInc > 0) {
+            offs += rowInc * (ssize_t)(height - 1);
+        }
+        return offs;
+    }
+} C2_PACK;
+
+struct C2PlanarLayout {
+//public:
+    enum type_t : uint32_t {
+        TYPE_UNKNOWN = 0,
+        TYPE_YUV = 0x100,   ///< YUV image with 3 planes
+        TYPE_YUVA,          ///< YUVA image with 4 planes
+        TYPE_RGB,           ///< RGB image with 3 planes
+        TYPE_RGBA,          ///< RBGA image with 4 planes
+    };
+
+    type_t type;                    // image type
+    uint32_t numPlanes;             // number of component planes
+    uint32_t rootPlanes;            // number of layout planes (root planes)
+
+    enum plane_index_t : uint32_t {
+        PLANE_Y = 0,
+        PLANE_U = 1,
+        PLANE_V = 2,
+        PLANE_R = 0,
+        PLANE_G = 1,
+        PLANE_B = 2,
+        PLANE_A = 3,
+        MAX_NUM_PLANES = 4,
+    };
+
+    C2PlaneInfo planes[MAX_NUM_PLANES];
+};
+
+/**
+ * Aspect for objects that have a planar section (crop rectangle).
+ *
+ * This class is copiable.
+ */
+class _C2PlanarSectionAspect : public _C2PlanarCapacityAspect {
+/// \name Planar section interface
+/// @{
+private:
+    inline constexpr _C2PlanarSectionAspect(uint32_t width, uint32_t height, const C2Rect &crop)
+        : _C2PlanarCapacityAspect(width, height),
+          mCrop(C2Rect(std::min(width - std::min(crop.left, width), crop.width),
+                       std::min(height - std::min(crop.top, height), crop.height)).at(
+                               std::min(crop.left, width),
+                               std::min(crop.height, height))) {
+    }
+
+public:
+    // crop can be an empty rect, does not have to line up with subsampling
+    // NOTE: we do not support floating-point crop
+    inline constexpr C2Rect crop() const { return mCrop; }
+
+    /**
+     * Returns a child planar section for |crop|, where the capacity represents this section.
+     */
+    inline constexpr _C2PlanarSectionAspect childSection(const C2Rect &crop) const {
+        return _C2PlanarSectionAspect(
+                mCrop.width, mCrop.height,
+                // crop and translate |crop| rect
+                C2Rect(c2_min(mCrop.right() - c2_clamp(mCrop.left, crop.left, mCrop.right()),
+                              crop.width),
+                       c2_min(mCrop.bottom() - c2_clamp(mCrop.top, crop.top, mCrop.bottom()),
+                              crop.height))
+                .at(c2_clamp(mCrop.left, crop.left, mCrop.right()) - mCrop.left,
+                    c2_clamp(mCrop.top, crop.top, mCrop.bottom()) - mCrop.top));
+    }
+
+protected:
+    inline constexpr _C2PlanarSectionAspect(const _C2PlanarCapacityAspect *parent)
+        : _C2PlanarCapacityAspect(parent), mCrop(width(), height()) {}
+
+    inline constexpr _C2PlanarSectionAspect(const _C2PlanarCapacityAspect *parent, const C2Rect &crop)
+        : _C2PlanarCapacityAspect(parent),
+          mCrop(parent == nullptr ? C2Rect() : ((C2Rect)*parent).intersect(crop).normalize()) { }
+
+    inline constexpr _C2PlanarSectionAspect(const _C2PlanarSectionAspect *parent, const C2Rect &crop)
+        : _C2PlanarCapacityAspect(parent),
+          mCrop(parent == nullptr ? C2Rect() : parent->crop().intersect(crop).normalize()) { }
+
+private:
+    friend class _C2EditablePlanarSectionAspect;
+    C2Rect mCrop;
+/// @}
+};
+
+/**
+ * Aspect for objects that have an editable planar section (crop rectangle).
+ *
+ * This class is copiable.
+ */
+class _C2EditablePlanarSectionAspect : public _C2PlanarSectionAspect {
+/// \name Planar section interface
+/// @{
+    using _C2PlanarSectionAspect::_C2PlanarSectionAspect;
+
+public:
+    // crop can be an empty rect, does not have to line up with subsampling
+    // NOTE: we do not support floating-point crop
+    inline constexpr C2Rect crop() const { return mCrop; }
+
+    /**
+     *  Sets crop to crop intersected with [(0,0) .. (width, height)]
+     */
+    inline void setCrop_be(const C2Rect &crop) {
+        mCrop.left = std::min(width(), crop.left);
+        mCrop.top = std::min(height(), crop.top);
+        // It's guaranteed that mCrop.left <= width() && mCrop.top <= height()
+        mCrop.width = std::min(width() - mCrop.left, crop.width);
+        mCrop.height = std::min(height() - mCrop.top, crop.height);
+    }
+
+    /**
+     * If crop is within the dimensions of this object, it sets crop to it.
+     *
+     * \return true iff crop is within the dimensions of this object
+     */
+    inline bool setCrop(const C2Rect &crop) {
+        if (width() < crop.width || height() < crop.height
+                || width() - crop.width < crop.left || height() - crop.height < crop.top) {
+            return false;
+        }
+        mCrop = crop;
+        return true;
+    }
+/// @}
+};
+
+/**
+ * Utility class for safe range calculations using size_t-s.
+ */
+class C2PlanarSection : public _C2PlanarSectionAspect {
+public:
+    inline constexpr C2PlanarSection(const _C2PlanarCapacityAspect &parent, const C2Rect &crop)
+        : _C2PlanarSectionAspect(&parent, crop) { }
+
+    inline constexpr C2PlanarSection(const _C2PlanarSectionAspect &parent, const C2Rect &crop)
+        : _C2PlanarSectionAspect(&parent, crop) { }
+
+    inline constexpr C2PlanarSection intersect(const C2Rect &crop) const {
+        return C2PlanarSection(*this, crop);
+    }
+};
+
+/**
+ * Utility class for simple and safe planar capacity and section construction.
+ */
+class C2PlanarCapacity : public _C2PlanarCapacityAspect {
+public:
+    inline constexpr explicit C2PlanarCapacity(size_t width, size_t height)
+        : _C2PlanarCapacityAspect(c2_min(width, std::numeric_limits<uint32_t>::max()),
+                                  c2_min(height, std::numeric_limits<uint32_t>::max())) { }
+
+    inline constexpr C2PlanarSection section(const C2Rect &crop) const {
+        return C2PlanarSection(*this, crop);
+    }
+};
+
+
+/**
+ * \ingroup graphic allocator
+ * 2D allocation interface.
+ */
+class C2GraphicAllocation : public _C2PlanarCapacityAspect {
+public:
+    /**
+     * Maps a rectangular section (as defined by |rect|) of a 2D allocation into local process
+     * memory for flexible access. On success, it fills out |layout| with the plane specifications
+     * and fills the |addr| array with pointers to the first byte of the top-left pixel of each
+     * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fence| will contain
+     * an acquire sync fence object. If it is already safe to access the
+     * buffer contents, then it will be an empty (already fired) fence.
+     *
+     * Safe regions for the pointer addresses returned can be gotten via C2LayoutInfo.minOffset()/
+     * maxOffset().
+     *
+     * \param rect          section to be mapped (this does not have to be aligned)
+     * \param usage         the desired usage. \todo this must be kSoftwareRead and/or
+     *                      kSoftwareWrite.
+     * \param fence         a pointer to a fence object if an async mapping is requested. If
+     *                      not-null, and acquire fence will be stored here on success, or empty
+     *                      fence on failure. If null, the mapping will be synchronous.
+     * \param layout        a pointer to where the mapped planes' descriptors will be
+     *                      stored. On failure, nullptr will be stored here.
+     * \param addr          pointer to an array with at least C2PlanarLayout::MAX_NUM_PLANES
+     *                      elements. Only layout.numPlanes elements will be modified on success.
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_REFUSED   no permission to map the section
+     * \retval C2_DUPLICATE there is already a mapped region and this allocation cannot support
+     *                      multi-mapping (caller error)
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_NO_MEMORY not enough memory to complete the operation
+     * \retval C2_BAD_VALUE the parameters (rect) are invalid or outside the allocation, or the
+     *                      usage flags are invalid (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+
+     */
+    virtual c2_status_t map(
+            C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
+            C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
+
+    /**
+     * Unmaps a section of an allocation at |addr| with |rect|. These must be parameters previously
+     * passed to and returned by |map|; otherwise, this operation is a no-op.
+     *
+     * \param addr          pointer to an array with at least C2PlanarLayout::MAX_NUM_PLANES
+     *                      elements containing the starting addresses of the mapped layers
+     * \param rect          boundaries of the mapped section
+     * \param fence         a pointer to a fence object if an async unmapping is requested. If
+     *                      not-null, a release fence will be stored here on success, or empty fence
+     *                      on failure. This fence signals when the original allocation contains
+     *                      all changes that happened to the mapped section. If null, the unmapping
+     *                      will be synchronous.
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_NOT_FOUND there is no such mapped region (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+     * \retval C2_REFUSED   no permission to unmap the section (unexpected - system)
+     */
+    virtual c2_status_t unmap(
+            uint8_t **addr /* nonnull */, C2Rect rect, C2Fence *fence /* nullable */) = 0;
+
+    /**
+     * Returns the allocator ID for this allocation. This is useful to put the handle into context.
+     */
+    virtual C2Allocator::id_t getAllocatorId() const = 0;
+
+    /**
+     * Returns a pointer to the allocation handle.
+     */
+    virtual const C2Handle *handle() const = 0;
+
+    /**
+     * Returns true if this is the same allocation as |other|.
+     */
+    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const = 0;
+
+protected:
+    using _C2PlanarCapacityAspect::_C2PlanarCapacityAspect;
+    virtual ~C2GraphicAllocation() = default;
+};
+
+class C2GraphicAllocation;
+
+/**
+ * A 2D block.
+ *
+ * \note width()/height() is not meaningful for users of blocks; instead, crop().width() and
+ * crop().height() is the capacity of the usable portion. Use and crop() if accessing the block
+ * directly through its handle to represent the allotted region of the underlying allocation to this
+ * block.
+ */
+class C2Block2D : public _C2PlanarSectionAspect {
+public:
+    /**
+     * Returns the underlying handle for this allocation.
+     *
+     * \note that the block and its block pool has shared ownership of the handle
+     *       and if all references to the block are released, the underlying block
+     *       allocation may get reused even if a client keeps a clone of this handle.
+     */
+    const C2Handle *handle() const;
+
+    /**
+     * Returns the allocator's ID that created the underlying allocation for this block. This
+     * provides the context for understanding the handle.
+     */
+    C2Allocator::id_t getAllocatorId() const;
+
+protected:
+    class Impl;
+    C2Block2D(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section);
+
+    friend struct _C2BlockFactory;
+    std::shared_ptr<Impl> mImpl;
+};
+
+/**
+ * Graphic view provides read or read-write access for a graphic block.
+ *
+ * This class is copiable.
+ *
+ * \note Due to the subsampling of graphic buffers, a read view must still contain a crop rectangle
+ * to ensure subsampling is followed. This results in nearly identical interface between read and
+ * write views, so C2GraphicView can encompass both of them.
+ */
+class C2GraphicView : public _C2EditablePlanarSectionAspect {
+public:
+    /**
+     * \return array of pointers (of layout().numPlanes elements) to the start of the planes or
+     * nullptr on error. Regardless of crop rect, they always point to the top-left corner of each
+     * plane. Access outside of the crop rect results in an undefined behavior.
+     */
+    const uint8_t *const *data() const;
+
+    /**
+     * \return array of pointers (of layout().numPlanes elements) to the start of the planes or
+     * nullptr on error. Regardless of crop rect, they always point to the top-left corner of each
+     * plane. Access outside of the crop rect results in an undefined behavior.
+     */
+    uint8_t *const *data();
+
+    /**
+     * \return layout of the graphic block to interpret the returned data.
+     */
+    const C2PlanarLayout layout() const;
+
+    /**
+     * Returns a section of this view.
+     *
+     * \param rect    the dimension of the section. \note This is clamped to the crop of this view.
+     *
+     * \return a read view containing the requested section of this view
+     */
+    const C2GraphicView subView(const C2Rect &rect) const;
+    C2GraphicView subView(const C2Rect &rect);
+
+    /**
+     * \return error during the creation/mapping of this view.
+     */
+    c2_status_t error() const;
+
+protected:
+    class Impl;
+    C2GraphicView(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section);
+    explicit C2GraphicView(c2_status_t error);
+
+private:
+    friend struct _C2BlockFactory;
+    std::shared_ptr<Impl> mImpl;
+};
+
+/**
+ * A constant (read-only) graphic block (portion of an allocation) with an acquire fence.
+ * Blocks are unmapped when created, and can be mapped into a read view on demand.
+ *
+ * This class is copiable and contains a reference to the allocation that it is based on.
+ */
+class C2ConstGraphicBlock : public C2Block2D {
+public:
+    /**
+     * Maps this block into memory and returns a read view for it.
+     *
+     * \return a read view for this block.
+     */
+    C2Acquirable<const C2GraphicView> map() const;
+
+    /**
+     * Returns a section of this block.
+     *
+     * \param rect    the coordinates of the section. \note This is clamped to the crop rectangle of
+     *              this block.
+     *
+     * \return a constant graphic block containing a portion of this block
+     */
+    C2ConstGraphicBlock subBlock(const C2Rect &rect) const;
+
+    /**
+     * Returns the acquire fence for this block.
+     *
+     * \return a fence that must be waited on before reading the block.
+     */
+    C2Fence fence() const { return mFence; }
+
+protected:
+    C2ConstGraphicBlock(
+            std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section, C2Fence fence);
+
+private:
+    friend struct _C2BlockFactory;
+    C2Fence mFence;
+};
+
+/**
+ * Graphic block is a writeable 2D block. Once written, it can be shared in whole or in part with
+ * consumers/readers as read-only const graphic block.
+ */
+class C2GraphicBlock : public C2Block2D {
+public:
+    /**
+     * Maps this block into memory and returns a write view for it.
+     *
+     * \return a write view for this block.
+     */
+    C2Acquirable<C2GraphicView> map();
+
+    /**
+     * Creates a read-only const linear block for a portion of this block; optionally protected
+     * by an acquire fence. There are two ways to use this:
+     *
+     * 1) share ready block after writing data into the block. In this case no fence shall be
+     *    supplied, and the block shall not be modified after calling this method.
+     * 2) share block metadata before actually (finishing) writing the data into the block. In
+     *    this case a fence must be supplied that will be triggered when the data is written.
+     *    The block shall be modified only until firing the event for the fence.
+     */
+    C2ConstGraphicBlock share(const C2Rect &crop, C2Fence fence);
+
+protected:
+    C2GraphicBlock(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect &section);
+
+    friend struct _C2BlockFactory;
+};
+
+/// @}
+
+/// \defgroup buffer_onj Buffer objects
+/// @{
+
+// ================================================================================================
+//  BUFFERS
+// ================================================================================================
+
+/// \todo: Do we still need this?
+///
+// There are 2 kinds of buffers: linear or graphic. Linear buffers can contain a single block, or
+// a list of blocks (LINEAR_CHUNKS). Support for list of blocks is optional, and can allow consuming
+// data from circular buffers or scattered data sources without extra memcpy. Currently, list of
+// graphic blocks is not supported.
+
+class C2LinearBuffer;   // read-write buffer
+class C2GraphicBuffer;  // read-write buffer
+class C2LinearChunksBuffer;
+
+/**
+ * C2BufferData: the main, non-meta data of a buffer. A buffer can contain either linear blocks
+ * or graphic blocks, and can contain either a single block or multiple blocks. This is determined
+ * by its type.
+ */
+class C2BufferData {
+public:
+    /**
+     *  The type of buffer data.
+     */
+    enum type_t : uint32_t {
+        INVALID,            ///< invalid buffer type. Do not use.
+        LINEAR,             ///< the buffer contains a single linear block
+        LINEAR_CHUNKS,      ///< the buffer contains one or more linear blocks
+        GRAPHIC,            ///< the buffer contains a single graphic block
+        GRAPHIC_CHUNKS,     ///< the buffer contains one of more graphic blocks
+    };
+    typedef type_t Type; // deprecated
+
+    /**
+     * Gets the type of this buffer (data).
+     * \return the type of this buffer data.
+     */
+    type_t type() const;
+
+    /**
+     * Gets the linear blocks of this buffer.
+     * \return a constant list of const linear blocks of this buffer.
+     * \retval empty list if this buffer does not contain linear block(s).
+     */
+    const std::vector<C2ConstLinearBlock> linearBlocks() const;
+
+    /**
+     * Gets the graphic blocks of this buffer.
+     * \return a constant list of const graphic blocks of this buffer.
+     * \retval empty list if this buffer does not contain graphic block(s).
+     */
+    const std::vector<C2ConstGraphicBlock> graphicBlocks() const;
+
+private:
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
+
+protected:
+    // no public constructor
+    explicit C2BufferData(const std::vector<C2ConstLinearBlock> &blocks);
+    explicit C2BufferData(const std::vector<C2ConstGraphicBlock> &blocks);
+};
+
+/**
+ * C2Buffer: buffer base class. These are always used as shared_ptrs. Though the underlying buffer
+ * objects (native buffers, ion buffers, or dmabufs) are reference-counted by the system,
+ * C2Buffers hold only a single reference.
+ *
+ * These objects cannot be used on the stack.
+ */
+class C2Buffer {
+public:
+    /**
+     * Gets the buffer's data.
+     *
+     * \return the buffer's data.
+     */
+    const C2BufferData data() const;
+
+    /**
+     * These will still work if used in onDeathNotify.
+     */
+#if 0
+    inline std::shared_ptr<C2LinearBuffer> asLinearBuffer() const {
+        return mType == LINEAR ? std::shared_ptr::reinterpret_cast<C2LinearBuffer>(this) : nullptr;
+    }
+
+    inline std::shared_ptr<C2GraphicBuffer> asGraphicBuffer() const {
+        return mType == GRAPHIC ? std::shared_ptr::reinterpret_cast<C2GraphicBuffer>(this) : nullptr;
+    }
+
+    inline std::shared_ptr<C2CircularBuffer> asCircularBuffer() const {
+        return mType == CIRCULAR ? std::shared_ptr::reinterpret_cast<C2CircularBuffer>(this) : nullptr;
+    }
+#endif
+
+    ///@name Pre-destroy notification handling
+    ///@{
+
+    /**
+     * Register for notification just prior to the destruction of this object.
+     */
+    typedef void (*OnDestroyNotify) (const C2Buffer *buf, void *arg);
+
+    /**
+     * Registers for a pre-destroy notification. This is called just prior to the destruction of
+     * this buffer (when this buffer is no longer valid.)
+     *
+     * \param onDestroyNotify   the notification callback
+     * \param arg               an arbitrary parameter passed to the callback
+     *
+     * \retval C2_OK        the registration was successful.
+     * \retval C2_DUPLICATE a notification was already registered for this callback and argument
+     * \retval C2_NO_MEMORY not enough memory to register for this callback
+     * \retval C2_CORRUPTED an unknown error prevented the registration (unexpected)
+     */
+    c2_status_t registerOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg = nullptr);
+
+    /**
+     * Unregisters a previously registered pre-destroy notification.
+     *
+     * \param onDestroyNotify   the notification callback
+     * \param arg               an arbitrary parameter passed to the callback
+     *
+     * \retval C2_OK        the unregistration was successful.
+     * \retval C2_NOT_FOUND the notification was not found
+     * \retval C2_CORRUPTED an unknown error prevented the registration (unexpected)
+     */
+    c2_status_t unregisterOnDestroyNotify(OnDestroyNotify onDestroyNotify, void *arg = nullptr);
+
+    ///@}
+
+    virtual ~C2Buffer() = default;
+
+    ///@name Buffer-specific arbitrary metadata handling
+    ///@{
+
+    /**
+     * Gets the list of metadata associated with this buffer.
+     *
+     * \return a constant list of info objects associated with this buffer.
+     */
+    const std::vector<std::shared_ptr<const C2Info>> info() const;
+
+    /**
+     * Attaches (or updates) an (existing) metadata for this buffer.
+     * If the metadata is stream specific, the stream information will be reset.
+     *
+     * \param info Metadata to update
+     *
+     * \retval C2_OK        the metadata was successfully attached/updated.
+     * \retval C2_NO_MEMORY not enough memory to attach the metadata (this return value is not
+     *                      used if the same kind of metadata is already attached to the buffer).
+     */
+    c2_status_t setInfo(const std::shared_ptr<C2Info> &info);
+
+    /**
+     * Checks if there is a certain type of metadata attached to this buffer.
+     *
+     * \param index the parameter type of the metadata
+     *
+     * \return true iff there is a metadata with the parameter type attached to this buffer.
+     */
+    bool hasInfo(C2Param::Type index) const;
+
+    /**
+     * Checks if there is a certain type of metadata attached to this buffer, and returns a
+     * shared pointer to it if there is. Returns an empty shared pointer object (nullptr) if there
+     * is not.
+     *
+     * \param index the parameter type of the metadata
+     *
+     * \return shared pointer to the metadata.
+     */
+    std::shared_ptr<const C2Info> getInfo(C2Param::Type index) const;
+
+    /**
+     * Removes a metadata from the buffer.
+     */
+    std::shared_ptr<C2Info> removeInfo(C2Param::Type index);
+    ///@}
+
+    /**
+     * Creates a buffer containing a single linear block.
+     *
+     * \param block the content of the buffer.
+     *
+     * \return shared pointer to the created buffer.
+     */
+    static std::shared_ptr<C2Buffer> CreateLinearBuffer(const C2ConstLinearBlock &block);
+
+    /**
+     * Creates a buffer containing a single graphic block.
+     *
+     * \param block the content of the buffer.
+     *
+     * \return shared pointer to the created buffer.
+     */
+    static std::shared_ptr<C2Buffer> CreateGraphicBuffer(const C2ConstGraphicBlock &block);
+
+
+
+protected:
+    // no public constructor
+    explicit C2Buffer(const std::vector<C2ConstLinearBlock> &blocks);
+    explicit C2Buffer(const std::vector<C2ConstGraphicBlock> &blocks);
+
+private:
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
+//    Type _mType;
+};
+
+/**
+ * An extension of C2Info objects that can contain arbitrary buffer data.
+ *
+ * \note This object is not describable and contains opaque data.
+ */
+class C2InfoBuffer {
+public:
+    /**
+     * Gets the index of this info object.
+     *
+     * \return the parameter index.
+     */
+    const C2Param::Index index() const;
+
+    /**
+     * Gets the buffer's data.
+     *
+     * \return the buffer's data.
+     */
+    const C2BufferData data() const;
+};
+
+/// @}
+
+/// \cond INTERNAL
+
+/// \todo These are no longer used
+
+/// \addtogroup linear
+/// @{
+
+/** \deprecated */
+class C2LinearBuffer
+    : public C2Buffer, public _C2LinearRangeAspect,
+      public std::enable_shared_from_this<C2LinearBuffer> {
+public:
+    /** \todo what is this? */
+    const C2Handle *handle() const;
+
+protected:
+    inline C2LinearBuffer(const C2ConstLinearBlock &block);
+
+private:
+    class Impl;
+    Impl *mImpl;
+};
+
+class C2ReadCursor;
+
+class C2WriteCursor {
+public:
+    uint32_t remaining() const; // remaining data to be read
+    void commit(); // commits the current position. discard data before current position
+    void reset() const;  // resets position to the last committed position
+    // slices off at most |size| bytes, and moves cursor ahead by the number of bytes
+    // sliced off.
+    C2ReadCursor slice(uint32_t size) const;
+    // slices off at most |size| bytes, and moves cursor ahead by the number of bytes
+    // sliced off.
+    C2WriteCursor reserve(uint32_t size);
+    // bool read(T&);
+    // bool write(T&);
+    C2Fence waitForSpace(uint32_t size);
+};
+
+/// @}
+
+/// \addtogroup graphic
+/// @{
+
+struct C2ColorSpace {
+//public:
+    enum Standard {
+        BT601,
+        BT709,
+        BT2020,
+        // TODO
+    };
+
+    enum Range {
+        LIMITED,
+        FULL,
+        // TODO
+    };
+
+    enum TransferFunction {
+        BT709Transfer,
+        BT2020Transfer,
+        HybridLogGamma2,
+        HybridLogGamma4,
+        // TODO
+    };
+};
+
+/** \deprecated */
+class C2GraphicBuffer : public C2Buffer {
+public:
+    // constant attributes
+    inline uint32_t width() const  { return mWidth; }
+    inline uint32_t height() const { return mHeight; }
+    inline uint32_t format() const { return mFormat; }
+    inline const C2MemoryUsage usage() const { return mUsage; }
+
+    // modifiable attributes
+
+
+    virtual const C2ColorSpace colorSpace() const = 0;
+    // best effort
+    virtual void setColorSpace_be(const C2ColorSpace &colorSpace) = 0;
+    virtual bool setColorSpace(const C2ColorSpace &colorSpace) = 0;
+
+    const C2Handle *handle() const;
+
+protected:
+    uint32_t mWidth;
+    uint32_t mHeight;
+    uint32_t mFormat;
+    C2MemoryUsage mUsage;
+
+    class Impl;
+    Impl *mImpl;
+};
+
+/// @}
+
+/// \endcond
+
+/// @}
+
+#endif  // C2BUFFER_H_
diff --git a/media/codec2/include/C2BufferBase.h b/media/codec2/include/C2BufferBase.h
new file mode 100644
index 0000000..2bd48f0
--- /dev/null
+++ b/media/codec2/include/C2BufferBase.h
@@ -0,0 +1,94 @@
+/*
+ * 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 C2BUFFER_BASE_H_
+#define C2BUFFER_BASE_H_
+
+/// \defgroup allocator Allocation and memory placement
+/// @{
+
+/**
+ * Buffer/memory usage bits. These shall be used by the allocators to select optimal memory type/
+ * pool and buffer layout. Usage bits are conceptually separated into read and write usage, while
+ * the buffer use life-cycle is separated into producers (writers) and consumers (readers).
+ * These two concepts are related but not equivalent: consumers may only read buffers and only
+ * producers may write to buffers; note, however, that buffer producers may also want or need to
+ * read the buffers.
+ *
+ * Read and write buffer usage bits shall be or-ed to arrive at the full buffer usage. Admittedly,
+ * this does not account for the amount of reading and writing (e.g. a buffer may have one or more
+ * readers); however, the proper information necessary to properly weigh the various usages would be
+ * the amount of data read/written for each usage type. This would result in an integer array of
+ * size 64 (or the number of distinct usages) for memory usage, and likely such detailed information
+ * would not always be available.
+ *
+ * That platform-agnostic Codec 2.0 API only defines the bare minimum usages. Platforms shall define
+ * usage bits that are appropriate for the platform.
+ */
+struct C2MemoryUsage {
+// public:
+    /**
+     * Buffer read usage.
+     */
+    enum read_t : uint64_t {
+        /** Buffer is read by the CPU. */
+        CPU_READ        = 1 << 0,
+        /**
+         * Buffer shall only be read by trusted hardware. The definition of trusted hardware is
+         * platform specific, but this flag is reserved to prevent mapping this block into CPU
+         * readable memory resulting in bus fault. This flag can be used when buffer access must be
+         * protected.
+         */
+        READ_PROTECTED  = 1 << 1,
+    };
+
+    /**
+     * Buffer write usage.
+     */
+    enum write_t : uint64_t {
+        /** Buffer is writted to by the CPU. */
+        CPU_WRITE        = 1 << 2,
+        /**
+         * Buffer shall only be written to by trusted hardware. The definition of trusted hardware
+         * is platform specific, but this flag is reserved to prevent mapping this block into CPU
+         * writable memory resulting in bus fault. This flag can be used when buffer integrity must
+         * be protected.
+         */
+        WRITE_PROTECTED  = 1 << 3,
+    };
+
+    enum : uint64_t {
+        /**
+         * Buffer usage bits reserved for the platform. We don't separately reserve read and
+         * write usages as platforms may have asymmetric distribution between them.
+         */
+        PLATFORM_MASK     = ~(CPU_READ | CPU_WRITE | READ_PROTECTED | WRITE_PROTECTED),
+    };
+
+    /** Create a usage from separate consumer and producer usage mask. \deprecated */
+    inline C2MemoryUsage(uint64_t consumer, uint64_t producer)
+        : expected(consumer | producer) { }
+
+    inline explicit C2MemoryUsage(uint64_t expected_)
+        : expected(expected_) { }
+
+    uint64_t expected; // expected buffer usage
+};
+
+/// @}
+
+#endif  // C2BUFFER_BASE_H_
+
diff --git a/media/codec2/include/C2Component.h b/media/codec2/include/C2Component.h
new file mode 100644
index 0000000..8810725
--- /dev/null
+++ b/media/codec2/include/C2Component.h
@@ -0,0 +1,975 @@
+/*
+ * 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 C2COMPONENT_H_
+
+#define C2COMPONENT_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <list>
+#include <memory>
+#include <vector>
+#include <functional>
+
+#include <C2Enum.h>
+#include <C2Param.h>
+#include <C2Work.h>
+
+/// \defgroup components Components
+/// @{
+
+struct C2FieldSupportedValuesQuery {
+    enum type_t : uint32_t {
+        POSSIBLE, ///< query all possible values regardless of other settings
+        CURRENT,  ///< query currently possible values given dependent settings
+    };
+
+private:
+    C2ParamField _mField;
+    type_t _mType;
+public:
+    c2_status_t status;
+    C2FieldSupportedValues values;
+
+    C2FieldSupportedValuesQuery(const C2ParamField &field_, type_t type_)
+        : _mField(field_), _mType(type_), status(C2_NO_INIT) { }
+
+    static C2FieldSupportedValuesQuery
+    Current(const C2ParamField &field_) {
+        return C2FieldSupportedValuesQuery(field_, CURRENT);
+    }
+
+    static C2FieldSupportedValuesQuery
+    Possible(const C2ParamField &field_) {
+        return C2FieldSupportedValuesQuery(field_, POSSIBLE);
+    }
+
+    inline C2ParamField field() const { return _mField; };
+
+    inline type_t type() const { return _mType; }
+};
+
+/**
+ * Component interface object. This object contains all of the configuration of a potential or
+ * actual component. It can be created and used independently of an actual C2Component instance to
+ * query support and parameters for various component settings and configurations for a potential
+ * component. Actual components also expose this interface.
+ */
+
+class C2ComponentInterface {
+public:
+    // ALWAYS AVAILABLE METHODS
+    // =============================================================================================
+
+    /**
+     * Returns the name of this component or component interface object.
+     * This is a unique name for this component or component interface 'class'; however, multiple
+     * instances of this component SHALL have the same name.
+     *
+     * When attached to a component, this method MUST be supported in any component state.
+     * This call does not change the state nor the internal configuration of the component.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the name of this component or component interface object.
+     * \retval an empty string if there was not enough memory to allocate the actual name.
+     */
+    virtual C2String getName() const = 0;
+
+    /**
+     * Returns a unique ID for this component or interface object.
+     * This ID is used as work targets, unique work IDs, and when configuring tunneling.
+     *
+     * When attached to a component, this method MUST be supported in any component state.
+     * This call does not change the state nor the internal configuration of the component.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return a unique node ID for this component or component interface instance.
+     */
+    virtual c2_node_id_t getId() const = 0;
+
+    /**
+     * Queries a set of parameters from the component or interface object.
+     * Querying is performed at best effort: the component SHALL query all supported parameters and
+     * skip unsupported ones, heap allocated parameters that could not be allocated or parameters
+     * that could not be queried without blocking. Any errors are communicated in the return value.
+     * Additionally, preallocated (e.g. stack) parameters that could not be queried are invalidated.
+     * Invalid or blocking parameters to be allocated on the heap are omitted from the result.
+     *
+     * \note Parameter values do not depend on the order of query.
+     *
+     * \todo This method cannot be used to query info-buffers. Is that a problem?
+     *
+     * When attached to a component, this method MUST be supported in any component state except
+     * released.
+     * This call does not change the state nor the internal configuration of the component.
+     *
+     * This method has a variable blocking behavior based on state.
+     * In the stopped state this method MUST be "non-blocking" and return within 1ms.
+     * In the running states this method may be momentarily blocking, but MUST return within 5ms.
+     *
+     * \param[in,out] stackParams  a list of params queried. These are initialized specific to each
+     *                             setting; e.g. size and index are set and rest of the members are
+     *                             cleared.
+     *                             \note Flexible settings that are of incorrect size will be
+     *                             invalidated.
+     * \param[in] heapParamIndices a vector of param indices for params to be queried and returned
+     *                             on the heap. These parameters will be returned in heapParams.
+     *                             Unsupported param indices will be ignored.
+     * \param[in] mayBlock         if true (C2_MAY_BLOCK), implementation may momentarily block.
+     *                             Otherwise (C2_DONT_BLOCK), it must be "non-blocking".
+     * \param[out] heapParams      a list of params where to which the supported heap parameters
+     *                             will be appended in the order they appear in heapParamIndices.
+     *
+     * \retval C2_OK        all parameters could be queried
+     * \retval C2_BAD_INDEX all supported parameters could be queried, but some parameters were not
+     *                      supported
+     * \retval C2_BAD_STATE when called in the released component state (user error)
+     *                      (this error code is only allowed for interfaces connected to components)
+     * \retval C2_NO_MEMORY could not allocate memory for a supported parameter
+     * \retval C2_BLOCKING  the operation must block to complete but mayBlock is false
+     *                      (this error code is only allowed for interfaces connected to components)
+     * \retval C2_TIMED_OUT could not query the parameters within the time limit (unexpected)
+     *                      (this error code is only allowed for interfaces connected to components
+     *                      in the running state)
+     * \retval C2_CORRUPTED some unknown error prevented the querying of the parameters
+     *                      (unexpected)
+     *                      (this error code is only allowed for interfaces connected to components)
+     */
+    virtual c2_status_t query_vb(
+        const std::vector<C2Param*> &stackParams,
+        const std::vector<C2Param::Index> &heapParamIndices,
+        c2_blocking_t mayBlock,
+        std::vector<std::unique_ptr<C2Param>>* const heapParams) const = 0;
+
+    /**
+     * Sets a set of parameters for the component or interface object.
+     *
+     * Tuning is performed at best effort: the component SHALL process the configuration updates in
+     * the order they appear in |params|. If any parameter update fails, the component shall
+     * communicate the failure in the return value and in |failures|, and still process the
+     * remaining parameters. Unsupported parameters are skipped, though they are communicated in
+     * ther return value. Most parameters are updated at best effort - such that even if client
+     * specifies an unsupported value for a field, the closest supported value is used. On the
+     * other hand, strict parameters only accept specific values for their fields, and if the client
+     * specifies an unsupported value, the parameter setting shall fail for that field.
+     * If the client tries to change the value of a field that requires momentary blocking without
+     * setting |mayBlock| to C2_MAY_BLOCK, that parameter shall also be skipped and a specific
+     * return value shall be used. Final values for all parameters set are propagated back to the
+     * caller in |params|.
+     *
+     * \note Parameter tuning DOES depend on the order of the tuning parameters. E.g. some parameter
+     * update may allow some subsequent values for further parameter updates.
+     *
+     * When attached to a component, this method MUST be supported in any component state except
+     * released.
+     *
+     * This method has a variable blocking behavior based on state.
+     * In the stopped state this method MUST be "non-blocking" and return within 1ms.
+     * In the running states this method may be momentarily blocking, but MUST return within 5ms.
+     *
+     * \param[in,out] params a list of parameter updates. These will be updated to the actual
+     *                       parameter values after the updates (this is because tuning is performed
+     *                       at best effort).
+     *                       \todo params that could not be updated are not marked here, so are
+     *                       confusing - are they "existing" values or intended to be configured
+     *                       values?
+     * \param[in] mayBlock   if true (C2_MAY_BLOCK), implementation may momentarily block.
+     *                       Otherwise (C2_DONT_BLOCK), it must be "non-blocking".
+     * \param[out] failures  a list of parameter failures and optional guidance
+     *
+     * \retval C2_OK        all parameters could be updated successfully
+     * \retval C2_BAD_INDEX all supported parameters could be updated successfully, but some
+     *                      parameters were not supported
+     * \retval C2_BAD_VALUE some supported parameters could not be updated successfully because
+     *                      they contained unsupported values. These are returned in |failures|.
+     * \retval C2_BAD_STATE when called in the released component state (user error)
+     *                      (this error code is only allowed for interfaces connected to components)
+     * \retval C2_NO_MEMORY some supported parameters could not be updated successfully because
+     *                      they contained unsupported values, but could not allocate a failure
+     *                      object for them.
+     * \retval C2_TIMED_OUT could not set the parameters within the time limit (unexpected)
+     *                      (this error code is only allowed for interfaces connected to components
+     *                      in the running state)
+     * \retval C2_BLOCKING  the operation must block to complete but mayBlock is false
+     *                      (this error code is only allowed for interfaces connected to components)
+     * \retval C2_CORRUPTED some unknown error prevented the update of the parameters
+     *                      (unexpected)
+     *                      (this error code is only allowed for interfaces connected to components)
+     */
+    virtual c2_status_t config_vb(
+            const std::vector<C2Param*> &params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+
+    // TUNNELING
+    // =============================================================================================
+
+    /**
+     * Creates a tunnel from this component to the target component.
+     *
+     * If the component is successfully created, subsequent work items queued may include a
+     * tunneled path between these components.
+     *
+     * When attached to a component, this method MUST be supported in any component state except
+     * released.
+     *
+     * This method may be momentarily blocking, but MUST return within 5ms.
+     *
+     * \retval C2_OK        the tunnel was successfully created
+     * \retval C2_BAD_INDEX the target component does not exist
+     * \retval C2_DUPLICATE the tunnel already exists
+     * \retval C2_OMITTED   tunneling is not supported by this component
+     * \retval C2_CANNOT_DO the specific tunnel is not supported
+     * \retval C2_BAD_STATE when called in the released component state (user error)
+     *                      (this error code is only allowed for interfaces connected to components)
+     *
+     * \retval C2_TIMED_OUT could not create the tunnel within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented the creation of the tunnel (unexpected)
+     *                      (this error code is only allowed for interfaces connected to components)
+     */
+    virtual c2_status_t createTunnel_sm(c2_node_id_t targetComponent) = 0;
+
+    /**
+     * Releases a tunnel from this component to the target component.
+     *
+     * The release of a tunnel is delayed while there are pending work items for the tunnel.
+     * After releasing a tunnel, subsequent work items queued MUST NOT include a tunneled
+     * path between these components.
+     *
+     * When attached to a component, this method MUST be supported in any component state except
+     * released.
+     *
+     * This method may be momentarily blocking, but MUST return within 5ms.
+     *
+     * \retval C2_OK        the tunnel was marked for release successfully
+     * \retval C2_BAD_INDEX the target component does not exist
+     * \retval C2_NOT_FOUND the tunnel does not exist
+     * \retval C2_OMITTED   tunneling is not supported by this component
+     * \retval C2_BAD_STATE when called in the released component state (user error)
+     *                      (this error code is only allowed for interfaces connected to components)
+     *
+     * \retval C2_TIMED_OUT could not mark the tunnel for release within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented the release of the tunnel (unexpected)
+     *                      (this error code is only allowed for interfaces connected to components)
+     */
+    virtual c2_status_t releaseTunnel_sm(c2_node_id_t targetComponent) = 0;
+
+    // REFLECTION MECHANISM (USED FOR EXTENSION)
+    // =============================================================================================
+
+    /**
+     * Returns the set of supported parameters.
+     *
+     * When attached to a component, this method MUST be supported in any component state except
+     * released.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \param[out] params a vector of supported parameters will be appended to this vector.
+     *
+     * \retval C2_OK        the operation completed successfully.
+     * \retval C2_BAD_STATE when called in the released component state (user error)
+     *                      (this error code is only allowed for interfaces connected to components)
+     * \retval C2_NO_MEMORY not enough memory to complete this method.
+     */
+    virtual c2_status_t querySupportedParams_nb(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const = 0;
+
+    /**
+     * Retrieves the supported values for the queried fields.
+     *
+     * Client SHALL set the parameter-field specifier and the type of supported values query (e.g.
+     * currently supported values, or potential supported values) in fields.
+     * Upon return the component SHALL fill in the supported values for the fields listed as well
+     * as a status for each field. Component shall process all fields queried even if some queries
+     * fail.
+     *
+     * When attached to a component, this method MUST be supported in any component state except
+     * released.
+     *
+     * This method has a variable blocking behavior based on state.
+     * In the stopped state this method MUST be "non-blocking" and return within 1ms.
+     * In the running states this method may be momentarily blocking, but MUST return within 5ms.
+     *
+     * \param[in out] fields a vector of fields descriptor structures.
+     * \param[in] mayBlock   if true (C2_MAY_BLOCK), implementation may momentarily block.
+     *                       Otherwise (C2_DONT_BLOCK), it must be "non-blocking".
+     *
+     * \retval C2_OK        the operation completed successfully.
+     * \retval C2_BAD_STATE when called in the released component state (user error)
+     *                      (this error code is only allowed for interfaces connected to components)
+     * \retval C2_BAD_INDEX at least one field was not recognized as a component field
+     * \retval C2_TIMED_OUT could not query supported values within the time limit (unexpected)
+     *                      (this error code is only allowed for interfaces connected to components
+     *                      in the running state)
+     * \retval C2_BLOCKING  the operation must block to complete but mayBlock is false
+     *                      (this error code is only allowed for interfaces connected to components)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+     *                      (this error code is only allowed for interfaces connected to components)
+     */
+    virtual c2_status_t querySupportedValues_vb(
+            std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock) const = 0;
+
+    virtual ~C2ComponentInterface() = default;
+};
+
+class C2Component {
+public:
+    class Listener {
+    public:
+        virtual void onWorkDone_nb(std::weak_ptr<C2Component> component,
+                                std::list<std::unique_ptr<C2Work>> workItems) = 0;
+
+        virtual void onTripped_nb(std::weak_ptr<C2Component> component,
+                               std::vector<std::shared_ptr<C2SettingResult>> settingResult) = 0;
+
+        virtual void onError_nb(std::weak_ptr<C2Component> component,
+                             uint32_t errorCode) = 0;
+
+        // virtual void onTunnelReleased(<from>, <to>) = 0;
+
+        // virtual void onComponentReleased(<id>) = 0;
+
+        virtual ~Listener() = default;
+    };
+
+    /**
+     * Sets the listener for this component
+     *
+     * This method MUST be supported in all states except released.
+     * The listener can only be set to non-null value in stopped state (that does not include
+     * tripped or error). It can be set to nullptr in both stopped and running states.
+     * Components only use the listener in running state.
+     *
+     * If listener is nullptr, the component SHALL guarantee that no more listener callbacks are
+     * done to the original listener once this method returns. (Any pending listener callbacks will
+     * need to be completed during this call - hence this call may be temporarily blocking.)
+     *
+     * This method has a variable blocking behavior based on state.
+     * In the stopped state this method MUST be "non-blocking" and return within 1ms.
+     * In the running states this method may be momentarily blocking, but MUST return within 5ms.
+     *
+     * Component SHALL handle listener notifications from the same thread (the thread used is
+     * at the component's discretion.)
+     *
+     * \note This could also be accomplished by passing a weak_ptr to a component-specific listener
+     * here and requiring the client to always promote the weak_ptr before any callback. This would
+     * put the burden on the client to clear the listener - wait for its deletion - at which point
+     * it is guaranteed that no more listener callbacks will occur.
+     *
+     * \param[in] listener the component listener object
+     * \param[in] mayBlock if true (C2_MAY_BLOCK), implementation may momentarily block.
+     *                     Otherwise (C2_DONT_BLOCK), it must be "non-blocking".
+     *
+     * \retval C2_BAD_STATE attempting to change the listener in the running state to a non-null
+     *                      value (user error), or called in the released state
+     * \retval C2_BLOCKING  the operation must block to complete but mayBlock is false
+     * \retval C2_OK        listener was updated successfully.
+     */
+    virtual c2_status_t setListener_vb(
+            const std::shared_ptr<Listener> &listener, c2_blocking_t mayBlock) = 0;
+
+    /// component domain (e.g. audio or video)
+    enum domain_t : uint32_t;
+
+    /// component kind (e.g. encoder, decoder or filter)
+    enum kind_t : uint32_t;
+
+    /// component rank. This number is used to determine component ordering (the lower the sooner)
+    /// in the component list.
+    typedef uint32_t rank_t;
+
+    /// component attributes
+    enum attrib_t : uint64_t;
+
+    /**
+     * Information about a component.
+     */
+    struct Traits {
+    // public:
+        C2String name; ///< name of the component
+        domain_t domain; ///< component domain
+        kind_t kind; ///< component kind
+        rank_t rank; ///< component rank
+        C2String mediaType; ///< media type supported by the component
+
+        /**
+         * name alias(es) for backward compatibility.
+         * \note Multiple components can have the same alias as long as their media-type differs.
+         */
+        std::vector<C2StringLiteral> aliases; ///< name aliases for backward compatibility
+    };
+
+    // METHODS AVAILABLE WHEN RUNNING
+    // =============================================================================================
+
+    /**
+     * Queues up work for the component.
+     *
+     * This method MUST be supported in running (including tripped and error) states.
+     *
+     * This method MUST be "non-blocking" and return within 1 ms
+     *
+     * It is acceptable for this method to return OK and return an error value using the
+     * onWorkDone() callback.
+     *
+     * \retval C2_OK        the work was successfully queued
+     * \retval C2_BAD_INDEX some component(s) in the work do(es) not exist
+     * \retval C2_CANNOT_DO the components are not tunneled
+     * \retval C2_BAD_STATE when called in the stopped or released state (user error)
+     *
+     * \retval C2_NO_MEMORY not enough memory to queue the work
+     * \retval C2_CORRUPTED some unknown error prevented queuing the work (unexpected)
+     */
+    virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) = 0;
+
+    /**
+     * Announces a work to be queued later for the component. This reserves a slot for the queue
+     * to ensure correct work ordering even if the work is queued later.
+     *
+     * This method MUST be supported in running (including tripped and error) states.
+     *
+     * This method MUST be "non-blocking" and return within 1 ms
+     *
+     * \retval C2_OK        the work announcement has been successfully recorded
+     * \retval C2_BAD_INDEX some component(s) in the work outline do(es) not exist
+     * \retval C2_CANNOT_DO the componentes are not tunneled
+     * \retval C2_BAD_STATE when called in the stopped or released state (user error)
+     *
+     * \retval C2_NO_MEMORY not enough memory to record the work announcement
+     * \retval C2_CORRUPTED some unknown error prevented recording the announcement (unexpected)
+     *
+     * \todo Can this be rolled into queue_nb?
+     * \todo Expose next work item for each component to detect stalls
+     */
+    virtual c2_status_t announce_nb(const std::vector<C2WorkOutline> &items) = 0;
+
+    enum flush_mode_t : uint32_t {
+        /// flush work from this component only
+        FLUSH_COMPONENT,
+
+        /// flush work from this component and all components connected downstream from it via
+        /// tunneling
+        FLUSH_CHAIN = (1 << 16),
+    };
+
+    /**
+     * Discards and abandons any pending work for the component, and optionally any component
+     * downstream.
+     *
+     * \todo define this: we could flush all work before last item queued for component across all
+     *                    components linked to this; flush only work items that are queued to this
+     *                    component
+     * \todo return work # of last flushed item; or all flushed (but not returned items)
+     * \todo we could make flush take a work item and flush all work before/after that item to allow
+     *       TBD (slicing/seek?)
+     * \todo we could simply take a list of numbers and flush those... this is bad for decoders
+     *       also, what would happen to fine grade references?
+     *
+     * This method MUST be supported in running (including tripped and error) states.
+     *
+     * This method may be momentarily blocking, but must return within 5ms.
+     *
+     * Work that could be immediately abandoned/discarded SHALL be returned in |flushedWork|; this
+     * can be done in an arbitrary order.
+     *
+     * Work that could not be abandoned or discarded immediately SHALL be marked to be
+     * discarded at the earliest opportunity, and SHALL be returned via the onWorkDone() callback.
+     * This shall be completed within 500ms.
+     *
+     * \param mode flush mode
+     *
+     * \retval C2_OK        the component has been successfully flushed
+     * \retval C2_BAD_STATE when called in the stopped or released state (user error)
+     * \retval C2_TIMED_OUT the flush could not be completed within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented flushing from completion (unexpected)
+     */
+    virtual c2_status_t flush_sm(flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const flushedWork) = 0;
+
+    enum drain_mode_t : uint32_t {
+        /// drain component only and add an "end-of-stream" marker. Component shall process all
+        /// queued work and complete the current stream. If new input is received, it shall start
+        /// a new stream. \todo define what a stream is.
+        DRAIN_COMPONENT_WITH_EOS,
+        /// drain component without setting "end-of-stream" marker. Component shall process all
+        /// queued work but shall expect more work items for the same stream.
+        DRAIN_COMPONENT_NO_EOS = (1 << 0),
+
+        /// marks the last work item with a persistent "end-of-stream" marker that will drain
+        /// downstream components
+        /// \todo this may confuse work-ordering downstream
+        DRAIN_CHAIN = (1 << 16),
+
+        /**
+         * \todo define this; we could place EOS to all upstream components, just this component, or
+         *       all upstream and downstream component.
+         * \todo should EOS carry over to downstream components?
+         */
+    };
+
+    /**
+     * Drains the component, and optionally downstream components. This is a signalling method;
+     * as such it does not wait for any work completion.
+     *
+     * Marks last work item as "drain-till-here", so component is notified not to wait for further
+     * work before it processes work already queued. This method can also used to set the
+     * end-of-stream flag after work has been queued. Client can continue to queue further work
+     * immediately after this method returns.
+     *
+     * This method MUST be supported in running (including tripped) states.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * Work that is completed SHALL be returned via the onWorkDone() callback.
+     *
+     * \param mode drain mode
+     *
+     * \retval C2_OK        the drain request has been successfully recorded
+     * \retval C2_BAD_STATE when called in the stopped or released state (user error)
+     * \retval C2_BAD_VALUE the drain mode is not supported by the component
+     *                      \todo define supported modes discovery
+     * \retval C2_TIMED_OUT the flush could not be completed within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented flushing from completion (unexpected)
+     */
+    virtual c2_status_t drain_nb(drain_mode_t mode) = 0;
+
+    // STATE CHANGE METHODS
+    // =============================================================================================
+
+    /**
+     * Starts the component.
+     *
+     * This method MUST be supported in stopped state, as well as during the tripped state.
+     *
+     * If the return value is C2_OK, the component shall be in the running state.
+     * If the return value is C2_BAD_STATE or C2_DUPLICATE, no state change is expected as a
+     * response to this call.
+     * Otherwise, the component shall be in the stopped state.
+     *
+     * \note If a component is in the tripped state and start() is called while the component
+     * configuration still results in a trip, start shall succeed and a new onTripped callback
+     * should be used to communicate the configuration conflict that results in the new trip.
+     *
+     * \todo This method MUST return within 500ms. Seems this should be able to return quickly, as
+     * there are no immediate guarantees. Though there are guarantees for responsiveness immediately
+     * after start returns.
+     *
+     * \retval C2_OK        the component has started (or resumed) successfully
+     * \retval C2_DUPLICATE when called during another start call from another thread
+     * \retval C2_BAD_STATE when called in any state other than the stopped state or tripped state,
+     *                      including when called during another state change call from another
+     *                      thread (user error)
+     * \retval C2_NO_MEMORY not enough memory to start the component
+     * \retval C2_TIMED_OUT the component could not be started within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented starting the component (unexpected)
+     */
+    virtual c2_status_t start() = 0;
+
+    /**
+     * Stops the component.
+     *
+     * This method MUST be supported in running (including tripped) state.
+     *
+     * This method MUST return withing 500ms.
+     *
+     * Upon this call, all pending work SHALL be abandoned and all buffer references SHALL be
+     * released.
+     * If the return value is C2_BAD_STATE or C2_DUPLICATE, no state change is expected as a
+     * response to this call.
+     * For all other return values, the component shall be in the stopped state.
+     *
+     * \todo should this return completed work, since client will just free it? Perhaps just to
+     * verify accounting.
+     *
+     * This does not alter any settings and tunings that may have resulted in a tripped state.
+     * (Is this material given the definition? Perhaps in case we want to start again.)
+     *
+     * \retval C2_OK        the component has started successfully
+     * \retval C2_DUPLICATE when called during another stop call from another thread
+     * \retval C2_BAD_STATE when called in any state other than the running state, including when
+     *                      called during another state change call from another thread (user error)
+     * \retval C2_TIMED_OUT the component could not be stopped within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented stopping the component (unexpected)
+     */
+    virtual c2_status_t stop() = 0;
+
+    /**
+     * Resets the component.
+     *
+     * This method MUST be supported in all (including tripped) states other than released.
+     *
+     * This method MUST be supported during any other blocking call.
+     *
+     * This method MUST return withing 500ms.
+     *
+     * After this call returns all work SHALL be abandoned, all buffer references SHALL be released.
+     * If the return value is C2_BAD_STATE or C2_DUPLICATE, no state change is expected as a
+     * response to this call.
+     * For all other return values, the component shall be in the stopped state.
+     *
+     * \todo should this return completed work, since client will just free it? Also, if it unblocks
+     * a stop, where should completed work be returned?
+     *
+     * This brings settings back to their default - "guaranteeing" no tripped space.
+     *
+     * \todo reclaim support - it seems that since ownership is passed, this will allow reclaiming
+     * stuff.
+     *
+     * \retval C2_OK        the component has been reset
+     * \retval C2_DUPLICATE when called during another reset call from another thread
+     * \retval C2_BAD_STATE when called in the released state
+     * \retval C2_TIMED_OUT the component could not be reset within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented resetting the component (unexpected)
+     */
+    virtual c2_status_t reset() = 0;
+
+    /**
+     * Releases the component.
+     *
+     * This method MUST be supported in stopped state.
+     *
+     * This method MUST return withing 500ms. Upon return all references shall be abandoned.
+     *
+     * \retval C2_OK        the component has been released
+     * \retval C2_DUPLICATE the component is already released
+     * \retval C2_BAD_STATE the component is running
+     * \retval C2_TIMED_OUT the component could not be released within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented releasing the component (unexpected)
+     */
+    virtual c2_status_t release() = 0;
+
+    /**
+     * Returns the interface for this component.
+     *
+     * \return the component interface
+     */
+    virtual std::shared_ptr<C2ComponentInterface> intf() = 0;
+
+    virtual ~C2Component() = default;
+};
+
+C2ENUM(C2Component::kind_t, uint32_t,
+    KIND_OTHER,
+    KIND_DECODER,
+    KIND_ENCODER
+);
+
+C2ENUM(C2Component::domain_t, uint32_t,
+    DOMAIN_OTHER,
+    DOMAIN_VIDEO,
+    DOMAIN_AUDIO,
+    DOMAIN_IMAGE
+);
+
+class C2FrameInfoParser {
+public:
+    /**
+     * \return the content type supported by this info parser.
+     *
+     * \todo this may be redundant
+     */
+    virtual C2StringLiteral getType() const = 0;
+
+    /**
+     * \return a vector of supported parameter indices parsed by this info parser.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \todo sticky vs. non-sticky params? this may be communicated by param-reflector.
+     */
+    virtual const std::vector<C2Param::Index> getParsedParams() const = 0;
+
+    /**
+     * Resets this info parser. This brings this parser to its initial state after creation.
+     *
+     * This method SHALL return within 5ms.
+     *
+     * \retval C2_OK        the info parser was reset
+     * \retval C2_TIMED_OUT could not reset the parser within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented the resetting of the parser (unexpected)
+     */
+    virtual c2_status_t reset() { return C2_OK; }
+
+    virtual c2_status_t parseFrame(C2FrameData &frame);
+
+    virtual ~C2FrameInfoParser() = default;
+};
+
+class C2AllocatorStore {
+public:
+    typedef C2Allocator::id_t id_t;
+
+    enum : C2Allocator::id_t {
+        DEFAULT_LINEAR,     ///< basic linear allocator type
+        DEFAULT_GRAPHIC,    ///< basic graphic allocator type
+        PLATFORM_START = 0x10,
+        VENDOR_START   = 0x100,
+        BAD_ID         = C2Allocator::BAD_ID, ///< DO NOT USE
+    };
+
+    /**
+     * Returns the unique name of this allocator store.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the name of this allocator store.
+     * \retval an empty string if there was not enough memory to allocate the actual name.
+     */
+    virtual C2String getName() const = 0;
+
+    /**
+     * Returns the set of allocators supported by this allocator store.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \retval vector of allocator information (as shared pointers)
+     * \retval an empty vector if there was not enough memory to allocate the whole vector.
+     */
+    virtual std::vector<std::shared_ptr<const C2Allocator::Traits>> listAllocators_nb() const = 0;
+
+    /**
+     * Retrieves/creates a shared allocator object.
+     *
+     * This method MUST be return within 5ms.
+     *
+     * The allocator is created on first use, and the same allocator is returned on subsequent
+     * concurrent uses in the same process. The allocator is freed when it is no longer referenced.
+     *
+     * \param id      the ID of the allocator to create. This is defined by the store, but
+     *                the ID of the default linear and graphic allocators is formalized.
+     * \param allocator shared pointer where the created allocator is stored. Cleared on failure
+     *                  and updated on success.
+     *
+     * \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 no such allocator
+     * \retval C2_NO_MEMORY not enough memory to create the allocator
+     */
+    virtual c2_status_t fetchAllocator(id_t id, std::shared_ptr<C2Allocator>* const allocator) = 0;
+
+    virtual ~C2AllocatorStore() = default;
+};
+
+class C2ComponentStore {
+public:
+    /**
+     * Returns the name of this component or component interface object.
+     * This is a unique name for this component or component interface 'class'; however, multiple
+     * instances of this component SHALL have the same name.
+     *
+     * This method MUST be supported in any state. This call does not change the state nor the
+     * internal states of the component.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the name of this component or component interface object.
+     * \retval an empty string if there was not enough memory to allocate the actual name.
+     */
+    virtual C2String getName() const = 0;
+
+    /**
+     * Creates a component.
+     *
+     * This method SHALL return within 100ms.
+     *
+     * \param name          name of the component to create
+     * \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_NOT_FOUND no such component
+     * \retval C2_NO_MEMORY not enough memory to create the component
+     */
+    virtual c2_status_t createComponent(
+            C2String name, std::shared_ptr<C2Component>* const component) = 0;
+
+    /**
+     * Creates a component interface.
+     *
+     * This method SHALL return within 100ms.
+     *
+     * \param name          name of the component interface to create
+     * \param interface     shared pointer where the created interface is stored
+     *
+     * \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_NOT_FOUND no such component interface
+     * \retval C2_NO_MEMORY not enough memory to create the component interface
+     *
+     * \todo Do we need an interface, or could this just be a component that is never started?
+     */
+    virtual c2_status_t createInterface(
+            C2String name, std::shared_ptr<C2ComponentInterface>* const interface) = 0;
+
+    /**
+     * Returns the list of components supported by this component store.
+     *
+     * This method MUST return within 500ms.
+     *
+     * \retval vector of component information.
+     */
+    virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() = 0;
+
+    // -------------------------------------- UTILITY METHODS --------------------------------------
+
+    // on-demand buffer layout conversion (swizzling)
+    //
+    virtual c2_status_t copyBuffer(
+            std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst) = 0;
+
+    // -------------------------------------- CONFIGURATION API -----------------------------------
+    // e.g. for global settings (system-wide stride, etc.)
+
+    /**
+     * Queries a set of system-wide parameters.
+     * Querying is performed at best effort: the store SHALL query all supported parameters and
+     * skip unsupported ones, or heap allocated parameters that could not be allocated. Any errors
+     * are communicated in the return value. Additionally, preallocated (e.g. stack) parameters that
+     * could not be queried are invalidated. Parameters to be allocated on the heap are omitted from
+     * the result.
+     *
+     * \note Parameter values do not depend on the order of query.
+     *
+     * This method may be momentarily blocking, but MUST return within 5ms.
+     *
+     * \param stackParams   a list of params queried. These are initialized specific to each
+     *                      setting; e.g. size and index are set and rest of the members are
+     *                      cleared.
+     *                      NOTE: Flexible settings that are of incorrect size will be invalidated.
+     * \param heapParamIndices a vector of param indices for params to be queried and returned on the
+     *                      heap. These parameters will be returned in heapParams. Unsupported param
+     *                      indices will be ignored.
+     * \param heapParams    a list of params where to which the supported heap parameters will be
+     *                      appended in the order they appear in heapParamIndices.
+     *
+     * \retval C2_OK        all parameters could be queried
+     * \retval C2_BAD_INDEX all supported parameters could be queried, but some parameters were not
+     *                      supported
+     * \retval C2_NO_MEMORY could not allocate memory for a supported parameter
+     * \retval C2_CORRUPTED some unknown error prevented the querying of the parameters
+     *                      (unexpected)
+     */
+    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 = 0;
+
+    /**
+     * Sets a set of system-wide parameters.
+     *
+     * \note There are no settable system-wide parameters defined thus far, but may be added in the
+     * future.
+     *
+     * Tuning is performed at best effort: the store SHALL update all supported configuration at
+     * best effort (unless configured otherwise) and skip unsupported ones. Any errors are
+     * communicated in the return value and in |failures|.
+     *
+     * \note Parameter tuning DOES depend on the order of the tuning parameters. E.g. some parameter
+     * update may allow some subsequent parameter update.
+     *
+     * This method may be momentarily blocking, but MUST return within 5ms.
+     *
+     * \param params        a list of parameter updates. These will be updated to the actual
+     *                      parameter values after the updates (this is because tuning is performed
+     *                      at best effort).
+     *                      \todo params that could not be updated are not marked here, so are
+     *                      confusing - are they "existing" values or intended to be configured
+     *                      values?
+     * \param failures      a list of parameter failures
+     *
+     * \retval C2_OK        all parameters could be updated successfully
+     * \retval C2_BAD_INDEX all supported parameters could be updated successfully, but some
+     *                      parameters were not supported
+     * \retval C2_BAD_VALUE some supported parameters could not be updated successfully because
+     *                      they contained unsupported values. These are returned in |failures|.
+     * \retval C2_NO_MEMORY some supported parameters could not be updated successfully because
+     *                      they contained unsupported values, but could not allocate a failure
+     *                      object for them.
+     * \retval C2_CORRUPTED some unknown error prevented the update of the parameters
+     *                      (unexpected)
+     */
+    virtual c2_status_t config_sm(
+            const std::vector<C2Param*> &params,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+
+    // REFLECTION MECHANISM (USED FOR EXTENSION)
+    // =============================================================================================
+
+    /**
+     * Returns the parameter reflector.
+     *
+     * This is used to describe parameter fields. This is shared for all components created by
+     * this component store.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return a shared parameter reflector object.
+     */
+    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const = 0;
+
+    /**
+     * Returns the set of supported parameters.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \param[out] params a vector of supported parameters will be appended to this vector.
+     *
+     * \retval C2_OK        the operation completed successfully.
+     * \retval C2_NO_MEMORY not enough memory to complete this method.
+     */
+    virtual c2_status_t querySupportedParams_nb(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const = 0;
+
+    /**
+     * Retrieves the supported values for the queried fields.
+     *
+     * Client SHALL set the parameter-field specifier and the type of supported values query (e.g.
+     * currently supported values, or potential supported values) in fields.
+     * Upon return the store SHALL fill in the supported values for the fields listed as well
+     * as a status for each field. Store shall process all fields queried even if some queries
+     * fail.
+     *
+     * This method may be momentarily blocking, but MUST return within 5ms.
+     *
+     * \param[in out] fields a vector of fields descriptor structures.
+     *
+     * \retval C2_OK        the operation completed successfully.
+     * \retval C2_BAD_INDEX at least one field was not recognized as a component store field
+     */
+    virtual c2_status_t querySupportedValues_sm(
+            std::vector<C2FieldSupportedValuesQuery> &fields) const = 0;
+
+    virtual ~C2ComponentStore() = default;
+};
+
+// ================================================================================================
+
+/// @}
+
+#endif  // C2COMPONENT_H_
diff --git a/media/codec2/include/C2Config.h b/media/codec2/include/C2Config.h
new file mode 100644
index 0000000..799ade4
--- /dev/null
+++ b/media/codec2/include/C2Config.h
@@ -0,0 +1,2179 @@
+/*
+ * 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 C2CONFIG_H_
+#define C2CONFIG_H_
+
+#include <C2.h>
+#include <C2Component.h>
+#include <C2Enum.h>
+#include <C2ParamDef.h>
+
+/// \defgroup config Component configuration
+/// @{
+
+/**
+ * Enumerated boolean.
+ */
+C2ENUM(c2_bool_t, uint32_t,
+    C2_FALSE, ///< true
+    C2_TRUE,  ///< false
+)
+
+typedef C2SimpleValueStruct<c2_bool_t> C2BoolValue;
+
+typedef C2SimpleValueStruct<C2EasyEnum<c2_bool_t>> C2EasyBoolValue;
+
+/**
+ * Enumerated set tri-state.
+ *
+ * Used for optional configurations to distinguish between values set by the client,
+ * default values set by the component, or unset values.
+ */
+C2ENUM(c2_set_t, uint32_t,
+    C2_UNSET,   // parameter is unset and has no value
+    C2_SET,     // parameter is/has been set by the client
+    C2_DEFAULT, // parameter has not been set by the client, but is set by the component
+)
+
+/** Enumerations used by configuration parameters */
+struct C2Config {
+    enum aac_packaging_t : uint32_t;        ///< AAC packaging (RAW vs ADTS)
+    enum aac_sbr_mode_t : uint32_t;         ///< AAC SBR mode
+    enum api_feature_t : uint64_t;          ///< API features
+    enum api_level_t : uint32_t;            ///< API level
+    enum bitrate_mode_t : uint32_t;         ///< bitrate control mode
+    enum drc_compression_mode_t : int32_t;  ///< DRC compression mode
+    enum drc_effect_type_t : int32_t;       ///< DRC effect type
+    enum intra_refresh_mode_t : uint32_t;   ///< intra refresh modes
+    enum level_t : uint32_t;                ///< coding level
+    enum ordinal_key_t : uint32_t;          ///< work ordering keys
+    enum pcm_encoding_t : uint32_t;         ///< PCM encoding
+    enum picture_type_t : uint32_t;         ///< picture types
+    enum platform_feature_t : uint64_t;     ///< platform features
+    enum platform_level_t : uint32_t;       ///< platform level
+    enum prepend_header_mode_t : uint32_t;  ///< prepend header operational modes
+    enum profile_t : uint32_t;              ///< coding profile
+    enum scaling_method_t : uint32_t;       ///< scaling methods
+    enum scan_order_t : uint32_t;           ///< scan orders
+    enum secure_mode_t : uint32_t;          ///< secure/protected modes
+    enum supplemental_info_t : uint32_t;    ///< supplemental information types
+    enum tiling_mode_t : uint32_t;          ///< tiling modes
+};
+
+namespace {
+
+enum C2ParamIndexKind : C2Param::type_index_t {
+    C2_PARAM_INDEX_INVALID             = 0x0,    ///< do not use
+    C2_PARAM_INDEX_STRUCT_START        = 0x1,    ///< struct only indices
+    C2_PARAM_INDEX_PARAM_START         = 0x800,  ///< regular parameters
+    C2_PARAM_INDEX_CODER_PARAM_START   = 0x1000, ///< en/transcoder parameters
+    C2_PARAM_INDEX_PICTURE_PARAM_START = 0x1800, ///< image/video parameters
+    C2_PARAM_INDEX_VIDEO_PARAM_START   = 0x2000, ///< video parameters
+    C2_PARAM_INDEX_IMAGE_PARAM_START   = 0x2800, ///< image parameters
+    C2_PARAM_INDEX_AUDIO_PARAM_START   = 0x3000, ///< image parameters
+    C2_PARAM_INDEX_PLATFORM_START      = 0x4000, ///< platform-defined parameters
+
+    /* =================================== structure indices =================================== */
+
+    kParamIndexColorXy = C2_PARAM_INDEX_STRUCT_START,
+    kParamIndexMasteringDisplayColorVolume,
+    kParamIndexChromaOffset,
+    kParamIndexGopLayer,
+
+    /* =================================== parameter indices =================================== */
+
+    kParamIndexApiLevel = C2_PARAM_INDEX_PARAM_START,
+    kParamIndexApiFeatures,
+
+    /* ------------------------------------ all components ------------------------------------ */
+
+    /* generic component characteristics */
+    kParamIndexName,
+    kParamIndexAliases,
+    kParamIndexKind,
+    kParamIndexDomain,
+    kParamIndexAttributes,
+    kParamIndexTimeStretch,
+
+    /* coding characteristics */
+    kParamIndexProfileLevel,
+    kParamIndexInitData,
+    kParamIndexSupplementalData,
+    kParamIndexSubscribedSupplementalData,
+
+    /* pipeline characteristics */
+    kParamIndexMediaType,
+    kParamIndexDelayRequest,
+    kParamIndexDelay,
+    kParamIndexMaxReferenceAge,
+    kParamIndexMaxReferenceCount,
+    kParamIndexReorderBufferDepth,
+    kParamIndexReorderKey,
+    kParamIndexStreamCount,
+    kParamIndexSubscribedParamIndices,
+    kParamIndexSuggestedBufferCount,
+    kParamIndexBatchSize,
+    kParamIndexCurrentWork,
+    kParamIndexLastWorkQueued,
+
+    /* memory allocation */
+    kParamIndexAllocators,
+    kParamIndexBlockPools,
+    kParamIndexBufferType,
+    kParamIndexUsage,
+    kParamIndexOutOfMemory,
+    kParamIndexMaxBufferSize,
+
+    /* misc. state */
+    kParamIndexTripped,
+    kParamIndexConfigCounter,
+
+    /* resources */
+    kParamIndexResourcesNeeded,
+    kParamIndexResourcesReserved,
+    kParamIndexOperatingRate,
+    kParamIndexRealTimePriority,
+
+    /* protected content */
+    kParamIndexSecureMode,
+
+    /* ------------------------------------ (trans/en)coders ------------------------------------ */
+
+    kParamIndexBitrate = C2_PARAM_INDEX_CODER_PARAM_START,
+    kParamIndexBitrateMode,
+    kParamIndexQuality,
+    kParamIndexComplexity,
+    kParamIndexPrependHeaderMode,
+
+    /* --------------------------------- image/video components --------------------------------- */
+
+    kParamIndexPictureSize = C2_PARAM_INDEX_PICTURE_PARAM_START,
+    kParamIndexCropRect,
+    kParamIndexPixelFormat,
+    kParamIndexRotation,
+    kParamIndexPixelAspectRatio,
+    kParamIndexScaledPictureSize,
+    kParamIndexScaledCropRect,
+    kParamIndexScalingMethod,
+    kParamIndexColorInfo,
+    kParamIndexColorAspects,
+    kParamIndexHdrStaticMetadata,
+    kParamIndexDefaultColorAspects,
+
+    kParamIndexBlockSize,
+    kParamIndexBlockCount,
+    kParamIndexBlockRate,
+
+    kParamIndexPictureTypeMask,
+    kParamIndexPictureType,
+
+    /* ------------------------------------ video components ------------------------------------ */
+
+    kParamIndexFrameRate = C2_PARAM_INDEX_VIDEO_PARAM_START,
+    kParamIndexMaxBitrate,
+    kParamIndexMaxFrameRate,
+    kParamIndexMaxPictureSize,
+    kParamIndexGop,
+    kParamIndexSyncFrameInterval,
+    kParamIndexRequestSyncFrame,
+    kParamIndexTemporalLayering,
+    kParamIndexLayerIndex,
+    kParamIndexLayerCount,
+    kParamIndexIntraRefresh,
+
+    /* ------------------------------------ image components ------------------------------------ */
+
+    kParamIndexTileLayout = C2_PARAM_INDEX_IMAGE_PARAM_START,
+    kParamIndexTileHandling,
+
+    /* ------------------------------------ audio components ------------------------------------ */
+
+    kParamIndexSampleRate = C2_PARAM_INDEX_AUDIO_PARAM_START,
+    kParamIndexChannelCount,
+    kParamIndexPcmEncoding,
+    kParamIndexAacPackaging,
+    kParamIndexMaxChannelCount,
+    kParamIndexAacSbrMode, // aac encode, enum
+    kParamIndexDrcEncodedTargetLevel,  // drc, float (dBFS)
+    kParamIndexDrcTargetReferenceLevel, // drc, float (dBFS)
+    kParamIndexDrcCompression, // drc, enum
+    kParamIndexDrcBoostFactor, // drc, float (0-1)
+    kParamIndexDrcAttenuationFactor, // drc, float (0-1)
+    kParamIndexDrcEffectType, // drc, enum
+
+    /* ============================== platform-defined parameters ============================== */
+
+    kParamIndexPlatformLevel = C2_PARAM_INDEX_PLATFORM_START, // all, u32
+    kParamIndexPlatformFeatures, // all, u64 mask
+    kParamIndexStoreIonUsage, // store, struct
+    kParamIndexAspectsToDataSpace, // store, struct
+    kParamIndexFlexiblePixelFormatDescriptor, // store, struct
+    kParamIndexFlexiblePixelFormatDescriptors, // store, struct[]
+    kParamIndexDataSpaceToAspects, // store, struct
+    kParamIndexDataSpace, // u32
+    kParamIndexSurfaceScaling, // u32
+
+    // input surface
+    kParamIndexInputSurfaceEos, // input-surface, eos
+    kParamIndexTimedControl, // struct
+    kParamIndexStartAt, // input-surface, struct
+    kParamIndexSuspendAt, // input-surface, struct
+    kParamIndexResumeAt, // input-surface, struct
+    kParamIndexStopAt, // input-surface, struct
+    kParamIndexTimeOffset, // input-surface, struct
+    kParamIndexMinFrameRate, // input-surface, float
+    kParamIndexTimestampGapAdjustment, // input-surface, struct
+
+    kParamIndexSurfaceAllocator, // u32
+
+    // deprecated indices due to renaming
+    kParamIndexAacStreamFormat = kParamIndexAacPackaging,
+    kParamIndexCsd = kParamIndexInitData,
+    kParamIndexMaxVideoSizeHint = kParamIndexMaxPictureSize,
+    kParamIndexMime = kParamIndexMediaType,
+    kParamIndexRequestedInfos = kParamIndexSubscribedParamIndices,
+
+
+    // deprecated indices due to removal
+    kParamIndexSupportedParams = 0xDEAD0000,
+    kParamIndexReadOnlyParams,
+    kParamIndexTemporal,
+};
+
+}
+
+/**
+ * Codec 2.0 parameter types follow the following naming convention:
+ *
+ * C2<group><domain><index><type>
+ *
+ * E.g. C2StreamPictureSizeInfo: group="" domain="Stream" index="PictureSize" type="Info".
+ * Group is somewhat arbitrary, but denotes kind of objects the parameter is defined.
+ * At this point we use Component and Store to distinguish basic component/store parameters.
+ *
+ * Parameter keys are named C2_PARAMKEY_[<group>_]<domain>_<index> as type is not expected
+ * to distinguish parameters. E.g. a component could change the type of the parameter and it
+ * is not expected users would need to change the key.
+ */
+
+/* ----------------------------------------- API level ----------------------------------------- */
+
+enum C2Config::api_level_t : uint32_t {
+    API_L0_1 = 0,   ///< support for API level 0.1
+};
+
+// read-only
+typedef C2GlobalParam<C2Setting, C2SimpleValueStruct<C2Config::api_level_t>, kParamIndexApiLevel>
+        C2ApiLevelSetting;
+constexpr char C2_PARAMKEY_API_LEVEL[] = "api.level";
+
+enum C2Config::api_feature_t : uint64_t {
+    API_REFLECTION       = (1U << 0),  ///< ability to list supported parameters
+    API_VALUES           = (1U << 1),  ///< ability to list supported values for each parameter
+    API_CURRENT_VALUES   = (1U << 2),  ///< ability to list currently supported values for each parameter
+    API_DEPENDENCY       = (1U << 3),  ///< have a defined parameter dependency
+
+    API_STREAMS          = (1ULL << 32),  ///< supporting variable number of streams
+
+    API_TUNNELING        = (1ULL << 48),  ///< tunneling API
+};
+
+// read-only
+typedef C2GlobalParam<C2Setting, C2SimpleValueStruct<C2Config::api_feature_t>, kParamIndexApiFeatures>
+        C2ApiFeaturesSetting;
+constexpr char C2_PARAMKEY_API_FEATURES[] = "api.features";
+
+/* ----------------------------- generic component characteristics ----------------------------- */
+
+/**
+ * The name of the component.
+ *
+ * This must contain only alphanumeric characters or dot '.', hyphen '-', plus '+', or
+ * underline '_'. The name of each component must be unique.
+ *
+ * For Android: Component names must start with 'c2.' followed by the company name or abbreviation
+ * and another dot, e.g. 'c2.android.'. Use of lowercase is preferred but not required.
+ */
+// read-only
+typedef C2GlobalParam<C2Setting, C2StringValue, kParamIndexName> C2ComponentNameSetting;
+constexpr char C2_PARAMKEY_COMPONENT_NAME[]  = "component.name";
+
+/**
+ * Alternate names (aliases) of the component.
+ *
+ * This is a comma ',' separated list of alternate component names. Unlike component names that
+ * must be unique, multiple components can have the same alias.
+ */
+// read-only
+typedef C2GlobalParam<C2Setting, C2StringValue, kParamIndexAliases> C2ComponentAliasesSetting;
+constexpr char C2_PARAMKEY_COMPONENT_ALIASES[]  = "component.aliases";
+
+/**
+ * Component kind.
+ */
+// read-only
+typedef C2GlobalParam<C2Setting, C2SimpleValueStruct<C2Component::kind_t>, kParamIndexKind>
+        C2ComponentKindSetting;
+constexpr char C2_PARAMKEY_COMPONENT_KIND[]  = "component.kind";
+
+/**
+ * Component domain.
+ */
+// read-only
+typedef C2GlobalParam<C2Setting, C2SimpleValueStruct<C2Component::domain_t>, kParamIndexDomain>
+        C2ComponentDomainSetting;
+typedef C2ComponentDomainSetting C2ComponentDomainInfo; // deprecated
+typedef C2Component::domain_t C2DomainKind; // deprecated
+constexpr char C2_PARAMKEY_COMPONENT_DOMAIN[]  = "component.domain";
+
+constexpr C2Component::domain_t C2DomainAudio = C2Component::DOMAIN_AUDIO; // deprecated
+constexpr C2Component::domain_t C2DomainOther = C2Component::DOMAIN_OTHER; // deprecate
+constexpr C2Component::domain_t C2DomainVideo = C2Component::DOMAIN_VIDEO; // deprecate
+
+/**
+ * Component attributes.
+ *
+ * These are a set of flags provided by the component characterizing its processing algorithm.
+ */
+C2ENUM(C2Component::attrib_t, uint64_t,
+    ATTRIB_IS_TEMPORAL = 1u << 0, ///< component input ordering matters for processing
+)
+
+// read-only
+typedef C2GlobalParam<C2Setting, C2SimpleValueStruct<C2Component::attrib_t>, kParamIndexAttributes>
+        C2ComponentAttributesSetting;
+constexpr char C2_PARAMKEY_COMPONENT_ATTRIBUTES[] = "component.attributes";
+
+// deprecated
+typedef C2ComponentAttributesSetting C2ComponentTemporalInfo;
+
+/**
+ * Time stretching.
+ *
+ * This is the ratio between the rate of the input timestamp, and the rate of the output timestamp.
+ * E.g. if this is 4.0, for every 1 seconds of input timestamp difference, the output shall differ
+ * by 4 seconds.
+ */
+typedef C2GlobalParam<C2Tuning, C2FloatValue, kParamIndexTimeStretch> C2ComponentTimeStretchTuning;
+constexpr char C2_PARAMKEY_TIME_STRETCH[]  = "algo.time-stretch";
+
+/* ----------------------------------- coding characteristics ----------------------------------- */
+
+/**
+ * Profile and level.
+ *
+ * Profile determines the tools used by the component.
+ * Level determines the level of resources used by the component.
+ */
+
+namespace {
+
+enum : uint32_t {
+    _C2_PL_MP2V_BASE = 0x1000,
+    _C2_PL_AAC_BASE  = 0x2000,
+    _C2_PL_H263_BASE = 0x3000,
+    _C2_PL_MP4V_BASE = 0x4000,
+    _C2_PL_AVC_BASE  = 0x5000,
+    _C2_PL_HEVC_BASE = 0x6000,
+    _C2_PL_VP9_BASE  = 0x7000,
+    _C2_PL_DV_BASE   = 0x8000,
+
+    C2_PROFILE_LEVEL_VENDOR_START = 0x70000000,
+};
+
+}
+
+enum C2Config::profile_t : uint32_t {
+    PROFILE_UNUSED = 0,                         ///< profile is not used by this media type
+
+    // AAC (MPEG-2 Part 7 and MPEG-4 Part 3) profiles
+    PROFILE_AAC_LC = _C2_PL_AAC_BASE,           ///< AAC Low-Complexity
+    PROFILE_AAC_MAIN,                           ///< AAC Main
+    PROFILE_AAC_SSR,                            ///< AAC Scalable Sampling Rate
+    PROFILE_AAC_LTP,                            ///< AAC Long Term Prediction
+    PROFILE_AAC_HE,                             ///< AAC High-Efficiency
+    PROFILE_AAC_SCALABLE,                       ///< AAC Scalable
+    PROFILE_AAC_ER_LC,                          ///< AAC Error Resilient Low-Complexity
+    PROFILE_AAC_ER_SCALABLE,                    ///< AAC Error Resilient Scalable
+    PROFILE_AAC_LD,                             ///< AAC Low Delay
+    PROFILE_AAC_HE_PS,                          ///< AAC High-Efficiency Parametric Stereo
+    PROFILE_AAC_ELD,                            ///< AAC Enhanced Low Delay
+    PROFILE_AAC_XHE,                            ///< AAC Extended High-Efficiency
+
+    // MPEG-2 Video profiles
+    PROFILE_MP2V_SIMPLE = _C2_PL_MP2V_BASE,     ///< MPEG-2 Video (H.262) Simple
+    PROFILE_MP2V_MAIN,                          ///< MPEG-2 Video (H.262) Main
+    PROFILE_MP2V_SNR_SCALABLE,                  ///< MPEG-2 Video (H.262) SNR Scalable
+    PROFILE_MP2V_SPATIALLY_SCALABLE,            ///< MPEG-2 Video (H.262) Spatially Scalable
+    PROFILE_MP2V_HIGH,                          ///< MPEG-2 Video (H.262) High
+    PROFILE_MP2V_422,                           ///< MPEG-2 Video (H.262) 4:2:2
+    PROFILE_MP2V_MULTIVIEW,                     ///< MPEG-2 Video (H.262) Multi-view
+
+    // H.263 profiles
+    PROFILE_H263_BASELINE = _C2_PL_H263_BASE,   ///< H.263 Baseline (Profile 0)
+    PROFILE_H263_H320,                          ///< H.263 H.320 Coding Efficiency Version 2 Backward-Compatibility (Profile 1)
+    PROFILE_H263_V1BC,                          ///< H.263 Version 1 Backward-Compatibility (Profile 2)
+    PROFILE_H263_ISWV2,                         ///< H.263 Version 2 Interactive and Streaming Wireless (Profile 3)
+    PROFILE_H263_ISWV3,                         ///< H.263 Version 3 Interactive and Streaming Wireless (Profile 4)
+    PROFILE_H263_HIGH_COMPRESSION,              ///< H.263 Conversational High Compression (Profile 5)
+    PROFILE_H263_INTERNET,                      ///< H.263 Conversational Internet (Profile 6)
+    PROFILE_H263_INTERLACE,                     ///< H.263 Conversational Interlace (Profile 7)
+    PROFILE_H263_HIGH_LATENCY,                  ///< H.263 High Latency (Profile 8)
+
+    // MPEG-4 Part 2 (Video) Natural Visual Profiles
+    PROFILE_MP4V_SIMPLE,                        ///< MPEG-4 Video Simple
+    PROFILE_MP4V_SIMPLE_SCALABLE,               ///< MPEG-4 Video Simple Scalable
+    PROFILE_MP4V_CORE,                          ///< MPEG-4 Video Core
+    PROFILE_MP4V_MAIN,                          ///< MPEG-4 Video Main
+    PROFILE_MP4V_NBIT,                          ///< MPEG-4 Video N-Bit
+    PROFILE_MP4V_ARTS,                          ///< MPEG-4 Video Advanced Realtime Simple
+    PROFILE_MP4V_CORE_SCALABLE,                 ///< MPEG-4 Video Core Scalable
+    PROFILE_MP4V_ACE,                           ///< MPEG-4 Video Advanced Coding Efficiency
+    PROFILE_MP4V_ADVANCED_CORE,                 ///< MPEG-4 Video Advanced Core
+    PROFILE_MP4V_SIMPLE_STUDIO,                 ///< MPEG-4 Video Simple Studio
+    PROFILE_MP4V_CORE_STUDIO,                   ///< MPEG-4 Video Core Studio
+    PROFILE_MP4V_ADVANCED_SIMPLE,               ///< MPEG-4 Video Advanced Simple
+    PROFILE_MP4V_FGS,                           ///< MPEG-4 Video Fine Granularity Scalable
+
+    // AVC / MPEG-4 Part 10 (H.264) profiles
+    PROFILE_AVC_BASELINE = _C2_PL_AVC_BASE,     ///< AVC (H.264) Baseline
+    PROFILE_AVC_CONSTRAINED_BASELINE,           ///< AVC (H.264) Constrained Baseline
+    PROFILE_AVC_MAIN,                           ///< AVC (H.264) Main
+    PROFILE_AVC_EXTENDED,                       ///< AVC (H.264) Extended
+    PROFILE_AVC_HIGH,                           ///< AVC (H.264) High
+    PROFILE_AVC_PROGRESSIVE_HIGH,               ///< AVC (H.264) Progressive High
+    PROFILE_AVC_CONSTRAINED_HIGH,               ///< AVC (H.264) Constrained High
+    PROFILE_AVC_HIGH_10,                        ///< AVC (H.264) High 10
+    PROFILE_AVC_PROGRESSIVE_HIGH_10,            ///< AVC (H.264) Progressive High 10
+    PROFILE_AVC_HIGH_422,                       ///< AVC (H.264) High 4:2:2
+    PROFILE_AVC_HIGH_444_PREDICTIVE,            ///< AVC (H.264) High 4:4:4 Predictive
+    PROFILE_AVC_HIGH_10_INTRA,                  ///< AVC (H.264) High 10 Intra
+    PROFILE_AVC_HIGH_422_INTRA,                 ///< AVC (H.264) High 4:2:2 Intra
+    PROFILE_AVC_HIGH_444_INTRA,                 ///< AVC (H.264) High 4:4:4 Intra
+    PROFILE_AVC_CAVLC_444_INTRA,                ///< AVC (H.264) CAVLC 4:4:4 Intra
+    PROFILE_AVC_SCALABLE_BASELINE = _C2_PL_AVC_BASE + 0x100,  ///< AVC (H.264) Scalable Baseline
+    PROFILE_AVC_SCALABLE_CONSTRAINED_BASELINE,  ///< AVC (H.264) Scalable Constrained Baseline
+    PROFILE_AVC_SCALABLE_HIGH,                  ///< AVC (H.264) Scalable High
+    PROFILE_AVC_SCALABLE_CONSTRAINED_HIGH,      ///< AVC (H.264) Scalable Constrained High
+    PROFILE_AVC_SCALABLE_HIGH_INTRA,            ///< AVC (H.264) Scalable High Intra
+    PROFILE_AVC_MULTIVIEW_HIGH = _C2_PL_AVC_BASE + 0x200,  ///< AVC (H.264) Multiview High
+    PROFILE_AVC_STEREO_HIGH,                    ///< AVC (H.264) Stereo High
+    PROFILE_AVC_MFC_HIGH,                       ///< AVC (H.264) MFC High
+    PROFILE_AVC_MULTIVIEW_DEPTH_HIGH = _C2_PL_AVC_BASE + 0x300,  ///< AVC (H.264) Multiview Depth High
+    PROFILE_AVC_MFC_DEPTH_HIGH,                 ///< AVC (H.264) MFC Depth High
+    PROFILE_AVC_ENHANCED_MULTIVIEW_DEPTH_HIGH = _C2_PL_AVC_BASE + 0x400,  ///< AVC (H.264) Enhanced Multiview Depth High
+
+    // HEVC profiles
+    PROFILE_HEVC_MAIN = _C2_PL_HEVC_BASE,       ///< HEVC (H.265) Main
+    PROFILE_HEVC_MAIN_10,                       ///< HEVC (H.265) Main 10
+    PROFILE_HEVC_MAIN_STILL,                    ///< HEVC (H.265) Main Still Picture
+    PROFILE_HEVC_MONO = _C2_PL_HEVC_BASE + 0x100,  ///< HEVC (H.265) Monochrome
+    PROFILE_HEVC_MONO_12,                       ///< HEVC (H.265) Monochrome 12
+    PROFILE_HEVC_MONO_16,                       ///< HEVC (H.265) Monochrome 16
+    PROFILE_HEVC_MAIN_12,                       ///< HEVC (H.265) Main 12
+    PROFILE_HEVC_MAIN_422_10,                   ///< HEVC (H.265) Main 4:2:2 10
+    PROFILE_HEVC_MAIN_422_12,                   ///< HEVC (H.265) Main 4:2:2 12
+    PROFILE_HEVC_MAIN_444,                      ///< HEVC (H.265) Main 4:4:4
+    PROFILE_HEVC_MAIN_444_10,                   ///< HEVC (H.265) Main 4:4:4 10
+    PROFILE_HEVC_MAIN_444_12,                   ///< HEVC (H.265) Main 4:4:4 12
+    PROFILE_HEVC_MAIN_INTRA,                    ///< HEVC (H.265) Main Intra
+    PROFILE_HEVC_MAIN_10_INTRA,                 ///< HEVC (H.265) Main 10 Intra
+    PROFILE_HEVC_MAIN_12_INTRA,                 ///< HEVC (H.265) Main 12 Intra
+    PROFILE_HEVC_MAIN_422_10_INTRA,             ///< HEVC (H.265) Main 4:2:2 10 Intra
+    PROFILE_HEVC_MAIN_422_12_INTRA,             ///< HEVC (H.265) Main 4:2:2 12 Intra
+    PROFILE_HEVC_MAIN_444_INTRA,                ///< HEVC (H.265) Main 4:4:4 Intra
+    PROFILE_HEVC_MAIN_444_10_INTRA,             ///< HEVC (H.265) Main 4:4:4 10 Intra
+    PROFILE_HEVC_MAIN_444_12_INTRA,             ///< HEVC (H.265) Main 4:4:4 12 Intra
+    PROFILE_HEVC_MAIN_444_16_INTRA,             ///< HEVC (H.265) Main 4:4:4 16 Intra
+    PROFILE_HEVC_MAIN_444_STILL,                ///< HEVC (H.265) Main 4:4:4 Still Picture
+    PROFILE_HEVC_MAIN_444_16_STILL,             ///< HEVC (H.265) Main 4:4:4 16 Still Picture
+    PROFILE_HEVC_HIGH_444 = _C2_PL_HEVC_BASE + 0x200,  ///< HEVC (H.265) High Throughput 4:4:4
+    PROFILE_HEVC_HIGH_444_10,                   ///< HEVC (H.265) High Throughput 4:4:4 10
+    PROFILE_HEVC_HIGH_444_14,                   ///< HEVC (H.265) High Throughput 4:4:4 14
+    PROFILE_HEVC_HIGH_444_16_INTRA,             ///< HEVC (H.265) High Throughput 4:4:4 16 Intra
+    PROFILE_HEVC_SX_MAIN = _C2_PL_HEVC_BASE + 0x300,  ///< HEVC (H.265) Screen-Extended Main
+    PROFILE_HEVC_SX_MAIN_10,                    ///< HEVC (H.265) Screen-Extended Main 10
+    PROFILE_HEVC_SX_MAIN_444,                   ///< HEVC (H.265) Screen-Extended Main 4:4:4
+    PROFILE_HEVC_SX_MAIN_444_10,                ///< HEVC (H.265) Screen-Extended Main 4:4:4 10
+    PROFILE_HEVC_SX_HIGH_444,                   ///< HEVC (H.265) Screen-Extended High Throughput 4:4:4
+    PROFILE_HEVC_SX_HIGH_444_10,                ///< HEVC (H.265) Screen-Extended High Throughput 4:4:4 10
+    PROFILE_HEVC_SX_HIGH_444_14,                ///< HEVC (H.265) Screen-Extended High Throughput 4:4:4 14
+    PROFILE_HEVC_MULTIVIEW_MAIN = _C2_PL_HEVC_BASE + 0x400,  ///< HEVC (H.265) Multiview Main
+    PROFILE_HEVC_SCALABLE_MAIN = _C2_PL_HEVC_BASE + 0x500,  ///< HEVC (H.265) Scalable Main
+    PROFILE_HEVC_SCALABLE_MAIN_10,              ///< HEVC (H.265) Scalable Main 10
+    PROFILE_HEVC_SCALABLE_MONO = _C2_PL_HEVC_BASE + 0x600,  ///< HEVC (H.265) Scalable Monochrome
+    PROFILE_HEVC_SCALABLE_MONO_12,              ///< HEVC (H.265) Scalable Monochrome 12
+    PROFILE_HEVC_SCALABLE_MONO_16,              ///< HEVC (H.265) Scalable Monochrome 16
+    PROFILE_HEVC_SCALABLE_MAIN_444,             ///< HEVC (H.265) Scalable Main 4:4:4
+    PROFILE_HEVC_3D_MAIN = _C2_PL_HEVC_BASE + 0x700,  ///< HEVC (H.265) 3D Main
+
+    // VP9 profiles
+    PROFILE_VP9_0 = _C2_PL_VP9_BASE,            ///< VP9 Profile 0 (4:2:0)
+    PROFILE_VP9_1,                              ///< VP9 Profile 1 (4:2:2 or 4:4:4)
+    PROFILE_VP9_2,                              ///< VP9 Profile 2 (4:2:0, 10 or 12 bit)
+    PROFILE_VP9_3,                              ///< VP9 Profile 3 (4:2:2 or 4:4:4, 10 or 12 bit)
+
+    // Dolby Vision profiles
+    PROFILE_DV_AV_PER = _C2_PL_DV_BASE + 0,     ///< Dolby Vision dvav.per profile (deprecated)
+    PROFILE_DV_AV_PEN,                          ///< Dolby Vision dvav.pen profile (deprecated)
+    PROFILE_DV_HE_DER,                          ///< Dolby Vision dvhe.der profile (deprecated)
+    PROFILE_DV_HE_DEN,                          ///< Dolby Vision dvhe.den profile (deprecated)
+    PROFILE_DV_HE_04 = _C2_PL_DV_BASE + 4,      ///< Dolby Vision dvhe.04 profile
+    PROFILE_DV_HE_05 = _C2_PL_DV_BASE + 5,      ///< Dolby Vision dvhe.05 profile
+    PROFILE_DV_HE_DTH,                          ///< Dolby Vision dvhe.dth profile (deprecated)
+    PROFILE_DV_HE_07 = _C2_PL_DV_BASE + 7,      ///< Dolby Vision dvhe.07 profile
+    PROFILE_DV_HE_08 = _C2_PL_DV_BASE + 8,      ///< Dolby Vision dvhe.08 profile
+    PROFILE_DV_AV_09 = _C2_PL_DV_BASE + 9,      ///< Dolby Vision dvav.09 profile
+};
+
+enum C2Config::level_t : uint32_t {
+    LEVEL_UNUSED = 0,                           ///< level is not used by this media type
+
+    // MPEG-2 Video levels
+    LEVEL_MP2V_LOW = _C2_PL_MP2V_BASE,          ///< MPEG-2 Video (H.262) Low Level
+    LEVEL_MP2V_MAIN,                            ///< MPEG-2 Video (H.262) Main Level
+    LEVEL_MP2V_HIGH_1440,                       ///< MPEG-2 Video (H.262) High 1440 Level
+    LEVEL_MP2V_HIGH,                            ///< MPEG-2 Video (H.262) High Level
+    LEVEL_MP2V_HIGHP,                           ///< MPEG-2 Video (H.262) HighP Level
+
+    // H.263 levels
+    LEVEL_H263_10 = _C2_PL_H263_BASE,           ///< H.263 Level 10
+    LEVEL_H263_20,                              ///< H.263 Level 20
+    LEVEL_H263_30,                              ///< H.263 Level 30
+    LEVEL_H263_40,                              ///< H.263 Level 40
+    LEVEL_H263_45,                              ///< H.263 Level 45
+    LEVEL_H263_50,                              ///< H.263 Level 50
+    LEVEL_H263_60,                              ///< H.263 Level 60
+    LEVEL_H263_70,                              ///< H.263 Level 70
+
+    // MPEG-4 Part 2 (Video) levels
+    LEVEL_MP4V_0 = _C2_PL_MP4V_BASE,            ///< MPEG-4 Video Level 0
+    LEVEL_MP4V_0B,                              ///< MPEG-4 Video Level 0b
+    LEVEL_MP4V_1,                               ///< MPEG-4 Video Level 1
+    LEVEL_MP4V_2,                               ///< MPEG-4 Video Level 2
+    LEVEL_MP4V_3,                               ///< MPEG-4 Video Level 3
+    LEVEL_MP4V_3B,                              ///< MPEG-4 Video Level 3b
+    LEVEL_MP4V_4,                               ///< MPEG-4 Video Level 4
+    LEVEL_MP4V_4A,                              ///< MPEG-4 Video Level 4a
+    LEVEL_MP4V_5,                               ///< MPEG-4 Video Level 5
+    LEVEL_MP4V_6,                               ///< MPEG-4 Video Level 6
+
+    // AVC / MPEG-4 Part 10 (H.264) levels
+    LEVEL_AVC_1 = _C2_PL_AVC_BASE,              ///< AVC (H.264) Level 1
+    LEVEL_AVC_1B,                               ///< AVC (H.264) Level 1b
+    LEVEL_AVC_1_1,                              ///< AVC (H.264) Level 1.1
+    LEVEL_AVC_1_2,                              ///< AVC (H.264) Level 1.2
+    LEVEL_AVC_1_3,                              ///< AVC (H.264) Level 1.3
+    LEVEL_AVC_2,                                ///< AVC (H.264) Level 2
+    LEVEL_AVC_2_1,                              ///< AVC (H.264) Level 2.1
+    LEVEL_AVC_2_2,                              ///< AVC (H.264) Level 2.2
+    LEVEL_AVC_3,                                ///< AVC (H.264) Level 3
+    LEVEL_AVC_3_1,                              ///< AVC (H.264) Level 3.1
+    LEVEL_AVC_3_2,                              ///< AVC (H.264) Level 3.2
+    LEVEL_AVC_4,                                ///< AVC (H.264) Level 4
+    LEVEL_AVC_4_1,                              ///< AVC (H.264) Level 4.1
+    LEVEL_AVC_4_2,                              ///< AVC (H.264) Level 4.2
+    LEVEL_AVC_5,                                ///< AVC (H.264) Level 5
+    LEVEL_AVC_5_1,                              ///< AVC (H.264) Level 5.1
+    LEVEL_AVC_5_2,                              ///< AVC (H.264) Level 5.2
+
+    // HEVC (H.265) tiers and levels
+    LEVEL_HEVC_MAIN_1 = _C2_PL_HEVC_BASE,       ///< HEVC (H.265) Main Tier Level 1
+    LEVEL_HEVC_MAIN_2,                          ///< HEVC (H.265) Main Tier Level 2
+    LEVEL_HEVC_MAIN_2_1,                        ///< HEVC (H.265) Main Tier Level 2.1
+    LEVEL_HEVC_MAIN_3,                          ///< HEVC (H.265) Main Tier Level 3
+    LEVEL_HEVC_MAIN_3_1,                        ///< HEVC (H.265) Main Tier Level 3.1
+    LEVEL_HEVC_MAIN_4,                          ///< HEVC (H.265) Main Tier Level 4
+    LEVEL_HEVC_MAIN_4_1,                        ///< HEVC (H.265) Main Tier Level 4.1
+    LEVEL_HEVC_MAIN_5,                          ///< HEVC (H.265) Main Tier Level 5
+    LEVEL_HEVC_MAIN_5_1,                        ///< HEVC (H.265) Main Tier Level 5.1
+    LEVEL_HEVC_MAIN_5_2,                        ///< HEVC (H.265) Main Tier Level 5.2
+    LEVEL_HEVC_MAIN_6,                          ///< HEVC (H.265) Main Tier Level 6
+    LEVEL_HEVC_MAIN_6_1,                        ///< HEVC (H.265) Main Tier Level 6.1
+    LEVEL_HEVC_MAIN_6_2,                        ///< HEVC (H.265) Main Tier Level 6.2
+
+    LEVEL_HEVC_HIGH_4 = _C2_PL_HEVC_BASE + 0x100,  ///< HEVC (H.265) High Tier Level 4
+    LEVEL_HEVC_HIGH_4_1,                        ///< HEVC (H.265) High Tier Level 4.1
+    LEVEL_HEVC_HIGH_5,                          ///< HEVC (H.265) High Tier Level 5
+    LEVEL_HEVC_HIGH_5_1,                        ///< HEVC (H.265) High Tier Level 5.1
+    LEVEL_HEVC_HIGH_5_2,                        ///< HEVC (H.265) High Tier Level 5.2
+    LEVEL_HEVC_HIGH_6,                          ///< HEVC (H.265) High Tier Level 6
+    LEVEL_HEVC_HIGH_6_1,                        ///< HEVC (H.265) High Tier Level 6.1
+    LEVEL_HEVC_HIGH_6_2,                        ///< HEVC (H.265) High Tier Level 6.2
+
+    // VP9 levels
+    LEVEL_VP9_1 = _C2_PL_VP9_BASE,              ///< VP9 Level 1
+    LEVEL_VP9_1_1,                              ///< VP9 Level 1.1
+    LEVEL_VP9_2,                                ///< VP9 Level 2
+    LEVEL_VP9_2_1,                              ///< VP9 Level 2.1
+    LEVEL_VP9_3,                                ///< VP9 Level 3
+    LEVEL_VP9_3_1,                              ///< VP9 Level 3.1
+    LEVEL_VP9_4,                                ///< VP9 Level 4
+    LEVEL_VP9_4_1,                              ///< VP9 Level 4.1
+    LEVEL_VP9_5,                                ///< VP9 Level 5
+    LEVEL_VP9_5_1,                              ///< VP9 Level 5.1
+    LEVEL_VP9_5_2,                              ///< VP9 Level 5.2
+    LEVEL_VP9_6,                                ///< VP9 Level 6
+    LEVEL_VP9_6_1,                              ///< VP9 Level 6.1
+    LEVEL_VP9_6_2,                              ///< VP9 Level 6.2
+
+    // Dolby Vision level
+    LEVEL_DV_MAIN_HD_24 = _C2_PL_DV_BASE,       ///< Dolby Vision main tier hd24
+    LEVEL_DV_MAIN_HD_30,                        ///< Dolby Vision main tier hd30
+    LEVEL_DV_MAIN_FHD_24,                       ///< Dolby Vision main tier fhd24
+    LEVEL_DV_MAIN_FHD_30,                       ///< Dolby Vision main tier fhd30
+    LEVEL_DV_MAIN_FHD_60,                       ///< Dolby Vision main tier fhd60
+    LEVEL_DV_MAIN_UHD_24,                       ///< Dolby Vision main tier uhd24
+    LEVEL_DV_MAIN_UHD_30,                       ///< Dolby Vision main tier uhd30
+    LEVEL_DV_MAIN_UHD_48,                       ///< Dolby Vision main tier uhd48
+    LEVEL_DV_MAIN_UHD_60,                       ///< Dolby Vision main tier uhd60
+
+    LEVEL_DV_HIGH_HD_24 = _C2_PL_DV_BASE + 0x100,  ///< Dolby Vision high tier hd24
+    LEVEL_DV_HIGH_HD_30,                        ///< Dolby Vision high tier hd30
+    LEVEL_DV_HIGH_FHD_24,                       ///< Dolby Vision high tier fhd24
+    LEVEL_DV_HIGH_FHD_30,                       ///< Dolby Vision high tier fhd30
+    LEVEL_DV_HIGH_FHD_60,                       ///< Dolby Vision high tier fhd60
+    LEVEL_DV_HIGH_UHD_24,                       ///< Dolby Vision high tier uhd24
+    LEVEL_DV_HIGH_UHD_30,                       ///< Dolby Vision high tier uhd30
+    LEVEL_DV_HIGH_UHD_48,                       ///< Dolby Vision high tier uhd48
+    LEVEL_DV_HIGH_UHD_60,                       ///< Dolby Vision high tier uhd60
+};
+
+struct C2ProfileLevelStruct {
+    C2Config::profile_t profile;  ///< coding profile
+    C2Config::level_t   level;    ///< coding level
+
+    C2ProfileLevelStruct(
+            C2Config::profile_t profile_ = C2Config::PROFILE_UNUSED,
+            C2Config::level_t level_ = C2Config::LEVEL_UNUSED)
+        : profile(profile_), level(level_) { }
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(ProfileLevel)
+    C2FIELD(profile, "profile")
+    C2FIELD(level,   "level")
+};
+
+// TODO: may need to make this explicit (have .set member)
+typedef C2StreamParam<C2Info, C2ProfileLevelStruct, kParamIndexProfileLevel>
+        C2StreamProfileLevelInfo;
+constexpr char C2_PARAMKEY_PROFILE_LEVEL[] = "coded.pl";
+#define C2_PARAMKEY_STREAM_PROFILE_LEVEL C2_PARAMKEY_PROFILE_LEVEL
+
+/**
+ * Codec-specific initialization data.
+ *
+ * This is initialization data for the codec.
+ *
+ * For AVC/HEVC, these are the concatenated SPS/PPS/VPS NALs.
+ *
+ * TODO: define for other codecs.
+ */
+typedef C2StreamParam<C2Info, C2BlobValue, kParamIndexInitData> C2StreamInitDataInfo;
+typedef C2StreamInitDataInfo C2StreamCsdInfo; // deprecated
+constexpr char C2_PARAMKEY_INIT_DATA[] = "coded.init-data";
+#define C2_PARAMKEY_STREAM_INIT_DATA C2_PARAMKEY_INIT_DATA
+
+/**
+ * Supplemental Data.
+ *
+ * This is coding-specific supplemental informational data, e.g. SEI for AVC/HEVC.
+ * This structure is not a configuration so it does not have a parameter key.
+ * This structure shall be returned in the configuration update, and can be repeated as needed
+ * in the same update.
+ */
+C2ENUM(C2Config::supplemental_info_t, uint32_t,
+    INFO_NONE = 0,
+
+    INFO_PREFIX_SEI_UNIT = 0x10000, ///< prefix SEI payload types add this flag
+    INFO_SUFFIX_SEI_UNIT = 0x20000, ///< suffix SEI payload types add this flag
+
+    INFO_SEI_USER_DATA = INFO_PREFIX_SEI_UNIT | 4,    ///< closed-captioning data (ITU-T T35)
+    INFO_SEI_MDCV      = INFO_PREFIX_SEI_UNIT | 137,  ///< mastering display color volume
+    INFO_SET_USER_DATA_SFX = INFO_SUFFIX_SEI_UNIT | 4, ///< closed-captioning data (ITU-T T35)
+
+    INFO_VENDOR_START = 0x70000000
+)
+
+struct C2SupplementalDataStruct {
+    C2SupplementalDataStruct()
+        : type_(INFO_NONE) { }
+
+    C2SupplementalDataStruct(
+            size_t flexCount, C2Config::supplemental_info_t type, std::vector<uint8_t> data_)
+        : type_(type) {
+            memcpy(data, &data_[0], c2_min(data_.size(), flexCount));
+    }
+
+    C2Config::supplemental_info_t type_;
+    uint8_t data[];
+
+    DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(SupplementalData, data)
+    C2FIELD(type_, "type")
+    C2FIELD(data, "data")
+};
+typedef C2StreamParam<C2Info, C2SupplementalDataStruct, kParamIndexSupplementalData>
+        C2StreamSupplementalDataInfo;
+
+/**
+ * Supplemental Data Subscription
+ */
+typedef C2StreamParam<C2Tuning, C2SimpleArrayStruct<C2Config::supplemental_info_t>,
+                kParamIndexSubscribedSupplementalData>
+        C2StreamSubscribedSupplementalDataTuning;
+constexpr char C2_PARAMKEY_SUBSCRIBED_SUPPLEMENTAL_DATA[] = "output.subscribed-supplemental";
+
+/* ---------------------------------- pipeline characteristics ---------------------------------- */
+
+/**
+ * Media-type.
+ *
+ * This is defined for both port and stream, but stream media type may be a subtype of the
+ * port media type.
+ */
+typedef C2PortParam<C2Setting, C2StringValue, kParamIndexMediaType> C2PortMediaTypeSetting;
+typedef C2PortMediaTypeSetting C2PortMimeConfig; // deprecated
+constexpr char C2_PARAMKEY_INPUT_MEDIA_TYPE[] = "input.media-type";
+constexpr char C2_PARAMKEY_OUTPUT_MEDIA_TYPE[] = "output.media-type";
+#define C2_NAME_INPUT_PORT_MIME_SETTING C2_PARAMKEY_INPUT_MEDIA_TYPE
+#define C2_NAME_OUTPUT_PORT_MIME_SETTING C2_PARAMKEY_OUTPUT_MEDIA_TYPE
+
+typedef C2StreamParam<C2Setting, C2StringValue, kParamIndexMediaType> C2StreamMediaTypeSetting;
+
+/**
+ * Pipeline delays.
+ *
+ * Input delay is the number of additional input frames requested by the component to process
+ * an input frame.
+ *
+ * Output delay is the number of additional output frames that need to be generated before an
+ * output can be released by the component.
+ *
+ * Pipeline delay is the number of additional frames that are processed at one time by the
+ * component.
+ *
+ * As these may vary from frame to frame, the number is the maximum required value. E.g. if
+ * input delay is 0, the component is expected to consume each frame queued even if no further
+ * frames are queued. Similarly, if input delay is 1, as long as there are always exactly 2
+ * outstanding input frames queued to the component, it shall produce output.
+ */
+
+typedef C2PortParam<C2Tuning, C2Uint32Value, kParamIndexDelayRequest> C2PortRequestedDelayTuning;
+typedef C2PortRequestedDelayTuning C2PortRequestedLatencyTuning; // deprecated
+constexpr char C2_PARAMKEY_INPUT_DELAY_REQUEST[] = "input.delay.requested";
+constexpr char C2_PARAMKEY_OUTPUT_DELAY_REQUEST[] = "output.delay.requested";
+
+typedef C2GlobalParam<C2Tuning, C2Uint32Value, kParamIndexDelayRequest>
+        C2RequestedPipelineDelayTuning;
+typedef C2RequestedPipelineDelayTuning C2ComponentRequestedLatencyTuning; // deprecated
+constexpr char C2_PARAMKEY_PIPELINE_DELAY_REQUEST[] = "pipeline-delay.requested";
+
+// read-only
+typedef C2PortParam<C2Tuning, C2Uint32Value, kParamIndexDelay> C2PortActualDelayTuning;
+typedef C2PortActualDelayTuning C2PortLatencyInfo; // deprecated
+constexpr char C2_PARAMKEY_INPUT_DELAY[] = "input.delay.actual";
+constexpr char C2_PARAMKEY_OUTPUT_DELAY[] = "output.delay.actual";
+
+// read-only
+typedef C2GlobalParam<C2Tuning, C2Uint32Value, kParamIndexDelay> C2ActualPipelineDelayTuning;
+typedef C2ActualPipelineDelayTuning C2ComponentLatencyInfo; // deprecated
+constexpr char C2_PARAMKEY_PIPELINE_DELAY[] = "algo.delay.actual";
+
+/**
+ * Reference characteristics.
+ *
+ * The component may hold onto input and output buffers even after completing the corresponding
+ * work item.
+ *
+ * Max reference age is the longest number of additional frame processing that a component may
+ * hold onto a buffer for. Max reference count is the number of buffers that a component may
+ * hold onto at the same time at the worst case. These numbers assume single frame per buffers.
+ *
+ * Use max-uint32 if there is no limit for the max age or count.
+ */
+typedef C2StreamParam<C2Tuning, C2Uint32Value, kParamIndexMaxReferenceAge>
+        C2StreamMaxReferenceAgeTuning;
+constexpr char C2_PARAMKEY_INPUT_MAX_REFERENCE_AGE[] = "input.reference.max-age";
+constexpr char C2_PARAMKEY_OUTPUT_MAX_REFERENCE_AGE[] = "output.reference.max-age";
+
+typedef C2StreamParam<C2Tuning, C2Uint32Value, kParamIndexMaxReferenceCount>
+        C2StreamMaxReferenceCountTuning;
+constexpr char C2_PARAMKEY_INPUT_MAX_REFERENCE_COUNT[] = "input.reference.max-count";
+constexpr char C2_PARAMKEY_OUTPUT_MAX_REFERENCE_COUNT[] = "output.reference.max-count";
+
+/**
+ * Output reordering.
+ *
+ * The size of the window to use for output buffer reordering. 0 is interpreted as 1.
+ */
+// output only
+typedef C2PortParam<C2Tuning, C2Uint32Value, kParamIndexReorderBufferDepth>
+        C2PortReorderBufferDepthTuning;
+constexpr char C2_PARAMKEY_OUTPUT_REORDER_DEPTH[] = "output.reorder.depth";
+
+C2ENUM(C2Config::ordinal_key_t, uint32_t,
+        ORDINAL,
+        TIMESTAMP,
+        CUSTOM)
+
+// read-only, output only
+typedef C2PortParam<C2Setting, C2SimpleValueStruct<C2Config::ordinal_key_t>, kParamIndexReorderKey>
+        C2PortReorderKeySetting;
+constexpr char C2_PARAMKEY_OUTPUT_REORDER_KEY[] = "output.reorder.key";
+
+/**
+ * Stream count.
+ */
+// private
+typedef C2PortParam<C2Tuning, C2Uint32Value, kParamIndexStreamCount> C2PortStreamCountTuning;
+typedef C2PortStreamCountTuning C2PortStreamCountConfig; // deprecated
+constexpr char C2_PARAMKEY_INPUT_STREAM_COUNT[] = "input.stream-count";
+constexpr char C2_PARAMKEY_OUTPUT_STREAM_COUNT[] = "output.stream-count";
+
+/**
+ * Config update subscription.
+ */
+// private
+typedef C2GlobalParam<C2Tuning, C2Uint32Array, kParamIndexSubscribedParamIndices>
+        C2SubscribedParamIndicesTuning;
+constexpr char C2_PARAMKEY_SUBSCRIBED_PARAM_INDICES[] = "output.subscribed-indices";
+
+/**
+ * Suggested buffer (C2Frame) count. This is a suggestion by the component for the number of
+ * input and output frames allocated for the component's use in the buffer pools.
+ *
+ * Component shall set the acceptable range of buffers allocated for it. E.g. client shall
+ * allocate at least the minimum required value.
+ */
+// read-only
+typedef C2PortParam<C2Tuning, C2Uint64Array, kParamIndexSuggestedBufferCount>
+        C2PortSuggestedBufferCountTuning;
+constexpr char C2_PARAMKEY_INPUT_SUGGESTED_BUFFER_COUNT[] = "input.buffers.pool-size";
+constexpr char C2_PARAMKEY_OUTPUT_SUGGESTED_BUFFER_COUNT[] = "output.buffers.pool-size";
+
+/**
+ * Input/output batching.
+ *
+ * For input, component requests that client batches work in batches of specified size. For output,
+ * client requests that the component batches work completion in given batch size.
+ * Value 0 means don't care.
+ */
+typedef C2PortParam<C2Tuning, C2Uint64Array, kParamIndexBatchSize> C2PortBatchSizeTuning;
+constexpr char C2_PARAMKEY_INPUT_BATCH_SIZE[] = "input.buffers.batch-size";
+constexpr char C2_PARAMKEY_OUTPUT_BATCH_SIZE[] = "output.buffers.batch-size";
+
+/**
+ * Current & last work ordinals.
+ *
+ * input port: last work queued to component.
+ * output port: last work completed by component.
+ * global: current work.
+ */
+typedef C2PortParam<C2Tuning, C2WorkOrdinalStruct, kParamIndexLastWorkQueued> C2LastWorkQueuedTuning;
+typedef C2GlobalParam<C2Tuning, C2WorkOrdinalStruct, kParamIndexCurrentWork> C2CurrentWorkTuning;
+
+
+/* ------------------------------------- memory allocation ------------------------------------- */
+
+/**
+ * Allocators to use.
+ *
+ * These are requested by the component.
+ *
+ * If none specified, client will use the default allocator ID based on the component domain and
+ * kind.
+ */
+typedef C2PortParam<C2Tuning, C2SimpleArrayStruct<C2Allocator::id_t>, kParamIndexAllocators>
+        C2PortAllocatorsTuning;
+constexpr char C2_PARAMKEY_INPUT_ALLOCATORS[] = "input.buffers.allocator-ids";
+constexpr char C2_PARAMKEY_OUTPUT_ALLOCATORS[] = "output.buffers.allocator-ids";
+
+typedef C2GlobalParam<C2Tuning, C2SimpleArrayStruct<C2Allocator::id_t>, kParamIndexAllocators>
+        C2PrivateAllocatorsTuning;
+constexpr char C2_PARAMKEY_PRIVATE_ALLOCATORS[] = "algo.buffers.allocator-ids";
+
+/**
+ * Allocator to use for outputting to surface.
+ *
+ * Components can optionally request allocator type for outputting to surface.
+ *
+ * If none specified, client will use the default BufferQueue-backed allocator ID for outputting to
+ * surface.
+ */
+typedef C2PortParam<C2Tuning, C2Uint32Value, kParamIndexSurfaceAllocator>
+        C2PortSurfaceAllocatorTuning;
+constexpr char C2_PARAMKEY_OUTPUT_SURFACE_ALLOCATOR[] = "output.buffers.surface-allocator-id";
+
+/**
+ * Block pools to use.
+ *
+ * These are allocated by the client for the component using the allocator IDs specified by the
+ * component. This is not used for the input port.
+ */
+typedef C2PortParam<C2Tuning, C2SimpleArrayStruct<C2BlockPool::local_id_t>, kParamIndexBlockPools>
+        C2PortBlockPoolsTuning;
+constexpr char C2_PARAMKEY_OUTPUT_BLOCK_POOLS[] = "output.buffers.pool-ids";
+
+typedef C2GlobalParam<C2Tuning, C2SimpleArrayStruct<C2BlockPool::local_id_t>, kParamIndexBlockPools>
+        C2PrivateBlockPoolsTuning;
+constexpr char C2_PARAMKEY_PRIVATE_BLOCK_POOLS[] = "algo.buffers.pool-ids";
+
+/**
+ * The max number of private allocations at any one time by the component.
+ * (This is an array with a corresponding value for each private allocator)
+ */
+typedef C2GlobalParam<C2Tuning, C2Uint32Array, kParamIndexMaxReferenceCount>
+        C2MaxPrivateBufferCountTuning;
+constexpr char C2_PARAMKEY_MAX_PRIVATE_BUFFER_COUNT[] = "algo.buffers.max-count";
+
+/**
+ * Buffer type
+ *
+ * This is provided by the component for the client to allocate the proper buffer type for the
+ * input port, and can be provided by the client to control the buffer type for the output.
+ */
+// private
+typedef C2StreamParam<C2Setting, C2SimpleValueStruct<C2EasyEnum<C2BufferData::type_t>>,
+                kParamIndexBufferType>
+        C2StreamBufferTypeSetting;
+
+constexpr C2BufferData::type_t C2FormatAudio      = C2BufferData::LINEAR; // deprecated
+constexpr C2BufferData::type_t C2FormatCompressed = C2BufferData::LINEAR; // deprecated
+constexpr C2BufferData::type_t C2FormatVideo      = C2BufferData::GRAPHIC; // deprecated
+typedef C2BufferData::type_t C2FormatKind; // deprecated
+
+typedef C2StreamBufferTypeSetting C2StreamFormatConfig; // deprecated
+constexpr char C2_PARAMKEY_INPUT_STREAM_BUFFER_TYPE[] = "input.buffers.type";
+constexpr char C2_PARAMKEY_OUTPUT_STREAM_BUFFER_TYPE[] = "output.buffers.type";
+
+// deprecated
+#define C2_NAME_INPUT_STREAM_FORMAT_SETTING C2_PARAMKEY_INPUT_STREAM_BUFFER_TYPE
+#define C2_NAME_OUTPUT_STREAM_FORMAT_SETTING C2_PARAMKEY_OUTPUT_STREAM_BUFFER_TYPE
+
+/**
+ * Memory usage.
+ *
+ * Suggested by component for input and negotiated between client and component for output.
+ */
+typedef C2StreamParam<C2Tuning, C2Uint64Value, kParamIndexUsage> C2StreamUsageTuning;
+constexpr char C2_PARAMKEY_INPUT_STREAM_USAGE[] = "input.buffers.usage";
+constexpr char C2_PARAMKEY_OUTPUT_STREAM_USAGE[] = "output.buffers.usage";
+// deprecated
+#define C2_NAME_INPUT_STREAM_USAGE_SETTING C2_PARAMKEY_INPUT_STREAM_USAGE
+
+/**
+ * Picture (video or image frame) size.
+ */
+struct C2PictureSizeStruct {
+    inline C2PictureSizeStruct()
+        : width(0), height(0) { }
+
+    inline C2PictureSizeStruct(uint32_t width_, uint32_t height_)
+        : width(width_), height(height_) { }
+
+    uint32_t width;     ///< video width
+    uint32_t height;    ///< video height
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(PictureSize)
+    C2FIELD(width, "width")
+    C2FIELD(height, "height")
+};
+
+/**
+ * Out of memory signaling
+ *
+ * This is a configuration for the client to mark that it cannot allocate necessary private and/
+ * or output buffers to continue operation, and to signal the failing configuration.
+ */
+struct C2OutOfMemoryStruct {
+    C2BlockPool::local_id_t pool;   ///< pool ID that failed the allocation
+    uint64_t usage;                 ///< memory usage used
+    C2PictureSizeStruct planar;     ///< buffer dimensions to be allocated if 2D
+    uint32_t format;                ///< pixel format to be used if 2D
+    uint32_t capacity;              ///< buffer capacity to be allocated if 1D
+    c2_bool_t outOfMemory;           ///< true if component is out of memory
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(OutOfMemory)
+    C2FIELD(pool, "pool")
+    C2FIELD(usage, "usage")
+    C2FIELD(planar, "planar")
+    C2FIELD(format, "format")
+    C2FIELD(capacity, "capacity")
+    C2FIELD(outOfMemory, "out-of-memory")
+};
+
+typedef C2GlobalParam<C2Tuning, C2OutOfMemoryStruct, kParamIndexOutOfMemory> C2OutOfMemoryTuning;
+constexpr char C2_PARAMKEY_OUT_OF_MEMORY[] = "algo.oom";
+
+/**
+ * Max buffer size
+ *
+ * This is a hint provided by the component for the maximum buffer size expected on a stream for the
+ * current configuration on its input and output streams. This is communicated to clients so they
+ * can preallocate input buffers, or configure downstream components that require a maximum size on
+ * their buffers.
+ *
+ * Read-only. Required to be provided by components on all compressed streams.
+ */
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexMaxBufferSize> C2StreamMaxBufferSizeInfo;
+constexpr char C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE[] = "input.buffers.max-size";
+constexpr char C2_PARAMKEY_OUTPUT_MAX_BUFFER_SIZE[] = "output.buffers.max-size";
+
+#define C2_NAME_STREAM_MAX_BUFFER_SIZE_SETTING C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE
+
+/* ---------------------------------------- misc. state ---------------------------------------- */
+
+/**
+ * Tripped state,
+ *
+ * This state exists to be able to provide reasoning for a tripped state during normal
+ * interface operations, as well as to allow client to trip the component on demand.
+ */
+typedef C2GlobalParam<C2Tuning, C2BoolValue, kParamIndexTripped>
+        C2TrippedTuning;
+constexpr char C2_PARAMKEY_TRIPPED[] = "algo.tripped";
+
+/**
+ * Configuration counters.
+ *
+ * Configurations are tracked using three counters. The input counter is incremented exactly
+ * once with each work accepted by the component. The output counter is incremented exactly
+ * once with each work completed by the component (in the order of work completion). The
+ * global counter is incremented exactly once during to each config() call. These counters
+ * shall be read-only.
+ *
+ * TODO: these should be counters.
+ */
+typedef C2PortParam<C2Tuning, C2Uint64Value, kParamIndexConfigCounter> C2PortConfigCounterTuning;
+typedef C2GlobalParam<C2Tuning, C2Uint64Value, kParamIndexConfigCounter> C2ConfigCounterTuning;
+constexpr char C2_PARAMKEY_INPUT_COUNTER[] = "input.buffers.counter";
+constexpr char C2_PARAMKEY_OUTPUT_COUNTER[] = "output.buffers.counter";
+constexpr char C2_PARAMKEY_CONFIG_COUNTER[] = "algo.config.counter";
+
+/* ----------------------------------------- resources ----------------------------------------- */
+
+/**
+ * Resources needed and resources reserved for current configuration.
+ *
+ * Resources are tracked as a vector of positive numbers. Available resources are defined by
+ * the vendor.
+ *
+ * By default, no resources are reserved for a component. If resource reservation is successful,
+ * the component shall be able to use those resources exclusively. If however, the component is
+ * not using all of the reserved resources, those may be shared with other components.
+ *
+ * TODO: define some of the resources.
+ */
+typedef C2GlobalParam<C2Tuning, C2Uint64Array, kParamIndexResourcesNeeded> C2ResourcesNeededTuning;
+typedef C2GlobalParam<C2Tuning, C2Uint64Array, kParamIndexResourcesReserved>
+        C2ResourcesReservedTuning;
+constexpr char C2_PARAMKEY_RESOURCES_NEEDED[] = "resources.needed";
+constexpr char C2_PARAMKEY_RESOURCES_RESERVED[] = "resources.reserved";
+
+/**
+ * Operating rate.
+ *
+ * Operating rate is the expected rate of work through the component. Negative values is
+ * invalid.
+ *
+ * TODO: this could distinguish set value
+ */
+typedef C2GlobalParam<C2Tuning, C2FloatValue, kParamIndexOperatingRate> C2OperatingRateTuning;
+constexpr char C2_PARAMKEY_OPERATING_RATE[] = "algo.rate";
+
+/**
+ * Realtime / operating point.
+ *
+ * Priority value defines the operating point for the component. Operating points are defined by
+ * the vendor. Priority value of 0 means that the client requires operation at the given operating
+ * rate. Priority values -1 and below define operating points in decreasing performance. In this
+ * case client expects best effort without exceeding the specific operating point. This allows
+ * client to run components deeper in the background by using larger priority values. In these
+ * cases operating rate is a hint for the maximum rate that the client anticipates.
+ *
+ * Operating rate and priority are used in tandem. E.g. if there are components that run at a
+ * higher operating point (priority) it will make more resources available for components at
+ * a lower operating point, so operating rate can be used to gate those components.
+ *
+ * Positive priority values are not defined at the moment and shall be treated equivalent to 0.
+ */
+typedef C2GlobalParam<C2Tuning, C2Int32Value, kParamIndexRealTimePriority>
+        C2RealTimePriorityTuning;
+constexpr char C2_PARAMKEY_PRIORITY[] = "algo.priority";
+
+/* ------------------------------------- protected content ------------------------------------- */
+
+/**
+ * Secure mode.
+ */
+C2ENUM(C2Config::secure_mode_t, uint32_t,
+    SM_UNPROTECTED,    ///< no content protection
+    SM_READ_PROTECTED, ///< input and output buffers shall be protected from reading
+)
+
+typedef C2GlobalParam<C2Tuning, C2SimpleValueStruct<C2Config::secure_mode_t>, kParamIndexSecureMode>
+        C2SecureModeTuning;
+constexpr char C2_PARAMKEY_SECURE_MODE[] = "algo.secure-mode";
+
+/* ===================================== ENCODER COMPONENTS ===================================== */
+
+/**
+ * Bitrate
+ */
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexBitrate> C2StreamBitrateInfo;
+typedef C2StreamBitrateInfo C2BitrateTuning; // deprecated
+constexpr char C2_PARAMKEY_BITRATE[] = "coded.bitrate";
+#define C2_NAME_STREAM_BITRATE_SETTING C2_PARAMKEY_BITRATE
+
+/**
+ * Bitrate mode.
+ *
+ * TODO: refine this with bitrate ranges and suggested window
+ */
+C2ENUM(C2Config::bitrate_mode_t, uint32_t,
+    BITRATE_CONST_SKIP_ALLOWED = 0,      ///< constant bitrate, frame skipping allowed
+    BITRATE_CONST = 1,                   ///< constant bitrate, keep all frames
+    BITRATE_VARIABLE_SKIP_ALLOWED = 2,   ///< bitrate can vary, frame skipping allowed
+    BITRATE_VARIABLE = 3,                ///< bitrate can vary, keep all frames
+    BITRATE_IGNORE = 7,                  ///< bitrate can be exceeded at will to achieve
+                                         ///< quality or other settings
+
+    // bitrate modes are composed of the following flags
+    BITRATE_FLAG_KEEP_ALL_FRAMES = 1,
+    BITRATE_FLAG_CAN_VARY = 2,
+    BITRATE_FLAG_CAN_EXCEED = 4,
+)
+
+typedef C2StreamParam<C2Tuning, C2SimpleValueStruct<C2Config::bitrate_mode_t>,
+                kParamIndexBitrateMode>
+        C2StreamBitrateModeTuning;
+constexpr char C2_PARAMKEY_BITRATE_MODE[] = "algo.bitrate-mode";
+
+/**
+ * Quality.
+ *
+ * This is defined by each component, the higher the better the output quality at the expense of
+ * less compression efficiency. This setting is defined for the output streams in case the
+ * component can support varying quality on each stream, or as an output port tuning in case the
+ * quality is global to all streams.
+ */
+typedef C2StreamParam<C2Tuning, C2Uint32Value, kParamIndexQuality> C2StreamQualityTuning;
+typedef C2PortParam<C2Tuning, C2Uint32Value, kParamIndexQuality> C2QualityTuning;
+constexpr char C2_PARAMKEY_QUALITY[] = "algo.quality";
+
+/**
+ * Complexity.
+ *
+ * This is defined by each component, this higher the value, the more resources the component
+ * will use to produce better quality at the same compression efficiency or better compression
+ * efficiency at the same quality. This setting is defined for the output streams in case the
+ * component can support varying complexity on each stream, or as an output port tuning in case the
+ * quality is global to all streams
+ */
+typedef C2StreamParam<C2Tuning, C2Uint32Value, kParamIndexComplexity> C2StreamComplexityTuning;
+typedef C2PortParam<C2Tuning, C2Uint32Value, kParamIndexComplexity> C2ComplexityTuning;
+constexpr char C2_PARAMKEY_COMPLEXITY[] = "algo.complexity";
+
+/**
+ * Header (init-data) handling around sync frames.
+ */
+C2ENUM(C2Config::prepend_header_mode_t, uint32_t,
+    /**
+     * don't prepend header. Signal header only through C2StreamInitDataInfo.
+     */
+    PREPEND_HEADER_TO_NONE,
+
+    /**
+     * prepend header before the first output frame and thereafter before the next sync frame
+     * if it changes.
+     */
+    PREPEND_HEADER_ON_CHANGE,
+
+    /**
+     * prepend header before every sync frame.
+     */
+    PREPEND_HEADER_TO_ALL_SYNC,
+)
+
+typedef C2GlobalParam<C2Setting, C2BoolValue, kParamIndexPrependHeaderMode>
+        C2PrependHeaderModeSetting;
+constexpr char C2_PARAMKEY_PREPEND_HEADER_MODE[] = "output.buffers.prepend-header";
+
+/* =================================== IMAGE/VIDEO COMPONENTS =================================== */
+
+/*
+ * Order of transformation is:
+ *
+ * crop => (scaling => scaled-crop) => sample-aspect-ratio => flip => rotation
+ */
+
+/**
+ * Picture (image- and video frame) size.
+ *
+ * This is used for the output of the video decoder, and the input of the video encoder.
+ */
+typedef C2PictureSizeStruct C2VideoSizeStruct; // deprecated
+
+typedef C2StreamParam<C2Info, C2PictureSizeStruct, kParamIndexPictureSize> C2StreamPictureSizeInfo;
+constexpr char C2_PARAMKEY_PICTURE_SIZE[] = "raw.size";
+#define C2_PARAMKEY_STREAM_PICTURE_SIZE C2_PARAMKEY_PICTURE_SIZE
+#define C2_NAME_STREAM_VIDEO_SIZE_INFO C2_PARAMKEY_PICTURE_SIZE
+typedef C2StreamPictureSizeInfo C2VideoSizeStreamInfo; // deprecated
+typedef C2StreamPictureSizeInfo C2VideoSizeStreamTuning; // deprecated
+#define C2_NAME_STREAM_VIDEO_SIZE_SETTING C2_PARAMKEY_PICTURE_SIZE
+
+/**
+ * Crop rectangle.
+ */
+struct C2RectStruct : C2Rect {
+    C2RectStruct() = default;
+    C2RectStruct(const C2Rect &rect) : C2Rect(rect) { }
+
+    bool operator==(const C2RectStruct &) = delete;
+    bool operator!=(const C2RectStruct &) = delete;
+
+    DEFINE_AND_DESCRIBE_BASE_C2STRUCT(Rect)
+    C2FIELD(width, "width")
+    C2FIELD(height, "height")
+    C2FIELD(left, "left")
+    C2FIELD(top, "top")
+};
+
+typedef C2StreamParam<C2Info, C2RectStruct, kParamIndexCropRect> C2StreamCropRectInfo;
+constexpr char C2_PARAMKEY_CROP_RECT[] = "raw.crop";
+constexpr char C2_PARAMKEY_CODED_CROP_RECT[] = "coded.crop";
+
+/**
+ * Pixel format.
+ */
+// TODO: define some
+
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexPixelFormat> C2StreamPixelFormatInfo;
+constexpr char C2_PARAMKEY_PIXEL_FORMAT[] = "raw.pixel-format";
+
+/**
+ * Extended rotation information also incorporating a flip.
+ *
+ * Rotation is counter clock-wise.
+ */
+struct C2RotationStruct {
+    C2RotationStruct(int32_t rotation = 0)
+        : flip(0), value(rotation) { }
+
+    int32_t flip;   ///< horizontal flip (left-right flip applied prior to rotation)
+    int32_t value;  ///< rotation in degrees counter clockwise
+
+    DEFINE_AND_DESCRIBE_BASE_C2STRUCT(Rotation)
+    C2FIELD(flip, "flip")
+    C2FIELD(value, "value")
+};
+
+typedef C2StreamParam<C2Info, C2RotationStruct, kParamIndexRotation> C2StreamRotationInfo;
+constexpr char C2_PARAMKEY_ROTATION[] = "raw.rotation";
+constexpr char C2_PARAMKEY_VUI_ROTATION[] = "coded.vui.rotation";
+
+/**
+ * Pixel (sample) aspect ratio.
+ */
+typedef C2StreamParam<C2Info, C2PictureSizeStruct, kParamIndexPixelAspectRatio>
+        C2StreamPixelAspectRatioInfo;
+constexpr char C2_PARAMKEY_PIXEL_ASPECT_RATIO[] = "raw.sar";
+constexpr char C2_PARAMKEY_VUI_PIXEL_ASPECT_RATIO[] = "coded.vui.sar";
+
+/**
+ * In-line scaling.
+ *
+ * Components can optionally support scaling of raw image/video frames.  Or scaling only a
+ * portion of raw image/video frames (scaled-crop).
+ */
+
+C2ENUM(C2Config::scaling_method_t, uint32_t,
+    SCALING_ARBITRARY,   ///< arbitrary, unspecified
+)
+
+typedef C2StreamParam<C2Tuning, C2SimpleValueStruct<C2Config::scaling_method_t>,
+                kParamIndexScalingMethod>
+        C2StreamScalingMethodTuning;
+constexpr char C2_PARAMKEY_SCALING_MODE[] = "raw.scaling-method";
+#define C2_PARAMKEY_STREAM_SCALING_MODE C2_PARAMKEY_SCALING_MODE
+
+typedef C2StreamParam<C2Tuning, C2PictureSizeStruct, kParamIndexScaledPictureSize>
+        C2StreamScaledPictureSizeTuning;
+constexpr char C2_PARAMKEY_SCALED_PICTURE_SIZE[] = "raw.scaled-size";
+#define C2_PARAMKEY_STREAM_SCALED_PICTURE_SIZE C2_PARAMKEY_SCALED_PICTURE_SIZE
+
+typedef C2StreamParam<C2Tuning, C2RectStruct, kParamIndexScaledCropRect>
+        C2StreamScaledCropRectTuning;
+constexpr char C2_PARAMKEY_SCALED_CROP_RECT[] = "raw.scaled-crop";
+
+/* ------------------------------------- color information ------------------------------------- */
+
+/**
+ * Color Info
+ *
+ * Chroma location can vary for top and bottom fields, so use an array, that can have 0 to 2
+ * values. Empty array is used for non YUV formats.
+ */
+
+struct C2Color {
+    enum matrix_t : uint32_t;  ///< matrix coefficient (YUV <=> RGB)
+    enum plane_layout_t : uint32_t;  ///< plane layout for flexible formats
+    enum primaries_t : uint32_t;  ///< color primaries and white point
+    enum range_t : uint32_t;  ///< range of color component values
+    enum subsampling_t : uint32_t;  ///< chroma subsampling
+    enum transfer_t : uint32_t;  ///< transfer function
+};
+
+/// Chroma subsampling
+C2ENUM(C2Color::subsampling_t, uint32_t,
+    MONOCHROME,     ///< there are no Cr nor Cb planes
+    MONOCHROME_ALPHA, ///< there are no Cr nor Cb planes, but there is an alpha plane
+    RGB,            ///< RGB
+    RGBA,           ///< RGBA
+    YUV_420,        ///< Cr and Cb planes are subsampled by 2 both horizontally and vertically
+    YUV_422,        ///< Cr and Cb planes are subsampled horizontally
+    YUV_444,        ///< Cr and Cb planes are not subsampled
+    YUVA_444,       ///< Cr and Cb planes are not subsampled, there is an alpha plane
+)
+
+struct C2ChromaOffsetStruct {
+    // chroma offsets defined by ITU
+    constexpr static C2ChromaOffsetStruct ITU_YUV_444() { return { 0.0f, 0.0f }; }
+    constexpr static C2ChromaOffsetStruct ITU_YUV_422() { return { 0.0f, 0.0f }; }
+    constexpr static C2ChromaOffsetStruct ITU_YUV_420_0() { return { 0.0f, 0.5f }; }
+    constexpr static C2ChromaOffsetStruct ITU_YUV_420_1() { return { 0.5f, 0.5f }; }
+    constexpr static C2ChromaOffsetStruct ITU_YUV_420_2() { return { 0.0f, 0.0f }; }
+    constexpr static C2ChromaOffsetStruct ITU_YUV_420_3() { return { 0.5f, 0.0f }; }
+    constexpr static C2ChromaOffsetStruct ITU_YUV_420_4() { return { 0.0f, 1.0f }; }
+    constexpr static C2ChromaOffsetStruct ITU_YUV_420_5() { return { 0.5f, 1.0f }; }
+
+    float x;    ///< x offset in pixels (towards right)
+    float y;    ///< y offset in pixels (towards down)
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(ChromaOffset)
+    C2FIELD(x, "x")
+    C2FIELD(y, "y")
+};
+
+struct C2ColorInfoStruct {
+    C2ColorInfoStruct()
+        : bitDepth(8), subsampling(C2Color::YUV_420) { }
+
+    uint32_t bitDepth;
+    C2Color::subsampling_t subsampling;
+    C2ChromaOffsetStruct locations[]; // max 2 elements
+
+    C2ColorInfoStruct(
+            size_t /* flexCount */, uint32_t bitDepth_, C2Color::subsampling_t subsampling_)
+        : bitDepth(bitDepth_), subsampling(subsampling_) { }
+
+    C2ColorInfoStruct(
+            size_t flexCount, uint32_t bitDepth_, C2Color::subsampling_t subsampling_,
+            std::initializer_list<C2ChromaOffsetStruct> locations_)
+        : bitDepth(bitDepth_), subsampling(subsampling_) {
+        size_t ix = 0;
+        for (const C2ChromaOffsetStruct &location : locations_) {
+            if (ix == flexCount) {
+                break;
+            }
+            locations[ix] = location;
+            ++ix;
+        }
+    }
+
+    DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(ColorInfo, locations)
+    C2FIELD(bitDepth, "bit-depth")
+    C2FIELD(subsampling, "subsampling")
+    C2FIELD(locations, "locations")
+};
+
+typedef C2StreamParam<C2Info, C2ColorInfoStruct, kParamIndexColorInfo> C2StreamColorInfo;
+constexpr char C2_PARAMKEY_COLOR_INFO[] = "raw.color-format";
+constexpr char C2_PARAMKEY_CODED_COLOR_INFO[] = "coded.color-format";
+
+/**
+ * Color Aspects
+ */
+
+/* The meaning of the following enumerators is as described in ITU-T H.273. */
+
+/// Range
+C2ENUM(C2Color::range_t, uint32_t,
+    RANGE_UNSPECIFIED,          ///< range is unspecified
+    RANGE_FULL,                 ///< full range
+    RANGE_LIMITED,              ///< limited range
+
+    RANGE_VENDOR_START = 0x80,  ///< vendor-specific range values start here
+    RANGE_OTHER = 0XFF          ///< max value, reserved for undefined values
+)
+
+/// Color primaries
+C2ENUM(C2Color::primaries_t, uint32_t,
+    PRIMARIES_UNSPECIFIED,          ///< primaries are unspecified
+    PRIMARIES_BT709,                ///< Rec.ITU-R BT.709-6 or equivalent
+    PRIMARIES_BT470_M,              ///< Rec.ITU-R BT.470-6 System M or equivalent
+    PRIMARIES_BT601_625,            ///< Rec.ITU-R BT.601-6 625 or equivalent
+    PRIMARIES_BT601_525,            ///< Rec.ITU-R BT.601-6 525 or equivalent
+    PRIMARIES_GENERIC_FILM,         ///< Generic Film
+    PRIMARIES_BT2020,               ///< Rec.ITU-R BT.2020 or equivalent
+    PRIMARIES_RP431,                ///< SMPTE RP 431-2 or equivalent
+    PRIMARIES_EG432,                ///< SMPTE EG 432-1 or equivalent
+    PRIMARIES_EBU3213,              ///< EBU Tech.3213-E or equivalent
+                                    ///
+    PRIMARIES_VENDOR_START = 0x80,  ///< vendor-specific primaries values start here
+    PRIMARIES_OTHER = 0xff          ///< max value, reserved for undefined values
+)
+
+/// Transfer function
+C2ENUM(C2Color::transfer_t, uint32_t,
+    TRANSFER_UNSPECIFIED,           ///< transfer is unspecified
+    TRANSFER_LINEAR,                ///< Linear transfer characteristics
+    TRANSFER_SRGB,                  ///< sRGB or equivalent
+    TRANSFER_170M,                  ///< SMPTE 170M or equivalent (e.g. BT.601/709/2020)
+    TRANSFER_GAMMA22,               ///< Assumed display gamma 2.2
+    TRANSFER_GAMMA28,               ///< Assumed display gamma 2.8
+    TRANSFER_ST2084,                ///< SMPTE ST 2084 for 10/12/14/16 bit systems
+    TRANSFER_HLG,                   ///< ARIB STD-B67 hybrid-log-gamma
+
+    TRANSFER_240M = 0x40,           ///< SMPTE 240M or equivalent
+    TRANSFER_XVYCC,                 ///< IEC 61966-2-4 or equivalent
+    TRANSFER_BT1361,                ///< Rec.ITU-R BT.1361 extended gamut
+    TRANSFER_ST428,                 ///< SMPTE ST 428-1 or equivalent
+                                    ///
+    TRANSFER_VENDOR_START = 0x80,   ///< vendor-specific transfer values start here
+    TRANSFER_OTHER = 0xff           ///< max value, reserved for undefined values
+)
+
+/// Matrix coefficient
+C2ENUM(C2Color::matrix_t, uint32_t,
+    MATRIX_UNSPECIFIED,             ///< matrix coefficients are unspecified
+    MATRIX_BT709,                   ///< Rec.ITU-R BT.709-5 or equivalent
+    MATRIX_FCC47_73_682,            ///< FCC Title 47 CFR 73.682 or equivalent (KR=0.30, KB=0.11)
+    MATRIX_BT601,                   ///< Rec.ITU-R BT.470, BT.601-6 625 or equivalent
+    MATRIX_240M,                    ///< SMPTE 240M or equivalent
+    MATRIX_BT2020,                  ///< Rec.ITU-R BT.2020 non-constant luminance
+    MATRIX_BT2020_CONSTANT,         ///< Rec.ITU-R BT.2020 constant luminance
+    MATRIX_VENDOR_START = 0x80,     ///< vendor-specific matrix coefficient values start here
+    MATRIX_OTHER = 0xff,            ///< max value, reserved for undefined values
+
+    MATRIX_SMPTE240M = MATRIX_240M, // deprecated
+    MATRIX_BT2020CONSTANT = MATRIX_BT2020_CONSTANT, // deprecated
+)
+
+constexpr C2Color::matrix_t MATRIX_BT470_6M = MATRIX_FCC47_73_682; // deprecated
+constexpr C2Color::matrix_t MATRIX_BT709_5 = MATRIX_BT709; // deprecated
+constexpr C2Color::matrix_t MATRIX_BT601_6 = MATRIX_BT601; // deprecated
+
+struct C2ColorAspectsStruct {
+    C2Color::range_t range;
+    C2Color::primaries_t primaries;
+    C2Color::transfer_t transfer;
+    C2Color::matrix_t matrix;
+
+    C2ColorAspectsStruct()
+        : range(C2Color::RANGE_UNSPECIFIED),
+          primaries(C2Color::PRIMARIES_UNSPECIFIED),
+          transfer(C2Color::TRANSFER_UNSPECIFIED),
+          matrix(C2Color::MATRIX_UNSPECIFIED) { }
+
+    C2ColorAspectsStruct(C2Color::range_t range_, C2Color::primaries_t primaries_,
+                         C2Color::transfer_t transfer_, C2Color::matrix_t matrix_)
+        : range(range_), primaries(primaries_), transfer(transfer_), matrix(matrix_) {}
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(ColorAspects)
+    C2FIELD(range, "range")
+    C2FIELD(primaries, "primaries")
+    C2FIELD(transfer, "transfer")
+    C2FIELD(matrix, "matrix")
+};
+
+typedef C2StreamParam<C2Info, C2ColorAspectsStruct, kParamIndexColorAspects>
+        C2StreamColorAspectsInfo;
+constexpr char C2_PARAMKEY_COLOR_ASPECTS[] = "raw.color";
+constexpr char C2_PARAMKEY_VUI_COLOR_ASPECTS[] = "coded.vui.color";
+
+/**
+ * Default color aspects to use. These come from the container or client and shall be handled
+ * according to the coding standard.
+ */
+typedef C2StreamParam<C2Tuning, C2ColorAspectsStruct, kParamIndexDefaultColorAspects>
+        C2StreamColorAspectsTuning;
+constexpr char C2_PARAMKEY_DEFAULT_COLOR_ASPECTS[] = "default.color";
+
+/**
+ * HDR Static Metadata Info.
+ */
+struct C2ColorXyStruct {
+    float x; ///< x color coordinate in xyY space [0-1]
+    float y; ///< y color coordinate in xyY space [0-1]
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(ColorXy)
+    C2FIELD(x, "x")
+    C2FIELD(y, "y")
+};
+
+struct C2MasteringDisplayColorVolumeStruct {
+    C2ColorXyStruct red;    ///< coordinates of red display primary
+    C2ColorXyStruct green;  ///< coordinates of green display primary
+    C2ColorXyStruct blue;   ///< coordinates of blue display primary
+    C2ColorXyStruct white;  ///< coordinates of white point
+
+    float maxLuminance;  ///< max display mastering luminance in cd/m^2
+    float minLuminance;  ///< min display mastering luminance in cd/m^2
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(MasteringDisplayColorVolume)
+    C2FIELD(red, "red")
+    C2FIELD(green, "green")
+    C2FIELD(blue, "blue")
+    C2FIELD(white, "white")
+
+    C2FIELD(maxLuminance, "max-luminance")
+    C2FIELD(minLuminance, "min-luminance")
+};
+
+struct C2HdrStaticMetadataStruct {
+    C2MasteringDisplayColorVolumeStruct mastering;
+
+    // content descriptors
+    float maxCll;  ///< max content light level (pixel luminance) in cd/m^2
+    float maxFall; ///< max frame average light level (frame luminance) in cd/m^2
+
+    DEFINE_AND_DESCRIBE_BASE_C2STRUCT(HdrStaticMetadata)
+    C2FIELD(mastering, "mastering")
+    C2FIELD(maxCll, "max-cll")
+    C2FIELD(maxFall, "max-fall")
+};
+typedef C2StreamParam<C2Info, C2HdrStaticMetadataStruct, kParamIndexHdrStaticMetadata>
+        C2StreamHdrStaticInfo;
+constexpr char C2_PARAMKEY_HDR_STATIC_INFO[] = "raw.hdr-static-info";
+
+/* ------------------------------------ block-based coding ----------------------------------- */
+
+/**
+ * Block-size, block count and block rate. Used to determine or communicate profile-level
+ * requirements.
+ */
+typedef C2StreamParam<C2Info, C2PictureSizeStruct, kParamIndexBlockSize> C2StreamBlockSizeInfo;
+constexpr char C2_PARAMKEY_BLOCK_SIZE[] = "coded.block-size";
+
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexBlockCount> C2StreamBlockCountInfo;
+constexpr char C2_PARAMKEY_BLOCK_COUNT[] = "coded.block-count";
+
+typedef C2StreamParam<C2Info, C2FloatValue, kParamIndexBlockRate> C2StreamBlockRateInfo;
+constexpr char C2_PARAMKEY_BLOCK_RATE[] = "coded.block-rate";
+
+/* ====================================== VIDEO COMPONENTS ====================================== */
+
+/**
+ * Frame rate (coded and port for raw data)
+ *
+ * Coded frame rates are what is represented in the compressed bitstream and should correspond to
+ * the timestamp.
+ *
+ * Frame rates on raw ports should still correspond to the timestamps.
+ *
+ * For slow motion or timelapse recording, the timestamp shall be adjusted prior to feeding an
+ * encoder, and the time stretch parameter should be used to signal the relationship between
+ * timestamp and real-world time.
+ */
+typedef C2StreamParam<C2Info, C2FloatValue, kParamIndexFrameRate> C2StreamFrameRateInfo;
+constexpr char C2_PARAMKEY_FRAME_RATE[] = "coded.frame-rate";
+#define C2_NAME_STREAM_FRAME_RATE_SETTING C2_PARAMKEY_FRAME_RATE
+
+typedef C2PortParam<C2Info, C2FloatValue, kParamIndexFrameRate> C2PortFrameRateInfo;
+constexpr char C2_PARAMKEY_INPUT_FRAME_RATE[] = "input.frame-rate";
+constexpr char C2_PARAMKEY_OUTPUT_FRAME_RATE[] = "output.frame-rate";
+
+/**
+ * Time stretch. Ratio between real-world time and timestamp. E.g. time stretch of 4.0 means that
+ * timestamp grows 1/4 the speed of real-world time (e.g. 4x slo-mo input). This can be used to
+ * optimize encoding.
+ */
+typedef C2PortParam<C2Info, C2FloatValue, kParamIndexTimeStretch> C2PortTimeStretchInfo;
+constexpr char C2_PARAMKEY_INPUT_TIME_STRETCH[] = "input.time-stretch";
+constexpr char C2_PARAMKEY_OUTPUT_TIME_STRETCH[] = "output.time-stretch";
+
+/**
+ * Max video frame size.
+ */
+typedef C2StreamParam<C2Tuning, C2PictureSizeStruct, kParamIndexMaxPictureSize>
+        C2StreamMaxPictureSizeTuning;
+typedef C2StreamMaxPictureSizeTuning C2MaxVideoSizeHintPortSetting;
+constexpr char C2_PARAMKEY_MAX_PICTURE_SIZE[] = "raw.max-size";
+
+/**
+ * Picture type mask.
+ */
+C2ENUM(C2Config::picture_type_t, uint32_t,
+    SYNC_FRAME = (1 << 0),  ///< sync frame, e.g. IDR
+    I_FRAME    = (1 << 1),  ///< intra frame that is completely encoded
+    P_FRAME    = (1 << 2),  ///< inter predicted frame from previous frames
+    B_FRAME    = (1 << 3),  ///< backward predicted (out-of-order) frame
+)
+
+typedef C2Config::picture_type_t C2PictureTypeMask; // deprecated
+constexpr C2Config::picture_type_t C2PictureTypeKeyFrame = C2Config::SYNC_FRAME; // deprecated
+
+/**
+ * Allowed picture types.
+ */
+typedef C2StreamParam<C2Tuning, C2SimpleValueStruct<C2EasyEnum<C2Config::picture_type_t>>,
+                kParamIndexPictureTypeMask>
+        C2StreamPictureTypeMaskTuning;
+constexpr char C2_PARAMKEY_PICTURE_TYPE_MASK[] = "coding.picture-type-mask";
+
+/**
+ * Resulting picture type
+ */
+typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2EasyEnum<C2Config::picture_type_t>>,
+                kParamIndexPictureType>
+        C2StreamPictureTypeInfo;
+typedef C2StreamPictureTypeInfo C2StreamPictureTypeMaskInfo;
+constexpr char C2_PARAMKEY_PICTURE_TYPE[] = "coded.picture-type";
+
+/**
+ * GOP specification.
+ *
+ * GOP is specified in layers between sync frames, by specifying the number of specific type of
+ * frames between the previous type (starting with sync frames for the first layer):
+ *
+ * E.g.
+ *      - 4 I frames between each sync frame
+ *      - 2 P frames between each I frame
+ *      - 1 B frame between each P frame
+ *
+ *      [ { I, 4 }, { P, 2 }, { B, 1 } ] ==> (Sync)BPBPB IBPBPB IBPBPB IBPBPB IBPBPB (Sync)BPBPB
+ *
+ * For infinite GOP, I layer can be omitted (as the first frame is always a sync frame.):
+ *
+ *      [ { P, MAX_UINT } ]   ==> (Sync)PPPPPPPPPPPPPPPPPP...
+ *
+ * Sync frames can also be requested on demand, and as a time-based interval. For time-based
+ * interval, if there hasn't been a sync frame in at least the given time, the next I frame shall
+ * be encoded as a sync frame.  For sync request, the next I frame shall be encoded as a sync frame.
+ *
+ * Temporal layering will determine GOP structure other than the I frame count between sync
+ * frames.
+ */
+struct C2GopLayerStruct {
+    C2GopLayerStruct(C2Config::picture_type_t type, uint32_t count_)
+        : type_(type), count(count_) { }
+
+    C2Config::picture_type_t type_;
+    uint32_t count;
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(GopLayer)
+    C2FIELD(type_, "type")
+    C2FIELD(count, "count")
+};
+
+typedef C2StreamParam<C2Tuning, C2SimpleArrayStruct<C2GopLayerStruct>, kParamIndexGop>
+        C2StreamGopTuning;
+constexpr char C2_PARAMKEY_GOP[] = "coding.gop";
+
+/**
+ * Sync frame can be requested on demand by the client.
+ *
+ * If true, the next I frame shall be encoded as a sync frame. This config can be passed
+ * synchronously with the work, or directly to the component - leading to different result.
+ * If it is passed with work, it shall take effect when that work item is being processed (so
+ * the first I frame at or after that work item shall be a sync frame).
+ */
+typedef C2StreamParam<C2Tuning, C2EasyBoolValue, kParamIndexRequestSyncFrame>
+        C2StreamRequestSyncFrameTuning;
+constexpr char C2_PARAMKEY_REQUEST_SYNC_FRAME[] = "coding.request-sync-frame";
+
+/**
+ * Sync frame interval in time domain (timestamp).
+ *
+ * If there hasn't been a sync frame in at least this value, the next intra frame shall be encoded
+ * as a sync frame. The value of MAX_I64 or a negative value means no sync frames after the first
+ * frame. A value of 0 means all sync frames.
+ */
+typedef C2StreamParam<C2Tuning, C2Int64Value, kParamIndexSyncFrameInterval>
+        C2StreamSyncFrameIntervalTuning;
+constexpr char C2_PARAMKEY_SYNC_FRAME_INTERVAL[] = "coding.sync-frame-interval";
+// deprecated
+#define C2_PARAMKEY_SYNC_FRAME_PERIOD C2_PARAMKEY_SYNC_FRAME_INTERVAL
+
+/**
+ * Temporal layering
+ *
+ * Layer index is a value between 0 and layer count - 1. Layers with higher index have higher
+ * frequency:
+ *     0
+ *   1   1
+ *  2 2 2 2
+ */
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexLayerIndex> C2StreamLayerIndexInfo;
+constexpr char C2_PARAMKEY_LAYER_INDEX[] = "coded.layer-index";
+
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexLayerCount> C2StreamLayerCountInfo;
+constexpr char C2_PARAMKEY_LAYER_COUNT[] = "coded.layer-count";
+
+struct C2TemporalLayeringStruct {
+    C2TemporalLayeringStruct()
+        : layerCount(0), bLayerCount(0) { }
+
+    C2TemporalLayeringStruct(size_t /* flexCount */, uint32_t layerCount_, uint32_t bLayerCount_)
+        : layerCount(layerCount_), bLayerCount(c2_min(layerCount_, bLayerCount_)) { }
+
+    C2TemporalLayeringStruct(size_t flexCount, uint32_t layerCount_, uint32_t bLayerCount_,
+                             std::initializer_list<float> ratios)
+        : layerCount(layerCount_), bLayerCount(c2_min(layerCount_, bLayerCount_)) {
+        size_t ix = 0;
+        for (float ratio : ratios) {
+            if (ix == flexCount) {
+                break;
+            }
+            bitrateRatios[ix++] = ratio;
+        }
+    }
+
+    uint32_t layerCount;     ///< total number of layers (0 means no temporal layering)
+    uint32_t bLayerCount;    ///< total number of bidirectional layers (<= num layers)
+    /**
+     * Bitrate budgets for each layer and the layers below, given as a ratio of the total
+     * stream bitrate. This can be omitted or partially specififed by the client while configuring,
+     * in which case the component shall fill in appropriate values for the missing layers.
+     * This must be provided by the component when queried for at least layer count - 1 (as the
+     * last layer's budget is always 1.0).
+     */
+    float bitrateRatios[];   ///< 1.0-based
+
+    DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(TemporalLayering, bitrateRatios)
+    C2FIELD(layerCount, "layer-count")
+    C2FIELD(bLayerCount, "b-layer-count")
+    C2FIELD(bitrateRatios, "bitrate-ratios")
+};
+
+typedef C2StreamParam<C2Tuning, C2TemporalLayeringStruct, kParamIndexTemporalLayering>
+        C2StreamTemporalLayeringTuning;
+constexpr char C2_PARAMKEY_TEMPORAL_LAYERING[] = "coding.temporal-layering";
+
+/**
+ * Intra-refresh.
+ */
+
+C2ENUM(C2Config::intra_refresh_mode_t, uint32_t,
+    INTRA_REFRESH_DISABLED,     ///< no intra refresh
+    INTRA_REFRESH_ARBITRARY,    ///< arbitrary, unspecified
+)
+
+struct C2IntraRefreshStruct {
+    C2IntraRefreshStruct()
+        : mode(C2Config::INTRA_REFRESH_DISABLED), period(0.) { }
+
+    C2IntraRefreshStruct(C2Config::intra_refresh_mode_t mode_, float period_)
+        : mode(mode_), period(period_) { }
+
+    C2Config::intra_refresh_mode_t mode; ///< refresh mode
+    float period;         ///< intra refresh period in frames (must be >= 1), 0 means disabled
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(IntraRefresh)
+    C2FIELD(mode, "mode")
+    C2FIELD(period, "period")
+};
+
+typedef C2StreamParam<C2Tuning, C2IntraRefreshStruct, kParamIndexIntraRefresh>
+        C2StreamIntraRefreshTuning;
+constexpr char C2_PARAMKEY_INTRA_REFRESH[] = "coding.intra-refresh";
+
+/* ====================================== IMAGE COMPONENTS ====================================== */
+
+/**
+ * Tile layout.
+ *
+ * This described how the image is decomposed into tiles.
+ */
+C2ENUM(C2Config::scan_order_t, uint32_t,
+    SCAN_LEFT_TO_RIGHT_THEN_DOWN
+)
+
+struct C2TileLayoutStruct {
+    C2PictureSizeStruct tile;       ///< tile size
+    uint32_t columnCount;           ///< number of tiles horizontally
+    uint32_t rowCount;              ///< number of tiles vertically
+    C2Config::scan_order_t order;   ///< tile order
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(TileLayout)
+    C2FIELD(tile, "tile")
+    C2FIELD(columnCount, "columns")
+    C2FIELD(rowCount, "rows")
+    C2FIELD(order, "order")
+};
+
+typedef C2StreamParam<C2Info, C2TileLayoutStruct, kParamIndexTileLayout> C2StreamTileLayoutInfo;
+constexpr char C2_PARAMKEY_TILE_LAYOUT[] = "coded.tile-layout";
+
+/**
+ * Tile handling.
+ *
+ * Whether to concatenate tiles or output them each.
+ */
+C2ENUM(C2Config::tiling_mode_t, uint32_t,
+    TILING_SEPARATE,    ///< output each tile in a separate onWorkDone
+    TILING_CONCATENATE  ///< output one work completion per frame (concatenate tiles)
+)
+
+typedef C2StreamParam<C2Tuning, C2TileLayoutStruct, kParamIndexTileHandling>
+        C2StreamTileHandlingTuning;
+constexpr char C2_PARAMKEY_TILE_HANDLING[] = "coding.tile-handling";
+
+/* ====================================== AUDIO COMPONENTS ====================================== */
+
+/**
+ * Sample rate
+ */
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexSampleRate> C2StreamSampleRateInfo;
+constexpr char C2_PARAMKEY_SAMPLE_RATE[] = "raw.sample-rate";
+constexpr char C2_PARAMKEY_CODED_SAMPLE_RATE[] = "coded.sample-rate";
+// deprecated
+#define C2_NAME_STREAM_SAMPLE_RATE_SETTING C2_PARAMKEY_SAMPLE_RATE
+
+/**
+ * Channel count.
+ */
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexChannelCount> C2StreamChannelCountInfo;
+constexpr char C2_PARAMKEY_CHANNEL_COUNT[] = "raw.channel-count";
+constexpr char C2_PARAMKEY_CODED_CHANNEL_COUNT[] = "coded.channel-count";
+// deprecated
+#define C2_NAME_STREAM_CHANNEL_COUNT_SETTING C2_PARAMKEY_CHANNEL_COUNT
+
+/**
+ * Max channel count. Used to limit the number of coded or decoded channels.
+ */
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexMaxChannelCount> C2StreamMaxChannelCountInfo;
+constexpr char C2_PARAMKEY_MAX_CHANNEL_COUNT[] = "raw.max-channel-count";
+constexpr char C2_PARAMKEY_MAX_CODED_CHANNEL_COUNT[] = "coded.max-channel-count";
+
+/**
+ * Audio sample format (PCM encoding)
+ */
+C2ENUM(C2Config::pcm_encoding_t, uint32_t,
+    PCM_16,
+    PCM_8,
+    PCM_FLOAT
+)
+
+typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2Config::pcm_encoding_t>, kParamIndexPcmEncoding>
+        C2StreamPcmEncodingInfo;
+constexpr char C2_PARAMKEY_PCM_ENCODING[] = "raw.pcm-encoding";
+constexpr char C2_PARAMKEY_CODED_PCM_ENCODING[] = "coded.pcm-encoding";
+
+/**
+ * AAC SBR Mode. Used during encoding.
+ */
+C2ENUM(C2Config::aac_sbr_mode_t, uint32_t,
+    AAC_SBR_OFF,
+    AAC_SBR_SINGLE_RATE,
+    AAC_SBR_DUAL_RATE,
+    AAC_SBR_AUTO ///< let the codec decide
+)
+
+typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2Config::aac_sbr_mode_t>, kParamIndexAacSbrMode>
+        C2StreamAacSbrModeTuning;
+constexpr char C2_PARAMKEY_AAC_SBR_MODE[] = "coding.aac-sbr-mode";
+
+/**
+ * DRC Compression. Used during decoding.
+ */
+C2ENUM(C2Config::drc_compression_mode_t, int32_t,
+    DRC_COMPRESSION_ODM_DEFAULT, ///< odm's default
+    DRC_COMPRESSION_NONE,
+    DRC_COMPRESSION_LIGHT,
+    DRC_COMPRESSION_HEAVY ///<
+)
+
+typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2Config::drc_compression_mode_t>,
+                kParamIndexDrcCompression>
+        C2StreamDrcCompressionModeTuning;
+constexpr char C2_PARAMKEY_DRC_COMPRESSION_MODE[] = "coding.drc.compression-mode";
+
+/**
+ * DRC target reference level in dBFS. Used during decoding.
+ */
+typedef C2StreamParam<C2Info, C2FloatValue, kParamIndexDrcTargetReferenceLevel>
+        C2StreamDrcTargetReferenceLevelTuning;
+constexpr char C2_PARAMKEY_DRC_TARGET_REFERENCE_LEVEL[] = "coding.drc.reference-level";
+
+/**
+ * DRC target reference level in dBFS. Used during decoding.
+ */
+typedef C2StreamParam<C2Info, C2FloatValue, kParamIndexDrcEncodedTargetLevel>
+        C2StreamDrcEncodedTargetLevelTuning;
+constexpr char C2_PARAMKEY_DRC_ENCODED_TARGET_LEVEL[] = "coding.drc.encoded-level";
+
+/**
+ * DRC target reference level in dBFS. Used during decoding.
+ */
+typedef C2StreamParam<C2Info, C2FloatValue, kParamIndexDrcBoostFactor>
+        C2StreamDrcBoostFactorTuning;
+constexpr char C2_PARAMKEY_DRC_BOOST_FACTOR[] = "coding.drc.boost-factor";
+
+/**
+ * DRC target reference level in dBFS. Used during decoding.
+ */
+typedef C2StreamParam<C2Info, C2FloatValue, kParamIndexDrcAttenuationFactor>
+        C2StreamDrcAttenuationFactorTuning;
+constexpr char C2_PARAMKEY_DRC_ATTENUATION_FACTOR[] = "coding.drc.attenuation-factor";
+
+/**
+ * DRC Effect Type (see ISO 23003-4) Uniform Dynamic Range Control. Used during decoding.
+ */
+C2ENUM(C2Config::drc_effect_type_t, int32_t,
+    DRC_EFFECT_ODM_DEFAULT = -2, ///< odm's default
+    DRC_EFFECT_OFF = -1,    ///< no DRC
+    DRC_EFFECT_NONE = 0,    ///< no DRC except to prevent clipping
+    DRC_EFFECT_LATE_NIGHT,
+    DRC_EFFECT_NOISY_ENVIRONMENT,
+    DRC_EFFECT_LIMITED_PLAYBACK_RANGE,
+    DRC_EFFECT_LOW_PLAYBACK_LEVEL,
+    DRC_EFFECT_DIALOG_ENHANCEMENT,
+    DRC_EFFECT_GENERAL_COMPRESSION
+)
+
+typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2Config::drc_effect_type_t>,
+                kParamIndexDrcEffectType>
+        C2StreamDrcEffectTypeTuning;
+constexpr char C2_PARAMKEY_DRC_EFFECT_TYPE[] = "coding.drc.effect-type";
+
+/* --------------------------------------- AAC components --------------------------------------- */
+
+/**
+ * AAC stream format
+ */
+C2ENUM(C2Config::aac_packaging_t, uint32_t,
+    AAC_PACKAGING_RAW,
+    AAC_PACKAGING_ADTS
+)
+
+typedef C2Config::aac_packaging_t C2AacStreamFormatKind; // deprecated
+// deprecated
+constexpr C2Config::aac_packaging_t C2AacStreamFormatRaw = C2Config::AAC_PACKAGING_RAW;
+constexpr C2Config::aac_packaging_t C2AacStreamFormatAdts = C2Config::AAC_PACKAGING_ADTS;
+
+typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2EasyEnum<C2Config::aac_packaging_t>>,
+        kParamIndexAacPackaging> C2StreamAacPackagingInfo;
+typedef C2StreamAacPackagingInfo C2StreamAacFormatInfo;
+constexpr char C2_PARAMKEY_AAC_PACKAGING[] = "coded.aac-packaging";
+#define C2_NAME_STREAM_AAC_FORMAT_SETTING C2_PARAMKEY_AAC_PACKAGING
+
+/* ================================ PLATFORM-DEFINED PARAMETERS ================================ */
+
+/**
+ * Platform level and features.
+ */
+enum C2Config::platform_level_t : uint32_t {
+    PLATFORM_P,   ///< support for Android 9.0 feature set
+};
+
+// read-only
+typedef C2GlobalParam<C2Setting, C2SimpleValueStruct<C2Config::platform_level_t>,
+                kParamIndexPlatformLevel>
+        C2PlatformLevelSetting;
+constexpr char C2_PARAMKEY_PLATFORM_LEVEL[] = "api.platform-level";
+
+enum C2Config::platform_feature_t : uint64_t {
+    // no platform-specific features have been defined
+};
+
+// read-only
+typedef C2GlobalParam<C2Setting, C2SimpleValueStruct<C2Config::platform_feature_t>,
+                kParamIndexPlatformFeatures>
+        C2PlatformFeaturesSetting;
+constexpr char C2_PARAMKEY_PLATFORM_FEATURES[] = "api.platform-features";
+
+/**
+ * This structure describes the preferred ion allocation parameters for a given memory usage.
+ */
+struct C2StoreIonUsageStruct {
+    inline C2StoreIonUsageStruct() {
+        memset(this, 0, sizeof(*this));
+    }
+
+    inline C2StoreIonUsageStruct(uint64_t usage_, uint32_t capacity_)
+        : usage(usage_), capacity(capacity_), heapMask(0), allocFlags(0), minAlignment(0) { }
+
+    uint64_t usage;        ///< C2MemoryUsage
+    uint32_t capacity;     ///< capacity
+    int32_t heapMask;      ///< ion heapMask
+    int32_t allocFlags;    ///< ion allocation flags
+    uint32_t minAlignment; ///< minimum alignment
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(StoreIonUsage)
+    C2FIELD(usage, "usage")
+    C2FIELD(capacity, "capacity")
+    C2FIELD(heapMask, "heap-mask")
+    C2FIELD(allocFlags, "alloc-flags")
+    C2FIELD(minAlignment, "min-alignment")
+};
+
+// store, private
+typedef C2GlobalParam<C2Info, C2StoreIonUsageStruct, kParamIndexStoreIonUsage>
+        C2StoreIonUsageInfo;
+
+/**
+ * Flexible pixel format descriptors
+ */
+struct C2FlexiblePixelFormatDescriptorStruct {
+    uint32_t pixelFormat;
+    uint32_t bitDepth;
+    C2Color::subsampling_t subsampling;
+    C2Color::plane_layout_t layout;
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(FlexiblePixelFormatDescriptor)
+    C2FIELD(pixelFormat, "pixel-format")
+    C2FIELD(bitDepth, "bit-depth")
+    C2FIELD(subsampling, "subsampling")
+    C2FIELD(layout, "layout")
+};
+
+/**
+ * Plane layout of flexible pixel formats.
+ *
+ * bpp: bytes per color component, e.g. 1 for 8-bit formats, and 2 for 10-16-bit formats.
+ */
+C2ENUM(C2Color::plane_layout_t, uint32_t,
+       /** Unknown layout */
+       UNKNOWN_LAYOUT,
+
+       /** Planar layout with rows of each plane packed (colInc = bpp) */
+       PLANAR_PACKED,
+
+       /** Semiplanar layout with rows of each plane packed (colInc_Y/A = bpp (planar),
+        *  colInc_Cb/Cr = 2*bpp (interleaved). Used only for YUV(A) formats. */
+       SEMIPLANAR_PACKED,
+
+       /** Interleaved packed. colInc = N*bpp (N are the number of color components) */
+       INTERLEAVED_PACKED,
+
+       /** Interleaved aligned. colInc = smallest power of 2 >= N*bpp (N are the number of color
+        *  components) */
+       INTERLEAVED_ALIGNED
+)
+
+typedef C2GlobalParam<C2Info, C2SimpleArrayStruct<C2FlexiblePixelFormatDescriptorStruct>,
+                kParamIndexFlexiblePixelFormatDescriptors>
+        C2StoreFlexiblePixelFormatDescriptorsInfo;
+
+/**
+ * This structure describes the android dataspace for a raw video/image frame.
+ */
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexDataSpace> C2StreamDataSpaceInfo;
+constexpr char C2_PARAMKEY_DATA_SPACE[] = "raw.data-space";
+
+/**
+ * This structure describes the android surface scaling mode for a raw video/image frame.
+ */
+typedef C2StreamParam<C2Info, C2Uint32Value, kParamIndexSurfaceScaling> C2StreamSurfaceScalingInfo;
+constexpr char C2_PARAMKEY_SURFACE_SCALING_MODE[] = "raw.surface-scaling";
+
+/* ======================================= INPUT SURFACE ======================================= */
+
+/**
+ * Input surface EOS
+ */
+typedef C2GlobalParam<C2Tuning, C2EasyBoolValue, kParamIndexInputSurfaceEos>
+        C2InputSurfaceEosTuning;
+constexpr char C2_PARAMKEY_INPUT_SURFACE_EOS[] = "input-surface.eos";
+#define C2_NAME_INPUT_SURFACE_EOS_TUNING C2_PARAMKEY_INPUT_SURFACE_EOS
+
+/**
+ * Start/suspend/resume/stop controls and timestamps for input surface.
+ *
+ * TODO: make these counters
+ */
+
+struct C2TimedControlStruct {
+    c2_bool_t enabled; ///< control is enabled
+    int64_t timestamp; ///< if enabled, time the control should take effect
+
+    C2TimedControlStruct()
+        : enabled(C2_FALSE), timestamp(0) { }
+
+    /* implicit */ C2TimedControlStruct(uint64_t timestamp_)
+        : enabled(C2_TRUE), timestamp(timestamp_) { }
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(TimedControl)
+    C2FIELD(enabled,   "enabled")
+    C2FIELD(timestamp, "timestamp")
+};
+
+typedef C2PortParam<C2Tuning, C2TimedControlStruct, kParamIndexStartAt>
+        C2PortStartTimestampTuning;
+constexpr char C2_PARAMKEY_INPUT_SURFACE_START_AT[] = "input-surface.start";
+typedef C2PortParam<C2Tuning, C2TimedControlStruct, kParamIndexSuspendAt>
+        C2PortSuspendTimestampTuning;
+constexpr char C2_PARAMKEY_INPUT_SURFACE_SUSPEND_AT[] = "input-surface.suspend";
+typedef C2PortParam<C2Tuning, C2TimedControlStruct, kParamIndexResumeAt>
+        C2PortResumeTimestampTuning;
+constexpr char C2_PARAMKEY_INPUT_SURFACE_RESUME_AT[] = "input-surface.resume";
+typedef C2PortParam<C2Tuning, C2TimedControlStruct, kParamIndexStopAt>
+        C2PortStopTimestampTuning;
+constexpr char C2_PARAMKEY_INPUT_SURFACE_STOP_AT[] = "input-surface.stop";
+
+/**
+ * Time offset for input surface. Input timestamp to codec is surface buffer timestamp plus this
+ * time offset.
+ */
+typedef C2GlobalParam<C2Tuning, C2Int64Value, kParamIndexTimeOffset> C2ComponentTimeOffsetTuning;
+constexpr char C2_PARAMKEY_INPUT_SURFACE_TIME_OFFSET[] = "input-surface.time-offset";
+
+/**
+ * Minimum fps for input surface.
+ *
+ * Repeat frame to meet this.
+ */
+typedef C2PortParam<C2Tuning, C2FloatValue, kParamIndexMinFrameRate> C2PortMinFrameRateTuning;
+constexpr char C2_PARAMKEY_INPUT_SURFACE_MIN_FRAME_RATE[] = "input-surface.min-frame-rate";
+
+/**
+ * Timestamp adjustment (override) for input surface buffers. These control the input timestamp
+ * fed to the codec, but do not impact the output timestamp.
+ */
+struct C2TimestampGapAdjustmentStruct {
+    /// control modes
+    enum mode_t : uint32_t;
+
+    inline C2TimestampGapAdjustmentStruct();
+
+    inline C2TimestampGapAdjustmentStruct(mode_t mode_, uint64_t value_)
+        : mode(mode_), value(value_) { }
+
+    mode_t mode;    ///< control mode
+    uint64_t value; ///< control value for gap between two timestamp
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(TimestampGapAdjustment)
+    C2FIELD(mode, "mode")
+    C2FIELD(value, "value")
+};
+
+C2ENUM(C2TimestampGapAdjustmentStruct::mode_t, uint32_t,
+    NONE,
+    MIN_GAP,
+    FIXED_GAP,
+);
+
+inline C2TimestampGapAdjustmentStruct::C2TimestampGapAdjustmentStruct()
+    : mode(C2TimestampGapAdjustmentStruct::NONE), value(0) { }
+
+typedef C2PortParam<C2Tuning, C2TimestampGapAdjustmentStruct> C2PortTimestampGapTuning;
+constexpr char C2_PARAMKEY_INPUT_SURFACE_TIMESTAMP_ADJUSTMENT[] = "input-surface.timestamp-adjustment";
+
+/// @}
+
+#endif  // C2CONFIG_H_
diff --git a/media/codec2/include/C2Enum.h b/media/codec2/include/C2Enum.h
new file mode 100644
index 0000000..b0fad8f
--- /dev/null
+++ b/media/codec2/include/C2Enum.h
@@ -0,0 +1,228 @@
+/*
+ * 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 C2ENUM_H_
+#define C2ENUM_H_
+
+#include <C2Param.h>
+#include <_C2MacroUtils.h>
+
+#include <utility>
+#include <vector>
+
+/** \file
+ * Tools for easier enum support.
+ */
+
+/// \cond INTERNAL
+
+/* ---------------------------- UTILITIES FOR ENUMERATION REFLECTION ---------------------------- */
+
+/**
+ * Utility class that allows ignoring enum value assignment (e.g. both '(_C2EnumConst)kValue = x'
+ * and '(_C2EnumConst)kValue' will eval to kValue.
+ */
+template<typename T>
+class _C2EnumConst {
+public:
+    // implicit conversion from T
+    inline _C2EnumConst(T value) : _mValue(value) {}
+    // implicit conversion to T
+    inline operator T() { return _mValue; }
+    // implicit conversion to C2Value::Primitive
+    inline operator C2Value::Primitive() { return (T)_mValue; }
+    // ignore assignment and return T here to avoid implicit conversion to T later
+    inline T &operator =(T value __unused) { return _mValue; }
+private:
+    T _mValue;
+};
+
+/// mapper to get name of enum
+/// \note this will contain any initialization, which we will remove when converting to lower-case
+#define _C2_GET_ENUM_NAME(x, y) #x
+/// mapper to get value of enum
+#define _C2_GET_ENUM_VALUE(x, type) (_C2EnumConst<type>)x
+
+/// \endcond
+
+class _C2EnumUtils {
+    static C2String camelCaseToDashed(C2String name);
+
+    static std::vector<C2String> sanitizeEnumValueNames(
+            const std::vector<C2StringLiteral> names,
+            C2StringLiteral _prefix = nullptr);
+
+    friend class C2UtilTest_EnumUtilsTest_Test;
+
+public:
+    // this may not be used...
+    static C2_HIDE std::vector<C2String> parseEnumValuesFromString(C2StringLiteral value);
+
+    template<typename T>
+    static C2_HIDE C2FieldDescriptor::NamedValuesType sanitizeEnumValues(
+            std::vector<T> values,
+            std::vector<C2StringLiteral> names,
+            C2StringLiteral prefix = nullptr) {
+        C2FieldDescriptor::NamedValuesType namedValues;
+        std::vector<C2String> sanitizedNames = sanitizeEnumValueNames(names, prefix);
+        for (size_t i = 0; i < values.size() && i < sanitizedNames.size(); ++i) {
+            namedValues.emplace_back(sanitizedNames[i], values[i]);
+        }
+        return namedValues;
+    }
+
+    template<typename E>
+    static C2_HIDE C2FieldDescriptor::NamedValuesType customEnumValues(
+            std::vector<std::pair<C2StringLiteral, E>> items) {
+        C2FieldDescriptor::NamedValuesType namedValues;
+        for (auto &item : items) {
+            namedValues.emplace_back(item.first, item.second);
+        }
+        return namedValues;
+    }
+};
+
+#define DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, ...) \
+    _DEFINE_C2_ENUM_VALUE_AUTO_HELPER(__C2_GENERATE_GLOBAL_VARS__, name, type, prefix, \
+            ##__VA_ARGS__)
+#define _DEFINE_C2_ENUM_VALUE_AUTO_HELPER(enabled, name, type, prefix, ...) \
+    __DEFINE_C2_ENUM_VALUE_AUTO_HELPER(enabled, name, type, prefix, ##__VA_ARGS__)
+#define __DEFINE_C2_ENUM_VALUE_AUTO_HELPER(enabled, name, type, prefix, ...) \
+    ___DEFINE_C2_ENUM_VALUE_AUTO_HELPER##enabled(name, type, prefix, ##__VA_ARGS__)
+#define ___DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, ...) \
+template<> \
+C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
+    return _C2EnumUtils::sanitizeEnumValues( \
+            std::vector<C2Value::Primitive> { _C2_MAP(_C2_GET_ENUM_VALUE, type, __VA_ARGS__) }, \
+            { _C2_MAP(_C2_GET_ENUM_NAME, type, __VA_ARGS__) }, \
+            prefix); \
+}
+#define ___DEFINE_C2_ENUM_VALUE_AUTO_HELPER__C2_GENERATE_GLOBAL_VARS__(name, type, prefix, ...)
+
+#define DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, names) \
+    _DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(__C2_GENERATE_GLOBAL_VARS__, name, names)
+#define _DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(enabled, name, names) \
+    __DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(enabled, name, names)
+#define __DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(enabled, name, names) \
+    ___DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER##enabled(name, names)
+#define ___DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, names) \
+template<> \
+C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
+    return _C2EnumUtils::customEnumValues( \
+            std::vector<std::pair<C2StringLiteral, name>> names); \
+}
+#define ___DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER__C2_GENERATE_GLOBAL_VARS__(name, names)
+
+/**
+ * Defines an enum type with the default named value mapper. The default mapper
+ * finds and removes the longest common prefix across all of the enum value names, and
+ * replaces camel-case separators with dashes ('-').
+ *
+ * This macro must be used in the global scope and namespace.
+ *
+ *  ~~~~~~~~~~~~~ (.cpp)
+ *  C2ENUM(c2_enum_t, uint32_t,
+ *    C2_VALUE1,
+ *    C2_VALUE2 = 5,
+ *    C2_VALUE3 = C2_VALUE1 + 1)
+ *  // named values are: C2_VALUE1 => "1", C2_VALUE2 => "2", ...
+ *  // longest common prefix is "C2_VALUE"
+ *  ~~~~~~~~~~~~~
+ *
+ * \param name name of the enum type (This can be an inner class enum.)
+ * \param type underlying type
+ */
+#define C2ENUM(name, type, ...) \
+enum name : type { __VA_ARGS__ }; \
+DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, nullptr, __VA_ARGS__)
+
+/**
+ * Defines an enum type with the default named value mapper but custom prefix. The default
+ * mapper removes the prefix from all of the enum value names (if present), and
+ * inserts dashes at camel-case separators (lowHigh becomes low-high) and also replaces
+ * non-leading underscores with dashes ('-').
+ *
+ * This macro must be used in the global scope and namespace.
+ *
+ *  ~~~~~~~~~~~~~ (.cpp)
+ *  C2ENUM_CUSTOM_PREFIX(c2_enum_t, uint32_t, "C2_",
+ *    C2_VALUE1,
+ *    C2_VALUE2 = 5,
+ *    C2_VALUE3 = C2_VALUE1 + 1)
+ *  // named values are: C2_VALUE1 => "VALUE1", C2_VALUE2 => "VALUE2", ...
+ *  ~~~~~~~~~~~~~
+ *
+ * \param name name of the enum type (This can be an inner class enum.)
+ * \param type underlying type
+ * \param prefix prefix to remove
+ */
+#define C2ENUM_CUSTOM_PREFIX(name, type, prefix, ...) \
+enum name : type { __VA_ARGS__ }; \
+DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, __VA_ARGS__)
+
+/**
+ * Defines an enum type with custom names.
+ *
+ * This macro must be used in the global scope and namespace.
+ *
+ *  ~~~~~~~~~~~~~ (.cpp)
+ *  C2ENUM_CUSTOM_NAMES(SomeStruct::c2_enum_t, uint32_t, ({
+ *      { "One", SomeStruct::C2_VALUE1 },
+ *      { "Two", SomeStruct::C2_VALUE2 },
+ *      { "Three", SomeStruct::C2_VALUE3 } }),
+ *    C2_VALUE1,
+ *    C2_VALUE2 = 5,
+ *    C2_VALUE3 = C2_VALUE1 + 1)
+ *
+ *  // named values are: C2_VALUE1 => "One", C2_VALUE2 => "Two", ...
+ *  ~~~~~~~~~~~~~
+ */
+#define C2ENUM_CUSTOM_NAMES(name, type, names, ...) \
+enum name : type { __VA_ARGS__ }; \
+DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, names)
+
+/**
+ * Make enums usable as their integral types.
+ *
+ * Note: this makes them not usable in printf()
+ */
+template<class E>
+struct C2EasyEnum {
+    using U = typename std::underlying_type<E>::type;
+    E value;
+    // define conversion functions
+    inline constexpr operator E() const { return value; }
+    inline constexpr C2EasyEnum(E value_) : value(value_) { }
+    inline constexpr C2EasyEnum(U value_) : value(E(value_)) { }
+    inline constexpr C2EasyEnum() = default;
+};
+
+// make C2EasyEnum behave like a regular enum
+
+namespace std {
+    template<typename E>
+    struct underlying_type<C2EasyEnum<E>> {
+        typedef typename underlying_type<E>::type type;
+    };
+
+    template<typename E>
+    struct is_enum<C2EasyEnum<E>> {
+        constexpr static bool value = true;
+    };
+}
+
+#endif  // C2ENUM_H_
+
diff --git a/media/codec2/include/C2Param.h b/media/codec2/include/C2Param.h
new file mode 100644
index 0000000..40be3b3
--- /dev/null
+++ b/media/codec2/include/C2Param.h
@@ -0,0 +1,1673 @@
+/*
+ * 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 C2PARAM_H_
+#define C2PARAM_H_
+
+#include <C2.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+/// \addtogroup Parameters
+/// @{
+
+/// \defgroup internal Internal helpers.
+
+/*!
+ * \file
+ * PARAMETERS: SETTINGs, TUNINGs, and INFOs
+ * ===
+ *
+ * These represent miscellaneous control and metadata information and are likely copied into
+ * kernel space. Therefore, these are C-like structures designed to carry just a small amount of
+ * information. We are using C++ to be able to add constructors, as well as non-virtual and class
+ * methods.
+ *
+ * ==Specification details:
+ *
+ * Restrictions:
+ *   - must be POD struct, e.g. no vtable (no virtual destructor)
+ *   - must have the same size in 64-bit and 32-bit mode (no size_t)
+ *   - as such, no pointer members
+ *   - some common member field names are reserved as they are defined as methods for all
+ *     parameters:
+ *     they are: size, type, kind, index and stream
+ *
+ * Behavior:
+ * - Params can be global (not related to input or output), related to input or output,
+ *   or related to an input/output stream.
+ * - All params are queried/set using a unique param index, which incorporates a potential stream
+ *   index and/or port.
+ * - Querying (supported) params MUST never fail.
+ * - All params MUST have default values.
+ * - If some fields have "unsupported" or "invalid" values during setting, this SHOULD be
+ *   communicated to the app.
+ *   a) Ideally, this should be avoided.  When setting parameters, in general, component should do
+ *     "best effort" to apply all settings. It should change "invalid/unsupported" values to the
+ *     nearest supported values.
+ *   - This is communicated to the client by changing the source values in tune()/
+ *     configure().
+ *   b) If falling back to a supported value is absolutely impossible, the component SHALL return
+ *     an error for the specific setting, but should continue to apply other settings.
+ *     TODO: this currently may result in unintended results.
+ *
+ * **NOTE:** unlike OMX, params are not versioned. Instead, a new struct with new param index
+ * SHALL be added as new versions are required.
+ *
+ * The proper subtype (Setting, Info or Param) is incorporated into the class type. Define structs
+ * to define multiple subtyped versions of related parameters.
+ *
+ * ==Implementation details:
+ *
+ * - Use macros to define parameters
+ * - All parameters must have a default constructor
+ *   - This is only used for instantiating the class in source (e.g. will not be used
+ *     when building a parameter by the framework from key/value pairs.)
+ */
+
+/// \ingroup internal
+
+/**
+ * Parameter base class.
+ */
+struct C2Param {
+    // param index encompasses the following:
+    //
+    // - kind (setting, tuning, info, struct)
+    // - scope
+    //   - direction (global, input, output)
+    //   - stream flag
+    //   - stream ID (usually 0)
+    // - and the parameter's type (core index)
+    //   - flexible parameter flag
+    //   - vendor extension flag
+    //   - type index (this includes the vendor extension flag)
+    //
+    // layout:
+    //
+    //        kind : <------- scope -------> : <----- core index ----->
+    //      +------+-----+---+------+--------+----|------+--------------+
+    //      | kind | dir | - |stream|streamID|flex|vendor|  type index  |
+    //      +------+-----+---+------+--------+----+------+--------------+
+    //  bit: 31..30 29.28       25   24 .. 17  16    15   14    ..     0
+    //
+public:
+    /**
+     * C2Param kinds, usable as bitmaps.
+     */
+    enum kind_t : uint32_t {
+        NONE    = 0,
+        STRUCT  = (1 << 0),
+        INFO    = (1 << 1),
+        SETTING = (1 << 2),
+        TUNING  = (1 << 3) | SETTING, // tunings are settings
+    };
+
+    /**
+     * The parameter type index specifies the underlying parameter type of a parameter as
+     * an integer value.
+     *
+     * Parameter types are divided into two groups: platform types and vendor types.
+     *
+     * Platform types are defined by the platform and are common for all implementations.
+     *
+     * Vendor types are defined by each vendors, so they may differ between implementations.
+     * It is recommended that vendor types be the same for all implementations by a specific
+     * vendor.
+     */
+    typedef uint32_t type_index_t;
+    enum : uint32_t {
+            TYPE_INDEX_VENDOR_START = 0x00008000, ///< vendor indices SHALL start after this
+    };
+
+    /**
+     * Core index is the underlying parameter type for a parameter. It is used to describe the
+     * layout of the parameter structure regardless of the component or parameter kind/scope.
+     *
+     * It is used to identify and distinguish global parameters, and also parameters on a given
+     * port or stream. They must be unique for the set of global parameters, as well as for the
+     * set of parameters on each port or each stream, but the same core index can be used for
+     * parameters on different streams or ports, as well as for global parameters and port/stream
+     * parameters.
+     *
+     * Multiple parameter types can share the same layout.
+     *
+     * \note The layout for all parameters with the same core index across all components must
+     * be identical.
+     */
+    struct CoreIndex {
+    //public:
+        enum : uint32_t {
+            IS_FLEX_FLAG = 0x00010000,
+        };
+
+    protected:
+        enum : uint32_t {
+            KIND_MASK      = 0xC0000000,
+            KIND_STRUCT    = 0x00000000,
+            KIND_TUNING    = 0x40000000,
+            KIND_SETTING   = 0x80000000,
+            KIND_INFO      = 0xC0000000,
+
+            DIR_MASK       = 0x30000000,
+            DIR_GLOBAL     = 0x20000000,
+            DIR_UNDEFINED  = DIR_MASK, // MUST have all bits set
+            DIR_INPUT      = 0x00000000,
+            DIR_OUTPUT     = 0x10000000,
+
+            IS_STREAM_FLAG  = 0x02000000,
+            STREAM_ID_MASK  = 0x01FE0000,
+            STREAM_ID_SHIFT = 17,
+            MAX_STREAM_ID   = STREAM_ID_MASK >> STREAM_ID_SHIFT,
+            STREAM_MASK     = IS_STREAM_FLAG | STREAM_ID_MASK,
+
+            IS_VENDOR_FLAG  = 0x00008000,
+            TYPE_INDEX_MASK = 0x0000FFFF,
+            CORE_MASK       = TYPE_INDEX_MASK | IS_FLEX_FLAG,
+        };
+
+    public:
+        /// constructor/conversion from uint32_t
+        inline CoreIndex(uint32_t index) : mIndex(index) { }
+
+        // no conversion from uint64_t
+        inline CoreIndex(uint64_t index) = delete;
+
+        /// returns true iff this is a vendor extension parameter
+        inline bool isVendor() const { return mIndex & IS_VENDOR_FLAG; }
+
+        /// returns true iff this is a flexible parameter (with variable size)
+        inline bool isFlexible() const { return mIndex & IS_FLEX_FLAG; }
+
+        /// returns the core index
+        /// This is the combination of the parameter type index and the flexible flag.
+        inline uint32_t coreIndex() const { return mIndex & CORE_MASK; }
+
+        /// returns the parameter type index
+        inline type_index_t typeIndex() const { return mIndex & TYPE_INDEX_MASK; }
+
+        DEFINE_FIELD_AND_MASK_BASED_COMPARISON_OPERATORS(CoreIndex, mIndex, CORE_MASK)
+
+    protected:
+        uint32_t mIndex;
+    };
+
+    /**
+     * Type encompasses the parameter's kind (tuning, setting, info), its scope (whether the
+     * parameter is global, input or output, and whether it is for a stream) and the its base
+     * index (which also determines its layout).
+     */
+    struct Type : public CoreIndex {
+    //public:
+        /// returns true iff this is a global parameter (not for input nor output)
+        inline bool isGlobal() const { return (mIndex & DIR_MASK) == DIR_GLOBAL; }
+        /// returns true iff this is an input or input stream parameter
+        inline bool forInput() const { return (mIndex & DIR_MASK) == DIR_INPUT; }
+        /// returns true iff this is an output or output stream parameter
+        inline bool forOutput() const { return (mIndex & DIR_MASK) == DIR_OUTPUT; }
+
+        /// returns true iff this is a stream parameter
+        inline bool forStream() const { return mIndex & IS_STREAM_FLAG; }
+        /// returns true iff this is a port (input or output) parameter
+        inline bool forPort() const   { return !forStream() && !isGlobal(); }
+
+        /// returns the parameter type: the parameter index without the stream ID
+        inline uint32_t type() const { return mIndex & (~STREAM_ID_MASK); }
+
+        /// return the kind (struct, info, setting or tuning) of this param
+        inline kind_t kind() const {
+            switch (mIndex & KIND_MASK) {
+                case KIND_STRUCT: return STRUCT;
+                case KIND_INFO: return INFO;
+                case KIND_SETTING: return SETTING;
+                case KIND_TUNING: return TUNING;
+                default: return NONE; // should not happen
+            }
+        }
+
+        /// constructor/conversion from uint32_t
+        inline Type(uint32_t index) : CoreIndex(index) { }
+
+        // no conversion from uint64_t
+        inline Type(uint64_t index) = delete;
+
+        DEFINE_FIELD_AND_MASK_BASED_COMPARISON_OPERATORS(Type, mIndex, ~STREAM_ID_MASK)
+
+    private:
+        friend struct C2Param;   // for setPort()
+        friend struct C2Tuning;  // for KIND_TUNING
+        friend struct C2Setting; // for KIND_SETTING
+        friend struct C2Info;    // for KIND_INFO
+        // for DIR_GLOBAL
+        template<typename T, typename S, int I, class F> friend struct C2GlobalParam;
+        template<typename T, typename S, int I, class F> friend struct C2PortParam;   // for kDir*
+        template<typename T, typename S, int I, class F> friend struct C2StreamParam; // for kDir*
+        friend struct _C2ParamInspector; // for testing
+
+        /**
+         * Sets the port/stream direction.
+         * @return true on success, false if could not set direction (e.g. it is global param).
+         */
+        inline bool setPort(bool output) {
+            if (isGlobal()) {
+                return false;
+            } else {
+                mIndex = (mIndex & ~DIR_MASK) | (output ? DIR_OUTPUT : DIR_INPUT);
+                return true;
+            }
+        }
+    };
+
+    /**
+     * index encompasses all remaining information: basically the stream ID.
+     */
+    struct Index : public Type {
+        /// returns the index as uint32_t
+        inline operator uint32_t() const { return mIndex; }
+
+        /// constructor/conversion from uint32_t
+        inline Index(uint32_t index) : Type(index) { }
+
+        /// copy constructor
+        inline Index(const Index &index) = default;
+
+        // no conversion from uint64_t
+        inline Index(uint64_t index) = delete;
+
+        /// returns the stream ID or ~0 if not a stream
+        inline unsigned stream() const {
+            return forStream() ? rawStream() : ~0U;
+        }
+
+        /// Returns an index with stream field set to given stream.
+        inline Index withStream(unsigned stream) const {
+            Index ix = mIndex;
+            (void)ix.setStream(stream);
+            return ix;
+        }
+
+        /// sets the port (direction). Returns true iff successful.
+        inline Index withPort(bool output) const {
+            Index ix = mIndex;
+            (void)ix.setPort(output);
+            return ix;
+        }
+
+        DEFINE_FIELD_BASED_COMPARISON_OPERATORS(Index, mIndex)
+
+    private:
+        friend struct C2Param;           // for setStream, MakeStreamId, isValid
+        friend struct _C2ParamInspector; // for testing
+
+        /**
+         * @return true if the type is valid, e.g. direction is not undefined AND
+         * stream is 0 if not a stream param.
+         */
+        inline bool isValid() const {
+            // there is no Type::isValid (even though some of this check could be
+            // performed on types) as this is only used on index...
+            return (forStream() ? rawStream() < MAX_STREAM_ID : rawStream() == 0)
+                    && (mIndex & DIR_MASK) != DIR_UNDEFINED;
+        }
+
+        /// returns the raw stream ID field
+        inline unsigned rawStream() const {
+            return (mIndex & STREAM_ID_MASK) >> STREAM_ID_SHIFT;
+        }
+
+        /// returns the streamId bitfield for a given |stream|. If stream is invalid,
+        /// returns an invalid bitfield.
+        inline static uint32_t MakeStreamId(unsigned stream) {
+            // saturate stream ID (max value is invalid)
+            if (stream > MAX_STREAM_ID) {
+                stream = MAX_STREAM_ID;
+            }
+            return (stream << STREAM_ID_SHIFT) & STREAM_ID_MASK;
+        }
+
+        inline bool convertToStream(bool output, unsigned stream) {
+            mIndex = (mIndex & ~DIR_MASK) | IS_STREAM_FLAG;
+            (void)setPort(output);
+            return setStream(stream);
+        }
+
+        inline void convertToPort(bool output) {
+            mIndex = (mIndex & ~(DIR_MASK | IS_STREAM_FLAG));
+            (void)setPort(output);
+        }
+
+        inline void convertToGlobal() {
+            mIndex = (mIndex & ~(DIR_MASK | IS_STREAM_FLAG)) | DIR_GLOBAL;
+        }
+
+        /**
+         * Sets the stream index.
+         * \return true on success, false if could not set index (e.g. not a stream param).
+         */
+        inline bool setStream(unsigned stream) {
+            if (forStream()) {
+                mIndex = (mIndex & ~STREAM_ID_MASK) | MakeStreamId(stream);
+                return this->stream() < MAX_STREAM_ID;
+            }
+            return false;
+        }
+    };
+
+public:
+    // public getters for Index methods
+
+    /// returns true iff this is a vendor extension parameter
+    inline bool isVendor() const { return _mIndex.isVendor(); }
+    /// returns true iff this is a flexible parameter
+    inline bool isFlexible() const { return _mIndex.isFlexible(); }
+    /// returns true iff this is a global parameter (not for input nor output)
+    inline bool isGlobal() const { return _mIndex.isGlobal(); }
+    /// returns true iff this is an input or input stream parameter
+    inline bool forInput() const { return _mIndex.forInput(); }
+    /// returns true iff this is an output or output stream parameter
+    inline bool forOutput() const { return _mIndex.forOutput(); }
+
+    /// returns true iff this is a stream parameter
+    inline bool forStream() const { return _mIndex.forStream(); }
+    /// returns true iff this is a port (input or output) parameter
+    inline bool forPort() const   { return _mIndex.forPort(); }
+
+    /// returns the stream ID or ~0 if not a stream
+    inline unsigned stream() const { return _mIndex.stream(); }
+
+    /// returns the parameter type: the parameter index without the stream ID
+    inline Type type() const { return _mIndex.type(); }
+
+    /// returns the index of this parameter
+    /// \todo: should we restrict this to C2ParamField?
+    inline uint32_t index() const { return (uint32_t)_mIndex; }
+
+    /// returns the core index of this parameter
+    inline CoreIndex coreIndex() const { return _mIndex.coreIndex(); }
+
+    /// returns the kind of this parameter
+    inline kind_t kind() const { return _mIndex.kind(); }
+
+    /// returns the size of the parameter or 0 if the parameter is invalid
+    inline size_t size() const { return _mSize; }
+
+    /// returns true iff the parameter is valid
+    inline operator bool() const { return _mIndex.isValid() && _mSize > 0; }
+
+    /// returns true iff the parameter is invalid
+    inline bool operator!() const { return !operator bool(); }
+
+    // equality is done by memcmp (use equals() to prevent any overread)
+    inline bool operator==(const C2Param &o) const {
+        return equals(o) && memcmp(this, &o, _mSize) == 0;
+    }
+    inline bool operator!=(const C2Param &o) const { return !operator==(o); }
+
+    /// safe(r) type cast from pointer and size
+    inline static C2Param* From(void *addr, size_t len) {
+        // _mSize must fit into size, but really C2Param must also to be a valid param
+        if (len < sizeof(C2Param)) {
+            return nullptr;
+        }
+        // _mSize must match length
+        C2Param *param = (C2Param*)addr;
+        if (param->_mSize != len) {
+            return nullptr;
+        }
+        return param;
+    }
+
+    /// Returns managed clone of |orig| at heap.
+    inline static std::unique_ptr<C2Param> Copy(const C2Param &orig) {
+        if (orig.size() == 0) {
+            return nullptr;
+        }
+        void *mem = ::operator new (orig.size());
+        C2Param *param = new (mem) C2Param(orig.size(), orig._mIndex);
+        param->updateFrom(orig);
+        return std::unique_ptr<C2Param>(param);
+    }
+
+    /// Returns managed clone of |orig| as a stream parameter at heap.
+    inline static std::unique_ptr<C2Param> CopyAsStream(
+            const C2Param &orig, bool output, unsigned stream) {
+        std::unique_ptr<C2Param> copy = Copy(orig);
+        if (copy) {
+            copy->_mIndex.convertToStream(output, stream);
+        }
+        return copy;
+    }
+
+    /// Returns managed clone of |orig| as a port parameter at heap.
+    inline static std::unique_ptr<C2Param> CopyAsPort(const C2Param &orig, bool output) {
+        std::unique_ptr<C2Param> copy = Copy(orig);
+        if (copy) {
+            copy->_mIndex.convertToPort(output);
+        }
+        return copy;
+    }
+
+    /// Returns managed clone of |orig| as a global parameter at heap.
+    inline static std::unique_ptr<C2Param> CopyAsGlobal(const C2Param &orig) {
+        std::unique_ptr<C2Param> copy = Copy(orig);
+        if (copy) {
+            copy->_mIndex.convertToGlobal();
+        }
+        return copy;
+    }
+
+#if 0
+    template<typename P, class=decltype(C2Param(P()))>
+    P *As() { return P::From(this); }
+    template<typename P>
+    const P *As() const { return const_cast<const P*>(P::From(const_cast<C2Param*>(this))); }
+#endif
+
+protected:
+    /// sets the stream field. Returns true iff successful.
+    inline bool setStream(unsigned stream) {
+        return _mIndex.setStream(stream);
+    }
+
+    /// sets the port (direction). Returns true iff successful.
+    inline bool setPort(bool output) {
+        return _mIndex.setPort(output);
+    }
+
+public:
+    /// invalidate this parameter. There is no recovery from this call; e.g. parameter
+    /// cannot be 'corrected' to be valid.
+    inline void invalidate() { _mSize = 0; }
+
+    // if other is the same kind of (valid) param as this, copy it into this and return true.
+    // otherwise, do not copy anything, and return false.
+    inline bool updateFrom(const C2Param &other) {
+        if (other._mSize <= _mSize && other._mIndex == _mIndex && _mSize > 0) {
+            memcpy(this, &other, other._mSize);
+            return true;
+        }
+        return false;
+    }
+
+protected:
+    // returns |o| if it is a null ptr, or if can suitably be a param of given |type| (e.g. has
+    // same type (ignoring stream ID), and size). Otherwise, returns null. If |checkDir| is false,
+    // allow undefined or different direction (e.g. as constructed from C2PortParam() vs.
+    // C2PortParam::input), but still require equivalent type (stream, port or global); otherwise,
+    // return null.
+    inline static const C2Param* IfSuitable(
+            const C2Param* o, size_t size, Type type, size_t flexSize = 0, bool checkDir = true) {
+        if (o == nullptr || o->_mSize < size || (flexSize && ((o->_mSize - size) % flexSize))) {
+            return nullptr;
+        } else if (checkDir) {
+            return o->_mIndex.type() == type.mIndex ? o : nullptr;
+        } else if (o->_mIndex.isGlobal()) {
+            return nullptr;
+        } else {
+            return ((o->_mIndex.type() ^ type.mIndex) & ~Type::DIR_MASK) ? nullptr : o;
+        }
+    }
+
+    /// base constructor
+    inline C2Param(uint32_t paramSize, Index paramIndex)
+        : _mSize(paramSize),
+          _mIndex(paramIndex) {
+        if (paramSize > sizeof(C2Param)) {
+            memset(this + 1, 0, paramSize - sizeof(C2Param));
+        }
+    }
+
+    /// base constructor with stream set
+    inline C2Param(uint32_t paramSize, Index paramIndex, unsigned stream)
+        : _mSize(paramSize),
+          _mIndex(paramIndex | Index::MakeStreamId(stream)) {
+        if (paramSize > sizeof(C2Param)) {
+            memset(this + 1, 0, paramSize - sizeof(C2Param));
+        }
+        if (!forStream()) {
+            invalidate();
+        }
+    }
+
+private:
+    friend struct _C2ParamInspector; // for testing
+
+    /// returns true iff |o| has the same size and index as this. This performs the
+    /// basic check for equality.
+    inline bool equals(const C2Param &o) const {
+        return _mSize == o._mSize && _mIndex == o._mIndex;
+    }
+
+    uint32_t _mSize;
+    Index _mIndex;
+};
+
+/// \ingroup internal
+/// allow C2Params access to private methods, e.g. constructors
+#define C2PARAM_MAKE_FRIENDS \
+    template<typename U, typename S, int I, class F> friend struct C2GlobalParam; \
+    template<typename U, typename S, int I, class F> friend struct C2PortParam; \
+    template<typename U, typename S, int I, class F> friend struct C2StreamParam; \
+
+/**
+ * Setting base structure for component method signatures. Wrap constructors.
+ */
+struct C2Setting : public C2Param {
+protected:
+    template<typename ...Args>
+    inline C2Setting(const Args(&... args)) : C2Param(args...) { }
+public: // TODO
+    enum : uint32_t { PARAM_KIND = Type::KIND_SETTING };
+};
+
+/**
+ * Tuning base structure for component method signatures. Wrap constructors.
+ */
+struct C2Tuning : public C2Setting {
+protected:
+    template<typename ...Args>
+    inline C2Tuning(const Args(&... args)) : C2Setting(args...) { }
+public: // TODO
+    enum : uint32_t { PARAM_KIND = Type::KIND_TUNING };
+};
+
+/**
+ * Info base structure for component method signatures. Wrap constructors.
+ */
+struct C2Info : public C2Param {
+protected:
+    template<typename ...Args>
+    inline C2Info(const Args(&... args)) : C2Param(args...) { }
+public: // TODO
+    enum : uint32_t { PARAM_KIND = Type::KIND_INFO };
+};
+
+/**
+ * Structure uniquely specifying a field in an arbitrary structure.
+ *
+ * \note This structure is used differently in C2FieldDescriptor to
+ * identify array fields, such that _mSize is the size of each element. This is
+ * because the field descriptor contains the array-length, and we want to keep
+ * a relevant element size for variable length arrays.
+ */
+struct _C2FieldId {
+//public:
+    /**
+     * Constructor used for C2FieldDescriptor that removes the array extent.
+     *
+     * \param[in] offset pointer to the field in an object at address 0.
+     */
+    template<typename T, class B=typename std::remove_extent<T>::type>
+    inline _C2FieldId(T* offset)
+        : // offset is from "0" so will fit on 32-bits
+          _mOffset((uint32_t)(uintptr_t)(offset)),
+          _mSize(sizeof(B)) { }
+
+    /**
+     * Direct constructor from offset and size.
+     *
+     * \param[in] offset offset of the field.
+     * \param[in] size size of the field.
+     */
+    inline _C2FieldId(size_t offset, size_t size)
+        : _mOffset(offset), _mSize(size) {}
+
+    /**
+     * Constructor used to identify a field in an object.
+     *
+     * \param U[type] pointer to the object that contains this field. This is needed in case the
+     *        field is in an (inherited) base class, in which case T will be that base class.
+     * \param pm[im] member pointer to the field
+     */
+    template<typename R, typename T, typename U, typename B=typename std::remove_extent<R>::type>
+    inline _C2FieldId(U *, R T::* pm)
+        : _mOffset((uint32_t)(uintptr_t)(&(((U*)256)->*pm)) - 256u),
+          _mSize(sizeof(B)) { }
+
+    /**
+     * Constructor used to identify a field in an object.
+     *
+     * \param pm[im] member pointer to the field
+     */
+    template<typename R, typename T, typename B=typename std::remove_extent<R>::type>
+    inline _C2FieldId(R T::* pm)
+        : _mOffset((uint32_t)(uintptr_t)(&(((T*)0)->*pm))),
+          _mSize(sizeof(B)) { }
+
+    inline bool operator==(const _C2FieldId &other) const {
+        return _mOffset == other._mOffset && _mSize == other._mSize;
+    }
+
+    inline bool operator<(const _C2FieldId &other) const {
+        return _mOffset < other._mOffset ||
+            // NOTE: order parent structure before sub field
+            (_mOffset == other._mOffset && _mSize > other._mSize);
+    }
+
+    DEFINE_OTHER_COMPARISON_OPERATORS(_C2FieldId)
+
+#if 0
+    inline uint32_t offset() const { return _mOffset; }
+    inline uint32_t size() const { return _mSize; }
+#endif
+
+#if defined(FRIEND_TEST)
+    friend void PrintTo(const _C2FieldId &d, ::std::ostream*);
+#endif
+
+private:
+    friend struct _C2ParamInspector;
+    friend struct C2FieldDescriptor;
+
+    uint32_t _mOffset; // offset of field
+    uint32_t _mSize;   // size of field
+};
+
+/**
+ * Structure uniquely specifying a 'field' in a configuration. The field
+ * can be a field of a configuration, a subfield of a field of a configuration,
+ * and even the whole configuration. Moreover, if the field can point to an
+ * element in a array field, or to the entire array field.
+ *
+ * This structure is used for querying supported values for a field, as well
+ * as communicating configuration failures and conflicts when trying to change
+ * a configuration for a component/interface or a store.
+ */
+struct C2ParamField {
+//public:
+    /**
+     * Create a field identifier using a configuration parameter (variable),
+     * and a pointer to member.
+     *
+     * ~~~~~~~~~~~~~ (.cpp)
+     *
+     * struct C2SomeParam {
+     *   uint32_t mField;
+     *   uint32_t mArray[2];
+     *   C2OtherStruct mStruct;
+     *   uint32_t mFlexArray[];
+     * } *mParam;
+     *
+     * C2ParamField(mParam, &mParam->mField);
+     * C2ParamField(mParam, &mParam->mArray);
+     * C2ParamField(mParam, &mParam->mArray[0]);
+     * C2ParamField(mParam, &mParam->mStruct.mSubField);
+     * C2ParamField(mParam, &mParam->mFlexArray);
+     * C2ParamField(mParam, &mParam->mFlexArray[2]);
+     *
+     * ~~~~~~~~~~~~~
+     *
+     * \todo fix what this is for T[] (for now size becomes T[1])
+     *
+     * \note this does not work for 64-bit members as it triggers a
+     * 'taking address of packed member' warning.
+     *
+     * \param param pointer to parameter
+     * \param offset member pointer
+     */
+    template<typename S, typename T>
+    inline C2ParamField(S* param, T* offset)
+        : _mIndex(param->index()),
+          _mFieldId((T*)((uintptr_t)offset - (uintptr_t)param)) {}
+
+    template<typename S, typename T>
+    inline static C2ParamField Make(S& param, T& offset) {
+        return C2ParamField(param.index(), (uintptr_t)&offset - (uintptr_t)&param, sizeof(T));
+    }
+
+    /**
+     * Create a field identifier using a configuration parameter (variable),
+     * and a member pointer. This method cannot be used to refer to an
+     * array element or a subfield.
+     *
+     * ~~~~~~~~~~~~~ (.cpp)
+     *
+     * C2SomeParam mParam;
+     * C2ParamField(&mParam, &C2SomeParam::mMemberField);
+     *
+     * ~~~~~~~~~~~~~
+     *
+     * \param p pointer to parameter
+     * \param T member pointer to the field member
+     */
+    template<typename R, typename T, typename U>
+    inline C2ParamField(U *p, R T::* pm) : _mIndex(p->index()), _mFieldId(p, pm) { }
+
+    /**
+     * Create a field identifier to a configuration parameter (variable).
+     *
+     * ~~~~~~~~~~~~~ (.cpp)
+     *
+     * C2SomeParam mParam;
+     * C2ParamField(&mParam);
+     *
+     * ~~~~~~~~~~~~~
+     *
+     * \param param pointer to parameter
+     */
+    template<typename S>
+    inline C2ParamField(S* param)
+        : _mIndex(param->index()), _mFieldId(0u, param->size()) { }
+
+    /** Copy constructor. */
+    inline C2ParamField(const C2ParamField &other) = default;
+
+    /**
+     * Equality operator.
+     */
+    inline bool operator==(const C2ParamField &other) const {
+        return _mIndex == other._mIndex && _mFieldId == other._mFieldId;
+    }
+
+    /**
+     * Ordering operator.
+     */
+    inline bool operator<(const C2ParamField &other) const {
+        return _mIndex < other._mIndex ||
+            (_mIndex == other._mIndex && _mFieldId < other._mFieldId);
+    }
+
+    DEFINE_OTHER_COMPARISON_OPERATORS(C2ParamField)
+
+protected:
+    inline C2ParamField(C2Param::Index index, uint32_t offset, uint32_t size)
+        : _mIndex(index), _mFieldId(offset, size) {}
+
+private:
+    friend struct _C2ParamInspector;
+
+    C2Param::Index _mIndex; ///< parameter index
+    _C2FieldId _mFieldId;   ///< field identifier
+};
+
+/**
+ * A shared (union) representation of numeric values
+ */
+class C2Value {
+public:
+    /// A union of supported primitive types.
+    union Primitive {
+        // first member is always zero initialized so it must be the largest
+        uint64_t    u64;   ///< uint64_t value
+        int64_t     i64;   ///< int64_t value
+        c2_cntr64_t c64;   ///< c2_cntr64_t value
+        uint32_t    u32;   ///< uint32_t value
+        int32_t     i32;   ///< int32_t value
+        c2_cntr32_t c32;   ///< c2_cntr32_t value
+        float       fp;    ///< float value
+
+        // constructors - implicit
+        Primitive(uint64_t value)    : u64(value) { }
+        Primitive(int64_t value)     : i64(value) { }
+        Primitive(c2_cntr64_t value) : c64(value) { }
+        Primitive(uint32_t value)    : u32(value) { }
+        Primitive(int32_t value)     : i32(value) { }
+        Primitive(c2_cntr32_t value) : c32(value) { }
+        Primitive(uint8_t value)     : u32(value) { }
+        Primitive(char value)        : i32(value) { }
+        Primitive(float value)       : fp(value)  { }
+
+        // allow construction from enum type
+        template<typename E, typename = typename std::enable_if<std::is_enum<E>::value>::type>
+        Primitive(E value)
+            : Primitive(static_cast<typename std::underlying_type<E>::type>(value)) { }
+
+        Primitive() : u64(0) { }
+
+        /** gets value out of the union */
+        template<typename T> const T &ref() const;
+
+        // verify that we can assume standard aliasing
+        static_assert(sizeof(u64) == sizeof(i64), "");
+        static_assert(sizeof(u64) == sizeof(c64), "");
+        static_assert(sizeof(u32) == sizeof(i32), "");
+        static_assert(sizeof(u32) == sizeof(c32), "");
+    };
+    // verify that we can assume standard aliasing
+    static_assert(offsetof(Primitive, u64) == offsetof(Primitive, i64), "");
+    static_assert(offsetof(Primitive, u64) == offsetof(Primitive, c64), "");
+    static_assert(offsetof(Primitive, u32) == offsetof(Primitive, i32), "");
+    static_assert(offsetof(Primitive, u32) == offsetof(Primitive, c32), "");
+
+    enum type_t : uint32_t {
+        NO_INIT,
+        INT32,
+        UINT32,
+        CNTR32,
+        INT64,
+        UINT64,
+        CNTR64,
+        FLOAT,
+    };
+
+    template<typename T, bool = std::is_enum<T>::value>
+    inline static constexpr type_t TypeFor() {
+        using U = typename std::underlying_type<T>::type;
+        return TypeFor<U>();
+    }
+
+    // deprectated
+    template<typename T, bool B = std::is_enum<T>::value>
+    inline static constexpr type_t typeFor() {
+        return TypeFor<T, B>();
+    }
+
+    // constructors - implicit
+    template<typename T>
+    C2Value(T value)  : _mType(typeFor<T>()), _mValue(value) { }
+
+    C2Value() : _mType(NO_INIT) { }
+
+    inline type_t type() const { return _mType; }
+
+    template<typename T>
+    inline bool get(T *value) const {
+        if (_mType == typeFor<T>()) {
+            *value = _mValue.ref<T>();
+            return true;
+        }
+        return false;
+    }
+
+    /// returns the address of the value
+    void *get() const {
+        return _mType == NO_INIT ? nullptr : (void*)&_mValue;
+    }
+
+    /// returns the size of the contained value
+    size_t inline sizeOf() const {
+        return SizeFor(_mType);
+    }
+
+    static size_t SizeFor(type_t type) {
+        switch (type) {
+            case INT32:
+            case UINT32:
+            case CNTR32: return sizeof(_mValue.i32);
+            case INT64:
+            case UINT64:
+            case CNTR64: return sizeof(_mValue.i64);
+            case FLOAT: return sizeof(_mValue.fp);
+            default: return 0;
+        }
+    }
+
+private:
+    type_t _mType;
+    Primitive _mValue;
+};
+
+template<> inline const int32_t &C2Value::Primitive::ref<int32_t>() const { return i32; }
+template<> inline const int64_t &C2Value::Primitive::ref<int64_t>() const { return i64; }
+template<> inline const uint32_t &C2Value::Primitive::ref<uint32_t>() const { return u32; }
+template<> inline const uint64_t &C2Value::Primitive::ref<uint64_t>() const { return u64; }
+template<> inline const c2_cntr32_t &C2Value::Primitive::ref<c2_cntr32_t>() const { return c32; }
+template<> inline const c2_cntr64_t &C2Value::Primitive::ref<c2_cntr64_t>() const { return c64; }
+template<> inline const float &C2Value::Primitive::ref<float>() const { return fp; }
+
+// provide types for enums and uint8_t, char even though we don't provide reading as them
+template<> constexpr C2Value::type_t C2Value::TypeFor<char, false>() { return INT32; }
+template<> constexpr C2Value::type_t C2Value::TypeFor<int32_t, false>() { return INT32; }
+template<> constexpr C2Value::type_t C2Value::TypeFor<int64_t, false>() { return INT64; }
+template<> constexpr C2Value::type_t C2Value::TypeFor<uint8_t, false>() { return UINT32; }
+template<> constexpr C2Value::type_t C2Value::TypeFor<uint32_t, false>() { return UINT32; }
+template<> constexpr C2Value::type_t C2Value::TypeFor<uint64_t, false>() { return UINT64; }
+template<> constexpr C2Value::type_t C2Value::TypeFor<c2_cntr32_t, false>() { return CNTR32; }
+template<> constexpr C2Value::type_t C2Value::TypeFor<c2_cntr64_t, false>() { return CNTR64; }
+template<> constexpr C2Value::type_t C2Value::TypeFor<float, false>() { return FLOAT; }
+
+// forward declare easy enum template
+template<typename E> struct C2EasyEnum;
+
+/**
+ * field descriptor. A field is uniquely defined by an index into a parameter.
+ * (Note: Stream-id is not captured as a field.)
+ *
+ * Ordering of fields is by offset. In case of structures, it is depth first,
+ * with a structure taking an index just before and in addition to its members.
+ */
+struct C2FieldDescriptor {
+//public:
+    /** field types and flags
+     * \note: only 32-bit and 64-bit fields are supported (e.g. no boolean, as that
+     * is represented using INT32).
+     */
+    enum type_t : uint32_t {
+        // primitive types
+        INT32   = C2Value::INT32,  ///< 32-bit signed integer
+        UINT32  = C2Value::UINT32, ///< 32-bit unsigned integer
+        CNTR32  = C2Value::CNTR32, ///< 32-bit counter
+        INT64   = C2Value::INT64,  ///< 64-bit signed integer
+        UINT64  = C2Value::UINT64, ///< 64-bit signed integer
+        CNTR64  = C2Value::CNTR64, ///< 64-bit counter
+        FLOAT   = C2Value::FLOAT,  ///< 32-bit floating point
+
+        // array types
+        STRING = 0x100, ///< fixed-size string (POD)
+        BLOB,           ///< blob. Blobs have no sub-elements and can be thought of as byte arrays;
+                        ///< however, bytes cannot be individually addressed by clients.
+
+        // complex types
+        STRUCT_FLAG = 0x20000, ///< structs. Marked with this flag in addition to their coreIndex.
+    };
+
+    typedef std::pair<C2String, C2Value::Primitive> NamedValueType;
+    typedef std::vector<NamedValueType> NamedValuesType;
+    //typedef std::pair<std::vector<C2String>, std::vector<C2Value::Primitive>> NamedValuesType;
+
+    /**
+     * Template specialization that returns the named values for a type.
+     *
+     * \todo hide from client.
+     *
+     * \return a vector of name-value pairs.
+     */
+    template<typename B>
+    static NamedValuesType namedValuesFor(const B &);
+
+    /** specialization for easy enums */
+    template<typename E>
+    inline static NamedValuesType namedValuesFor(const C2EasyEnum<E> &) {
+        return namedValuesFor(*(E*)nullptr);
+    }
+
+private:
+    template<typename B, bool enabled=std::is_arithmetic<B>::value || std::is_enum<B>::value>
+    struct C2_HIDE _NamedValuesGetter;
+
+public:
+    inline C2FieldDescriptor(uint32_t type, uint32_t extent, C2String name, size_t offset, size_t size)
+        : _mType((type_t)type), _mExtent(extent), _mName(name), _mFieldId(offset, size) { }
+
+    inline C2FieldDescriptor(const C2FieldDescriptor &) = default;
+
+    template<typename T, class B=typename std::remove_extent<T>::type>
+    inline C2FieldDescriptor(const T* offset, const char *name)
+        : _mType(this->GetType((B*)nullptr)),
+          _mExtent(std::is_array<T>::value ? std::extent<T>::value : 1),
+          _mName(name),
+          _mNamedValues(_NamedValuesGetter<B>::getNamedValues()),
+          _mFieldId(offset) {}
+
+/*
+    template<typename T, typename B=typename std::remove_extent<T>::type>
+    inline C2FieldDescriptor<T, B, false>(T* offset, const char *name)
+        : _mType(this->GetType((B*)nullptr)),
+          _mExtent(std::is_array<T>::value ? std::extent<T>::value : 1),
+          _mName(name),
+          _mFieldId(offset) {}
+*/
+
+    /// \deprecated
+    template<typename T, typename S, class B=typename std::remove_extent<T>::type>
+    inline C2FieldDescriptor(S*, T S::* field, const char *name)
+        : _mType(this->GetType((B*)nullptr)),
+          _mExtent(std::is_array<T>::value ? std::extent<T>::value : 1),
+          _mName(name),
+          _mFieldId(&(((S*)0)->*field)) {}
+
+    /// returns the type of this field
+    inline type_t type() const { return _mType; }
+    /// returns the length of the field in case it is an array. Returns 0 for
+    /// T[] arrays, returns 1 for T[1] arrays as well as if the field is not an array.
+    inline size_t extent() const { return _mExtent; }
+    /// returns the name of the field
+    inline C2String name() const { return _mName; }
+
+    const NamedValuesType &namedValues() const { return _mNamedValues; }
+
+#if defined(FRIEND_TEST)
+    friend void PrintTo(const C2FieldDescriptor &, ::std::ostream*);
+    friend bool operator==(const C2FieldDescriptor &, const C2FieldDescriptor &);
+    FRIEND_TEST(C2ParamTest_ParamFieldList, VerifyStruct);
+#endif
+
+private:
+    /**
+     * Construct an offseted field descriptor.
+     */
+    inline C2FieldDescriptor(const C2FieldDescriptor &desc, size_t offset)
+        : _mType(desc._mType), _mExtent(desc._mExtent),
+          _mName(desc._mName), _mNamedValues(desc._mNamedValues),
+          _mFieldId(desc._mFieldId._mOffset + offset, desc._mFieldId._mSize) { }
+
+    type_t _mType;
+    uint32_t _mExtent; // the last member can be arbitrary length if it is T[] array,
+                       // extending to the end of the parameter (this is marked with
+                       // 0). T[0]-s are not fields.
+    C2String _mName;
+    NamedValuesType _mNamedValues;
+
+    _C2FieldId _mFieldId;   // field identifier (offset and size)
+
+    // NOTE: We do not capture default value(s) here as that may depend on the component.
+    // NOTE: We also do not capture bestEffort, as 1) this should be true for most fields,
+    // 2) this is at parameter granularity.
+
+    // type resolution
+    inline static type_t GetType(int32_t*)     { return INT32; }
+    inline static type_t GetType(uint32_t*)    { return UINT32; }
+    inline static type_t GetType(c2_cntr32_t*) { return CNTR32; }
+    inline static type_t GetType(int64_t*)     { return INT64; }
+    inline static type_t GetType(uint64_t*)    { return UINT64; }
+    inline static type_t GetType(c2_cntr64_t*) { return CNTR64; }
+    inline static type_t GetType(float*)       { return FLOAT; }
+    inline static type_t GetType(char*)        { return STRING; }
+    inline static type_t GetType(uint8_t*)     { return BLOB; }
+
+    template<typename T,
+             class=typename std::enable_if<std::is_enum<T>::value>::type>
+    inline static type_t GetType(T*) {
+        typename std::underlying_type<T>::type underlying(0);
+        return GetType(&underlying);
+    }
+
+    // verify C2Struct by having a FieldList() and a CORE_INDEX.
+    template<typename T,
+             class=decltype(T::CORE_INDEX + 1), class=decltype(T::FieldList())>
+    inline static type_t GetType(T*) {
+        static_assert(!std::is_base_of<C2Param, T>::value, "cannot use C2Params as fields");
+        return (type_t)(T::CORE_INDEX | STRUCT_FLAG);
+    }
+
+    friend struct _C2ParamInspector;
+};
+
+// no named values for compound types
+template<typename B>
+struct C2FieldDescriptor::_NamedValuesGetter<B, false> {
+    inline static C2FieldDescriptor::NamedValuesType getNamedValues() {
+        return NamedValuesType();
+    }
+};
+
+template<typename B>
+struct C2FieldDescriptor::_NamedValuesGetter<B, true> {
+    inline static C2FieldDescriptor::NamedValuesType getNamedValues() {
+        return C2FieldDescriptor::namedValuesFor(*(B*)nullptr);
+    }
+};
+
+#define DEFINE_NO_NAMED_VALUES_FOR(type) \
+template<> inline C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const type &) { \
+    return NamedValuesType(); \
+}
+
+// We cannot subtype constructor for enumerated types so insted define no named values for
+// non-enumerated integral types.
+DEFINE_NO_NAMED_VALUES_FOR(int32_t)
+DEFINE_NO_NAMED_VALUES_FOR(uint32_t)
+DEFINE_NO_NAMED_VALUES_FOR(c2_cntr32_t)
+DEFINE_NO_NAMED_VALUES_FOR(int64_t)
+DEFINE_NO_NAMED_VALUES_FOR(uint64_t)
+DEFINE_NO_NAMED_VALUES_FOR(c2_cntr64_t)
+DEFINE_NO_NAMED_VALUES_FOR(uint8_t)
+DEFINE_NO_NAMED_VALUES_FOR(char)
+DEFINE_NO_NAMED_VALUES_FOR(float)
+
+/**
+ * Describes the fields of a structure.
+ */
+struct C2StructDescriptor {
+public:
+    /// Returns the core index of the struct
+    inline C2Param::CoreIndex coreIndex() const { return _mType.coreIndex(); }
+
+    // Returns the number of fields in this struct (not counting any recursive fields).
+    // Must be at least 1 for valid structs.
+    inline size_t numFields() const { return _mFields.size(); }
+
+    // Returns the list of direct fields (not counting any recursive fields).
+    typedef std::vector<C2FieldDescriptor>::const_iterator field_iterator;
+    inline field_iterator cbegin() const { return _mFields.cbegin(); }
+    inline field_iterator cend() const { return _mFields.cend(); }
+
+    // only supplying const iterator - but these names are needed for range based loops
+    inline field_iterator begin() const { return _mFields.cbegin(); }
+    inline field_iterator end() const { return _mFields.cend(); }
+
+    template<typename T>
+    inline C2StructDescriptor(T*)
+        : C2StructDescriptor(T::CORE_INDEX, T::FieldList()) { }
+
+    inline C2StructDescriptor(
+            C2Param::CoreIndex type,
+            const std::vector<C2FieldDescriptor> &fields)
+        : _mType(type), _mFields(fields) { }
+
+private:
+    friend struct _C2ParamInspector;
+
+    inline C2StructDescriptor(
+            C2Param::CoreIndex type,
+            std::vector<C2FieldDescriptor> &&fields)
+        : _mType(type), _mFields(std::move(fields)) { }
+
+    const C2Param::CoreIndex _mType;
+    const std::vector<C2FieldDescriptor> _mFields;
+};
+
+/**
+ * Describes parameters for a component.
+ */
+struct C2ParamDescriptor {
+public:
+    /**
+     * Returns whether setting this param is required to configure this component.
+     * This can only be true for builtin params for platform-defined components (e.g. video and
+     * audio encoders/decoders, video/audio filters).
+     * For vendor-defined components, it can be true even for vendor-defined params,
+     * but it is not recommended, in case the component becomes platform-defined.
+     */
+    inline bool isRequired() const { return _mAttrib & IS_REQUIRED; }
+
+    /**
+     * Returns whether this parameter is persistent. This is always true for C2Tuning and C2Setting,
+     * but may be false for C2Info. If true, this parameter persists across frames and applies to
+     * the current and subsequent frames. If false, this C2Info parameter only applies to the
+     * current frame and is not assumed to have the same value (or even be present) on subsequent
+     * frames, unless it is specified for those frames.
+     */
+    inline bool isPersistent() const { return _mAttrib & IS_PERSISTENT; }
+
+    inline bool isStrict() const { return _mAttrib & IS_STRICT; }
+
+    inline bool isReadOnly() const { return _mAttrib & IS_READ_ONLY; }
+
+    inline bool isVisible() const { return !(_mAttrib & IS_HIDDEN); }
+
+    inline bool isPublic() const { return !(_mAttrib & IS_INTERNAL); }
+
+    /// Returns the name of this param.
+    /// This defaults to the underlying C2Struct's name, but could be altered for a component.
+    inline C2String name() const { return _mName; }
+
+    /// Returns the parameter index
+    inline C2Param::Index index() const { return _mIndex; }
+
+    /// Returns the indices of parameters that this parameter has a dependency on
+    inline const std::vector<C2Param::Index> &dependencies() const { return _mDependencies; }
+
+    /// \deprecated
+    template<typename T>
+    inline C2ParamDescriptor(bool isRequired, C2StringLiteral name, const T*)
+        : _mIndex(T::PARAM_TYPE),
+          _mAttrib(IS_PERSISTENT | (isRequired ? IS_REQUIRED : 0)),
+          _mName(name) { }
+
+    /// \deprecated
+    inline C2ParamDescriptor(
+            bool isRequired, C2StringLiteral name, C2Param::Index index)
+        : _mIndex(index),
+          _mAttrib(IS_PERSISTENT | (isRequired ? IS_REQUIRED : 0)),
+          _mName(name) { }
+
+    enum attrib_t : uint32_t {
+        // flags that default on
+        IS_REQUIRED   = 1u << 0, ///< parameter is required to be specified
+        IS_PERSISTENT = 1u << 1, ///< parameter retains its value
+        // flags that default off
+        IS_STRICT     = 1u << 2, ///< parameter is strict
+        IS_READ_ONLY  = 1u << 3, ///< parameter is publicly read-only
+        IS_HIDDEN     = 1u << 4, ///< parameter shall not be visible to clients
+        IS_INTERNAL   = 1u << 5, ///< parameter shall not be used by framework (other than testing)
+        IS_CONST      = 1u << 6 | IS_READ_ONLY, ///< parameter is publicly const (hence read-only)
+    };
+
+    inline C2ParamDescriptor(
+        C2Param::Index index, attrib_t attrib, C2StringLiteral name)
+        : _mIndex(index),
+          _mAttrib(attrib),
+          _mName(name) { }
+
+    inline C2ParamDescriptor(
+        C2Param::Index index, attrib_t attrib, C2String &&name,
+        std::vector<C2Param::Index> &&dependencies)
+        : _mIndex(index),
+          _mAttrib(attrib),
+          _mName(name),
+          _mDependencies(std::move(dependencies)) { }
+
+private:
+    const C2Param::Index _mIndex;
+    const uint32_t _mAttrib;
+    const C2String _mName;
+    std::vector<C2Param::Index> _mDependencies;
+
+    friend struct _C2ParamInspector;
+};
+
+DEFINE_ENUM_OPERATORS(::C2ParamDescriptor::attrib_t)
+
+
+/// \ingroup internal
+/// Define a structure without CORE_INDEX.
+/// \note _FIELD_LIST is used only during declaration so that C2Struct declarations can end with
+/// a simple list of C2FIELD-s and closing bracket. Mark it unused as it is not used in templated
+/// structs.
+#define DEFINE_BASE_C2STRUCT(name) \
+private: \
+    const static std::vector<C2FieldDescriptor> _FIELD_LIST __unused; /**< structure fields */ \
+public: \
+    typedef C2##name##Struct _type; /**< type name shorthand */ \
+    static const std::vector<C2FieldDescriptor> FieldList(); /**< structure fields factory */
+
+/// Define a structure with matching CORE_INDEX.
+#define DEFINE_C2STRUCT(name) \
+public: \
+    enum : uint32_t { CORE_INDEX = kParamIndex##name }; \
+    DEFINE_BASE_C2STRUCT(name)
+
+/// Define a flexible structure without CORE_INDEX.
+#define DEFINE_BASE_FLEX_C2STRUCT(name, flexMember) \
+public: \
+    FLEX(C2##name##Struct, flexMember) \
+    DEFINE_BASE_C2STRUCT(name)
+
+/// Define a flexible structure with matching CORE_INDEX.
+#define DEFINE_FLEX_C2STRUCT(name, flexMember) \
+public: \
+    FLEX(C2##name##Struct, flexMember) \
+    enum : uint32_t { CORE_INDEX = kParamIndex##name | C2Param::CoreIndex::IS_FLEX_FLAG }; \
+    DEFINE_BASE_C2STRUCT(name)
+
+/// \ingroup internal
+/// Describe a structure of a templated structure.
+// Use list... as the argument gets resubsitituted and it contains commas. Alternative would be
+// to wrap list in an expression, e.g. ({ std::vector<C2FieldDescriptor> list; })) which converts
+// it from an initializer list to a vector.
+#define DESCRIBE_TEMPLATED_C2STRUCT(strukt, list...) \
+    _DESCRIBE_TEMPLATABLE_C2STRUCT(template<>, strukt, __C2_GENERATE_GLOBAL_VARS__, list)
+
+/// \deprecated
+/// Describe the fields of a structure using an initializer list.
+#define DESCRIBE_C2STRUCT(name, list...) \
+    _DESCRIBE_TEMPLATABLE_C2STRUCT(, C2##name##Struct, __C2_GENERATE_GLOBAL_VARS__, list)
+
+/// \ingroup internal
+/// Macro layer to get value of enabled that is passed in as a macro variable
+#define _DESCRIBE_TEMPLATABLE_C2STRUCT(template, strukt, enabled, list...) \
+    __DESCRIBE_TEMPLATABLE_C2STRUCT(template, strukt, enabled, list)
+
+/// \ingroup internal
+/// Macro layer to resolve to the specific macro based on macro variable
+#define __DESCRIBE_TEMPLATABLE_C2STRUCT(template, strukt, enabled, list...) \
+    ___DESCRIBE_TEMPLATABLE_C2STRUCT##enabled(template, strukt, list)
+
+#define ___DESCRIBE_TEMPLATABLE_C2STRUCT(template, strukt, list...) \
+    template \
+    const std::vector<C2FieldDescriptor> strukt::FieldList() { return list; }
+
+#define ___DESCRIBE_TEMPLATABLE_C2STRUCT__C2_GENERATE_GLOBAL_VARS__(template, strukt, list...)
+
+/**
+ * Describe a field of a structure.
+ * These must be in order.
+ *
+ * There are two ways to use this macro:
+ *
+ *  ~~~~~~~~~~~~~ (.cpp)
+ *  struct C2VideoWidthStruct {
+ *      int32_t width;
+ *      C2VideoWidthStruct() {} // optional default constructor
+ *      C2VideoWidthStruct(int32_t _width) : width(_width) {}
+ *
+ *      DEFINE_AND_DESCRIBE_C2STRUCT(VideoWidth)
+ *      C2FIELD(width, "width")
+ *  };
+ *  ~~~~~~~~~~~~~
+ *
+ *  ~~~~~~~~~~~~~ (.cpp)
+ *  struct C2VideoWidthStruct {
+ *      int32_t width;
+ *      C2VideoWidthStruct() = default; // optional default constructor
+ *      C2VideoWidthStruct(int32_t _width) : width(_width) {}
+ *
+ *      DEFINE_C2STRUCT(VideoWidth)
+ *  } C2_PACK;
+ *
+ *  DESCRIBE_C2STRUCT(VideoWidth, {
+ *      C2FIELD(width, "width")
+ *  })
+ *  ~~~~~~~~~~~~~
+ *
+ *  For flexible structures (those ending in T[]), use the flexible macros:
+ *
+ *  ~~~~~~~~~~~~~ (.cpp)
+ *  struct C2VideoFlexWidthsStruct {
+ *      int32_t widths[];
+ *      C2VideoFlexWidthsStruct(); // must have a default constructor
+ *
+ *  private:
+ *      // may have private constructors taking number of widths as the first argument
+ *      // This is used by the C2Param factory methods, e.g.
+ *      //   C2VideoFlexWidthsGlobalParam::AllocUnique(size_t, int32_t);
+ *      C2VideoFlexWidthsStruct(size_t flexCount, int32_t value) {
+ *          for (size_t i = 0; i < flexCount; ++i) {
+ *              widths[i] = value;
+ *          }
+ *      }
+ *
+ *      // If the last argument is T[N] or std::initializer_list<T>, the flexCount will
+ *      // be automatically calculated and passed by the C2Param factory methods, e.g.
+ *      //   int widths[] = { 1, 2, 3 };
+ *      //   C2VideoFlexWidthsGlobalParam::AllocUnique(widths);
+ *      template<unsigned N>
+ *      C2VideoFlexWidthsStruct(size_t flexCount, const int32_t(&init)[N]) {
+ *          for (size_t i = 0; i < flexCount; ++i) {
+ *              widths[i] = init[i];
+ *          }
+ *      }
+ *
+ *      DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(VideoFlexWidths, widths)
+ *      C2FIELD(widths, "widths")
+ *  };
+ *  ~~~~~~~~~~~~~
+ *
+ *  ~~~~~~~~~~~~~ (.cpp)
+ *  struct C2VideoFlexWidthsStruct {
+ *      int32_t mWidths[];
+ *      C2VideoFlexWidthsStruct(); // must have a default constructor
+ *
+ *      DEFINE_FLEX_C2STRUCT(VideoFlexWidths, mWidths)
+ *  } C2_PACK;
+ *
+ *  DESCRIBE_C2STRUCT(VideoFlexWidths, {
+ *      C2FIELD(mWidths, "widths")
+ *  })
+ *  ~~~~~~~~~~~~~
+ *
+ */
+#define DESCRIBE_C2FIELD(member, name) \
+  C2FieldDescriptor(&((_type*)(nullptr))->member, name),
+
+#define C2FIELD(member, name) _C2FIELD(member, name, __C2_GENERATE_GLOBAL_VARS__)
+/// \if 0
+#define _C2FIELD(member, name, enabled) __C2FIELD(member, name, enabled)
+#define __C2FIELD(member, name, enabled) DESCRIBE_C2FIELD##enabled(member, name)
+#define DESCRIBE_C2FIELD__C2_GENERATE_GLOBAL_VARS__(member, name)
+/// \endif
+
+/// Define a structure with matching CORE_INDEX and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_C2STRUCT(name) \
+    _DEFINE_AND_DESCRIBE_C2STRUCT(name, DEFINE_C2STRUCT, __C2_GENERATE_GLOBAL_VARS__)
+
+/// Define a base structure (with no CORE_INDEX) and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_BASE_C2STRUCT(name) \
+    _DEFINE_AND_DESCRIBE_C2STRUCT(name, DEFINE_BASE_C2STRUCT, __C2_GENERATE_GLOBAL_VARS__)
+
+/// Define a flexible structure with matching CORE_INDEX and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember) \
+    _DEFINE_AND_DESCRIBE_FLEX_C2STRUCT( \
+            name, flexMember, DEFINE_FLEX_C2STRUCT, __C2_GENERATE_GLOBAL_VARS__)
+
+/// Define a flexible base structure (with no CORE_INDEX) and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_BASE_FLEX_C2STRUCT(name, flexMember) \
+    _DEFINE_AND_DESCRIBE_FLEX_C2STRUCT( \
+            name, flexMember, DEFINE_BASE_FLEX_C2STRUCT, __C2_GENERATE_GLOBAL_VARS__)
+
+/// \if 0
+/*
+   Alternate declaration of field definitions in case no field list is to be generated.
+   The specific macro is chosed based on the value of __C2_GENERATE_GLOBAL_VARS__ (whether it is
+   defined (to be empty) or not. This requires two level of macro substitution.
+   TRICKY: use namespace declaration to handle closing bracket that is normally after
+   these macros.
+*/
+
+#define _DEFINE_AND_DESCRIBE_C2STRUCT(name, defineMacro, enabled) \
+    __DEFINE_AND_DESCRIBE_C2STRUCT(name, defineMacro, enabled)
+#define __DEFINE_AND_DESCRIBE_C2STRUCT(name, defineMacro, enabled) \
+    ___DEFINE_AND_DESCRIBE_C2STRUCT##enabled(name, defineMacro)
+#define ___DEFINE_AND_DESCRIBE_C2STRUCT__C2_GENERATE_GLOBAL_VARS__(name, defineMacro) \
+    defineMacro(name) } C2_PACK; namespace {
+#define ___DEFINE_AND_DESCRIBE_C2STRUCT(name, defineMacro) \
+    defineMacro(name) } C2_PACK; \
+    const std::vector<C2FieldDescriptor> C2##name##Struct::FieldList() { return _FIELD_LIST; } \
+    const std::vector<C2FieldDescriptor> C2##name##Struct::_FIELD_LIST = {
+
+#define _DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember, defineMacro, enabled) \
+    __DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember, defineMacro, enabled)
+#define __DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember, defineMacro, enabled) \
+    ___DEFINE_AND_DESCRIBE_FLEX_C2STRUCT##enabled(name, flexMember, defineMacro)
+#define ___DEFINE_AND_DESCRIBE_FLEX_C2STRUCT__C2_GENERATE_GLOBAL_VARS__(name, flexMember, defineMacro) \
+    defineMacro(name, flexMember) } C2_PACK; namespace {
+#define ___DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember, defineMacro) \
+    defineMacro(name, flexMember) } C2_PACK; \
+    const std::vector<C2FieldDescriptor> C2##name##Struct::FieldList() { return _FIELD_LIST; } \
+    const std::vector<C2FieldDescriptor> C2##name##Struct::_FIELD_LIST = {
+/// \endif
+
+
+/**
+ * Parameter reflector class.
+ *
+ * This class centralizes the description of parameter structures. This can be shared
+ * by multiple components as describing a parameter does not imply support of that
+ * parameter. However, each supported parameter and any dependent structures within
+ * must be described by the parameter reflector provided by a component.
+ */
+class C2ParamReflector {
+public:
+    /**
+     *  Describes a parameter structure.
+     *
+     *  \param[in] coreIndex the core index of the parameter structure containing at least the
+     *  core index
+     *
+     *  \return the description of the parameter structure
+     *  \retval nullptr if the parameter is not supported by this reflector
+     *
+     *  This methods shall not block and return immediately.
+     *
+     *  \note this class does not take a set of indices because we would then prefer
+     *  to also return any dependent structures, and we don't want this logic to be
+     *  repeated in each reflector. Alternately, this could just return a map of all
+     *  descriptions, but we want to conserve memory if client only wants the description
+     *  of a few indices.
+     */
+    virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const = 0;
+
+protected:
+    virtual ~C2ParamReflector() = default;
+};
+
+/**
+ * Generic supported values for a field.
+ *
+ * This can be either a range or a set of values. The range can be a simple range, an arithmetic,
+ * geometric or multiply-accumulate series with a clear minimum and maximum value. Values can
+ * be discrete values, or can optionally represent flags to be or-ed.
+ *
+ * \note Do not use flags to represent bitfields. Use individual values or separate fields instead.
+ */
+struct C2FieldSupportedValues {
+//public:
+    enum type_t {
+        EMPTY,      ///< no supported values
+        RANGE,      ///< a numeric range that can be continuous or discrete
+        VALUES,     ///< a list of values
+        FLAGS       ///< a list of flags that can be OR-ed
+    };
+
+    type_t type; /** Type of values for this field. */
+
+    typedef C2Value::Primitive Primitive;
+
+    /**
+     * Range specifier for supported value. Used if type is RANGE.
+     *
+     * If step is 0 and num and denom are both 1, the supported values are any value, for which
+     * min <= value <= max.
+     *
+     * Otherwise, the range represents a geometric/arithmetic/multiply-accumulate series, where
+     * successive supported values can be derived from previous values (starting at min), using the
+     * following formula:
+     *  v[0] = min
+     *  v[i] = v[i-1] * num / denom + step for i >= 1, while min < v[i] <= max.
+     */
+    struct {
+        /** Lower end of the range (inclusive). */
+        Primitive min;
+        /** Upper end of the range (inclusive if permitted by series). */
+        Primitive max;
+        /** Step between supported values. */
+        Primitive step;
+        /** Numerator of a geometric series. */
+        Primitive num;
+        /** Denominator of a geometric series. */
+        Primitive denom;
+    } range;
+
+    /**
+     * List of values. Used if type is VALUES or FLAGS.
+     *
+     * If type is VALUES, this is the list of supported values in decreasing preference.
+     *
+     * If type is FLAGS, this vector contains { min-mask, flag1, flag2... }. Basically, the first
+     * value is the required set of flags to be set, and the rest of the values are flags that can
+     * be set independently. FLAGS is only supported for integral types. Supported flags should
+     * not overlap, as it can make validation non-deterministic. The standard validation method
+     * is that starting from the original value, if each flag is removed when fully present (the
+     * min-mask must be fully present), we shall arrive at 0.
+     */
+    std::vector<Primitive> values;
+
+    C2FieldSupportedValues()
+        : type(EMPTY) {
+    }
+
+    template<typename T>
+    C2FieldSupportedValues(T min, T max, T step = T(std::is_floating_point<T>::value ? 0 : 1))
+        : type(RANGE),
+          range{min, max, step, (T)1, (T)1} { }
+
+    template<typename T>
+    C2FieldSupportedValues(T min, T max, T num, T den) :
+        type(RANGE),
+        range{min, max, (T)0, num, den} { }
+
+    template<typename T>
+    C2FieldSupportedValues(T min, T max, T step, T num, T den)
+        : type(RANGE),
+          range{min, max, step, num, den} { }
+
+    /// \deprecated
+    template<typename T>
+    C2FieldSupportedValues(bool flags, std::initializer_list<T> list)
+        : type(flags ? FLAGS : VALUES),
+          range{(T)0, (T)0, (T)0, (T)0, (T)0} {
+        for (T value : list) {
+            values.emplace_back(value);
+        }
+    }
+
+    /// \deprecated
+    template<typename T>
+    C2FieldSupportedValues(bool flags, const std::vector<T>& list)
+        : type(flags ? FLAGS : VALUES),
+          range{(T)0, (T)0, (T)0, (T)0, (T)0} {
+        for(T value : list) {
+            values.emplace_back(value);
+        }
+    }
+
+    /// \internal
+    /// \todo: create separate values vs. flags initializer as for flags we want
+    /// to list both allowed and required flags
+    template<typename T, typename E=decltype(C2FieldDescriptor::namedValuesFor(*(T*)0))>
+    C2FieldSupportedValues(bool flags, const T*)
+        : type(flags ? FLAGS : VALUES),
+          range{(T)0, (T)0, (T)0, (T)0, (T)0} {
+              C2FieldDescriptor::NamedValuesType named = C2FieldDescriptor::namedValuesFor(*(T*)0);
+        if (flags) {
+            values.emplace_back(0); // min-mask defaults to 0
+        }
+        for (const C2FieldDescriptor::NamedValueType &item : named){
+            values.emplace_back(item.second);
+        }
+    }
+};
+
+/**
+ * Supported values for a specific field.
+ *
+ * This is a pair of the field specifier together with an optional supported values object.
+ * This structure is used when reporting parameter configuration failures and conflicts.
+ */
+struct C2ParamFieldValues {
+    C2ParamField paramOrField; ///< the field or parameter
+    /// optional supported values for the field if paramOrField specifies an actual field that is
+    /// numeric (non struct, blob or string). Supported values for arrays (including string and
+    /// blobs) describe the supported values for each element (character for string, and bytes for
+    /// blobs). It is optional for read-only strings and blobs.
+    std::unique_ptr<C2FieldSupportedValues> values;
+
+    // This struct is meant to be move constructed.
+    C2_DEFAULT_MOVE(C2ParamFieldValues);
+
+    // Copy constructor/assignment is also provided as this object may get copied.
+    C2ParamFieldValues(const C2ParamFieldValues &other)
+        : paramOrField(other.paramOrField),
+          values(other.values ? std::make_unique<C2FieldSupportedValues>(*other.values) : nullptr) { }
+
+    C2ParamFieldValues& operator=(const C2ParamFieldValues &other) {
+        paramOrField = other.paramOrField;
+        values = other.values ? std::make_unique<C2FieldSupportedValues>(*other.values) : nullptr;
+        return *this;
+    }
+
+
+    /**
+     * Construct with no values.
+     */
+    C2ParamFieldValues(const C2ParamField &paramOrField_)
+        : paramOrField(paramOrField_) { }
+
+    /**
+     * Construct with values.
+     */
+    C2ParamFieldValues(const C2ParamField &paramOrField_, const C2FieldSupportedValues &values_)
+        : paramOrField(paramOrField_),
+          values(std::make_unique<C2FieldSupportedValues>(values_)) { }
+
+    /**
+     * Construct from fields.
+     */
+    C2ParamFieldValues(const C2ParamField &paramOrField_, std::unique_ptr<C2FieldSupportedValues> &&values_)
+        : paramOrField(paramOrField_),
+          values(std::move(values_)) { }
+};
+
+/// @}
+
+// include debug header for C2Params.h if C2Debug.h was already included
+#ifdef C2UTILS_DEBUG_H_
+#include <util/C2Debug-param.h>
+#endif
+
+#endif  // C2PARAM_H_
diff --git a/media/codec2/include/C2ParamDef.h b/media/codec2/include/C2ParamDef.h
new file mode 100644
index 0000000..0a33283
--- /dev/null
+++ b/media/codec2/include/C2ParamDef.h
@@ -0,0 +1,931 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * Templates used to declare parameters.
+ */
+#ifndef C2PARAM_DEF_H_
+#define C2PARAM_DEF_H_
+
+#include <type_traits>
+
+#include <C2Param.h>
+
+/// \addtogroup Parameters
+/// @{
+
+/* ======================== UTILITY TEMPLATES FOR PARAMETER DEFINITIONS ======================== */
+
+/// \addtogroup internal
+/// @{
+
+/// Helper class that checks if a type has equality and inequality operators.
+struct C2_HIDE _C2Comparable_impl
+{
+    template<typename S, typename=decltype(S() == S())>
+    static std::true_type TestEqual(int);
+    template<typename>
+    static std::false_type TestEqual(...);
+
+    template<typename S, typename=decltype(S() != S())>
+    static std::true_type TestNotEqual(int);
+    template<typename>
+    static std::false_type TestNotEqual(...);
+};
+
+/**
+ * Helper template that returns if a type has equality and inequality operators.
+ *
+ * Use as _C2Comparable<typename S>::value.
+ */
+template<typename S>
+struct C2_HIDE _C2Comparable
+    : public std::integral_constant<bool, decltype(_C2Comparable_impl::TestEqual<S>(0))::value
+                        || decltype(_C2Comparable_impl::TestNotEqual<S>(0))::value> {
+};
+
+///  Helper class that checks if a type has a CORE_INDEX constant.
+struct C2_HIDE _C2CoreIndexHelper_impl
+{
+    template<typename S, int=S::CORE_INDEX>
+    static std::true_type TestCoreIndex(int);
+    template<typename>
+    static std::false_type TestCoreIndex(...);
+};
+
+/// Macro that defines and thus overrides a type's CORE_INDEX for a setting
+#define _C2_CORE_INDEX_OVERRIDE(coreIndex) \
+public: \
+    enum : uint32_t { CORE_INDEX = coreIndex };
+
+
+/// Helper template that adds a CORE_INDEX to a type if it does not have one (for testing)
+template<typename S, int CoreIndex>
+struct C2_HIDE _C2AddCoreIndex : public S {
+    _C2_CORE_INDEX_OVERRIDE(CoreIndex)
+};
+
+/**
+ * \brief Helper class to check struct requirements for parameters.
+ *
+ * Features:
+ *  - verify default constructor, no virtual methods, and no equality operators.
+ *  - expose PARAM_TYPE, and non-flex FLEX_SIZE.
+ */
+template<typename S, int CoreIndex, unsigned TypeFlags>
+struct C2_HIDE _C2StructCheck {
+    static_assert(
+            std::is_default_constructible<S>::value, "C2 structure must have default constructor");
+    static_assert(!std::is_polymorphic<S>::value, "C2 structure must not have virtual methods");
+    static_assert(!_C2Comparable<S>::value, "C2 structure must not have operator== or !=");
+
+public:
+    enum : uint32_t {
+        PARAM_TYPE = CoreIndex | TypeFlags
+    };
+
+protected:
+    enum : uint32_t {
+        FLEX_SIZE = 0,
+    };
+};
+
+/// Helper class that checks if a type has an integer FLEX_SIZE member.
+struct C2_HIDE _C2Flexible_impl {
+    /// specialization for types that have a FLEX_SIZE member
+    template<typename S, unsigned=S::FLEX_SIZE>
+    static std::true_type TestFlexSize(int);
+    template<typename>
+    static std::false_type TestFlexSize(...);
+};
+
+/// Helper template that returns if a type has an integer FLEX_SIZE member.
+template<typename S>
+struct C2_HIDE _C2Flexible
+    : public std::integral_constant<bool, decltype(_C2Flexible_impl::TestFlexSize<S>(0))::value> {
+};
+
+/// Macro to test if a type is flexible (has a FLEX_SIZE member).
+#define IF_FLEXIBLE(S) ENABLE_IF(_C2Flexible<S>::value)
+/// Shorthand for std::enable_if
+#define ENABLE_IF(cond) typename std::enable_if<cond>::type
+
+template<typename T, typename V=void>
+struct C2_HIDE _c2_enable_if_type {
+    typedef V type;
+};
+
+/// Helper template that exposes the flexible subtype of a struct.
+template<typename S, typename E=void>
+struct C2_HIDE _C2FlexHelper {
+    typedef void FlexType;
+    enum : uint32_t { FLEX_SIZE = 0 };
+};
+
+/// Specialization for flexible types. This only works if _FlexMemberType is public.
+template<typename S>
+struct C2_HIDE _C2FlexHelper<S,
+        typename _c2_enable_if_type<typename S::_FlexMemberType>::type> {
+    typedef typename _C2FlexHelper<typename S::_FlexMemberType>::FlexType FlexType;
+    enum : uint32_t { FLEX_SIZE = _C2FlexHelper<typename S::_FlexMemberType>::FLEX_SIZE };
+};
+
+/// Specialization for flex arrays.
+template<typename S>
+struct C2_HIDE _C2FlexHelper<S[],
+        typename std::enable_if<std::is_void<typename _C2FlexHelper<S>::FlexType>::value>::type> {
+    typedef S FlexType;
+    enum : uint32_t { FLEX_SIZE = sizeof(S) };
+};
+
+/**
+ * \brief Helper class to check flexible struct requirements and add common operations.
+ *
+ * Features:
+ *  - expose CORE_INDEX and FieldList (this is normally inherited from the struct, but flexible
+ *    structs cannot be base classes and thus inherited from)
+ *  - disable copy assignment and construction (TODO: this is already done in the FLEX macro for the
+ *    flexible struct, so may not be needed here)
+ */
+template<typename S, int ParamIndex, unsigned TypeFlags>
+struct C2_HIDE _C2FlexStructCheck :
+// add flexible flag as _C2StructCheck defines PARAM_TYPE
+        public _C2StructCheck<S, ParamIndex | C2Param::CoreIndex::IS_FLEX_FLAG, TypeFlags> {
+public:
+    enum : uint32_t {
+        /// \hideinitializer
+        CORE_INDEX = ParamIndex | C2Param::CoreIndex::IS_FLEX_FLAG, ///< flexible struct core-index
+    };
+
+    inline static const std::vector<C2FieldDescriptor> FieldList() { return S::FieldList(); }
+
+    // default constructor needed because of the disabled copy constructor
+    inline _C2FlexStructCheck() = default;
+
+protected:
+    // cannot copy flexible params
+    _C2FlexStructCheck(const _C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
+    _C2FlexStructCheck& operator= (const _C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
+
+    // constants used for helper methods
+    enum : uint32_t {
+        /// \hideinitializer
+        FLEX_SIZE = _C2FlexHelper<S>::FLEX_SIZE, ///< size of flexible type
+        /// \hideinitializer
+        MAX_SIZE = (uint32_t)std::min((size_t)UINT32_MAX, SIZE_MAX), // TODO: is this always u32 max?
+        /// \hideinitializer
+        BASE_SIZE = sizeof(S) + sizeof(C2Param), ///< size of the base param
+    };
+
+    /// returns the allocated size of this param with flexCount, or 0 if it would overflow.
+    inline static size_t CalcSize(size_t flexCount, size_t size = BASE_SIZE) {
+        if (flexCount <= (MAX_SIZE - size) / S::FLEX_SIZE) {
+            return size + S::FLEX_SIZE * flexCount;
+        }
+        return 0;
+    }
+
+    /// dynamic new operator usable for params of type S
+    inline void* operator new(size_t size, size_t flexCount) noexcept {
+        // TODO: assert(size == BASE_SIZE);
+        size = CalcSize(flexCount, size);
+        if (size > 0) {
+            return ::operator new(size);
+        }
+        return nullptr;
+    }
+};
+
+/// Define From() cast operators for params.
+#define DEFINE_CAST_OPERATORS(_Type) \
+    inline static _Type* From(C2Param *other) { \
+        return (_Type*)C2Param::IfSuitable( \
+                other, sizeof(_Type), _Type::PARAM_TYPE, _Type::FLEX_SIZE, \
+                (_Type::PARAM_TYPE & T::Index::DIR_UNDEFINED) != T::Index::DIR_UNDEFINED); \
+    } \
+    inline static const _Type* From(const C2Param *other) { \
+        return const_cast<const _Type*>(From(const_cast<C2Param *>(other))); \
+    } \
+    inline static _Type* From(std::nullptr_t) { return nullptr; } \
+
+/**
+ * Define flexible allocators (AllocShared or AllocUnique) for flexible params.
+ *  - P::AllocXyz(flexCount, args...): allocate for given flex-count. This maps to
+ *          T(flexCount, args...)\
+ *
+ * Clang does not support args... followed by templated param as args... eats it. Hence,
+ * provide specializations where the initializer replaces the flexCount.
+ *
+ * Specializations that deduce flexCount:
+ *  - P::AllocXyz(T[], args...): allocate for size of (and with) init array.
+ *  - P::AllocXyz(std::initializer_list<T>, args...): allocate for size of (and with) initializer
+ *            list.
+ *  - P::AllocXyz(std::vector<T>, args...): allocate for size of (and with) init vector.
+ *  These specializations map to T(flexCount = size-of-init, args..., init)
+ */
+#define DEFINE_FLEXIBLE_ALLOC(_Type, S, ptr, Ptr) \
+    template<typename ...Args> \
+    inline static std::ptr##_ptr<_Type> Alloc##Ptr(size_t flexCount, const Args(&... args)) { \
+        return std::ptr##_ptr<_Type>(new(flexCount) _Type(flexCount, args...)); \
+    } \
+    template<typename ...Args, typename U=typename S::FlexType> \
+    inline static std::ptr##_ptr<_Type> Alloc##Ptr( \
+            const std::initializer_list<U> &init, const Args(&... args)) { \
+        return std::ptr##_ptr<_Type>(new(init.size()) _Type(init.size(), args..., init)); \
+    } \
+    template<typename ...Args, typename U=typename S::FlexType> \
+    inline static std::ptr##_ptr<_Type> Alloc##Ptr( \
+            const std::vector<U> &init, const Args(&... args)) { \
+        return std::ptr##_ptr<_Type>(new(init.size()) _Type(init.size(), args..., init)); \
+    } \
+    template<typename ...Args, typename U=typename S::FlexType, unsigned N> \
+    inline static std::ptr##_ptr<_Type> Alloc##Ptr(const U(&init)[N], const Args(&... args)) { \
+        return std::ptr##_ptr<_Type>(new(N) _Type(N, args..., init)); \
+    } \
+
+/**
+ * Define flexible methods AllocShared, AllocUnique and flexCount.
+ */
+#define DEFINE_FLEXIBLE_METHODS(_Type, S) \
+    DEFINE_FLEXIBLE_ALLOC(_Type, S, shared, Shared) \
+    DEFINE_FLEXIBLE_ALLOC(_Type, S, unique, Unique) \
+    inline size_t flexCount() const { \
+        static_assert(sizeof(_Type) == _Type::BASE_SIZE, "incorrect BASE_SIZE"); \
+        size_t sz = this->size(); \
+        if (sz >= sizeof(_Type)) { \
+            return (sz - sizeof(_Type)) / _Type::FLEX_SIZE; \
+        } \
+        return 0; \
+    } \
+
+/// Mark flexible member variable and make structure flexible.
+#define FLEX(cls, m) \
+    C2_DO_NOT_COPY(cls) \
+private: \
+    C2PARAM_MAKE_FRIENDS \
+    /** \if 0 */ \
+    template<typename, typename> friend struct _C2FlexHelper; \
+public: \
+    typedef decltype(m) _FlexMemberType; \
+    /* default constructor with flexCount */ \
+    inline cls(size_t) : cls() {} \
+    /* constexpr static _FlexMemberType cls::* flexMember = &cls::m; */ \
+    typedef typename _C2FlexHelper<_FlexMemberType>::FlexType FlexType; \
+    static_assert(\
+            !std::is_void<FlexType>::value, \
+            "member is not flexible, or a flexible array of a flexible type"); \
+    enum : uint32_t { FLEX_SIZE = _C2FlexHelper<_FlexMemberType>::FLEX_SIZE }; \
+    /** \endif */ \
+
+/// @}
+
+/**
+ * Global-parameter template.
+ *
+ * Base template to define a global setting/tuning or info based on a structure and
+ * an optional ParamIndex. Global parameters are not tied to a port (input or output).
+ *
+ * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
+ * structure can be accessed directly, and constructors and potential public methods are also
+ * wrapped.
+ *
+ * \tparam T param type C2Setting, C2Tuning or C2Info
+ * \tparam S wrapped structure
+ * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
+ * structures.
+ */
+template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
+struct C2_HIDE C2GlobalParam : public T, public S,
+        public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
+    _C2_CORE_INDEX_OVERRIDE(ParamIndex)
+private:
+    typedef C2GlobalParam<T, S, ParamIndex> _Type;
+
+public:
+    /// Wrapper around base structure's constructor.
+    template<typename ...Args>
+    inline C2GlobalParam(const Args(&... args)) : T(sizeof(_Type), _Type::PARAM_TYPE), S(args...) { }
+
+    DEFINE_CAST_OPERATORS(_Type)
+};
+
+/**
+ * Global-parameter template for flexible structures.
+ *
+ * Base template to define a global setting/tuning or info based on a flexible structure and
+ * an optional ParamIndex. Global parameters are not tied to a port (input or output).
+ *
+ * \tparam T param type C2Setting, C2Tuning or C2Info
+ * \tparam S wrapped flexible structure
+ * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
+ *         structures.
+ *
+ * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
+ * structures can be accessed via the m member variable; however, the constructors of the structure
+ * are wrapped directly. (This is because flexible types cannot be subclassed.)
+ */
+template<typename T, typename S, int ParamIndex>
+struct C2_HIDE C2GlobalParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
+    : public T, public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
+private:
+    typedef C2GlobalParam<T, S, ParamIndex> _Type;
+
+    /// Wrapper around base structure's constructor.
+    template<typename ...Args>
+    inline C2GlobalParam(size_t flexCount, const Args(&... args))
+        : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE), m(flexCount, args...) { }
+
+public:
+    S m; ///< wrapped flexible structure
+
+    DEFINE_FLEXIBLE_METHODS(_Type, S)
+    DEFINE_CAST_OPERATORS(_Type)
+};
+
+/**
+ * Port-parameter template.
+ *
+ * Base template to define a port setting/tuning or info based on a structure and
+ * an optional ParamIndex. Port parameters are tied to a port (input or output), but not to a
+ * specific stream.
+ *
+ * \tparam T param type C2Setting, C2Tuning or C2Info
+ * \tparam S wrapped structure
+ * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
+ *         structures.
+ *
+ * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
+ * structure can be accessed directly, and constructors and potential public methods are also
+ * wrapped.
+ *
+ * There are 3 flavors of port parameters: unspecified, input and output. Parameters with
+ * unspecified port expose a setPort method, and add an initial port parameter to the constructor.
+ */
+template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
+struct C2_HIDE C2PortParam : public T, public S,
+        private _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_UNDEFINED> {
+    _C2_CORE_INDEX_OVERRIDE(ParamIndex)
+private:
+    typedef C2PortParam<T, S, ParamIndex> _Type;
+
+public:
+    /// Default constructor.
+    inline C2PortParam() : T(sizeof(_Type), _Type::PARAM_TYPE) { }
+    template<typename ...Args>
+    /// Wrapper around base structure's constructor while specifying port/direction.
+    inline C2PortParam(bool _output, const Args(&... args))
+        : T(sizeof(_Type), _output ? output::PARAM_TYPE : input::PARAM_TYPE), S(args...) { }
+    /// Set port/direction.
+    inline void setPort(bool output) { C2Param::setPort(output); }
+
+    DEFINE_CAST_OPERATORS(_Type)
+
+    /// Specialization for an input port parameter.
+    struct input : public T, public S,
+            public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
+        _C2_CORE_INDEX_OVERRIDE(ParamIndex)
+        /// Wrapper around base structure's constructor.
+        template<typename ...Args>
+        inline input(const Args(&... args)) : T(sizeof(_Type), input::PARAM_TYPE), S(args...) { }
+
+        DEFINE_CAST_OPERATORS(input)
+
+    };
+
+    /// Specialization for an output port parameter.
+    struct output : public T, public S,
+            public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
+        _C2_CORE_INDEX_OVERRIDE(ParamIndex)
+        /// Wrapper around base structure's constructor.
+        template<typename ...Args>
+        inline output(const Args(&... args)) : T(sizeof(_Type), output::PARAM_TYPE), S(args...) { }
+
+        DEFINE_CAST_OPERATORS(output)
+    };
+};
+
+/**
+ * Port-parameter template for flexible structures.
+ *
+ * Base template to define a port setting/tuning or info based on a flexible structure and
+ * an optional ParamIndex. Port parameters are tied to a port (input or output), but not to a
+ * specific stream.
+ *
+ * \tparam T param type C2Setting, C2Tuning or C2Info
+ * \tparam S wrapped flexible structure
+ * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
+ *         structures.
+ *
+ * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
+ * structures can be accessed via the m member variable; however, the constructors of the structure
+ * are wrapped directly. (This is because flexible types cannot be subclassed.)
+ *
+ * There are 3 flavors of port parameters: unspecified, input and output. Parameters with
+ * unspecified port expose a setPort method, and add an initial port parameter to the constructor.
+ */
+template<typename T, typename S, int ParamIndex>
+struct C2_HIDE C2PortParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
+    : public T, public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_UNDEFINED> {
+private:
+    typedef C2PortParam<T, S, ParamIndex> _Type;
+
+    /// Default constructor for basic allocation: new(flexCount) P.
+    inline C2PortParam(size_t flexCount) : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE) { }
+    template<typename ...Args>
+    /// Wrapper around base structure's constructor while also specifying port/direction.
+    inline C2PortParam(size_t flexCount, bool _output, const Args(&... args))
+        : T(_Type::CalcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE),
+          m(flexCount, args...) { }
+
+public:
+    /// Set port/direction.
+    inline void setPort(bool output) { C2Param::setPort(output); }
+
+    S m; ///< wrapped flexible structure
+
+    DEFINE_FLEXIBLE_METHODS(_Type, S)
+    DEFINE_CAST_OPERATORS(_Type)
+
+    /// Specialization for an input port parameter.
+    struct input : public T,
+            public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
+    private:
+        /// Wrapper around base structure's constructor while also specifying port/direction.
+        template<typename ...Args>
+        inline input(size_t flexCount, const Args(&... args))
+            : T(_Type::CalcSize(flexCount), input::PARAM_TYPE), m(flexCount, args...) { }
+
+    public:
+        S m; ///< wrapped flexible structure
+
+        DEFINE_FLEXIBLE_METHODS(input, S)
+        DEFINE_CAST_OPERATORS(input)
+    };
+
+    /// Specialization for an output port parameter.
+    struct output : public T,
+            public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
+    private:
+        /// Wrapper around base structure's constructor while also specifying port/direction.
+        template<typename ...Args>
+        inline output(size_t flexCount, const Args(&... args))
+            : T(_Type::CalcSize(flexCount), output::PARAM_TYPE), m(flexCount, args...) { }
+
+    public:
+        S m; ///< wrapped flexible structure
+
+        DEFINE_FLEXIBLE_METHODS(output, S)
+        DEFINE_CAST_OPERATORS(output)
+    };
+};
+
+/**
+ * Stream-parameter template.
+ *
+ * Base template to define a stream setting/tuning or info based on a structure and
+ * an optional ParamIndex. Stream parameters are tied to a specific stream on a port (input or
+ * output).
+ *
+ * \tparam T param type C2Setting, C2Tuning or C2Info
+ * \tparam S wrapped structure
+ * \tparam ParamIndex optional paramter index override. Must be specified for base/reused
+ *         structures.
+ *
+ * Parameters wrap structures by prepending a (parameter) header. The fields of the wrapped
+ * structure can be accessed directly, and constructors and potential public methods are also
+ * wrapped.
+ *
+ * There are 3 flavors of stream parameters: unspecified port, input and output. All of these expose
+ * a setStream method and an extra initial streamID parameter for the constructor. Moreover,
+ * parameters with unspecified port expose a setPort method, and add an additional initial port
+ * parameter to the constructor.
+ */
+template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
+struct C2_HIDE C2StreamParam : public T, public S,
+        private _C2StructCheck<S, ParamIndex,
+                T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Index::DIR_UNDEFINED> {
+    _C2_CORE_INDEX_OVERRIDE(ParamIndex)
+private:
+    typedef C2StreamParam<T, S, ParamIndex> _Type;
+
+public:
+    /// Default constructor. Port/direction and stream-ID is undefined.
+    inline C2StreamParam() : T(sizeof(_Type), _Type::PARAM_TYPE) { }
+    /// Wrapper around base structure's constructor while also specifying port/direction and
+    /// stream-ID.
+    template<typename ...Args>
+    inline C2StreamParam(bool _output, unsigned stream, const Args(&... args))
+        : T(sizeof(_Type), _output ? output::PARAM_TYPE : input::PARAM_TYPE, stream),
+          S(args...) { }
+    /// Set port/direction.
+    inline void setPort(bool output) { C2Param::setPort(output); }
+    /// Set stream-id. \retval true if the stream-id was successfully set.
+    inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
+
+    DEFINE_CAST_OPERATORS(_Type)
+
+    /// Specialization for an input stream parameter.
+    struct input : public T, public S,
+            public _C2StructCheck<S, ParamIndex,
+                    T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
+        _C2_CORE_INDEX_OVERRIDE(ParamIndex)
+
+        /// Default constructor. Stream-ID is undefined.
+        inline input() : T(sizeof(_Type), input::PARAM_TYPE) { }
+        /// Wrapper around base structure's constructor while also specifying stream-ID.
+        template<typename ...Args>
+        inline input(unsigned stream, const Args(&... args))
+            : T(sizeof(_Type), input::PARAM_TYPE, stream), S(args...) { }
+        /// Set stream-id. \retval true if the stream-id was successfully set.
+        inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
+
+        DEFINE_CAST_OPERATORS(input)
+    };
+
+    /// Specialization for an output stream parameter.
+    struct output : public T, public S,
+            public _C2StructCheck<S, ParamIndex,
+                    T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
+        _C2_CORE_INDEX_OVERRIDE(ParamIndex)
+
+        /// Default constructor. Stream-ID is undefined.
+        inline output() : T(sizeof(_Type), output::PARAM_TYPE) { }
+        /// Wrapper around base structure's constructor while also specifying stream-ID.
+        template<typename ...Args>
+        inline output(unsigned stream, const Args(&... args))
+            : T(sizeof(_Type), output::PARAM_TYPE, stream), S(args...) { }
+        /// Set stream-id. \retval true if the stream-id was successfully set.
+        inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
+
+        DEFINE_CAST_OPERATORS(output)
+    };
+};
+
+/**
+ * Stream-parameter template for flexible structures.
+ *
+ * Base template to define a stream setting/tuning or info based on a flexible structure and
+ * an optional ParamIndex. Stream parameters are tied to a specific stream on a port (input or
+ * output).
+ *
+ * \tparam T param type C2Setting, C2Tuning or C2Info
+ * \tparam S wrapped flexible structure
+ * \tparam ParamIndex optional parameter index override. Must be specified for base/reused
+ *         structures.
+ *
+ * Parameters wrap structures by prepending a (parameter) header. The fields and methods of flexible
+ * structures can be accessed via the m member variable; however, the constructors of the structure
+ * are wrapped directly. (This is because flexible types cannot be subclassed.)
+ *
+ * There are 3 flavors of stream parameters: unspecified port, input and output. All of these expose
+ * a setStream method and an extra initial streamID parameter for the constructor. Moreover,
+ * parameters with unspecified port expose a setPort method, and add an additional initial port
+ * parameter to the constructor.
+ */
+template<typename T, typename S, int ParamIndex>
+struct C2_HIDE C2StreamParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
+    : public T,
+      public _C2FlexStructCheck<S, ParamIndex,
+              T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Index::DIR_UNDEFINED> {
+private:
+    typedef C2StreamParam<T, S, ParamIndex> _Type;
+    /// Default constructor. Port/direction and stream-ID is undefined.
+    inline C2StreamParam(size_t flexCount) : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE, 0u) { }
+    /// Wrapper around base structure's constructor while also specifying port/direction and
+    /// stream-ID.
+    template<typename ...Args>
+    inline C2StreamParam(size_t flexCount, bool _output, unsigned stream, const Args(&... args))
+        : T(_Type::CalcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE, stream),
+          m(flexCount, args...) { }
+
+public:
+    S m; ///< wrapped flexible structure
+
+    /// Set port/direction.
+    inline void setPort(bool output) { C2Param::setPort(output); }
+    /// Set stream-id. \retval true if the stream-id was successfully set.
+    inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
+
+    DEFINE_FLEXIBLE_METHODS(_Type, S)
+    DEFINE_CAST_OPERATORS(_Type)
+
+    /// Specialization for an input stream parameter.
+    struct input : public T,
+            public _C2FlexStructCheck<S, ParamIndex,
+                    T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
+    private:
+        /// Default constructor. Stream-ID is undefined.
+        inline input(size_t flexCount) : T(_Type::CalcSize(flexCount), input::PARAM_TYPE) { }
+        /// Wrapper around base structure's constructor while also specifying stream-ID.
+        template<typename ...Args>
+        inline input(size_t flexCount, unsigned stream, const Args(&... args))
+            : T(_Type::CalcSize(flexCount), input::PARAM_TYPE, stream), m(flexCount, args...) { }
+
+    public:
+        S m; ///< wrapped flexible structure
+
+        /// Set stream-id. \retval true if the stream-id was successfully set.
+        inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
+
+        DEFINE_FLEXIBLE_METHODS(input, S)
+        DEFINE_CAST_OPERATORS(input)
+    };
+
+    /// Specialization for an output stream parameter.
+    struct output : public T,
+            public _C2FlexStructCheck<S, ParamIndex,
+                    T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
+    private:
+        /// Default constructor. Stream-ID is undefined.
+        inline output(size_t flexCount) : T(_Type::CalcSize(flexCount), output::PARAM_TYPE) { }
+        /// Wrapper around base structure's constructor while also specifying stream-ID.
+        template<typename ...Args>
+        inline output(size_t flexCount, unsigned stream, const Args(&... args))
+            : T(_Type::CalcSize(flexCount), output::PARAM_TYPE, stream), m(flexCount, args...) { }
+
+    public:
+        S m; ///< wrapped flexible structure
+
+        /// Set stream-id. \retval true if the stream-id was successfully set.
+        inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
+
+        DEFINE_FLEXIBLE_METHODS(output, S)
+        DEFINE_CAST_OPERATORS(output)
+    };
+};
+
+/* ======================== SIMPLE VALUE PARAMETERS ======================== */
+
+/**
+ * \ingroup internal
+ * A structure template encapsulating a single element with default constructors and no core-index.
+ */
+template<typename T>
+struct C2SimpleValueStruct {
+    T value; ///< simple value of the structure
+    // Default constructor.
+    inline C2SimpleValueStruct() = default;
+    // Constructor with an initial value.
+    inline C2SimpleValueStruct(T value) : value(value) {}
+    DEFINE_BASE_C2STRUCT(SimpleValue)
+};
+
+// TODO: move this and next to some generic place
+/**
+ * Interface to a block of (mapped) memory containing an array of some type (T).
+ */
+template<typename T>
+struct C2MemoryBlock {
+    /// \returns the number of elements in this block.
+    virtual size_t size() const = 0;
+    /// \returns a const pointer to the start of this block. Care must be taken to not read outside
+    /// the block.
+    virtual const T *data() const = 0; // TODO: should this be friend access only in some C2Memory module?
+    /// \returns a pointer to the start of this block. Care must be taken to not read or write
+    /// outside the block.
+    inline T *data() { return const_cast<T*>(const_cast<const C2MemoryBlock*>(this)->data()); }
+
+protected:
+    // TODO: for now it should never be deleted as C2MemoryBlock
+    virtual ~C2MemoryBlock() = default;
+};
+
+/**
+ * Interface to a block of memory containing a constant (constexpr) array of some type (T).
+ */
+template<typename T>
+struct C2ConstMemoryBlock : public C2MemoryBlock<T> {
+    virtual const T * data() const { return _mData; }
+    virtual size_t size() const { return _mSize; }
+
+    /// Constructor.
+    template<unsigned N>
+    inline constexpr C2ConstMemoryBlock(const T(&init)[N]) : _mData(init), _mSize(N) {}
+
+private:
+    const T *_mData;
+    const size_t _mSize;
+};
+
+/// \addtogroup internal
+/// @{
+
+/// Helper class to initialize flexible arrays with various initalizers.
+struct _C2ValueArrayHelper {
+    // char[]-s are used as null terminated strings, so the last element is never inited.
+
+    /// Initialize a flexible array using a constexpr memory block.
+    template<typename T>
+    static void init(T(&array)[], size_t arrayLen, const C2MemoryBlock<T> &block) {
+        // reserve last element for terminal 0 for strings
+        if (arrayLen && std::is_same<T, char>::value) {
+            --arrayLen;
+        }
+        if (block.data()) {
+            memcpy(array, block.data(), std::min(arrayLen, block.size()) * sizeof(T));
+        }
+    }
+
+    /// Initialize a flexible array using an initializer list.
+    template<typename T>
+    static void init(T(&array)[], size_t arrayLen, const std::initializer_list<T> &init) {
+        size_t ix = 0;
+        // reserve last element for terminal 0 for strings
+        if (arrayLen && std::is_same<T, char>::value) {
+            --arrayLen;
+        }
+        for (const T &item : init) {
+            if (ix == arrayLen) {
+                break;
+            }
+            array[ix++] = item;
+        }
+    }
+
+    /// Initialize a flexible array using a vector.
+    template<typename T>
+    static void init(T(&array)[], size_t arrayLen, const std::vector<T> &init) {
+        size_t ix = 0;
+        // reserve last element for terminal 0 for strings
+        if (arrayLen && std::is_same<T, char>::value) {
+            --arrayLen;
+        }
+        for (const T &item : init) {
+            if (ix == arrayLen) {
+                break;
+            }
+            array[ix++] = item;
+        }
+    }
+
+    /// Initialize a flexible array using another flexible array.
+    template<typename T, unsigned N>
+    static void init(T(&array)[], size_t arrayLen, const T(&str)[N]) {
+        // reserve last element for terminal 0 for strings
+        if (arrayLen && std::is_same<T, char>::value) {
+            --arrayLen;
+        }
+        if (arrayLen) {
+            memcpy(array, str, std::min(arrayLen, (size_t)N) * sizeof(T));
+        }
+    }
+};
+
+/**
+ * Specialization for a flexible blob and string arrays. A structure template encapsulating a single
+ * flexible array member with default flexible constructors and no core-index. This type cannot be
+ * constructed on its own as it's size is 0.
+ *
+ * \internal This is different from C2SimpleArrayStruct<T[]> simply because its member has the name
+ * as value to reflect this is a single value.
+ */
+template<typename T>
+struct C2SimpleValueStruct<T[]> {
+    static_assert(std::is_same<T, char>::value || std::is_same<T, uint8_t>::value,
+                  "C2SimpleValueStruct<T[]> is only for BLOB or STRING");
+    T value[];
+
+    inline C2SimpleValueStruct() = default;
+    DEFINE_BASE_C2STRUCT(SimpleValue)
+    FLEX(C2SimpleValueStruct, value)
+
+private:
+    inline C2SimpleValueStruct(size_t flexCount, const C2MemoryBlock<T> &block) {
+        _C2ValueArrayHelper::init(value, flexCount, block);
+    }
+
+    inline C2SimpleValueStruct(size_t flexCount, const std::initializer_list<T> &init) {
+        _C2ValueArrayHelper::init(value, flexCount, init);
+    }
+
+    inline C2SimpleValueStruct(size_t flexCount, const std::vector<T> &init) {
+        _C2ValueArrayHelper::init(value, flexCount, init);
+    }
+
+    template<unsigned N>
+    inline C2SimpleValueStruct(size_t flexCount, const T(&init)[N]) {
+        _C2ValueArrayHelper::init(value, flexCount, init);
+    }
+};
+
+/// @}
+
+/**
+ * A structure template encapsulating a single flexible array element of a specific type (T) with
+ * default constructors and no core-index. This type cannot be constructed on its own as it's size
+ * is 0. Instead, it is meant to be used as a parameter, e.g.
+ *
+ *   typedef C2StreamParam<C2Info, C2SimpleArrayStruct<C2MyFancyStruct>,
+ *           kParamIndexMyFancyArrayStreamParam> C2MyFancyArrayStreamInfo;
+ */
+template<typename T>
+struct C2SimpleArrayStruct {
+    static_assert(!std::is_same<T, char>::value && !std::is_same<T, uint8_t>::value,
+                  "use C2SimpleValueStruct<T[]> is for BLOB or STRING");
+
+    T values[]; ///< array member
+    /// Default constructor
+    inline C2SimpleArrayStruct() = default;
+    DEFINE_BASE_FLEX_C2STRUCT(SimpleArray, values)
+    //FLEX(C2SimpleArrayStruct, values)
+
+private:
+    /// Construct from a C2MemoryBlock.
+    /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
+    inline C2SimpleArrayStruct(size_t flexCount, const C2MemoryBlock<T> &block) {
+        _C2ValueArrayHelper::init(values, flexCount, block);
+    }
+
+    /// Construct from an initializer list.
+    /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
+    inline C2SimpleArrayStruct(size_t flexCount, const std::initializer_list<T> &init) {
+        _C2ValueArrayHelper::init(values, flexCount, init);
+    }
+
+    /// Construct from an vector.
+    /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
+    inline C2SimpleArrayStruct(size_t flexCount, const std::vector<T> &init) {
+        _C2ValueArrayHelper::init(values, flexCount, init);
+    }
+
+    /// Construct from another flexible array.
+    /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
+    template<unsigned N>
+    inline C2SimpleArrayStruct(size_t flexCount, const T(&init)[N]) {
+        _C2ValueArrayHelper::init(values, flexCount, init);
+    }
+};
+
+/**
+ * \addtogroup simplevalue Simple value and array structures.
+ * @{
+ *
+ * Simple value structures.
+ *
+ * Structures containing a single simple value. These can be reused to easily define simple
+ * parameters of various types:
+ *
+ *   typedef C2PortParam<C2Tuning, C2Int32Value, kParamIndexMyIntegerPortParam>
+ *           C2MyIntegerPortParamTuning;
+ *
+ * They contain a single member (value or values) that is described as "value" or "values".
+ *
+ * These structures don't define a core index, and as such, they cannot be used in structure
+ * declarations. Use type[] instead, such as int32_t field[].
+ */
+/// A 32-bit signed integer parameter in value, described as "value"
+typedef C2SimpleValueStruct<int32_t> C2Int32Value;
+/// A 32-bit signed integer array parameter in values, described as "values"
+typedef C2SimpleArrayStruct<int32_t> C2Int32Array;
+/// A 32-bit unsigned integer parameter in value, described as "value"
+typedef C2SimpleValueStruct<uint32_t> C2Uint32Value;
+/// A 32-bit unsigned integer array parameter in values, described as "values"
+typedef C2SimpleArrayStruct<uint32_t> C2Uint32Array;
+/// A 64-bit signed integer parameter in value, described as "value"
+typedef C2SimpleValueStruct<int64_t> C2Int64Value;
+/// A 64-bit signed integer array parameter in values, described as "values"
+typedef C2SimpleArrayStruct<int64_t> C2Int64Array;
+/// A 64-bit unsigned integer parameter in value, described as "value"
+typedef C2SimpleValueStruct<uint64_t> C2Uint64Value;
+/// A 64-bit unsigned integer array parameter in values, described as "values"
+typedef C2SimpleArrayStruct<uint64_t> C2Uint64Array;
+/// A float parameter in value, described as "value"
+typedef C2SimpleValueStruct<float> C2FloatValue;
+/// A float array parameter in values, described as "values"
+typedef C2SimpleArrayStruct<float> C2FloatArray;
+/// A blob flexible parameter in value, described as "value"
+typedef C2SimpleValueStruct<uint8_t[]> C2BlobValue;
+/// A string flexible parameter in value, described as "value"
+typedef C2SimpleValueStruct<char[]> C2StringValue;
+
+template<typename T>
+const std::vector<C2FieldDescriptor> C2SimpleValueStruct<T>::FieldList() {
+    return { DESCRIBE_C2FIELD(value, "value") };
+}
+template<typename T>
+const std::vector<C2FieldDescriptor> C2SimpleValueStruct<T[]>::FieldList() {
+    return { DESCRIBE_C2FIELD(value, "value") };
+}
+template<typename T>
+const std::vector<C2FieldDescriptor> C2SimpleArrayStruct<T>::FieldList() {
+    return { DESCRIBE_C2FIELD(values, "values") };
+}
+
+/// @}
+
+/// @}
+
+#endif  // C2PARAM_DEF_H_
diff --git a/media/codec2/include/C2Work.h b/media/codec2/include/C2Work.h
new file mode 100644
index 0000000..6923f3e
--- /dev/null
+++ b/media/codec2/include/C2Work.h
@@ -0,0 +1,235 @@
+/*
+ * 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 C2WORK_H_
+
+#define C2WORK_H_
+
+#include <C2Buffer.h>
+#include <C2Param.h>
+
+#include <memory>
+#include <list>
+#include <vector>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/// \defgroup work Work and data processing
+/// @{
+
+/**
+ * Information describing the reason a parameter settings may fail, or
+ * may be overriden.
+ */
+struct C2SettingResult {
+    enum Failure : uint32_t {
+        /* parameter failures below */
+        BAD_TYPE,   ///< parameter is not supported
+        BAD_PORT,   ///< parameter is not supported on the specific port
+        BAD_INDEX,  ///< parameter is not supported on the specific stream
+        READ_ONLY,  ///< parameter is read-only and cannot be set
+        MISMATCH,   ///< parameter mismatches input data
+
+        /* field failures below */
+        BAD_VALUE,  ///< strict parameter does not accept value for the field at all
+        CONFLICT,   ///< strict parameter field value is in conflict with an/other setting(s)
+
+        /// parameter field is out of range due to other settings (this failure mode
+        /// can only be used for strict calculated parameters)
+        UNSUPPORTED,
+
+        /// field does not access the requested parameter value at all. It has been corrected to
+        /// the closest supported value. This failure mode is provided to give guidance as to what
+        /// are the currently supported values for this field (which may be a subset of the at-all-
+        /// potential values)
+        INFO_BAD_VALUE,
+
+        /// requested parameter value is in conflict with an/other setting(s)
+        /// and has been corrected to the closest supported value. This failure
+        /// mode is given to provide guidance as to what are the currently supported values as well
+        /// as to optionally provide suggestion to the client as to how to enable the requested
+        /// parameter value.
+        INFO_CONFLICT,
+    };
+
+    Failure failure;    ///< failure code
+
+    /// Failing (or corrected) field or parameterand optionally, currently supported values for the
+    /// field. Values must only be set for field failures other than BAD_VALUE, and only if they are
+    /// different from the globally supported values (e.g. due to restrictions by another param or
+    /// input data).
+    C2ParamFieldValues field;
+
+    /// Conflicting parameters or fields with optional suggestions with (optional) suggested values
+    /// for any conflicting fields to avoid the conflict. Must only be set for CONFLICT, UNSUPPORTED
+    /// and INFO_CONFLICT failure codes.
+    std::vector<C2ParamFieldValues> conflicts;
+};
+
+// ================================================================================================
+//  WORK
+// ================================================================================================
+
+/** Unique ID for a processing node. */
+typedef uint32_t c2_node_id_t;
+
+enum {
+    kParamIndexWorkOrdinal,
+};
+
+/**
+ * Information for ordering work items on a component port.
+ */
+struct C2WorkOrdinalStruct {
+//public:
+    c2_cntr64_t timestamp;     /** frame timestamp in microseconds */
+    c2_cntr64_t frameIndex;    /** submission ordinal on the initial component */
+    c2_cntr64_t customOrdinal; /** can be given by the component, e.g. decode order */
+
+    DEFINE_AND_DESCRIBE_C2STRUCT(WorkOrdinal)
+    C2FIELD(timestamp, "timestamp")
+    C2FIELD(frameIndex, "frame-index")
+    C2FIELD(customOrdinal, "custom-ordinal")
+};
+
+/**
+ * This structure represents a Codec 2.0 frame with its metadata.
+ *
+ * A frame basically consists of an ordered sets of buffers, configuration changes and info buffers
+ * along with some non-configuration metadata.
+ */
+struct C2FrameData {
+//public:
+    enum flags_t : uint32_t {
+        /**
+         * For input frames: no output frame shall be generated when processing this frame, but
+         * metadata shall still be processed.
+         * For output frames: this frame shall be discarded and but metadata is still valid.
+         */
+        FLAG_DROP_FRAME    = (1 << 0),
+        /**
+         * This frame is the last frame of the current stream. Further frames are part of a new
+         * stream.
+         */
+        FLAG_END_OF_STREAM = (1 << 1),
+        /**
+         * This frame shall be discarded with its metadata.
+         * This flag is only set by components - e.g. as a response to the flush command.
+         */
+        FLAG_DISCARD_FRAME = (1 << 2),
+        /**
+         * This frame is not the last frame produced for the input.
+         *
+         * This flag is normally set by the component - e.g. when an input frame results in multiple
+         * output frames, this flag is set on all but the last output frame.
+         *
+         * Also, when components are chained, this flag should be propagated down the
+         * work chain. That is, if set on an earlier frame of a work-chain, it should be propagated
+         * to all later frames in that chain. Additionally, components down the chain could set
+         * this flag even if not set earlier, e.g. if multiple output frame is generated at that
+         * component for the input frame.
+         */
+        FLAG_INCOMPLETE = (1 << 3),
+        /**
+         * This frame contains only codec-specific configuration data, and no actual access unit.
+         *
+         * \deprecated pass codec configuration with using the \todo codec-specific configuration
+         * info together with the access unit.
+         */
+        FLAG_CODEC_CONFIG  = (1u << 31),
+    };
+
+    /**
+     * Frame flags */
+    flags_t  flags;
+    C2WorkOrdinalStruct ordinal;
+    std::vector<std::shared_ptr<C2Buffer>> buffers;
+    //< for initial work item, these may also come from the parser - if provided
+    //< for output buffers, these are the responses to requestedInfos
+    std::vector<std::unique_ptr<C2Param>>      configUpdate;
+    std::vector<std::shared_ptr<C2InfoBuffer>> infoBuffers;
+};
+
+struct C2Worklet {
+//public:
+    // IN
+    c2_node_id_t component;
+
+    /** Configuration changes to be applied before processing this worklet. */
+    std::vector<std::unique_ptr<C2Tuning>> tunings;
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+
+    // OUT
+    C2FrameData output;
+};
+
+/**
+ * Information about partial work-chains not part of the current work items.
+ *
+ * To be defined later.
+ */
+struct C2WorkChainInfo;
+
+/**
+ * This structure holds information about all a single work item.
+ *
+ * This structure shall be passed by the client to the component for the first worklet. As such,
+ * worklets must not be empty. The ownership of this object is passed.
+ */
+struct C2Work {
+//public:
+    /// additional work chain info not part of this work
+    std::shared_ptr<C2WorkChainInfo> chainInfo;
+
+    /// The input data to be processed as part of this work/work-chain. This is provided by the
+    /// client with ownership. When the work is returned (via onWorkDone), the input buffer-pack's
+    /// buffer vector shall contain nullptrs.
+    C2FrameData input;
+
+    /// The chain of components, tunings (including output buffer pool IDs) and info requests that the
+    /// data must pass through. If this has more than a single element, the tunnels between successive
+    /// components of the worklet chain must have been (successfully) pre-registered at the time that
+    /// the work is submitted. Allocating the output buffers in the worklets is the responsibility of
+    /// each component. Upon work submission, each output buffer-pack shall be an appropriately sized
+    /// vector containing nullptrs. When the work is completed/returned to the client, output buffers
+    /// pointers from all but the final worklet shall be nullptrs.
+    std::list<std::unique_ptr<C2Worklet>> worklets;
+
+    /// Number of worklets successfully processed in this chain. This shall be initialized to 0 by the
+    /// client when the work is submitted. It shall contain the number of worklets that were
+    /// successfully processed when the work is returned to the client. If this is less then the number
+    /// of worklets, result must not be success. It must be in the range of [0, worklets.size()].
+    uint32_t workletsProcessed;
+
+    /// The final outcome of the work (corresponding to the current workletsProcessed). If 0 when
+    /// work is returned, it is assumed that all worklets have been processed.
+    c2_status_t result;
+};
+
+/**
+ * Information about a future work to be submitted to the component. The information is used to
+ * reserve the work for work ordering purposes.
+ */
+struct C2WorkOutline {
+//public:
+    C2WorkOrdinalStruct ordinal;
+    std::vector<c2_node_id_t> chain;
+};
+
+/// @}
+
+#endif  // C2WORK_H_
diff --git a/media/codec2/include/_C2MacroUtils.h b/media/codec2/include/_C2MacroUtils.h
new file mode 100644
index 0000000..04e9ba5
--- /dev/null
+++ b/media/codec2/include/_C2MacroUtils.h
@@ -0,0 +1,162 @@
+/*
+ * 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_MACRO_UTILS_H_
+#define C2UTILS_MACRO_UTILS_H_
+
+/** \file
+ * Macro utilities for the utils library used by Codec2 implementations.
+ */
+
+/// \if 0
+
+/* --------------------------------- VARIABLE ARGUMENT COUNTING --------------------------------- */
+
+// remove empty arguments - _C2_ARG() expands to '', while _C2_ARG(x) expands to ', x'
+// _C2_ARGn(...) does the same for n arguments
+#define _C2_ARG(...) , ##__VA_ARGS__
+#define _C2_ARG2(_1, _2) _C2_ARG(_1) _C2_ARG(_2)
+#define _C2_ARG4(_1, _2, _3, _4) _C2_ARG2(_1, _2) _C2_ARG2(_3, _4)
+#define _C2_ARG8(_1, _2, _3, _4, _5, _6, _7, _8) _C2_ARG4(_1, _2, _3, _4) _C2_ARG4(_5, _6, _7, _8)
+#define _C2_ARG16(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
+        _C2_ARG8(_1, _2, _3, _4, _5, _6, _7, _8) _C2_ARG8(_9, _10, _11, _12, _13, _14, _15, _16)
+
+// return the 65th argument
+#define _C2_ARGC_3(_, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \
+        _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, \
+        _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, \
+        _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, ...) _64
+
+/// \endif
+
+/**
+ * Returns the number of arguments.
+ */
+// We do this by prepending 1 and appending 65 designed values such that the 65th element
+// will be the number of arguments.
+#define _C2_ARGC(...) _C2_ARGC_1(0, ##__VA_ARGS__, \
+        64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, \
+        42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \
+        20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
+
+/// \if 0
+
+// step 1. remove empty arguments - this is needed to allow trailing comma in enum definitions
+// (NOTE: we don't know which argument will have this trailing comma so we have to try all)
+#define _C2_ARGC_1(_, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \
+        _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, \
+        _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, \
+        _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, ...) \
+    _C2_ARGC_2(_ _C2_ARG(_0) \
+    _C2_ARG16(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
+    _C2_ARG16(_17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32) \
+    _C2_ARG16(_33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48) \
+    _C2_ARG16(_49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64), \
+    ##__VA_ARGS__)
+
+// step 2. this is needed as removed arguments cannot be passed directly as empty into a macro
+#define _C2_ARGC_2(...) _C2_ARGC_3(__VA_ARGS__)
+
+/// \endif
+
+/* -------------------------------- VARIABLE ARGUMENT CONVERSION -------------------------------- */
+
+/// \if 0
+
+// macros that convert _1, _2, _3, ... to fn(_1, arg), fn(_2, arg), fn(_3, arg), ...
+#define _C2_MAP_64(fn, arg, head, ...) fn(head, arg), _C2_MAP_63(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_63(fn, arg, head, ...) fn(head, arg), _C2_MAP_62(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_62(fn, arg, head, ...) fn(head, arg), _C2_MAP_61(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_61(fn, arg, head, ...) fn(head, arg), _C2_MAP_60(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_60(fn, arg, head, ...) fn(head, arg), _C2_MAP_59(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_59(fn, arg, head, ...) fn(head, arg), _C2_MAP_58(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_58(fn, arg, head, ...) fn(head, arg), _C2_MAP_57(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_57(fn, arg, head, ...) fn(head, arg), _C2_MAP_56(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_56(fn, arg, head, ...) fn(head, arg), _C2_MAP_55(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_55(fn, arg, head, ...) fn(head, arg), _C2_MAP_54(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_54(fn, arg, head, ...) fn(head, arg), _C2_MAP_53(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_53(fn, arg, head, ...) fn(head, arg), _C2_MAP_52(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_52(fn, arg, head, ...) fn(head, arg), _C2_MAP_51(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_51(fn, arg, head, ...) fn(head, arg), _C2_MAP_50(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_50(fn, arg, head, ...) fn(head, arg), _C2_MAP_49(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_49(fn, arg, head, ...) fn(head, arg), _C2_MAP_48(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_48(fn, arg, head, ...) fn(head, arg), _C2_MAP_47(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_47(fn, arg, head, ...) fn(head, arg), _C2_MAP_46(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_46(fn, arg, head, ...) fn(head, arg), _C2_MAP_45(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_45(fn, arg, head, ...) fn(head, arg), _C2_MAP_44(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_44(fn, arg, head, ...) fn(head, arg), _C2_MAP_43(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_43(fn, arg, head, ...) fn(head, arg), _C2_MAP_42(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_42(fn, arg, head, ...) fn(head, arg), _C2_MAP_41(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_41(fn, arg, head, ...) fn(head, arg), _C2_MAP_40(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_40(fn, arg, head, ...) fn(head, arg), _C2_MAP_39(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_39(fn, arg, head, ...) fn(head, arg), _C2_MAP_38(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_38(fn, arg, head, ...) fn(head, arg), _C2_MAP_37(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_37(fn, arg, head, ...) fn(head, arg), _C2_MAP_36(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_36(fn, arg, head, ...) fn(head, arg), _C2_MAP_35(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_35(fn, arg, head, ...) fn(head, arg), _C2_MAP_34(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_34(fn, arg, head, ...) fn(head, arg), _C2_MAP_33(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_33(fn, arg, head, ...) fn(head, arg), _C2_MAP_32(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_32(fn, arg, head, ...) fn(head, arg), _C2_MAP_31(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_31(fn, arg, head, ...) fn(head, arg), _C2_MAP_30(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_30(fn, arg, head, ...) fn(head, arg), _C2_MAP_29(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_29(fn, arg, head, ...) fn(head, arg), _C2_MAP_28(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_28(fn, arg, head, ...) fn(head, arg), _C2_MAP_27(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_27(fn, arg, head, ...) fn(head, arg), _C2_MAP_26(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_26(fn, arg, head, ...) fn(head, arg), _C2_MAP_25(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_25(fn, arg, head, ...) fn(head, arg), _C2_MAP_24(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_24(fn, arg, head, ...) fn(head, arg), _C2_MAP_23(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_23(fn, arg, head, ...) fn(head, arg), _C2_MAP_22(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_22(fn, arg, head, ...) fn(head, arg), _C2_MAP_21(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_21(fn, arg, head, ...) fn(head, arg), _C2_MAP_20(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_20(fn, arg, head, ...) fn(head, arg), _C2_MAP_19(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_19(fn, arg, head, ...) fn(head, arg), _C2_MAP_18(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_18(fn, arg, head, ...) fn(head, arg), _C2_MAP_17(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_17(fn, arg, head, ...) fn(head, arg), _C2_MAP_16(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_16(fn, arg, head, ...) fn(head, arg), _C2_MAP_15(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_15(fn, arg, head, ...) fn(head, arg), _C2_MAP_14(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_14(fn, arg, head, ...) fn(head, arg), _C2_MAP_13(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_13(fn, arg, head, ...) fn(head, arg), _C2_MAP_12(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_12(fn, arg, head, ...) fn(head, arg), _C2_MAP_11(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_11(fn, arg, head, ...) fn(head, arg), _C2_MAP_10(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_10(fn, arg, head, ...) fn(head, arg), _C2_MAP_9(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_9(fn, arg, head, ...) fn(head, arg), _C2_MAP_8(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_8(fn, arg, head, ...) fn(head, arg), _C2_MAP_7(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_7(fn, arg, head, ...) fn(head, arg), _C2_MAP_6(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_6(fn, arg, head, ...) fn(head, arg), _C2_MAP_5(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_5(fn, arg, head, ...) fn(head, arg), _C2_MAP_4(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_4(fn, arg, head, ...) fn(head, arg), _C2_MAP_3(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_3(fn, arg, head, ...) fn(head, arg), _C2_MAP_2(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_2(fn, arg, head, ...) fn(head, arg), _C2_MAP_1(fn, arg, ##__VA_ARGS__)
+#define _C2_MAP_1(fn, arg, head, ...) fn(head, arg)
+
+/// \endif
+
+/**
+ * Maps each argument using another macro x -> fn(x, arg)
+ */
+// use wrapper to call the proper mapper based on the number of arguments
+#define _C2_MAP(fn, arg, ...) _C2_MAP__(_C2_ARGC(__VA_ARGS__), fn, arg, ##__VA_ARGS__)
+
+/// \if 0
+
+// evaluate _n so it becomes a number
+#define _C2_MAP__(_n, fn, arg, ...) _C2_MAP_(_n, fn, arg, __VA_ARGS__)
+// call the proper mapper
+#define _C2_MAP_(_n, fn, arg, ...) _C2_MAP_##_n (fn, arg, __VA_ARGS__)
+
+/// \endif
+
+#endif  // C2UTILS_MACRO_UTILS_H_
diff --git a/media/codec2/include/android-C2Buffer.h b/media/codec2/include/android-C2Buffer.h
new file mode 100644
index 0000000..26beab7
--- /dev/null
+++ b/media/codec2/include/android-C2Buffer.h
@@ -0,0 +1,71 @@
+/*
+ * 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 ANDROID_C2BUFFER_H_
+#define ANDROID_C2BUFFER_H_
+
+#include <cutils/native_handle.h>
+#include <hardware/gralloc.h>
+
+/* Use android native handle for C2Handle */
+typedef ::native_handle_t C2Handle;
+
+namespace android {
+
+/**
+ * Android platform buffer/memory usage bits.
+ */
+struct C2AndroidMemoryUsage : public C2MemoryUsage {
+    inline C2AndroidMemoryUsage(const C2MemoryUsage &usage) : C2MemoryUsage(usage) { }
+
+// public:
+    /**
+     * Reuse gralloc flags where possible, as Codec 2.0 API only uses bits 0 and 1.
+     */
+    enum consumer_t : uint64_t {
+        RENDERSCRIPT_READ = GRALLOC_USAGE_RENDERSCRIPT,
+        HW_TEXTURE_READ   = GRALLOC_USAGE_HW_TEXTURE,
+        HW_COMPOSER_READ  = GRALLOC_USAGE_HW_COMPOSER,
+        // gralloc does not define a video decoder read usage flag, so use encoder for
+        // now
+        HW_CODEC_READ     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+        READ_PROTECTED    = GRALLOC_USAGE_PROTECTED,
+    };
+
+    enum producer_t : uint64_t {
+        RENDERSCRIPT_WRITE = GRALLOC_USAGE_RENDERSCRIPT,
+        HW_TEXTURE_WRITE   = GRALLOC_USAGE_HW_RENDER,
+        HW_COMPOSER_WRITE  = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER,
+        HW_CODEC_WRITE     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+        // gralloc does not define a write protected usage flag, so use read protected
+        // now
+        WRITE_PROTECTED    = GRALLOC_USAGE_PROTECTED,
+    };
+
+    /**
+     * Convert from gralloc usage.
+     */
+    static C2MemoryUsage FromGrallocUsage(uint64_t usage);
+
+    /**
+     * Convert to gralloc usage.
+     */
+    uint64_t asGrallocUsage() const;
+};
+
+}  // namespace android
+
+#endif  // ANDROID_C2BUFFER_H_
diff --git a/media/codec2/include/media/stagefright/codec2/1.0/InputSurface.h b/media/codec2/include/media/stagefright/codec2/1.0/InputSurface.h
new file mode 100644
index 0000000..b011a06
--- /dev/null
+++ b/media/codec2/include/media/stagefright/codec2/1.0/InputSurface.h
@@ -0,0 +1,71 @@
+/*
+ * 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 ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
+#define ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
+
+#include <memory>
+
+#include <C2Component.h>
+#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
+
+namespace android {
+
+class GraphicBufferSource;
+
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
+        HGraphicBufferProducer;
+typedef ::android::IGraphicBufferProducer BGraphicBufferProducer;
+
+// TODO: ::android::TWGraphicBufferProducer<IInputSurface>
+typedef ::android::TWGraphicBufferProducer<HGraphicBufferProducer> InputSurfaceBase;
+
+class InputSurface : public InputSurfaceBase {
+public:
+    virtual ~InputSurface() = default;
+
+    // Methods from IInputSurface
+    sp<InputSurfaceConnection> connectToComponent(
+            const std::shared_ptr<::C2Component> &comp);
+    // TODO: intf()
+
+    static sp<InputSurface> Create();
+
+private:
+    InputSurface(
+            const sp<BGraphicBufferProducer> &base,
+            const sp<::android::GraphicBufferSource> &source);
+
+    sp<::android::GraphicBufferSource> mSource;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
diff --git a/media/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h b/media/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h
new file mode 100644
index 0000000..b24a416
--- /dev/null
+++ b/media/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h
@@ -0,0 +1,67 @@
+/*
+ * 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 ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H
+#define ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H
+
+#include <memory>
+
+#include <C2Component.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+// TODO: inherit from IInputSurfaceConnection
+class InputSurfaceConnection : public RefBase {
+public:
+    virtual ~InputSurfaceConnection();
+
+    // From IInputSurfaceConnection
+    void disconnect();
+
+private:
+    friend class InputSurface;
+
+    // For InputSurface
+    InputSurfaceConnection(
+            const sp<GraphicBufferSource> &source, const std::shared_ptr<C2Component> &comp);
+    bool init();
+
+    InputSurfaceConnection() = delete;
+
+    class Impl;
+
+    sp<GraphicBufferSource> mSource;
+    sp<Impl> mImpl;
+
+    DISALLOW_EVIL_CONSTRUCTORS(InputSurfaceConnection);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H