blob: 7861af87fce8293f6a24032dd55677e1115e22ff [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <aidl/android/hardware/graphics/common/BlendMode.h>
#include <aidl/android/hardware/graphics/common/BufferUsage.h>
#include <aidl/android/hardware/graphics/common/Cta861_3.h>
#include <aidl/android/hardware/graphics/common/Dataspace.h>
#include <aidl/android/hardware/graphics/common/ExtendableType.h>
#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
#include <aidl/android/hardware/graphics/common/PlaneLayoutComponent.h>
#include <aidl/android/hardware/graphics/common/Rect.h>
#include <aidl/android/hardware/graphics/common/Smpte2086.h>
#include <aidl/android/hardware/graphics/common/StandardMetadataType.h>
#include <aidl/android/hardware/graphics/common/XyColor.h>
#include <android/hardware/graphics/mapper/IMapper.h>
#include <cinttypes>
#include <string_view>
#include <type_traits>
#include <vector>
namespace android::hardware::graphics::mapper {
using ::aidl::android::hardware::graphics::common::BlendMode;
using ::aidl::android::hardware::graphics::common::BufferUsage;
using ::aidl::android::hardware::graphics::common::Cta861_3;
using ::aidl::android::hardware::graphics::common::Dataspace;
using ::aidl::android::hardware::graphics::common::ExtendableType;
using ::aidl::android::hardware::graphics::common::PixelFormat;
using ::aidl::android::hardware::graphics::common::PlaneLayout;
using ::aidl::android::hardware::graphics::common::PlaneLayoutComponent;
using ::aidl::android::hardware::graphics::common::Rect;
using ::aidl::android::hardware::graphics::common::Smpte2086;
using ::aidl::android::hardware::graphics::common::StandardMetadataType;
using ::aidl::android::hardware::graphics::common::XyColor;
class MetadataWriter {
private:
uint8_t* _Nonnull mDest;
size_t mSizeRemaining = 0;
int32_t mDesiredSize = 0;
void* _Nullable reserve(size_t sizeToWrite) {
if (mDesiredSize < 0) {
// Error state
return nullptr;
}
if (__builtin_add_overflow(mDesiredSize, sizeToWrite, &mDesiredSize)) {
// Overflowed, abort writing any further data
mDesiredSize = -AIMAPPER_ERROR_BAD_VALUE;
mSizeRemaining = 0;
return nullptr;
}
if (sizeToWrite > mSizeRemaining) {
mSizeRemaining = 0;
return nullptr;
} else {
mSizeRemaining -= sizeToWrite;
uint8_t* whereToWrite = mDest;
mDest += sizeToWrite;
return whereToWrite;
}
}
public:
explicit MetadataWriter(void* _Nullable destBuffer, size_t destBufferSize)
: mDest(reinterpret_cast<uint8_t*>(destBuffer)), mSizeRemaining(destBufferSize) {}
int32_t desiredSize() const { return mDesiredSize; }
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
MetadataWriter& write(T value) {
auto sizeToWrite = sizeof(T);
if (void* dest = reserve(sizeToWrite)) {
memcpy(dest, &value, sizeToWrite);
}
return *this;
}
MetadataWriter& write(float value) {
auto sizeToWrite = sizeof(float);
if (void* dest = reserve(sizeToWrite)) {
memcpy(dest, &value, sizeToWrite);
}
return *this;
}
MetadataWriter& write(const std::string_view& value) {
auto sizeToWrite = value.length();
write<int64_t>(sizeToWrite);
if (void* dest = reserve(sizeToWrite)) {
memcpy(dest, value.data(), sizeToWrite);
}
return *this;
}
MetadataWriter& write(const std::vector<uint8_t>& value) {
auto sizeToWrite = value.size();
write<int64_t>(sizeToWrite);
if (void* dest = reserve(sizeToWrite)) {
memcpy(dest, value.data(), sizeToWrite);
}
return *this;
}
MetadataWriter& write(const ExtendableType& value) {
return write(value.name).write(value.value);
}
MetadataWriter& write(const XyColor& value) { return write(value.x).write(value.y); }
};
class MetadataReader {
private:
const uint8_t* _Nonnull mSrc;
size_t mSizeRemaining = 0;
bool mOk = true;
const void* _Nullable advance(size_t size) {
if (mOk && mSizeRemaining >= size) {
const void* buf = mSrc;
mSrc += size;
mSizeRemaining -= size;
return buf;
}
mOk = false;
return nullptr;
}
public:
explicit MetadataReader(const void* _Nonnull metadata, size_t metadataSize)
: mSrc(reinterpret_cast<const uint8_t*>(metadata)), mSizeRemaining(metadataSize) {}
[[nodiscard]] size_t remaining() const { return mSizeRemaining; }
[[nodiscard]] bool ok() const { return mOk; }
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
MetadataReader& read(T& dest) {
if (const void* src = advance(sizeof(T))) {
memcpy(&dest, src, sizeof(T));
}
return *this;
}
MetadataReader& read(float& dest) {
if (const void* src = advance(sizeof(float))) {
memcpy(&dest, src, sizeof(float));
}
return *this;
}
MetadataReader& read(std::string& dest) {
dest = readString();
return *this;
}
MetadataReader& read(ExtendableType& dest) {
dest.name = readString();
read(dest.value);
return *this;
}
MetadataReader& read(XyColor& dest) {
read(dest.x);
read(dest.y);
return *this;
}
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
[[nodiscard]] std::optional<T> readInt() {
auto sizeToRead = sizeof(T);
if (const void* src = advance(sizeof(T))) {
T ret;
memcpy(&ret, src, sizeToRead);
return ret;
}
return std::nullopt;
}
[[nodiscard]] std::string_view readString() {
auto lengthOpt = readInt<int64_t>();
if (!lengthOpt) {
return std::string_view{};
}
size_t length = lengthOpt.value();
if (const void* src = advance(length)) {
return std::string_view{reinterpret_cast<const char*>(src), length};
}
return std::string_view{};
}
[[nodiscard]] std::optional<ExtendableType> readExtendable() {
ExtendableType ret;
ret.name = readString();
auto value = readInt<int64_t>();
if (value) {
ret.value = value.value();
return ret;
} else {
return std::nullopt;
}
}
[[nodiscard]] std::vector<uint8_t> readBuffer() {
std::vector<uint8_t> ret;
size_t length = readInt<int64_t>().value_or(0);
if (const void* src = advance(length)) {
ret.resize(length);
memcpy(ret.data(), src, length);
}
return ret;
}
};
template <typename T, class Enable = void>
struct MetadataValue {};
template <typename T>
struct MetadataValue<T, std::enable_if_t<std::is_integral_v<T>>> {
[[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
size_t destBufferSize) {
return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
}
[[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
size_t metadataSize) {
return MetadataReader{metadata, metadataSize}.readInt<T>();
}
};
template <typename T>
struct MetadataValue<T, std::enable_if_t<std::is_enum_v<T>>> {
[[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
size_t destBufferSize) {
return MetadataWriter{destBuffer, destBufferSize}
.write(static_cast<std::underlying_type_t<T>>(value))
.desiredSize();
}
[[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
size_t metadataSize) {
std::underlying_type_t<T> temp;
return MetadataReader{metadata, metadataSize}.read(temp).ok()
? std::optional<T>(static_cast<T>(temp))
: std::nullopt;
}
};
template <>
struct MetadataValue<std::string> {
[[nodiscard]] static int32_t encode(const std::string_view& value, void* _Nullable destBuffer,
size_t destBufferSize) {
return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
}
[[nodiscard]] static std::optional<std::string> decode(const void* _Nonnull metadata,
size_t metadataSize) {
auto reader = MetadataReader{metadata, metadataSize};
auto result = reader.readString();
return reader.ok() ? std::optional<std::string>{result} : std::nullopt;
}
};
template <>
struct MetadataValue<ExtendableType> {
static_assert(sizeof(int64_t) == sizeof(ExtendableType::value));
[[nodiscard]] static int32_t encode(const ExtendableType& value, void* _Nullable destBuffer,
size_t destBufferSize) {
return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
}
[[nodiscard]] static std::optional<ExtendableType> decode(const void* _Nonnull metadata,
size_t metadataSize) {
return MetadataReader{metadata, metadataSize}.readExtendable();
}
};
template <>
struct MetadataValue<std::vector<PlaneLayout>> {
[[nodiscard]] static int32_t encode(const std::vector<PlaneLayout>& values,
void* _Nullable destBuffer, size_t destBufferSize) {
MetadataWriter writer{destBuffer, destBufferSize};
writer.write<int64_t>(values.size());
for (const auto& value : values) {
writer.write<int64_t>(value.components.size());
for (const auto& component : value.components) {
writer.write(component.type)
.write<int64_t>(component.offsetInBits)
.write<int64_t>(component.sizeInBits);
}
writer.write<int64_t>(value.offsetInBytes)
.write<int64_t>(value.sampleIncrementInBits)
.write<int64_t>(value.strideInBytes)
.write<int64_t>(value.widthInSamples)
.write<int64_t>(value.heightInSamples)
.write<int64_t>(value.totalSizeInBytes)
.write<int64_t>(value.horizontalSubsampling)
.write<int64_t>(value.verticalSubsampling);
}
return writer.desiredSize();
}
using DecodeResult = std::optional<std::vector<PlaneLayout>>;
[[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
std::vector<PlaneLayout> values;
MetadataReader reader{metadata, metadataSize};
auto numPlanes = reader.readInt<int64_t>().value_or(0);
values.reserve(numPlanes);
for (int i = 0; i < numPlanes && reader.ok(); i++) {
PlaneLayout& value = values.emplace_back();
auto numPlaneComponents = reader.readInt<int64_t>().value_or(0);
value.components.reserve(numPlaneComponents);
for (int i = 0; i < numPlaneComponents && reader.ok(); i++) {
PlaneLayoutComponent& component = value.components.emplace_back();
reader.read(component.type)
.read<int64_t>(component.offsetInBits)
.read<int64_t>(component.sizeInBits);
}
reader.read<int64_t>(value.offsetInBytes)
.read<int64_t>(value.sampleIncrementInBits)
.read<int64_t>(value.strideInBytes)
.read<int64_t>(value.widthInSamples)
.read<int64_t>(value.heightInSamples)
.read<int64_t>(value.totalSizeInBytes)
.read<int64_t>(value.horizontalSubsampling)
.read<int64_t>(value.verticalSubsampling);
}
return reader.ok() ? DecodeResult{std::move(values)} : std::nullopt;
}
};
template <>
struct MetadataValue<std::vector<Rect>> {
[[nodiscard]] static int32_t encode(const std::vector<Rect>& value, void* _Nullable destBuffer,
size_t destBufferSize) {
MetadataWriter writer{destBuffer, destBufferSize};
writer.write<int64_t>(value.size());
for (auto& rect : value) {
writer.write<int32_t>(rect.left)
.write<int32_t>(rect.top)
.write<int32_t>(rect.right)
.write<int32_t>(rect.bottom);
}
return writer.desiredSize();
}
using DecodeResult = std::optional<std::vector<Rect>>;
[[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
MetadataReader reader{metadata, metadataSize};
std::vector<Rect> value;
auto numRects = reader.readInt<int64_t>().value_or(0);
value.reserve(numRects);
for (int i = 0; i < numRects && reader.ok(); i++) {
Rect& rect = value.emplace_back();
reader.read<int32_t>(rect.left)
.read<int32_t>(rect.top)
.read<int32_t>(rect.right)
.read<int32_t>(rect.bottom);
}
return reader.ok() ? DecodeResult{std::move(value)} : std::nullopt;
}
};
template <>
struct MetadataValue<std::optional<Smpte2086>> {
[[nodiscard]] static int32_t encode(const std::optional<Smpte2086>& optValue,
void* _Nullable destBuffer, size_t destBufferSize) {
if (optValue.has_value()) {
const auto& value = *optValue;
return MetadataWriter{destBuffer, destBufferSize}
.write(value.primaryRed)
.write(value.primaryGreen)
.write(value.primaryBlue)
.write(value.whitePoint)
.write(value.maxLuminance)
.write(value.minLuminance)
.desiredSize();
} else {
return 0;
}
}
// Double optional because the value type itself is an optional<>
using DecodeResult = std::optional<std::optional<Smpte2086>>;
[[nodiscard]] static DecodeResult decode(const void* _Nullable metadata, size_t metadataSize) {
std::optional<Smpte2086> optValue{std::nullopt};
if (metadataSize > 0) {
Smpte2086 value;
MetadataReader reader{metadata, metadataSize};
reader.read(value.primaryRed)
.read(value.primaryGreen)
.read(value.primaryBlue)
.read(value.whitePoint)
.read(value.maxLuminance)
.read(value.minLuminance);
if (reader.ok()) {
optValue = std::move(value);
} else {
return std::nullopt;
}
}
return DecodeResult{std::move(optValue)};
}
};
template <>
struct MetadataValue<std::optional<Cta861_3>> {
[[nodiscard]] static int32_t encode(const std::optional<Cta861_3>& optValue,
void* _Nullable destBuffer, size_t destBufferSize) {
if (optValue.has_value()) {
const auto& value = *optValue;
return MetadataWriter{destBuffer, destBufferSize}
.write(value.maxContentLightLevel)
.write(value.maxFrameAverageLightLevel)
.desiredSize();
} else {
return 0;
}
}
// Double optional because the value type itself is an optional<>
using DecodeResult = std::optional<std::optional<Cta861_3>>;
[[nodiscard]] static DecodeResult decode(const void* _Nullable metadata, size_t metadataSize) {
std::optional<Cta861_3> optValue{std::nullopt};
if (metadataSize > 0) {
MetadataReader reader{metadata, metadataSize};
Cta861_3 value;
reader.read(value.maxContentLightLevel).read(value.maxFrameAverageLightLevel);
if (reader.ok()) {
optValue = std::move(value);
} else {
return std::nullopt;
}
}
return DecodeResult{std::move(optValue)};
}
};
template <>
struct MetadataValue<std::optional<std::vector<uint8_t>>> {
[[nodiscard]] static int32_t encode(const std::optional<std::vector<uint8_t>>& value,
void* _Nullable destBuffer, size_t destBufferSize) {
if (!value.has_value()) {
return 0;
}
return MetadataWriter{destBuffer, destBufferSize}.write(*value).desiredSize();
}
using DecodeResult = std::optional<std::optional<std::vector<uint8_t>>>;
[[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
std::optional<std::vector<uint8_t>> optValue;
if (metadataSize > 0) {
MetadataReader reader{metadata, metadataSize};
auto value = reader.readBuffer();
if (reader.ok()) {
optValue = std::move(value);
} else {
return std::nullopt;
}
}
return DecodeResult{std::move(optValue)};
}
};
template <StandardMetadataType>
struct StandardMetadata {};
#define DEFINE_TYPE(name, typeArg) \
template <> \
struct StandardMetadata<StandardMetadataType::name> { \
using value_type = typeArg; \
using value = MetadataValue<value_type>; \
static_assert( \
StandardMetadataType::name == \
ndk::internal::enum_values<StandardMetadataType>[static_cast<size_t>( \
StandardMetadataType::name)], \
"StandardMetadataType must have equivalent value to index"); \
}
DEFINE_TYPE(BUFFER_ID, uint64_t);
DEFINE_TYPE(NAME, std::string);
DEFINE_TYPE(WIDTH, uint64_t);
DEFINE_TYPE(HEIGHT, uint64_t);
DEFINE_TYPE(LAYER_COUNT, uint64_t);
DEFINE_TYPE(PIXEL_FORMAT_REQUESTED, PixelFormat);
DEFINE_TYPE(PIXEL_FORMAT_FOURCC, uint32_t);
DEFINE_TYPE(PIXEL_FORMAT_MODIFIER, uint64_t);
DEFINE_TYPE(USAGE, BufferUsage);
DEFINE_TYPE(ALLOCATION_SIZE, uint64_t);
DEFINE_TYPE(PROTECTED_CONTENT, uint64_t);
DEFINE_TYPE(COMPRESSION, ExtendableType);
DEFINE_TYPE(INTERLACED, ExtendableType);
DEFINE_TYPE(CHROMA_SITING, ExtendableType);
DEFINE_TYPE(PLANE_LAYOUTS, std::vector<PlaneLayout>);
DEFINE_TYPE(CROP, std::vector<Rect>);
DEFINE_TYPE(DATASPACE, Dataspace);
DEFINE_TYPE(BLEND_MODE, BlendMode);
DEFINE_TYPE(SMPTE2086, std::optional<Smpte2086>);
DEFINE_TYPE(CTA861_3, std::optional<Cta861_3>);
DEFINE_TYPE(SMPTE2094_10, std::optional<std::vector<uint8_t>>);
DEFINE_TYPE(SMPTE2094_40, std::optional<std::vector<uint8_t>>);
#undef DEFINE_TYPE
template <typename F, std::size_t... I>
void invokeWithStandardMetadata(F&& f, StandardMetadataType type, std::index_sequence<I...>) {
// Setup the jump table, mapping from each type to a springboard that invokes the template
// function with the appropriate concrete type
using F_PTR = decltype(&f);
using THUNK = void (*)(F_PTR);
static constexpr auto jump = std::array<THUNK, sizeof...(I)>{[](F_PTR fp) {
constexpr StandardMetadataType type = ndk::internal::enum_values<StandardMetadataType>[I];
if constexpr (type != StandardMetadataType::INVALID) {
(*fp)(StandardMetadata<type>{});
}
}...};
auto index = static_cast<size_t>(type);
if (index >= 0 && index < jump.size()) {
jump[index](&f);
}
}
template <typename F, typename StandardMetadataSequence = std::make_index_sequence<
ndk::internal::enum_values<StandardMetadataType>.size()>>
int32_t provideStandardMetadata(StandardMetadataType type, void* _Nullable destBuffer,
size_t destBufferSize, F&& f) {
int32_t retVal = -AIMAPPER_ERROR_UNSUPPORTED;
invokeWithStandardMetadata(
[&]<StandardMetadataType T>(StandardMetadata<T>) {
retVal = f.template operator()<T>(
[&](const typename StandardMetadata<T>::value_type& value) -> int32_t {
return StandardMetadata<T>::value::encode(value, destBuffer,
destBufferSize);
});
},
type, StandardMetadataSequence{});
return retVal;
}
template <typename F, typename StandardMetadataSequence = std::make_index_sequence<
ndk::internal::enum_values<StandardMetadataType>.size()>>
AIMapper_Error applyStandardMetadata(StandardMetadataType type, const void* _Nonnull metadata,
size_t metadataSize, F&& f) {
AIMapper_Error retVal = AIMAPPER_ERROR_UNSUPPORTED;
invokeWithStandardMetadata(
[&]<StandardMetadataType T>(StandardMetadata<T>) {
auto value = StandardMetadata<T>::value::decode(metadata, metadataSize);
if (value.has_value()) {
retVal = f.template operator()<T>(std::move(*value));
} else {
retVal = AIMAPPER_ERROR_BAD_VALUE;
}
},
type, StandardMetadataSequence{});
return retVal;
}
} // namespace android::hardware::graphics::mapper