Add V4L2 Format Metadata Factory.

This factory queries the device for the properties detailing
what formats it supports. Since this may fail, Metadata/V4L2Metadata
was moved from the weird inheritance/constructor stuff it was doing
to Metadata having a better constructor and V4L2Metadata being a
factory.

BUG: 30140438
TEST: unit tests pass

Change-Id: Id4bcb27fbd8b517e3a9a8e9fb8a984af139254b3
diff --git a/modules/camera/3_4/Android.mk b/modules/camera/3_4/Android.mk
index ae28598..140e73b 100644
--- a/modules/camera/3_4/Android.mk
+++ b/modules/camera/3_4/Android.mk
@@ -39,6 +39,7 @@
 
 v4l2_src_files := \
   camera.cpp \
+  format_metadata_factory.cpp \
   metadata/enum_converter.cpp \
   metadata/metadata.cpp \
   stream.cpp \
@@ -46,10 +47,11 @@
   v4l2_camera.cpp \
   v4l2_camera_hal.cpp \
   v4l2_gralloc.cpp \
-  v4l2_metadata.cpp \
+  v4l2_metadata_factory.cpp \
   v4l2_wrapper.cpp \
 
 v4l2_test_files := \
+  format_metadata_factory_test.cpp \
   metadata/control_factory_test.cpp \
   metadata/control_test.cpp \
   metadata/enum_converter_test.cpp \
