Add stream capabilites to metadata reader
Read configs, stall durations, and reprocess formats.
BUG: 31044638
TEST: unit tests pass
Change-Id: I9089de0d51b7c4d8ef940a3737785177f257382f
diff --git a/modules/camera/3_4/metadata/metadata_common.h b/modules/camera/3_4/metadata/metadata_common.h
index 15f8084..34b7777 100644
--- a/modules/camera/3_4/metadata/metadata_common.h
+++ b/modules/camera/3_4/metadata/metadata_common.h
@@ -160,7 +160,7 @@
//
// Returns:
// -ENOENT: The tag couldn't be found or was empty.
-// -EINVAL: The tag contained more than one item.
+// -EINVAL: The tag contained more than one item, or |val| is null.
// -ENODEV: The tag claims to be non-empty, but the data pointer is null.
// 0: Success. |*val| will contain the value for |tag|.
@@ -169,6 +169,10 @@
static int SingleTagValue(const android::CameraMetadata& metadata,
int32_t tag,
T* val) {
+ if (!val) {
+ HAL_LOGE("Null pointer passed to SingleTagValue.");
+ return -EINVAL;
+ }
camera_metadata_ro_entry_t entry = metadata.find(tag);
if (entry.count == 0) {
HAL_LOGE("Metadata tag %d is empty.", tag);
@@ -196,6 +200,10 @@
static int SingleTagValue(const android::CameraMetadata& metadata,
int32_t tag,
std::array<T, N>* val) {
+ if (!val) {
+ HAL_LOGE("Null pointer passed to SingleTagValue.");
+ return -EINVAL;
+ }
camera_metadata_ro_entry_t entry = metadata.find(tag);
if (entry.count == 0) {
HAL_LOGE("Metadata tag %d is empty.", tag);
@@ -222,6 +230,84 @@
return 0;
}
+// VectorTagValue(metadata, tag, val)
+//
+// Get the value of the |tag| entry in |metadata|.
+// |tag| is expected to refer to an entry with a vector
+// of the templated type. For arrays, an error will be
+// returned if it the wrong number of items are present.
+//
+// Returns:
+// -ENOENT: The tag couldn't be found or was empty. While technically an
+// empty vector may be valid, this error is returned for consistency
+// with SingleTagValue.
+// -EINVAL: The tag contained an invalid number of entries (e.g. 6 entries for
+// a vector of length 4 arrays), or |val| is null.
+// -ENODEV: The tag claims to be non-empty, but the data pointer is null.
+// 0: Success. |*val| will contain the values for |tag|.
+template <typename T>
+static int VectorTagValue(const android::CameraMetadata& metadata,
+ int32_t tag,
+ std::vector<T>* val) {
+ if (!val) {
+ HAL_LOGE("Null pointer passed to VectorTagValue.");
+ return -EINVAL;
+ }
+ camera_metadata_ro_entry_t entry = metadata.find(tag);
+ if (entry.count == 0) {
+ return -ENOENT;
+ }
+ const T* data = nullptr;
+ GetDataPointer(entry, &data);
+ if (data == nullptr) {
+ HAL_LOGE("Metadata tag %d claims to have elements but is empty.", tag);
+ return -ENODEV;
+ }
+ // Copy the data for |tag| into the output vector.
+ *val = std::vector<T>(data, data + entry.count);
+ return 0;
+}
+
+// Specialization for std::array.
+template <typename T, size_t N>
+static int VectorTagValue(const android::CameraMetadata& metadata,
+ int32_t tag,
+ std::vector<std::array<T, N>>* val) {
+ if (!val) {
+ HAL_LOGE("Null pointer passed to VectorTagValue.");
+ return -EINVAL;
+ }
+ camera_metadata_ro_entry_t entry = metadata.find(tag);
+ if (entry.count == 0) {
+ return -ENOENT;
+ }
+ if (entry.count % N != 0) {
+ HAL_LOGE(
+ "Error: expected metadata tag %d to contain a vector of arrays of "
+ "length %d (had %d entries, which is not divisible by %d).",
+ tag,
+ N,
+ entry.count,
+ N);
+ return -EINVAL;
+ }
+ const T* data = nullptr;
+ GetDataPointer(entry, &data);
+ if (data == nullptr) {
+ HAL_LOGE("Metadata tag %d claims to have elements but is empty.", tag);
+ return -ENODEV;
+ }
+ // Copy the data for |tag| into separate arrays for the output vector.
+ size_t num_arrays = entry.count / N;
+ *val = std::vector<std::array<T, N>>(num_arrays);
+ for (size_t i = 0; i < num_arrays; ++i) {
+ for (size_t j = 0; j < N; ++j) {
+ val->at(i)[j] = data[i * N + j];
+ }
+ }
+ return 0;
+}
+
} // namespace v4l2_camera_hal
#endif // V4L2_CAMERA_HAL_METADATA_METADATA_COMMON_H_
diff --git a/modules/camera/3_4/metadata/metadata_reader.cpp b/modules/camera/3_4/metadata/metadata_reader.cpp
index c570048..53c9535 100644
--- a/modules/camera/3_4/metadata/metadata_reader.cpp
+++ b/modules/camera/3_4/metadata/metadata_reader.cpp
@@ -83,4 +83,167 @@
return 0;
}
+int MetadataReader::MaxInputStreams(int32_t* max_input) const {
+ int res = v4l2_camera_hal::SingleTagValue(
+ *metadata_, ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, max_input);
+ if (res == -ENOENT) {
+ // Not required; default to 0.
+ *max_input = 0;
+ } else if (res) {
+ ALOGE("%s: Failed to get max output streams from static metadata.",
+ __func__);
+ return res;
+ }
+ return 0;
+}
+
+int MetadataReader::MaxOutputStreams(int32_t* max_raw,
+ int32_t* max_non_stalling,
+ int32_t* max_stalling) const {
+ std::array<int32_t, 3> max_output_streams;
+ int res = v4l2_camera_hal::SingleTagValue(
+ *metadata_, ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS, &max_output_streams);
+ if (res) {
+ ALOGE("%s: Failed to get max output streams from static metadata.",
+ __func__);
+ return res;
+ }
+ *max_raw = max_output_streams[0];
+ *max_non_stalling = max_output_streams[1];
+ *max_stalling = max_output_streams[2];
+ return 0;
+}
+
+int MetadataReader::StreamConfigurations(
+ std::vector<StreamConfiguration>* configs) const {
+ std::vector<RawStreamConfiguration> raw_stream_configs;
+ int res = v4l2_camera_hal::VectorTagValue(
+ *metadata_,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ &raw_stream_configs);
+ if (res) {
+ ALOGE("%s: Failed to get stream configs from static metadata.", __func__);
+ return res;
+ }
+
+ // TODO(b/31384253): check for required configs.
+
+ // Convert from raw.
+ configs->insert(
+ configs->end(), raw_stream_configs.begin(), raw_stream_configs.end());
+
+ // Check that all configs are valid.
+ for (const auto& config : *configs) {
+ // Must have positive dimensions.
+ if (config.spec.width < 1 || config.spec.height < 1) {
+ ALOGE("%s: Invalid stream config: non-positive dimensions (%d, %d).",
+ __func__,
+ config.spec.width,
+ config.spec.height);
+ return -EINVAL;
+ }
+ // Must have a known direction enum.
+ switch (config.direction) {
+ case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT:
+ case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT:
+ break;
+ default:
+ ALOGE("%s: Invalid stream config direction: %d.",
+ __func__,
+ config.direction);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+int MetadataReader::StreamStallDurations(
+ std::vector<StreamStallDuration>* stalls) const {
+ std::vector<RawStreamStallDuration> raw_stream_stall_durations;
+ int res =
+ v4l2_camera_hal::VectorTagValue(*metadata_,
+ ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
+ &raw_stream_stall_durations);
+ if (res) {
+ ALOGE("%s: Failed to get stall durations from static metadata.", __func__);
+ return res;
+ }
+
+ // Convert from raw.
+ stalls->insert(stalls->end(),
+ raw_stream_stall_durations.begin(),
+ raw_stream_stall_durations.end());
+ // Check that all stalls are valid.
+ for (const auto& stall : *stalls) {
+ // Must have positive dimensions.
+ if (stall.spec.width < 1 || stall.spec.height < 1) {
+ ALOGE("%s: Invalid stall duration: non-positive dimensions (%d, %d).",
+ __func__,
+ stall.spec.width,
+ stall.spec.height);
+ return -EINVAL;
+ }
+ // Must have a non-negative stall.
+ if (stall.duration < 0) {
+ ALOGE("%s: Invalid stall duration: negative stall %d.",
+ __func__,
+ stall.duration);
+ return -EINVAL;
+ }
+ // TODO(b/31384253): YUV_420_888, RAW10, RAW12, RAW_OPAQUE,
+ // and IMPLEMENTATION_DEFINED must have 0 stall duration.
+ }
+
+ return 0;
+}
+
+int MetadataReader::ReprocessFormats(ReprocessFormatMap* reprocess_map) const {
+ std::vector<int32_t> input_output_formats;
+ int res = v4l2_camera_hal::VectorTagValue(
+ *metadata_,
+ ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP,
+ &input_output_formats);
+ if (res) {
+ ALOGE("%s: Failed to get input output format map from static metadata.",
+ __func__);
+ return res;
+ }
+
+ // Convert from the raw vector.
+ for (size_t i = 0; i < input_output_formats.size();) {
+ // The map is represented as variable-length entries of the format
+ // input, num_outputs, <outputs>.
+
+ // Get the input format.
+ int32_t input_format = input_output_formats[i++];
+
+ // Find the output begin and end for this format.
+ int32_t num_output_formats = input_output_formats[i++];
+ if (num_output_formats < 1) {
+ ALOGE(
+ "%s: No output formats for input format %d.", __func__, input_format);
+ return -EINVAL;
+ }
+ size_t outputs_end = i + num_output_formats;
+ if (outputs_end > input_output_formats.size()) {
+ ALOGE("%s: Input format %d requests more data than available.",
+ __func__,
+ input_format);
+ return -EINVAL;
+ }
+
+ // Copy all the output formats into the map.
+ (*reprocess_map)[input_format].insert(
+ input_output_formats.data() + i,
+ input_output_formats.data() + outputs_end);
+
+ // Move on to the next entry.
+ i = outputs_end;
+ }
+
+ // TODO(b/31384253): check for required mappings.
+
+ return 0;
+}
+
} // namespace default_camera_hal
diff --git a/modules/camera/3_4/metadata/metadata_reader.h b/modules/camera/3_4/metadata/metadata_reader.h
index 64bedd6..828e992 100644
--- a/modules/camera/3_4/metadata/metadata_reader.h
+++ b/modules/camera/3_4/metadata/metadata_reader.h
@@ -17,11 +17,13 @@
#ifndef DEFAULT_CAMERA_HAL_METADATA_METADATA_READER_H_
#define DEFAULT_CAMERA_HAL_METADATA_METADATA_READER_H_
+#include <map>
#include <memory>
#include <camera/CameraMetadata.h>
#include "../common.h"
+#include "types.h"
namespace default_camera_hal {
@@ -51,6 +53,15 @@
// The |facing| returned will be one of the enum values from system/camera.h.
virtual int Facing(int* facing) const;
virtual int Orientation(int* orientation) const;
+ virtual int MaxInputStreams(int32_t* max_input_streams) const;
+ virtual int MaxOutputStreams(int32_t* max_raw_output_streams,
+ int32_t* max_non_stalling_output_streams,
+ int32_t* max_stalling_output_streams) const;
+ virtual int StreamConfigurations(
+ std::vector<StreamConfiguration>* configs) const;
+ virtual int StreamStallDurations(
+ std::vector<StreamStallDuration>* stalls) const;
+ virtual int ReprocessFormats(ReprocessFormatMap* reprocess_map) const;
private:
std::unique_ptr<const android::CameraMetadata> metadata_;
diff --git a/modules/camera/3_4/metadata/metadata_reader_test.cpp b/modules/camera/3_4/metadata/metadata_reader_test.cpp
index cdbb3f9..eadf51c 100644
--- a/modules/camera/3_4/metadata/metadata_reader_test.cpp
+++ b/modules/camera/3_4/metadata/metadata_reader_test.cpp
@@ -21,6 +21,7 @@
#include <gtest/gtest.h>
#include <system/camera.h>
+#include "array_vector.h"
#include "metadata_common.h"
using testing::AtMost;
@@ -52,7 +53,15 @@
const int32_t facing_tag_ = ANDROID_LENS_FACING;
const int32_t orientation_tag_ = ANDROID_SENSOR_ORIENTATION;
+ const int32_t max_inputs_tag_ = ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS;
+ const int32_t max_outputs_tag_ = ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS;
+ const int32_t configs_tag_ = ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+ const int32_t stalls_tag_ = ANDROID_SCALER_AVAILABLE_STALL_DURATIONS;
+ const int32_t reprocess_formats_tag_ =
+ ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP;
+
const std::vector<int32_t> valid_orientations_ = {0, 90, 180, 270};
+ // TODO(b/31384253): check for required configs/reprocess formats.
};
TEST_F(MetadataReaderTest, FacingTranslations) {
@@ -130,4 +139,235 @@
EXPECT_EQ(dut_->Orientation(&actual), -ENOENT);
}
+TEST_F(MetadataReaderTest, MaxInputs) {
+ int32_t expected = 12;
+ ASSERT_EQ(v4l2_camera_hal::UpdateMetadata(
+ metadata_.get(), max_inputs_tag_, expected),
+ 0);
+ FillDUT();
+ int32_t actual = expected + 1;
+ ASSERT_EQ(dut_->MaxInputStreams(&actual), 0);
+ EXPECT_EQ(actual, expected);
+}
+
+TEST_F(MetadataReaderTest, EmptyMaxInputs) {
+ FillDUT();
+ // Max inputs is an optional key; if not present the default is 0.
+ int32_t expected = 0;
+ int32_t actual = expected + 1;
+ ASSERT_EQ(dut_->MaxInputStreams(&actual), 0);
+ EXPECT_EQ(actual, expected);
+}
+
+TEST_F(MetadataReaderTest, MaxOutputs) {
+ std::array<int32_t, 3> expected = {{12, 34, 56}};
+ ASSERT_EQ(v4l2_camera_hal::UpdateMetadata(
+ metadata_.get(), max_outputs_tag_, expected),
+ 0);
+ FillDUT();
+ std::array<int32_t, 3> actual;
+ ASSERT_EQ(dut_->MaxOutputStreams(&actual[0], &actual[1], &actual[2]), 0);
+ EXPECT_EQ(actual, expected);
+}
+
+TEST_F(MetadataReaderTest, InvalidMaxOutputs) {
+ // Must be a 3-tuple to be valid.
+ std::array<int32_t, 4> invalid = {{12, 34, 56, 78}};
+ ASSERT_EQ(v4l2_camera_hal::UpdateMetadata(
+ metadata_.get(), max_outputs_tag_, invalid),
+ 0);
+ FillDUT();
+ int32_t actual;
+ // Don't mind the aliasing since we don't care about the value.
+ ASSERT_EQ(dut_->MaxOutputStreams(&actual, &actual, &actual), -EINVAL);
+}
+
+TEST_F(MetadataReaderTest, EmptyMaxOutputs) {
+ FillDUT();
+ int32_t actual;
+ // Don't mind the aliasing since we don't care about the value.
+ ASSERT_EQ(dut_->MaxOutputStreams(&actual, &actual, &actual), -ENOENT);
+}
+
+TEST_F(MetadataReaderTest, StreamConfigurations) {
+ v4l2_camera_hal::ArrayVector<int32_t, 4> configs;
+ std::array<int32_t, 4> config1{
+ {1, 2, 3, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT}};
+ std::array<int32_t, 4> config2{
+ {5, 6, 7, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT}};
+ configs.push_back(config1);
+ configs.push_back(config2);
+ ASSERT_EQ(
+ v4l2_camera_hal::UpdateMetadata(metadata_.get(), configs_tag_, configs),
+ 0);
+ FillDUT();
+ std::vector<StreamConfiguration> actual;
+ ASSERT_EQ(dut_->StreamConfigurations(&actual), 0);
+ ASSERT_EQ(actual.size(), configs.num_arrays());
+ EXPECT_EQ(actual[0].spec.format, config1[0]);
+ EXPECT_EQ(actual[0].spec.width, config1[1]);
+ EXPECT_EQ(actual[0].spec.height, config1[2]);
+ EXPECT_EQ(actual[0].direction, config1[3]);
+ EXPECT_EQ(actual[1].spec.format, config2[0]);
+ EXPECT_EQ(actual[1].spec.width, config2[1]);
+ EXPECT_EQ(actual[1].spec.height, config2[2]);
+ EXPECT_EQ(actual[1].direction, config2[3]);
+}
+
+TEST_F(MetadataReaderTest, InvalidStreamConfigurationDirection) {
+ // -1 is not a valid direction.
+ std::array<int32_t, 4> config{{1, 2, 3, -1}};
+ ASSERT_EQ(
+ v4l2_camera_hal::UpdateMetadata(metadata_.get(), configs_tag_, config),
+ 0);
+ FillDUT();
+ std::vector<StreamConfiguration> actual;
+ ASSERT_EQ(dut_->StreamConfigurations(&actual), -EINVAL);
+}
+
+TEST_F(MetadataReaderTest, InvalidStreamConfigurationSize) {
+ // Both size dimensions must be > 0.
+ std::array<int32_t, 4> config{
+ {1, 2, 0, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT}};
+ ASSERT_EQ(
+ v4l2_camera_hal::UpdateMetadata(metadata_.get(), configs_tag_, config),
+ 0);
+ FillDUT();
+ std::vector<StreamConfiguration> actual;
+ ASSERT_EQ(dut_->StreamConfigurations(&actual), -EINVAL);
+}
+
+TEST_F(MetadataReaderTest, InvalidStreamConfigurationNumElements) {
+ // Should be a multiple of 4.
+ std::array<int32_t, 5> config{
+ {1, 2, 3, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT, 5}};
+ ASSERT_EQ(
+ v4l2_camera_hal::UpdateMetadata(metadata_.get(), configs_tag_, config),
+ 0);
+ FillDUT();
+ std::vector<StreamConfiguration> actual;
+ ASSERT_EQ(dut_->StreamConfigurations(&actual), -EINVAL);
+}
+
+// TODO(b/31384253): Test that failure occurs if
+// required configurations are not present.
+
+TEST_F(MetadataReaderTest, NoStreamConfigurations) {
+ FillDUT();
+ std::vector<StreamConfiguration> actual;
+ ASSERT_EQ(dut_->StreamConfigurations(&actual), -ENOENT);
+}
+
+TEST_F(MetadataReaderTest, StreamStallDurations) {
+ v4l2_camera_hal::ArrayVector<int64_t, 4> stalls;
+ std::array<int64_t, 4> stall1{{1, 2, 3, 4}};
+ std::array<int64_t, 4> stall2{{5, 6, 7, 8}};
+ stalls.push_back(stall1);
+ stalls.push_back(stall2);
+ ASSERT_EQ(
+ v4l2_camera_hal::UpdateMetadata(metadata_.get(), stalls_tag_, stalls), 0);
+ FillDUT();
+ std::vector<StreamStallDuration> actual;
+ ASSERT_EQ(dut_->StreamStallDurations(&actual), 0);
+ ASSERT_EQ(actual.size(), stalls.num_arrays());
+ EXPECT_EQ(actual[0].spec.format, stall1[0]);
+ EXPECT_EQ(actual[0].spec.width, stall1[1]);
+ EXPECT_EQ(actual[0].spec.height, stall1[2]);
+ EXPECT_EQ(actual[0].duration, stall1[3]);
+ EXPECT_EQ(actual[1].spec.format, stall2[0]);
+ EXPECT_EQ(actual[1].spec.width, stall2[1]);
+ EXPECT_EQ(actual[1].spec.height, stall2[2]);
+ EXPECT_EQ(actual[1].duration, stall2[3]);
+}
+
+TEST_F(MetadataReaderTest, InvalidStreamStallDurationDuration) {
+ // -1 is not a valid duration.
+ std::array<int64_t, 4> stall{{1, 2, 3, -1}};
+ ASSERT_EQ(
+ v4l2_camera_hal::UpdateMetadata(metadata_.get(), stalls_tag_, stall), 0);
+ FillDUT();
+ std::vector<StreamStallDuration> actual;
+ ASSERT_EQ(dut_->StreamStallDurations(&actual), -EINVAL);
+}
+
+TEST_F(MetadataReaderTest, InvalidStreamStallDurationSize) {
+ // Both size dimensions must be > 0.
+ std::array<int64_t, 4> stall{{1, 2, 0, 3}};
+ ASSERT_EQ(
+ v4l2_camera_hal::UpdateMetadata(metadata_.get(), stalls_tag_, stall), 0);
+ FillDUT();
+ std::vector<StreamStallDuration> actual;
+ ASSERT_EQ(dut_->StreamStallDurations(&actual), -EINVAL);
+}
+
+TEST_F(MetadataReaderTest, InvalidStreamStallDurationNumElements) {
+ // Should be a multiple of 4.
+ std::array<int64_t, 5> stall{{1, 2, 3, 4, 5}};
+ ASSERT_EQ(
+ v4l2_camera_hal::UpdateMetadata(metadata_.get(), stalls_tag_, stall), 0);
+ FillDUT();
+ std::vector<StreamStallDuration> actual;
+ ASSERT_EQ(dut_->StreamStallDurations(&actual), -EINVAL);
+}
+
+// TODO(b/31384253): Test that failure occurs if
+// YUV_420_888, RAW10, RAW12, RAW_OPAQUE, or IMPLEMENTATION_DEFINED
+// formats have stall durations > 0.
+
+TEST_F(MetadataReaderTest, NoStreamStallDurations) {
+ FillDUT();
+ std::vector<StreamStallDuration> actual;
+ ASSERT_EQ(dut_->StreamStallDurations(&actual), -ENOENT);
+}
+
+TEST_F(MetadataReaderTest, ReprocessFormats) {
+ ReprocessFormatMap expected{{1, {4}}, {2, {5, 6}}, {3, {7, 8, 9}}};
+ std::vector<int32_t> raw;
+ for (const auto& input_outputs : expected) {
+ raw.push_back(input_outputs.first);
+ raw.push_back(input_outputs.second.size());
+ raw.insert(
+ raw.end(), input_outputs.second.begin(), input_outputs.second.end());
+ }
+ ASSERT_EQ(v4l2_camera_hal::UpdateMetadata(
+ metadata_.get(), reprocess_formats_tag_, raw),
+ 0);
+ FillDUT();
+ ReprocessFormatMap actual;
+ ASSERT_EQ(dut_->ReprocessFormats(&actual), 0);
+ EXPECT_EQ(actual, expected);
+}
+
+TEST_F(MetadataReaderTest, ReprocessFormatsNoOutputs) {
+ // 0 indicates that there are 0 output formats for input format 1,
+ // which is not ok.
+ std::vector<int32_t> raw{1, 0};
+ ASSERT_EQ(v4l2_camera_hal::UpdateMetadata(
+ metadata_.get(), reprocess_formats_tag_, raw),
+ 0);
+ FillDUT();
+ ReprocessFormatMap actual;
+ ASSERT_EQ(dut_->ReprocessFormats(&actual), -EINVAL);
+}
+
+TEST_F(MetadataReaderTest, ReprocessFormatsPastEnd) {
+ // 3 indicates that there are 3 output formats for input format 1,
+ // which is not ok since there are only 2 here.
+ std::vector<int32_t> raw{1, 3, 0, 0};
+ ASSERT_EQ(v4l2_camera_hal::UpdateMetadata(
+ metadata_.get(), reprocess_formats_tag_, raw),
+ 0);
+ FillDUT();
+ ReprocessFormatMap actual;
+ ASSERT_EQ(dut_->ReprocessFormats(&actual), -EINVAL);
+}
+
+TEST_F(MetadataReaderTest, EmptyReprocessFormats) {
+ // 3 indicates that there are 3 output formats for input format 1,
+ // which is not ok since there are only 2 here.
+ FillDUT();
+ ReprocessFormatMap actual;
+ ASSERT_EQ(dut_->ReprocessFormats(&actual), -ENOENT);
+}
+
} // namespace default_camera_hal
diff --git a/modules/camera/3_4/metadata/types.h b/modules/camera/3_4/metadata/types.h
new file mode 100644
index 0000000..093fe01
--- /dev/null
+++ b/modules/camera/3_4/metadata/types.h
@@ -0,0 +1,82 @@
+/*
+ * 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 DEFAULT_CAMERA_HAL_METADATA_TYPES_H_
+#define DEFAULT_CAMERA_HAL_METADATA_TYPES_H_
+
+#include <array>
+#include <map>
+#include <set>
+
+#include <hardware/camera3.h>
+
+namespace default_camera_hal {
+
+// A variety of Structs describing more complex metadata entries.
+
+// StreamSpec describe the attributes of a single stream.
+struct StreamSpec {
+ int32_t format;
+ int32_t width;
+ int32_t height;
+
+ StreamSpec(int32_t f, int32_t w, int32_t h)
+ : format(f), width(w), height(h) {}
+ StreamSpec(const camera3_stream_t* stream)
+ : format(stream->format), width(stream->width), height(stream->height) {}
+
+ struct Compare {
+ bool operator()(const StreamSpec& left, const StreamSpec& right) const {
+ // Base equality/comparison first on format, then on width, then height.
+ return left.format < right.format ||
+ (left.format == right.format &&
+ (left.width < right.width ||
+ (left.width == right.width && left.height < right.height)));
+ }
+ };
+};
+
+// StreamConfigurations indicate a possible direction configuration for
+// a given set of stream specifications.
+typedef std::array<int32_t, 4> RawStreamConfiguration;
+struct StreamConfiguration {
+ StreamSpec spec;
+ int32_t direction;
+
+ StreamConfiguration(const RawStreamConfiguration& raw)
+ : spec({raw[0], raw[1], raw[2]}), direction(raw[3]) {}
+};
+
+// StreamStallDurations indicate the stall duration (in ns) for
+// when a stream with a given set of specifications is used as output.
+typedef std::array<int64_t, 4> RawStreamStallDuration;
+struct StreamStallDuration {
+ StreamSpec spec;
+ int64_t duration;
+
+ StreamStallDuration(const RawStreamStallDuration& raw)
+ : spec({static_cast<int32_t>(raw[0]),
+ static_cast<int32_t>(raw[1]),
+ static_cast<int32_t>(raw[2])}),
+ duration(raw[3]) {}
+};
+
+// Map input formats to their supported reprocess output formats.
+typedef std::map<int32_t, std::set<int32_t>> ReprocessFormatMap;
+
+} // namespace default_camera_hal
+
+#endif // DEFAULT_CAMERA_HAL_METADATA_TYPES_H_