Add V4L2 Control Factory
Also moves all control factory methods into a separate file.
BUG: 30900438
TEST: unit tests pass
Change-Id: I885903d8e23a548b63fd20006568145a233c0316
diff --git a/modules/camera/3_4/Android.mk b/modules/camera/3_4/Android.mk
index 1e7f4d6..ae28598 100644
--- a/modules/camera/3_4/Android.mk
+++ b/modules/camera/3_4/Android.mk
@@ -50,6 +50,7 @@
v4l2_wrapper.cpp \
v4l2_test_files := \
+ metadata/control_factory_test.cpp \
metadata/control_test.cpp \
metadata/enum_converter_test.cpp \
metadata/ignored_control_delegate_test.cpp \
diff --git a/modules/camera/3_4/metadata/control.h b/modules/camera/3_4/metadata/control.h
index 199ecd0..7c8c6bf 100644
--- a/modules/camera/3_4/metadata/control.h
+++ b/modules/camera/3_4/metadata/control.h
@@ -22,9 +22,7 @@
#include <system/camera_metadata.h>
#include "../common.h"
-#include "menu_control_options.h"
#include "metadata_common.h"
-#include "no_effect_control_delegate.h"
#include "partial_metadata_interface.h"
#include "tagged_control_delegate.h"
#include "tagged_control_options.h"
@@ -52,13 +50,7 @@
virtual int SetRequestValues(
const android::CameraMetadata& metadata) override;
- // Factory methods for some common combinations of delegates & options.
- // NoEffectMenuControl: Some menu options, but they have no effect.
- // The default value will be the first element of |options|.
- static std::unique_ptr<Control<T>> NoEffectMenuControl(
- int32_t delegate_tag, int32_t options_tag, const std::vector<T>& options);
-
- protected:
+ private:
std::unique_ptr<TaggedControlDelegate<T>> delegate_;
std::unique_ptr<TaggedControlOptions<T>> options_;
@@ -178,24 +170,6 @@
return delegate_->SetValue(requested);
}
-template <typename T>
-std::unique_ptr<Control<T>> Control<T>::NoEffectMenuControl(
- int32_t delegate_tag, int32_t options_tag, const std::vector<T>& options) {
- HAL_LOG_ENTER();
-
- if (options.empty()) {
- HAL_LOGE("At least one option must be provided.");
- return nullptr;
- }
-
- return std::make_unique<Control<T>>(
- std::make_unique<TaggedControlDelegate<T>>(
- delegate_tag,
- std::make_unique<NoEffectControlDelegate<T>>(options[0])),
- std::make_unique<TaggedControlOptions<T>>(
- options_tag, std::make_unique<MenuControlOptions<T>>(options)));
-}
-
} // namespace v4l2_camera_hal
#endif // V4L2_CAMERA_HAL_METADATA_CONTROL_H_
diff --git a/modules/camera/3_4/metadata/control_factory.h b/modules/camera/3_4/metadata/control_factory.h
new file mode 100644
index 0000000..911b67f
--- /dev/null
+++ b/modules/camera/3_4/metadata/control_factory.h
@@ -0,0 +1,275 @@
+/*
+ * 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 V4L2_CAMERA_HAL_METADATA_CONTROL_FACTORY_H_
+#define V4L2_CAMERA_HAL_METADATA_CONTROL_FACTORY_H_
+
+#include "../common.h"
+#include "control.h"
+#include "menu_control_options.h"
+#include "no_effect_control_delegate.h"
+#include "ranged_converter.h"
+#include "slider_control_options.h"
+#include "tagged_control_delegate.h"
+#include "tagged_control_options.h"
+#include "v4l2_control_delegate.h"
+
+namespace v4l2_camera_hal {
+
+enum class ControlType { kMenu, kSlider };
+
+// Static functions to create controls. Nullptr is returned on failures.
+
+// NoEffectMenuControl: Some menu options, but they have no effect.
+// The default value will be the first element of |options|.
+template <typename T>
+static std::unique_ptr<Control<T>> NoEffectMenuControl(
+ int32_t delegate_tag, int32_t options_tag, const std::vector<T>& options);
+
+// NoEffectSliderControl: A slider of options, but they have no effect.
+// The default value will be |min|.
+template <typename T>
+static std::unique_ptr<Control<T>> NoEffectSliderControl(int32_t delegate_tag,
+ int32_t options_tag,
+ T min,
+ T max);
+
+// NoEffectControl: A control with no effect and only a single allowable
+// value. Chooses an appropriate ControlOptionsInterface depending on type.
+template <typename T>
+static std::unique_ptr<Control<T>> NoEffectControl(ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ T value);
+
+// V4L2Control: A control corresponding to a V4L2 control.
+template <typename T>
+static std::unique_ptr<Control<T>> V4L2Control(
+ ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ std::shared_ptr<V4L2Wrapper> device,
+ int control_id,
+ std::shared_ptr<ConverterInterface<T, int32_t>> converter);
+
+// V4L2ControlOrDefault: Like V4L2Control, but if the V4L2Control fails to
+// initialize for some reason, this method will fall back to NoEffectControl.
+template <typename T>
+static std::unique_ptr<Control<T>> V4L2ControlOrDefault(
+ ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ std::shared_ptr<V4L2Wrapper> device,
+ int control_id,
+ std::shared_ptr<ConverterInterface<T, int32_t>> converter,
+ const T& default_value);
+
+// -----------------------------------------------------------------------------
+
+template <typename T>
+std::unique_ptr<Control<T>> NoEffectMenuControl(int32_t delegate_tag,
+ int32_t options_tag,
+ const std::vector<T>& options) {
+ HAL_LOG_ENTER();
+
+ if (options.empty()) {
+ HAL_LOGE("At least one option must be provided.");
+ return nullptr;
+ }
+
+ return std::make_unique<Control<T>>(
+ std::make_unique<TaggedControlDelegate<T>>(
+ delegate_tag,
+ std::make_unique<NoEffectControlDelegate<T>>(options[0])),
+ std::make_unique<TaggedControlOptions<T>>(
+ options_tag, std::make_unique<MenuControlOptions<T>>(options)));
+}
+
+template <typename T>
+std::unique_ptr<Control<T>> NoEffectSliderControl(int32_t delegate_tag,
+ int32_t options_tag,
+ T min,
+ T max) {
+ HAL_LOG_ENTER();
+
+ return std::make_unique<Control<T>>(
+ std::make_unique<TaggedControlDelegate<T>>(
+ delegate_tag, std::make_unique<NoEffectControlDelegate<T>>(min)),
+ std::make_unique<TaggedControlOptions<T>>(
+ options_tag, std::make_unique<SliderControlOptions<T>>(min, max)));
+}
+
+template <typename T>
+std::unique_ptr<Control<T>> NoEffectControl(ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ T value) {
+ HAL_LOG_ENTER();
+
+ switch (type) {
+ case ControlType::kMenu:
+ return NoEffectMenuControl<T>(delegate_tag, options_tag, {value});
+ case ControlType::kSlider:
+ return NoEffectSliderControl(delegate_tag, options_tag, value, value);
+ }
+}
+
+template <typename T>
+std::unique_ptr<Control<T>> V4L2Control(
+ ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ std::shared_ptr<V4L2Wrapper> device,
+ int control_id,
+ std::shared_ptr<ConverterInterface<T, int32_t>> converter) {
+ HAL_LOG_ENTER();
+
+ // Query the device.
+ v4l2_query_ext_ctrl control_query;
+ int res = device->QueryControl(control_id, &control_query);
+ if (res) {
+ HAL_LOGE("Failed to query control %d.", control_id);
+ return nullptr;
+ }
+
+ int32_t control_min = static_cast<int32_t>(control_query.minimum);
+ int32_t control_max = static_cast<int32_t>(control_query.maximum);
+ int32_t control_step = static_cast<int32_t>(control_query.step);
+ if (control_min > control_max) {
+ HAL_LOGE("No acceptable values (min %d is greater than max %d).",
+ control_min,
+ control_max);
+ return nullptr;
+ }
+
+ // Variables needed by the various switch statements.
+ std::vector<T> options;
+ T metadata_val;
+ T metadata_min;
+ T metadata_max;
+ // Set up the result converter and result options based on type.
+ std::shared_ptr<ConverterInterface<T, int32_t>> result_converter(converter);
+ std::unique_ptr<ControlOptionsInterface<T>> result_options;
+ switch (control_query.type) {
+ case V4L2_CTRL_TYPE_BOOLEAN: // Fall-through.
+ case V4L2_CTRL_TYPE_MENU:
+ if (type != ControlType::kMenu) {
+ HAL_LOGE(
+ "V4L2 control %d is of type %d, which isn't compatible with "
+ "desired metadata control type %d",
+ control_id,
+ control_query.type,
+ type);
+ return nullptr;
+ }
+
+ // Convert each available option,
+ // ignoring ones without a known conversion.
+ for (int32_t i = control_min; i <= control_max; i += control_step) {
+ res = converter->V4L2ToMetadata(i, &metadata_val);
+ if (res == -EINVAL) {
+ HAL_LOGV("V4L2 value %d for control %d has no metadata equivalent.",
+ i,
+ control_id);
+ continue;
+ } else if (res) {
+ HAL_LOGE("Error converting value %d for control %d.", i, control_id);
+ return nullptr;
+ }
+ options.push_back(metadata_val);
+ }
+ // Check to make sure there's at least one option.
+ if (options.empty()) {
+ HAL_LOGE("No valid options for control %d.", control_id);
+ return nullptr;
+ }
+ result_options.reset(new MenuControlOptions<T>(options));
+ // No converter changes necessary.
+ break;
+ case V4L2_CTRL_TYPE_INTEGER:
+ if (type != ControlType::kSlider) {
+ HAL_LOGE(
+ "V4L2 control %d is of type %d, which isn't compatible with "
+ "desired metadata control type %d",
+ control_id,
+ control_query.type,
+ type);
+ return nullptr;
+ }
+
+ // Upgrade to a range/step-clamping converter.
+ result_converter.reset(new RangedConverter<T, int32_t>(
+ converter, control_min, control_max, control_step));
+
+ // Convert the min and max.
+ res = result_converter->V4L2ToMetadata(control_min, &metadata_min);
+ if (res) {
+ HAL_LOGE(
+ "Failed to convert V4L2 min value %d for control %d to metadata.",
+ control_min,
+ control_id);
+ return nullptr;
+ }
+ res = result_converter->V4L2ToMetadata(control_max, &metadata_max);
+ if (res) {
+ HAL_LOGE(
+ "Failed to convert V4L2 max value %d for control %d to metadata.",
+ control_max,
+ control_id);
+ return nullptr;
+ }
+ result_options.reset(
+ new SliderControlOptions<T>(metadata_min, metadata_max));
+ break;
+ default:
+ HAL_LOGE("Control %d is of unsupported type %d",
+ control_id,
+ control_query.type);
+ return nullptr;
+ }
+
+ // Construct the control.
+ return std::make_unique<Control<T>>(
+ std::make_unique<TaggedControlDelegate<T>>(
+ delegate_tag,
+ std::make_unique<V4L2ControlDelegate<T>>(
+ device, control_id, result_converter)),
+ std::make_unique<TaggedControlOptions<T>>(options_tag,
+ std::move(result_options)));
+}
+
+template <typename T>
+std::unique_ptr<Control<T>> V4L2ControlOrDefault(
+ ControlType type,
+ int32_t delegate_tag,
+ int32_t options_tag,
+ std::shared_ptr<V4L2Wrapper> device,
+ int control_id,
+ std::shared_ptr<ConverterInterface<T, int32_t>> converter,
+ const T& default_value) {
+ HAL_LOG_ENTER();
+
+ std::unique_ptr<Control<T>> result = V4L2Control(
+ type, delegate_tag, options_tag, device, control_id, converter);
+ if (!result) {
+ result = NoEffectControl(type, delegate_tag, options_tag, default_value);
+ }
+ return result;
+}
+
+} // namespace v4l2_camera_hal
+
+#endif // V4L2_CAMERA_HAL_METADATA_CONTROL_FACTORY_H_
diff --git a/modules/camera/3_4/metadata/control_factory_test.cpp b/modules/camera/3_4/metadata/control_factory_test.cpp
new file mode 100644
index 0000000..9010879
--- /dev/null
+++ b/modules/camera/3_4/metadata/control_factory_test.cpp
@@ -0,0 +1,433 @@
+/*
+ * 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 <camera/CameraMetadata.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "../v4l2_wrapper_mock.h"
+#include "control_factory.h"
+#include "converter_interface_mock.h"
+#include "metadata_common.h"
+#include "test_common.h"
+
+using testing::AtMost;
+using testing::Expectation;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class ControlFactoryTest : public Test {
+ protected:
+ virtual void SetUp() {
+ mock_device_.reset(new V4L2WrapperMock());
+ mock_converter_.reset(new ConverterInterfaceMock<uint8_t, int32_t>());
+ // Nullify control so an error will be thrown
+ // if a test doesn't construct it.
+ control_.reset();
+ }
+
+ virtual void ExpectTags() {
+ ASSERT_EQ(control_->StaticTags().size(), 1);
+ EXPECT_EQ(control_->StaticTags()[0], options_tag_);
+ ASSERT_EQ(control_->ControlTags().size(), 1);
+ EXPECT_EQ(control_->ControlTags()[0], delegate_tag_);
+ ASSERT_EQ(control_->DynamicTags().size(), 1);
+ EXPECT_EQ(control_->DynamicTags()[0], delegate_tag_);
+ }
+
+ virtual void ExpectOptions(const std::vector<uint8_t>& options) {
+ // Options should be available.
+ android::CameraMetadata metadata;
+ ASSERT_EQ(control_->PopulateStaticFields(&metadata), 0);
+ EXPECT_EQ(metadata.entryCount(), 1);
+ ExpectMetadataEq(metadata, options_tag_, options);
+ }
+
+ virtual void ExpectValue(uint8_t value) {
+ android::CameraMetadata metadata;
+ ASSERT_EQ(control_->PopulateDynamicFields(&metadata), 0);
+ EXPECT_EQ(metadata.entryCount(), 1);
+ ExpectMetadataEq(metadata, delegate_tag_, value);
+ }
+
+ std::unique_ptr<Control<uint8_t>> control_;
+ std::shared_ptr<ConverterInterfaceMock<uint8_t, int32_t>> mock_converter_;
+ std::shared_ptr<V4L2WrapperMock> mock_device_;
+
+ // Need tags that match the data type (uint8_t) being passed.
+ const int32_t delegate_tag_ = ANDROID_COLOR_CORRECTION_ABERRATION_MODE;
+ const int32_t options_tag_ =
+ ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
+};
+
+TEST_F(ControlFactoryTest, NoEffectMenu) {
+ std::vector<uint8_t> test_options = {9, 8, 12};
+ control_ =
+ NoEffectMenuControl<uint8_t>(delegate_tag_, options_tag_, test_options);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectTags();
+
+ // Options should be available.
+ ExpectOptions(test_options);
+ // Default value should be test_options[0].
+ ExpectValue(test_options[0]);
+}
+
+TEST_F(ControlFactoryTest, NoEffectGenericMenu) {
+ uint8_t default_val = 9;
+ control_ = NoEffectControl<uint8_t>(
+ ControlType::kMenu, delegate_tag_, options_tag_, default_val);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectTags();
+
+ // Options should be available.
+ ExpectOptions({default_val});
+ // |default_val| should be default option.
+ ExpectValue(default_val);
+}
+
+TEST_F(ControlFactoryTest, NoEffectSlider) {
+ std::vector<uint8_t> test_range = {9, 12};
+ control_ = NoEffectSliderControl<uint8_t>(
+ delegate_tag_, options_tag_, test_range[0], test_range[1]);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectTags();
+
+ // Single option should be available.
+ ExpectOptions(test_range);
+ // Default value should be the minimum (test_range[0]).
+ ExpectValue(test_range[0]);
+}
+
+TEST_F(ControlFactoryTest, NoEffectGenericSlider) {
+ uint8_t default_val = 9;
+ control_ = NoEffectControl<uint8_t>(
+ ControlType::kSlider, delegate_tag_, options_tag_, default_val);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectTags();
+
+ // Range containing only |default_val| should be available.
+ ExpectOptions({default_val, default_val});
+ // |default_val| should be default option.
+ ExpectValue(default_val);
+}
+
+TEST_F(ControlFactoryTest, V4L2FactoryQueryFail) {
+ int control_id = 55;
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _)).WillOnce(Return(-1));
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ // Failure, should return null.
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(ControlFactoryTest, V4L2FactoryQueryBadType) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_CTRL_CLASS;
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ // Failure, should return null.
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(ControlFactoryTest, V4L2FactoryQueryBadRange) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_MENU;
+ query_result.minimum = 10;
+ query_result.maximum = 1; // Less than minimum.
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ // Failure, should return null.
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(ControlFactoryTest, V4L2FactoryTypeRequestMenuMismatch) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_INTEGER;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+ // Have conversions for values 1-5, by step size 2.
+ std::map<int32_t, uint8_t> conversion_map = {{1, 10}, {3, 30}, {5, 50}};
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+
+ // If you ask for a Menu, but the V4L2 control is a slider type, that's bad.
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(ControlFactoryTest, V4L2FactoryTypeRequestSliderMismatch) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_MENU;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+ // Have conversions for values 1-5, by step size 2.
+ std::map<int32_t, uint8_t> conversion_map = {{1, 10}, {3, 30}, {5, 50}};
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+
+ // If you ask for a Slider and get a Menu, that's bad.
+ control_ = V4L2Control<uint8_t>(ControlType::kSlider,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(ControlFactoryTest, V4L2FactoryMenu) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_MENU;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+ // Have conversions for values 1-5, by step size 2.
+ std::map<int32_t, uint8_t> conversion_map = {{1, 10}, {3, 30}, {5, 50}};
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ // Should convert values.
+ std::vector<uint8_t> expected_options;
+ for (auto kv : conversion_map) {
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(kv.first, _))
+ .WillOnce(DoAll(SetArgPointee<1>(kv.second), Return(0)));
+ expected_options.push_back(kv.second);
+ }
+ // Will fail to convert 7 with -EINVAL, shouldn't matter.
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(7, _)).WillOnce(Return(-EINVAL));
+
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectTags();
+ ExpectOptions(expected_options);
+}
+
+TEST_F(ControlFactoryTest, V4L2FactoryMenuConversionFail) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_MENU;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ // Conversion fails with non-EINVAL error.
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(_, _)).WillOnce(Return(-1));
+
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(ControlFactoryTest, V4L2FactoryMenuNoConversions) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_MENU;
+ query_result.minimum = 1;
+ query_result.maximum = 1;
+ query_result.step = 1;
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ // Conversion fails with -EINVAL error.
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(1, _)).WillOnce(Return(-EINVAL));
+
+ control_ = V4L2Control<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ // Since there were no convertable options, should fail.
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(ControlFactoryTest, V4L2FactoryInteger) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_INTEGER;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+ // Have conversions for values 1 & 7.
+ std::map<int32_t, uint8_t> conversion_map = {{1, 10}, {7, 70}};
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ // Should convert values.
+ std::vector<uint8_t> expected_options;
+ for (auto kv : conversion_map) {
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(kv.first, _))
+ .WillOnce(DoAll(SetArgPointee<1>(kv.second), Return(0)));
+ expected_options.push_back(kv.second);
+ }
+
+ control_ = V4L2Control<uint8_t>(ControlType::kSlider,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectTags();
+ ExpectOptions(expected_options);
+
+ // Should be fitting converted values to steps.
+ uint8_t set_val = 10;
+ android::CameraMetadata metadata;
+ EXPECT_EQ(UpdateMetadata(&metadata, delegate_tag_, set_val), 0);
+ EXPECT_CALL(*mock_converter_, MetadataToV4L2(set_val, _))
+ .WillOnce(DoAll(SetArgPointee<1>(4), Return(0)));
+ // When it calls into the device, the 4 returned above should be
+ // rounded down to the step value of 3.
+ EXPECT_CALL(*mock_device_, SetControl(control_id, 3, _)).WillOnce(Return(0));
+ EXPECT_EQ(control_->SetRequestValues(metadata), 0);
+}
+
+TEST_F(ControlFactoryTest, V4L2FactoryIntegerFailedConversion) {
+ int control_id = 55;
+ v4l2_query_ext_ctrl query_result;
+ query_result.type = V4L2_CTRL_TYPE_INTEGER;
+ query_result.minimum = 1;
+ query_result.maximum = 7;
+ query_result.step = 2;
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _))
+ .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
+ // Fail to convert a value. Even -EINVAL is bad in this case.
+ EXPECT_CALL(*mock_converter_, V4L2ToMetadata(1, _)).WillOnce(Return(-EINVAL));
+
+ control_ = V4L2Control<uint8_t>(ControlType::kSlider,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_);
+ ASSERT_EQ(control_, nullptr);
+}
+
+TEST_F(ControlFactoryTest, V4L2FallbackMenu) {
+ uint8_t default_val = 9;
+ int control_id = 55;
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _)).WillOnce(Return(-1));
+
+ // Shouldn't fail, should fall back to menu control.
+ control_ = V4L2ControlOrDefault<uint8_t>(ControlType::kMenu,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_,
+ default_val);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectTags();
+
+ // Options should be available.
+ ExpectOptions({default_val});
+ // |default_val| should be default option.
+ ExpectValue(default_val);
+}
+
+TEST_F(ControlFactoryTest, V4L2FallbackSlider) {
+ uint8_t default_val = 9;
+ int control_id = 55;
+
+ // Should query the device.
+ EXPECT_CALL(*mock_device_, QueryControl(control_id, _)).WillOnce(Return(-1));
+
+ // Shouldn't fail, should fall back to slider control.
+ control_ = V4L2ControlOrDefault<uint8_t>(ControlType::kSlider,
+ delegate_tag_,
+ options_tag_,
+ mock_device_,
+ control_id,
+ mock_converter_,
+ default_val);
+ ASSERT_NE(control_, nullptr);
+
+ ExpectTags();
+
+ // Range containing only |default_val| should be available.
+ ExpectOptions({default_val, default_val});
+ // |default_val| should be default option.
+ ExpectValue(default_val);
+}
+
+} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/control_test.cpp b/modules/camera/3_4/metadata/control_test.cpp
index b414ad3..5297a01 100644
--- a/modules/camera/3_4/metadata/control_test.cpp
+++ b/modules/camera/3_4/metadata/control_test.cpp
@@ -28,7 +28,6 @@
using testing::AtMost;
using testing::Expectation;
using testing::Return;
-using testing::ReturnRef;
using testing::SetArgPointee;
using testing::Test;
using testing::_;
@@ -62,6 +61,35 @@
}
}
+ virtual void ExpectTags(bool with_options = true) {
+ if (with_options) {
+ ASSERT_EQ(control_->StaticTags().size(), 1);
+ EXPECT_EQ(control_->StaticTags()[0], options_tag_);
+ } else {
+ EXPECT_TRUE(control_->StaticTags().empty());
+ }
+ // Controls use the same delgate, and thus tag, for getting and setting.
+ ASSERT_EQ(control_->ControlTags().size(), 1);
+ EXPECT_EQ(control_->ControlTags()[0], delegate_tag_);
+ ASSERT_EQ(control_->DynamicTags().size(), 1);
+ EXPECT_EQ(control_->DynamicTags()[0], delegate_tag_);
+ }
+
+ virtual void ExpectOptions(const std::vector<uint8_t>& options) {
+ // Options should be available.
+ android::CameraMetadata metadata;
+ ASSERT_EQ(control_->PopulateStaticFields(&metadata), 0);
+ EXPECT_EQ(metadata.entryCount(), 1);
+ ExpectMetadataEq(metadata, options_tag_, options);
+ }
+
+ virtual void ExpectValue(uint8_t value) {
+ android::CameraMetadata metadata;
+ ASSERT_EQ(control_->PopulateDynamicFields(&metadata), 0);
+ EXPECT_EQ(metadata.entryCount(), 1);
+ ExpectMetadataEq(metadata, delegate_tag_, value);
+ }
+
std::unique_ptr<Control<uint8_t>> control_;
std::unique_ptr<ControlDelegateInterfaceMock<uint8_t>> mock_delegate_;
std::unique_ptr<ControlOptionsInterfaceMock<uint8_t>> mock_options_;
@@ -74,24 +102,12 @@
TEST_F(ControlTest, Tags) {
PrepareControl();
- ASSERT_EQ(control_->StaticTags().size(), 1);
- EXPECT_EQ(control_->StaticTags()[0], options_tag_);
- // Controls use the same delgate, and thus tag, for getting and setting.
- ASSERT_EQ(control_->ControlTags().size(), 1);
- EXPECT_EQ(control_->ControlTags()[0], delegate_tag_);
- ASSERT_EQ(control_->DynamicTags().size(), 1);
- EXPECT_EQ(control_->DynamicTags()[0], delegate_tag_);
+ ExpectTags();
}
TEST_F(ControlTest, TagsNoOptions) {
PrepareControl(false);
- // No options, so no options tag.
- ASSERT_EQ(control_->StaticTags().size(), 0);
- // Controls use the same delgate, and thus tag, for getting and setting.
- ASSERT_EQ(control_->ControlTags().size(), 1);
- EXPECT_EQ(control_->ControlTags()[0], delegate_tag_);
- ASSERT_EQ(control_->DynamicTags().size(), 1);
- EXPECT_EQ(control_->DynamicTags()[0], delegate_tag_);
+ ExpectTags(false);
}
TEST_F(ControlTest, PopulateStatic) {
@@ -99,13 +115,7 @@
EXPECT_CALL(*mock_options_, MetadataRepresentation())
.WillOnce(Return(expected));
PrepareControl();
-
- android::CameraMetadata metadata;
- ASSERT_EQ(control_->PopulateStaticFields(&metadata), 0);
- // Should only have added 1 entry.
- EXPECT_EQ(metadata.entryCount(), 1);
- // Should have added the right entry.
- ExpectMetadataEq(metadata, options_tag_, expected);
+ ExpectOptions(expected);
}
TEST_F(ControlTest, PopulateStaticNoOptions) {
@@ -121,14 +131,7 @@
EXPECT_CALL(*mock_delegate_, GetValue(_))
.WillOnce(DoAll(SetArgPointee<0>(test_option), Return(0)));
PrepareControl();
-
- android::CameraMetadata metadata;
- ASSERT_EQ(control_->PopulateDynamicFields(&metadata), 0);
-
- // Should only have added 1 entry.
- EXPECT_EQ(metadata.entryCount(), 1);
- // Should have added the right entry.
- ExpectMetadataEq(metadata, delegate_tag_, test_option);
+ ExpectValue(test_option);
}
TEST_F(ControlTest, PopulateDynamicNoOptions) {
@@ -137,14 +140,7 @@
EXPECT_CALL(*mock_delegate_, GetValue(_))
.WillOnce(DoAll(SetArgPointee<0>(test_option), Return(0)));
PrepareControl(false);
-
- android::CameraMetadata metadata;
- EXPECT_EQ(control_->PopulateDynamicFields(&metadata), 0);
-
- // Should only have added 1 entry.
- EXPECT_EQ(metadata.entryCount(), 1);
- // Should have added the right entry.
- ExpectMetadataEq(metadata, delegate_tag_, test_option);
+ ExpectValue(test_option);
}
TEST_F(ControlTest, PopulateDynamicFail) {
@@ -303,31 +299,4 @@
EXPECT_EQ(control_->SetRequestValues(metadata), 0);
}
-TEST_F(ControlTest, NoEffectMenuFactory) {
- std::vector<uint8_t> test_options = {9, 8, 12};
- std::unique_ptr<Control<uint8_t>> dut = Control<uint8_t>::NoEffectMenuControl(
- delegate_tag_, options_tag_, test_options);
- ASSERT_NE(dut, nullptr);
-
- ASSERT_EQ(dut->StaticTags().size(), 1);
- EXPECT_EQ(dut->StaticTags()[0], options_tag_);
- // Controls use the same delgate, and thus tag, for getting and setting.
- ASSERT_EQ(dut->ControlTags().size(), 1);
- EXPECT_EQ(dut->ControlTags()[0], delegate_tag_);
- ASSERT_EQ(dut->DynamicTags().size(), 1);
- EXPECT_EQ(dut->DynamicTags()[0], delegate_tag_);
-
- // Options should be available.
- android::CameraMetadata metadata;
- ASSERT_EQ(dut->PopulateStaticFields(&metadata), 0);
- EXPECT_EQ(metadata.entryCount(), 1);
- ExpectMetadataEq(metadata, options_tag_, test_options);
-
- // Default value should be test_options[0].
- metadata.clear();
- ASSERT_EQ(dut->PopulateDynamicFields(&metadata), 0);
- EXPECT_EQ(metadata.entryCount(), 1);
- ExpectMetadataEq(metadata, delegate_tag_, test_options[0]);
-}
-
} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/v4l2_metadata.cpp b/modules/camera/3_4/v4l2_metadata.cpp
index c289a40..06bd8d9 100644
--- a/modules/camera/3_4/v4l2_metadata.cpp
+++ b/modules/camera/3_4/v4l2_metadata.cpp
@@ -20,6 +20,8 @@
#include "common.h"
#include "metadata/control.h"
+#include "metadata/control_factory.h"
+#include "metadata/enum_converter.h"
#include "metadata/property.h"
namespace v4l2_camera_hal {
@@ -36,7 +38,7 @@
// V4L2 enum controls. Will add the other properties as more PartialMetadata
// subclasses get implemented.
- AddComponent(Control<uint8_t>::NoEffectMenuControl(
+ AddComponent(NoEffectMenuControl<uint8_t>(
ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
{ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST,
@@ -48,37 +50,46 @@
AddComponent(std::unique_ptr<PartialMetadataInterface>(
new Property<std::array<int32_t, 3>>(ANDROID_CONTROL_MAX_REGIONS,
{{/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0}})));
- AddEnumControlOrDefault(V4L2_CID_EXPOSURE_AUTO,
- ANDROID_CONTROL_AE_MODE,
- ANDROID_CONTROL_AE_AVAILABLE_MODES,
- {{V4L2_EXPOSURE_AUTO, ANDROID_CONTROL_AE_MODE_ON},
- {V4L2_EXPOSURE_MANUAL, ANDROID_CONTROL_AE_MODE_OFF}},
- ANDROID_CONTROL_AE_MODE_ON);
- AddEnumControlOrDefault(V4L2_CID_POWER_LINE_FREQUENCY,
- ANDROID_CONTROL_AE_ANTIBANDING_MODE,
- ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
- {{V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
- ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF},
- {V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
- ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ},
- {V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
- ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ},
- {V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
- ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO}},
- ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO);
+ AddComponent(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
+ ANDROID_CONTROL_AE_MODE,
+ ANDROID_CONTROL_AE_AVAILABLE_MODES,
+ device_,
+ V4L2_CID_EXPOSURE_AUTO,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
+ {{V4L2_EXPOSURE_AUTO, ANDROID_CONTROL_AE_MODE_ON},
+ {V4L2_EXPOSURE_MANUAL, ANDROID_CONTROL_AE_MODE_OFF}})),
+ ANDROID_CONTROL_AE_MODE_ON));
+ AddComponent(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+ ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+ device_,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(
+ new EnumConverter({{V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF},
+ {V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ},
+ {V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ},
+ {V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO}})),
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO));
// V4L2 offers multiple white balance interfaces. Try the advanced one before
// falling
// back to the simpler version.
// Modes from each API that don't match up:
// Android: WARM_FLUORESCENT, TWILIGHT.
// V4L2: FLUORESCENT_H, HORIZON, FLASH.
- /* TODO(b/30900438): Use v4l2 control factory.
- std::unique_ptr<PartialMetadataInterface> awb(
- V4L2EnumControl::NewV4L2EnumControl(
- device_,
- V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
- ANDROID_CONTROL_AWB_MODE,
- ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+ std::unique_ptr<PartialMetadataInterface> awb(V4L2Control<
+ uint8_t>(
+ ControlType::kMenu,
+ ANDROID_CONTROL_AWB_MODE,
+ ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+ device_,
+ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
{{V4L2_WHITE_BALANCE_MANUAL, ANDROID_CONTROL_AWB_MODE_OFF},
{V4L2_WHITE_BALANCE_AUTO, ANDROID_CONTROL_AWB_MODE_AUTO},
{V4L2_WHITE_BALANCE_INCANDESCENT,
@@ -88,73 +99,83 @@
{V4L2_WHITE_BALANCE_DAYLIGHT, ANDROID_CONTROL_AWB_MODE_DAYLIGHT},
{V4L2_WHITE_BALANCE_CLOUDY,
ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT},
- {V4L2_WHITE_BALANCE_SHADE, ANDROID_CONTROL_AWB_MODE_SHADE}}));
+ {V4L2_WHITE_BALANCE_SHADE, ANDROID_CONTROL_AWB_MODE_SHADE}}))));
if (awb) {
AddComponent(std::move(awb));
} else {
// Fall back to simpler AWB or even just an ignored control.
- AddEnumControlOrDefault(
- V4L2_CID_AUTO_WHITE_BALANCE,
+ AddComponent(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
ANDROID_CONTROL_AWB_MODE,
ANDROID_CONTROL_AWB_AVAILABLE_MODES,
- {{0, ANDROID_CONTROL_AWB_MODE_OFF}, {1, ANDROID_CONTROL_AWB_MODE_AUTO}},
- ANDROID_CONTROL_AWB_MODE_AUTO);
+ device_,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(
+ new EnumConverter({{0, ANDROID_CONTROL_AWB_MODE_OFF},
+ {1, ANDROID_CONTROL_AWB_MODE_AUTO}})),
+ ANDROID_CONTROL_AWB_MODE_AUTO));
}
- */
// TODO(b/30510395): subcomponents of scene modes
// (may itself be a subcomponent of 3A).
// Modes from each API that don't match up:
// Android: FACE_PRIORITY, ACTION, NIGHT_PORTRAIT, THEATRE, STEADYPHOTO,
- // BARCODE, HIGH_SPEED_VIDEO, SNOW (combined with BEACH in V4L2. Only BEACH
- // is reported to avoid ambiguity).
+ // BARCODE, HIGH_SPEED_VIDEO.
// V4L2: BACKLIGHT, DAWN_DUSK, FALL_COLORS, TEXT.
- AddEnumControlOrDefault(
- V4L2_CID_SCENE_MODE,
+ AddComponent(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
ANDROID_CONTROL_SCENE_MODE,
ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
- {{V4L2_SCENE_MODE_NONE, ANDROID_CONTROL_SCENE_MODE_DISABLED},
- {V4L2_SCENE_MODE_BEACH_SNOW, ANDROID_CONTROL_SCENE_MODE_BEACH},
- {V4L2_SCENE_MODE_CANDLE_LIGHT, ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT},
- {V4L2_SCENE_MODE_FIREWORKS, ANDROID_CONTROL_SCENE_MODE_FIREWORKS},
- {V4L2_SCENE_MODE_LANDSCAPE, ANDROID_CONTROL_SCENE_MODE_LANDSCAPE},
- {V4L2_SCENE_MODE_NIGHT, ANDROID_CONTROL_SCENE_MODE_NIGHT},
- {V4L2_SCENE_MODE_PARTY_INDOOR, ANDROID_CONTROL_SCENE_MODE_PARTY},
- {V4L2_SCENE_MODE_SPORTS, ANDROID_CONTROL_SCENE_MODE_SPORTS},
- {V4L2_SCENE_MODE_SUNSET, ANDROID_CONTROL_SCENE_MODE_SUNSET}},
- ANDROID_CONTROL_SCENE_MODE_DISABLED);
+ device_,
+ V4L2_CID_SCENE_MODE,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
+ {{V4L2_SCENE_MODE_NONE, ANDROID_CONTROL_SCENE_MODE_DISABLED},
+ {V4L2_SCENE_MODE_BEACH_SNOW, ANDROID_CONTROL_SCENE_MODE_BEACH},
+ {V4L2_SCENE_MODE_BEACH_SNOW, ANDROID_CONTROL_SCENE_MODE_SNOW},
+ {V4L2_SCENE_MODE_CANDLE_LIGHT,
+ ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT},
+ {V4L2_SCENE_MODE_FIREWORKS, ANDROID_CONTROL_SCENE_MODE_FIREWORKS},
+ {V4L2_SCENE_MODE_LANDSCAPE, ANDROID_CONTROL_SCENE_MODE_LANDSCAPE},
+ {V4L2_SCENE_MODE_NIGHT, ANDROID_CONTROL_SCENE_MODE_NIGHT},
+ {V4L2_SCENE_MODE_PARTY_INDOOR, ANDROID_CONTROL_SCENE_MODE_PARTY},
+ {V4L2_SCENE_MODE_SPORTS, ANDROID_CONTROL_SCENE_MODE_SPORTS},
+ {V4L2_SCENE_MODE_SUNSET, ANDROID_CONTROL_SCENE_MODE_SUNSET}})),
+ ANDROID_CONTROL_SCENE_MODE_DISABLED));
// Modes from each API that don't match up:
// Android: POSTERIZE, WHITEBOARD, BLACKBOARD.
// V4L2: ANTIQUE, ART_FREEZE, EMBOSS, GRASS_GREEN, SKETCH, SKIN_WHITEN,
// SKY_BLUE, SILHOUETTE, VIVID, SET_CBCR.
- AddEnumControlOrDefault(
- V4L2_CID_COLORFX,
+ AddComponent(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
ANDROID_CONTROL_EFFECT_MODE,
ANDROID_CONTROL_AVAILABLE_EFFECTS,
- {{V4L2_COLORFX_NONE, ANDROID_CONTROL_EFFECT_MODE_OFF},
- {V4L2_COLORFX_BW, ANDROID_CONTROL_EFFECT_MODE_MONO},
- {V4L2_COLORFX_NEGATIVE, ANDROID_CONTROL_EFFECT_MODE_NEGATIVE},
- {V4L2_COLORFX_SOLARIZATION, ANDROID_CONTROL_EFFECT_MODE_SOLARIZE},
- {V4L2_COLORFX_SEPIA, ANDROID_CONTROL_EFFECT_MODE_SEPIA},
- {V4L2_COLORFX_AQUA, ANDROID_CONTROL_EFFECT_MODE_AQUA}},
- ANDROID_CONTROL_EFFECT_MODE_OFF);
+ device_,
+ V4L2_CID_COLORFX,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
+ {{V4L2_COLORFX_NONE, ANDROID_CONTROL_EFFECT_MODE_OFF},
+ {V4L2_COLORFX_BW, ANDROID_CONTROL_EFFECT_MODE_MONO},
+ {V4L2_COLORFX_NEGATIVE, ANDROID_CONTROL_EFFECT_MODE_NEGATIVE},
+ {V4L2_COLORFX_SOLARIZATION, ANDROID_CONTROL_EFFECT_MODE_SOLARIZE},
+ {V4L2_COLORFX_SEPIA, ANDROID_CONTROL_EFFECT_MODE_SEPIA},
+ {V4L2_COLORFX_AQUA, ANDROID_CONTROL_EFFECT_MODE_AQUA}})),
+ ANDROID_CONTROL_EFFECT_MODE_OFF));
// Not sure if V4L2 does or doesn't do this, but HAL documentation says
// all devices must support FAST, and FAST can be equivalent to OFF, so
// either way it's fine to list.
- AddComponent(
- Control<uint8_t>::NoEffectMenuControl(ANDROID_EDGE_MODE,
- ANDROID_EDGE_AVAILABLE_EDGE_MODES,
- {ANDROID_EDGE_MODE_FAST}));
+ AddComponent(NoEffectMenuControl<uint8_t>(
+ ANDROID_EDGE_MODE,
+ ANDROID_EDGE_AVAILABLE_EDGE_MODES,
+ {ANDROID_EDGE_MODE_FAST}));
// TODO(30510395): subcomponents of hotpixel.
// No known V4L2 hot pixel correction. But it might be happening,
// so we report FAST/HIGH_QUALITY.
- AddComponent(Control<uint8_t>::NoEffectMenuControl(
+ AddComponent(NoEffectMenuControl<uint8_t>(
ANDROID_HOT_PIXEL_MODE,
ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES,
{ANDROID_HOT_PIXEL_MODE_FAST, ANDROID_HOT_PIXEL_MODE_HIGH_QUALITY}));
// ON only needs to be supported for RAW capable devices.
- AddComponent(Control<uint8_t>::NoEffectMenuControl(
+ AddComponent(NoEffectMenuControl<uint8_t>(
ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
{ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF}));
@@ -162,17 +183,17 @@
// TODO(30510395): subcomponents focus/lens.
// No way to actually get the aperture and focal length
// in V4L2, but they're required keys, so fake them.
- AddComponent(
- Control<float>::NoEffectMenuControl(ANDROID_LENS_APERTURE,
- ANDROID_LENS_INFO_AVAILABLE_APERTURES,
- {2.0})); // RPi camera v2 is f/2.0.
- AddComponent(Control<float>::NoEffectMenuControl(
+ AddComponent(NoEffectMenuControl<float>(
+ ANDROID_LENS_APERTURE,
+ ANDROID_LENS_INFO_AVAILABLE_APERTURES,
+ {2.0})); // RPi camera v2 is f/2.0.
+ AddComponent(NoEffectMenuControl<float>(
ANDROID_LENS_FOCAL_LENGTH,
ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
{3.04})); // RPi camera v2 is 3.04mm.
// No known way to get filter densities from V4L2,
// report 0 to indicate this control is not supported.
- AddComponent(Control<float>::NoEffectMenuControl(
+ AddComponent(NoEffectMenuControl<float>(
ANDROID_LENS_FILTER_DENSITY,
ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES,
{0.0}));
@@ -183,31 +204,35 @@
// info.hyperfocalDistance not required for UNCALIBRATED.
// No known V4L2 lens shading. But it might be happening,
// so report FAST/HIGH_QUALITY.
- AddComponent(Control<uint8_t>::NoEffectMenuControl(
+ AddComponent(NoEffectMenuControl<uint8_t>(
ANDROID_SHADING_MODE,
ANDROID_SHADING_AVAILABLE_MODES,
{ANDROID_SHADING_MODE_FAST, ANDROID_SHADING_MODE_HIGH_QUALITY}));
// ON only needs to be supported for RAW capable devices.
- AddComponent(Control<uint8_t>::NoEffectMenuControl(
+ AddComponent(NoEffectMenuControl<uint8_t>(
ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
{ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF}));
// V4L2 doesn't differentiate between OPTICAL and VIDEO stabilization,
// so only report one (and report the other as OFF).
- AddEnumControlOrDefault(V4L2_CID_IMAGE_STABILIZATION,
- ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
- ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
- {{0, ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF},
- {1, ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON}},
- ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF);
- AddComponent(Control<uint8_t>::NoEffectMenuControl(
+ AddComponent(V4L2ControlOrDefault<uint8_t>(
+ ControlType::kMenu,
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+ ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+ device_,
+ V4L2_CID_IMAGE_STABILIZATION,
+ std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
+ {{0, ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF},
+ {1, ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON}})),
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF));
+ AddComponent(NoEffectMenuControl<uint8_t>(
ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
{ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF}));
// Unable to control noise reduction in V4L2 devices,
// but FAST is allowed to be the same as OFF.
- AddComponent(Control<uint8_t>::NoEffectMenuControl(
+ AddComponent(NoEffectMenuControl<uint8_t>(
ANDROID_NOISE_REDUCTION_MODE,
ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
{ANDROID_NOISE_REDUCTION_MODE_FAST}));
@@ -216,7 +241,7 @@
// For now, no thumbnails available (only [0,0], the "no thumbnail" size).
// TODO(b/29580107): Could end up with a mismatch between request & result,
// since V4L2 doesn't actually allow for thumbnail size control.
- AddComponent(Control<std::array<int32_t, 2>>::NoEffectMenuControl(
+ AddComponent(NoEffectMenuControl<std::array<int32_t, 2>>(
ANDROID_JPEG_THUMBNAIL_SIZE,
ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
{{{0, 0}}}));
@@ -265,7 +290,7 @@
// TODO(30510395): subcomponents of face detection.
// Face detection not supported.
- AddComponent(Control<uint8_t>::NoEffectMenuControl(
+ AddComponent(NoEffectMenuControl<uint8_t>(
ANDROID_STATISTICS_FACE_DETECT_MODE,
ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
{ANDROID_STATISTICS_FACE_DETECT_MODE_OFF}));
@@ -288,20 +313,4 @@
HAL_LOG_ENTER();
}
-void V4L2Metadata::AddEnumControlOrDefault(
- int v4l2_control,
- int32_t control_tag,
- int32_t options_tag,
- const std::map<int32_t, uint8_t>& v4l2_to_metadata,
- uint8_t default_value) {
- HAL_LOG_ENTER();
- // TODO(b/30900438): Replace this function with a V4L2 control factory.
-
- std::unique_ptr<PartialMetadataInterface> control(
- Control<uint8_t>::NoEffectMenuControl(
- control_tag, options_tag, {default_value}));
-
- AddComponent(std::move(control));
-}
-
} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/v4l2_metadata.h b/modules/camera/3_4/v4l2_metadata.h
index a046d3f..29e69b9 100644
--- a/modules/camera/3_4/v4l2_metadata.h
+++ b/modules/camera/3_4/v4l2_metadata.h
@@ -34,15 +34,6 @@
virtual ~V4L2Metadata();
private:
- // Attempt to construct and add an enum control. If construction fails,
- // use an IgnoredControl with only the default value instead.
- void AddEnumControlOrDefault(
- int v4l2_control,
- int32_t control_tag,
- int32_t options_tag,
- const std::map<int32_t, uint8_t>& v4l2_to_metadata,
- uint8_t default_value);
-
// Access to the device.
std::shared_ptr<V4L2Wrapper> device_;