camera: usb: read sensor data

Rolling shutter skew and exposure time are from sensor.
We read sensor registers via third-party SDK if the
camera module supports the feature.

BUG=b:123889668
TEST=use flashlight and see the correct values are reported

Change-Id: I407d1003744ede8aa4ee9097b5b6acceec9e6ad7
Reviewed-on: https://chromium-review.googlesource.com/1583570
Tested-by: Heng-ruey Hsu <henryhsu@google.com>
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Heng-ruey Hsu <henryhsu@google.com>
diff --git a/camera/hal/usb/camera_characteristics.cc b/camera/hal/usb/camera_characteristics.cc
index 011e94a..e5b26cc 100644
--- a/camera/hal/usb/camera_characteristics.cc
+++ b/camera/hal/usb/camera_characteristics.cc
@@ -67,6 +67,8 @@
   } else if (key == "constant_framerate_unsupported") {
     std::istringstream(value) >> std::boolalpha >>
         info->constant_framerate_unsupported;
+  } else if (key == "monocle_quirks") {
+    std::istringstream(value) >> std::boolalpha >> info->monocle_quirks;
   } else if (key == "lens_facing") {
     info->lens_facing = stoi(value);
   } else if (key == "sensor_orientation") {
diff --git a/camera/hal/usb/camera_client.cc b/camera/hal/usb/camera_client.cc
index 1e94428..0885eeb 100644
--- a/camera/hal/usb/camera_client.cc
+++ b/camera/hal/usb/camera_client.cc
@@ -40,7 +40,6 @@
       device_info_(device_info),
       device_(new V4L2CameraDevice(device_info)),
       callback_ops_(nullptr),
-      metadata_handler_(new MetadataHandler(static_info)),
       request_thread_("Capture request thread") {
   memset(&camera3_device_, 0, sizeof(camera3_device_));
   camera3_device_.common.tag = HARDWARE_DEVICE_TAG;
@@ -56,6 +55,9 @@
   SupportedFormats supported_formats =
       device_->GetDeviceSupportedFormats(device_info_.device_path);
   qualified_formats_ = GetQualifiedFormats(supported_formats);
+
+  metadata_handler_ = std::make_unique<MetadataHandler>(
+      static_info, device_info, qualified_formats_);
 }
 
 CameraClient::~CameraClient() {}
@@ -681,8 +683,9 @@
   }
 
   NotifyShutter(capture_result.frame_number);
-  ret = metadata_handler_->PostHandleRequest(
-      capture_result.frame_number, CurrentBufferTimestamp(), metadata);
+  ret = metadata_handler_->PostHandleRequest(capture_result.frame_number,
+                                             CurrentBufferTimestamp(), metadata,
+                                             stream_on_resolution_);
   if (ret) {
     LOGFID(WARNING, device_id_)
         << "Update metadata in PostHandleRequest failed";
diff --git a/camera/hal/usb/common_types.h b/camera/hal/usb/common_types.h
index 1292cf3..1aa684a 100644
--- a/camera/hal/usb/common_types.h
+++ b/camera/hal/usb/common_types.h
@@ -58,6 +58,9 @@
   int32_t sensor_info_pixel_array_size_height;
   float sensor_info_physical_size_width;
   float sensor_info_physical_size_height;
+
+  // Special setting for specified camera modules.
+  bool monocle_quirks = false;
 };
 
 typedef std::vector<DeviceInfo> DeviceInfos;
diff --git a/camera/hal/usb/libcamera_hal.gyp b/camera/hal/usb/libcamera_hal.gyp
index 0b8793e..87231ae 100644
--- a/camera/hal/usb/libcamera_hal.gyp
+++ b/camera/hal/usb/libcamera_hal.gyp
@@ -17,6 +17,16 @@
         'libyuv',
         're2',
       ],
+      'conditions': [
+        ['USE_usb_camera_monocle == 1', {
+          'deps': [
+            'librealtek-sdk',
+          ],
+          'defines': [
+            'MONOCLE_QUIRKS=1',
+          ],
+        }],
+      ],
     },
   },
   'targets': [
@@ -39,11 +49,19 @@
         'frame_buffer.cc',
         'image_processor.cc',
         'metadata_handler.cc',
+        'sensor_handler.cc',
         'stream_format.cc',
         'test_pattern.cc',
         'v4l2_camera_device.cc',
         'vendor_tag.cc',
       ],