diff --git a/modules/camera/3_4/format_metadata_factory.cpp b/modules/camera/3_4/format_metadata_factory.cpp
new file mode 100644
index 0000000..83cf5cc
--- /dev/null
+++ b/modules/camera/3_4/format_metadata_factory.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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 "format_metadata_factory.h"
+
+#include "metadata/array_vector.h"
+
+namespace v4l2_camera_hal {
+
+static int GetHalFormats(const std::shared_ptr<V4L2Wrapper>& device,
+                         std::set<int32_t>* result_formats) {
+  if (!result_formats) {
+    HAL_LOGE("Null result formats pointer passed");
+    return -EINVAL;
+  }
+
+  std::set<uint32_t> v4l2_formats;
+  int res = device->GetFormats(&v4l2_formats);
+  if (res) {
+    HAL_LOGE("Failed to get device formats.");
+    return res;
+  }
+  for (auto v4l2_format : v4l2_formats) {
+    int32_t hal_format = StreamFormat::V4L2ToHalPixelFormat(v4l2_format);
+    if (hal_format < 0) {
+      // Unrecognized/unused format. Skip it.
+      continue;
+    }
+    result_formats->insert(hal_format);
+  }
+
+  // In addition to well-defined formats, there may be an
+  // "Implementation Defined" format chosen by the HAL (in this
+  // case what that means is managed by the StreamFormat class).
+
+  // Get the V4L2 format for IMPLEMENTATION_DEFINED.
+  int v4l2_format = StreamFormat::HalToV4L2PixelFormat(
+      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+  // If it's available, add IMPLEMENTATION_DEFINED to the result set.
+  if (v4l2_format && v4l2_formats.count(v4l2_format) > 0) {
+    result_formats->insert(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+  }
+
+  return 0;
+}
+
+int AddFormatComponents(
+    std::shared_ptr<V4L2Wrapper> device,
+    std::insert_iterator<PartialMetadataSet> insertion_point) {
+  HAL_LOG_ENTER();
+
+  // Get all supported formats.
+  std::set<int32_t> hal_formats;
+  int res = GetHalFormats(device, &hal_formats);
+  if (res) {
+    return res;
+  }
+
+  // Requirements check: need to support YCbCr_420_888, JPEG,
+  // and "Implementation Defined".
+  if (hal_formats.find(HAL_PIXEL_FORMAT_YCbCr_420_888) == hal_formats.end()) {
+    HAL_LOGE("YCbCr_420_888 not supported by device.");
+    return -ENODEV;
+  } else if (hal_formats.find(HAL_PIXEL_FORMAT_BLOB) == hal_formats.end()) {
+    HAL_LOGE("JPEG not supported by device.");
+    return -ENODEV;
+  } else if (hal_formats.find(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) ==
+             hal_formats.end()) {
+    HAL_LOGE("HAL implementation defined format not supported by device.");
+    return -ENODEV;
+  }
+
+  // Find sizes and frame/stall durations for all formats.
+  // We also want to find the smallest max frame duration amongst all formats,
+  // And the largest min frame duration amongst YUV (i.e. largest max frame rate
+  // supported by all YUV sizes).
+  // Stream configs are {format, width, height, direction} (input or output).
+  ArrayVector<int32_t, 4> stream_configs;
+  // Frame durations are {format, width, height, duration} (duration in ns).
+  ArrayVector<int64_t, 4> min_frame_durations;
+  // Stall durations are {format, width, height, duration} (duration in ns).
+  ArrayVector<int64_t, 4> stall_durations;
+  int64_t min_max_frame_duration = std::numeric_limits<int64_t>::max();
+  int64_t max_min_frame_duration_yuv = std::numeric_limits<int64_t>::min();
+  for (auto hal_format : hal_formats) {
+    // Get the corresponding V4L2 format.
+    uint32_t v4l2_format = StreamFormat::HalToV4L2PixelFormat(hal_format);
+    if (v4l2_format == 0) {
+      // Unrecognized/unused format. Should never happen since hal_formats
+      // came from translating a bunch of V4L2 formats above.
+      HAL_LOGE("Couldn't find V4L2 format for HAL format %d", hal_format);
+      return -ENODEV;
+    }
+
+    // Get the available sizes for this format.
+    std::set<std::array<int32_t, 2>> frame_sizes;
+    res = device->GetFormatFrameSizes(v4l2_format, &frame_sizes);
+    if (res) {
+      HAL_LOGE("Failed to get all frame sizes for format %d", v4l2_format);
+      return res;
+    }
+
+    for (const auto& frame_size : frame_sizes) {
+      // Note the format and size combination in stream configs.
+      stream_configs.push_back(
+          {{hal_format,
+            frame_size[0],
+            frame_size[1],
+            ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT}});
+
+      // Find the duration range for this format and size.
+      std::array<int64_t, 2> duration_range;
+      res = device->GetFormatFrameDurationRange(
+          v4l2_format, frame_size, &duration_range);
+      if (res) {
+        HAL_LOGE(
+            "Failed to get frame duration range for format %d, "
+            "size %u x %u",
+            v4l2_format,
+            frame_size[0],
+            frame_size[1]);
+        return res;
+      }
+      int64_t size_min_frame_duration = duration_range[0];
+      int64_t size_max_frame_duration = duration_range[1];
+      min_frame_durations.push_back({{hal_format,
+                                      frame_size[0],
+                                      frame_size[1],
+                                      size_min_frame_duration}});
+
+      // Note the stall duration for this format and size.
+      // Usually 0 for non-jpeg, non-zero for JPEG.
+      // Randomly choosing absurd 1 sec for JPEG. Unsure what this breaks.
+      int64_t stall_duration = 0;
+      if (hal_format == HAL_PIXEL_FORMAT_BLOB) {
+        stall_duration = 1000000000;
+      }
+      stall_durations.push_back(
+          {{hal_format, frame_size[0], frame_size[1], stall_duration}});
+
+      // Update our search for general min & max frame durations.
+      // In theory max frame duration (min frame rate) should be consistent
+      // between all formats, but we check and only advertise the smallest
+      // available max duration just in case.
+      if (size_max_frame_duration < min_max_frame_duration) {
+        min_max_frame_duration = size_max_frame_duration;
+      }
+      // We only care about the largest min frame duration
+      // (smallest max frame rate) for YUV sizes.
+      if (hal_format == HAL_PIXEL_FORMAT_YCbCr_420_888 &&
+          size_min_frame_duration > max_min_frame_duration_yuv) {
+        max_min_frame_duration_yuv = size_min_frame_duration;
+      }
+    }
+  }
+
+  // Convert from frame durations measured in ns.
+  // Min fps supported by all formats.
+  int32_t min_fps = 1000000000 / min_max_frame_duration;
+  if (min_fps > 15) {
+    HAL_LOGE("Minimum FPS %d is larger than HAL max allowable value of 15",
+             min_fps);
+    return -ENODEV;
+  }
+  // Max fps supported by all YUV formats.
+  int32_t max_yuv_fps = 1000000000 / max_min_frame_duration_yuv;
+  // ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES should be at minimum
+  // {mi, ma}, {ma, ma} where mi and ma are min and max frame rates for
+  // YUV_420_888. Min should be at most 15.
+  std::vector<std::array<int32_t, 2>> fps_ranges;
+  fps_ranges.push_back({{min_fps, max_yuv_fps}});
+  fps_ranges.push_back({{max_yuv_fps, max_yuv_fps}});
+
+  // Construct the metadata components.
+  insertion_point = std::make_unique<Property<ArrayVector<int32_t, 4>>>(
+      ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+      std::move(stream_configs));
+  insertion_point = std::make_unique<Property<ArrayVector<int64_t, 4>>>(
+      ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+      std::move(min_frame_durations));
+  insertion_point = std::make_unique<Property<ArrayVector<int64_t, 4>>>(
+      ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, std::move(stall_durations));
+  insertion_point = std::make_unique<Property<int64_t>>(
+      ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, min_max_frame_duration);
+  // TODO(b/31019725): This should probably not be a NoEffect control.
+  insertion_point = NoEffectMenuControl<std::array<int32_t, 2>>(
+      ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+      ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+      fps_ranges);
+
+  return 0;
+}
+
+}  // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/v4l2_metadata.h b/modules/camera/3_4/format_metadata_factory.h
similarity index 60%
copy from modules/camera/3_4/v4l2_metadata.h
copy to modules/camera/3_4/format_metadata_factory.h
index 29e69b9..f9eb8b2 100644
--- a/modules/camera/3_4/v4l2_metadata.h
+++ b/modules/camera/3_4/format_metadata_factory.h
@@ -14,32 +14,25 @@
  * limitations under the License.
  */
 
-#ifndef V4L2_CAMERA_HAL_V4L2_METADATA_H_
-#define V4L2_CAMERA_HAL_V4L2_METADATA_H_
+#ifndef V4L2_CAMERA_HAL_FORMAT_METADATA_FACTORY_H_
+#define V4L2_CAMERA_HAL_FORMAT_METADATA_FACTORY_H_
 
-#include <map>
+#include <iterator>
 #include <memory>
-
-#include <hardware/camera3.h>
+#include <set>
 
 #include "common.h"
-#include "metadata/control.h"
-#include "metadata/metadata.h"
+#include "metadata/control_factory.h"
+#include "metadata/metadata_common.h"
+#include "metadata/property.h"
 #include "v4l2_wrapper.h"
 
 namespace v4l2_camera_hal {
-class V4L2Metadata : public Metadata {
- public:
-  V4L2Metadata(std::shared_ptr<V4L2Wrapper> device);
-  virtual ~V4L2Metadata();
 
- private:
-  // Access to the device.
-  std::shared_ptr<V4L2Wrapper> device_;
-
-  DISALLOW_COPY_AND_ASSIGN(V4L2Metadata);
-};
+int AddFormatComponents(
+    std::shared_ptr<V4L2Wrapper> device,
+    std::insert_iterator<PartialMetadataSet> insertion_point);
 
 }  // namespace v4l2_camera_hal
 
-#endif  // V4L2_CAMERA_HAL_V4L2_METADATA_H_
+#endif  // V4L2_CAMERA_HAL_FORMAT_METADATA_FACTORY_H_
diff --git a/modules/camera/3_4/format_metadata_factory_test.cpp b/modules/camera/3_4/format_metadata_factory_test.cpp
new file mode 100644
index 0000000..f033e37
--- /dev/null
+++ b/modules/camera/3_4/format_metadata_factory_test.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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 "format_metadata_factory.h"
+#include "metadata/test_common.h"
+#include "v4l2_wrapper_mock.h"
+
+using testing::AtLeast;
+using testing::Expectation;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class FormatMetadataFactoryTest : public Test {
+ protected:
+  virtual void SetUp() { mock_device_.reset(new V4L2WrapperMock()); }
+
+  virtual void ExpectMetadataTagCount(const android::CameraMetadata& metadata,
+                                      uint32_t tag,
+                                      size_t count) {
+    camera_metadata_ro_entry_t entry = metadata.find(tag);
+    EXPECT_EQ(entry.count, count);
+  }
+
+  std::shared_ptr<V4L2WrapperMock> mock_device_;
+};
+
+TEST_F(FormatMetadataFactoryTest, GetFormatMetadata) {
+  std::set<uint32_t> formats{V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420};
+  std::map<uint32_t, std::set<std::array<int32_t, 2>>> sizes{
+      {V4L2_PIX_FMT_JPEG, {{{10, 20}}, {{30, 60}}, {{120, 240}}}},
+      {V4L2_PIX_FMT_YUV420, {{{1, 2}}, {{3, 6}}, {{12, 24}}}}};
+  // These need to be on the correct order of magnitude,
+  // as there is a check for min fps > 15.
+  std::map<uint32_t, std::map<std::array<int32_t, 2>, std::array<int64_t, 2>>>
+      durations{{V4L2_PIX_FMT_JPEG,
+                 {{{{10, 20}}, {{100000000, 200000000}}},
+                  {{{30, 60}}, {{1000000000, 2000000000}}},
+                  {{{120, 240}}, {{700000000, 1200000000}}}}},
+                {V4L2_PIX_FMT_YUV420,
+                 {{{{1, 2}}, {{10000000000, 20000000000}}},
+                  {{{3, 6}}, {{11000000000, 21000000000}}},
+                  {{{12, 24}}, {{10500000000, 19000000000}}}}}};
+
+  EXPECT_CALL(*mock_device_, GetFormats(_))
+      .WillOnce(DoAll(SetArgPointee<0>(formats), Return(0)));
+
+  for (auto format : formats) {
+    std::set<std::array<int32_t, 2>> format_sizes = sizes[format];
+    EXPECT_CALL(*mock_device_, GetFormatFrameSizes(format, _))
+        .Times(AtLeast(1))
+        .WillRepeatedly(DoAll(SetArgPointee<1>(format_sizes), Return(0)));
+    for (auto size : format_sizes) {
+      EXPECT_CALL(*mock_device_, GetFormatFrameDurationRange(format, size, _))
+          .Times(AtLeast(1))
+          .WillRepeatedly(
+              DoAll(SetArgPointee<2>(durations[format][size]), Return(0)));
+    }
+  }
+
+  PartialMetadataSet components;
+  ASSERT_EQ(AddFormatComponents(mock_device_,
+                                std::inserter(components, components.end())),
+            0);
+
+  for (auto& component : components) {
+    android::CameraMetadata metadata;
+    component->PopulateStaticFields(&metadata);
+    ASSERT_EQ(metadata.entryCount(), 1);
+    int32_t tag = component->StaticTags()[0];
+    switch (tag) {
+      case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS:  // Fall through.
+      case ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS:    // Fall through.
+      case ANDROID_SCALER_AVAILABLE_STALL_DURATIONS:        // Fall through.
+        // 3 sizes per format, 4 elements per config.
+        // # formats + 1 for IMPLEMENTATION_DEFINED.
+        ExpectMetadataTagCount(metadata, tag, (formats.size() + 1) * 3 * 4);
+        break;
+      case ANDROID_SENSOR_INFO_MAX_FRAME_DURATION:
+        // The lowest max duration from above.
+        ExpectMetadataEq(metadata, tag, 200000000);
+        break;
+      case ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES:
+        // 2 ranges ({min, max} and {max, max}), each with a min and max.
+        ExpectMetadataTagCount(metadata, tag, 4);
+        break;
+      default:
+        FAIL() << "Unexpected component created.";
+        break;
+    }
+  }
+}
+}  // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/metadata.cpp b/modules/camera/3_4/metadata/metadata.cpp
index e18a454..976a77d 100644
--- a/modules/camera/3_4/metadata/metadata.cpp
+++ b/modules/camera/3_4/metadata/metadata.cpp
@@ -23,7 +23,8 @@
 
 namespace v4l2_camera_hal {
 
-Metadata::Metadata() {
+Metadata::Metadata(PartialMetadataSet components)
+    : components_(std::move(components)) {
   HAL_LOG_ENTER();
 }
 
@@ -31,13 +32,6 @@
   HAL_LOG_ENTER();
 }
 
-void Metadata::AddComponent(
-    std::unique_ptr<PartialMetadataInterface> component) {
-  HAL_LOG_ENTER();
-
-  components_.push_back(std::move(component));
-}
-
 int Metadata::FillStaticMetadata(android::CameraMetadata* metadata) {
   HAL_LOG_ENTER();
 
diff --git a/modules/camera/3_4/metadata/metadata.h b/modules/camera/3_4/metadata/metadata.h
index 36e238b..0683df2 100644
--- a/modules/camera/3_4/metadata/metadata.h
+++ b/modules/camera/3_4/metadata/metadata.h
@@ -17,16 +17,18 @@
 #ifndef V4L2_CAMERA_HAL_METADATA_H_
 #define V4L2_CAMERA_HAL_METADATA_H_
 
+#include <set>
+
 #include <camera/CameraMetadata.h>
 #include <hardware/camera3.h>
 
 #include "../common.h"
-#include "partial_metadata_interface.h"
+#include "metadata_common.h"
 
 namespace v4l2_camera_hal {
 class Metadata {
  public:
-  Metadata();
+  Metadata(PartialMetadataSet components);
   virtual ~Metadata();
 
   int FillStaticMetadata(android::CameraMetadata* metadata);
@@ -34,16 +36,10 @@
   int SetRequestSettings(const android::CameraMetadata& metadata);
   int FillResultMetadata(android::CameraMetadata* metadata);
 
- protected:
-  // Helper for the child constructors to fill in metadata components.
-  void AddComponent(std::unique_ptr<PartialMetadataInterface> component);
-
  private:
   // The overall metadata is broken down into several distinct pieces.
   // Note: it is undefined behavior if multiple components share tags.
-  std::vector<std::unique_ptr<PartialMetadataInterface>> components_;
-
-  friend class MetadataTest;
+  PartialMetadataSet components_;
 
   DISALLOW_COPY_AND_ASSIGN(Metadata);
 };
diff --git a/modules/camera/3_4/metadata/metadata_common.h b/modules/camera/3_4/metadata/metadata_common.h
index efea152..15f8084 100644
--- a/modules/camera/3_4/metadata/metadata_common.h
+++ b/modules/camera/3_4/metadata/metadata_common.h
@@ -18,14 +18,19 @@
 #define V4L2_CAMERA_HAL_METADATA_METADATA_COMMON_H_
 
 #include <array>
+#include <memory>
+#include <set>
 #include <vector>
 
 #include <camera/CameraMetadata.h>
 
 #include "array_vector.h"
+#include "partial_metadata_interface.h"
 
 namespace v4l2_camera_hal {
 
+typedef std::set<std::unique_ptr<PartialMetadataInterface>> PartialMetadataSet;
+
 // Templated helper functions effectively extending android::CameraMetadata.
 // Will cause a compile-time errors if CameraMetadata doesn't support
 // using the templated type. Templates are provided to extend this support
diff --git a/modules/camera/3_4/metadata/metadata_test.cpp b/modules/camera/3_4/metadata/metadata_test.cpp
index 3ea94ba..e6fb70f 100644
--- a/modules/camera/3_4/metadata/metadata_test.cpp
+++ b/modules/camera/3_4/metadata/metadata_test.cpp
@@ -24,7 +24,8 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include "metadata/partial_metadata_interface_mock.h"
+#include "metadata_common.h"
+#include "partial_metadata_interface_mock.h"
 
 using testing::AtMost;
 using testing::Return;
@@ -36,7 +37,8 @@
 class MetadataTest : public Test {
  protected:
   virtual void SetUp() {
-    dut_.reset(new Metadata());
+    // Clear the DUT. AddComponents must be called before using it.
+    dut_.reset();
 
     component1_.reset(new PartialMetadataInterfaceMock());
     component2_.reset(new PartialMetadataInterfaceMock());
@@ -51,8 +53,10 @@
   virtual void AddComponents() {
     // Don't mind moving; Gmock/Gtest fails on leaked mocks unless disabled by
     // runtime flags.
-    dut_->AddComponent(std::move(component1_));
-    dut_->AddComponent(std::move(component2_));
+    PartialMetadataSet components;
+    components.insert(std::move(component1_));
+    components.insert(std::move(component2_));
+    dut_.reset(new Metadata(std::move(components)));
   }
 
   virtual void CompareTags(const std::set<int32_t>& expected,
diff --git a/modules/camera/3_4/metadata/property.h b/modules/camera/3_4/metadata/property.h
index 1ddd20f..3ded4c4 100644
--- a/modules/camera/3_4/metadata/property.h
+++ b/modules/camera/3_4/metadata/property.h
@@ -27,7 +27,7 @@
 template <typename T>
 class Property : public PartialMetadataInterface {
  public:
-  Property(int32_t tag, T value) : tag_(tag), value_(value){};
+  Property(int32_t tag, T value) : tag_(tag), value_(std::move(value)){};
 
   virtual std::vector<int32_t> StaticTags() const override { return {tag_}; };
 
diff --git a/modules/camera/3_4/v4l2_metadata.cpp b/modules/camera/3_4/v4l2_metadata_factory.cpp
similarity index 77%
rename from modules/camera/3_4/v4l2_metadata.cpp
rename to modules/camera/3_4/v4l2_metadata_factory.cpp
index 06bd8d9..86c9a4d 100644
--- a/modules/camera/3_4/v4l2_metadata.cpp
+++ b/modules/camera/3_4/v4l2_metadata_factory.cpp
@@ -14,20 +14,22 @@
  * limitations under the License.
  */
 
-#include "v4l2_metadata.h"
+#include "v4l2_metadata_factory.h"
 
 #include <camera/CameraMetadata.h>
 
 #include "common.h"
+#include "format_metadata_factory.h"
 #include "metadata/control.h"
 #include "metadata/control_factory.h"
 #include "metadata/enum_converter.h"
+#include "metadata/metadata_common.h"
 #include "metadata/property.h"
 
 namespace v4l2_camera_hal {
 
-V4L2Metadata::V4L2Metadata(std::shared_ptr<V4L2Wrapper> device)
-    : device_(std::move(device)) {
+int GetV4L2Metadata(std::shared_ptr<V4L2Wrapper> device,
+                    std::unique_ptr<Metadata>* result) {
   HAL_LOG_ENTER();
 
   // TODO: Temporarily connect to the device so that V4L2-specific components
@@ -38,7 +40,9 @@
   // V4L2 enum controls. Will add the other properties as more PartialMetadata
   // subclasses get implemented.
 
-  AddComponent(NoEffectMenuControl<uint8_t>(
+  PartialMetadataSet components;
+
+  components.insert(NoEffectMenuControl<uint8_t>(
       ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
       ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
       {ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST,
@@ -47,24 +51,24 @@
   // TODO(b/30510395): subcomponents of 3A.
   // In general, default to ON/AUTO since they imply pretty much nothing,
   // while OFF implies guarantees about not hindering performance.
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(
+  components.insert(std::unique_ptr<PartialMetadataInterface>(
       new Property<std::array<int32_t, 3>>(ANDROID_CONTROL_MAX_REGIONS,
                                            {{/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0}})));
-  AddComponent(V4L2ControlOrDefault<uint8_t>(
+  components.insert(V4L2ControlOrDefault<uint8_t>(
       ControlType::kMenu,
       ANDROID_CONTROL_AE_MODE,
       ANDROID_CONTROL_AE_AVAILABLE_MODES,
-      device_,
+      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>(
+  components.insert(V4L2ControlOrDefault<uint8_t>(
       ControlType::kMenu,
       ANDROID_CONTROL_AE_ANTIBANDING_MODE,
       ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
-      device_,
+      device,
       V4L2_CID_POWER_LINE_FREQUENCY,
       std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(
           new EnumConverter({{V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
@@ -82,12 +86,11 @@
   // Modes from each API that don't match up:
   // Android: WARM_FLUORESCENT, TWILIGHT.
   // V4L2: FLUORESCENT_H, HORIZON, FLASH.
-  std::unique_ptr<PartialMetadataInterface> awb(V4L2Control<
-                                                uint8_t>(
+  std::unique_ptr<PartialMetadataInterface> awb(V4L2Control<uint8_t>(
       ControlType::kMenu,
       ANDROID_CONTROL_AWB_MODE,
       ANDROID_CONTROL_AWB_AVAILABLE_MODES,
-      device_,
+      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},
@@ -101,14 +104,14 @@
             ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT},
            {V4L2_WHITE_BALANCE_SHADE, ANDROID_CONTROL_AWB_MODE_SHADE}}))));
   if (awb) {
-    AddComponent(std::move(awb));
+    components.insert(std::move(awb));
   } else {
     // Fall back to simpler AWB or even just an ignored control.
-    AddComponent(V4L2ControlOrDefault<uint8_t>(
+    components.insert(V4L2ControlOrDefault<uint8_t>(
         ControlType::kMenu,
         ANDROID_CONTROL_AWB_MODE,
         ANDROID_CONTROL_AWB_AVAILABLE_MODES,
-        device_,
+        device,
         V4L2_CID_AUTO_WHITE_BALANCE,
         std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(
             new EnumConverter({{0, ANDROID_CONTROL_AWB_MODE_OFF},
@@ -121,11 +124,11 @@
   // Android: FACE_PRIORITY, ACTION, NIGHT_PORTRAIT, THEATRE, STEADYPHOTO,
   // BARCODE, HIGH_SPEED_VIDEO.
   // V4L2: BACKLIGHT, DAWN_DUSK, FALL_COLORS, TEXT.
-  AddComponent(V4L2ControlOrDefault<uint8_t>(
+  components.insert(V4L2ControlOrDefault<uint8_t>(
       ControlType::kMenu,
       ANDROID_CONTROL_SCENE_MODE,
       ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
-      device_,
+      device,
       V4L2_CID_SCENE_MODE,
       std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
           {{V4L2_SCENE_MODE_NONE, ANDROID_CONTROL_SCENE_MODE_DISABLED},
@@ -144,11 +147,11 @@
   // Android: POSTERIZE, WHITEBOARD, BLACKBOARD.
   // V4L2: ANTIQUE, ART_FREEZE, EMBOSS, GRASS_GREEN, SKETCH, SKIN_WHITEN,
   // SKY_BLUE, SILHOUETTE, VIVID, SET_CBCR.
-  AddComponent(V4L2ControlOrDefault<uint8_t>(
+  components.insert(V4L2ControlOrDefault<uint8_t>(
       ControlType::kMenu,
       ANDROID_CONTROL_EFFECT_MODE,
       ANDROID_CONTROL_AVAILABLE_EFFECTS,
-      device_,
+      device,
       V4L2_CID_COLORFX,
       std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
           {{V4L2_COLORFX_NONE, ANDROID_CONTROL_EFFECT_MODE_OFF},
@@ -162,20 +165,20 @@
   // 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(NoEffectMenuControl<uint8_t>(
-      ANDROID_EDGE_MODE,
-      ANDROID_EDGE_AVAILABLE_EDGE_MODES,
-      {ANDROID_EDGE_MODE_FAST}));
+  components.insert(
+      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(NoEffectMenuControl<uint8_t>(
+  components.insert(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(NoEffectMenuControl<uint8_t>(
+  components.insert(NoEffectMenuControl<uint8_t>(
       ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
       ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
       {ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF}));
@@ -183,56 +186,57 @@
   // 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(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.
+  components.insert(
+      NoEffectMenuControl<float>(ANDROID_LENS_APERTURE,
+                                 ANDROID_LENS_INFO_AVAILABLE_APERTURES,
+                                 {2.0}));  // RPi camera v2 is f/2.0.
+  components.insert(
+      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(NoEffectMenuControl<float>(
-      ANDROID_LENS_FILTER_DENSITY,
-      ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES,
-      {0.0}));
+  components.insert(
+      NoEffectMenuControl<float>(ANDROID_LENS_FILTER_DENSITY,
+                                 ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES,
+                                 {0.0}));
   // V4L2 focal units do not correspond to a particular physical unit.
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(new Property<uint8_t>(
-      ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
-      ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED)));
+  components.insert(
+      std::unique_ptr<PartialMetadataInterface>(new Property<uint8_t>(
+          ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
+          ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED)));
   // info.hyperfocalDistance not required for UNCALIBRATED.
   // No known V4L2 lens shading. But it might be happening,
   // so report FAST/HIGH_QUALITY.
-  AddComponent(NoEffectMenuControl<uint8_t>(
+  components.insert(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(NoEffectMenuControl<uint8_t>(
+  components.insert(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).
-  AddComponent(V4L2ControlOrDefault<uint8_t>(
+  components.insert(V4L2ControlOrDefault<uint8_t>(
       ControlType::kMenu,
       ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
       ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
-      device_,
+      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>(
+  components.insert(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(NoEffectMenuControl<uint8_t>(
+  components.insert(NoEffectMenuControl<uint8_t>(
       ANDROID_NOISE_REDUCTION_MODE,
       ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
       {ANDROID_NOISE_REDUCTION_MODE_FAST}));
@@ -241,76 +245,84 @@
   // 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(NoEffectMenuControl<std::array<int32_t, 2>>(
+  components.insert(NoEffectMenuControl<std::array<int32_t, 2>>(
       ANDROID_JPEG_THUMBNAIL_SIZE,
       ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
       {{{0, 0}}}));
   // TODO(b/29939583): V4L2 can only support 1 stream at a time.
   // For now, just reporting minimum allowable for LIMITED devices.
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(
+  components.insert(std::unique_ptr<PartialMetadataInterface>(
       new Property<std::array<int32_t, 3>>(
           ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
           {{/* Raw */ 0, /* Non-stalling */ 2, /* Stalling */ 1}})));
   // Reprocessing not supported.
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(
+  components.insert(std::unique_ptr<PartialMetadataInterface>(
       new Property<int32_t>(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, 0)));
   // No way to know pipeline depth for V4L2, so fake with max allowable latency.
   // Doesn't mean much without per-frame controls anyways.
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(
+  components.insert(std::unique_ptr<PartialMetadataInterface>(
       new Property<uint8_t>(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, 4)));
   // "LIMITED devices are strongly encouraged to use a non-negative value.
   // If UNKNOWN is used here then app developers do not have a way to know
   // when sensor settings have been applied." - Unfortunately, V4L2 doesn't
   // really help here either. Could even be that adjusting settings mid-stream
   // blocks in V4L2, and should be avoided.
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(new Property<int32_t>(
-      ANDROID_SYNC_MAX_LATENCY, ANDROID_SYNC_MAX_LATENCY_UNKNOWN)));
+  components.insert(
+      std::unique_ptr<PartialMetadataInterface>(new Property<int32_t>(
+          ANDROID_SYNC_MAX_LATENCY, ANDROID_SYNC_MAX_LATENCY_UNKNOWN)));
 
   // TODO(30510395): subcomponents of cropping/sensors.
   // V4L2 VIDIOC_CROPCAP doesn't give a way to query this;
   // it's driver dependent. For now, assume freeform, and
   // some cameras may just behave badly.
   // TODO(b/29579652): Figure out a way to determine this.
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(new Property<uint8_t>(
-      ANDROID_SCALER_CROPPING_TYPE, ANDROID_SCALER_CROPPING_TYPE_FREEFORM)));
+  components.insert(std::unique_ptr<PartialMetadataInterface>(
+      new Property<uint8_t>(ANDROID_SCALER_CROPPING_TYPE,
+                            ANDROID_SCALER_CROPPING_TYPE_FREEFORM)));
   // No way to get in V4L2, so faked. RPi camera v2 is 3.674 x 2.760 mm.
   // Physical size is used in framework calculations (field of view,
   // pixel pitch, etc.), so faking it may have unexpected results.
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(
+  components.insert(std::unique_ptr<PartialMetadataInterface>(
       new Property<std::array<float, 2>>(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
                                          {{3.674, 2.760}})));
   // HAL uses BOOTTIME timestamps.
   // TODO(b/29457051): make sure timestamps are consistent throughout the HAL.
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(
+  components.insert(std::unique_ptr<PartialMetadataInterface>(
       new Property<uint8_t>(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
                             ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN)));
   // Noo way to actually get orientation from V4L2.
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(
+  components.insert(std::unique_ptr<PartialMetadataInterface>(
       new Property<int32_t>(ANDROID_SENSOR_ORIENTATION, 0)));
 
   // TODO(30510395): subcomponents of face detection.
   // Face detection not supported.
-  AddComponent(NoEffectMenuControl<uint8_t>(
+  components.insert(NoEffectMenuControl<uint8_t>(
       ANDROID_STATISTICS_FACE_DETECT_MODE,
       ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
       {ANDROID_STATISTICS_FACE_DETECT_MODE_OFF}));
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(
+  components.insert(std::unique_ptr<PartialMetadataInterface>(
       new Property<int32_t>(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, 0)));
 
   /* Capabilities. */
   // The V4L2Metadata pretends to at least meet the
   // "LIMITED" and "BACKWARD_COMPATIBLE" functionality requirements.
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(
+  components.insert(std::unique_ptr<PartialMetadataInterface>(
       new Property<uint8_t>(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
                             ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED)));
-  AddComponent(std::unique_ptr<PartialMetadataInterface>(
+  components.insert(std::unique_ptr<PartialMetadataInterface>(
       new Property<std::vector<uint8_t>>(
           ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
           {ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE})));
-}
 
-V4L2Metadata::~V4L2Metadata() {
-  HAL_LOG_ENTER();
+  int res =
+      AddFormatComponents(device, std::inserter(components, components.end()));
+  if (res) {
+    HAL_LOGE("Failed to initialize format components.");
+    return res;
+  }
+
+  *result = std::make_unique<Metadata>(std::move(components));
+  return 0;
 }
 
 }  // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/v4l2_metadata.h b/modules/camera/3_4/v4l2_metadata_factory.h
similarity index 61%
rename from modules/camera/3_4/v4l2_metadata.h
rename to modules/camera/3_4/v4l2_metadata_factory.h
index 29e69b9..f25a370 100644
--- a/modules/camera/3_4/v4l2_metadata.h
+++ b/modules/camera/3_4/v4l2_metadata_factory.h
@@ -14,32 +14,21 @@
  * limitations under the License.
  */
 
-#ifndef V4L2_CAMERA_HAL_V4L2_METADATA_H_
-#define V4L2_CAMERA_HAL_V4L2_METADATA_H_
+#ifndef V4L2_CAMERA_HAL_V4L2_METADATA_FACTORY_H_
+#define V4L2_CAMERA_HAL_V4L2_METADATA_FACTORY_H_
 
-#include <map>
 #include <memory>
 
-#include <hardware/camera3.h>
-
-#include "common.h"
-#include "metadata/control.h"
 #include "metadata/metadata.h"
 #include "v4l2_wrapper.h"
 
 namespace v4l2_camera_hal {
-class V4L2Metadata : public Metadata {
- public:
-  V4L2Metadata(std::shared_ptr<V4L2Wrapper> device);
-  virtual ~V4L2Metadata();
 
- private:
-  // Access to the device.
-  std::shared_ptr<V4L2Wrapper> device_;
-
-  DISALLOW_COPY_AND_ASSIGN(V4L2Metadata);
-};
+// A static function to get a Metadata object populated with V4L2 or other
+// controls as appropriate.
+int GetV4L2Metadata(std::shared_ptr<V4L2Wrapper> device,
+                    std::unique_ptr<Metadata>* result);
 
 }  // namespace v4l2_camera_hal
 
-#endif  // V4L2_CAMERA_HAL_V4L2_METADATA_H_
+#endif  // V4L2_CAMERA_HAL_V4L2_METADATA_FACTORY_H_