Merge "MediaCodec refactoring part 1-c: buffer ownership"
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index b2699fa..0533ba6 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -330,8 +330,8 @@
static status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle);
- static status_t stopAudioSource(audio_io_handle_t handle);
+ audio_patch_handle_t *handle);
+ static status_t stopAudioSource(audio_patch_handle_t handle);
static status_t setMasterMono(bool mono);
static status_t getMasterMono(bool *mono);
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index ef15a0c..5637dd5 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -164,8 +164,8 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle) = 0;
- virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+ audio_patch_handle_t *handle) = 0;
+ virtual status_t stopAudioSource(audio_patch_handle_t handle) = 0;
virtual status_t setMasterMono(bool mono) = 0;
virtual status_t getMasterMono(bool *mono) = 0;
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 33974e0..d45b12f 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -1175,14 +1175,14 @@
status_t AudioSystem::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle)
+ audio_patch_handle_t *handle)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
return aps->startAudioSource(source, attributes, handle);
}
-status_t AudioSystem::stopAudioSource(audio_io_handle_t handle)
+status_t AudioSystem::stopAudioSource(audio_patch_handle_t handle)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 946da8a..2fb2da6 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -738,7 +738,7 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle)
+ audio_patch_handle_t *handle)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
@@ -755,11 +755,11 @@
if (status != NO_ERROR) {
return status;
}
- *handle = (audio_io_handle_t)reply.readInt32();
+ *handle = (audio_patch_handle_t)reply.readInt32();
return status;
}
- virtual status_t stopAudioSource(audio_io_handle_t handle)
+ virtual status_t stopAudioSource(audio_patch_handle_t handle)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
@@ -1332,7 +1332,7 @@
data.read(&source, sizeof(struct audio_port_config));
audio_attributes_t attributes;
data.read(&attributes, sizeof(audio_attributes_t));
- audio_io_handle_t handle = {};
+ audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
status_t status = startAudioSource(&source, &attributes, &handle);
reply->writeInt32(status);
reply->writeInt32(handle);
@@ -1341,7 +1341,7 @@
case STOP_AUDIO_SOURCE: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
- audio_io_handle_t handle = (audio_io_handle_t)data.readInt32();
+ audio_patch_handle_t handle = (audio_patch_handle_t) data.readInt32();
status_t status = stopAudioSource(handle);
reply->writeInt32(status);
return NO_ERROR;
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
index 1af7dc1..1b88e5d 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -73,6 +73,10 @@
class FLACParser : public RefBase {
public:
+ enum {
+ kMaxChannels = 8,
+ };
+
explicit FLACParser(
const sp<DataSource> &dataSource,
// If metadata pointers aren't provided, we don't fill them
@@ -122,7 +126,7 @@
// media buffers
size_t mMaxBufferSize;
MediaBufferGroup *mGroup;
- void (*mCopy)(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels);
+ void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
// handle to underlying libFLAC parser
FLAC__StreamDecoder *mDecoder;
@@ -139,7 +143,7 @@
bool mWriteRequested;
bool mWriteCompleted;
FLAC__FrameHeader mWriteHeader;
- const FLAC__int32 * const *mWriteBuffer;
+ FLAC__int32 const * mWriteBuffer[kMaxChannels];
// most recent error reported by libFLAC parser
FLAC__StreamDecoderErrorStatus mErrorStatus;
@@ -323,7 +327,7 @@
mWriteRequested = false;
// FLAC parser doesn't free or realloc buffer until next frame or finish
mWriteHeader = frame->header;
- mWriteBuffer = buffer;
+ memmove(mWriteBuffer, buffer, sizeof(const FLAC__int32 * const) * getChannels());
mWriteCompleted = true;
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
} else {
@@ -382,7 +386,7 @@
static void copyMono8(
short *dst,
- const int *const *src,
+ const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
@@ -392,7 +396,7 @@
static void copyStereo8(
short *dst,
- const int *const *src,
+ const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
@@ -401,7 +405,7 @@
}
}
-static void copyMultiCh8(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
+static void copyMultiCh8(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -412,7 +416,7 @@
static void copyMono16(
short *dst,
- const int *const *src,
+ const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
@@ -422,7 +426,7 @@
static void copyStereo16(
short *dst,
- const int *const *src,
+ const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
@@ -431,7 +435,7 @@
}
}
-static void copyMultiCh16(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
+static void copyMultiCh16(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -444,7 +448,7 @@
static void copyMono24(
short *dst,
- const int *const *src,
+ const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
@@ -454,7 +458,7 @@
static void copyStereo24(
short *dst,
- const int *const *src,
+ const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
for (unsigned i = 0; i < nSamples; ++i) {
@@ -463,7 +467,7 @@
}
}
-static void copyMultiCh24(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
+static void copyMultiCh24(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -474,7 +478,7 @@
static void copyTrespass(
short * /* dst */,
- const int *const * /* src */,
+ const int *[FLACParser::kMaxChannels] /* src */,
unsigned /* nSamples */,
unsigned /* nChannels */) {
TRESPASS();
@@ -499,7 +503,6 @@
mStreamInfoValid(false),
mWriteRequested(false),
mWriteCompleted(false),
- mWriteBuffer(NULL),
mErrorStatus((FLAC__StreamDecoderErrorStatus) -1)
{
ALOGV("FLACParser::FLACParser");
@@ -555,7 +558,7 @@
}
if (mStreamInfoValid) {
// check channel count
- if (getChannels() == 0 || getChannels() > 8) {
+ if (getChannels() == 0 || getChannels() > kMaxChannels) {
ALOGE("unsupported channel count %u", getChannels());
return NO_INIT;
}
@@ -591,7 +594,7 @@
static const struct {
unsigned mChannels;
unsigned mBitsPerSample;
- void (*mCopy)(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels);
+ void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
} table[] = {
{ 1, 8, copyMono8 },
{ 2, 8, copyStereo8 },
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 93643c2..d3b34b7 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -1169,7 +1169,7 @@
}
}
- if (flags & kPreferSoftwareCodecs) {
+ if (flags & kPreferSoftwareCodecs || property_get_bool("debug.stagefright.swcodec", false)) {
matches->sort(compareSoftwareCodecsFirst);
}
}
diff --git a/media/libstagefright/codec2/Android.mk b/media/libstagefright/codec2/Android.mk
new file mode 100644
index 0000000..a463205
--- /dev/null
+++ b/media/libstagefright/codec2/Android.mk
@@ -0,0 +1,20 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ C2.cpp \
+
+LOCAL_C_INCLUDES += \
+ $(TOP)/frameworks/av/media/libstagefright/codec2/include \
+ $(TOP)/frameworks/native/include/media/hardware \
+
+LOCAL_MODULE:= libstagefright_codec2
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+
+include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/codec2/C2.cpp b/media/libstagefright/codec2/C2.cpp
new file mode 100644
index 0000000..a51b073
--- /dev/null
+++ b/media/libstagefright/codec2/C2.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#include <C2.h>
+#include <C2Buffer.h>
+#include <C2Component.h>
+#include <C2Config.h>
+#include <C2Param.h>
+#include <C2ParamDef.h>
+#include <C2Work.h>
+
+namespace android {
+
+/**
+ * There is nothing here yet. This library is built to see what symbols and methods get
+ * defined as part of the API include files.
+ *
+ * Going forward, the Codec2 library will contain utility methods that are useful for
+ * Codec2 clients.
+ */
+
+} // namespace android
+
diff --git a/media/libstagefright/codec2/include/C2.h b/media/libstagefright/codec2/include/C2.h
new file mode 100644
index 0000000..7d00a03
--- /dev/null
+++ b/media/libstagefright/codec2/include/C2.h
@@ -0,0 +1,287 @@
+/*
+ * 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 <string>
+#include <vector>
+#include <list>
+
+#ifdef __ANDROID__
+
+#include <utils/Errors.h> // for status_t
+#include <utils/Timers.h> // for nsecs_t
+
+namespace android {
+
+#else
+
+#include <errno.h>
+typedef int64_t nsecs_t;
+
+enum {
+ GRALLOC_USAGE_SW_READ_OFTEN,
+ GRALLOC_USAGE_RENDERSCRIPT,
+ GRALLOC_USAGE_HW_TEXTURE,
+ GRALLOC_USAGE_HW_COMPOSER,
+ GRALLOC_USAGE_HW_VIDEO_ENCODER,
+ GRALLOC_USAGE_PROTECTED,
+ GRALLOC_USAGE_SW_WRITE_OFTEN,
+ GRALLOC_USAGE_HW_RENDER,
+};
+
+#endif
+
+/** \mainpage Codec2
+ *
+ * Codec2 is a frame-based data processing API used by android.
+ *
+ * The framework 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 status_t, with C2_NOT_IMPLEMENTED 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;
+typedef const char *C2StringLiteral;
+
+/**
+ * C2Error: status codes used.
+ */
+typedef int32_t C2Error;
+enum {
+#ifndef __ANDROID__
+ OK = 0,
+ BAD_VALUE = -EINVAL,
+ BAD_INDEX = -EOVERFLOW,
+ UNKNOWN_TRANSACTION = -EBADMSG,
+ ALREADY_EXISTS = -EEXIST,
+ NAME_NOT_FOUND = -ENOENT,
+ INVALID_OPERATION = -ENOSYS,
+ NO_MEMORY = -ENOMEM,
+ PERMISSION_DENIED = -EPERM,
+ TIMED_OUT = -ETIMEDOUT,
+ UNKNOWN_ERROR = -EINVAL,
+#endif
+
+ C2_OK = OK, ///< operation completed successfully
+
+ // bad input
+ C2_BAD_VALUE = BAD_VALUE, ///< argument has invalid value (user error)
+ C2_BAD_INDEX = BAD_INDEX, ///< argument uses invalid index (user error)
+ C2_UNSUPPORTED = UNKNOWN_TRANSACTION, ///< argument/index is value but not supported \todo is this really BAD_INDEX/VALUE?
+
+ // bad sequencing of events
+ C2_DUPLICATE = ALREADY_EXISTS, ///< object already exists
+ C2_NOT_FOUND = NAME_NOT_FOUND, ///< object not found
+ C2_BAD_STATE = INVALID_OPERATION, ///< operation is not permitted in the current state
+
+ // bad environment
+ C2_NO_MEMORY = NO_MEMORY, ///< not enough memory to complete operation
+ C2_NO_PERMISSION = PERMISSION_DENIED, ///< missing permission to complete operation
+ C2_TIMED_OUT = TIMED_OUT, ///< operation did not complete within timeout
+
+ // bad versioning
+ C2_NOT_IMPLEMENTED = UNKNOWN_TRANSACTION, ///< operation is not implemented (optional only) \todo for now reuse error code
+
+ // unknown fatal
+ C2_CORRUPTED = UNKNOWN_ERROR, ///< some unexpected error prevented the operation
+};
+
+/// @}
+
+/// \defgroup utils Utilities
+/// @{
+
+#define C2_DO_NOT_COPY(type, args...) \
+ type args& operator=(const type args&) = delete; \
+ type(const type args&) = delete; \
+
+#define C2_PURE __attribute__((pure))
+#define C2_CONST __attribute__((const))
+#define C2_HIDE __attribute__((visibility("hidden")))
+#define C2_INTERNAL __attribute__((internal_linkage))
+
+#define DEFINE_OTHER_COMPARISON_OPERATORS(type) \
+ inline bool operator!=(const type &other) { return !(*this == other); } \
+ inline bool operator<=(const type &other) { return (*this == other) || (*this < other); } \
+ inline bool operator>=(const type &other) { return !(*this < other); } \
+ inline bool operator>(const type &other) { 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)
+
+/// \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 mintype;
+};
+
+/** 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 mintype;
+};
+
+/// @}
+
+/// \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>::mintype, V...>::mintype mintype;
+};
+
+/**
+ * \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>::mintype 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>::mintype>(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...>::mintype c2_min(const T a, const U b, const V ... c) {
+ typedef typename c2_types<U, V...>::mintype 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>::mintype>(a_ < b_ ? a_ : b_);
+ });
+}
+
+/// @}
+
+#ifdef __ANDROID__
+} // namespace android
+#endif
+
+#endif // C2_H_
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
new file mode 100644
index 0000000..9f6b487
--- /dev/null
+++ b/media/libstagefright/codec2/include/C2Buffer.h
@@ -0,0 +1,1777 @@
+/*
+ * 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 <C2Param.h> // for C2Info
+
+#include <list>
+#include <memory>
+
+typedef int C2Fence;
+
+#ifdef __ANDROID__
+
+// #include <system/window.h>
+#include <cutils/native_handle.h>
+#include <hardware/gralloc.h> // TODO: remove
+
+typedef native_handle_t C2Handle;
+
+#else
+
+typedef void* C2Handle;
+
+#endif
+
+namespace android {
+
+/// \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_NO_PERMISSION no permission to wait for the fence (unexpected - system)
+ * \retval C2_CORRUPTED some unknown error prevented waiting for the fence (unexpected)
+ */
+ C2Error wait(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;
+
+private:
+ class Impl;
+ std::shared_ptr<Impl> mImpl;
+};
+
+/**
+ * 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_ALREADY_EXISTS the fence(s) have already been signaled (caller error)
+ * \retval C2_NO_PERMISSION no permission to signal the fence (unexpected - system)
+ * \retval C2_CORRUPTED some unknown error prevented signaling the fence(s) (unexpected)
+ */
+ C2Error 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_ALREADY_EXISTS the fence have already been merged (caller error)
+ * \retval C2_BAD_STATE the fence have already been signaled or abandoned (caller error)
+ * \retval C2_NO_PERMISSION no permission to merge the fence (unexpected - system)
+ * \retval C2_CORRUPTED some unknown error prevented merging the fence(s) (unexpected)
+ */
+ C2Error 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_ALREADY_EXISTS the fence(s) have already been abandoned (caller error)
+ * \retval C2_NO_PERMISSION no permission to abandon the fence (unexpected - system)
+ * \retval C2_CORRUPTED some unknown error prevented signaling the fence(s) (unexpected)
+ */
+ C2Error abandon();
+
+private:
+ class Impl;
+ std::shared_ptr<Impl> mImpl;
+};
+
+/// \addtogroup buf_internal Internal
+/// @{
+
+/**
+ * Interface for objects that encapsulate an updatable error value.
+ */
+struct _C2InnateError {
+ inline C2Error error() const { return mError; }
+
+protected:
+ _C2InnateError(C2Error error) : mError(error) { }
+
+ C2Error mError; // this error 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();
+
+protected:
+ C2Acquirable(C2Error error, C2Fence fence, T t) : C2Fence(fence), mInitialError(error), mT(t) { }
+
+private:
+ C2Error mInitialError;
+ T mT; // TODO: move instead of copy
+};
+
+/// @}
+
+/// \defgroup linear Linear Data Blocks
+/// @{
+
+/**************************************************************************************************
+ LINEAR ASPECTS, BLOCKS AND VIEWS
+**************************************************************************************************/
+
+/**
+ * Common aspect for all objects that have a linear capacity.
+ */
+class _C2LinearCapacityAspect {
+/// \name Linear capacity interface
+/// @{
+public:
+ inline uint32_t capacity() const { return 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 _C2LinearCapacityAspect(uint32_t capacity)
+ : mCapacity(capacity) { }
+
+ inline explicit _C2LinearCapacityAspect(const _C2LinearCapacityAspect *parent)
+ : mCapacity(parent == nullptr ? 0 : parent->capacity()) { }
+
+private:
+ const uint32_t mCapacity;
+/// @}
+};
+
+/**
+ * Aspect for objects that have a linear range.
+ *
+ * This class is copiable.
+ */
+class _C2LinearRangeAspect : public _C2LinearCapacityAspect {
+/// \name Linear range interface
+/// @{
+public:
+ inline uint32_t offset() const { return mOffset; }
+ inline uint32_t size() const { return mSize; }
+
+protected:
+ inline explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
+ : _C2LinearCapacityAspect(parent),
+ mOffset(0),
+ mSize(capacity()) { }
+
+ inline _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 two [offset, offset + size] ranges
+ inline _C2LinearRangeAspect(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
+ : _C2LinearCapacityAspect(parent == nullptr ? 0 : parent->capacity()),
+ mOffset(c2_min(c2_max(offset, parent == nullptr ? 0 : parent->offset()), capacity())),
+ mSize(c2_min(c2_min(size, parent == nullptr ? 0 : parent->size()), capacity() - mOffset)) { }
+
+private:
+ friend class _C2EditableLinearRange;
+ // invariants 0 <= mOffset <= mOffset + mSize <= capacity()
+ uint32_t mOffset;
+ uint32_t mSize;
+/// @}
+};
+
+/**
+ * Aspect for objects that have an editable linear range.
+ *
+ * This class is copiable.
+ */
+class _C2EditableLinearRange : public _C2LinearRangeAspect {
+protected:
+ inline explicit _C2EditableLinearRange(const _C2LinearCapacityAspect *parent)
+ : _C2LinearRangeAspect(parent) { }
+
+ inline _C2EditableLinearRange(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
+ : _C2LinearRangeAspect(parent, offset, size) { }
+
+ // subsection of the two [offset, offset + size] ranges
+ inline _C2EditableLinearRange(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
+ : _C2LinearRangeAspect(parent, offset, size) { }
+
+/// \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) {
+ if (offset > capacity()) {
+ offset = capacity();
+ }
+ if (offset > mOffset + mSize) {
+ mSize = 0;
+ } else {
+ mSize = mOffset + mSize - offset;
+ }
+ mOffset = offset;
+ }
+ /**
+ * 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 = std::min(size, capacity() - mOffset);
+ }
+/// @}
+};
+
+// ================================================================================================
+// BLOCKS
+// ================================================================================================
+
+/**
+ * Blocks are sections of allocations. They can be either 1D or 2D.
+ */
+
+class C2LinearAllocation;
+
+class C2Block1D : public _C2LinearRangeAspect {
+public:
+ const C2Handle *handle() const;
+
+protected:
+ C2Block1D(std::shared_ptr<C2LinearAllocation> alloc);
+ C2Block1D(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+
+private:
+ class Impl;
+ 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.
+ */
+ const uint8_t *data();
+
+ /**
+ * 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.
+ */
+ C2Error error();
+
+private:
+ class Impl;
+ std::shared_ptr<Impl> mImpl;
+};
+
+/**
+ * Write view provides read/write access for a linear memory segment.
+ *
+ * This class is copiable. \todo movable only?
+ */
+class C2WriteView : public _C2EditableLinearRange {
+public:
+ /**
+ * Start of the block.
+ *
+ * \return pointer to the start of the block or nullptr on error.
+ */
+ uint8_t *base();
+
+ /**
+ * \return pointer to the block at the current offset or nullptr on error.
+ */
+ uint8_t *data();
+
+ /**
+ * \return error during the creation/mapping of this view.
+ */
+ C2Error error();
+
+private:
+ class Impl;
+ /// \todo should this be unique_ptr to make this movable only - to avoid inconsistent regions
+ /// between copies.
+ 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; }
+
+private:
+ 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);
+};
+
+/// @}
+
+/**************************************************************************************************
+ 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)
+ */
+ C2Error 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)
+ */
+ C2Error 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 list 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)
+ */
+ C2Error share(size_t size, C2Fence fence, std::list<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.
+ */
+ C2Error error();
+};
+
+/**
+ * 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)
+ */
+ C2Error 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
+/// @{
+
+/**
+ * Interface for objects that have a width and height (planar capacity).
+ */
+class _C2PlanarCapacityAspect {
+/// \name Planar capacity interface
+/// @{
+public:
+ inline uint32_t width() const { return mWidth; }
+ inline uint32_t height() const { return mHeight; }
+
+protected:
+ inline _C2PlanarCapacityAspect(uint32_t width, uint32_t height)
+ : mWidth(width), mHeight(height) { }
+
+ inline _C2PlanarCapacityAspect(const _C2PlanarCapacityAspect *parent)
+ : mWidth(parent == nullptr ? 0 : parent->width()),
+ mHeight(parent == nullptr ? 0 : parent->height()) { }
+
+private:
+ const uint32_t mWidth;
+ const uint32_t mHeight;
+/// @}
+};
+
+/**
+ * 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 mLeft;
+ uint32_t mTop;
+ uint32_t mWidth;
+ uint32_t mHeight;
+
+ inline C2Rect(uint32_t width, uint32_t height)
+ : C2Rect(width, height, 0, 0) { }
+
+ inline C2Rect(uint32_t width, uint32_t height, uint32_t left, uint32_t top)
+ : mLeft(left), mTop(top), mWidth(width), mHeight(height) { }
+
+ // utility methods
+
+ inline bool isEmpty() const {
+ return mWidth == 0 || mHeight == 0;
+ }
+
+ inline bool isValid() const {
+ return mLeft <= ~mWidth && mTop <= ~mHeight;
+ }
+
+ inline operator bool() const {
+ return isValid() && !isEmpty();
+ }
+
+ inline bool operator!() const {
+ return !bool(*this);
+ }
+
+ inline bool contains(const C2Rect &other) const {
+ if (!isValid() || !other.isValid()) {
+ return false;
+ } else if (other.isEmpty()) {
+ return true;
+ } else {
+ return mLeft <= other.mLeft && mTop <= other.mTop
+ && mLeft + mWidth >= other.mLeft + other.mWidth
+ && mTop + mHeight >= other.mTop + other.mHeight;
+ }
+ }
+
+ inline bool operator==(const C2Rect &other) const {
+ if (!isValid()) {
+ return !other.isValid();
+ } else if (isEmpty()) {
+ return other.isEmpty();
+ } else {
+ return mLeft == other.mLeft && mTop == other.mTop
+ && mWidth == other.mWidth && mHeight == other.mHeight;
+ }
+ }
+
+ inline bool operator!=(const C2Rect &other) const {
+ return !operator==(other);
+ }
+
+ inline bool operator>=(const C2Rect &other) const {
+ return contains(other);
+ }
+
+ inline bool operator>(const C2Rect &other) const {
+ return contains(other) && !operator==(other);
+ }
+
+ inline bool operator<=(const C2Rect &other) const {
+ return other.contains(*this);
+ }
+
+ inline bool operator<(const C2Rect &other) const {
+ return other.contains(*this) && !operator==(other);
+ }
+};
+
+/**
+ * C2PlaneInfo: information on the layout of flexible planes.
+ *
+ * Public fields without getters/setters.
+ */
+struct C2PlaneInfo {
+// public:
+ enum Channel : uint32_t {
+ Y,
+ R,
+ G,
+ B,
+ A,
+ Cr,
+ Cb,
+ } mChannel;
+
+ int32_t mColInc; // column increment in bytes. may be negative
+ int32_t mRowInc; // row increment in bytes. may be negative
+ uint32_t mHorizSubsampling; // subsampling compared to width
+ uint32_t mVertSubsampling; // subsampling compared to height
+
+ uint32_t mBitDepth;
+ uint32_t mAllocatedDepth;
+
+ inline ssize_t minOffset(uint32_t width, uint32_t height) {
+ ssize_t offs = 0;
+ if (width > 0 && mColInc < 0) {
+ offs += mColInc * (ssize_t)(width - 1);
+ }
+ if (height > 0 && mRowInc < 0) {
+ offs += mRowInc * (ssize_t)(height - 1);
+ }
+ return offs;
+ }
+
+ inline ssize_t maxOffset(uint32_t width, uint32_t height, uint32_t allocatedDepth) {
+ ssize_t offs = (allocatedDepth + 7) >> 3;
+ if (width > 0 && mColInc > 0) {
+ offs += mColInc * (ssize_t)(width - 1);
+ }
+ if (height > 0 && mRowInc > 0) {
+ offs += mRowInc * (ssize_t)(height - 1);
+ }
+ return offs;
+ }
+};
+
+struct C2PlaneLayout {
+public:
+ enum Type : uint32_t {
+ MEDIA_IMAGE_TYPE_UNKNOWN = 0,
+ MEDIA_IMAGE_TYPE_YUV = 0x100,
+ MEDIA_IMAGE_TYPE_YUVA,
+ MEDIA_IMAGE_TYPE_RGB,
+ MEDIA_IMAGE_TYPE_RGBA,
+ };
+
+ Type mType;
+ uint32_t mNumPlanes; // number of planes
+
+ enum PlaneIndex : uint32_t {
+ Y = 0,
+ U = 1,
+ V = 2,
+ R = 0,
+ G = 1,
+ B = 2,
+ A = 3,
+ MAX_NUM_PLANES = 4,
+ };
+
+ C2PlaneInfo mPlanes[MAX_NUM_PLANES];
+};
+
+/**
+ * Aspect for objects that have a planar section (crop rectangle).
+ *
+ * This class is copiable.
+ */
+class _C2PlanarSection : public _C2PlanarCapacityAspect {
+/// \name Planar section interface
+/// @{
+public:
+ // crop can be an empty rect, does not have to line up with subsampling
+ // NOTE: we do not support floating-point crop
+ inline const C2Rect crop() { return mCrop; }
+
+ /**
+ * Sets crop to crop intersected with [(0,0) .. (width, height)]
+ */
+ inline void setCrop_be(const C2Rect &crop);
+
+ /**
+ * 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);
+
+private:
+ C2Rect mCrop;
+/// @}
+};
+
+class C2Block2D : public _C2PlanarSection {
+public:
+ const C2Handle *handle() const;
+
+private:
+ class Impl;
+ 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 _C2PlanarSection {
+public:
+ /**
+ * \return pointer to the start of the block or nullptr on error.
+ */
+ const uint8_t *data() const;
+
+ /**
+ * \return pointer to the start of the block or nullptr on error.
+ */
+ uint8_t *data();
+
+ /**
+ * 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.
+ */
+ C2Error error() const;
+
+private:
+ class Impl;
+ 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; }
+
+private:
+ 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);
+};
+
+/// @}
+
+/// \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 : uint32_t {
+ 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
+ };
+
+ /**
+ * Gets the type of this buffer (data).
+ * \return the type of this buffer data.
+ */
+ Type 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::list<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::list<C2ConstGraphicBlock> graphicBlocks() const;
+
+private:
+ class Impl;
+ std::shared_ptr<Impl> mImpl;
+
+protected:
+ // no public constructor
+ // C2BufferData(const std::shared_ptr<const Impl> &impl) : mImpl(impl) {}
+};
+
+/**
+ * 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)
+ */
+ C2Error 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)
+ */
+ C2Error 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::list<std::shared_ptr<const C2Info>> infos() 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).
+ */
+ C2Error 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;
+ std::shared_ptr<C2Info> removeInfo(C2Param::Type index) const;
+ ///@}
+
+protected:
+ // no public constructor
+ inline C2Buffer() = default;
+
+private:
+// 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;
+};
+
+/// @}
+
+/**************************************************************************************************
+ ALLOCATIONS
+**************************************************************************************************/
+
+/// \defgroup allocator Allocation and memory placement
+/// @{
+
+/**
+ * Buffer/memory usage bits. These are used by the allocators to select optimal memory type/pool and
+ * buffer layout.
+ *
+ * \note This struct has public fields without getters/setters. All methods are inline.
+ */
+struct C2MemoryUsage {
+// public:
+ // TODO: match these to gralloc1.h
+ enum Consumer : uint64_t {
+ kSoftwareRead = GRALLOC_USAGE_SW_READ_OFTEN,
+ kRenderScriptRead = GRALLOC_USAGE_RENDERSCRIPT,
+ kTextureRead = GRALLOC_USAGE_HW_TEXTURE,
+ kHardwareComposer = GRALLOC_USAGE_HW_COMPOSER,
+ kHardwareEncoder = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+ kProtectedRead = GRALLOC_USAGE_PROTECTED,
+ };
+
+ enum Producer : uint64_t {
+ kSoftwareWrite = GRALLOC_USAGE_SW_WRITE_OFTEN,
+ kRenderScriptWrite = GRALLOC_USAGE_RENDERSCRIPT,
+ kTextureWrite = GRALLOC_USAGE_HW_RENDER,
+ kCompositionTarget = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER,
+ kHardwareDecoder = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+ kProtectedWrite = GRALLOC_USAGE_PROTECTED,
+ };
+
+ uint64_t mConsumer; // e.g. input
+ uint64_t mProducer; // e.g. output
+};
+
+/**
+ * \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.
+ * |fenceFd| is a file descriptor referring to an acquire sync fence object. If it is already
+ * safe to access the buffer contents, then -1.
+ *
+ * \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 fenceFd a pointer to a file descriptor if an async mapping is requested. If
+ * not-null, and acquire fence FD will be stored here on success, or -1
+ * 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_NO_PERMISSION no permission to map the portion
+ * \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 (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 C2Error map(
+ size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd /* nullable */,
+ void **addr /* nonnull */) = 0;
+
+ /**
+ * Unmaps a portion of an allocation at |addr| with |size|. These must be parameters previously
+ * passed to |map|; otherwise, this operation is a no-op.
+ *
+ * \param addr starting address of the mapped region
+ * \param size size of the mapped region
+ * \param fenceFd a pointer to a file descriptor if an async unmapping is requested. If
+ * not-null, a release fence FD will be stored here on success, or -1
+ * on failure. This fence signals when the original allocation contains
+ * any 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_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_NO_PERMISSION no permission to unmap the portion (unexpected - system)
+ */
+ virtual C2Error unmap(void *addr, size_t size, int *fenceFd /* nullable */) = 0;
+
+ /**
+ * Returns true if this is a valid allocation.
+ *
+ * \todo remove?
+ */
+ virtual bool isValid() 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;
+};
+
+/**
+ * \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. |fenceFd| is a file
+ * descriptor referring to an acquire sync fence object. If it is already safe to access the
+ * buffer contents, then -1.
+ *
+ * \note Only one portion of the graphic allocation can be mapped at the same time. (This is
+ * from gralloc1 limitation.)
+ *
+ * \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 fenceFd a pointer to a file descriptor if an async mapping is requested. If
+ * not-null, and acquire fence FD will be stored here on success, or -1
+ * 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.
+ *
+ * \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_NO_PERMISSION no permission to map the section
+ * \retval C2_ALREADY_EXISTS there is already a mapped region (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 C2Error map(
+ C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+ // TODO: return <addr, size> buffers with plane sizes
+ C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
+
+ /**
+ * Unmaps the last mapped rectangular section.
+ *
+ * \param fenceFd a pointer to a file descriptor if an async unmapping is requested. If
+ * not-null, a release fence FD will be stored here on success, or -1
+ * on failure. This fence signals when the original allocation contains
+ * any 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 mapped region (caller error)
+ * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+ * \retval C2_NO_PERMISSION no permission to unmap the section (unexpected - system)
+ */
+ virtual C2Error unmap(C2Fence *fenceFd /* nullable */) = 0;
+
+ /**
+ * Returns true if this is a valid allocation.
+ *
+ * \todo remove?
+ */
+ virtual bool isValid() 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) = 0;
+
+protected:
+ virtual ~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:
+ /**
+ * 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_NO_PERMISSION no permission to complete the allocation
+ * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+ * \retval C2_UNSUPPORTED this allocator does not support 1D allocations
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ */
+ virtual C2Error allocateLinearBuffer(
+ uint32_t capacity __unused, C2MemoryUsage usage __unused,
+ std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
+ *allocation = nullptr;
+ return C2_UNSUPPORTED;
+ }
+
+ /**
+ * (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
+ * \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_NO_PERMISSION no permission to recreate the allocation
+ * \retval C2_BAD_VALUE invalid handle (caller error)
+ * \retval C2_UNSUPPORTED this allocator does not support 1D allocations
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ */
+ virtual C2Error recreateLinearBuffer(
+ const C2Handle *handle __unused,
+ std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
+ *allocation = nullptr;
+ return C2_UNSUPPORTED;
+ }
+
+ /**
+ * 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_NO_PERMISSION no permission to complete the allocation
+ * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
+ * \retval C2_UNSUPPORTED this allocator does not support 2D allocations
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ */
+ virtual C2Error allocateGraphicBuffer(
+ 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_UNSUPPORTED;
+ }
+
+ /**
+ * (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
+ * \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_NO_PERMISSION no permission to recreate the allocation
+ * \retval C2_BAD_VALUE invalid handle (caller error)
+ * \retval C2_UNSUPPORTED this allocator does not support 2D allocations
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected)
+ */
+ virtual C2Error recreateGraphicBuffer(
+ const C2Handle *handle __unused,
+ std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
+ *allocation = nullptr;
+ return C2_UNSUPPORTED;
+ }
+
+protected:
+ C2Allocator() = default;
+
+ virtual ~C2Allocator() = default;
+};
+
+/**
+ * Block allocators are used by components to allocate memory for output buffers. They can
+ * support either linear (1D), circular (1D) or graphic (2D) allocations.
+ *
+ * Never constructed on stack.
+ *
+ * Block allocators are provided by the framework.
+ */
+class C2BlockAllocator {
+public:
+ /**
+ * Allocates 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 allocation. \note that the
+ * returned allocation may be later used/mapped with different usage.
+ * The allocator shall lay out 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 block pointer to where the allocated block 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_NO_PERMISSION no permission to complete the allocation
+ * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+ * \retval C2_UNSUPPORTED this allocator does not support linear allocations
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ */
+ virtual C2Error allocateLinearBlock(
+ uint32_t capacity __unused, C2MemoryUsage usage __unused,
+ std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+ *block = nullptr;
+ return C2_UNSUPPORTED;
+ }
+
+ /**
+ * Allocates 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. (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 shall lay out 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 block pointer to where the allocated block 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_NO_PERMISSION no permission to complete the allocation
+ * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+ * \retval C2_UNSUPPORTED this allocator does not support circular allocations
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ */
+ virtual C2Error allocateCircularBlock(
+ uint32_t capacity __unused, C2MemoryUsage usage __unused,
+ std::shared_ptr<C2CircularBlock> *block /* nonnull */) {
+ *block = nullptr;
+ return C2_UNSUPPORTED;
+ }
+
+ /**
+ * Allocates a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
+ * the allocation is stored in |block|. Otherwise, |block| 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 block 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_NO_PERMISSION no permission to complete the allocation
+ * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
+ * \retval C2_UNSUPPORTED this allocator does not support 2D allocations
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ */
+ virtual C2Error allocateGraphicBlock(
+ 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_UNSUPPORTED;
+ }
+
+protected:
+ C2BlockAllocator() = default;
+
+ virtual ~C2BlockAllocator() = default;
+};
+
+/// @}
+
+/// \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
+
+/// @}
+
+} // namespace android
+
+#endif // C2BUFFER_H_
diff --git a/media/libstagefright/codec2/include/C2Component.h b/media/libstagefright/codec2/include/C2Component.h
new file mode 100644
index 0000000..1ee9302
--- /dev/null
+++ b/media/libstagefright/codec2/include/C2Component.h
@@ -0,0 +1,685 @@
+/*
+ * 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 <C2Param.h>
+#include <C2Work.h>
+
+namespace android {
+
+/// \defgroup components Components
+/// @{
+
+class C2Component;
+
+class C2ComponentListener {
+public:
+ virtual void onWorkDone(std::weak_ptr<C2Component> component,
+ std::vector<std::unique_ptr<C2Work>> workItems) = 0;
+
+ virtual void onTripped(std::weak_ptr<C2Component> component,
+ std::vector<std::shared_ptr<C2SettingResult>> settingResult) = 0;
+
+ virtual void onError(std::weak_ptr<C2Component> component,
+ uint32_t errorCode) = 0;
+
+ // virtual void onTunnelReleased(<from>, <to>) = 0;
+
+ // virtual void onComponentReleased(<id>) = 0;
+
+protected:
+ virtual ~C2ComponentListener();
+};
+
+/**
+ * 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.
+ *
+ * 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;
+
+ /**
+ * Returns a unique ID for this component or interface object.
+ * This ID is used as work targets, unique work IDs, and when configuring tunneling.
+ *
+ * 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 a unique node ID for this component or component interface instance.
+ */
+ virtual node_id 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, 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.
+ *
+ * \todo This method cannot be used to query info-buffers. Is that a problem?
+ *
+ * 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.
+ *
+ * \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[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_NO_MEMORY could not allocate memory for a supported parameter
+ * \retval C2_CORRUPTED some unknown error prevented the querying of the parameters
+ * (unexpected)
+ */
+ virtual status_t query_nb(
+ const std::vector<C2Param* const> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ 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 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 MUST be supported in any state.
+ *
+ * This method MUST be "non-blocking" and return within 1ms.
+ *
+ * \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[out] 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 status_t config_nb(
+ const std::vector<C2Param* const> ¶ms,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+
+ /**
+ * Atomically sets a set of parameters for the component or interface object.
+ *
+ * \note This method is used mainly for reserving resources for a component.
+ *
+ * The component SHALL update all supported configuration at
+ * best effort(TBD) (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 MUST be supported in any state.
+ *
+ * This method may be momentarily blocking, but MUST return within 5ms.
+ *
+ * \param params[in,out] 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[out] 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 status_t commit_sm(
+ const std::vector<C2Param* const> ¶ms,
+ 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.
+ *
+ * This method MUST be supported in any state.
+ *
+ * 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_ALREADY_EXIST the tunnel already exists
+ * \retval C2_UNSUPPORTED the tunnel is not supported
+ *
+ * \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)
+ */
+ virtual status_t createTunnel_sm(node_id 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.
+ *
+ * This method MUST be supported in any state.
+ *
+ * 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_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)
+ */
+ virtual status_t releaseTunnel_sm(node_id targetComponent) = 0;
+
+
+ // REFLECTION MECHANISM (USED FOR EXTENSION)
+ // =============================================================================================
+
+ /**
+ * Returns the parameter reflector.
+ *
+ * This is used to describe parameter fields.
+ *
+ * \return a shared parameter reflector object.
+ */
+ virtual std::shared_ptr<C2ParamReflector> getParamReflector() const = 0;
+
+ /**
+ * Returns the set of supported parameters.
+ *
+ * \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 status_t getSupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const = 0;
+
+ /**
+ *
+ * \todo should this take a list considering that setting some fields may further limit other
+ * fields in the same list?
+ */
+ virtual status_t getSupportedValues(
+ const std::vector<const C2ParamField> fields,
+ std::vector<C2FieldSupportedValues>* const values) const = 0;
+
+ virtual ~C2ComponentInterface() = default;
+};
+
+class C2Component {
+public:
+ // METHODS AVAILABLE WHEN RUNNING
+ // =============================================================================================
+
+ /**
+ * Queues up work for the component.
+ *
+ * This method MUST be supported in running (including tripped) states.
+ *
+ * This method MUST be "non-blocking" and return within 1ms
+ *
+ * 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_UNSUPPORTED the components are not tunneled
+ *
+ * \retval C2_NO_MEMORY not enough memory to queue the work
+ * \retval C2_CORRUPTED some unknown error prevented queuing the work (unexpected)
+ */
+ virtual 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) 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_UNSUPPORTED the componentes are not tunneled
+ *
+ * \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?
+ */
+ virtual status_t announce_nb(const std::vector<C2WorkOutline> &items) = 0;
+
+ /**
+ * 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) 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.
+ *
+ * \param flushThrough flush work from this component and all components connected downstream
+ * from it via tunneling.
+ *
+ * \retval C2_OK the work announcement has been successfully recorded
+ * \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 status_t flush_sm(bool flushThrough, std::list<std::unique_ptr<C2Work>>* const flushedWork) = 0;
+
+ /**
+ * Drains the component, and optionally downstream components
+ *
+ * \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?
+ *
+ * Marks last work item as "end-of-stream", so component is notified not to wait for further
+ * work before it processes work already queued. This method is called 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 drainThrough marks the last work item with a persistent "end-of-stream" marker that
+ * will drain downstream components.
+ *
+ * \todo this may confuse work-ordering downstream; could be an mode enum
+ *
+ * \retval C2_OK the work announcement has been successfully recorded
+ * \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 status_t drain_nb(bool drainThrough) = 0;
+
+ // STATE CHANGE METHODS
+ // =============================================================================================
+
+ /**
+ * Starts the component.
+ *
+ * This method MUST be supported in stopped state.
+ *
+ * \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.
+ *
+ * \todo Could we just start a ComponentInterface to get a Component?
+ *
+ * \retval C2_OK the work announcement has been successfully recorded
+ * \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 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.
+ *
+ * \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.)
+ */
+ virtual status_t stop() = 0;
+
+ /**
+ * Resets the component.
+ *
+ * This method MUST be supported in running (including tripped) state.
+ *
+ * This method MUST be supported during any other call (\todo or just blocking ones?)
+ *
+ * This method MUST return withing 500ms.
+ *
+ * After this call returns all work is/must be abandoned, all references should be released.
+ *
+ * \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.
+ */
+ virtual void reset() = 0;
+
+ /**
+ * Releases the component.
+ *
+ * This method MUST be supported in any state. (\todo Or shall we force reset() first to bring
+ * to a known state?)
+ *
+ * This method MUST return withing 500ms.
+ *
+ * \todo should this return completed work, since client will just free it? Also, if it unblocks
+ * a stop, where should completed work be returned?
+ *
+ * TODO: does it matter if this call has a short time limit? Yes, as upon return all references
+ * shall be abandoned.
+ */
+ virtual void release() = 0;
+
+ /**
+ * Returns the interface for this component.
+ *
+ * \return the component interface
+ */
+ virtual std::shared_ptr<C2ComponentInterface> intf() = 0;
+
+protected:
+ virtual ~C2Component() = default;
+};
+
+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.
+ *
+ * \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 status_t reset() { return C2_OK; }
+
+ virtual status_t parseFrame(C2BufferPack &frame);
+
+ virtual ~C2FrameInfoParser() = default;
+};
+
+struct C2ComponentInfo {
+ // TBD
+
+};
+
+class C2AllocatorStore {
+public:
+ // TBD
+
+ enum Type {
+ LINEAR, ///< basic linear allocator type
+ GRALLOC, ///< basic gralloc allocator type
+ };
+
+ /**
+ * Creates an allocator.
+ *
+ * \param type the type of allocator to create
+ * \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 status_t createAllocator(Type type, std::shared_ptr<C2Allocator>* const allocator) = 0;
+
+ virtual ~C2AllocatorStore() = default;
+};
+
+class C2ComponentStore {
+ /**
+ * 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 status_t createComponent(C2String name, std::shared_ptr<C2Component>* const component);
+
+ /**
+ * 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 status_t createInterface(C2String name, std::shared_ptr<C2ComponentInterface>* const interface);
+
+ /**
+ * Returns the list of components supported by this component store.
+ *
+ * This method SHALL return within 1ms.
+ *
+ * \retval vector of component information.
+ */
+ virtual std::vector<std::unique_ptr<const C2ComponentInfo>> getComponents();
+
+ // -------------------------------------- UTILITY METHODS --------------------------------------
+
+ // on-demand buffer layout conversion (swizzling)
+ virtual status_t copyBuffer(std::shared_ptr<C2GraphicBuffer> src, std::shared_ptr<C2GraphicBuffer> dst);
+
+ // status_t selectPreferredColor(formats<A>, formats<B>);
+
+ // GLOBAL SETTINGS
+ // system-wide stride & slice-height (???)
+
+ /**
+ * 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 MUST be "non-blocking" and return within 1ms.
+ *
+ * \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 status_t query_nb(
+ const std::vector<C2Param* const> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) = 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 MUST be "non-blocking" and return within 1ms.
+ *
+ * \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 status_t config_nb(
+ const std::vector<C2Param* const> ¶ms,
+ std::list<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+
+ virtual ~C2ComponentStore() = default;
+};
+
+// ================================================================================================
+
+/// @}
+
+} // namespace android
+
+#endif // C2COMPONENT_H_
diff --git a/media/libstagefright/codec2/include/C2Config.h b/media/libstagefright/codec2/include/C2Config.h
new file mode 100644
index 0000000..30e9193
--- /dev/null
+++ b/media/libstagefright/codec2/include/C2Config.h
@@ -0,0 +1,251 @@
+/*
+ * 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 <C2ParamDef.h>
+
+namespace android {
+
+/// \defgroup config Component configuration
+/// @{
+
+#ifndef DEFINE_C2_ENUM_VALUE_AUTO_HELPER
+#define DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, ...)
+#define DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, type, names, ...)
+#endif
+
+#define C2ENUM(name, type, ...) \
+enum name : type { __VA_ARGS__ }; \
+DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, NULL, __VA_ARGS__)
+
+#define C2ENUM_CUSTOM_PREFIX(name, type, prefix, ...) \
+enum name : type { __VA_ARGS__ }; \
+DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, __VA_ARGS__)
+
+#define C2ENUM_CUSTOM_NAMES(name, type, names, ...) \
+enum name : type { __VA_ARGS__ }; \
+DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, type, names, __VA_ARGS__)
+
+enum C2ParamIndexKind : uint32_t {
+ /// domain
+ kParamIndexDomain,
+
+ /// configuration descriptors
+ kParamIndexSupportedParams,
+ kParamIndexRequiredParams,
+ kParamIndexReadOnlyParams,
+ kParamIndexRequestedInfos,
+
+ /// latency
+ kParamIndexLatency,
+
+ // generic time behavior
+ kParamIndexTemporal,
+
+ /// port configuration
+ kParamIndexMime,
+ kParamIndexStreamCount,
+ kParamIndexFormat,
+
+ // video info
+
+ kParamIndexStructStart = 0x1,
+ kParamIndexVideoSize,
+ kParamIndexMaxVideoSizeHint,
+
+ kParamIndexParamStart = 0x800,
+};
+
+C2ENUM(C2DomainKind, int32_t,
+ C2DomainVideo,
+ C2DomainAudio,
+ C2DomainOther = C2DomainAudio + 1
+);
+
+// read-only
+
+typedef C2GlobalParam<C2Info, C2SimpleValueStruct<C2DomainKind>, kParamIndexDomain> C2ComponentDomainInfo;
+// typedef C2GlobalParam<C2Info, C2Uint32Value, kParamIndexDomain> C2ComponentDomainInfo;
+//DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<C2DomainKind>, { C2FIELD(mValue, "value") });
+
+// read-only
+typedef C2GlobalParam<C2Info, C2Uint32Array, kParamIndexSupportedParams> C2SupportedParamsInfo;
+
+/// \todo do we define it as a param?
+// read-only
+typedef C2GlobalParam<C2Info, C2Uint32Array, kParamIndexRequiredParams> C2RequiredParamsInfo;
+
+// read-only
+typedef C2GlobalParam<C2Info, C2Uint32Array, kParamIndexReadOnlyParams> C2ReadOnlyParamsInfo;
+
+// read-only
+typedef C2GlobalParam<C2Info, C2Uint32Array, kParamIndexRequestedInfos> C2RequestedInfosInfo;
+
+// read-only
+//typedef C2GlobalParam<C2Info, C2Uint32Value, kParamIndexRequestedInfos> C2RequestedInfosInfo;
+
+/// latency
+
+typedef C2PortParam<C2Info, C2Uint32Value, kParamIndexLatency> C2PortLatencyInfo;
+
+typedef C2GlobalParam<C2Info, C2Uint32Value, kParamIndexLatency> C2ComponentLatencyInfo;
+
+/// \todo
+typedef C2GlobalParam<C2Info, C2Uint32Value, kParamIndexTemporal> C2ComponentTemporalInfo;
+
+/// port configuration
+
+typedef C2PortParam<C2Tuning, C2StringValue, kParamIndexMime> C2PortMimeConfig;
+
+typedef C2PortParam<C2Tuning, C2Uint32Value, kParamIndexStreamCount> C2PortStreamCountConfig;
+
+typedef C2StreamParam<C2Tuning, C2StringValue, kParamIndexMime> C2StreamMimeConfig;
+
+C2ENUM(C2FormatKind, uint32_t,
+ C2FormatCompressed,
+ C2FormatAudio = 1,
+ C2FormatVideo = 4,
+)
+
+typedef C2StreamParam<C2Tuning, C2Uint32Value, kParamIndexFormat> C2StreamFormatConfig;
+
+/*
+ Component description fields:
+
+// format (video/compressed/audio/other-do we need other?) per stream
+
+// likely some of these are exposed as separate settings:
+
+struct C2BaseTuning {
+ // latency characteristics
+ uint32_t latency;
+ bool temporal; // seems this only makes sense if latency is 1..., so this could be captured as latency = 0
+ uint32_t delay;
+
+ uint32_t numInputStreams; // RW? - or suggestion only: RO
+ uint32_t numOutputStreams; // RW
+ //
+ // refs characteristics (per stream?)
+ uint32_t maxInputRefs; // RO
+ uint32_t maxOutputRefs; // RO
+ uint32_t maxInputMemory; // RO - max time refs are held for
+ uint32_t maxOutputMemory; // RO
+
+ // per stream
+ bool compressed;
+ // format... video/compressed/audio/other?
+ // actual "audio/video" format type
+ uint32_t width/height? is this needed, or just queue...
+ // mime...
+};
+*/
+
+
+
+
+
+
+// overall component
+// => C: domain: audio or video
+// => C: kind: decoder, encoder or filter
+// => "mime" class
+
+// => C: temporal (bool) => does this depend on ordering?
+// => I: latency
+// => I: history max duration...
+// => I: history max frames kept...
+// => I: reordering depth
+// => I: frc (bool) (perhaps ratio?)
+// => I: current frc
+
+// - pause
+// => last frame 'number' processed
+// => current frame 'number' processed
+// => invalid settings =>[]
+
+// video decoder configuration: // audio
+// - encoding // -encoding
+// - hint: max width/height // -hint: sample rate, channels
+// - hint: profile/level // -hint: tools used
+// - hint: framerate (bitrate?) // -hint: bitrate
+// - default: color space (from container)
+// - hint: color format // -hint: pcm-encoding
+// - hint: # of views (e.g. MVC) // -hint?: channel groups
+// - default: HDR static info (from container) // -hint?: channel mappings
+// - hint: rotation (e.g. for allocator)
+
+// => # of streams required and their formats? (setting?)
+// => # of streams produced and their formats? (tuning)
+
+// => output
+// - # of views // -channel groups && channel mappings
+// - width/height/crop/color format/color space/HDR static info (from buffers)
+// (as required by the allocator & framework)
+// - SEI (or equivalent) <= [port]
+// - CC
+// - reference info
+
+// video encoder configurations
+// - encoding // - encoding
+// - hint: width/height // - hint: sample rate, channels
+// - hint: frame rate
+// - hint: max width/height (? does this differ from width/height?)
+// - # of input (e.g. MVC) // - hint: # groups and mappings
+// - # of output (e.g. SVC) => bitrates/width/height/framerates? per stream
+// - hint: profile/level // - hint: profile/level
+// - HDR static info + (info: HDR)
+// - color space
+// - hint: color format? // - hint: pcm encoding
+// - SEI
+// - CC
+// - reference directive
+// - hint: bitrate (or quality) // - hint: bitrate/quality
+// - optional: codec-specific parameters // - optional: csd
+
+// => output // => output
+// - layers per stream? // E-AC3?... DTS?...Dolby-Vision?
+// - reference info
+
+
+// RM:
+// - need SPS for full knowledge => component should return max. (component can use less)
+// - critical parameters? (interlaced? profile? level?)
+
+struct C2VideoSizeStruct {
+ int32_t mWidth; ///< video width
+ int32_t mHeight; ///< video height
+
+ DEFINE_AND_DESCRIBE_C2STRUCT(VideoSize)
+ C2FIELD(mWidth, "width")
+ C2FIELD(mHeight, "height")
+};
+
+// video size for video decoder [OUT]
+typedef C2StreamParam<C2Info, C2VideoSizeStruct> C2VideoSizeStreamInfo;
+
+// max video size for video decoder [IN]
+typedef C2PortParam<C2Setting, C2VideoSizeStruct, kParamIndexMaxVideoSizeHint> C2MaxVideoSizeHintPortSetting;
+
+// video encoder size [IN]
+typedef C2StreamParam<C2Tuning, C2VideoSizeStruct> C2VideoSizeStreamTuning;
+
+/// @}
+
+} // namespace android
+
+#endif
diff --git a/media/libstagefright/codec2/include/C2Param.h b/media/libstagefright/codec2/include/C2Param.h
new file mode 100644
index 0000000..fd43061
--- /dev/null
+++ b/media/libstagefright/codec2/include/C2Param.h
@@ -0,0 +1,1171 @@
+/*
+ * 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 <list>
+#include <string>
+#include <type_traits>
+
+#define C2_PACK __attribute__((packed))
+
+namespace android {
+
+/// \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
+ *
+ * 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 base 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
+struct _C2ParamManipulator;
+
+/**
+ * Parameter base class.
+ */
+struct C2Param {
+ // param index encompasses the following:
+ //
+ // - type (setting, tuning, info, struct)
+ // - vendor extension flag
+ // - flexible parameter flag
+ // - direction (global, input, output)
+ // - stream flag
+ // - stream ID (usually 0)
+ //
+ // layout:
+ //
+ // +------+-----+---+------+--------+----|------+--------------+
+ // | kind | dir | - |stream|streamID|flex|vendor| base index |
+ // +------+-----+---+------+--------+----+------+--------------+
+ // bit: 31..30 29.28 25 24 .. 17 16 15 14 .. 0
+ //
+public:
+ /**
+ * C2Param kinds, usable as bitmaps.
+ */
+ enum Kind : uint32_t {
+ NONE = 0,
+ STRUCT = (1 << 0),
+ INFO = (1 << 1),
+ SETTING = (1 << 2),
+ TUNING = (1 << 3) | SETTING, // tunings are settings
+ };
+
+ /**
+ * base index (including the vendor extension bit) is a global index for
+ * C2 parameter structs. (e.g. the same indices cannot be reused for different
+ * structs for different components).
+ */
+ struct BaseIndex {
+ protected:
+ enum : uint32_t {
+ kTypeMask = 0xC0000000,
+ kTypeStruct = 0x00000000,
+ kTypeTuning = 0x40000000,
+ kTypeSetting = 0x80000000,
+ kTypeInfo = 0xC0000000,
+
+ kDirMask = 0x30000000,
+ kDirGlobal = 0x20000000,
+ kDirUndefined = 0x30000000, // MUST have all bits set
+ kDirInput = 0x00000000,
+ kDirOutput = 0x10000000,
+
+ kStreamFlag = 0x02000000,
+ kStreamIdMask = 0x01FE0000,
+ kStreamIdShift = 17,
+ kStreamIdMax = kStreamIdMask >> kStreamIdShift,
+ kStreamMask = kStreamFlag | kStreamIdMask,
+
+ kFlexibleFlag = 0x00010000,
+ kVendorFlag = 0x00008000,
+ kParamMask = 0x0000FFFF,
+ kBaseMask = kParamMask | kFlexibleFlag,
+ };
+
+ public:
+ enum : uint32_t {
+ kVendorStart = kVendorFlag, ///< vendor structs SHALL start after this
+ _kFlexibleFlag = kFlexibleFlag, // TODO: this is only needed for testing
+ };
+
+ /// constructor/conversion from uint32_t
+ inline BaseIndex(uint32_t index) : mIndex(index) { }
+
+ // no conversion from uint64_t
+ inline BaseIndex(uint64_t index) = delete;
+
+ /// returns true iff this is a vendor extension parameter
+ inline bool isVendor() const { return mIndex & kVendorFlag; }
+
+ /// returns true iff this is a flexible parameter (with variable size)
+ inline bool isFlexible() const { return mIndex & kFlexibleFlag; }
+
+ /// returns the base type: the index for the underlying struct
+ inline unsigned int baseIndex() const { return mIndex & kBaseMask; }
+
+ /// returns the param index for the underlying struct
+ inline unsigned int paramIndex() const { return mIndex & kParamMask; }
+
+ DEFINE_FIELD_BASED_COMPARISON_OPERATORS(BaseIndex, mIndex)
+
+ protected:
+ uint32_t mIndex;
+ };
+
+ /**
+ * type encompasses the parameter kind (tuning, setting, info), whether the
+ * parameter is global, input or output, and whether it is for a stream.
+ */
+ struct Type : public BaseIndex {
+ /// returns true iff this is a global parameter (not for input nor output)
+ inline bool isGlobal() const { return (mIndex & kDirMask) == kDirGlobal; }
+ /// returns true iff this is an input or input stream parameter
+ inline bool forInput() const { return (mIndex & kDirMask) == kDirInput; }
+ /// returns true iff this is an output or output stream parameter
+ inline bool forOutput() const { return (mIndex & kDirMask) == kDirOutput; }
+
+ /// returns true iff this is a stream parameter
+ inline bool forStream() const { return mIndex & kStreamFlag; }
+ /// 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 & (~kStreamIdMask); }
+
+ /// return the kind of this param
+ inline Kind kind() const {
+ switch (mIndex & kTypeMask) {
+ case kTypeStruct: return STRUCT;
+ case kTypeInfo: return INFO;
+ case kTypeSetting: return SETTING;
+ case kTypeTuning: return TUNING;
+ default: return NONE; // should not happen
+ }
+ }
+
+ /// constructor/conversion from uint32_t
+ inline Type(uint32_t index) : BaseIndex(index) { }
+
+ // no conversion from uint64_t
+ inline Type(uint64_t index) = delete;
+
+ private:
+ friend struct C2Param; // for setPort()
+ friend struct C2Tuning; // for kTypeTuning
+ friend struct C2Setting; // for kTypeSetting
+ friend struct C2Info; // for kTypeInfo
+ // for kDirGlobal
+ 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 & ~kDirMask) | (output ? kDirOutput : kDirInput);
+ 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) { }
+
+ // 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;
+ }
+
+ 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() < kStreamIdMax : rawStream() == 0)
+ && (mIndex & kDirMask) != kDirUndefined;
+ }
+
+ /// returns the raw stream ID field
+ inline unsigned rawStream() const {
+ return (mIndex & kStreamIdMask) >> kStreamIdShift;
+ }
+
+ /// 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 > kStreamIdMax) {
+ stream = kStreamIdMax;
+ }
+ return (stream << kStreamIdShift) & kStreamIdMask;
+ }
+
+ /**
+ * 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 & ~kStreamIdMask) | makeStreamId(stream);
+ return this->stream() < kStreamIdMax;
+ }
+ 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 uint32_t type() const { return _mIndex.type(); }
+
+ /// returns the kind of this parameter
+ inline Kind 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
+ if (len < sizeof(_mSize) + offsetof(C2Param, _mSize)) {
+ return nullptr;
+ }
+ // _mSize must match length
+ C2Param *param = (C2Param*)addr;
+ if (param->_mSize != len) {
+ return nullptr;
+ }
+ return param;
+ }
+
+#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, _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::kDirMask) ? 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 the base type: the index for the underlying struct (for testing
+ /// as this can be gotten by the baseIndex enum)
+ inline uint32_t _baseIndex() const { return _mIndex.baseIndex(); }
+
+ /// 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 { indexFlags = Type::kTypeSetting };
+};
+
+/**
+ * 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 { indexFlags = Type::kTypeTuning };
+};
+
+/**
+ * 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 { indexFlags = Type::kTypeInfo };
+};
+
+/**
+ * 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 U[type] pointer to the object that contains this field
+ * \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:
+ uint32_t _mOffset; // offset of field
+ uint32_t _mSize; // size of field
+};
+
+/**
+ * Structure uniquely specifying a field in a configuration
+ */
+struct C2ParamField {
+//public:
+ // TODO: fix what this is for T[] (for now size becomes T[1])
+ template<typename S, typename T>
+ inline C2ParamField(S* param, T* offset)
+ : _mIndex(param->index()),
+ _mFieldId(offset) {}
+
+ template<typename R, typename T, typename U>
+ inline C2ParamField(U *p, R T::* pm) : _mIndex(p->type()), _mFieldId(p, pm) { }
+
+ inline bool operator==(const C2ParamField &other) const {
+ return _mIndex == other._mIndex && _mFieldId == other._mFieldId;
+ }
+
+ inline bool operator<(const C2ParamField &other) const {
+ return _mIndex < other._mIndex ||
+ (_mIndex == other._mIndex && _mFieldId < other._mFieldId);
+ }
+
+ DEFINE_OTHER_COMPARISON_OPERATORS(C2ParamField)
+
+private:
+ C2Param::Index _mIndex;
+ _C2FieldId _mFieldId;
+};
+
+/**
+ * A shared (union) representation of numeric values
+ */
+class C2Value {
+public:
+ /// A union of supported primitive types.
+ union Primitive {
+ int32_t i32; ///< int32_t value
+ uint32_t u32; ///< uint32_t value
+ int64_t i64; ///< int64_t value
+ uint64_t u64; ///< uint64_t value
+ float fp; ///< float value
+
+ // constructors - implicit
+ Primitive(int32_t value) : i32(value) { }
+ Primitive(uint32_t value) : u32(value) { }
+ Primitive(int64_t value) : i64(value) { }
+ Primitive(uint64_t value) : u64(value) { }
+ Primitive(float value) : fp(value) { }
+
+ Primitive() : u64(0) { }
+
+ private:
+ friend class C2Value;
+ template<typename T> const T &ref() const;
+ };
+
+ enum Type {
+ NO_INIT,
+ INT32,
+ UINT32,
+ INT64,
+ UINT64,
+ FLOAT,
+ };
+
+ template<typename T> static constexpr Type typeFor();
+
+ // constructors - implicit
+ template<typename T>
+ C2Value(T value) : mType(typeFor<T>()), mValue(value) { }
+
+ C2Value() : mType(NO_INIT) { }
+
+ inline Type 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;
+ }
+
+private:
+ Type mType;
+ Primitive mValue;
+};
+
+template<> const int32_t &C2Value::Primitive::ref<int32_t>() const { return i32; }
+template<> const int64_t &C2Value::Primitive::ref<int64_t>() const { return i64; }
+template<> const uint32_t &C2Value::Primitive::ref<uint32_t>() const { return u32; }
+template<> const uint64_t &C2Value::Primitive::ref<uint64_t>() const { return u64; }
+template<> const float &C2Value::Primitive::ref<float>() const { return fp; }
+
+template<> constexpr C2Value::Type C2Value::typeFor<int32_t>() { return INT32; }
+template<> constexpr C2Value::Type C2Value::typeFor<int64_t>() { return INT64; }
+template<> constexpr C2Value::Type C2Value::typeFor<uint32_t>() { return UINT32; }
+template<> constexpr C2Value::Type C2Value::typeFor<uint64_t>() { return UINT64; }
+template<> constexpr C2Value::Type C2Value::typeFor<float>() { return FLOAT; }
+
+/**
+ * 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 : uint32_t {
+ // primitive types
+ INT32 = C2Value::INT32, ///< 32-bit signed integer
+ UINT32 = C2Value::UINT32, ///< 32-bit unsigned integer
+ INT64 = C2Value::INT64, ///< 64-bit signed integer
+ UINT64 = C2Value::UINT64, ///< 64-bit signed integer
+ 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 = 0x10000, ///< structs. Marked with this flag in addition to their baseIndex.
+ };
+
+ typedef std::pair<C2String, C2Value::Primitive> named_value_type;
+ typedef std::vector<const named_value_type> named_values_type;
+ //typedef std::pair<std::vector<C2String>, std::vector<C2Value::Primitive>> named_values_type;
+
+ /**
+ * 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 named_values_type namedValuesFor(const B &);
+
+ inline C2FieldDescriptor(uint32_t type, uint32_t length, C2StringLiteral name, size_t offset, size_t size)
+ : _mType((Type)type), _mLength(length), _mName(name), _mFieldId(offset, size) { }
+
+ template<typename T, class B=typename std::remove_extent<T>::type>
+ inline C2FieldDescriptor(const T* offset, const char *name)
+ : _mType(this->getType((B*)nullptr)),
+ _mLength(std::is_array<T>::value ? std::extent<T>::value : 1),
+ _mName(name),
+ _mNamedValues(namedValuesFor(*(B*)0)),
+ _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)),
+ _mLength(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>
+ constexpr inline C2FieldDescriptor(S*, T S::* field, const char *name)
+ : _mType(this->getType((B*)nullptr)),
+ _mLength(std::is_array<T>::value ? std::extent<T>::value : 1),
+ _mName(name),
+ _mFieldId(&(((S*)0)->*field)) {}
+
+ /// returns the type of this field
+ inline Type 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 length() const { return _mLength; }
+ /// returns the name of the field
+ inline C2StringLiteral name() const { return _mName; }
+
+ const named_values_type &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:
+ const Type _mType;
+ const uint32_t _mLength; // 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.
+ const C2StringLiteral _mName;
+ const named_values_type _mNamedValues;
+
+ const _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 getType(int32_t*) { return INT32; }
+ inline static Type getType(uint32_t*) { return UINT32; }
+ inline static Type getType(int64_t*) { return INT64; }
+ inline static Type getType(uint64_t*) { return UINT64; }
+ inline static Type getType(float*) { return FLOAT; }
+ inline static Type getType(char*) { return STRING; }
+ inline static Type getType(uint8_t*) { return BLOB; }
+
+ template<typename T,
+ class=typename std::enable_if<std::is_enum<T>::value>::type>
+ inline static Type getType(T*) {
+ typename std::underlying_type<T>::type underlying(0);
+ return getType(&underlying);
+ }
+
+ // verify C2Struct by having a fieldList and a baseIndex.
+ template<typename T,
+ class=decltype(T::baseIndex + 1), class=decltype(T::fieldList)>
+ inline static Type getType(T*) {
+ static_assert(!std::is_base_of<C2Param, T>::value, "cannot use C2Params as fields");
+ return (Type)(T::baseIndex | STRUCT_FLAG);
+ }
+};
+
+#define DEFINE_NO_NAMED_VALUES_FOR(type) \
+template<> inline C2FieldDescriptor::named_values_type C2FieldDescriptor::namedValuesFor(const type &) { \
+ return named_values_type(); \
+}
+
+// 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(int64_t)
+DEFINE_NO_NAMED_VALUES_FOR(uint64_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 parameter type
+ inline C2Param::BaseIndex baseIndex() const { return _mType.baseIndex(); }
+
+ // Returns the number of fields in this param (not counting any recursive fields).
+ // Must be at least 1 for valid params.
+ inline size_t numFields() const { return _mFields.size(); }
+
+ // Returns the list of immediate fields (not counting any recursive fields).
+ typedef std::vector<const 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 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::baseIndex, T::fieldList) { }
+
+ inline C2StructDescriptor(
+ C2Param::BaseIndex type,
+ std::initializer_list<const C2FieldDescriptor> fields)
+ : _mType(type), _mFields(fields) { }
+
+private:
+ const C2Param::BaseIndex _mType;
+ const std::vector<const 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 _mIsRequired; }
+
+ /**
+ * 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 _mIsPersistent; }
+
+ /// 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 type
+ /// \todo fix this
+ inline C2Param::Type type() const { return _mType; }
+
+ template<typename T>
+ inline C2ParamDescriptor(bool isRequired, C2StringLiteral name, const T*)
+ : _mIsRequired(isRequired),
+ _mIsPersistent(true),
+ _mName(name),
+ _mType(T::typeIndex) { }
+
+ inline C2ParamDescriptor(
+ bool isRequired, C2StringLiteral name, C2Param::Type type)
+ : _mIsRequired(isRequired),
+ _mIsPersistent(true),
+ _mName(name),
+ _mType(type) { }
+
+private:
+ const bool _mIsRequired;
+ const bool _mIsPersistent;
+ const C2String _mName;
+ const C2Param::Type _mType;
+};
+
+/// \ingroup internal
+/// Define a structure without baseIndex.
+#define DEFINE_C2STRUCT_NO_BASE(name) \
+public: \
+ typedef C2##name##Struct _type; /**< type name shorthand */ \
+ const static std::initializer_list<const C2FieldDescriptor> fieldList; /**< structure fields */
+
+/// Define a structure with matching baseIndex.
+#define DEFINE_C2STRUCT(name) \
+public: \
+ enum : uint32_t { baseIndex = kParamIndex##name }; \
+ DEFINE_C2STRUCT_NO_BASE(name)
+
+/// Define a flexible structure with matching baseIndex.
+#define DEFINE_FLEX_C2STRUCT(name, flexMember) \
+public: \
+ FLEX(C2##name##Struct, flexMember) \
+ enum : uint32_t { baseIndex = kParamIndex##name | C2Param::BaseIndex::_kFlexibleFlag }; \
+ DEFINE_C2STRUCT_NO_BASE(name)
+
+/// \ingroup internal
+/// Describe a structure of a templated structure.
+#define DESCRIBE_TEMPLATED_C2STRUCT(strukt, list) \
+ template<> \
+ const std::initializer_list<const C2FieldDescriptor> strukt::fieldList = list;
+
+/// \deprecated
+/// Describe the fields of a structure using an initializer list.
+#define DESCRIBE_C2STRUCT(name, list) \
+ const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = 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 mWidth;
+ * C2VideoWidthStruct() {} // optional default constructor
+ * C2VideoWidthStruct(int32_t _width) : mWidth(_width) {}
+ *
+ * DEFINE_AND_DESCRIBE_C2STRUCT(VideoWidth)
+ * C2FIELD(mWidth, "width")
+ * };
+ * ~~~~~~~~~~~~~
+ *
+ * ~~~~~~~~~~~~~ (.cpp)
+ * struct C2VideoWidthStruct {
+ * int32_t mWidth;
+ * C2VideoWidthStruct() = default; // optional default constructor
+ * C2VideoWidthStruct(int32_t _width) : mWidth(_width) {}
+ *
+ * DEFINE_C2STRUCT(VideoWidth)
+ * } C2_PACK;
+ *
+ * DESCRIBE_C2STRUCT(VideoWidth, {
+ * C2FIELD(mWidth, "width")
+ * })
+ * ~~~~~~~~~~~~~
+ *
+ * For flexible structures (those ending in T[]), use the flexible macros:
+ *
+ * ~~~~~~~~~~~~~ (.cpp)
+ * struct C2VideoFlexWidthsStruct {
+ * int32_t mWidths[];
+ * 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::alloc_unique(size_t, int32_t);
+ * C2VideoFlexWidthsStruct(size_t flexCount, int32_t value) {
+ * for (size_t i = 0; i < flexCount; ++i) {
+ * mWidths[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::alloc_unique(widths);
+ * template<unsigned N>
+ * C2VideoFlexWidthsStruct(size_t flexCount, const int32_t(&init)[N]) {
+ * for (size_t i = 0; i < flexCount; ++i) {
+ * mWidths[i] = init[i];
+ * }
+ * }
+ *
+ * DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(VideoFlexWidths, mWidths)
+ * C2FIELD(mWidths, "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 C2FIELD(member, name) \
+ C2FieldDescriptor(&((_type*)(nullptr))->member, name),
+
+/// \deprecated
+#define C2SOLE_FIELD(member, name) \
+ C2FieldDescriptor(&_type::member, name, 0)
+
+/// Define a structure with matching baseIndex and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_C2STRUCT(name) \
+ DEFINE_C2STRUCT(name) } C2_PACK; \
+ const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = {
+
+/// Define a flexible structure with matching baseIndex and start describing its fields.
+/// This must be at the end of the structure definition.
+#define DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(name, flexMember) \
+ DEFINE_FLEX_C2STRUCT(name, flexMember) } C2_PACK; \
+ const std::initializer_list<const C2FieldDescriptor> C2##name##Struct::fieldList = {
+
+/**
+ * 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] paramIndex the base index of the parameter structure
+ *
+ * \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::BaseIndex paramIndex) = 0;
+
+protected:
+ virtual ~C2ParamReflector() = default;
+};
+
+/**
+ * A useable supported values for a field.
+ *
+ * This can be either a range or a set of values. The range can be linear or geometric with a
+ * clear minimum and maximum value, and can have an optional step size or geometric ratio. Values
+ * can optionally represent flags.
+ *
+ * \note Do not use flags to represent bitfields. Use individual values or separate fields instead.
+ */
+template<typename T>
+struct C2TypedFieldSupportedValues {
+//public:
+ enum Type {
+ 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 type;
+
+ struct {
+ T min;
+ T max;
+ T step;
+ T nom;
+ T denom;
+ } range;
+ std::vector<T> values;
+
+ C2TypedFieldSupportedValues(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} { }
+
+ C2TypedFieldSupportedValues(T min, T max, T nom, T den) :
+ type(RANGE),
+ range{min, max, (T)0, nom, den} { }
+
+ C2TypedFieldSupportedValues(bool flags, std::initializer_list<T> list) :
+ type(flags ? FLAGS : VALUES),
+ values(list) {}
+};
+
+/**
+ * Generic supported values for a field.
+ *
+ * This can be either a range or a set of values. The range can be linear or geometric with a
+ * clear minimum and maximum value, and can have an optional step size or geometric ratio. Values
+ * can optionally represent flags.
+ *
+ * \note Do not use flags to represent bitfields. Use individual values or separate fields instead.
+ */
+struct C2FieldSupportedValues {
+//public:
+ enum Type {
+ 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 type;
+
+ typedef C2Value::Primitive Primitive;
+
+ struct {
+ Primitive min;
+ Primitive max;
+ Primitive step;
+ Primitive nom;
+ Primitive denom;
+ } range;
+ std::vector<Primitive> values;
+
+ 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 nom, T den) :
+ type(RANGE),
+ range{min, max, (T)0, nom, den} { }
+
+ 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);
+ }
+ }
+
+ 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::named_values_type named = C2FieldDescriptor::namedValuesFor(*(T*)0);
+ for (const C2FieldDescriptor::named_value_type &item : named) {
+ values.emplace_back(item.second);
+ }
+ }
+};
+
+/// @}
+
+} // namespace android
+
+#endif // C2PARAM_H_
diff --git a/media/libstagefright/codec2/include/C2ParamDef.h b/media/libstagefright/codec2/include/C2ParamDef.h
new file mode 100644
index 0000000..f369617
--- /dev/null
+++ b/media/libstagefright/codec2/include/C2ParamDef.h
@@ -0,0 +1,901 @@
+/*
+ * 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>
+
+namespace android {
+
+/// \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 __testEQ(int);
+ template<typename>
+ static std::false_type __testEQ(...);
+
+ template<typename S, typename=decltype(S() != S())>
+ static std::true_type __testNE(int);
+ template<typename>
+ static std::false_type __testNE(...);
+};
+
+/**
+ * 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::__testEQ<S>(0))::value
+ || decltype(_C2Comparable_impl::__testNE<S>(0))::value> {
+};
+
+/// Helper class that checks if a type has a baseIndex constant.
+struct C2_HIDE _C2BaseIndexHelper_impl
+{
+ template<typename S, int=S::baseIndex>
+ static std::true_type __testBaseIndex(int);
+ template<typename>
+ static std::false_type __testBaseIndex(...);
+};
+
+/// Helper template that verifies a type's baseIndex and creates it if the type does not have one.
+template<typename S, int BaseIndex,
+ bool HasBase=decltype(_C2BaseIndexHelper_impl::__testBaseIndex<S>(0))::value>
+struct C2_HIDE C2BaseIndexOverride {
+ // TODO: what if we allow structs without baseIndex?
+ static_assert(BaseIndex == S::baseIndex, "baseIndex differs from structure");
+};
+
+/// Specialization for types without a baseIndex.
+template<typename S, int BaseIndex>
+struct C2_HIDE C2BaseIndexOverride<S, BaseIndex, false> {
+public:
+ enum : uint32_t {
+ baseIndex = BaseIndex, ///< baseIndex override.
+ };
+};
+
+/// Helper template that adds a baseIndex to a type if it does not have one.
+template<typename S, int BaseIndex>
+struct C2_HIDE C2AddBaseIndex : public S, public C2BaseIndexOverride<S, BaseIndex> {};
+
+/**
+ * \brief Helper class to check struct requirements for parameters.
+ *
+ * Features:
+ * - verify default constructor, no virtual methods, and no equality operators.
+ * - expose typeIndex, and non-flex flexSize.
+ */
+template<typename S, int BaseIndex, unsigned TypeIndex>
+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 {
+ typeIndex = BaseIndex | TypeIndex
+ };
+
+protected:
+ enum : uint32_t {
+ flexSize = 0, // TODO: is this still needed? this may be confusing.
+ };
+};
+
+/// Helper class that checks if a type has an integer flexSize member.
+struct C2_HIDE _C2Flexible_impl {
+ /// specialization for types that have a flexSize member
+ template<typename S, unsigned=S::flexSize>
+ static std::true_type __testFlexSize(int);
+ template<typename>
+ static std::false_type __testFlexSize(...);
+};
+
+/// Helper template that returns if a type has an integer flexSize 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 flexSize 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
+
+/// 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 { flexSize = 0 };
+};
+
+/// Specialization for flexible types.
+template<typename S>
+struct C2_HIDE _C2FlexHelper<S,
+ typename std::enable_if<!std::is_void<typename S::flexMemberType>::value>::type> {
+ typedef typename _C2FlexHelper<typename S::flexMemberType>::flexType flexType;
+ enum : uint32_t { flexSize = _C2FlexHelper<typename S::flexMemberType>::flexSize };
+};
+
+/// 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 { flexSize = sizeof(S) };
+};
+
+/**
+ * \brief Helper class to check flexible struct requirements and add common operations.
+ *
+ * Features:
+ * - expose baseIndex 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 BaseIndex, unsigned TypeIndex>
+struct C2_HIDE C2FlexStructCheck : public C2StructCheck<S, BaseIndex, TypeIndex> {
+public:
+ enum : uint32_t {
+ /// \hideinitializer
+ baseIndex = BaseIndex | C2Param::BaseIndex::_kFlexibleFlag, ///< flexible struct base-index
+ };
+
+ const static std::initializer_list<const C2FieldDescriptor> fieldList; // TODO assign here
+
+ // default constructor needed because of the disabled copy constructor
+ inline C2FlexStructCheck() = default;
+
+protected:
+ // cannot copy flexible params
+ C2FlexStructCheck(const C2FlexStructCheck<S, BaseIndex, TypeIndex> &) = delete;
+ C2FlexStructCheck& operator= (const C2FlexStructCheck<S, BaseIndex, TypeIndex> &) = delete;
+
+ // constants used for helper methods
+ enum : uint32_t {
+ /// \hideinitializer
+ flexSize = _C2FlexHelper<S>::flexSize, ///< size of flexible type
+ /// \hideinitializer
+ maxSize = (uint32_t)std::min((size_t)UINT32_MAX, SIZE_MAX), // TODO: is this always u32 max?
+ /// \hideinitializer
+ baseSize = 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 = baseSize) {
+ if (flexCount <= (maxSize - size) / S::flexSize) {
+ return size + S::flexSize * 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 == baseSize);
+ size = calcSize(flexCount, size);
+ if (size > 0) {
+ return ::operator new(size);
+ }
+ return nullptr;
+ }
+};
+
+// TODO: this probably does not work.
+/// Expose fieldList from subClass;
+template<typename S, int BaseIndex, unsigned TypeIndex>
+const std::initializer_list<const C2FieldDescriptor> C2FlexStructCheck<S, BaseIndex, TypeIndex>::fieldList = S::fieldList;
+
+/// 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::typeIndex, _type::flexSize, \
+ (_type::typeIndex & T::Index::kDirUndefined) != T::Index::kDirUndefined); \
+ } \
+ 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 (alloc_shared or alloc_unique) for flexible params.
+ * - P::alloc_xyz(flexCount, args...): allocate for given flex-count.
+ * - P::alloc_xyz(args..., T[]): allocate for size of (and with) init array.
+ * - P::alloc_xyz(T[]): allocate for size of (and with) init array with no other args.
+ * - P::alloc_xyz(args..., std::initializer_list<T>): allocate for size of (and with) initializer
+ * list.
+ */
+#define DEFINE_FLEXIBLE_ALLOC(_type, S, 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...)); \
+ } \
+ /* NOTE: unfortunately this is not supported by clang yet */ \
+ template<typename ...Args, typename U=typename S::flexType, unsigned N> \
+ inline static std::ptr##_ptr<_type> alloc_##ptr(const Args(&... args), const U(&init)[N]) { \
+ return std::ptr##_ptr<_type>(new(N) _type(N, args..., init)); \
+ } \
+ /* so for now, specialize for no args */ \
+ template<typename U=typename S::flexType, unsigned N> \
+ inline static std::ptr##_ptr<_type> alloc_##ptr(const U(&init)[N]) { \
+ return std::ptr##_ptr<_type>(new(N) _type(N, init)); \
+ } \
+ template<typename ...Args, typename U=typename S::flexType> \
+ inline static std::ptr##_ptr<_type> alloc_##ptr( \
+ const Args(&... args), const std::initializer_list<U> &init) { \
+ return std::ptr##_ptr<_type>(new(init.size()) _type(init.size(), args..., init)); \
+ } \
+
+/**
+ * Define flexible methods alloc_shared, alloc_unique and flexCount.
+ */
+#define DEFINE_FLEXIBLE_METHODS(_type, S) \
+ DEFINE_FLEXIBLE_ALLOC(_type, S, shared) \
+ DEFINE_FLEXIBLE_ALLOC(_type, S, unique) \
+ inline size_t flexCount() const { \
+ static_assert(sizeof(_type) == _type::baseSize, "incorrect baseSize"); \
+ size_t sz = this->size(); \
+ if (sz >= sizeof(_type)) { \
+ return (sz - sizeof(_type)) / _type::flexSize; \
+ } \
+ return 0; \
+ } \
+
+/// Mark flexible member variable and make structure flexible.
+#define FLEX(cls, m) \
+ C2_DO_NOT_COPY(cls) \
+private: \
+ C2PARAM_MAKE_FRIENDS \
+ /* default constructor with flexCount */ \
+ inline cls(size_t) : cls() {} \
+ /** \if 0 */ \
+ template<typename, typename> friend struct _C2FlexHelper; \
+ typedef decltype(m) flexMemberType; \
+public: \
+ /* 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 { flexSize = _C2FlexHelper<flexMemberType>::flexSize }; \
+ /** \endif */ \
+
+/// @}
+
+/**
+ * Global-parameter template.
+ *
+ * Base template to define a global setting/tuning or info based on a structure and
+ * an optional BaseIndex. 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 BaseIndex optional base-index override. Must be specified for common/reused structures.
+ */
+template<typename T, typename S, int BaseIndex=S::baseIndex, class Flex=void>
+struct C2_HIDE C2GlobalParam : public T, public S, public C2BaseIndexOverride<S, BaseIndex>,
+ public C2StructCheck<S, BaseIndex, T::indexFlags | T::Type::kDirGlobal> {
+private:
+ typedef C2GlobalParam<T, S, BaseIndex> _type;
+
+public:
+ /// Wrapper around base structure's constructor.
+ template<typename ...Args>
+ inline C2GlobalParam(const Args(&... args)) : T(sizeof(_type), _type::typeIndex), 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 BaseIndex. 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 BaseIndex optional base-index override. Must be specified for common/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 BaseIndex>
+struct C2_HIDE C2GlobalParam<T, S, BaseIndex, IF_FLEXIBLE(S)>
+ : public T, public C2FlexStructCheck<S, BaseIndex, T::indexFlags | T::Type::kDirGlobal> {
+private:
+ typedef C2GlobalParam<T, S, BaseIndex> _type;
+
+ /// Wrapper around base structure's constructor.
+ template<typename ...Args>
+ inline C2GlobalParam(size_t flexCount, const Args(&... args))
+ : T(_type::calcSize(flexCount), _type::typeIndex), 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 BaseIndex. 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 BaseIndex optional base-index override. Must be specified for common/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 BaseIndex=S::baseIndex, class Flex=void>
+struct C2_HIDE C2PortParam : public T, public S, public C2BaseIndexOverride<S, BaseIndex>,
+ private C2StructCheck<S, BaseIndex, T::indexFlags | T::Index::kDirUndefined> {
+private:
+ typedef C2PortParam<T, S, BaseIndex> _type;
+
+public:
+ /// Default constructor.
+ inline C2PortParam() : T(sizeof(_type), _type::typeIndex) { }
+ 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::typeIndex : input::typeIndex), 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 C2BaseIndexOverride<S, BaseIndex>,
+ public C2StructCheck<S, BaseIndex, T::indexFlags | T::Index::kDirInput> {
+ /// Wrapper around base structure's constructor.
+ template<typename ...Args>
+ inline input(const Args(&... args)) : T(sizeof(_type), input::typeIndex), S(args...) { }
+
+ DEFINE_CAST_OPERATORS(input)
+
+ };
+
+ /// Specialization for an output port parameter.
+ struct output : public T, public S, public C2BaseIndexOverride<S, BaseIndex>,
+ public C2StructCheck<S, BaseIndex, T::indexFlags | T::Index::kDirOutput> {
+ /// Wrapper around base structure's constructor.
+ template<typename ...Args>
+ inline output(const Args(&... args)) : T(sizeof(_type), output::typeIndex), 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 BaseIndex. 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 BaseIndex optional base-index override. Must be specified for common/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 BaseIndex>
+struct C2_HIDE C2PortParam<T, S, BaseIndex, IF_FLEXIBLE(S)>
+ : public T, public C2FlexStructCheck<S, BaseIndex, T::indexFlags | T::Type::kDirUndefined> {
+private:
+ typedef C2PortParam<T, S, BaseIndex> _type;
+
+ /// Default constructor for basic allocation: new(flexCount) P.
+ inline C2PortParam(size_t flexCount) : T(_type::calcSize(flexCount), _type::typeIndex) { }
+ 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::typeIndex : input::typeIndex),
+ 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 C2BaseIndexOverride<S, BaseIndex>,
+ public C2FlexStructCheck<S, BaseIndex, T::indexFlags | T::Index::kDirInput> {
+ 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::typeIndex), 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 C2BaseIndexOverride<S, BaseIndex>,
+ public C2FlexStructCheck<S, BaseIndex, T::indexFlags | T::Index::kDirOutput> {
+ 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::typeIndex), 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 BaseIndex. 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 BaseIndex optional base-index override. Must be specified for common/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 BaseIndex=S::baseIndex, class Flex=void>
+struct C2_HIDE C2StreamParam : public T, public S, public C2BaseIndexOverride<S, BaseIndex>,
+ private C2StructCheck<S, BaseIndex,
+ T::indexFlags | T::Index::kStreamFlag | T::Index::kDirUndefined> {
+private:
+ typedef C2StreamParam<T, S, BaseIndex> _type;
+
+public:
+ /// Default constructor. Port/direction and stream-ID is undefined.
+ inline C2StreamParam() : T(sizeof(_type), _type::typeIndex) { }
+ /// 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::typeIndex : input::typeIndex, 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 C2BaseIndexOverride<S, BaseIndex>,
+ public C2StructCheck<S, BaseIndex,
+ T::indexFlags | T::Index::kStreamFlag | T::Type::kDirInput> {
+ /// Default constructor. Stream-ID is undefined.
+ inline input() : T(sizeof(_type), input::typeIndex) { }
+ /// 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::typeIndex, 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 C2BaseIndexOverride<S, BaseIndex>,
+ public C2StructCheck<S, BaseIndex,
+ T::indexFlags | T::Index::kStreamFlag | T::Type::kDirOutput> {
+ /// Default constructor. Stream-ID is undefined.
+ inline output() : T(sizeof(_type), output::typeIndex) { }
+ /// 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::typeIndex, 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 BaseIndex. 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 BaseIndex optional base-index override. Must be specified for common/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 BaseIndex>
+struct C2_HIDE C2StreamParam<T, S, BaseIndex, IF_FLEXIBLE(S)>
+ : public T, public C2BaseIndexOverride<S, BaseIndex>,
+ private C2FlexStructCheck<S, BaseIndex,
+ T::indexFlags | T::Index::kStreamFlag | T::Index::kDirUndefined> {
+private:
+ typedef C2StreamParam<T, S> _type;
+ /// Default constructor. Port/direction and stream-ID is undefined.
+ inline C2StreamParam(size_t flexCount) : T(_type::calcSize(flexCount), _type::typeIndex, 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::typeIndex : input::typeIndex, 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 C2BaseIndexOverride<S, BaseIndex>,
+ public C2FlexStructCheck<S, BaseIndex,
+ T::indexFlags | T::Index::kStreamFlag | T::Type::kDirInput> {
+ private:
+ /// Default constructor. Stream-ID is undefined.
+ inline input(size_t flexCount) : T(_type::calcSize(flexCount), input::typeIndex) { }
+ /// 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::typeIndex, 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 C2BaseIndexOverride<S, BaseIndex>,
+ public C2FlexStructCheck<S, BaseIndex,
+ T::indexFlags | T::Index::kStreamFlag | T::Type::kDirOutput> {
+ private:
+ /// Default constructor. Stream-ID is undefined.
+ inline output(size_t flexCount) : T(_type::calcSize(flexCount), output::typeIndex) { }
+ /// 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::typeIndex, 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 base-index.
+ */
+template<typename T>
+struct C2SimpleValueStruct {
+ T mValue; ///< simple value of the structure
+ // Default constructor.
+ inline C2SimpleValueStruct() = default;
+ // Constructor with an initial value.
+ inline C2SimpleValueStruct(T value) : mValue(value) {}
+ DEFINE_C2STRUCT_NO_BASE(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*>(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 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) {
+ strncpy(array, str, std::min(arrayLen, (size_t)N));
+ }
+ }
+};
+
+/**
+ * Specialization for a flexible blob and string arrays. A structure template encapsulating a single
+ * flexible array member with default flexible constructors and no base-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 mValue 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 mValue[];
+
+ inline C2SimpleValueStruct() = default;
+ DEFINE_C2STRUCT_NO_BASE(SimpleValue)
+ FLEX(C2SimpleValueStruct, mValue)
+
+private:
+ inline C2SimpleValueStruct(size_t flexCount, const C2MemoryBlock<T> &block) {
+ _C2ValueArrayHelper::init(mValue, flexCount, block);
+ }
+
+ inline C2SimpleValueStruct(size_t flexCount, const std::initializer_list<T> &init) {
+ _C2ValueArrayHelper::init(mValue, flexCount, init);
+ }
+
+ template<unsigned N>
+ inline C2SimpleValueStruct(size_t flexCount, const T(&init)[N]) {
+ _C2ValueArrayHelper::init(mValue, flexCount, init);
+ }
+};
+
+/// @}
+
+/**
+ * A structure template encapsulating a single flexible array element of a specific type (T) with
+ * default constructors and no base-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 mValues[]; ///< array member
+ /// Default constructor
+ inline C2SimpleArrayStruct() = default;
+ DEFINE_C2STRUCT_NO_BASE(SimpleArray)
+ FLEX(C2SimpleArrayStruct, mValues)
+
+private:
+ /// Construct from a C2MemoryBlock.
+ /// Used only by the flexible parameter allocators (alloc_unique & alloc_shared).
+ inline C2SimpleArrayStruct(size_t flexCount, const C2MemoryBlock<T> &block) {
+ _C2ValueArrayHelper::init(mValues, flexCount, block);
+ }
+
+ /// Construct from an initializer list.
+ /// Used only by the flexible parameter allocators (alloc_unique & alloc_shared).
+ inline C2SimpleArrayStruct(size_t flexCount, const std::initializer_list<T> &init) {
+ _C2ValueArrayHelper::init(mValues, flexCount, init);
+ }
+
+ /// Construct from another flexible array.
+ /// Used only by the flexible parameter allocators (alloc_unique & alloc_shared).
+ template<unsigned N>
+ inline C2SimpleArrayStruct(size_t flexCount, const T(&init)[N]) {
+ _C2ValueArrayHelper::init(mValues, 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 (mValue or mValues) that is described as "value" or "values".
+ */
+/// A 32-bit signed integer parameter in mValue, described as "value"
+typedef C2SimpleValueStruct<int32_t> C2Int32Value;
+/// A 32-bit signed integer array parameter in mValues, described as "values"
+typedef C2SimpleArrayStruct<int32_t> C2Int32Array;
+/// A 32-bit unsigned integer parameter in mValue, described as "value"
+typedef C2SimpleValueStruct<uint32_t> C2Uint32Value;
+/// A 32-bit unsigned integer array parameter in mValues, described as "values"
+typedef C2SimpleArrayStruct<uint32_t> C2Uint32Array;
+/// A 64-bit signed integer parameter in mValue, described as "value"
+typedef C2SimpleValueStruct<int64_t> C2Int64Value;
+/// A 64-bit signed integer array parameter in mValues, described as "values"
+typedef C2SimpleArrayStruct<int64_t> C2Int64Array;
+/// A 64-bit unsigned integer parameter in mValue, described as "value"
+typedef C2SimpleValueStruct<uint64_t> C2Uint64Value;
+/// A 64-bit unsigned integer array parameter in mValues, described as "values"
+typedef C2SimpleArrayStruct<uint64_t> C2Uint64Array;
+/// A float parameter in mValue, described as "value"
+typedef C2SimpleValueStruct<float> C2FloatValue;
+/// A float array parameter in mValues, described as "values"
+typedef C2SimpleArrayStruct<float> C2FloatArray;
+/// A blob flexible parameter in mValue, described as "value"
+typedef C2SimpleValueStruct<uint8_t[]> C2BlobValue;
+/// A string flexible parameter in mValue, described as "value"
+typedef C2SimpleValueStruct<char[]> C2StringValue;
+
+#if 1
+template<typename T>
+const std::initializer_list<const C2FieldDescriptor> C2SimpleValueStruct<T>::fieldList = { C2FIELD(mValue, "value") };
+template<typename T>
+const std::initializer_list<const C2FieldDescriptor> C2SimpleValueStruct<T[]>::fieldList = { C2FIELD(mValue, "value") };
+template<typename T>
+const std::initializer_list<const C2FieldDescriptor> C2SimpleArrayStruct<T>::fieldList = { C2FIELD(mValues, "values") };
+#else
+// This seem to be able to be handled by the template above
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<int32_t>, { C2FIELD(mValue, "value") });
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<uint32_t>, { C2FIELD(mValue, "value") });
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<int64_t>, { C2FIELD(mValue, "value") });
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<uint64_t>, { C2FIELD(mValue, "value") });
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<float>, { C2FIELD(mValue, "value") });
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<uint8_t[]>, { C2FIELD(mValue, "value") });
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleValueStruct<char[]>, { C2FIELD(mValue, "value") });
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleArrayStruct<int32_t>, { C2FIELD(mValues, "values") });
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleArrayStruct<uint32_t>, { C2FIELD(mValues, "values") });
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleArrayStruct<int64_t>, { C2FIELD(mValues, "values") });
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleArrayStruct<uint64_t>, { C2FIELD(mValues, "values") });
+DESCRIBE_TEMPLATED_C2STRUCT(C2SimpleArrayStruct<float>, { C2FIELD(mValues, "values") });
+#endif
+
+/// @}
+
+/// @}
+
+} // namespace android
+
+#endif // C2PARAM_DEF_H_
diff --git a/media/libstagefright/codec2/include/C2Work.h b/media/libstagefright/codec2/include/C2Work.h
new file mode 100644
index 0000000..a42d11a
--- /dev/null
+++ b/media/libstagefright/codec2/include/C2Work.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 C2WORK_H_
+
+#define C2WORK_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <C2Param.h>
+#include <C2Buffer.h>
+#include <C2Config.h>
+
+#include <memory>
+#include <list>
+#include <vector>
+
+typedef int status_t;
+
+namespace android {
+
+/// \defgroup work Work and data processing
+/// @{
+
+struct C2SettingResult {
+ enum Failure {
+ READ_ONLY, ///< parameter is read-only and cannot be set
+ MISMATCH, ///< parameter mismatches input data
+ BAD_VALUE, ///< parameter does not accept value
+ 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
+ CONFLICT, ///< parameter is in conflict with another setting
+ };
+
+ C2ParamField field;
+ Failure failure;
+ std::unique_ptr<C2FieldSupportedValues> supportedValues; //< if different from normal (e.g. in conflict w/another param or input data)
+ std::list<C2ParamField> conflictingFields;
+};
+
+// ================================================================================================
+// WORK
+// ================================================================================================
+
+// node_id-s
+typedef uint32_t node_id;
+
+enum flags_t : uint32_t {
+ BUFFERFLAG_CODEC_CONFIG,
+ BUFFERFLAG_DROP_FRAME,
+ BUFFERFLAG_END_OF_STREAM,
+};
+
+enum {
+ kParamIndexWorkOrdinal,
+};
+
+struct C2WorkOrdinalStruct {
+ uint64_t timestamp;
+ uint64_t frame_index; // submission ordinal on the initial component
+ uint64_t custom_ordinal; // can be given by the component, e.g. decode order
+
+ DEFINE_AND_DESCRIBE_C2STRUCT(WorkOrdinal)
+ C2FIELD(timestamp, "timestamp")
+ C2FIELD(frame_index, "frame-index")
+ C2FIELD(custom_ordinal, "custom-ordinal")
+};
+
+struct C2BufferPack {
+//public:
+ 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::list<std::unique_ptr<C2Info>> infos;
+ std::list<std::shared_ptr<C2InfoBuffer>> infoBuffers;
+};
+
+struct C2Worklet {
+//public:
+ // IN
+ node_id component;
+
+ std::list<std::unique_ptr<C2Param>> tunings; //< tunings to be applied before processing this
+ // worklet
+ std::list<C2Param::Type> requestedInfos;
+ std::vector<std::shared_ptr<C2BlockAllocator>> allocators; //< This vector shall be the same size as
+ //< output.buffers.
+
+ // OUT
+ C2BufferPack output;
+ std::list<std::unique_ptr<C2SettingResult>> failures;
+};
+
+/**
+ * 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.
+ *
+ * input:
+ * The input data to be processed. This is provided by the client with ownership. When the work
+ * is returned, the input buffer-pack's buffer vector shall contain nullptrs.
+ *
+ * worklets:
+ * The chain of components and associated allocators, tunings 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
+ * 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,
+ *
+ * worklets_processed:
+ * It 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. If this is less then the number of worklets, result must not be success.
+ * It must be in the range of [0, worklets.size()].
+ *
+ * result:
+ * The final outcome of the work. If 0 when work is returned, it is assumed that all worklets
+ * have been processed.
+ */
+struct C2Work {
+//public:
+ // pre-chain infos (for portions of a tunneling chain that happend before this work-chain for
+ // this work item - due to framework facilitated (non-tunneled) work-chaining)
+ std::list<std::pair<std::unique_ptr<C2PortMimeConfig>, std::unique_ptr<C2Info>>> preChainInfos;
+ std::list<std::pair<std::unique_ptr<C2PortMimeConfig>, std::unique_ptr<C2Buffer>>> preChainInfoBlobs;
+
+ C2BufferPack input;
+ std::list<std::unique_ptr<C2Worklet>> worklets;
+
+ uint32_t worklets_processed;
+ status_t result;
+};
+
+struct C2WorkOutline {
+//public:
+ C2WorkOrdinalStruct ordinal;
+ std::list<node_id> chain;
+};
+
+/// @}
+
+} // namespace android
+
+#endif // C2WORK_H_
diff --git a/media/libstagefright/codec2/tests/Android.mk b/media/libstagefright/codec2/tests/Android.mk
new file mode 100644
index 0000000..49c4253
--- /dev/null
+++ b/media/libstagefright/codec2/tests/Android.mk
@@ -0,0 +1,37 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_MODULE := codec2_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+ vndk/C2UtilTest.cpp \
+ C2_test.cpp \
+ C2Param_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libstagefright_codec2 \
+ liblog
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/media/libstagefright/codec2/include \
+ frameworks/av/media/libstagefright/codec2/vndk/include \
+ $(TOP)/frameworks/native/include/media/openmax \
+
+LOCAL_CFLAGS += -Werror -Wall -std=c++14
+LOCAL_CLANG := true
+
+include $(BUILD_NATIVE_TEST)
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/media/libstagefright/codec2/tests/C2Param_test.cpp b/media/libstagefright/codec2/tests/C2Param_test.cpp
new file mode 100644
index 0000000..ec82c84
--- /dev/null
+++ b/media/libstagefright/codec2/tests/C2Param_test.cpp
@@ -0,0 +1,2687 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2Param_test"
+
+#include <gtest/gtest.h>
+
+#include <util/C2ParamUtils.h>
+#include <C2ParamDef.h>
+
+namespace android {
+
+void PrintTo(const _C2FieldId &id, ::std::ostream* os) {
+ *os << "@" << id._mOffset << "+" << id._mSize;
+}
+
+void PrintTo(const C2FieldDescriptor &fd, ::std::ostream *os) {
+ using FD=C2FieldDescriptor;
+ switch (fd.type()) {
+ case FD::INT32: *os << "i32"; break;
+ case FD::INT64: *os << "i64"; break;
+ case FD::UINT32: *os << "u32"; break;
+ case FD::UINT64: *os << "u64"; break;
+ case FD::FLOAT: *os << "float"; break;
+ case FD::STRING: *os << "char"; break;
+ case FD::BLOB: *os << "u8"; break;
+ default:
+ if (fd.type() & FD::STRUCT_FLAG) {
+ *os << "struct-" << (fd.type() & ~FD::STRUCT_FLAG);
+ } else {
+ *os << "type-" << fd.type();
+ }
+ }
+ *os << " " << fd.name();
+ if (fd.length() > 1) {
+ *os << "[" << fd.length() << "]";
+ } else if (fd.length() == 0) {
+ *os << "[]";
+ }
+ *os << " (";
+ PrintTo(fd._mFieldId, os);
+ *os << "*" << fd.length() << ")";
+}
+
+enum C2ParamIndexType {
+ kParamIndexNumber,
+ kParamIndexNumbers,
+ kParamIndexNumber2,
+ kParamIndexVendorStart = C2Param::BaseIndex::kVendorStart,
+ kParamIndexVendorNumbers,
+};
+
+void ffff(int(*)(int)) {}
+
+/* ============================= STRUCT DECLARATION AND DESCRIPTION ============================= */
+
+typedef C2FieldDescriptor FD;
+
+class C2ParamTest : public ::testing::Test {
+};
+
+class C2ParamTest_ParamFieldList
+ : public ::testing::TestWithParam<std::initializer_list<const C2FieldDescriptor>> {
+};
+
+enum {
+ kParamIndexSize,
+ kParamIndexTestA,
+ kParamIndexTestB,
+ kParamIndexTestFlexS32,
+ kParamIndexTestFlexEndS32,
+ kParamIndexTestFlexS64,
+ kParamIndexTestFlexEndS64,
+ kParamIndexTestFlexSize,
+ kParamIndexTestFlexEndSize,
+};
+
+struct C2SizeStruct {
+ int32_t mNumber;
+ int32_t mHeight;
+ enum : uint32_t { baseIndex = kParamIndexSize }; // <= needed for C2FieldDescriptor
+ const static std::initializer_list<const C2FieldDescriptor> fieldList; // <= needed for C2FieldDescriptor
+ const static FD::Type TYPE = (FD::Type)(baseIndex | FD::STRUCT_FLAG);
+};
+
+DEFINE_NO_NAMED_VALUES_FOR(C2SizeStruct)
+
+// Test 1. define a structure without any helper methods
+
+bool operator==(const C2FieldDescriptor &a, const C2FieldDescriptor &b) {
+ return a.type() == b.type()
+ && a.length() == b.length()
+ && strcmp(a.name(), b.name()) == 0
+ && a._mFieldId == b._mFieldId;
+}
+
+struct C2TestStruct_A {
+ int32_t mSigned32;
+ int64_t mSigned64[2];
+ uint32_t mUnsigned32[1];
+ uint64_t mUnsigned64;
+ float mFloat;
+ C2SizeStruct mSize[3];
+ uint8_t mBlob[100];
+ char mString[100];
+ bool mYesNo[100];
+
+ const static std::initializer_list<const C2FieldDescriptor> fieldList;
+ // enum : uint32_t { baseIndex = kParamIndexTest };
+ // typedef C2TestStruct_A _type;
+} __attribute__((packed));
+
+const std::initializer_list<const C2FieldDescriptor> C2TestStruct_A::fieldList =
+ { { FD::INT32, 1, "s32", 0, 4 },
+ { FD::INT64, 2, "s64", 4, 8 },
+ { FD::UINT32, 1, "u32", 20, 4 },
+ { FD::UINT64, 1, "u64", 24, 8 },
+ { FD::FLOAT, 1, "fp", 32, 4 },
+ { C2SizeStruct::TYPE, 3, "size", 36, 8 },
+ { FD::BLOB, 100, "blob", 60, 1 },
+ { FD::STRING, 100, "str", 160, 1 },
+ { FD::BLOB, 100, "y-n", 260, 1 } };
+
+TEST_P(C2ParamTest_ParamFieldList, VerifyStruct) {
+ std::vector<const C2FieldDescriptor> fields = GetParam(), expected = C2TestStruct_A::fieldList;
+
+ // verify first field descriptor
+ EXPECT_EQ(FD::INT32, fields[0].type());
+ EXPECT_STREQ("s32", fields[0].name());
+ EXPECT_EQ(1u, fields[0].length());
+ EXPECT_EQ(_C2FieldId(0, 4), fields[0]._mFieldId);
+
+ EXPECT_EQ(expected[0], fields[0]);
+ EXPECT_EQ(expected[1], fields[1]);
+ EXPECT_EQ(expected[2], fields[2]);
+ EXPECT_EQ(expected[3], fields[3]);
+ EXPECT_EQ(expected[4], fields[4]);
+ EXPECT_EQ(expected[5], fields[5]);
+ EXPECT_EQ(expected[6], fields[6]);
+ EXPECT_EQ(expected[7], fields[7]);
+ for (size_t i = 8; i < fields.size() && i < expected.size(); ++i) {
+ EXPECT_EQ(expected[i], fields[i]);
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(InitializerList, C2ParamTest_ParamFieldList, ::testing::Values(C2TestStruct_A::fieldList));
+
+// define fields using C2FieldDescriptor pointer constructor
+const std::initializer_list<const C2FieldDescriptor> C2TestStruct_A_FD_PTR_fieldList =
+ { C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->mSigned32, "s32"),
+ C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->mSigned64, "s64"),
+ C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->mUnsigned32, "u32"),
+ C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->mUnsigned64, "u64"),
+ C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->mFloat, "fp"),
+ C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->mSize, "size"),
+ C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->mBlob, "blob"),
+ C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->mString, "str"),
+ // C2FieldDescriptor(&((C2TestStruct_A*)(nullptr))->mYesNo, "y-n")
+ };
+
+INSTANTIATE_TEST_CASE_P(PointerConstructor, C2ParamTest_ParamFieldList, ::testing::Values(C2TestStruct_A_FD_PTR_fieldList));
+
+// define fields using C2FieldDescriptor member-pointer constructor
+const std::initializer_list<const C2FieldDescriptor> C2TestStruct_A_FD_MEM_PTR_fieldList =
+ { C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::mSigned32, "s32"),
+ C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::mSigned64, "s64"),
+ C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::mUnsigned32, "u32"),
+ C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::mUnsigned64, "u64"),
+ C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::mFloat, "fp"),
+ C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::mSize, "size"),
+ C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::mBlob, "blob"),
+ C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::mString, "str"),
+ // C2FieldDescriptor((C2TestStruct_A*)0, &C2TestStruct_A::mYesNo, "y-n")
+ };
+
+INSTANTIATE_TEST_CASE_P(MemberPointerConstructor, C2ParamTest_ParamFieldList, ::testing::Values(C2TestStruct_A_FD_MEM_PTR_fieldList));
+
+// Test 2. define a structure with two-step helper methods
+
+struct C2TestAStruct {
+ int32_t mSigned32;
+ int64_t mSigned64[2];
+ uint32_t mUnsigned32[1];
+ uint64_t mUnsigned64;
+ float mFloat;
+ C2SizeStruct mSize[3];
+ uint8_t mBlob[100];
+ char mString[100];
+ bool mYesNo[100];
+
+private: // test access level
+ DEFINE_C2STRUCT(TestA)
+} C2_PACK;
+
+DESCRIBE_C2STRUCT(TestA, {
+ C2FIELD(mSigned32, "s32")
+ C2FIELD(mSigned64, "s64")
+ C2FIELD(mUnsigned32, "u32")
+ C2FIELD(mUnsigned64, "u64")
+ C2FIELD(mFloat, "fp")
+ C2FIELD(mSize, "size")
+ C2FIELD(mBlob, "blob")
+ C2FIELD(mString, "str")
+ // C2FIELD(mYesNo, "y-n")
+}) // ; optional
+
+INSTANTIATE_TEST_CASE_P(DescribeStruct2Step, C2ParamTest_ParamFieldList, ::testing::Values(C2TestAStruct::fieldList));
+
+// Test 3. define a structure with one-step helper method
+
+struct C2TestBStruct {
+ int32_t mSigned32;
+ int64_t mSigned64[2];
+ uint32_t mUnsigned32[1];
+ uint64_t mUnsigned64;
+ float mFloat;
+ C2SizeStruct mSize[3];
+ uint8_t mBlob[100];
+ char mString[100];
+ bool mYesNo[100];
+
+private: // test access level
+ DEFINE_AND_DESCRIBE_C2STRUCT(TestB)
+
+ C2FIELD(mSigned32, "s32")
+ C2FIELD(mSigned64, "s64")
+ C2FIELD(mUnsigned32, "u32")
+ C2FIELD(mUnsigned64, "u64")
+ C2FIELD(mFloat, "fp")
+ C2FIELD(mSize, "size")
+ C2FIELD(mBlob, "blob")
+ C2FIELD(mString, "str")
+ // C2FIELD(mYesNo, "y-n")
+};
+
+INSTANTIATE_TEST_CASE_P(DescribeStruct1Step, C2ParamTest_ParamFieldList, ::testing::Values(C2TestBStruct::fieldList));
+
+// Test 4. flexible members
+
+template<typename T>
+class C2ParamTest_FlexParamFieldList : public ::testing::Test {
+protected:
+ using Type=FD::Type;
+
+ // static std::initializer_list<std::initializer_list<const C2FieldDescriptor>>
+ static std::vector<std::vector<const C2FieldDescriptor>>
+ GetLists();
+
+ constexpr static Type flexType =
+ std::is_same<T, int32_t>::value ? FD::INT32 :
+ std::is_same<T, int64_t>::value ? FD::INT64 :
+ std::is_same<T, uint32_t>::value ? FD::UINT32 :
+ std::is_same<T, uint64_t>::value ? FD::UINT64 :
+ std::is_same<T, float>::value ? FD::FLOAT :
+ std::is_same<T, uint8_t>::value ? FD::BLOB :
+ std::is_same<T, char>::value ? FD::STRING :
+ std::is_same<T, C2SizeStruct>::value ? C2SizeStruct::TYPE : (Type)0;
+ constexpr static size_t flexSize = sizeof(T);
+};
+
+typedef ::testing::Types<int32_t, int64_t, C2SizeStruct> FlexTypes;
+TYPED_TEST_CASE(C2ParamTest_FlexParamFieldList, FlexTypes);
+
+TYPED_TEST(C2ParamTest_FlexParamFieldList, VerifyStruct) {
+ for (auto a : this->GetLists()) {
+ std::vector<const C2FieldDescriptor> fields = a;
+ if (fields.size() > 1) {
+ EXPECT_EQ(2u, fields.size());
+ EXPECT_EQ(C2FieldDescriptor(FD::INT32, 1, "s32", 0, 4), fields[0]);
+ EXPECT_EQ(C2FieldDescriptor(this->flexType, 0, "flex", 4, this->flexSize),
+ fields[1]);
+ } else {
+ EXPECT_EQ(1u, fields.size());
+ EXPECT_EQ(C2FieldDescriptor(this->flexType, 0, "flex", 0, this->flexSize),
+ fields[0]);
+ }
+ }
+}
+
+struct C2TestStruct_FlexS32 {
+ int32_t mFlex[];
+
+ const static std::initializer_list<const C2FieldDescriptor> fieldList;
+ // enum : uint32_t { baseIndex = kParamIndexTestFlex, flexSize = 4 };
+ // typedef C2TestStruct_FlexS32 _type;
+ // typedef int32_t flexType;
+};
+
+const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexS32::fieldList = {
+ { FD::INT32, 0, "flex", 0, 4 }
+};
+
+struct C2TestStruct_FlexEndS32 {
+ int32_t mSigned32;
+ int32_t mFlex[];
+
+ const static std::initializer_list<const C2FieldDescriptor> fieldList;
+ // enum : uint32_t { baseIndex = kParamIndexTestFlexEnd, flexSize = 4 };
+ // typedef C2TestStruct_FlexEnd _type;
+ // typedef int32_t flexType;
+};
+
+const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexEndS32::fieldList = {
+ { FD::INT32, 1, "s32", 0, 4 },
+ { FD::INT32, 0, "flex", 4, 4 },
+};
+
+const static std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexEndS32_ptr_fieldList = {
+ C2FieldDescriptor(&((C2TestStruct_FlexEndS32*)0)->mSigned32, "s32"),
+ C2FieldDescriptor(&((C2TestStruct_FlexEndS32*)0)->mFlex, "flex"),
+};
+
+struct C2TestFlexS32Struct {
+ int32_t mFlexSigned32[];
+private: // test access level
+ C2TestFlexS32Struct() {}
+
+ DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(TestFlexS32, mFlexSigned32)
+ C2FIELD(mFlexSigned32, "flex")
+};
+
+struct C2TestFlexEndS32Struct {
+ int32_t mSigned32;
+ int32_t mFlexSigned32[];
+private: // test access level
+ C2TestFlexEndS32Struct() {}
+
+ DEFINE_FLEX_C2STRUCT(TestFlexEndS32, mFlexSigned32)
+} C2_PACK;
+
+DESCRIBE_C2STRUCT(TestFlexEndS32, {
+ C2FIELD(mSigned32, "s32")
+ C2FIELD(mFlexSigned32, "flex")
+}) // ; optional
+
+template<>
+std::vector<std::vector<const C2FieldDescriptor>>
+//std::initializer_list<std::initializer_list<const C2FieldDescriptor>>
+C2ParamTest_FlexParamFieldList<int32_t>::GetLists() {
+ return {
+ C2TestStruct_FlexS32::fieldList,
+ C2TestStruct_FlexEndS32::fieldList,
+ C2TestStruct_FlexEndS32_ptr_fieldList,
+ C2TestFlexS32Struct::fieldList,
+ C2TestFlexEndS32Struct::fieldList,
+ };
+}
+
+struct C2TestStruct_FlexS64 {
+ int64_t mFlexSigned64[];
+
+ const static std::initializer_list<const C2FieldDescriptor> fieldList;
+ // enum : uint32_t { baseIndex = kParamIndexTestFlexS64, flexSize = 8 };
+ // typedef C2TestStruct_FlexS64 _type;
+ // typedef int64_t flexType;
+};
+
+const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexS64::fieldList = {
+ { FD::INT64, 0, "flex", 0, 8 }
+};
+
+struct C2TestStruct_FlexEndS64 {
+ int32_t mSigned32;
+ int64_t mSigned64Flex[];
+
+ const static std::initializer_list<const C2FieldDescriptor> fieldList;
+ // enum : uint32_t { baseIndex = C2TestStruct_FlexEndS64, flexSize = 8 };
+ // typedef C2TestStruct_FlexEndS64 _type;
+ // typedef int64_t flexType;
+};
+
+const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexEndS64::fieldList = {
+ { FD::INT32, 1, "s32", 0, 4 },
+ { FD::INT64, 0, "flex", 4, 8 },
+};
+
+struct C2TestFlexS64Struct {
+ int64_t mFlexSigned64[];
+ C2TestFlexS64Struct() {}
+
+ DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(TestFlexS64, mFlexSigned64)
+ C2FIELD(mFlexSigned64, "flex")
+};
+
+struct C2TestFlexEndS64Struct {
+ int32_t mSigned32;
+ int64_t mFlexSigned64[];
+ C2TestFlexEndS64Struct() {}
+
+ DEFINE_FLEX_C2STRUCT(TestFlexEndS64, mFlexSigned64)
+} C2_PACK;
+
+DESCRIBE_C2STRUCT(TestFlexEndS64, {
+ C2FIELD(mSigned32, "s32")
+ C2FIELD(mFlexSigned64, "flex")
+}) // ; optional
+
+template<>
+std::vector<std::vector<const C2FieldDescriptor>>
+//std::initializer_list<std::initializer_list<const C2FieldDescriptor>>
+C2ParamTest_FlexParamFieldList<int64_t>::GetLists() {
+ return {
+ C2TestStruct_FlexS64::fieldList,
+ C2TestStruct_FlexEndS64::fieldList,
+ C2TestFlexS64Struct::fieldList,
+ C2TestFlexEndS64Struct::fieldList,
+ };
+}
+
+struct C2TestStruct_FlexSize {
+ C2SizeStruct mFlexSize[];
+
+ const static std::initializer_list<const C2FieldDescriptor> fieldList;
+ // enum : uint32_t { baseIndex = kParamIndexTestFlexSize, flexSize = 8 };
+ // typedef C2TestStruct_FlexSize _type;
+ // typedef C2SizeStruct flexType;
+};
+
+const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexSize::fieldList = {
+ { C2SizeStruct::TYPE, 0, "flex", 0, sizeof(C2SizeStruct) }
+};
+
+struct C2TestStruct_FlexEndSize {
+ int32_t mSigned32;
+ C2SizeStruct mSizeFlex[];
+
+ const static std::initializer_list<const C2FieldDescriptor> fieldList;
+ // enum : uint32_t { baseIndex = C2TestStruct_FlexEndSize, flexSize = 8 };
+ // typedef C2TestStruct_FlexEndSize _type;
+ // typedef C2SizeStruct flexType;
+};
+
+const std::initializer_list<const C2FieldDescriptor> C2TestStruct_FlexEndSize::fieldList = {
+ { FD::INT32, 1, "s32", 0, 4 },
+ { C2SizeStruct::TYPE, 0, "flex", 4, sizeof(C2SizeStruct) },
+};
+
+struct C2TestFlexSizeStruct {
+ C2SizeStruct mFlexSize[];
+ C2TestFlexSizeStruct() {}
+
+ DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(TestFlexSize, mFlexSize)
+ C2FIELD(mFlexSize, "flex")
+};
+
+struct C2TestFlexEndSizeStruct {
+ int32_t mSigned32;
+ C2SizeStruct mFlexSize[];
+ C2TestFlexEndSizeStruct() {}
+
+ DEFINE_FLEX_C2STRUCT(TestFlexEndSize, mFlexSize)
+} C2_PACK;
+
+DESCRIBE_C2STRUCT(TestFlexEndSize, {
+ C2FIELD(mSigned32, "s32")
+ C2FIELD(mFlexSize, "flex")
+}) // ; optional
+
+template<>
+std::vector<std::vector<const C2FieldDescriptor>>
+//std::initializer_list<std::initializer_list<const C2FieldDescriptor>>
+C2ParamTest_FlexParamFieldList<C2SizeStruct>::GetLists() {
+ return {
+ C2TestStruct_FlexSize::fieldList,
+ C2TestStruct_FlexEndSize::fieldList,
+ C2TestFlexSizeStruct::fieldList,
+ C2TestFlexEndSizeStruct::fieldList,
+ };
+}
+
+TEST_F(C2ParamTest, FieldId) {
+ // pointer constructor
+ EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&((C2TestStruct_A*)0)->mSigned32));
+ EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&((C2TestStruct_A*)0)->mSigned64));
+ EXPECT_EQ(_C2FieldId(20, 4), _C2FieldId(&((C2TestStruct_A*)0)->mUnsigned32));
+ EXPECT_EQ(_C2FieldId(24, 8), _C2FieldId(&((C2TestStruct_A*)0)->mUnsigned64));
+ EXPECT_EQ(_C2FieldId(32, 4), _C2FieldId(&((C2TestStruct_A*)0)->mFloat));
+ EXPECT_EQ(_C2FieldId(36, 8), _C2FieldId(&((C2TestStruct_A*)0)->mSize));
+ EXPECT_EQ(_C2FieldId(60, 1), _C2FieldId(&((C2TestStruct_A*)0)->mBlob));
+ EXPECT_EQ(_C2FieldId(160, 1), _C2FieldId(&((C2TestStruct_A*)0)->mString));
+ EXPECT_EQ(_C2FieldId(260, 1), _C2FieldId(&((C2TestStruct_A*)0)->mYesNo));
+
+ EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&((C2TestFlexEndSizeStruct*)0)->mSigned32));
+ EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&((C2TestFlexEndSizeStruct*)0)->mFlexSize));
+
+ // member pointer constructor
+ EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::mSigned32));
+ EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::mSigned64));
+ EXPECT_EQ(_C2FieldId(20, 4), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::mUnsigned32));
+ EXPECT_EQ(_C2FieldId(24, 8), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::mUnsigned64));
+ EXPECT_EQ(_C2FieldId(32, 4), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::mFloat));
+ EXPECT_EQ(_C2FieldId(36, 8), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::mSize));
+ EXPECT_EQ(_C2FieldId(60, 1), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::mBlob));
+ EXPECT_EQ(_C2FieldId(160, 1), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::mString));
+ EXPECT_EQ(_C2FieldId(260, 1), _C2FieldId((C2TestStruct_A*)0, &C2TestStruct_A::mYesNo));
+
+ EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId((C2TestFlexEndSizeStruct*)0, &C2TestFlexEndSizeStruct::mSigned32));
+ EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId((C2TestFlexEndSizeStruct*)0, &C2TestFlexEndSizeStruct::mFlexSize));
+
+ // member pointer sans type pointer
+ EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&C2TestStruct_A::mSigned32));
+ EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&C2TestStruct_A::mSigned64));
+ EXPECT_EQ(_C2FieldId(20, 4), _C2FieldId(&C2TestStruct_A::mUnsigned32));
+ EXPECT_EQ(_C2FieldId(24, 8), _C2FieldId(&C2TestStruct_A::mUnsigned64));
+ EXPECT_EQ(_C2FieldId(32, 4), _C2FieldId(&C2TestStruct_A::mFloat));
+ EXPECT_EQ(_C2FieldId(36, 8), _C2FieldId(&C2TestStruct_A::mSize));
+ EXPECT_EQ(_C2FieldId(60, 1), _C2FieldId(&C2TestStruct_A::mBlob));
+ EXPECT_EQ(_C2FieldId(160, 1), _C2FieldId(&C2TestStruct_A::mString));
+ EXPECT_EQ(_C2FieldId(260, 1), _C2FieldId(&C2TestStruct_A::mYesNo));
+
+ EXPECT_EQ(_C2FieldId(0, 4), _C2FieldId(&C2TestFlexEndSizeStruct::mSigned32));
+ EXPECT_EQ(_C2FieldId(4, 8), _C2FieldId(&C2TestFlexEndSizeStruct::mFlexSize));
+
+ typedef C2GlobalParam<C2Info, C2TestAStruct> C2TestAInfo;
+ typedef C2GlobalParam<C2Info, C2TestFlexEndSizeStruct> C2TestFlexEndSizeInfo;
+
+ // pointer constructor in C2Param
+ EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&((C2TestAInfo*)0)->mSigned32));
+ EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&((C2TestAInfo*)0)->mSigned64));
+ EXPECT_EQ(_C2FieldId(28, 4), _C2FieldId(&((C2TestAInfo*)0)->mUnsigned32));
+ EXPECT_EQ(_C2FieldId(32, 8), _C2FieldId(&((C2TestAInfo*)0)->mUnsigned64));
+ EXPECT_EQ(_C2FieldId(40, 4), _C2FieldId(&((C2TestAInfo*)0)->mFloat));
+ EXPECT_EQ(_C2FieldId(44, 8), _C2FieldId(&((C2TestAInfo*)0)->mSize));
+ EXPECT_EQ(_C2FieldId(68, 1), _C2FieldId(&((C2TestAInfo*)0)->mBlob));
+ EXPECT_EQ(_C2FieldId(168, 1), _C2FieldId(&((C2TestAInfo*)0)->mString));
+ EXPECT_EQ(_C2FieldId(268, 1), _C2FieldId(&((C2TestAInfo*)0)->mYesNo));
+
+ EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&((C2TestFlexEndSizeInfo*)0)->m.mSigned32));
+ EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&((C2TestFlexEndSizeInfo*)0)->m.mFlexSize));
+
+ // member pointer in C2Param
+ EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::mSigned32));
+ EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::mSigned64));
+ EXPECT_EQ(_C2FieldId(28, 4), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::mUnsigned32));
+ EXPECT_EQ(_C2FieldId(32, 8), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::mUnsigned64));
+ EXPECT_EQ(_C2FieldId(40, 4), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::mFloat));
+ EXPECT_EQ(_C2FieldId(44, 8), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::mSize));
+ EXPECT_EQ(_C2FieldId(68, 1), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::mBlob));
+ EXPECT_EQ(_C2FieldId(168, 1), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::mString));
+ EXPECT_EQ(_C2FieldId(268, 1), _C2FieldId((C2TestAInfo*)0, &C2TestAInfo::mYesNo));
+
+ // NOTE: cannot use a member pointer for flex params due to introduction of 'm'
+ // EXPECT_EQ(_C2FieldId(8, 4), _C2FieldId(&C2TestFlexEndSizeInfo::m.mSigned32));
+ // EXPECT_EQ(_C2FieldId(12, 8), _C2FieldId(&C2TestFlexEndSizeInfo::m.mFlexSize));
+
+
+
+}
+
+struct S32 {
+ template<typename T, class B=typename std::remove_extent<T>::type>
+ inline S32(const T*) {
+ static_assert(!std::is_array<T>::value, "should not be an array");
+ static_assert(std::is_same<B, int32_t>::value, "should be int32_t");
+ }
+};
+
+struct FLX {
+ template<typename U, typename T, class B=typename std::remove_extent<T>::type>
+ inline FLX(const T*, const U*) {
+ static_assert(std::is_array<T>::value, "should be an array");
+ static_assert(std::extent<T>::value == 0, "should be an array of 0 extent");
+ static_assert(std::is_same<B, U>::value, "should be type U");
+ }
+};
+
+struct MP {
+ template<typename U, typename T, typename ExpectedU, typename UnexpectedU>
+ inline MP(T U::*, const ExpectedU*, const UnexpectedU*) {
+ static_assert(!std::is_same<U, UnexpectedU>::value, "should not be member pointer of the base type");
+ static_assert(std::is_same<U, ExpectedU>::value, "should be member pointer of the derived type");
+ }
+
+ template<typename U, typename T, typename B, typename D>
+ inline MP(T D::*, const D*) { }
+};
+
+void compiledStatic_arrayTypePropagationTest() {
+ (void)S32(&((C2TestFlexEndS32Struct *)0)->mSigned32);
+ (void)FLX(&((C2TestFlexEndS32Struct *)0)->mFlexSigned32, (int32_t*)0);
+ (void)FLX(&((C2TestFlexS32Struct *)0)->mFlexSigned32, (int32_t*)0);
+
+ typedef C2GlobalParam<C2Info, C2TestAStruct> C2TestAInfo;
+
+ // TRICKY: &derivedClass::baseMember has type of baseClass::*
+ static_assert(std::is_same<decltype(&C2TestAInfo::mSigned32), int32_t C2TestAStruct::*>::value,
+ "base member pointer should have base class in type");
+
+ // therefore, member pointer expands to baseClass::* in templates
+ (void)MP(&C2TestAInfo::mSigned32,
+ (C2TestAStruct*)0 /* expected */, (C2TestAInfo*)0 /* unexpected */);
+ // but can be cast to derivedClass::*
+ (void)MP((int32_t C2TestAInfo::*)&C2TestAInfo::mSigned32,
+ (C2TestAInfo*)0 /* expected */, (C2TestAStruct*)0 /* unexpected */);
+
+ // TRICKY: baseClass::* does not autoconvert to derivedClass::* even in templates
+ // (void)MP(&C2TestAInfo::mSigned32, (C2TestAInfo*)0);
+}
+
+TEST_F(C2ParamTest, MemberPointerCast) {
+ typedef C2GlobalParam<C2Info, C2TestAStruct> C2TestAInfo;
+
+ static_assert(offsetof(C2TestAInfo, mSigned32) == 8, "offset should be 8");
+ constexpr int32_t C2TestAStruct::* s32ptr = &C2TestAInfo::mSigned32;
+ constexpr int32_t C2TestAInfo::* s32ptr_derived = (int32_t C2TestAStruct::*)&C2TestAInfo::mSigned32;
+ constexpr int32_t C2TestAInfo::* s32ptr_cast2derived = (int32_t C2TestAInfo::*)s32ptr;
+ C2TestAInfo *info = (C2TestAInfo *)256;
+ C2TestAStruct *strukt = (C2TestAStruct *)info;
+ int32_t *info_s32_derived = &(info->*s32ptr_derived);
+ int32_t *info_s32_cast2derived = &(info->*s32ptr_cast2derived);
+ int32_t *info_s32 = &(info->*s32ptr);
+ int32_t *strukt_s32 = &(strukt->*s32ptr);
+
+ EXPECT_EQ(256u, (uintptr_t)info);
+ EXPECT_EQ(264u, (uintptr_t)strukt);
+ EXPECT_EQ(264u, (uintptr_t)info_s32_derived);
+ EXPECT_EQ(264u, (uintptr_t)info_s32_cast2derived);
+ EXPECT_EQ(264u, (uintptr_t)info_s32);
+ EXPECT_EQ(264u, (uintptr_t)strukt_s32);
+
+ typedef C2GlobalParam<C2Info, C2TestFlexEndSizeStruct> C2TestFlexEndSizeInfo;
+ static_assert(offsetof(C2TestFlexEndSizeInfo, m.mSigned32) == 8, "offset should be 8");
+ static_assert(offsetof(C2TestFlexEndSizeInfo, m.mFlexSize) == 12, "offset should be 12");
+}
+
+/* ===================================== PARAM USAGE TESTS ===================================== */
+
+struct C2NumberStruct {
+ int32_t mNumber;
+ C2NumberStruct() {}
+ C2NumberStruct(int32_t _number) : mNumber(_number) {}
+
+ DEFINE_AND_DESCRIBE_C2STRUCT(Number)
+ C2FIELD(mNumber, "number")
+};
+
+struct C2NumbersStruct {
+ int32_t mNumbers[];
+ C2NumbersStruct() {}
+
+ DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(Numbers, mNumbers)
+ C2FIELD(mNumbers, "numbers")
+};
+static_assert(sizeof(C2NumbersStruct) == 0, "C2NumbersStruct has incorrect size");
+
+typedef C2GlobalParam<C2Tuning, C2NumberStruct> C2NumberTuning;
+typedef C2PortParam<C2Tuning, C2NumberStruct> C2NumberPortTuning;
+typedef C2StreamParam<C2Tuning, C2NumberStruct> C2NumberStreamTuning;
+
+typedef C2GlobalParam<C2Tuning, C2NumbersStruct> C2NumbersTuning;
+typedef C2PortParam<C2Tuning, C2NumbersStruct> C2NumbersPortTuning;
+typedef C2StreamParam<C2Tuning, C2NumbersStruct> C2NumbersStreamTuning;
+
+//
+#if 0
+
+void test() {
+ C2NumberStruct s(10);
+ (void)C2NumberStruct::fieldList;
+};
+
+typedef C2StreamParam<C2Tuning, C2Int64Value, kParamIndexNumberB> C2NumberConfig4;
+typedef C2PortParam<C2Tuning, C2Int32Value, kParamIndexNumber> C2NumberConfig3;
+typedef C2GlobalParam<C2Tuning, C2StringValue, kParamIndexNumber> C2VideoNameConfig;
+
+void test3() {
+ C2NumberConfig3 s(10);
+ s.mValue = 11;
+ s = 12;
+ (void)C2NumberConfig3::fieldList;
+ std::shared_ptr<C2VideoNameConfig> n = C2VideoNameConfig::alloc_shared(25);
+ strcpy(n->m.mValue, "lajos");
+ C2NumberConfig4 t(false, 0, 11);
+ t.mValue = 15;
+};
+
+struct C2NumbersStruct {
+ int32_t mNumbers[];
+ enum { baseIndex = kParamIndexNumber };
+ const static std::initializer_list<const C2FieldDescriptor> fieldList;
+ C2NumbersStruct() {}
+
+ FLEX(C2NumbersStruct, mNumbers);
+};
+
+static_assert(sizeof(C2NumbersStruct) == 0, "yes");
+
+
+typedef C2GlobalParam<C2Info, C2NumbersStruct> C2NumbersInfo;
+
+const std::initializer_list<const C2FieldDescriptor> C2NumbersStruct::fieldList =
+// { { FD::INT32, 0, "widths" } };
+ { C2FieldDescriptor(&((C2NumbersStruct*)(nullptr))->mNumbers, "number") };
+
+typedef C2PortParam<C2Tuning, C2NumberStruct> C2NumberConfig;
+
+std::list<const C2FieldDescriptor> myList = C2NumberConfig::fieldList;
+
+ std::unique_ptr<android::C2ParamDescriptor> __test_describe(uint32_t paramType) {
+ std::list<const C2FieldDescriptor> fields = describeC2Params<C2NumberConfig>();
+
+ auto widths = C2NumbersInfo::alloc_shared(5);
+ widths->flexCount();
+ widths->m.mNumbers[4] = 1;
+
+ test();
+ test3();
+
+ C2NumberConfig outputWidth(false, 123);
+
+ C2Param::Index index(paramType);
+ switch (paramType) {
+ case C2NumberConfig::baseIndex:
+ return std::unique_ptr<C2ParamDescriptor>(new C2ParamDescriptor{
+ true /* isRequired */,
+ "number",
+ index,
+ });
+ }
+ return nullptr;
+ }
+
+
+} // namespace android
+
+#endif
+//
+
+template<typename T>
+bool canSetPort(T &o, bool output) { return o.setPort(output); }
+bool canSetPort(...) { return false; }
+
+template<typename S, typename=decltype(((S*)0)->setPort(true))>
+static std::true_type _canCallSetPort(int);
+template<typename>
+static std::false_type _canCallSetPort(...);
+#define canCallSetPort(x) decltype(_canCallSetPort<std::remove_reference<decltype(x)>::type>(0))::value
+
+/* ======================================= STATIC TESTS ======================================= */
+
+static_assert(_C2Comparable<int>::value, "int is not comparable");
+static_assert(!_C2Comparable<void>::value, "void is comparable");
+
+struct C2_HIDE _test0 {
+ bool operator==(const _test0&);
+ bool operator!=(const _test0&);
+};
+struct C2_HIDE _test1 {
+ bool operator==(const _test1&);
+};
+struct C2_HIDE _test2 {
+ bool operator!=(const _test2&);
+};
+static_assert(_C2Comparable<_test0>::value, "class with == and != is not comparable");
+static_assert(_C2Comparable<_test1>::value, "class with == is not comparable");
+static_assert(_C2Comparable<_test2>::value, "class with != is not comparable");
+
+/* ======================================= C2PARAM TESTS ======================================= */
+
+struct _C2ParamInspector {
+ static void StaticTest();
+ static void StaticFlexTest();
+};
+
+// TEST_F(_C2ParamInspector, StaticTest) {
+void _C2ParamInspector::StaticTest() {
+ typedef C2Param::Index I;
+
+ // C2NumberStruct: baseIndex = kIndex (args)
+ static_assert(C2NumberStruct::baseIndex == kParamIndexNumber, "bad index");
+ static_assert(sizeof(C2NumberStruct) == 4, "bad size");
+
+ // C2NumberTuning: kIndex | tun | global (args)
+ static_assert(C2NumberTuning::baseIndex == kParamIndexNumber, "bad index");
+ static_assert(C2NumberTuning::typeIndex == (kParamIndexNumber | I::kTypeTuning | I::kDirGlobal), "bad index");
+ static_assert(sizeof(C2NumberTuning) == 12, "bad size");
+
+ static_assert(offsetof(C2NumberTuning, _mSize) == 0, "bad size");
+ static_assert(offsetof(C2NumberTuning, _mIndex) == 4, "bad offset");
+ static_assert(offsetof(C2NumberTuning, mNumber) == 8, "bad offset");
+
+ // C2NumberPortTuning: kIndex | tun | port (bool, args)
+ static_assert(sizeof(C2NumberPortTuning) == 12, "bad size");
+ // C2NumberPortTuning::input: kIndex | tun | port | input (args)
+ // C2NumberPortTuning::output: kIndex | tun | port | output (args)
+ static_assert(C2NumberPortTuning::input::baseIndex ==
+ kParamIndexNumber, "bad index");
+ static_assert(C2NumberPortTuning::input::typeIndex ==
+ (kParamIndexNumber | I::kTypeTuning | I::kDirInput), "bad index");
+ static_assert(C2NumberPortTuning::output::baseIndex ==
+ kParamIndexNumber, "bad index");
+ static_assert(C2NumberPortTuning::output::typeIndex ==
+ (kParamIndexNumber | I::kTypeTuning | I::kDirOutput), "bad index");
+ static_assert(sizeof(C2NumberPortTuning::input) == 12, "bad size");
+ static_assert(sizeof(C2NumberPortTuning::output) == 12, "bad size");
+ static_assert(offsetof(C2NumberPortTuning::input, _mSize) == 0, "bad size");
+ static_assert(offsetof(C2NumberPortTuning::input, _mIndex) == 4, "bad offset");
+ static_assert(offsetof(C2NumberPortTuning::input, mNumber) == 8, "bad offset");
+ static_assert(offsetof(C2NumberPortTuning::output, _mSize) == 0, "bad size");
+ static_assert(offsetof(C2NumberPortTuning::output, _mIndex) == 4, "bad offset");
+ static_assert(offsetof(C2NumberPortTuning::output, mNumber) == 8, "bad offset");
+
+ // C2NumberStreamTuning: kIndex | tun | str (bool, uint, args)
+ static_assert(sizeof(C2NumberStreamTuning) == 12u, "bad size");
+ // C2NumberStreamTuning::input kIndex | tun | str | input (int, args)
+ // C2NumberStreamTuning::output kIx | tun | str | output (int, args)
+ static_assert(C2NumberStreamTuning::input::baseIndex ==
+ kParamIndexNumber, "bad index");
+ static_assert(C2NumberStreamTuning::input::typeIndex ==
+ (kParamIndexNumber | I::kTypeTuning | I::kDirInput | I::kStreamFlag), "bad index");
+ static_assert(C2NumberStreamTuning::output::baseIndex ==
+ kParamIndexNumber, "bad index");
+ static_assert(C2NumberStreamTuning::output::typeIndex ==
+ (kParamIndexNumber | I::kTypeTuning | I::kDirOutput | I::kStreamFlag), "bad index");
+ static_assert(sizeof(C2NumberStreamTuning::input) == 12u, "bad size");
+ static_assert(sizeof(C2NumberStreamTuning::output) == 12u, "bad size");
+ static_assert(offsetof(C2NumberStreamTuning::input, _mSize) == 0, "bad size");
+ static_assert(offsetof(C2NumberStreamTuning::input, _mIndex) == 4, "bad offset");
+ static_assert(offsetof(C2NumberStreamTuning::input, mNumber) == 8, "bad offset");
+ static_assert(offsetof(C2NumberStreamTuning::output, _mSize) == 0, "bad size");
+ static_assert(offsetof(C2NumberStreamTuning::output, _mIndex) == 4, "bad offset");
+ static_assert(offsetof(C2NumberStreamTuning::output, mNumber) == 8, "bad offset");
+}
+
+void _C2ParamInspector::StaticFlexTest() {
+ typedef C2Param::Index I;
+
+ // C2NumbersStruct: baseIndex = kIndex (args)
+ static_assert(C2NumbersStruct::baseIndex == (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
+ static_assert(sizeof(C2NumbersStruct) == 0, "bad size");
+
+ // C2NumbersTuning: kIndex | tun | global (args)
+ static_assert(C2NumbersTuning::baseIndex == (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
+ static_assert(C2NumbersTuning::typeIndex == (I::kFlexibleFlag | kParamIndexNumbers | I::kTypeTuning | I::kDirGlobal), "bad index");
+ static_assert(sizeof(C2NumbersTuning) == 8, "bad size");
+
+ static_assert(offsetof(C2NumbersTuning, _mSize) == 0, "bad size");
+ static_assert(offsetof(C2NumbersTuning, _mIndex) == 4, "bad offset");
+ static_assert(offsetof(C2NumbersTuning, m.mNumbers) == 8, "bad offset");
+
+ // C2NumbersPortTuning: kIndex | tun | port (bool, args)
+ static_assert(sizeof(C2NumbersPortTuning) == 8, "bad size");
+ // C2NumbersPortTuning::input: kIndex | tun | port | input (args)
+ // C2NumbersPortTuning::output: kIndex | tun | port | output (args)
+ static_assert(C2NumbersPortTuning::input::baseIndex ==
+ (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
+ static_assert(C2NumbersPortTuning::input::typeIndex ==
+ (I::kFlexibleFlag | kParamIndexNumbers | I::kTypeTuning | I::kDirInput), "bad index");
+ static_assert(C2NumbersPortTuning::output::baseIndex ==
+ (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
+ static_assert(C2NumbersPortTuning::output::typeIndex ==
+ (I::kFlexibleFlag | kParamIndexNumbers | I::kTypeTuning | I::kDirOutput), "bad index");
+ static_assert(sizeof(C2NumbersPortTuning::input) == 8, "bad size");
+ static_assert(sizeof(C2NumbersPortTuning::output) == 8, "bad size");
+ static_assert(offsetof(C2NumbersPortTuning::input, _mSize) == 0, "bad size");
+ static_assert(offsetof(C2NumbersPortTuning::input, _mIndex) == 4, "bad offset");
+ static_assert(offsetof(C2NumbersPortTuning::input, m.mNumbers) == 8, "bad offset");
+ static_assert(offsetof(C2NumbersPortTuning::output, _mSize) == 0, "bad size");
+ static_assert(offsetof(C2NumbersPortTuning::output, _mIndex) == 4, "bad offset");
+ static_assert(offsetof(C2NumbersPortTuning::output, m.mNumbers) == 8, "bad offset");
+
+ // C2NumbersStreamTuning: kIndex | tun | str (bool, uint, args)
+ static_assert(sizeof(C2NumbersStreamTuning) == 8, "bad size");
+ // C2NumbersStreamTuning::input kIndex | tun | str | input (int, args)
+ // C2NumbersStreamTuning::output kIx | tun | str | output (int, args)
+ static_assert(C2NumbersStreamTuning::input::baseIndex ==
+ (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
+ static_assert(C2NumbersStreamTuning::input::typeIndex ==
+ (I::kFlexibleFlag | kParamIndexNumbers | I::kTypeTuning | I::kDirInput | I::kStreamFlag), "bad index");
+ static_assert(C2NumbersStreamTuning::output::baseIndex ==
+ (I::kFlexibleFlag | kParamIndexNumbers), "bad index");
+ static_assert(C2NumbersStreamTuning::output::typeIndex ==
+ (I::kFlexibleFlag | kParamIndexNumbers | I::kTypeTuning | I::kDirOutput | I::kStreamFlag), "bad index");
+ static_assert(sizeof(C2NumbersStreamTuning::input) == 8, "bad size");
+ static_assert(sizeof(C2NumbersStreamTuning::output) == 8, "bad size");
+ static_assert(offsetof(C2NumbersStreamTuning::input, _mSize) == 0, "bad size");
+ static_assert(offsetof(C2NumbersStreamTuning::input, _mIndex) == 4, "bad offset");
+ static_assert(offsetof(C2NumbersStreamTuning::input, m.mNumbers) == 8, "bad offset");
+ static_assert(offsetof(C2NumbersStreamTuning::output, _mSize) == 0, "bad size");
+ static_assert(offsetof(C2NumbersStreamTuning::output, _mIndex) == 4, "bad offset");
+ static_assert(offsetof(C2NumbersStreamTuning::output, m.mNumbers) == 8, "bad offset");
+}
+
+TEST_F(C2ParamTest, ParamOpsTest) {
+ const C2NumberStruct str(100);
+ C2NumberStruct bstr;
+
+ {
+ EXPECT_EQ(100, str.mNumber);
+ bstr.mNumber = 100;
+
+ C2Param::BaseIndex index = C2NumberStruct::baseIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_FALSE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
+ }
+
+ const C2NumberTuning tun(100);
+ C2NumberTuning btun;
+
+ {
+ // flags & invariables
+ for (const auto &p : { tun, btun }) {
+ EXPECT_TRUE((bool)p);
+ EXPECT_FALSE(!p);
+ EXPECT_EQ(12u, p.size());
+
+ EXPECT_FALSE(p.isVendor());
+ EXPECT_FALSE(p.isFlexible());
+ EXPECT_TRUE(p.isGlobal());
+ EXPECT_FALSE(p.forInput());
+ EXPECT_FALSE(p.forOutput());
+ EXPECT_FALSE(p.forStream());
+ EXPECT_FALSE(p.forPort());
+ }
+
+ // value
+ EXPECT_EQ(100, tun.mNumber);
+ EXPECT_EQ(0, btun.mNumber);
+ EXPECT_FALSE(tun == btun);
+ EXPECT_FALSE(tun.operator==(btun));
+ EXPECT_TRUE(tun != btun);
+ EXPECT_TRUE(tun.operator!=(btun));
+ btun.mNumber = 100;
+ EXPECT_EQ(tun, btun);
+
+ // index
+ EXPECT_EQ(C2Param::Type(tun.type()).baseIndex(), C2NumberStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(tun.type()).paramIndex(), kParamIndexNumber);
+ EXPECT_EQ(tun.type(), C2NumberTuning::typeIndex);
+ EXPECT_EQ(tun.stream(), ~0u);
+
+ C2Param::BaseIndex index = C2NumberTuning::baseIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_FALSE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
+
+ C2Param::Type type = C2NumberTuning::typeIndex;
+ EXPECT_FALSE(type.isVendor());
+ EXPECT_FALSE(type.isFlexible());
+ EXPECT_TRUE(type.isGlobal());
+ EXPECT_FALSE(type.forInput());
+ EXPECT_FALSE(type.forOutput());
+ EXPECT_FALSE(type.forStream());
+ EXPECT_FALSE(type.forPort());
+
+ EXPECT_EQ(C2NumberTuning::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumberTuning::From(&tun), &tun);
+ EXPECT_EQ(C2NumberPortTuning::From(&tun), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::input::From(&tun), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::output::From(&tun), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::From(&tun), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::input::From(&tun), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::output::From(&tun), nullptr);
+ }
+
+ const C2NumberPortTuning outp1(true, 100), inp1(false, 100);
+ C2NumberPortTuning boutp1, binp1, binp3(false, 100);
+ const C2NumberPortTuning::input inp2(100);
+ C2NumberPortTuning::input binp2;
+ const C2NumberPortTuning::output outp2(100);
+ C2NumberPortTuning::output boutp2;
+
+ {
+ static_assert(canCallSetPort(binp3), "should be able to");
+ static_assert(canCallSetPort(binp1), "should be able to");
+ static_assert(!canCallSetPort(inp1), "should not be able to (const)");
+ static_assert(!canCallSetPort(inp2), "should not be able to (const & type)");
+ static_assert(!canCallSetPort(binp2), "should not be able to (type)");
+
+ // flags & invariables
+ for (const auto &p : { outp1, inp1, boutp1 }) {
+ EXPECT_EQ(12u, p.size());
+ EXPECT_FALSE(p.isVendor());
+ EXPECT_FALSE(p.isFlexible());
+ EXPECT_FALSE(p.isGlobal());
+ EXPECT_FALSE(p.forStream());
+ EXPECT_TRUE(p.forPort());
+ }
+ for (const auto &p : { inp2, binp2 }) {
+ EXPECT_EQ(12u, p.size());
+ EXPECT_FALSE(p.isVendor());
+ EXPECT_FALSE(p.isFlexible());
+ EXPECT_FALSE(p.isGlobal());
+ EXPECT_FALSE(p.forStream());
+ EXPECT_TRUE(p.forPort());
+ }
+ for (const auto &p : { outp2, boutp2 }) {
+ EXPECT_EQ(12u, p.size());
+ EXPECT_FALSE(p.isVendor());
+ EXPECT_FALSE(p.isFlexible());
+ EXPECT_FALSE(p.isGlobal());
+ EXPECT_FALSE(p.forStream());
+ EXPECT_TRUE(p.forPort());
+ }
+
+ // port specific flags & invariables
+ EXPECT_FALSE(outp1.forInput());
+ EXPECT_TRUE(outp1.forOutput());
+
+ EXPECT_TRUE(inp1.forInput());
+ EXPECT_FALSE(inp1.forOutput());
+
+ for (const auto &p : { outp1, inp1 }) {
+ EXPECT_TRUE((bool)p);
+ EXPECT_FALSE(!p);
+ EXPECT_EQ(100, p.mNumber);
+ }
+ for (const auto &p : { outp2, boutp2 }) {
+ EXPECT_TRUE((bool)p);
+ EXPECT_FALSE(!p);
+
+ EXPECT_FALSE(p.forInput());
+ EXPECT_TRUE(p.forOutput());
+ }
+ for (const auto &p : { inp2, binp2 }) {
+ EXPECT_TRUE((bool)p);
+ EXPECT_FALSE(!p);
+
+ EXPECT_TRUE(p.forInput());
+ EXPECT_FALSE(p.forOutput());
+ }
+ for (const auto &p : { boutp1 } ) {
+ EXPECT_FALSE((bool)p);
+ EXPECT_TRUE(!p);
+
+ EXPECT_FALSE(p.forInput());
+ EXPECT_FALSE(p.forOutput());
+ EXPECT_EQ(0, p.mNumber);
+ }
+
+ // values
+ EXPECT_EQ(100, inp2.mNumber);
+ EXPECT_EQ(100, outp2.mNumber);
+ EXPECT_EQ(0, binp1.mNumber);
+ EXPECT_EQ(0, binp2.mNumber);
+ EXPECT_EQ(0, boutp1.mNumber);
+ EXPECT_EQ(0, boutp2.mNumber);
+
+ EXPECT_TRUE(inp1 != outp1);
+ EXPECT_TRUE(inp1 == inp2);
+ EXPECT_TRUE(outp1 == outp2);
+ EXPECT_TRUE(binp1 == boutp1);
+ EXPECT_TRUE(binp2 != boutp2);
+
+ EXPECT_TRUE(inp1 != binp1);
+ binp1.mNumber = 100;
+ EXPECT_TRUE(inp1 != binp1);
+ binp1.setPort(false /* output */);
+ EXPECT_TRUE((bool)binp1);
+ EXPECT_FALSE(!binp1);
+ EXPECT_TRUE(inp1 == binp1);
+
+ EXPECT_TRUE(inp2 != binp2);
+ binp2.mNumber = 100;
+ EXPECT_TRUE(inp2 == binp2);
+
+ binp1.setPort(true /* output */);
+ EXPECT_TRUE(outp1 == binp1);
+
+ EXPECT_TRUE(outp1 != boutp1);
+ boutp1.mNumber = 100;
+ EXPECT_TRUE(outp1 != boutp1);
+ boutp1.setPort(true /* output */);
+ EXPECT_TRUE((bool)boutp1);
+ EXPECT_FALSE(!boutp1);
+ EXPECT_TRUE(outp1 == boutp1);
+
+ EXPECT_TRUE(outp2 != boutp2);
+ boutp2.mNumber = 100;
+ EXPECT_TRUE(outp2 == boutp2);
+
+ boutp1.setPort(false /* output */);
+ EXPECT_TRUE(inp1 == boutp1);
+
+ // index
+ EXPECT_EQ(C2Param::Type(inp1.type()).baseIndex(), C2NumberStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(inp1.type()).paramIndex(), kParamIndexNumber);
+ EXPECT_EQ(inp1.type(), C2NumberPortTuning::input::typeIndex);
+ EXPECT_EQ(inp1.stream(), ~0u);
+
+ EXPECT_EQ(C2Param::Type(inp2.type()).baseIndex(), C2NumberStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(inp2.type()).paramIndex(), kParamIndexNumber);
+ EXPECT_EQ(inp2.type(), C2NumberPortTuning::input::typeIndex);
+ EXPECT_EQ(inp2.stream(), ~0u);
+
+ EXPECT_EQ(C2Param::Type(outp1.type()).baseIndex(), C2NumberStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(outp1.type()).paramIndex(), kParamIndexNumber);
+ EXPECT_EQ(outp1.type(), C2NumberPortTuning::output::typeIndex);
+ EXPECT_EQ(outp1.stream(), ~0u);
+
+ EXPECT_EQ(C2Param::Type(outp2.type()).baseIndex(), C2NumberStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(outp2.type()).paramIndex(), kParamIndexNumber);
+ EXPECT_EQ(outp2.type(), C2NumberPortTuning::output::typeIndex);
+ EXPECT_EQ(outp2.stream(), ~0u);
+
+ C2Param::BaseIndex index = C2NumberPortTuning::input::typeIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_FALSE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
+
+ index = C2NumberPortTuning::output::typeIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_FALSE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
+
+ C2Param::Type type = C2NumberPortTuning::input::typeIndex;
+ EXPECT_FALSE(type.isVendor());
+ EXPECT_FALSE(type.isFlexible());
+ EXPECT_FALSE(type.isGlobal());
+ EXPECT_TRUE(type.forInput());
+ EXPECT_FALSE(type.forOutput());
+ EXPECT_FALSE(type.forStream());
+ EXPECT_TRUE(type.forPort());
+
+ type = C2NumberPortTuning::output::typeIndex;
+ EXPECT_FALSE(type.isVendor());
+ EXPECT_FALSE(type.isFlexible());
+ EXPECT_FALSE(type.isGlobal());
+ EXPECT_FALSE(type.forInput());
+ EXPECT_TRUE(type.forOutput());
+ EXPECT_FALSE(type.forStream());
+ EXPECT_TRUE(type.forPort());
+
+ EXPECT_EQ(C2NumberPortTuning::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::input::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::output::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumberTuning::From(&inp1), nullptr);
+ EXPECT_EQ(C2NumberTuning::From(&inp2), nullptr);
+ EXPECT_EQ(C2NumberTuning::From(&outp1), nullptr);
+ EXPECT_EQ(C2NumberTuning::From(&outp2), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::From(&inp1), &inp1);
+ EXPECT_EQ(C2NumberPortTuning::From(&inp2), (C2NumberPortTuning*)&inp2);
+ EXPECT_EQ(C2NumberPortTuning::From(&outp1), &outp1);
+ EXPECT_EQ(C2NumberPortTuning::From(&outp2), (C2NumberPortTuning*)&outp2);
+ EXPECT_EQ(C2NumberPortTuning::input::From(&inp1), (C2NumberPortTuning::input*)&inp1);
+ EXPECT_EQ(C2NumberPortTuning::input::From(&inp2), &inp2);
+ EXPECT_EQ(C2NumberPortTuning::input::From(&outp1), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::input::From(&outp2), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::output::From(&inp1), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::output::From(&inp2), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::output::From(&outp1), (C2NumberPortTuning::output*)&outp1);
+ EXPECT_EQ(C2NumberPortTuning::output::From(&outp2), &outp2);
+ EXPECT_EQ(C2NumberStreamTuning::From(&inp1), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::From(&inp2), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::From(&outp1), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::From(&outp2), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::input::From(&inp1), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::input::From(&inp2), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::input::From(&outp1), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::input::From(&outp2), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::output::From(&inp1), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::output::From(&inp2), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::output::From(&outp1), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::output::From(&outp2), nullptr);
+ }
+
+ const C2NumberStreamTuning outs1(true, 1u, 100), ins1(false, 1u, 100);
+ C2NumberStreamTuning bouts1, bins1, bins3(false, 1u, 100);
+ const C2NumberStreamTuning::input ins2(1u, 100);
+ C2NumberStreamTuning::input bins2;
+ const C2NumberStreamTuning::output outs2(1u, 100);
+ C2NumberStreamTuning::output bouts2;
+
+ {
+ static_assert(canCallSetPort(bins3), "should be able to");
+ static_assert(canCallSetPort(bins1), "should be able to");
+ static_assert(!canCallSetPort(ins1), "should not be able to (const)");
+ static_assert(!canCallSetPort(ins2), "should not be able to (const & type)");
+ static_assert(!canCallSetPort(bins2), "should not be able to (type)");
+
+ // flags & invariables
+ for (const auto &p : { outs1, ins1, bouts1 }) {
+ EXPECT_EQ(12u, p.size());
+ EXPECT_FALSE(p.isVendor());
+ EXPECT_FALSE(p.isFlexible());
+ EXPECT_FALSE(p.isGlobal());
+ EXPECT_TRUE(p.forStream());
+ EXPECT_FALSE(p.forPort());
+ }
+ for (const auto &p : { ins2, bins2 }) {
+ EXPECT_EQ(12u, p.size());
+ EXPECT_FALSE(p.isVendor());
+ EXPECT_FALSE(p.isFlexible());
+ EXPECT_FALSE(p.isGlobal());
+ EXPECT_TRUE(p.forStream());
+ EXPECT_FALSE(p.forPort());
+ }
+ for (const auto &p : { outs2, bouts2 }) {
+ EXPECT_EQ(12u, p.size());
+ EXPECT_FALSE(p.isVendor());
+ EXPECT_FALSE(p.isFlexible());
+ EXPECT_FALSE(p.isGlobal());
+ EXPECT_TRUE(p.forStream());
+ EXPECT_FALSE(p.forPort());
+ }
+
+ // port specific flags & invariables
+ EXPECT_FALSE(outs1.forInput());
+ EXPECT_TRUE(outs1.forOutput());
+
+ EXPECT_TRUE(ins1.forInput());
+ EXPECT_FALSE(ins1.forOutput());
+
+ for (const auto &p : { outs1, ins1 }) {
+ EXPECT_TRUE((bool)p);
+ EXPECT_FALSE(!p);
+ EXPECT_EQ(100, p.mNumber);
+ EXPECT_EQ(1u, p.stream());
+ }
+ for (const auto &p : { outs2, bouts2 }) {
+ EXPECT_TRUE((bool)p);
+ EXPECT_FALSE(!p);
+
+ EXPECT_FALSE(p.forInput());
+ EXPECT_TRUE(p.forOutput());
+ }
+ for (const auto &p : { ins2, bins2 }) {
+ EXPECT_TRUE((bool)p);
+ EXPECT_FALSE(!p);
+
+ EXPECT_TRUE(p.forInput());
+ EXPECT_FALSE(p.forOutput());
+ }
+ for (const auto &p : { bouts1 } ) {
+ EXPECT_FALSE((bool)p);
+ EXPECT_TRUE(!p);
+
+ EXPECT_FALSE(p.forInput());
+ EXPECT_FALSE(p.forOutput());
+ EXPECT_EQ(0, p.mNumber);
+ }
+
+ // values
+ EXPECT_EQ(100, ins2.mNumber);
+ EXPECT_EQ(100, outs2.mNumber);
+ EXPECT_EQ(0, bins1.mNumber);
+ EXPECT_EQ(0, bins2.mNumber);
+ EXPECT_EQ(0, bouts1.mNumber);
+ EXPECT_EQ(0, bouts2.mNumber);
+
+ EXPECT_EQ(1u, ins2.stream());
+ EXPECT_EQ(1u, outs2.stream());
+ EXPECT_EQ(0u, bins1.stream());
+ EXPECT_EQ(0u, bins2.stream());
+ EXPECT_EQ(0u, bouts1.stream());
+ EXPECT_EQ(0u, bouts2.stream());
+
+ EXPECT_TRUE(ins1 != outs1);
+ EXPECT_TRUE(ins1 == ins2);
+ EXPECT_TRUE(outs1 == outs2);
+ EXPECT_TRUE(bins1 == bouts1);
+ EXPECT_TRUE(bins2 != bouts2);
+
+ EXPECT_TRUE(ins1 != bins1);
+ bins1.mNumber = 100;
+ EXPECT_TRUE(ins1 != bins1);
+ bins1.setPort(false /* output */);
+ EXPECT_TRUE(ins1 != bins1);
+ bins1.setStream(1u);
+ EXPECT_TRUE(ins1 == bins1);
+
+ EXPECT_TRUE(ins2 != bins2);
+ bins2.mNumber = 100;
+ EXPECT_TRUE(ins2 != bins2);
+ bins2.setStream(1u);
+ EXPECT_TRUE(ins2 == bins2);
+
+ bins1.setPort(true /* output */);
+ EXPECT_TRUE(outs1 == bins1);
+
+ EXPECT_TRUE(outs1 != bouts1);
+ bouts1.mNumber = 100;
+ EXPECT_TRUE(outs1 != bouts1);
+ bouts1.setPort(true /* output */);
+ EXPECT_TRUE(outs1 != bouts1);
+ bouts1.setStream(1u);
+ EXPECT_TRUE(outs1 == bouts1);
+
+ EXPECT_TRUE(outs2 != bouts2);
+ bouts2.mNumber = 100;
+ EXPECT_TRUE(outs2 != bouts2);
+ bouts2.setStream(1u);
+ EXPECT_TRUE(outs2 == bouts2);
+
+ bouts1.setPort(false /* output */);
+ EXPECT_TRUE(ins1 == bouts1);
+
+ // index
+ EXPECT_EQ(C2Param::Type(ins1.type()).baseIndex(), C2NumberStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(ins1.type()).paramIndex(), kParamIndexNumber);
+ EXPECT_EQ(ins1.type(), C2NumberStreamTuning::input::typeIndex);
+
+ EXPECT_EQ(C2Param::Type(ins2.type()).baseIndex(), C2NumberStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(ins2.type()).paramIndex(), kParamIndexNumber);
+ EXPECT_EQ(ins2.type(), C2NumberStreamTuning::input::typeIndex);
+
+ EXPECT_EQ(C2Param::Type(outs1.type()).baseIndex(), C2NumberStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(outs1.type()).paramIndex(), kParamIndexNumber);
+ EXPECT_EQ(outs1.type(), C2NumberStreamTuning::output::typeIndex);
+
+ EXPECT_EQ(C2Param::Type(outs2.type()).baseIndex(), C2NumberStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(outs2.type()).paramIndex(), kParamIndexNumber);
+ EXPECT_EQ(outs2.type(), C2NumberStreamTuning::output::typeIndex);
+
+ C2Param::BaseIndex index = C2NumberStreamTuning::input::typeIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_FALSE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
+
+ index = C2NumberStreamTuning::output::typeIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_FALSE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumber);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumber);
+
+ C2Param::Type type = C2NumberStreamTuning::input::typeIndex;
+ EXPECT_FALSE(type.isVendor());
+ EXPECT_FALSE(type.isFlexible());
+ EXPECT_FALSE(type.isGlobal());
+ EXPECT_TRUE(type.forInput());
+ EXPECT_FALSE(type.forOutput());
+ EXPECT_TRUE(type.forStream());
+ EXPECT_FALSE(type.forPort());
+
+ type = C2NumberStreamTuning::output::typeIndex;
+ EXPECT_FALSE(type.isVendor());
+ EXPECT_FALSE(type.isFlexible());
+ EXPECT_FALSE(type.isGlobal());
+ EXPECT_FALSE(type.forInput());
+ EXPECT_TRUE(type.forOutput());
+ EXPECT_TRUE(type.forStream());
+ EXPECT_FALSE(type.forPort());
+
+ EXPECT_EQ(C2NumberPortTuning::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::input::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::output::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumberTuning::From(&ins1), nullptr);
+ EXPECT_EQ(C2NumberTuning::From(&ins2), nullptr);
+ EXPECT_EQ(C2NumberTuning::From(&outs1), nullptr);
+ EXPECT_EQ(C2NumberTuning::From(&outs2), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::From(&ins1), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::From(&ins2), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::From(&outs1), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::From(&outs2), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::input::From(&ins1), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::input::From(&ins2), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::input::From(&outs1), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::input::From(&outs2), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::output::From(&ins1), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::output::From(&ins2), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::output::From(&outs1), nullptr);
+ EXPECT_EQ(C2NumberPortTuning::output::From(&outs2), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::From(&ins1), &ins1);
+ EXPECT_EQ(C2NumberStreamTuning::From(&ins2), (C2NumberStreamTuning*)&ins2);
+ EXPECT_EQ(C2NumberStreamTuning::From(&outs1), &outs1);
+ EXPECT_EQ(C2NumberStreamTuning::From(&outs2), (C2NumberStreamTuning*)&outs2);
+ EXPECT_EQ(C2NumberStreamTuning::input::From(&ins1), (C2NumberStreamTuning::input*)&ins1);
+ EXPECT_EQ(C2NumberStreamTuning::input::From(&ins2), &ins2);
+ EXPECT_EQ(C2NumberStreamTuning::input::From(&outs1), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::input::From(&outs2), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::output::From(&ins1), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::output::From(&ins2), nullptr);
+ EXPECT_EQ(C2NumberStreamTuning::output::From(&outs1), (C2NumberStreamTuning::output*)&outs1);
+ EXPECT_EQ(C2NumberStreamTuning::output::From(&outs2), &outs2);
+
+ }
+
+ {
+ uint32_t videoWidth[] = { 12u, C2NumberStreamTuning::output::typeIndex, 100 };
+ C2Param *p1 = C2Param::From(videoWidth, sizeof(videoWidth));
+ EXPECT_NE(p1, nullptr);
+ EXPECT_EQ(12u, p1->size());
+ EXPECT_EQ(p1->type(), C2NumberStreamTuning::output::typeIndex);
+
+ p1 = C2Param::From(videoWidth, sizeof(videoWidth) + 2);
+ EXPECT_EQ(p1, nullptr);
+
+ p1 = C2Param::From(videoWidth, sizeof(videoWidth) - 2);
+ EXPECT_EQ(p1, nullptr);
+
+ p1 = C2Param::From(videoWidth, 3);
+ EXPECT_EQ(p1, nullptr);
+
+ p1 = C2Param::From(videoWidth, 0);
+ EXPECT_EQ(p1, nullptr);
+ }
+}
+
+void StaticTestAddBaseIndex() {
+ struct nobase {};
+ struct base { enum : uint32_t { baseIndex = 1 }; };
+ static_assert(C2AddBaseIndex<nobase, 2>::baseIndex == 2, "should be 2");
+ static_assert(C2AddBaseIndex<base, 1>::baseIndex == 1, "should be 1");
+}
+
+class TestFlexHelper {
+ struct _Flex {
+ int32_t a;
+ char b[];
+ _Flex() {}
+ FLEX(_Flex, b);
+ };
+
+ struct _BoFlex {
+ _Flex a;
+ _BoFlex() {}
+ FLEX(_BoFlex, a);
+ };
+
+ struct _NonFlex {
+ };
+
+
+ static void StaticTest() {
+ static_assert(std::is_same<_C2FlexHelper<char>::flexType, void>::value, "should be void");
+ static_assert(std::is_same<_C2FlexHelper<char[]>::flexType, char>::value, "should be char");
+ static_assert(std::is_same<_C2FlexHelper<_Flex>::flexType, char>::value, "should be char");
+
+ static_assert(std::is_same<_C2FlexHelper<_BoFlex>::flexType, char>::value, "should be void");
+
+ static_assert(_C2Flexible<_Flex>::value, "should be flexible");
+ static_assert(!_C2Flexible<_NonFlex>::value, "should not be flexible");
+ }
+};
+
+TEST_F(C2ParamTest, FlexParamOpsTest) {
+// const C2NumbersStruct str{100};
+ C2NumbersStruct bstr;
+ {
+// EXPECT_EQ(100, str->m.mNumbers[0]);
+ (void)&bstr.mNumbers[0];
+
+ C2Param::BaseIndex index = C2NumbersStruct::baseIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_TRUE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
+ }
+
+ std::unique_ptr<C2NumbersTuning> tun_ = C2NumbersTuning::alloc_unique(1);
+ tun_->m.mNumbers[0] = 100;
+ std::unique_ptr<const C2NumbersTuning> tun = std::move(tun_);
+ std::shared_ptr<C2NumbersTuning> btun = C2NumbersTuning::alloc_shared(1);
+
+ {
+ // flags & invariables
+ const C2NumbersTuning *T[] = { tun.get(), btun.get() };
+ for (const auto p : T) {
+ EXPECT_TRUE((bool)(*p));
+ EXPECT_FALSE(!(*p));
+ EXPECT_EQ(12u, p->size());
+
+ EXPECT_FALSE(p->isVendor());
+ EXPECT_TRUE(p->isFlexible());
+ EXPECT_TRUE(p->isGlobal());
+ EXPECT_FALSE(p->forInput());
+ EXPECT_FALSE(p->forOutput());
+ EXPECT_FALSE(p->forStream());
+ EXPECT_FALSE(p->forPort());
+ }
+
+ // value
+ EXPECT_EQ(100, tun->m.mNumbers[0]);
+ EXPECT_EQ(0, btun->m.mNumbers[0]);
+ EXPECT_FALSE(*tun == *btun);
+ EXPECT_FALSE(tun->operator==(*btun));
+ EXPECT_TRUE(*tun != *btun);
+ EXPECT_TRUE(tun->operator!=(*btun));
+ btun->m.mNumbers[0] = 100;
+ EXPECT_EQ(*tun, *btun);
+
+ // index
+ EXPECT_EQ(C2Param::Type(tun->type()).baseIndex(), C2NumbersStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(tun->type()).paramIndex(), kParamIndexNumbers);
+ EXPECT_EQ(tun->type(), C2NumbersTuning::typeIndex);
+ EXPECT_EQ(tun->stream(), ~0u);
+
+ C2Param::BaseIndex index = C2NumbersTuning::baseIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_TRUE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
+
+ C2Param::Type type = C2NumbersTuning::typeIndex;
+ EXPECT_FALSE(type.isVendor());
+ EXPECT_TRUE(type.isFlexible());
+ EXPECT_TRUE(type.isGlobal());
+ EXPECT_FALSE(type.forInput());
+ EXPECT_FALSE(type.forOutput());
+ EXPECT_FALSE(type.forStream());
+ EXPECT_FALSE(type.forPort());
+
+ EXPECT_EQ(C2NumbersTuning::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumbersTuning::From(tun.get()), tun.get());
+ EXPECT_EQ(C2NumbersPortTuning::From(tun.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::input::From(tun.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::output::From(tun.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::From(tun.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::input::From(tun.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::output::From(tun.get()), nullptr);
+ }
+
+ std::unique_ptr<C2NumbersPortTuning> outp1_(C2NumbersPortTuning::alloc_unique(1, true)),
+ inp1_ = C2NumbersPortTuning::alloc_unique(1, false);
+ outp1_->m.mNumbers[0] = 100;
+ inp1_->m.mNumbers[0] = 100;
+ std::unique_ptr<const C2NumbersPortTuning> outp1 = std::move(outp1_);
+ std::unique_ptr<const C2NumbersPortTuning> inp1 = std::move(inp1_);
+ std::shared_ptr<C2NumbersPortTuning> boutp1(C2NumbersPortTuning::alloc_shared(1)),
+ binp1 = C2NumbersPortTuning::alloc_shared(1),
+ binp3 = C2NumbersPortTuning::alloc_shared(1, false);
+ binp3->m.mNumbers[0] = 100;
+ std::unique_ptr<C2NumbersPortTuning::input> inp2_(C2NumbersPortTuning::input::alloc_unique(1));
+ inp2_->m.mNumbers[0] = 100;
+ std::unique_ptr<const C2NumbersPortTuning::input> inp2 = std::move(inp2_);
+ std::shared_ptr<C2NumbersPortTuning::input> binp2(C2NumbersPortTuning::input::alloc_shared(1));
+ std::unique_ptr<C2NumbersPortTuning::output> outp2_(C2NumbersPortTuning::output::alloc_unique(1));
+ outp2_->m.mNumbers[0] = 100;
+ std::unique_ptr<const C2NumbersPortTuning::output> outp2 = std::move(outp2_);
+ std::shared_ptr<C2NumbersPortTuning::output> boutp2(C2NumbersPortTuning::output::alloc_shared(1));
+
+ {
+ static_assert(canCallSetPort(*binp3), "should be able to");
+ static_assert(canCallSetPort(*binp1), "should be able to");
+ static_assert(!canCallSetPort(*inp1), "should not be able to (const)");
+ static_assert(!canCallSetPort(*inp2), "should not be able to (const & type)");
+ static_assert(!canCallSetPort(*binp2), "should not be able to (type)");
+
+ // flags & invariables
+ const C2NumbersPortTuning *P[] = { outp1.get(), inp1.get(), boutp1.get() };
+ for (const auto p : P) {
+ EXPECT_EQ(12u, p->size());
+ EXPECT_FALSE(p->isVendor());
+ EXPECT_TRUE(p->isFlexible());
+ EXPECT_FALSE(p->isGlobal());
+ EXPECT_FALSE(p->forStream());
+ EXPECT_TRUE(p->forPort());
+ }
+ const C2NumbersPortTuning::input *PI[] = { inp2.get(), binp2.get() };
+ for (const auto p : PI) {
+ EXPECT_EQ(12u, p->size());
+ EXPECT_FALSE(p->isVendor());
+ EXPECT_TRUE(p->isFlexible());
+ EXPECT_FALSE(p->isGlobal());
+ EXPECT_FALSE(p->forStream());
+ EXPECT_TRUE(p->forPort());
+ }
+ const C2NumbersPortTuning::output *PO[] = { outp2.get(), boutp2.get() };
+ for (const auto p : PO) {
+ EXPECT_EQ(12u, p->size());
+ EXPECT_FALSE(p->isVendor());
+ EXPECT_TRUE(p->isFlexible());
+ EXPECT_FALSE(p->isGlobal());
+ EXPECT_FALSE(p->forStream());
+ EXPECT_TRUE(p->forPort());
+ }
+
+ // port specific flags & invariables
+ EXPECT_FALSE(outp1->forInput());
+ EXPECT_TRUE(outp1->forOutput());
+
+ EXPECT_TRUE(inp1->forInput());
+ EXPECT_FALSE(inp1->forOutput());
+
+ const C2NumbersPortTuning *P2[] = { outp1.get(), inp1.get() };
+ for (const auto p : P2) {
+ EXPECT_TRUE((bool)(*p));
+ EXPECT_FALSE(!(*p));
+ EXPECT_EQ(100, p->m.mNumbers[0]);
+ }
+ for (const auto p : PO) {
+ EXPECT_TRUE((bool)(*p));
+ EXPECT_FALSE(!(*p));
+
+ EXPECT_FALSE(p->forInput());
+ EXPECT_TRUE(p->forOutput());
+ }
+ for (const auto p : PI) {
+ EXPECT_TRUE((bool)(*p));
+ EXPECT_FALSE(!(*p));
+
+ EXPECT_TRUE(p->forInput());
+ EXPECT_FALSE(p->forOutput());
+ }
+ const C2NumbersPortTuning *P3[] = { boutp1.get() };
+ for (const auto p : P3) {
+ EXPECT_FALSE((bool)(*p));
+ EXPECT_TRUE(!(*p));
+
+ EXPECT_FALSE(p->forInput());
+ EXPECT_FALSE(p->forOutput());
+ EXPECT_EQ(0, p->m.mNumbers[0]);
+ }
+
+ // values
+ EXPECT_EQ(100, inp2->m.mNumbers[0]);
+ EXPECT_EQ(100, outp2->m.mNumbers[0]);
+ EXPECT_EQ(0, binp1->m.mNumbers[0]);
+ EXPECT_EQ(0, binp2->m.mNumbers[0]);
+ EXPECT_EQ(0, boutp1->m.mNumbers[0]);
+ EXPECT_EQ(0, boutp2->m.mNumbers[0]);
+
+ EXPECT_TRUE(*inp1 != *outp1);
+ EXPECT_TRUE(*inp1 == *inp2);
+ EXPECT_TRUE(*outp1 == *outp2);
+ EXPECT_TRUE(*binp1 == *boutp1);
+ EXPECT_TRUE(*binp2 != *boutp2);
+
+ EXPECT_TRUE(*inp1 != *binp1);
+ binp1->m.mNumbers[0] = 100;
+ EXPECT_TRUE(*inp1 != *binp1);
+ binp1->setPort(false /* output */);
+ EXPECT_TRUE((bool)*binp1);
+ EXPECT_FALSE(!*binp1);
+ EXPECT_TRUE(*inp1 == *binp1);
+
+ EXPECT_TRUE(*inp2 != *binp2);
+ binp2->m.mNumbers[0] = 100;
+ EXPECT_TRUE(*inp2 == *binp2);
+
+ binp1->setPort(true /* output */);
+ EXPECT_TRUE(*outp1 == *binp1);
+
+ EXPECT_TRUE(*outp1 != *boutp1);
+ boutp1->m.mNumbers[0] = 100;
+ EXPECT_TRUE(*outp1 != *boutp1);
+ boutp1->setPort(true /* output */);
+ EXPECT_TRUE((bool)*boutp1);
+ EXPECT_FALSE(!*boutp1);
+ EXPECT_TRUE(*outp1 == *boutp1);
+
+ EXPECT_TRUE(*outp2 != *boutp2);
+ boutp2->m.mNumbers[0] = 100;
+ EXPECT_TRUE(*outp2 == *boutp2);
+
+ boutp1->setPort(false /* output */);
+ EXPECT_TRUE(*inp1 == *boutp1);
+
+ // index
+ EXPECT_EQ(C2Param::Type(inp1->type()).baseIndex(), C2NumbersStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(inp1->type()).paramIndex(), kParamIndexNumbers);
+ EXPECT_EQ(inp1->type(), C2NumbersPortTuning::input::typeIndex);
+ EXPECT_EQ(inp1->stream(), ~0u);
+
+ EXPECT_EQ(C2Param::Type(inp2->type()).baseIndex(), C2NumbersStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(inp2->type()).paramIndex(), kParamIndexNumbers);
+ EXPECT_EQ(inp2->type(), C2NumbersPortTuning::input::typeIndex);
+ EXPECT_EQ(inp2->stream(), ~0u);
+
+ EXPECT_EQ(C2Param::Type(outp1->type()).baseIndex(), C2NumbersStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(outp1->type()).paramIndex(), kParamIndexNumbers);
+ EXPECT_EQ(outp1->type(), C2NumbersPortTuning::output::typeIndex);
+ EXPECT_EQ(outp1->stream(), ~0u);
+
+ EXPECT_EQ(C2Param::Type(outp2->type()).baseIndex(), C2NumbersStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(outp2->type()).paramIndex(), kParamIndexNumbers);
+ EXPECT_EQ(outp2->type(), C2NumbersPortTuning::output::typeIndex);
+ EXPECT_EQ(outp2->stream(), ~0u);
+
+ C2Param::BaseIndex index = C2NumbersPortTuning::input::typeIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_TRUE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
+
+ index = C2NumbersPortTuning::output::typeIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_TRUE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
+
+ C2Param::Type type = C2NumbersPortTuning::input::typeIndex;
+ EXPECT_FALSE(type.isVendor());
+ EXPECT_TRUE(type.isFlexible());
+ EXPECT_FALSE(type.isGlobal());
+ EXPECT_TRUE(type.forInput());
+ EXPECT_FALSE(type.forOutput());
+ EXPECT_FALSE(type.forStream());
+ EXPECT_TRUE(type.forPort());
+
+ type = C2NumbersPortTuning::output::typeIndex;
+ EXPECT_FALSE(type.isVendor());
+ EXPECT_TRUE(type.isFlexible());
+ EXPECT_FALSE(type.isGlobal());
+ EXPECT_FALSE(type.forInput());
+ EXPECT_TRUE(type.forOutput());
+ EXPECT_FALSE(type.forStream());
+ EXPECT_TRUE(type.forPort());
+
+ EXPECT_EQ(C2NumbersPortTuning::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::input::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::output::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumbersTuning::From(inp1.get()), nullptr);
+ EXPECT_EQ(C2NumbersTuning::From(inp2.get()), nullptr);
+ EXPECT_EQ(C2NumbersTuning::From(outp1.get()), nullptr);
+ EXPECT_EQ(C2NumbersTuning::From(outp2.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::From(inp1.get()), inp1.get());
+ EXPECT_EQ(C2NumbersPortTuning::From(inp2.get()), (C2NumbersPortTuning*)inp2.get());
+ EXPECT_EQ(C2NumbersPortTuning::From(outp1.get()), outp1.get());
+ EXPECT_EQ(C2NumbersPortTuning::From(outp2.get()), (C2NumbersPortTuning*)outp2.get());
+ EXPECT_EQ(C2NumbersPortTuning::input::From(inp1.get()), (C2NumbersPortTuning::input*)inp1.get());
+ EXPECT_EQ(C2NumbersPortTuning::input::From(inp2.get()), inp2.get());
+ EXPECT_EQ(C2NumbersPortTuning::input::From(outp1.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::input::From(outp2.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::output::From(inp1.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::output::From(inp2.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::output::From(outp1.get()), (C2NumbersPortTuning::output*)outp1.get());
+ EXPECT_EQ(C2NumbersPortTuning::output::From(outp2.get()), outp2.get());
+ EXPECT_EQ(C2NumbersStreamTuning::From(inp1.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::From(inp2.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::From(outp1.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::From(outp2.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::input::From(inp1.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::input::From(inp2.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::input::From(outp1.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::input::From(outp2.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::output::From(inp1.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::output::From(inp2.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::output::From(outp1.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::output::From(outp2.get()), nullptr);
+
+ }
+
+ std::unique_ptr<C2NumbersStreamTuning> outs1_(C2NumbersStreamTuning::alloc_unique(1, true, 1u));
+ outs1_->m.mNumbers[0] = 100;
+ std::unique_ptr<const C2NumbersStreamTuning> outs1 = std::move(outs1_);
+ std::unique_ptr<C2NumbersStreamTuning> ins1_(C2NumbersStreamTuning::alloc_unique(1, false, 1u));
+ ins1_->m.mNumbers[0] = 100;
+ std::unique_ptr<const C2NumbersStreamTuning> ins1 = std::move(ins1_);
+ std::shared_ptr<C2NumbersStreamTuning> bouts1(C2NumbersStreamTuning::alloc_shared(1));
+ std::shared_ptr<C2NumbersStreamTuning> bins1(C2NumbersStreamTuning::alloc_shared(1));
+ std::shared_ptr<C2NumbersStreamTuning> bins3(C2NumbersStreamTuning::alloc_shared(1, false, 1u));
+ bins3->m.mNumbers[0] = 100;
+ std::unique_ptr<C2NumbersStreamTuning::input> ins2_(C2NumbersStreamTuning::input::alloc_unique(1, 1u));
+ ins2_->m.mNumbers[0] = 100;
+ std::unique_ptr<const C2NumbersStreamTuning::input> ins2 = std::move(ins2_);
+ std::shared_ptr<C2NumbersStreamTuning::input> bins2(C2NumbersStreamTuning::input::alloc_shared(1));
+ std::unique_ptr<C2NumbersStreamTuning::output> outs2_(C2NumbersStreamTuning::output::alloc_unique(1, 1u));
+ outs2_->m.mNumbers[0] = 100;
+ std::unique_ptr<const C2NumbersStreamTuning::output> outs2 = std::move(outs2_);
+ std::shared_ptr<C2NumbersStreamTuning::output> bouts2(C2NumbersStreamTuning::output::alloc_shared(1));
+
+ {
+ static_assert(canCallSetPort(*bins3), "should be able to");
+ static_assert(canCallSetPort(*bins1), "should be able to");
+ static_assert(!canCallSetPort(*ins1), "should not be able to (const)");
+ static_assert(!canCallSetPort(*ins2), "should not be able to (const & type)");
+ static_assert(!canCallSetPort(*bins2), "should not be able to (type)");
+
+ // flags & invariables
+ const C2NumbersStreamTuning *S[] = { outs1.get(), ins1.get(), bouts1.get() };
+ for (const auto p : S) {
+ EXPECT_EQ(12u, p->size());
+ EXPECT_FALSE(p->isVendor());
+ EXPECT_TRUE(p->isFlexible());
+ EXPECT_FALSE(p->isGlobal());
+ EXPECT_TRUE(p->forStream());
+ EXPECT_FALSE(p->forPort());
+ }
+ const C2NumbersStreamTuning::input *SI[] = { ins2.get(), bins2.get() };
+ for (const auto p : SI) {
+ EXPECT_EQ(12u, p->size());
+ EXPECT_FALSE(p->isVendor());
+ EXPECT_TRUE(p->isFlexible());
+ EXPECT_FALSE(p->isGlobal());
+ EXPECT_TRUE(p->forStream());
+ EXPECT_FALSE(p->forPort());
+ }
+ const C2NumbersStreamTuning::output *SO[] = { outs2.get(), bouts2.get() };
+ for (const auto p : SO) {
+ EXPECT_EQ(12u, p->size());
+ EXPECT_FALSE(p->isVendor());
+ EXPECT_TRUE(p->isFlexible());
+ EXPECT_FALSE(p->isGlobal());
+ EXPECT_TRUE(p->forStream());
+ EXPECT_FALSE(p->forPort());
+ }
+
+ // port specific flags & invariables
+ EXPECT_FALSE(outs1->forInput());
+ EXPECT_TRUE(outs1->forOutput());
+
+ EXPECT_TRUE(ins1->forInput());
+ EXPECT_FALSE(ins1->forOutput());
+
+ const C2NumbersStreamTuning *S2[] = { outs1.get(), ins1.get() };
+ for (const auto p : S2) {
+ EXPECT_TRUE((bool)(*p));
+ EXPECT_FALSE(!(*p));
+ EXPECT_EQ(100, p->m.mNumbers[0]);
+ EXPECT_EQ(1u, p->stream());
+ }
+ for (const auto p : SO) {
+ EXPECT_TRUE((bool)(*p));
+ EXPECT_FALSE(!(*p));
+
+ EXPECT_FALSE(p->forInput());
+ EXPECT_TRUE(p->forOutput());
+ }
+ for (const auto p : SI) {
+ EXPECT_TRUE((bool)(*p));
+ EXPECT_FALSE(!(*p));
+
+ EXPECT_TRUE(p->forInput());
+ EXPECT_FALSE(p->forOutput());
+ }
+ const C2NumbersStreamTuning *S3[] = { bouts1.get() };
+ for (const auto p : S3) {
+ EXPECT_FALSE((bool)(*p));
+ EXPECT_TRUE(!(*p));
+
+ EXPECT_FALSE(p->forInput());
+ EXPECT_FALSE(p->forOutput());
+ EXPECT_EQ(0, p->m.mNumbers[0]);
+ }
+
+ // values
+ EXPECT_EQ(100, ins2->m.mNumbers[0]);
+ EXPECT_EQ(100, outs2->m.mNumbers[0]);
+ EXPECT_EQ(0, bins1->m.mNumbers[0]);
+ EXPECT_EQ(0, bins2->m.mNumbers[0]);
+ EXPECT_EQ(0, bouts1->m.mNumbers[0]);
+ EXPECT_EQ(0, bouts2->m.mNumbers[0]);
+
+ EXPECT_EQ(1u, ins2->stream());
+ EXPECT_EQ(1u, outs2->stream());
+ EXPECT_EQ(0u, bins1->stream());
+ EXPECT_EQ(0u, bins2->stream());
+ EXPECT_EQ(0u, bouts1->stream());
+ EXPECT_EQ(0u, bouts2->stream());
+
+ EXPECT_TRUE(*ins1 != *outs1);
+ EXPECT_TRUE(*ins1 == *ins2);
+ EXPECT_TRUE(*outs1 == *outs2);
+ EXPECT_TRUE(*bins1 == *bouts1);
+ EXPECT_TRUE(*bins2 != *bouts2);
+
+ EXPECT_TRUE(*ins1 != *bins1);
+ bins1->m.mNumbers[0] = 100;
+ EXPECT_TRUE(*ins1 != *bins1);
+ bins1->setPort(false /* output */);
+ EXPECT_TRUE(*ins1 != *bins1);
+ bins1->setStream(1u);
+ EXPECT_TRUE(*ins1 == *bins1);
+
+ EXPECT_TRUE(*ins2 != *bins2);
+ bins2->m.mNumbers[0] = 100;
+ EXPECT_TRUE(*ins2 != *bins2);
+ bins2->setStream(1u);
+ EXPECT_TRUE(*ins2 == *bins2);
+
+ bins1->setPort(true /* output */);
+ EXPECT_TRUE(*outs1 == *bins1);
+
+ EXPECT_TRUE(*outs1 != *bouts1);
+ bouts1->m.mNumbers[0] = 100;
+ EXPECT_TRUE(*outs1 != *bouts1);
+ bouts1->setPort(true /* output */);
+ EXPECT_TRUE(*outs1 != *bouts1);
+ bouts1->setStream(1u);
+ EXPECT_TRUE(*outs1 == *bouts1);
+
+ EXPECT_TRUE(*outs2 != *bouts2);
+ bouts2->m.mNumbers[0] = 100;
+ EXPECT_TRUE(*outs2 != *bouts2);
+ bouts2->setStream(1u);
+ EXPECT_TRUE(*outs2 == *bouts2);
+
+ bouts1->setPort(false /* output */);
+ EXPECT_TRUE(*ins1 == *bouts1);
+
+ // index
+ EXPECT_EQ(C2Param::Type(ins1->type()).baseIndex(), C2NumbersStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(ins1->type()).paramIndex(), kParamIndexNumbers);
+ EXPECT_EQ(ins1->type(), C2NumbersStreamTuning::input::typeIndex);
+
+ EXPECT_EQ(C2Param::Type(ins2->type()).baseIndex(), C2NumbersStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(ins2->type()).paramIndex(), kParamIndexNumbers);
+ EXPECT_EQ(ins2->type(), C2NumbersStreamTuning::input::typeIndex);
+
+ EXPECT_EQ(C2Param::Type(outs1->type()).baseIndex(), C2NumbersStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(outs1->type()).paramIndex(), kParamIndexNumbers);
+ EXPECT_EQ(outs1->type(), C2NumbersStreamTuning::output::typeIndex);
+
+ EXPECT_EQ(C2Param::Type(outs2->type()).baseIndex(), C2NumbersStruct::baseIndex);
+ EXPECT_EQ(C2Param::Type(outs2->type()).paramIndex(), kParamIndexNumbers);
+ EXPECT_EQ(outs2->type(), C2NumbersStreamTuning::output::typeIndex);
+
+ C2Param::BaseIndex index = C2NumbersStreamTuning::input::typeIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_TRUE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
+
+ index = C2NumbersStreamTuning::output::typeIndex;
+ EXPECT_FALSE(index.isVendor());
+ EXPECT_TRUE(index.isFlexible());
+ EXPECT_EQ(index.baseIndex(), kParamIndexNumbers | C2Param::BaseIndex::_kFlexibleFlag);
+ EXPECT_EQ(index.paramIndex(), kParamIndexNumbers);
+
+ C2Param::Type type = C2NumbersStreamTuning::input::typeIndex;
+ EXPECT_FALSE(type.isVendor());
+ EXPECT_TRUE(type.isFlexible());
+ EXPECT_FALSE(type.isGlobal());
+ EXPECT_TRUE(type.forInput());
+ EXPECT_FALSE(type.forOutput());
+ EXPECT_TRUE(type.forStream());
+ EXPECT_FALSE(type.forPort());
+
+ type = C2NumbersStreamTuning::output::typeIndex;
+ EXPECT_FALSE(type.isVendor());
+ EXPECT_TRUE(type.isFlexible());
+ EXPECT_FALSE(type.isGlobal());
+ EXPECT_FALSE(type.forInput());
+ EXPECT_TRUE(type.forOutput());
+ EXPECT_TRUE(type.forStream());
+ EXPECT_FALSE(type.forPort());
+
+ EXPECT_EQ(C2NumbersPortTuning::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::input::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::output::From(nullptr), nullptr);
+ EXPECT_EQ(C2NumbersTuning::From(ins1.get()), nullptr);
+ EXPECT_EQ(C2NumbersTuning::From(ins2.get()), nullptr);
+ EXPECT_EQ(C2NumbersTuning::From(outs1.get()), nullptr);
+ EXPECT_EQ(C2NumbersTuning::From(outs2.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::From(ins1.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::From(ins2.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::From(outs1.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::From(outs2.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::input::From(ins1.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::input::From(ins2.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::input::From(outs1.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::input::From(outs2.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::output::From(ins1.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::output::From(ins2.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::output::From(outs1.get()), nullptr);
+ EXPECT_EQ(C2NumbersPortTuning::output::From(outs2.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::From(ins1.get()), ins1.get());
+ EXPECT_EQ(C2NumbersStreamTuning::From(ins2.get()), (C2NumbersStreamTuning*)ins2.get());
+ EXPECT_EQ(C2NumbersStreamTuning::From(outs1.get()), outs1.get());
+ EXPECT_EQ(C2NumbersStreamTuning::From(outs2.get()), (C2NumbersStreamTuning*)outs2.get());
+ EXPECT_EQ(C2NumbersStreamTuning::input::From(ins1.get()), (C2NumbersStreamTuning::input*)ins1.get());
+ EXPECT_EQ(C2NumbersStreamTuning::input::From(ins2.get()), ins2.get());
+ EXPECT_EQ(C2NumbersStreamTuning::input::From(outs1.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::input::From(outs2.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::output::From(ins1.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::output::From(ins2.get()), nullptr);
+ EXPECT_EQ(C2NumbersStreamTuning::output::From(outs1.get()), (C2NumbersStreamTuning::output*)outs1.get());
+ EXPECT_EQ(C2NumbersStreamTuning::output::From(outs2.get()), outs2.get());
+
+ }
+
+ {
+ C2Int32Value int32Value(INT32_MIN);
+ static_assert(std::is_same<decltype(int32Value.mValue), int32_t>::value, "should be int32_t");
+ EXPECT_EQ(INT32_MIN, int32Value.mValue);
+ std::list<const C2FieldDescriptor> fields = int32Value.fieldList;
+ EXPECT_EQ(1u, fields.size());
+ EXPECT_EQ(FD::INT32, fields.cbegin()->type());
+ EXPECT_EQ(1u, fields.cbegin()->length());
+ EXPECT_EQ(C2String("value"), fields.cbegin()->name());
+ }
+
+ {
+ C2Uint32Value uint32Value(UINT32_MAX);
+ static_assert(std::is_same<decltype(uint32Value.mValue), uint32_t>::value, "should be uint32_t");
+ EXPECT_EQ(UINT32_MAX, uint32Value.mValue);
+ std::list<const C2FieldDescriptor> fields = uint32Value.fieldList;
+ EXPECT_EQ(1u, fields.size());
+ EXPECT_EQ(FD::UINT32, fields.cbegin()->type());
+ EXPECT_EQ(1u, fields.cbegin()->length());
+ EXPECT_EQ(C2String("value"), fields.cbegin()->name());
+ }
+
+ {
+ C2Int64Value int64Value(INT64_MIN);
+ static_assert(std::is_same<decltype(int64Value.mValue), int64_t>::value, "should be int64_t");
+ EXPECT_EQ(INT64_MIN, int64Value.mValue);
+ std::list<const C2FieldDescriptor> fields = int64Value.fieldList;
+ EXPECT_EQ(1u, fields.size());
+ EXPECT_EQ(FD::INT64, fields.cbegin()->type());
+ EXPECT_EQ(1u, fields.cbegin()->length());
+ EXPECT_EQ(C2String("value"), fields.cbegin()->name());
+ }
+
+ {
+ C2Uint64Value uint64Value(UINT64_MAX);
+ static_assert(std::is_same<decltype(uint64Value.mValue), uint64_t>::value, "should be uint64_t");
+ EXPECT_EQ(UINT64_MAX, uint64Value.mValue);
+ std::list<const C2FieldDescriptor> fields = uint64Value.fieldList;
+ EXPECT_EQ(1u, fields.size());
+ EXPECT_EQ(FD::UINT64, fields.cbegin()->type());
+ EXPECT_EQ(1u, fields.cbegin()->length());
+ EXPECT_EQ(C2String("value"), fields.cbegin()->name());
+ }
+
+ {
+ C2FloatValue floatValue(123.4f);
+ static_assert(std::is_same<decltype(floatValue.mValue), float>::value, "should be float");
+ EXPECT_EQ(123.4f, floatValue.mValue);
+ std::list<const C2FieldDescriptor> fields = floatValue.fieldList;
+ EXPECT_EQ(1u, fields.size());
+ EXPECT_EQ(FD::FLOAT, fields.cbegin()->type());
+ EXPECT_EQ(1u, fields.cbegin()->length());
+ EXPECT_EQ(C2String("value"), fields.cbegin()->name());
+ }
+
+ {
+ uint8_t initValue[] = "ABCD";
+ typedef C2GlobalParam<C2Setting, C2BlobValue, 0> BlobSetting;
+ std::unique_ptr<BlobSetting> blobValue = BlobSetting::alloc_unique(6, C2ConstMemoryBlock<uint8_t>(initValue));
+ static_assert(std::is_same<decltype(blobValue->m.mValue), uint8_t[]>::value, "should be uint8_t[]");
+ EXPECT_EQ(0, memcmp(blobValue->m.mValue, "ABCD\0", 6));
+ EXPECT_EQ(6u, blobValue->flexCount());
+ std::list<const C2FieldDescriptor> fields = blobValue->fieldList;
+ EXPECT_EQ(1u, fields.size());
+ EXPECT_EQ(FD::BLOB, fields.cbegin()->type());
+ EXPECT_EQ(0u, fields.cbegin()->length());
+ EXPECT_EQ(C2String("value"), fields.cbegin()->name());
+
+ blobValue = BlobSetting::alloc_unique(3, C2ConstMemoryBlock<uint8_t>(initValue));
+ EXPECT_EQ(0, memcmp(blobValue->m.mValue, "ABC", 3));
+ EXPECT_EQ(3u, blobValue->flexCount());
+ }
+
+ {
+ constexpr char initValue[] = "ABCD";
+ typedef C2GlobalParam<C2Setting, C2StringValue, 0> StringSetting;
+ std::unique_ptr<StringSetting> stringValue = StringSetting::alloc_unique(6, C2ConstMemoryBlock<char>(initValue));
+ stringValue = StringSetting::alloc_unique(6, initValue);
+ static_assert(std::is_same<decltype(stringValue->m.mValue), char[]>::value, "should be char[]");
+ EXPECT_EQ(0, memcmp(stringValue->m.mValue, "ABCD\0", 6));
+ EXPECT_EQ(6u, stringValue->flexCount());
+ std::list<const C2FieldDescriptor> fields = stringValue->fieldList;
+ EXPECT_EQ(1u, fields.size());
+ EXPECT_EQ(FD::STRING, fields.cbegin()->type());
+ EXPECT_EQ(0u, fields.cbegin()->length());
+ EXPECT_EQ(C2String("value"), fields.cbegin()->name());
+
+ stringValue = StringSetting::alloc_unique(3, C2ConstMemoryBlock<char>(initValue));
+ EXPECT_EQ(0, memcmp(stringValue->m.mValue, "AB", 3));
+ EXPECT_EQ(3u, stringValue->flexCount());
+
+ stringValue = StringSetting::alloc_unique(11, "initValue");
+ EXPECT_EQ(0, memcmp(stringValue->m.mValue, "initValue\0", 11));
+ EXPECT_EQ(11u, stringValue->flexCount());
+
+ stringValue = StringSetting::alloc_unique(initValue);
+ EXPECT_EQ(0, memcmp(stringValue->m.mValue, "ABCD", 5));
+ EXPECT_EQ(5u, stringValue->flexCount());
+
+ stringValue = StringSetting::alloc_unique({ 'A', 'B', 'C', 'D' });
+ EXPECT_EQ(0, memcmp(stringValue->m.mValue, "ABC", 4));
+ EXPECT_EQ(4u, stringValue->flexCount());
+ }
+
+ {
+ uint32_t videoWidth[] = { 12u, C2NumbersStreamTuning::output::typeIndex, 100 };
+ C2Param *p1 = C2Param::From(videoWidth, sizeof(videoWidth));
+ EXPECT_NE(nullptr, p1);
+ EXPECT_EQ(12u, p1->size());
+ EXPECT_EQ(C2NumbersStreamTuning::output::typeIndex, p1->type());
+
+ C2NumbersStreamTuning::output *vst = C2NumbersStreamTuning::output::From(p1);
+ EXPECT_NE(nullptr, vst);
+ if (vst) {
+ EXPECT_EQ(1u, vst->flexCount());
+ EXPECT_EQ(100, vst->m.mNumbers[0]);
+ }
+
+ p1 = C2Param::From(videoWidth, sizeof(videoWidth) + 2);
+ EXPECT_EQ(nullptr, p1);
+
+ p1 = C2Param::From(videoWidth, sizeof(videoWidth) - 2);
+ EXPECT_EQ(nullptr, p1);
+
+ p1 = C2Param::From(videoWidth, 3);
+ EXPECT_EQ(nullptr, p1);
+
+ p1 = C2Param::From(videoWidth, 0);
+ EXPECT_EQ(nullptr, p1);
+ }
+
+ {
+ uint32_t videoWidth[] = { 16u, C2NumbersPortTuning::input::typeIndex, 101, 102 };
+
+ C2Param *p1 = C2Param::From(videoWidth, sizeof(videoWidth));
+ EXPECT_NE(nullptr, p1);
+ EXPECT_EQ(16u, p1->size());
+ EXPECT_EQ(C2NumbersPortTuning::input::typeIndex, p1->type());
+
+ C2NumbersPortTuning::input *vpt = C2NumbersPortTuning::input::From(p1);
+ EXPECT_NE(nullptr, vpt);
+ if (vpt) {
+ EXPECT_EQ(2u, vpt->flexCount());
+ EXPECT_EQ(101, vpt->m.mNumbers[0]);
+ EXPECT_EQ(102, vpt->m.mNumbers[1]);
+ }
+
+ p1 = C2Param::From(videoWidth, sizeof(videoWidth) + 2);
+ EXPECT_EQ(nullptr, p1);
+
+ p1 = C2Param::From(videoWidth, sizeof(videoWidth) - 2);
+ EXPECT_EQ(nullptr, p1);
+
+ p1 = C2Param::From(videoWidth, 3);
+ EXPECT_EQ(nullptr, p1);
+
+ p1 = C2Param::From(videoWidth, 0);
+ EXPECT_EQ(nullptr, p1);
+ }
+}
+
+// ***********************
+
+}
+
+#include <util/C2ParamUtils.h>
+#include <C2Config.h>
+#include <C2Component.h>
+#include <unordered_map>
+
+namespace android {
+
+C2ENUM(
+ MetadataType, int32_t,
+ kInvalid = -1,
+ kNone = 0,
+ kGralloc,
+ kNativeHandle,
+ kANativeWindow,
+ kCamera,
+)
+
+enum {
+ kParamIndexVideoConfig = 0x1234,
+};
+
+struct C2VideoConfigStruct {
+ int32_t mWidth;
+ uint32_t mHeight;
+ MetadataType mMetadataType;
+ int32_t mSupportedFormats[];
+
+ C2VideoConfigStruct() {}
+
+ DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(VideoConfig, mSupportedFormats)
+ C2FIELD(mWidth, "width")
+ C2FIELD(mHeight, "height")
+ C2FIELD(mMetadataType, "metadata-type")
+ C2FIELD(mSupportedFormats, "formats")
+};
+
+typedef C2PortParam<C2Tuning, C2VideoConfigStruct> C2VideoConfigPortTuning;
+
+class MyReflector : public C2ParamReflector {
+private:
+ std::unique_ptr<C2VideoConfigPortTuning::input> inputVideoConfigTuning;
+ std::unique_ptr<C2VideoConfigPortTuning::output> outputVideoConfigTuning;
+
+public:
+ void describeSupportedValues() {
+ C2TypedFieldSupportedValues<int32_t> supportedWidths(16, 1920, 8);
+ C2FieldSupportedValues supportedWidths2(16, 1920, 8);
+
+
+ std::list<C2FieldSupportedValues> supported;
+ //supported.emplace_push(inputVideoConfigTuning->mNumber, range(16, 1920, 8));
+ //supported.emplace_push(inputVideoConfigTuning->mHeight, range(16, 1088, 8));
+ //supported.emplace_push(inputVideoConfigTuning->mMetadataType, all_enums);
+ //supported.emplace_push(inputVideoConfigTuning->mSupportedFormats, { 0, 1, 5, 7 });
+ }
+
+ virtual std::unique_ptr<android::C2StructDescriptor> describe(C2Param::BaseIndex paramType) {
+ switch (paramType.baseIndex()) {
+ case C2VideoConfigPortTuning::baseIndex:
+ return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor{
+ paramType.baseIndex(),
+ C2VideoConfigPortTuning::fieldList,
+ });
+ }
+ return nullptr;
+ }
+};
+
+class MyComponentInstance : public C2ComponentInterface {
+public:
+ virtual C2String getName() const {
+ /// \todo this seems too specific
+ return "sample.interface";
+ };
+
+ virtual node_id getId() const {
+ /// \todo how are these shared?
+ return 0;
+ }
+
+ virtual status_t commit_sm(
+ const std::vector<C2Param* const> ¶ms,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+ (void)params;
+ (void)failures;
+ return C2_UNSUPPORTED;
+ }
+
+ virtual status_t config_nb(
+ const std::vector<C2Param* const> ¶ms,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+ (void)params;
+ (void)failures;
+ return C2_UNSUPPORTED;
+ }
+
+ virtual status_t createTunnel_sm(node_id targetComponent) {
+ (void)targetComponent;
+ return C2_UNSUPPORTED;
+ }
+
+ virtual status_t query_nb(
+ const std::vector<C2Param* const> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
+ for (C2Param* const param : stackParams) {
+ if (!*param) { // param is already invalid - remember it
+ continue;
+ }
+
+ // note: this does not handle stream params (should use index...)
+ if (!mMyParams.count(param->type())) {
+ continue; // not my param
+ }
+
+ C2Param & myParam = mMyParams.find(param->type())->second;
+ if (myParam.size() != param->size()) { // incorrect size
+ param->invalidate();
+ continue;
+ }
+
+ param->updateFrom(myParam);
+ }
+
+ for (const C2Param::Index index : heapParamIndices) {
+ if (mMyParams.count(index)) {
+ C2Param & myParam = mMyParams.find(index)->second;
+ std::unique_ptr<C2Param> paramCopy(C2Param::From(&myParam, myParam.size()));
+ heapParams->push_back(std::move(paramCopy));
+ }
+ }
+
+ return C2_OK;
+ }
+
+ std::unordered_map<uint32_t, C2Param &> mMyParams;
+
+ C2ComponentDomainInfo mDomainInfo;
+
+ MyComponentInstance() {
+ mMyParams.insert({mDomainInfo.type(), mDomainInfo});
+ }
+
+ virtual status_t releaseTunnel_sm(node_id targetComponent) {
+ (void)targetComponent;
+ return C2_UNSUPPORTED;
+ }
+
+ class MyParamReflector : public C2ParamReflector {
+ const MyComponentInstance *instance;
+
+ public:
+ MyParamReflector(const MyComponentInstance *i) : instance(i) { }
+
+ virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::BaseIndex paramIndex) {
+ switch (paramIndex.baseIndex()) {
+ case decltype(instance->mDomainInfo)::baseIndex:
+ default:
+ return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor{
+ instance->mDomainInfo.type(),
+ decltype(instance->mDomainInfo)::fieldList,
+ });
+ }
+ return nullptr;
+ }
+ };
+
+ virtual status_t getSupportedValues(
+ const std::vector<const C2ParamField> fields,
+ std::vector<C2FieldSupportedValues>* const values) const {
+ for (const C2ParamField &field : fields) {
+ if (field == C2ParamField(&mDomainInfo, &C2ComponentDomainInfo::mValue)) {
+ values->push_back(C2FieldSupportedValues(
+ false /* flag */,
+ &mDomainInfo.mValue
+ //,
+ //{(int32_t)C2DomainVideo}
+ ));
+ }
+ }
+ return C2_OK;
+ }
+
+ virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
+ return std::shared_ptr<C2ParamReflector>(new MyParamReflector(this));
+ }
+
+ virtual status_t getSupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const {
+ params->push_back(std::make_shared<C2ParamDescriptor>(
+ true /* required */, "_domain", &mDomainInfo));
+ return C2_OK;
+ }
+
+ status_t getSupportedParams2(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) {
+ params->push_back(std::shared_ptr<C2ParamDescriptor>(
+ new C2ParamDescriptor(true /* required */, "_domain", &mDomainInfo)));
+ return C2_OK;
+ }
+
+};
+
+template<typename E, bool S=std::is_enum<E>::value>
+struct getter {
+ int32_t get(const C2FieldSupportedValues::Primitive &p, int32_t*) {
+ return p.i32;
+ }
+ int64_t get(const C2FieldSupportedValues::Primitive &p, int64_t*) {
+ return p.i64;
+ }
+ uint32_t get(const C2FieldSupportedValues::Primitive &p, uint32_t*) {
+ return p.u32;
+ }
+ uint64_t get(const C2FieldSupportedValues::Primitive &p, uint64_t*) {
+ return p.u64;
+ }
+ float get(const C2FieldSupportedValues::Primitive &p, float*) {
+ return p.fp;
+ }
+};
+
+template<typename E>
+struct getter<E, true> {
+ typename std::underlying_type<E>::type get(const C2FieldSupportedValues::Primitive &p, E*) {
+ using u=typename std::underlying_type<E>::type;
+ return getter<u>().get(p, (u*)0);
+ }
+};
+
+template<typename T, bool E=std::is_enum<T>::value>
+struct lax_underlying_type {
+ typedef typename std::underlying_type<T>::type type;
+};
+
+template<typename T>
+struct lax_underlying_type<T, false> {
+ typedef T type;
+};
+
+template<typename E>
+typename lax_underlying_type<E>::type get(
+ const C2FieldSupportedValues::Primitive &p, E*) {
+ return getter<E>().get(p, (E*)0);
+}
+
+template<typename T>
+void dumpFSV(const C2FieldSupportedValues &sv, T*t) {
+ using namespace std;
+ cout << (std::is_enum<T>::value ? (std::is_signed<typename std::underlying_type<T>::type>::value ? "i" : "u")
+ : std::is_integral<T>::value ? std::is_signed<T>::value ? "i" : "u" : "f")
+ << (8 * sizeof(T));
+ if (sv.type == sv.RANGE) {
+ cout << ".range(" << get(sv.range.min, t);
+ if (get(sv.range.step, t) != std::is_integral<T>::value) {
+ cout << ":" << get(sv.range.step, t);
+ }
+ if (get(sv.range.nom, t) != 1 || get(sv.range.denom, t) != 1) {
+ cout << ":" << get(sv.range.nom, t) << "/" << get(sv.range.denom, t);
+ }
+ cout << get(sv.range.max, t) << ")";
+ }
+ if (sv.values.size()) {
+ cout << (sv.type == sv.FLAGS ? ".flags(" : ".list(");
+ const char *sep = "";
+ for (const C2FieldSupportedValues::Primitive &p : sv.values) {
+ cout << sep << get(p, t);
+ sep = ",";
+ }
+ cout << ")";
+ }
+ cout << endl;
+}
+
+void dumpType(C2Param::Type type) {
+ using namespace std;
+ cout << (type.isVendor() ? "Vendor" : "C2");
+ if (type.forInput()) {
+ cout << "Input";
+ } else if (type.forOutput()) {
+ cout << "Output";
+ } else if (type.forPort() && !type.forStream()) {
+ cout << "Port";
+ }
+ if (type.forStream()) {
+ cout << "Stream";
+ }
+
+ if (type.isFlexible()) {
+ cout << "Flex";
+ }
+
+ cout << type.paramIndex();
+
+ switch (type.kind()) {
+ case C2Param::INFO: cout << "Info"; break;
+ case C2Param::SETTING: cout << "Setting"; break;
+ case C2Param::TUNING: cout << "Tuning"; break;
+ case C2Param::STRUCT: cout << "Struct"; break;
+ default: cout << "Kind" << (int32_t)type.kind(); break;
+ }
+}
+
+void dumpType(C2Param::BaseIndex type) {
+ using namespace std;
+ cout << (type.isVendor() ? "Vendor" : "C2");
+ if (type.isFlexible()) {
+ cout << "Flex";
+ }
+
+ cout << type.paramIndex() << "Struct";
+}
+
+void dumpType(FD::Type type) {
+ using namespace std;
+ switch (type) {
+ case FD::BLOB: cout << "blob "; break;
+ case FD::FLOAT: cout << "float "; break;
+ case FD::INT32: cout << "int32_t "; break;
+ case FD::INT64: cout << "int64_t "; break;
+ case FD::UINT32: cout << "uint32_t "; break;
+ case FD::UINT64: cout << "uint64_t "; break;
+ case FD::STRING: cout << "char "; break;
+ default:
+ cout << "struct ";
+ dumpType((C2Param::Type)type);
+ break;
+ }
+}
+
+void dumpStruct(const C2StructDescriptor &sd) {
+ using namespace std;
+ cout << "struct ";
+ dumpType(sd.baseIndex());
+ cout << " {" << endl;
+ //C2FieldDescriptor &f;
+ for (const C2FieldDescriptor &f : sd) {
+ PrintTo(f, &cout);
+ cout << endl;
+
+ if (f.namedValues().size()) {
+ cout << ".named(";
+ const char *sep = "";
+ for (const FD::named_value_type &p : f.namedValues()) {
+ cout << sep << p.first << "=";
+ switch (f.type()) {
+ case C2Value::INT32: cout << get(p.second, (int32_t *)0); break;
+ case C2Value::INT64: cout << get(p.second, (int64_t *)0); break;
+ case C2Value::UINT32: cout << get(p.second, (uint32_t *)0); break;
+ case C2Value::UINT64: cout << get(p.second, (uint64_t *)0); break;
+ case C2Value::FLOAT: cout << get(p.second, (float *)0); break;
+ default: cout << "???"; break;
+ }
+ sep = ",";
+ }
+ cout << ")";
+ }
+ }
+
+ cout << "};" << endl;
+}
+
+void dumpDesc(const C2ParamDescriptor &pd) {
+ using namespace std;
+ if (pd.isRequired()) {
+ cout << "required ";
+ }
+ if (pd.isPersistent()) {
+ cout << "persistent ";
+ }
+ cout << "struct ";
+ dumpType(pd.type());
+ cout << " " << pd.name() << ";" << endl;
+}
+
+TEST_F(C2ParamTest, ReflectorTest) {
+ C2ComponentDomainInfo domainInfo;
+ std::shared_ptr<C2ComponentInterface> comp(new MyComponentInstance);
+ std::vector<C2FieldSupportedValues> values;
+
+ std::unique_ptr<C2StructDescriptor> desc{
+ comp->getParamReflector()->describe(C2ComponentDomainInfo::indexFlags)};
+ dumpStruct(*desc);
+
+ EXPECT_EQ(
+ C2_OK,
+ comp->getSupportedValues(
+ { C2ParamField(&domainInfo, &C2ComponentDomainInfo::mValue) },
+ &values)
+ );
+
+ for (const C2FieldSupportedValues &sv : values) {
+ dumpFSV(sv, &domainInfo.mValue);
+ }
+}
+
+C2ENUM(Enum1, uint32_t,
+ Enum1Value1,
+ Enum1Value2,
+ Enum1Value4 = Enum1Value2 + 2,
+);
+
+C2ENUM_CUSTOM_PREFIX(Enum2, uint32_t, "Enum",
+ Enum2Value1,
+ Enum2Value2,
+ Enum2Value4 = Enum1Value2 + 2,
+);
+
+C2ENUM_CUSTOM_NAMES(Enum3, uint8_t,
+ ({ { "value1", Enum3Value1 },
+ { "value2", Enum3Value2 },
+ { "value4", Enum3Value4 },
+ { "invalid", Invalid } }),
+ Enum3Value1,
+ Enum3Value2,
+ Enum3Value4 = Enum3Value2 + 2,
+ Invalid,
+);
+
+TEST_F(C2ParamTest, EnumUtilsTest) {
+ std::vector<std::pair<C2String, Enum3>> pairs ( { { "value1", Enum3Value1 },
+ { "value2", Enum3Value2 },
+ { "value4", Enum3Value4 },
+ { "invalid", Invalid } });
+ Enum3 e3;
+ FD::namedValuesFor(e3);
+}
+
+TEST_F(C2ParamTest, ParamUtilsTest) {
+ // upper case
+ EXPECT_EQ("yes", C2ParamUtils::camelCaseToDashed("YES"));
+ EXPECT_EQ("no", C2ParamUtils::camelCaseToDashed("NO"));
+ EXPECT_EQ("yes-no", C2ParamUtils::camelCaseToDashed("YES_NO"));
+ EXPECT_EQ("yes-no", C2ParamUtils::camelCaseToDashed("YES__NO"));
+ EXPECT_EQ("a2dp", C2ParamUtils::camelCaseToDashed("A2DP"));
+ EXPECT_EQ("mp2-ts", C2ParamUtils::camelCaseToDashed("MP2_TS"));
+ EXPECT_EQ("block-2d", C2ParamUtils::camelCaseToDashed("BLOCK_2D"));
+ EXPECT_EQ("mpeg-2-ts", C2ParamUtils::camelCaseToDashed("MPEG_2_TS"));
+ EXPECT_EQ("_hidden-value", C2ParamUtils::camelCaseToDashed("_HIDDEN_VALUE"));
+ EXPECT_EQ("__hidden-value2", C2ParamUtils::camelCaseToDashed("__HIDDEN_VALUE2"));
+ EXPECT_EQ("__hidden-value-2", C2ParamUtils::camelCaseToDashed("__HIDDEN_VALUE_2"));
+
+ // camel case
+ EXPECT_EQ("yes", C2ParamUtils::camelCaseToDashed("Yes"));
+ EXPECT_EQ("no", C2ParamUtils::camelCaseToDashed("No"));
+ EXPECT_EQ("yes-no", C2ParamUtils::camelCaseToDashed("YesNo"));
+ EXPECT_EQ("yes-no", C2ParamUtils::camelCaseToDashed("Yes_No"));
+ EXPECT_EQ("mp2-ts", C2ParamUtils::camelCaseToDashed("MP2Ts"));
+ EXPECT_EQ("block-2d", C2ParamUtils::camelCaseToDashed("Block2D"));
+ EXPECT_EQ("mpeg-2-ts", C2ParamUtils::camelCaseToDashed("Mpeg2ts"));
+ EXPECT_EQ("_hidden-value", C2ParamUtils::camelCaseToDashed("_HiddenValue"));
+ EXPECT_EQ("__hidden-value-2", C2ParamUtils::camelCaseToDashed("__HiddenValue2"));
+
+ // mixed case
+ EXPECT_EQ("mp2t-s", C2ParamUtils::camelCaseToDashed("MP2T_s"));
+ EXPECT_EQ("block-2d", C2ParamUtils::camelCaseToDashed("Block_2D"));
+ EXPECT_EQ("block-2-d", C2ParamUtils::camelCaseToDashed("Block2_D"));
+ EXPECT_EQ("mpeg-2-ts", C2ParamUtils::camelCaseToDashed("Mpeg_2ts"));
+ EXPECT_EQ("mpeg-2-ts", C2ParamUtils::camelCaseToDashed("Mpeg_2_TS"));
+ EXPECT_EQ("_hidden-value", C2ParamUtils::camelCaseToDashed("_Hidden__VALUE"));
+ EXPECT_EQ("__hidden-value-2", C2ParamUtils::camelCaseToDashed("__HiddenValue_2"));
+ EXPECT_EQ("_2", C2ParamUtils::camelCaseToDashed("_2"));
+ EXPECT_EQ("__23", C2ParamUtils::camelCaseToDashed("__23"));
+}
+
+TEST_F(C2ParamTest, C2ValueTest) {
+ C2Value val;
+ int32_t i32 = -32;
+ int64_t i64 = -64;
+ uint32_t u32 = 32;
+ uint64_t u64 = 64;
+ float fp = 1.5f;
+
+ EXPECT_EQ(C2Value::NO_INIT, val.type());
+ EXPECT_EQ(false, val.get(&i32));
+ EXPECT_EQ(-32, i32);
+ EXPECT_EQ(false, val.get(&i64));
+ EXPECT_EQ(-64, i64);
+ EXPECT_EQ(false, val.get(&u32));
+ EXPECT_EQ(32u, u32);
+ EXPECT_EQ(false, val.get(&u64));
+ EXPECT_EQ(64u, u64);
+ EXPECT_EQ(false, val.get(&fp));
+ EXPECT_EQ(1.5f, fp);
+
+ val = int32_t(-3216);
+ EXPECT_EQ(C2Value::INT32, val.type());
+ EXPECT_EQ(true, val.get(&i32));
+ EXPECT_EQ(-3216, i32);
+ EXPECT_EQ(false, val.get(&i64));
+ EXPECT_EQ(-64, i64);
+ EXPECT_EQ(false, val.get(&u32));
+ EXPECT_EQ(32u, u32);
+ EXPECT_EQ(false, val.get(&u64));
+ EXPECT_EQ(64u, u64);
+ EXPECT_EQ(false, val.get(&fp));
+ EXPECT_EQ(1.5f, fp);
+
+ val = uint32_t(3216);
+ EXPECT_EQ(C2Value::UINT32, val.type());
+ EXPECT_EQ(false, val.get(&i32));
+ EXPECT_EQ(-3216, i32);
+ EXPECT_EQ(false, val.get(&i64));
+ EXPECT_EQ(-64, i64);
+ EXPECT_EQ(true, val.get(&u32));
+ EXPECT_EQ(3216u, u32);
+ EXPECT_EQ(false, val.get(&u64));
+ EXPECT_EQ(64u, u64);
+ EXPECT_EQ(false, val.get(&fp));
+ EXPECT_EQ(1.5f, fp);
+
+ val = int64_t(-6432);
+ EXPECT_EQ(C2Value::INT64, val.type());
+ EXPECT_EQ(false, val.get(&i32));
+ EXPECT_EQ(-3216, i32);
+ EXPECT_EQ(true, val.get(&i64));
+ EXPECT_EQ(-6432, i64);
+ EXPECT_EQ(false, val.get(&u32));
+ EXPECT_EQ(3216u, u32);
+ EXPECT_EQ(false, val.get(&u64));
+ EXPECT_EQ(64u, u64);
+ EXPECT_EQ(false, val.get(&fp));
+ EXPECT_EQ(1.5f, fp);
+
+ val = uint64_t(6432);
+ EXPECT_EQ(C2Value::UINT64, val.type());
+ EXPECT_EQ(false, val.get(&i32));
+ EXPECT_EQ(-3216, i32);
+ EXPECT_EQ(false, val.get(&i64));
+ EXPECT_EQ(-6432, i64);
+ EXPECT_EQ(false, val.get(&u32));
+ EXPECT_EQ(3216u, u32);
+ EXPECT_EQ(true, val.get(&u64));
+ EXPECT_EQ(6432u, u64);
+ EXPECT_EQ(false, val.get(&fp));
+ EXPECT_EQ(1.5f, fp);
+
+ val = 15.25f;
+ EXPECT_EQ(C2Value::FLOAT, val.type());
+ EXPECT_EQ(false, val.get(&i32));
+ EXPECT_EQ(-3216, i32);
+ EXPECT_EQ(false, val.get(&i64));
+ EXPECT_EQ(-6432, i64);
+ EXPECT_EQ(false, val.get(&u32));
+ EXPECT_EQ(3216u, u32);
+ EXPECT_EQ(false, val.get(&u64));
+ EXPECT_EQ(6432u, u64);
+ EXPECT_EQ(true, val.get(&fp));
+ EXPECT_EQ(15.25f, fp);
+}
+
+} // namespace android
diff --git a/media/libstagefright/codec2/tests/C2_test.cpp b/media/libstagefright/codec2/tests/C2_test.cpp
new file mode 100644
index 0000000..92a3d91
--- /dev/null
+++ b/media/libstagefright/codec2/tests/C2_test.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2_test"
+
+#include <gtest/gtest.h>
+
+#include <C2.h>
+
+namespace android {
+
+/* ======================================= STATIC TESTS ======================================= */
+
+template<int N>
+struct c2_const_checker
+{
+ inline constexpr static int num() { return N; }
+};
+
+constexpr auto min_i32_i32 = c2_min(int32_t(1), int32_t(2));
+static_assert(std::is_same<decltype(min_i32_i32), const int32_t>::value, "should be int32_t");
+constexpr auto min_i32_i64 = c2_min(int32_t(3), int64_t(2));
+static_assert(std::is_same<decltype(min_i32_i64), const int64_t>::value, "should be int64_t");
+constexpr auto min_i8_i32 = c2_min(int8_t(0xff), int32_t(0xffffffff));
+static_assert(std::is_same<decltype(min_i8_i32), const int32_t>::value, "should be int32_t");
+
+static_assert(c2_const_checker<min_i32_i32>::num() == 1, "should be 1");
+static_assert(c2_const_checker<min_i32_i64>::num() == 2, "should be 2");
+static_assert(c2_const_checker<min_i8_i32>::num() == 0xffffffff, "should be 0xffffffff");
+
+constexpr auto min_u32_u32 = c2_min(uint32_t(1), uint32_t(2));
+static_assert(std::is_same<decltype(min_u32_u32), const uint32_t>::value, "should be uint32_t");
+constexpr auto min_u32_u64 = c2_min(uint32_t(3), uint64_t(2));
+static_assert(std::is_same<decltype(min_u32_u64), const uint32_t>::value, "should be uint32_t");
+constexpr auto min_u32_u8 = c2_min(uint32_t(0xffffffff), uint8_t(0xff));
+static_assert(std::is_same<decltype(min_u32_u8), const uint8_t>::value, "should be uint8_t");
+
+static_assert(c2_const_checker<min_u32_u32>::num() == 1, "should be 1");
+static_assert(c2_const_checker<min_u32_u64>::num() == 2, "should be 2");
+static_assert(c2_const_checker<min_u32_u8>::num() == 0xff, "should be 0xff");
+
+constexpr auto max_i32_i32 = c2_max(int32_t(1), int32_t(2));
+static_assert(std::is_same<decltype(max_i32_i32), const int32_t>::value, "should be int32_t");
+constexpr auto max_i32_i64 = c2_max(int32_t(3), int64_t(2));
+static_assert(std::is_same<decltype(max_i32_i64), const int64_t>::value, "should be int64_t");
+constexpr auto max_i8_i32 = c2_max(int8_t(0xff), int32_t(0xffffffff));
+static_assert(std::is_same<decltype(max_i8_i32), const int32_t>::value, "should be int32_t");
+
+static_assert(c2_const_checker<max_i32_i32>::num() == 2, "should be 2");
+static_assert(c2_const_checker<max_i32_i64>::num() == 3, "should be 3");
+static_assert(c2_const_checker<max_i8_i32>::num() == 0xffffffff, "should be 0xffffffff");
+
+constexpr auto max_u32_u32 = c2_max(uint32_t(1), uint32_t(2));
+static_assert(std::is_same<decltype(max_u32_u32), const uint32_t>::value, "should be uint32_t");
+constexpr auto max_u32_u64 = c2_max(uint32_t(3), uint64_t(2));
+static_assert(std::is_same<decltype(max_u32_u64), const uint64_t>::value, "should be uint64_t");
+constexpr auto max_u32_u8 = c2_max(uint32_t(0x7fffffff), uint8_t(0xff));
+static_assert(std::is_same<decltype(max_u32_u8), const uint32_t>::value, "should be uint32_t");
+
+static_assert(c2_const_checker<max_u32_u32>::num() == 2, "should be 2");
+static_assert(c2_const_checker<max_u32_u64>::num() == 3, "should be 3");
+static_assert(c2_const_checker<max_u32_u8>::num() == 0x7fffffff, "should be 0x7fffffff");
+
+} // namespace android
diff --git a/media/libstagefright/codec2/tests/vndk/C2UtilTest.cpp b/media/libstagefright/codec2/tests/vndk/C2UtilTest.cpp
new file mode 100644
index 0000000..7a1374b
--- /dev/null
+++ b/media/libstagefright/codec2/tests/vndk/C2UtilTest.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#include <util/_C2MacroUtils.h>
+
+/** \file
+ * Tests for vndk/util.
+ */
+
+/* --------------------------------------- _C2MacroUtils --------------------------------------- */
+
+static_assert(0 == _C2_ARGC(), "should be 0");
+static_assert(1 == _C2_ARGC(1), "should be 1");
+static_assert(2 == _C2_ARGC(1, 2), "should be 2");
+static_assert(64 == _C2_ARGC(
+ 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), "should be 64");
+
+static_assert(0 == _C2_ARGC(,), "should be 0");
+static_assert(1 == _C2_ARGC(1,), "should be 1");
+static_assert(2 == _C2_ARGC(1, 2,), "should be 2");
+static_assert(64 == _C2_ARGC(
+ 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,), "should be 64");
+
diff --git a/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h b/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h
new file mode 100644
index 0000000..edae303
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2UTILS_PARAM_UTILS_H_
+#define C2UTILS_PARAM_UTILS_H_
+
+#include <C2Param.h>
+#include <util/_C2MacroUtils.h>
+
+#include <iostream>
+
+/** \file
+ * Utilities for parameter handling to be used by Codec2 implementations.
+ */
+
+namespace android {
+
+/// \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
+
+#define DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, ...) \
+template<> C2FieldDescriptor::named_values_type C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
+ return C2ParamUtils::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_CUSTOM_HELPER(name, type, names, ...) \
+template<> C2FieldDescriptor::named_values_type C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
+ return C2ParamUtils::customEnumValues( \
+ std::vector<std::pair<C2StringLiteral, name>> names); \
+}
+
+
+class C2ParamUtils {
+private:
+ static size_t countLeadingUnderscores(C2StringLiteral a) {
+ size_t i = 0;
+ while (a[i] == '_') {
+ ++i;
+ }
+ return i;
+ }
+
+ static size_t countMatching(C2StringLiteral a, const C2String &b) {
+ for (size_t i = 0; i < b.size(); ++i) {
+ if (!a[i] || a[i] != b[i]) {
+ return i;
+ }
+ }
+ return b.size();
+ }
+
+ // ABCDef => abc-def
+ // ABCD2ef => abcd2-ef // 0
+ // ABCD2Ef => ancd2-ef // -1
+ // AbcDef => abc-def // -1
+ // Abc2Def => abc-2def
+ // Abc2def => abc-2-def
+ // _Yo => _yo
+ // _yo => _yo
+ // C2_yo => c2-yo
+ // C2__yo => c2-yo
+
+ static C2String camelCaseToDashed(C2String name) {
+ enum {
+ kNone = '.',
+ kLower = 'a',
+ kUpper = 'A',
+ kDigit = '1',
+ kDash = '-',
+ kUnderscore = '_',
+ } type = kNone;
+ size_t word_start = 0;
+ for (size_t ix = 0; ix < name.size(); ++ix) {
+ /* std::cout << name.substr(0, word_start) << "|"
+ << name.substr(word_start, ix - word_start) << "["
+ << name.substr(ix, 1) << "]" << name.substr(ix + 1)
+ << ": " << (char)type << std::endl; */
+ if (isupper(name[ix])) {
+ if (type == kLower) {
+ name.insert(ix++, 1, '-');
+ word_start = ix;
+ }
+ name[ix] = tolower(name[ix]);
+ type = kUpper;
+ } else if (islower(name[ix])) {
+ if (type == kDigit && ix > 0) {
+ name.insert(ix++, 1, '-');
+ word_start = ix;
+ } else if (type == kUpper && ix > word_start + 1) {
+ name.insert(ix++ - 1, 1, '-');
+ word_start = ix - 1;
+ }
+ type = kLower;
+ } else if (isdigit(name[ix])) {
+ if (type == kLower) {
+ name.insert(ix++, 1, '-');
+ word_start = ix;
+ }
+ type = kDigit;
+ } else if (name[ix] == '_') {
+ if (type == kDash) {
+ name.erase(ix--, 1);
+ } else if (type != kNone && type != kUnderscore) {
+ name[ix] = '-';
+ type = kDash;
+ word_start = ix + 1;
+ } else {
+ type = kUnderscore;
+ word_start = ix + 1;
+ }
+ } else {
+ name.resize(ix);
+ }
+ }
+ // std::cout << "=> " << name << std::endl;
+ return name;
+ }
+
+ static std::vector<C2String> sanitizeEnumValueNames(
+ const std::vector<C2StringLiteral> names,
+ C2StringLiteral _prefix = NULL) {
+ std::vector<C2String> sanitizedNames;
+ C2String prefix;
+ size_t extraUnderscores = 0;
+ bool first = true;
+ if (_prefix) {
+ extraUnderscores = countLeadingUnderscores(_prefix);
+ prefix = _prefix + extraUnderscores;
+ first = false;
+ // std::cout << "prefix:" << prefix << ", underscores:" << extraUnderscores << std::endl;
+ }
+
+ // calculate prefix and minimum leading underscores
+ for (C2StringLiteral s : names) {
+ // std::cout << s << std::endl;
+ size_t underscores = countLeadingUnderscores(s);
+ if (first) {
+ extraUnderscores = underscores;
+ prefix = s + underscores;
+ first = false;
+ } else {
+ size_t matching = countMatching(
+ s + underscores,
+ prefix);
+ prefix.resize(matching);
+ extraUnderscores = std::min(underscores, extraUnderscores);
+ }
+ // std::cout << "prefix:" << prefix << ", underscores:" << extraUnderscores << std::endl;
+ if (prefix.size() == 0 && extraUnderscores == 0) {
+ break;
+ }
+ }
+
+ // we swallow the first underscore after upper case prefixes
+ bool upperCasePrefix = true;
+ for (size_t i = 0; i < prefix.size(); ++i) {
+ if (islower(prefix[i])) {
+ upperCasePrefix = false;
+ break;
+ }
+ }
+
+ for (C2StringLiteral s : names) {
+ size_t underscores = countLeadingUnderscores(s);
+ C2String sanitized = C2String(s, underscores - extraUnderscores);
+ sanitized.append(s + prefix.size() + underscores +
+ (upperCasePrefix && s[prefix.size() + underscores] == '_'));
+ sanitizedNames.push_back(camelCaseToDashed(sanitized));
+ }
+
+ for (C2String s : sanitizedNames) {
+ std::cout << s << std::endl;
+ }
+
+ return sanitizedNames;
+ }
+
+ friend class C2ParamTest_ParamUtilsTest_Test;
+
+public:
+ static std::vector<C2String> getEnumValuesFromString(C2StringLiteral value) {
+ std::vector<C2String> foundNames;
+ size_t pos = 0, len = strlen(value);
+ do {
+ size_t endPos = strcspn(value + pos, " ,=") + pos;
+ if (endPos > pos) {
+ foundNames.emplace_back(value + pos, endPos - pos);
+ }
+ if (value[endPos] && value[endPos] != ',') {
+ endPos += strcspn(value + endPos, ",");
+ }
+ pos = strspn(value + endPos, " ,") + endPos;
+ } while (pos < len);
+ return foundNames;
+ }
+
+ template<typename T>
+ static C2FieldDescriptor::named_values_type sanitizeEnumValues(
+ std::vector<T> values,
+ std::vector<C2StringLiteral> names,
+ C2StringLiteral prefix = NULL) {
+ C2FieldDescriptor::named_values_type 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 C2FieldDescriptor::named_values_type customEnumValues(
+ std::vector<std::pair<C2StringLiteral, E>> items) {
+ C2FieldDescriptor::named_values_type namedValues;
+ for (auto &item : items) {
+ namedValues.emplace_back(item.first, item.second);
+ }
+ return namedValues;
+ }
+};
+
+/* ---------------------------- UTILITIES FOR PARAMETER REFLECTION ---------------------------- */
+
+/* ======================== UTILITY TEMPLATES FOR PARAMETER REFLECTION ======================== */
+
+#if 1
+template<typename... Params>
+class C2_HIDE _C2Tuple { };
+
+C2_HIDE
+void addC2Params(std::list<const C2FieldDescriptor> &, _C2Tuple<> *) {
+}
+
+template<typename T, typename... Params>
+C2_HIDE
+void addC2Params(std::list<const C2FieldDescriptor> &fields, _C2Tuple<T, Params...> *)
+{
+ //C2Param::index_t index = T::baseIndex;
+ //(void)index;
+ fields.insert(fields.end(), T::fieldList);
+ addC2Params(fields, (_C2Tuple<Params...> *)nullptr);
+}
+
+template<typename... Params>
+C2_HIDE
+std::list<const C2FieldDescriptor> describeC2Params() {
+ std::list<const C2FieldDescriptor> fields;
+ addC2Params(fields, (_C2Tuple<Params...> *)nullptr);
+ return fields;
+}
+
+#endif
+
+/* ---------------------------- UTILITIES FOR ENUMERATION REFLECTION ---------------------------- */
+
+} // namespace android
+
+#endif // C2UTILS_PARAM_UTILS_H_
+
diff --git a/media/libstagefright/codec2/vndk/include/util/_C2MacroUtils.h b/media/libstagefright/codec2/vndk/include/util/_C2MacroUtils.h
new file mode 100644
index 0000000..04e9ba5
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/util/_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/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index cecc52b..e2bba25 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -49,58 +49,10 @@
(IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
static const CodecProfileLevel kProfileLevels[] = {
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel42 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel5 },
- { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel51 },
{ OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel52 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel1 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel1b },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel11 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel12 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel13 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel2 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel21 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel22 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel3 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel31 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel32 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel4 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel41 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel42 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel5 },
- { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel51 },
{ OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel52 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel1 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel1b },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel11 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel12 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel13 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel2 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel21 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel22 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel3 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel31 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel32 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel4 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel41 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel42 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel5 },
- { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel51 },
{ OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel52 },
};
@@ -120,7 +72,8 @@
mIvColorFormat(IV_YUV_420P),
mChangingResolution(false),
mSignalledError(false),
- mStride(mWidth){
+ mStride(mWidth),
+ mInputOffset(0){
initPorts(
1 /* numMinInputBuffers */, kNumBuffers, INPUT_BUF_SIZE,
1 /* numMinOutputBuffers */, kNumBuffers, CODEC_MIME_TYPE);
@@ -215,6 +168,7 @@
status_t SoftAVC::resetPlugin() {
mIsInFlush = false;
mReceivedEOS = false;
+ mInputOffset = 0;
memset(mTimeStamps, 0, sizeof(mTimeStamps));
memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
@@ -443,8 +397,8 @@
if (inHeader) {
ps_dec_ip->u4_ts = timeStampIx;
ps_dec_ip->pv_stream_buffer =
- inHeader->pBuffer + inHeader->nOffset;
- ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
+ inHeader->pBuffer + inHeader->nOffset + mInputOffset;
+ ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen - mInputOffset;
} else {
ps_dec_ip->u4_ts = 0;
ps_dec_ip->pv_stream_buffer = NULL;
@@ -515,6 +469,8 @@
void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
UNUSED(portIndex);
+ OMX_BUFFERHEADERTYPE *inHeader = NULL;
+ BufferInfo *inInfo = NULL;
if (mSignalledError) {
return;
@@ -541,17 +497,11 @@
List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
while (!outQueue.empty()) {
- BufferInfo *inInfo;
- OMX_BUFFERHEADERTYPE *inHeader;
-
BufferInfo *outInfo;
OMX_BUFFERHEADERTYPE *outHeader;
- size_t timeStampIx;
+ size_t timeStampIx = 0;
- inInfo = NULL;
- inHeader = NULL;
-
- if (!mIsInFlush) {
+ if (!mIsInFlush && (NULL == inHeader)) {
if (!inQueue.empty()) {
inInfo = *inQueue.begin();
inHeader = inInfo->mHeader;
@@ -618,7 +568,7 @@
return;
}
// If input dump is enabled, then write to file
- DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes);
+ DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes, mInputOffset);
GETTIME(&mTimeStart, NULL);
/* Compute time elapsed between end of previous decode()
@@ -734,24 +684,26 @@
resetPlugin();
}
}
+ mInputOffset += s_dec_op.u4_num_bytes_consumed;
}
-
- /* If input EOS is seen and decoder is not in flush mode,
- * set the decoder in flush mode.
- * There can be a case where EOS is sent along with last picture data
- * In that case, only after decoding that input data, decoder has to be
- * put in flush. This case is handled here */
-
- if (mReceivedEOS && !mIsInFlush) {
- setFlushMode();
- }
-
- if (inHeader != NULL) {
+ // If more than 4 bytes are remaining in input, then do not release it
+ if (inHeader != NULL && ((inHeader->nFilledLen - mInputOffset) <= 4)) {
inInfo->mOwnedByUs = false;
inQueue.erase(inQueue.begin());
inInfo = NULL;
notifyEmptyBufferDone(inHeader);
inHeader = NULL;
+ mInputOffset = 0;
+
+ /* If input EOS is seen and decoder is not in flush mode,
+ * set the decoder in flush mode.
+ * There can be a case where EOS is sent along with last picture data
+ * In that case, only after decoding that input data, decoder has to be
+ * put in flush. This case is handled here */
+
+ if (mReceivedEOS && !mIsInFlush) {
+ setFlushMode();
+ }
}
}
}
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.h b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
index b333190..2a71188 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.h
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
@@ -99,6 +99,7 @@
bool mFlushNeeded;
bool mSignalledError;
size_t mStride;
+ size_t mInputOffset;
status_t initDecoder();
status_t deInitDecoder();
@@ -143,10 +144,10 @@
ALOGD("Could not open file %s", m_filename); \
} \
}
-#define DUMP_TO_FILE(m_filename, m_buf, m_size) \
+#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)\
{ \
FILE *fp = fopen(m_filename, "ab"); \
- if (fp != NULL && m_buf != NULL) { \
+ if (fp != NULL && m_buf != NULL && m_offset == 0) { \
int i; \
i = fwrite(m_buf, 1, m_size, fp); \
ALOGD("fwrite ret %d to write %d", i, m_size); \
@@ -154,10 +155,12 @@
ALOGD("Error in fwrite, returned %d", i); \
perror("Error in write to file"); \
} \
- fclose(fp); \
- } else { \
+ } else if (fp == NULL) { \
ALOGD("Could not write to file %s", m_filename);\
} \
+ if (fp) { \
+ fclose(fp); \
+ } \
}
#else /* FILE_DUMP_ENABLE */
#define INPUT_DUMP_PATH
@@ -166,7 +169,7 @@
#define OUTPUT_DUMP_EXT
#define GENERATE_FILE_NAMES()
#define CREATE_DUMP_FILE(m_filename)
-#define DUMP_TO_FILE(m_filename, m_buf, m_size)
+#define DUMP_TO_FILE(m_filename, m_buf, m_size, m_offset)
#endif /* FILE_DUMP_ENABLE */
} // namespace android
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
index 5c70387..a3fd336 100644
--- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
@@ -48,14 +48,6 @@
(IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
static const CodecProfileLevel kProfileLevels[] = {
- { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel1 },
- { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel2 },
- { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel21 },
- { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel3 },
- { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel31 },
- { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel4 },
- { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel41 },
- { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel5 },
{ OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 },
};
diff --git a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
index 5ed037a..ce28faf 100644
--- a/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
+++ b/media/libstagefright/codecs/mpeg2dec/SoftMPEG2.cpp
@@ -47,14 +47,8 @@
(IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_NUM_CORES
static const CodecProfileLevel kProfileLevels[] = {
- { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelLL },
- { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelML },
- { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelH14 },
{ OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelHL },
- { OMX_VIDEO_MPEG2ProfileMain , OMX_VIDEO_MPEG2LevelLL },
- { OMX_VIDEO_MPEG2ProfileMain , OMX_VIDEO_MPEG2LevelML },
- { OMX_VIDEO_MPEG2ProfileMain , OMX_VIDEO_MPEG2LevelH14 },
{ OMX_VIDEO_MPEG2ProfileMain , OMX_VIDEO_MPEG2LevelHL },
};
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index e3d2ec6..82a2627 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -39,6 +39,12 @@
namespace android {
+namespace {
+
+static constexpr int USB_CONTROL_TRANSFER_TIMEOUT_MS = 200;
+
+} // namespace
+
#if 0
static bool isMtpDevice(uint16_t vendor, uint16_t product) {
// Sandisk Sansa Fuze
@@ -84,15 +90,18 @@
interface->bInterfaceSubClass == 1 && // Still Image Capture
interface->bInterfaceProtocol == 1) // Picture Transfer Protocol (PIMA 15470)
{
- char* manufacturerName = usb_device_get_manufacturer_name(device);
- char* productName = usb_device_get_product_name(device);
+ char* manufacturerName = usb_device_get_manufacturer_name(device,
+ USB_CONTROL_TRANSFER_TIMEOUT_MS);
+ char* productName = usb_device_get_product_name(device,
+ USB_CONTROL_TRANSFER_TIMEOUT_MS);
ALOGD("Found camera: \"%s\" \"%s\"\n", manufacturerName, productName);
free(manufacturerName);
free(productName);
} else if (interface->bInterfaceClass == 0xFF &&
interface->bInterfaceSubClass == 0xFF &&
interface->bInterfaceProtocol == 0) {
- char* interfaceName = usb_device_get_string(device, interface->iInterface);
+ char* interfaceName = usb_device_get_string(device, interface->iInterface,
+ USB_CONTROL_TRANSFER_TIMEOUT_MS);
if (!interfaceName) {
continue;
} else if (strcmp(interfaceName, "MTP")) {
@@ -102,8 +111,10 @@
free(interfaceName);
// Looks like an android style MTP device
- char* manufacturerName = usb_device_get_manufacturer_name(device);
- char* productName = usb_device_get_product_name(device);
+ char* manufacturerName = usb_device_get_manufacturer_name(device,
+ USB_CONTROL_TRANSFER_TIMEOUT_MS);
+ char* productName = usb_device_get_product_name(device,
+ USB_CONTROL_TRANSFER_TIMEOUT_MS);
ALOGD("Found MTP device: \"%s\" \"%s\"\n", manufacturerName, productName);
free(manufacturerName);
free(productName);
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 4b32691..c60b49a 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -234,9 +234,9 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle,
+ audio_patch_handle_t *handle,
uid_t uid) = 0;
- virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+ virtual status_t stopAudioSource(audio_patch_handle_t handle) = 0;
virtual status_t setMasterMono(bool mono) = 0;
virtual status_t getMasterMono(bool *mono) = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
index 4ab7cf0..7e1e24d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
@@ -50,7 +50,7 @@
};
class AudioSourceCollection :
- public DefaultKeyedVector< audio_io_handle_t, sp<AudioSourceDescriptor> >
+ public DefaultKeyedVector< audio_patch_handle_t, sp<AudioSourceDescriptor> >
{
public:
status_t dump(int fd) const;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 7c955e5..2f01b02 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -3026,7 +3026,7 @@
status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle,
+ audio_patch_handle_t *handle,
uid_t uid)
{
ALOGV("%s source %p attributes %p handle %p", __FUNCTION__, source, attributes, handle);
@@ -3034,7 +3034,7 @@
return BAD_VALUE;
}
- *handle = AUDIO_IO_HANDLE_NONE;
+ *handle = AUDIO_PATCH_HANDLE_NONE;
if (source->role != AUDIO_PORT_ROLE_SOURCE ||
source->type != AUDIO_PORT_TYPE_DEVICE) {
@@ -3141,7 +3141,7 @@
return NO_ERROR;
}
-status_t AudioPolicyManager::stopAudioSource(audio_io_handle_t handle __unused)
+status_t AudioPolicyManager::stopAudioSource(audio_patch_handle_t handle __unused)
{
sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueFor(handle);
ALOGV("%s handle %d", __FUNCTION__, handle);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 46f0625..52fa082 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -228,9 +228,9 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle,
+ audio_patch_handle_t *handle,
uid_t uid);
- virtual status_t stopAudioSource(audio_io_handle_t handle);
+ virtual status_t stopAudioSource(audio_patch_handle_t handle);
virtual status_t setMasterMono(bool mono);
virtual status_t getMasterMono(bool *mono);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index f6da920..53c54bb 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -712,7 +712,7 @@
status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle)
+ audio_patch_handle_t *handle)
{
Mutex::Autolock _l(mLock);
if (mAudioPolicyManager == NULL) {
@@ -723,7 +723,7 @@
IPCThreadState::self()->getCallingUid());
}
-status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle)
+status_t AudioPolicyService::stopAudioSource(audio_patch_handle_t handle)
{
Mutex::Autolock _l(mLock);
if (mAudioPolicyManager == NULL) {
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index 517fba1..a5b96fe 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -610,12 +610,12 @@
status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle)
+ audio_patch_handle_t *handle)
{
return INVALID_OPERATION;
}
-status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle)
+status_t AudioPolicyService::stopAudioSource(audio_patch_handle_t handle)
{
return INVALID_OPERATION;
}
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index f34473c..a310735 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -200,8 +200,8 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle);
- virtual status_t stopAudioSource(audio_io_handle_t handle);
+ audio_patch_handle_t *handle);
+ virtual status_t stopAudioSource(audio_patch_handle_t handle);
virtual status_t setMasterMono(bool mono);
virtual status_t getMasterMono(bool *mono);