+      'conditions': [
+        ['USE_usb_camera_monocle == 1', {
+          'sources': [
+            'sensor_handler_monocle.cc',
+          ],
+        }],
+      ],
     },
   ],
   'conditions': [
diff --git a/camera/hal/usb/metadata_handler.cc b/camera/hal/usb/metadata_handler.cc
index b53735f..2a649d7 100644
--- a/camera/hal/usb/metadata_handler.cc
+++ b/camera/hal/usb/metadata_handler.cc
@@ -26,8 +26,10 @@
 
 namespace cros {
 
-MetadataHandler::MetadataHandler(const camera_metadata_t& metadata)
-    : af_trigger_(false) {
+MetadataHandler::MetadataHandler(const camera_metadata_t& metadata,
+                                 const DeviceInfo& device_info,
+                                 const SupportedFormats& supported_formats)
+    : device_info_(device_info), af_trigger_(false) {
   // MetadataBase::operator= will make a copy of camera_metadata_t.
   metadata_ = &metadata;
 
@@ -36,6 +38,8 @@
     template_settings_[i] = CreateDefaultRequestSettings(i);
   }
 
+  sensor_handler_ = SensorHandler::Create(device_info, supported_formats);
+
   thread_checker_.DetachFromThread();
 }
 
@@ -655,7 +659,8 @@
 
 int MetadataHandler::PostHandleRequest(int frame_number,
                                        int64_t timestamp,
-                                       android::CameraMetadata* metadata) {
+                                       android::CameraMetadata* metadata,
+                                       const Size& resolution) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (current_frame_number_ != frame_number) {
     LOGF(ERROR)
@@ -720,11 +725,11 @@
 
   // Rolling shutter skew and exposure time values are fake due to ARCore
   // test requirement.
-  // TODO(henryhsu): Read the two values from camera.
-  const int64_t rolling_shutter_skew = 33'300'000;  // 33.3ms
+  const int64_t rolling_shutter_skew =
+      sensor_handler_->GetRollingShutterSkew(resolution);
   UPDATE(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW, &rolling_shutter_skew, 1);
 
-  const int64_t exposure_time = 16'600'000;  // 16.6ms
+  const int64_t exposure_time = sensor_handler_->GetExposureTime(resolution);
   UPDATE(ANDROID_SENSOR_EXPOSURE_TIME, &exposure_time, 1);
 
   // android.statistics
diff --git a/camera/hal/usb/metadata_handler.h b/camera/hal/usb/metadata_handler.h
index 8714052..7f34b73 100644
--- a/camera/hal/usb/metadata_handler.h
+++ b/camera/hal/usb/metadata_handler.h
@@ -13,6 +13,7 @@
 #include <hardware/camera3.h>
 
 #include "hal/usb/common_types.h"
+#include "hal/usb/sensor_handler.h"
 
 namespace cros {
 
@@ -29,7 +30,9 @@
 // CameraDevice.
 class MetadataHandler {
  public:
-  explicit MetadataHandler(const camera_metadata_t& metadata);
+  MetadataHandler(const camera_metadata_t& metadata,
+                  const DeviceInfo& device_info,
+                  const SupportedFormats& supported_formats);
   ~MetadataHandler();
 
   static int FillDefaultMetadata(android::CameraMetadata* metadata);
@@ -57,7 +60,8 @@
   // required metadata which can be gotton from 3A or image processor.
   int PostHandleRequest(int frame_number,
                         int64_t timestamp,
-                        android::CameraMetadata* metadata);
+                        android::CameraMetadata* metadata,
+                        const Size& resolution);
 
  private:
   // Check |template_type| is valid or not.
@@ -83,9 +87,15 @@
   // thread.
   base::ThreadChecker thread_checker_;
 
+  // Camera device information.
+  const DeviceInfo device_info_;
+
   int current_frame_number_;
 
   bool af_trigger_;
+
+  // Sensor handler to get sensor related metadata.
+  std::unique_ptr<SensorHandler> sensor_handler_;
 };
 
 }  // namespace cros
diff --git a/camera/hal/usb/sensor_handler.cc b/camera/hal/usb/sensor_handler.cc
new file mode 100644
index 0000000..4961174
--- /dev/null
+++ b/camera/hal/usb/sensor_handler.cc
@@ -0,0 +1,33 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "hal/usb/sensor_handler.h"
+
+#include "cros-camera/common.h"
+#if defined(MONOCLE_QUIRKS)
+#include "hal/usb/sensor_handler_monocle.h"
+#endif
+
+namespace cros {
+
+// static
+std::unique_ptr<SensorHandler> SensorHandler::Create(
+    const DeviceInfo& device_info, const SupportedFormats& supported_formats) {
+#if defined(MONOCLE_QUIRKS)
+  return std::make_unique<SensorHandlerMonocle>(device_info, supported_formats);
+#else
+  return std::make_unique<SensorHandlerDefault>();
+#endif
+}
+
+int64_t SensorHandlerDefault::GetRollingShutterSkew(const Size& resolution) {
+  return 33'300'000;
+}
+
+int64_t SensorHandlerDefault::GetExposureTime(const Size& resolution) {
+  return 16'600'000;
+}
+
+}  // namespace cros
diff --git a/camera/hal/usb/sensor_handler.h b/camera/hal/usb/sensor_handler.h
new file mode 100644
index 0000000..070e5f3
--- /dev/null
+++ b/camera/hal/usb/sensor_handler.h
@@ -0,0 +1,39 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef CAMERA_HAL_USB_SENSOR_HANDLER_H_
+#define CAMERA_HAL_USB_SENSOR_HANDLER_H_
+
+#include <memory>
+
+#include "hal/usb/common_types.h"
+
+namespace cros {
+
+class SensorHandler {
+ public:
+  static std::unique_ptr<SensorHandler> Create(
+      const DeviceInfo& device_info, const SupportedFormats& supported_formats);
+  virtual ~SensorHandler() {}
+
+  // Get rolling shutter skew value. The return value unit is nano seconds.
+  virtual int64_t GetRollingShutterSkew(const Size& resolution) = 0;
+
+  // Get exposure time. The return value unit is nano seconds.
+  virtual int64_t GetExposureTime(const Size& resolution) = 0;
+};
+
+class SensorHandlerDefault : public SensorHandler {
+ public:
+  SensorHandlerDefault() {}
+  ~SensorHandlerDefault() override = default;
+
+  int64_t GetRollingShutterSkew(const Size& resolution) override;
+  int64_t GetExposureTime(const Size& resolution) override;
+};
+
+}  // namespace cros
+
+#endif  // CAMERA_HAL_USB_SENSOR_HANDLER_H_
diff --git a/camera/hal/usb/sensor_handler_monocle.cc b/camera/hal/usb/sensor_handler_monocle.cc
new file mode 100644
index 0000000..848d46d
--- /dev/null
+++ b/camera/hal/usb/sensor_handler_monocle.cc
@@ -0,0 +1,99 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "hal/usb/sensor_handler_monocle.h"
+
+#include <string>
+
+#include <base/files/file_util.h>
+#include <rts_read_sensor.h>
+
+#include "cros-camera/common.h"
+
+namespace cros {
+
+SensorHandlerMonocle::SensorHandlerMonocle(
+    const DeviceInfo& device_info, const SupportedFormats& supported_formats)
+    : handle_(nullptr) {
+  if (!device_info.monocle_quirks) {
+    return;
+  }
+
+  base::FilePath target;
+  std::string device_path;
+  // SDK supposes the device path should be /dev/videoX.
+  if (base::ReadSymbolicLink(base::FilePath(device_info.device_path),
+                             &target)) {
+    device_path = "/dev/" + target.BaseName().value();
+  } else {
+    device_path = device_info.device_path;
+  }
+  handle_ = rts_uvc_open(device_path.c_str());
+  if (handle_ == nullptr) {
+    LOGF(ERROR) << "Cannot open device to read sensor data: " << device_path;
+  }
+
+  InitSensorParameters(device_info, supported_formats);
+}
+
+SensorHandlerMonocle::~SensorHandlerMonocle() {
+  if (handle_)
+    rts_uvc_close(handle_);
+}
+
+void SensorHandlerMonocle::InitSensorParameters(
+    const DeviceInfo& device_info, const SupportedFormats& supported_formats) {
+  // TODO(henryhsu): Move to a config file.
+  if (device_info.usb_vid == "0bda" && device_info.usb_pid == "5647") {
+    // These parameters are from OV8856 specification.
+    // Initial exposure time parameters
+    SensorParameters param;
+    for (const auto& supported_format : supported_formats) {
+      if (supported_format.width == 3264 && supported_format.height == 2448) {
+        param.line_pixel_width = 3864;
+        param.line_count = 2452;
+      } else if (supported_format.width == 1920 &&
+                 supported_format.height == 1080) {
+        param.line_pixel_width = 3200;
+        param.line_count = 1840;
+      } else {
+        param.line_pixel_width = 3864;
+        param.line_count = 1224;
+      }
+
+      param.readout_time = param.line_pixel_width * param.line_count *
+                           1'000'000'000 / kPixelClock_;
+      param.line_duration =
+          param.line_pixel_width * 1'000'000'000 / kPixelClock_;
+
+      Size resolution(supported_format.width, supported_format.height);
+      sensor_parameters_[resolution] = param;
+    }
+  }
+}
+
+int64_t SensorHandlerMonocle::GetRollingShutterSkew(const Size& resolution) {
+  if (sensor_parameters_.find(resolution) == sensor_parameters_.end()) {
+    return 33'300'000;
+  }
+  return sensor_parameters_[resolution].readout_time;
+}
+
+int64_t SensorHandlerMonocle::GetExposureTime(const Size& resolution) {
+  if (handle_ == nullptr ||
+      sensor_parameters_.find(resolution) == sensor_parameters_.end()) {
+    return 16'600'000;
+  }
+  uint64_t line_count = 0;
+  for (const auto& addr : kExposureTimeRegisters_) {
+    uint16_t value;
+    rts_read_sensor_reg(handle_, addr, &value);
+    line_count = (line_count << 8) | value;
+  }
+  line_count >>= kExposureTimeFractionBits_;
+  return sensor_parameters_[resolution].line_duration * line_count;
+}
+
+}  // namespace cros
diff --git a/camera/hal/usb/sensor_handler_monocle.h b/camera/hal/usb/sensor_handler_monocle.h
new file mode 100644
index 0000000..827316c4
--- /dev/null
+++ b/camera/hal/usb/sensor_handler_monocle.h
@@ -0,0 +1,64 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef CAMERA_HAL_USB_SENSOR_HANDLER_MONOCLE_H_
+#define CAMERA_HAL_USB_SENSOR_HANDLER_MONOCLE_H_
+
+#include <map>
+#include <vector>
+
+#include "hal/usb/common_types.h"
+#include "hal/usb/sensor_handler.h"
+
+namespace cros {
+
+class SensorHandlerMonocle : public SensorHandler {
+ public:
+  // We need some information from sensor to calculate rolling shutter skew
+  // metadata. The metadata is different for each resolution.
+  struct SensorParameters {
+    // The number of pixels horizontally.
+    int64_t line_pixel_width;
+    // The line number vertically.
+    int64_t line_count;
+
+    // Cache calculated rolling shutter skew.
+    int64_t readout_time;
+    // Cache calculated line duration for exposure time.
+    int64_t line_duration;
+  };
+
+  SensorHandlerMonocle(const DeviceInfo& device_info,
+                       const SupportedFormats& supported_formats);
+  ~SensorHandlerMonocle() override;
+
+  int64_t GetRollingShutterSkew(const Size& resolution) override;
+  int64_t GetExposureTime(const Size& resolution) override;
+
+ private:
+  // Initial sensor parameters for all resolutions by device info.
+  void InitSensorParameters(const DeviceInfo& device_info,
+                            const SupportedFormats& supported_formats);
+
+  // Clock rate used in camera sensor. The unit is HZ.
+  static constexpr int64_t kPixelClock_ = 144'000'000;
+
+  // The sensor registers to export exposure time.
+  static constexpr uint32_t kExposureTimeRegisters_[] = {0x3500, 0x3501,
+                                                         0x3502};
+
+  // Exposure time parameters.
+  static constexpr uint32_t kExposureTimeFractionBits_ = 4;
+
+  // Sensor parameters for each resolution.
+  std::map<Size, SensorParameters> sensor_parameters_;
+
+  // file handle for third_party SDK to read sensor data.
+  void* handle_;
+};
+
+}  // namespace cros
+
+#endif  // CAMERA_HAL_USB_SENSOR_HANDLER_MONOCLE_H_
diff --git a/common-mk/common.gypi b/common-mk/common.gypi
index 96fcc10..1a64175 100644
--- a/common-mk/common.gypi
+++ b/common-mk/common.gypi
@@ -67,6 +67,7 @@
     'USE_tpm2_simulator%': 0,
     'USE_ubsan%': 0,
     'USE_udev%': 0,
+    'USE_usb_camera_monocle%': 0,
     'USE_vpn%': 0,
     'USE_wake_on_wifi%': 0,
     'USE_wifi%': 0,
diff --git a/common-mk/platform2.py b/common-mk/platform2.py
index 4e542e1..489c485 100755
--- a/common-mk/platform2.py
+++ b/common-mk/platform2.py
@@ -76,6 +76,7 @@
     'tpm2_simulator',
     'ubsan',
     'udev',
+    'usb_camera_monocle',
     'vpn',
     'wake_on_wifi',
     'wifi',