blob: bd3441c794062e6cdad3f3c11f1754ce7d8d9d70 [file] [log] [blame]
// Copyright 2016 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 "camera3_test/camera3_module_fixture.h"
#include <algorithm>
#include <string>
#include <base/at_exit.h>
#include <base/bind.h>
#include <base/command_line.h>
#include <base/files/file_path.h>
#include <base/logging.h>
#include <base/macros.h>
#include <base/no_destructor.h>
#include <base/stl_util.h>
#include <base/strings/string_split.h>
#include <base/strings/stringprintf.h>
#include <base/system/sys_info.h>
#include <brillo/message_loops/base_message_loop.h>
#include <chromeos-config/libcros_config/cros_config.h>
#include <system/camera_metadata_hidden.h>
#include "camera3_test/camera3_device.h"
#include "camera3_test/camera3_perf_log.h"
#include "camera3_test/camera3_test_data_forwarder.h"
#include "common/utils/camera_hal_enumerator.h"
#include "cros-camera/camera_mojo_channel_manager.h"
#include "cros-camera/cros_camera_hal.h"
namespace camera3_test {
#define IGNORE_HARDWARE_LEVEL UINT8_MAX
static camera_module_t* g_cam_module = NULL;
static cros::CameraThread& GetModuleThread() {
static base::NoDestructor<cros::CameraThread> t("Camera3TestModuleThread");
return *t;
}
bool isHardwareLevelSupported(uint8_t actual_level, uint8_t required_level) {
constexpr int32_t kSortedLevels[] = {
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3,
};
for (uint8_t level : kSortedLevels) {
if (level == required_level) {
return true;
} else if (level == actual_level) {
return false;
}
}
return false;
}
std::vector<std::tuple<int, int32_t, int32_t, float, bool>>
ParseRecordingParams() {
// This parameter would be generated and passed by the camera_HAL3 autotest.
if (!base::CommandLine::ForCurrentProcess()->HasSwitch("recording_params")) {
LOGF(ERROR) << "Missing recording parameters in the test command";
// Return invalid parameters to fail the test
return {{-1, 0, 0, 0.0, false}};
}
std::vector<std::tuple<int, int32_t, int32_t, float, bool>> params;
std::string params_str =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
"recording_params");
// Expected video recording parameters in the format
// "camera_id:width:height:frame_rate:support_constant_frame_rate".
// For example:
// "0:1280:720:30:1,0:1920:1080:30:1,1:1280:720:30:0" means camcorder profiles
// contains 1280x720 and 1920x1080 for camera 0 and just 1280x720 for camera
// 1. And we should skip the constant frame rate check for camera 1 under
// 1280x720 resolution since it might be unsupported.
const size_t kNumParamsInProfileLegacy = 4;
const size_t kNumParamsInProfile = 5;
enum {
CAMERA_ID_IDX,
WIDTH_IDX,
HEIGHT_IDX,
FRAME_RATE_IDX,
SUPPORT_CONSTANT_FRAME_RATE_IDX
};
for (const auto& it : base::SplitString(
params_str, ",", base::WhitespaceHandling::TRIM_WHITESPACE,
base::SplitResult::SPLIT_WANT_ALL)) {
auto profile =
base::SplitString(it, ":", base::WhitespaceHandling::TRIM_WHITESPACE,
base::SplitResult::SPLIT_WANT_ALL);
// TODO(b/141517606): Remove the legacy branch once we ensure all tests put
// correct numbers of recording parameters.
if (profile.size() == kNumParamsInProfileLegacy) {
params.emplace_back(std::stoi(profile[CAMERA_ID_IDX]),
std::stoi(profile[WIDTH_IDX]),
std::stoi(profile[HEIGHT_IDX]),
std::stof(profile[FRAME_RATE_IDX]), true);
} else if (profile.size() == kNumParamsInProfile) {
params.emplace_back(
std::stoi(profile[CAMERA_ID_IDX]), std::stoi(profile[WIDTH_IDX]),
std::stoi(profile[HEIGHT_IDX]), std::stof(profile[FRAME_RATE_IDX]),
std::stoi(profile[SUPPORT_CONSTANT_FRAME_RATE_IDX]) == 1);
} else {
ADD_FAILURE() << "Failed to parse video recording parameters (" << it
<< ")";
continue;
}
}
std::set<int> param_ids;
for (const auto& param : params) {
param_ids.insert(std::get<CAMERA_ID_IDX>(param));
}
// We are going to enable usb camera hal on all boards, so there will be more
// than one hals on many platforms just like today's nautilus. The
// recording_params is now generated from media_profiles.xml, where the camera
// ids are already translated by SuperHAL. But cros_camera_test is used to
// test only one camera hal directly without going through the hal_adapter,
// therefore we have to remap the ids here.
//
// TODO(shik): This is a temporary workaround for SuperHAL camera ids mapping
// until we have better ground truth config file. Here we exploit the fact
// that there are at most one back and at most one front internal cameras for
// now, and all cameras are sorted by facing in SuperHAL. I feel bad when
// implementing the following hack (sigh).
std::vector<std::tuple<int, int32_t, int32_t, float, bool>> result;
Camera3Module module;
if (module.GetCameraIds().size() < param_ids.size()) {
// SuperHAL case
for (const auto& cam_id : module.GetTestCameraIds()) {
camera_info info;
EXPECT_EQ(0, Camera3Module().GetCameraInfo(cam_id, &info));
bool found_matching_param = false;
for (auto param : params) {
if (std::get<CAMERA_ID_IDX>(param) == info.facing) {
found_matching_param = true;
std::get<CAMERA_ID_IDX>(param) = cam_id;
result.emplace_back(param);
}
}
EXPECT_TRUE(found_matching_param);
}
} else {
// Single HAL case
for (const auto& cam_id : module.GetTestCameraIds()) {
if (std::find_if(
params.begin(), params.end(),
[&](const std::tuple<int, int32_t, int32_t, float, bool>& item) {
return std::get<CAMERA_ID_IDX>(item) == cam_id;
}) == params.end()) {
ADD_FAILURE() << "Missing video recording parameters for camera "
<< cam_id;
}
}
result = std::move(params);
}
LOGF(INFO) << "The parameters will be used for recording test:";
for (const auto& param : result) {
LOGF(INFO) << base::StringPrintf(
"camera id = %d, size = %dx%d, fps = %g, support_constant_frame_rate = "
"%d",
std::get<CAMERA_ID_IDX>(param), std::get<WIDTH_IDX>(param),
std::get<HEIGHT_IDX>(param), std::get<FRAME_RATE_IDX>(param),
std::get<SUPPORT_CONSTANT_FRAME_RATE_IDX>(param));
}
return result;
}
// static
void CameraModuleCallbacksHandler::camera_device_status_change(
const camera_module_callbacks_t* callbacks, int camera_id, int new_status) {
auto* aux = static_cast<const CameraModuleCallbacksAux*>(callbacks);
aux->handler->CameraDeviceStatusChange(
camera_id, static_cast<camera_device_status_t>(new_status));
}
// static
void CameraModuleCallbacksHandler::torch_mode_status_change(
const camera_module_callbacks_t* callbacks,
const char* camera_id,
int new_status) {
auto* aux = static_cast<const CameraModuleCallbacksAux*>(callbacks);
aux->handler->TorchModeStatusChange(
atoi(camera_id), static_cast<torch_mode_status_t>(new_status));
}
// static
CameraModuleCallbacksHandler* CameraModuleCallbacksHandler::GetInstance() {
static auto* instance = new CameraModuleCallbacksHandler();
return instance;
}
bool CameraModuleCallbacksHandler::IsExternalCameraPresent(int camera_id) {
base::AutoLock l(lock_);
auto it = device_status_.find(camera_id);
return it != device_status_.end() &&
it->second == CAMERA_DEVICE_STATUS_PRESENT;
}
// TODO(shik): Run tests on external cameras as well if detected. We need to
// relax the requirements for them just like what CTS did.
void CameraModuleCallbacksHandler::CameraDeviceStatusChange(
int camera_id, camera_device_status_t new_status) {
base::AutoLock l(lock_);
LOGF(INFO) << "camera_id = " << camera_id << ", new status = " << new_status;
device_status_[camera_id] = new_status;
}
void CameraModuleCallbacksHandler::TorchModeStatusChange(
int camera_id, torch_mode_status_t new_status) {
LOGF(INFO) << "camera_id = " << camera_id << ", new status = " << new_status;
}
int32_t ResolutionInfo::Width() const {
return width_;
}
int32_t ResolutionInfo::Height() const {
return height_;
}
int32_t ResolutionInfo::Area() const {
return width_ * height_;
}
bool ResolutionInfo::operator==(const ResolutionInfo& resolution) const {
return (width_ == resolution.Width()) && (height_ == resolution.Height());
}
bool ResolutionInfo::operator<(const ResolutionInfo& resolution) const {
// Compare by area it covers, if the areas are same, then compare the widths.
return (Area() < resolution.Area()) ||
(Area() == resolution.Area() && width_ < resolution.Width());
}
std::ostream& operator<<(std::ostream& out, const ResolutionInfo& info) {
out << info.width_ << 'x' << info.height_;
return out;
}
static std::vector<int> GetCmdLineTestCameraIds() {
auto id_str =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII("camera_ids");
std::vector<int> ids;
if (!id_str.empty()) {
auto id_strs = base::SplitString(id_str, ",",
base::WhitespaceHandling::TRIM_WHITESPACE,
base::SplitResult::SPLIT_WANT_ALL);
for (const auto& id : id_strs) {
ids.push_back(stoi(id));
}
}
return ids;
}
// static
CameraModuleCallbacksAux* CameraModuleCallbacksAux::GetInstance() {
static base::NoDestructor<CameraModuleCallbacksAux> aux;
return aux.get();
}
CameraModuleCallbacksAux::CameraModuleCallbacksAux() {
camera_device_status_change =
&CameraModuleCallbacksHandler::camera_device_status_change;
torch_mode_status_change =
&CameraModuleCallbacksHandler::torch_mode_status_change;
handler = CameraModuleCallbacksHandler::GetInstance();
}
static void InitCameraModuleOnThread(camera_module_t* cam_module) {
if (cam_module->get_vendor_tag_ops) {
static vendor_tag_ops ops = {};
cam_module->get_vendor_tag_ops(&ops);
ASSERT_EQ(0, set_camera_metadata_vendor_ops(&ops))
<< "Failed to set camera metadata vendor ops";
}
if (cam_module->init) {
ASSERT_EQ(0, cam_module->init());
}
int num_builtin_cameras = cam_module->get_number_of_cameras();
VLOGF(1) << "num_builtin_cameras = " << num_builtin_cameras;
ASSERT_EQ(0,
cam_module->set_callbacks(CameraModuleCallbacksAux::GetInstance()));
}
// On successfully Initialized, |cam_module_| will pointed to valid
// camera_module_t.
static void InitCameraModule(const base::FilePath& camera_hal_path,
cros::CameraMojoChannelManager* mojo_manager,
void** cam_hal_handle,
camera_module_t** cam_module,
cros::cros_camera_hal_t** cros_camera_hal) {
*cam_hal_handle = dlopen(camera_hal_path.value().c_str(), RTLD_NOW);
ASSERT_NE(nullptr, *cam_hal_handle) << "Failed to dlopen: " << dlerror();
*cros_camera_hal = static_cast<cros::cros_camera_hal_t*>(
dlsym(*cam_hal_handle, CROS_CAMERA_HAL_INFO_SYM_AS_STR));
// TODO(b/151270948): We should report error here if it fails to find the
// symbol once all camera HALs have implemented the interface.
if (*cros_camera_hal != nullptr) {
(*cros_camera_hal)->set_up(mojo_manager);
}
camera_module_t* module = static_cast<camera_module_t*>(
dlsym(*cam_hal_handle, HAL_MODULE_INFO_SYM_AS_STR));
ASSERT_NE(nullptr, module) << "Camera module is invalid";
ASSERT_NE(nullptr, module->get_number_of_cameras)
<< "get_number_of_cameras is not implemented";
ASSERT_NE(nullptr, module->get_camera_info)
<< "get_camera_info is not implemented";
ASSERT_NE(nullptr, module->common.methods->open) << "open() is unimplemented";
for (int id : GetCmdLineTestCameraIds()) {
ASSERT_GT(module->get_number_of_cameras(), id)
<< "No such test camera id in HAL";
}
ASSERT_EQ(0, GetModuleThread().PostTaskSync(
FROM_HERE, base::Bind(&InitCameraModuleOnThread, module)));
*cam_module = module;
}
static void InitCameraModuleByHalPath(
const base::FilePath& camera_hal_path,
cros::CameraMojoChannelManager* mojo_manager,
void** cam_hal_handle,
cros::cros_camera_hal_t** cros_camera_hal) {
InitCameraModule(camera_hal_path, mojo_manager, cam_hal_handle, &g_cam_module,
cros_camera_hal);
}
static void InitCameraModuleByFacing(
int facing,
cros::CameraMojoChannelManager* mojo_manager,
void** cam_hal_handle,
cros::cros_camera_hal_t** cros_camera_hal,
base::FilePath* camera_hal_path) {
// Do cleanup when exit from ASSERT_XX
struct CleanupModule {
void operator()(void** cam_hal_handle) {
if (*cam_hal_handle) {
set_camera_metadata_vendor_ops(nullptr);
ASSERT_EQ(0, dlclose(*cam_hal_handle))
<< "Failed to close camera hal when probing facing";
g_cam_module = NULL;
*cam_hal_handle = NULL;
}
}
};
for (const auto& hal_path : cros::GetCameraHalPaths()) {
InitCameraModule(hal_path, mojo_manager, cam_hal_handle, &g_cam_module,
cros_camera_hal);
std::unique_ptr<void*, CleanupModule> cleanup_ptr(cam_hal_handle);
if (g_cam_module != NULL) {
Camera3Module camera_module;
for (int i = 0; i < camera_module.GetNumberOfCameras(); i++) {
camera_info info;
ASSERT_EQ(0, camera_module.GetCameraInfo(i, &info));
if (info.facing == facing) {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
"camera_ids", std::to_string(i));
*camera_hal_path = hal_path;
cleanup_ptr.release();
return;
}
}
}
}
FAIL() << "Cannot find camera with facing=" << facing;
}
static void InitPerfLog() {
// GetNumberOfCameras() returns the number of internal cameras, so here we
// should not see any external cameras (facing = 2).
const std::string facing_names[] = {"back", "front"};
camera3_test::Camera3Module camera_module;
int num_cameras = camera_module.GetNumberOfCameras();
std::map<int, std::string> name_map;
for (int i = 0; i < num_cameras; i++) {
camera_info info;
ASSERT_EQ(0, camera_module.GetCameraInfo(i, &info));
ASSERT_LE(0, info.facing);
ASSERT_LT(info.facing, base::size(facing_names));
name_map[i] = facing_names[info.facing];
}
camera3_test::Camera3PerfLog::GetInstance()->SetCameraNameMap(name_map);
}
struct NumberOfBuiltInCameras {
int mipi;
int usb;
};
static base::Optional<NumberOfBuiltInCameras> GetNumberOfBuiltInCameras() {
NumberOfBuiltInCameras num_built_in_cams = {0};
brillo::CrosConfig cros_config;
if (!cros_config.Init()) {
ADD_FAILURE() << "Failed to initialize CrOS config";
return base::nullopt;
}
std::string count_str;
if (cros_config.GetString("/camera", "count", &count_str)) {
if (count_str == "0") {
return num_built_in_cams;
}
}
std::string interface;
for (int i = 0;; ++i) {
if (!cros_config.GetString(base::StringPrintf("/camera/devices/%i", i),
"interface", &interface)) {
if (i == 0) {
return base::nullopt;
}
break;
}
if (interface == "mipi") {
++num_built_in_cams.mipi;
} else {
++num_built_in_cams.usb;
}
}
return num_built_in_cams;
}
static camera_module_t* GetCameraModule() {
return g_cam_module;
}
// Camera module
Camera3Module::Camera3Module() : test_camera_ids_(GetCmdLineTestCameraIds()) {
if (g_cam_module != nullptr) {
cam_module_connector_ = std::make_unique<HalModuleConnector>(
GetCameraModule(), &GetModuleThread());
} else {
cam_module_connector_ =
std::make_unique<ClientModuleConnector>(CameraHalClient::GetInstance());
}
}
int Camera3Module::GetNumberOfCameras() {
return cam_module_connector_->GetNumberOfCameras();
}
std::vector<int> Camera3Module::GetCameraIds() {
int num_cams = GetNumberOfCameras();
if (num_cams <= 0) {
return std::vector<int>();
}
std::vector<int> ids(num_cams);
for (int i = 0; i < num_cams; i++) {
ids[i] = i;
}
return ids;
}
std::vector<int> Camera3Module::GetTestCameraIds() {
return test_camera_ids_.empty() ? GetCameraIds() : test_camera_ids_;
}
void Camera3Module::GetStreamConfigEntry(int cam_id,
int32_t key,
camera_metadata_ro_entry_t* entry) {
entry->count = 0;
camera_info info;
ASSERT_EQ(0, GetCameraInfo(cam_id, &info))
<< "Can't get info for camera " << cam_id;
camera_metadata_ro_entry_t local_entry = {};
ASSERT_EQ(
0, find_camera_metadata_ro_entry(
const_cast<camera_metadata_t*>(info.static_camera_characteristics),
key, &local_entry))
<< "Fail to find metadata key " << get_camera_metadata_tag_name(key);
ASSERT_NE(0u, local_entry.count) << "Camera stream configuration is empty";
ASSERT_EQ(0u, local_entry.count % kNumOfElementsInStreamConfigEntry)
<< "Camera stream configuration parsing error";
*entry = local_entry;
}
bool Camera3Module::IsFormatAvailable(int cam_id, int format) {
camera_metadata_ro_entry_t available_config = {};
GetStreamConfigEntry(cam_id, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
&available_config);
for (uint32_t i = 0; i < available_config.count;
i += kNumOfElementsInStreamConfigEntry) {
if (available_config.data.i32[i + STREAM_CONFIG_FORMAT_INDEX] == format) {
return true;
}
}
return false;
}
int Camera3Module::GetCameraInfo(int cam_id, camera_info* info) {
return cam_module_connector_->GetCameraInfo(cam_id, info);
}
std::unique_ptr<DeviceConnector> Camera3Module::OpenDevice(int cam_id) {
return cam_module_connector_->OpenDevice(cam_id);
}
bool Camera3Module::GetVendorTagByName(const std::string name, uint32_t* tag) {
return cam_module_connector_->GetVendorTagByName(name, tag);
}
std::vector<int32_t> Camera3Module::GetOutputFormats(int cam_id) {
camera_metadata_ro_entry_t available_config = {};
GetStreamConfigEntry(cam_id, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
&available_config);
std::set<int32_t> available_formats;
for (uint32_t i = 0; i < available_config.count;
i += kNumOfElementsInStreamConfigEntry) {
if (available_config.data.i32[i + STREAM_CONFIG_DIRECTION_INDEX] ==
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {
available_formats.insert(
available_config.data.i32[i + STREAM_CONFIG_FORMAT_INDEX]);
}
}
return std::vector<int32_t>(available_formats.begin(),
available_formats.end());
}
std::vector<ResolutionInfo> Camera3Module::GetSortedOutputResolutions(
int cam_id, int32_t format) {
camera_metadata_ro_entry_t available_config = {};
GetStreamConfigEntry(cam_id, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
&available_config);
std::vector<ResolutionInfo> available_resolutions;
for (uint32_t i = 0; i < available_config.count;
i += kNumOfElementsInStreamConfigEntry) {
int32_t fmt = available_config.data.i32[i + STREAM_CONFIG_FORMAT_INDEX];
int32_t width = available_config.data.i32[i + STREAM_CONFIG_WIDTH_INDEX];
int32_t height = available_config.data.i32[i + STREAM_CONFIG_HEIGHT_INDEX];
int32_t in_or_out =
available_config.data.i32[i + STREAM_CONFIG_DIRECTION_INDEX];
if ((fmt == format) &&
(in_or_out == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT)) {
available_resolutions.emplace_back(width, height);
}
}
std::sort(available_resolutions.begin(), available_resolutions.end());
return available_resolutions;
}
int64_t Camera3Module::GetOutputKeyParameterI64(
int cam_id,
int32_t format,
const ResolutionInfo& resolution,
int32_t key,
int32_t index) {
camera_metadata_ro_entry_t available_config = {};
GetStreamConfigEntry(cam_id, key, &available_config);
for (uint32_t i = 0; i < available_config.count;
i += kNumOfElementsInStreamConfigEntry) {
int64_t fmt = available_config.data.i64[i + STREAM_CONFIG_FORMAT_INDEX];
int64_t width = available_config.data.i64[i + STREAM_CONFIG_WIDTH_INDEX];
int64_t height = available_config.data.i64[i + STREAM_CONFIG_HEIGHT_INDEX];
if (fmt == format && width == resolution.Width() &&
height == resolution.Height()) {
return available_config.data.i64[i + index];
}
}
return -ENODATA;
}
int64_t Camera3Module::GetOutputStallDuration(
int cam_id, int32_t format, const ResolutionInfo& resolution) {
int64_t value = GetOutputKeyParameterI64(
cam_id, format, resolution, ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
STREAM_CONFIG_STALL_DURATION_INDEX);
return (value != -ENODATA)
? value
: 0; // Default duration is '0' (unsupported/no extra stall)
}
int64_t Camera3Module::GetOutputMinFrameDuration(
int cam_id, int32_t format, const ResolutionInfo& resolution) {
return GetOutputKeyParameterI64(cam_id, format, resolution,
ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
STREAM_CONFIG_MIN_DURATION_INDEX);
}
// Test cases
TEST_F(Camera3ModuleFixture, NumberOfCameras) {
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
base::FilePath camera_hal_path =
cmd_line->GetSwitchValuePath("camera_hal_path");
auto num_built_in_cams = GetNumberOfBuiltInCameras();
if (num_built_in_cams.has_value()) {
if (camera_hal_path.value().find("usb") != std::string::npos) {
ASSERT_EQ(cam_module_.GetNumberOfCameras(), num_built_in_cams->usb)
<< "Incorrect number of cameras";
} else {
ASSERT_EQ(cam_module_.GetNumberOfCameras(), num_built_in_cams->mipi)
<< "Incorrect number of cameras";
}
} else {
ASSERT_GT(cam_module_.GetNumberOfCameras(), 0) << "No cameras found";
ASSERT_LE(cam_module_.GetNumberOfCameras(), kMaxNumCameras)
<< "Too many cameras found";
}
}
TEST_F(Camera3ModuleFixture, OpenDeviceOfBadIndices) {
auto* callbacks_handler = CameraModuleCallbacksHandler::GetInstance();
std::vector<int> bad_ids = {-1};
for (int id = cam_module_.GetNumberOfCameras(); bad_ids.size() < 3; id++) {
if (callbacks_handler->IsExternalCameraPresent(id)) {
LOG(INFO) << "Camera " << id << " is an external camera, skip it";
continue;
}
bad_ids.push_back(id);
}
// Possible TOCTOU race here if the external camera is plugged after
// |IsExternalCameraPresent()|, but before |OpenDevice()|.
for (int id : bad_ids) {
Camera3Device cam_dev(id);
ASSERT_NE(0, cam_dev.Initialize(&cam_module_))
<< "Open camera device of bad id " << id;
}
}
TEST_F(Camera3ModuleFixture, IsActiveArraySizeSubsetOfPixelArraySize) {
for (int cam_id = 0; cam_id < cam_module_.GetNumberOfCameras(); cam_id++) {
camera_info info;
ASSERT_EQ(0, cam_module_.GetCameraInfo(cam_id, &info))
<< "Can't get camera info for " << cam_id;
camera_metadata_ro_entry_t entry;
ASSERT_EQ(
0,
find_camera_metadata_ro_entry(
const_cast<camera_metadata_t*>(info.static_camera_characteristics),
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, &entry))
<< "Can't find the sensor pixel array size.";
int pixel_array_w = entry.data.i32[0];
int pixel_array_h = entry.data.i32[1];
ASSERT_EQ(
0,
find_camera_metadata_ro_entry(
const_cast<camera_metadata_t*>(info.static_camera_characteristics),
ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, &entry))
<< "Can't find the sensor active array size.";
int active_array_w = entry.data.i32[0];
int active_array_h = entry.data.i32[1];
ASSERT_LE(active_array_h, pixel_array_h);
ASSERT_LE(active_array_w, pixel_array_w);
}
}
TEST_F(Camera3ModuleFixture, OpenDevice) {
for (int cam_id = 0; cam_id < cam_module_.GetNumberOfCameras(); cam_id++) {
Camera3Device cam_dev(cam_id);
ASSERT_EQ(0, cam_dev.Initialize(&cam_module_))
<< "Camera open device failed";
cam_dev.Destroy();
}
}
TEST_F(Camera3ModuleFixture, DeviceVersion) {
camera_info info;
for (int cam_id = 0; cam_id < cam_module_.GetNumberOfCameras(); cam_id++) {
ASSERT_EQ(0, cam_module_.GetCameraInfo(cam_id, &info))
<< "Can't get camera info for " << cam_id;
EXPECT_GE(info.device_version, (uint16_t)HARDWARE_MODULE_API_VERSION(3, 3))
<< "Device " << cam_id << " fails to support at least HALv3.3";
}
}
TEST_F(Camera3ModuleFixture, OpenDeviceTwice) {
for (int cam_id = 0; cam_id < cam_module_.GetNumberOfCameras(); cam_id++) {
Camera3Device cam_dev(cam_id);
ASSERT_EQ(0, cam_dev.Initialize(&cam_module_))
<< "Camera open device failed";
// Open the device again
Camera3Device cam_bad_dev(cam_id);
ASSERT_NE(0, cam_bad_dev.Initialize(&cam_module_))
<< "Opening camera device twice should have failed";
}
}
TEST_F(Camera3ModuleFixture, RequiredFormats) {
auto IsResolutionSupported =
[](const std::vector<ResolutionInfo>& resolution_list,
const ResolutionInfo& resolution) {
return std::find(resolution_list.begin(), resolution_list.end(),
resolution) != resolution_list.end();
};
auto RemoveResolution = [](std::vector<ResolutionInfo>& resolution_list,
const ResolutionInfo& resolution) {
auto it =
std::find(resolution_list.begin(), resolution_list.end(), resolution);
if (it != resolution_list.end()) {
resolution_list.erase(it);
}
};
auto GetMaxVideoResolution = [](int cam_id) {
auto recording_params = ParseRecordingParams();
int32_t width = 0;
int32_t height = 0;
for (const auto& it : recording_params) {
int32_t area = std::get<1>(it) * std::get<2>(it);
if (std::get<0>(it) == cam_id &&
(width * height < area ||
(width * height == area && width < std::get<1>(it)))) {
width = std::get<1>(it);
height = std::get<2>(it);
}
}
return ResolutionInfo(width, height);
};
for (int cam_id = 0; cam_id < cam_module_.GetNumberOfCameras(); cam_id++) {
ASSERT_TRUE(cam_module_.IsFormatAvailable(cam_id, HAL_PIXEL_FORMAT_BLOB))
<< "Camera stream configuration does not support JPEG";
ASSERT_TRUE(
cam_module_.IsFormatAvailable(cam_id, HAL_PIXEL_FORMAT_YCbCr_420_888))
<< "Camera stream configuration does not support flexible YUV";
// Reference:
// camera2/cts/ExtendedCameraCharacteristicsTest.java#testAvailableStreamConfigs
camera_info info;
ASSERT_EQ(0, cam_module_.GetCameraInfo(cam_id, &info))
<< "Can't get camera info for " << cam_id;
std::vector<ResolutionInfo> jpeg_resolutions =
cam_module_.GetSortedOutputResolutions(cam_id, HAL_PIXEL_FORMAT_BLOB);
std::vector<ResolutionInfo> yuv_resolutions =
cam_module_.GetSortedOutputResolutions(cam_id,
HAL_PIXEL_FORMAT_YCbCr_420_888);
std::vector<ResolutionInfo> private_resolutions =
cam_module_.GetSortedOutputResolutions(
cam_id, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
const ResolutionInfo full_hd(1920, 1080), full_hd_alt(1920, 1088),
hd(1280, 720), vga(640, 480), qvga(320, 240);
camera_metadata_ro_entry_t entry;
ASSERT_EQ(
0,
find_camera_metadata_ro_entry(
const_cast<camera_metadata_t*>(info.static_camera_characteristics),
ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, &entry))
<< "Can't find the sensor active array size.";
ResolutionInfo active_array(entry.data.i32[0], entry.data.i32[1]);
if ((active_array.Width() >= full_hd.Width()) &&
(active_array.Height() >= full_hd.Height())) {
EXPECT_TRUE(IsResolutionSupported(jpeg_resolutions, full_hd) ||
IsResolutionSupported(jpeg_resolutions, full_hd_alt))
<< "Required FULLHD size not found for JPEG for camera " << cam_id;
}
if ((active_array.Width() >= hd.Width()) &&
(active_array.Height() >= hd.Height())) {
EXPECT_TRUE(IsResolutionSupported(jpeg_resolutions, hd))
<< "Required HD size not found for JPEG for camera " << cam_id;
}
if ((active_array.Width() >= vga.Width()) &&
(active_array.Height() >= vga.Height())) {
EXPECT_TRUE(IsResolutionSupported(jpeg_resolutions, vga))
<< "Required VGA size not found for JPEG for camera " << cam_id;
}
if ((active_array.Width() >= qvga.Width()) &&
(active_array.Height() >= qvga.Height())) {
EXPECT_TRUE(IsResolutionSupported(jpeg_resolutions, qvga))
<< "Required QVGA size not found for JPEG for camera " << cam_id;
}
ASSERT_EQ(
0,
find_camera_metadata_ro_entry(
const_cast<camera_metadata_t*>(info.static_camera_characteristics),
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &entry))
<< "Cannot find the metadata ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL";
int32_t hw_level = entry.data.i32[0];
// Handle FullHD special case first
if (IsResolutionSupported(jpeg_resolutions, full_hd)) {
if (hw_level == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL) {
EXPECT_TRUE(IsResolutionSupported(yuv_resolutions, full_hd) ||
IsResolutionSupported(yuv_resolutions, full_hd_alt))
<< "FullHD YUV size not found in Full device ";
EXPECT_TRUE(IsResolutionSupported(private_resolutions, full_hd) ||
IsResolutionSupported(private_resolutions, full_hd_alt))
<< "FullHD private size not found in Full device ";
}
// Remove all FullHD or FullHD_Alt sizes for the remaining of the test
RemoveResolution(jpeg_resolutions, full_hd);
RemoveResolution(jpeg_resolutions, full_hd_alt);
}
// Check all sizes other than FullHD
if (hw_level == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED) {
// Remove all jpeg sizes larger than max video size
auto max_video_resolution = GetMaxVideoResolution(cam_id);
for (auto it = jpeg_resolutions.begin(); it != jpeg_resolutions.end();) {
if (it->Width() >= max_video_resolution.Width() &&
it->Height() >= max_video_resolution.Height()) {
it = jpeg_resolutions.erase(it);
} else {
it++;
}
}
}
std::stringstream ss;
auto PrintResolutions =
[&](const std::vector<ResolutionInfo>& resolutions) {
ss.str("");
for (const auto& it : resolutions) {
ss << (ss.str().empty() ? "" : ", ") << it.Width() << "x"
<< it.Height();
}
return ss.str();
};
if (hw_level == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
hw_level == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED) {
std::vector<ResolutionInfo> diff;
std::set_difference(jpeg_resolutions.begin(), jpeg_resolutions.end(),
yuv_resolutions.begin(), yuv_resolutions.end(),
std::inserter(diff, diff.begin()));
EXPECT_TRUE(diff.empty())
<< "Sizes " << PrintResolutions(diff) << " not found in YUV format";
}
std::vector<ResolutionInfo> diff;
std::set_difference(jpeg_resolutions.begin(), jpeg_resolutions.end(),
private_resolutions.begin(), private_resolutions.end(),
std::inserter(diff, diff.begin()));
EXPECT_TRUE(diff.empty())
<< "Sizes " << PrintResolutions(diff) << " not found in private format";
}
}
// TODO(hywu): test keys used by RAW, burst and reprocessing capabilities when
// full mode is supported
static bool AreAllCapabilitiesSupported(
camera_metadata_t* characteristics,
const std::vector<uint8_t>& capabilities) {
std::set<uint8_t> supported_capabilities;
camera_metadata_ro_entry_t entry;
if (find_camera_metadata_ro_entry(characteristics,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
&entry) == 0) {
for (size_t i = 0; i < entry.count; i++) {
if ((entry.data.u8[i] >=
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) &&
(entry.data.u8[i] <=
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO)) { // NOLINT(whitespace/line_length)
supported_capabilities.insert(entry.data.u8[i]);
}
}
}
for (const auto& it : capabilities) {
if (supported_capabilities.find(it) == supported_capabilities.end()) {
return false;
}
}
return true;
}
static void ExpectKeyAvailable(camera_metadata_t* characteristics,
int32_t key,
uint8_t hw_level,
const std::vector<uint8_t>& capabilities) {
camera_metadata_ro_entry_t entry;
ASSERT_EQ(0,
find_camera_metadata_ro_entry(
characteristics, ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &entry))
<< "Cannot find the metadata ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL";
uint8_t actual_hw_level = entry.data.u8[0];
// For LIMITED-level targeted keys, rely on capability check, not level
if (isHardwareLevelSupported(actual_hw_level, hw_level) &&
hw_level != ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED) {
ASSERT_EQ(0, find_camera_metadata_ro_entry(characteristics, key, &entry))
<< "Key " << get_camera_metadata_tag_name(key)
<< " must be in characteristics for this hardware level ";
} else if (AreAllCapabilitiesSupported(characteristics, capabilities)) {
if (!(hw_level == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED &&
!isHardwareLevelSupported(actual_hw_level, hw_level))) {
// Don't enforce LIMITED-starting keys on LEGACY level, even if cap is
// defined
std::stringstream ss;
auto PrintCapabilities = [&]() {
for (const auto& it : capabilities) {
ss << (ss.str().empty() ? "" : ", ");
switch (it) {
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE:
ss << "BACKWARD_COMPATIBLE";
break;
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR:
ss << "MANUAL_SENSOR";
break;
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING:
ss << "MANUAL_POST_PROCESSING";
break;
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW:
ss << "RAW";
break;
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING:
ss << "PRIVATE_PROCESSING";
break;
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS:
ss << "READ_SENSOR_SETTINGS";
break;
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE:
ss << "BURST_CAPTURE";
break;
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING:
ss << "YUV_REPROCESSING";
break;
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT:
ss << "DEPTH_OUTPUT";
break;
case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO: // NOLINT(whitespace/line_length)
ss << "HIGHT_SPEED_VIDEO";
break;
default:
ss << "unknown(" << it << ")";
}
}
return ss.str();
};
ASSERT_EQ(0, find_camera_metadata_ro_entry(characteristics, key, &entry))
<< "Key " << get_camera_metadata_tag_name(key)
<< " must be in characteristics for capabilities "
<< PrintCapabilities();
}
} else {
if (actual_hw_level == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY &&
hw_level != IGNORE_HARDWARE_LEVEL) {
auto result = find_camera_metadata_ro_entry(characteristics, key, &entry);
if (result == 0)
LOGF(WARNING)
<< "Key " << get_camera_metadata_tag_name(key)
<< " is not required for LEGACY devices but still appears";
}
// OK: Key may or may not be present.
}
}
static void ExpectKeyAvailable(camera_metadata_t* c,
int32_t key,
uint8_t hw_level,
uint8_t capability) {
return ExpectKeyAvailable(c, key, hw_level, std::vector<uint8_t>{capability});
}
TEST_F(Camera3ModuleFixture, StaticKeysTest) {
// Reference:
// camera2/cts/ExtendedCameraCharacteristicsTest.java#testKeys
#define IGNORE_CAPABILITY -1
for (int cam_id = 0; cam_id < cam_module_.GetNumberOfCameras(); cam_id++) {
camera_info info;
ASSERT_EQ(0, cam_module_.GetCameraInfo(cam_id, &info))
<< "Can't get camera info for " << cam_id;
auto c = const_cast<camera_metadata_t*>(info.static_camera_characteristics);
// The BACKWARD_COMPATIBLE capability must always be defined for HALv3:
// https://source.android.com/devices/camera/versioning#camera_api2
EXPECT_TRUE(AreAllCapabilitiesSupported(
c, {ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE}));
ExpectKeyAvailable(
c, ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AVAILABLE_MODES, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AE_AVAILABLE_MODES, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AE_COMPENSATION_RANGE, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AE_COMPENSATION_STEP, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AE_LOCK_AVAILABLE, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AF_AVAILABLE_MODES, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AVAILABLE_EFFECTS, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AVAILABLE_SCENE_MODES, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AWB_AVAILABLE_MODES, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_CONTROL_AWB_LOCK_AVAILABLE, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
// TODO(hywu): ANDROID_CONTROL_MAX_REGIONS_AE,
// ANDROID_CONTROL_MAX_REGIONS_AF,
// ANDROID_CONTROL_MAX_REGIONS_AWB
ExpectKeyAvailable(c, ANDROID_EDGE_AVAILABLE_EDGE_MODES,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
IGNORE_CAPABILITY);
ExpectKeyAvailable(
c, ANDROID_FLASH_INFO_AVAILABLE, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(c, ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(
c, ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_LENS_FACING, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(c, ANDROID_LENS_INFO_AVAILABLE_APERTURES,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
ExpectKeyAvailable(c, ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
ExpectKeyAvailable(
c, ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(c, ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
ExpectKeyAvailable(
c, ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, IGNORE_HARDWARE_LEVEL,
std::vector<uint8_t>{
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING});
ExpectKeyAvailable(
c, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_REQUEST_PIPELINE_MAX_DEPTH, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_SCALER_CROPPING_TYPE, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(c, ANDROID_SENSOR_BLACK_LEVEL_PATTERN,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
std::vector<uint8_t>{
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW});
ExpectKeyAvailable(c, ANDROID_SENSOR_CALIBRATION_TRANSFORM1,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(c, ANDROID_SENSOR_COLOR_TRANSFORM1,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(c, ANDROID_SENSOR_FORWARD_MATRIX1, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(
c, ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, IGNORE_HARDWARE_LEVEL,
std::vector<uint8_t>{
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW});
ExpectKeyAvailable(c, ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(c, ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
ExpectKeyAvailable(c, ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
ExpectKeyAvailable(
c, ANDROID_SENSOR_INFO_PHYSICAL_SIZE, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(c, ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
ExpectKeyAvailable(c, ANDROID_SENSOR_INFO_WHITE_LEVEL,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(
c, ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(c, ANDROID_SENSOR_MAX_ANALOG_SENSITIVITY,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
ExpectKeyAvailable(
c, ANDROID_SENSOR_ORIENTATION, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(c, ANDROID_SENSOR_REFERENCE_ILLUMINANT1,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(
c, ANDROID_SHADING_AVAILABLE_MODES,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
std::vector<uint8_t>{
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW});
ExpectKeyAvailable(
c, ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(c, ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(c,
ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(
c, ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_SYNC_MAX_LATENCY, IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
ExpectKeyAvailable(
c, ANDROID_TONEMAP_AVAILABLE_TONE_MAP_MODES,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING);
ExpectKeyAvailable(
c, ANDROID_TONEMAP_MAX_CURVE_POINTS,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING);
camera_metadata_ro_entry_t entry;
if (find_camera_metadata_ro_entry(c, ANDROID_SENSOR_REFERENCE_ILLUMINANT2,
&entry) == 0) {
ExpectKeyAvailable(c, ANDROID_SENSOR_REFERENCE_ILLUMINANT2,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(c, ANDROID_SENSOR_COLOR_TRANSFORM2,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(c, ANDROID_SENSOR_CALIBRATION_TRANSFORM2,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
ExpectKeyAvailable(c, ANDROID_SENSOR_FORWARD_MATRIX2,
IGNORE_HARDWARE_LEVEL,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
}
}
}
TEST_F(Camera3ModuleFixture, StreamConfigurationMapTest) {
// Reference:
// camera2/cts/ExtendedCameraCharacteristicsTest.java#testStreamConfigurationMap
const int64_t kToleranceFactor = 2;
for (int cam_id = 0; cam_id < cam_module_.GetNumberOfCameras(); cam_id++) {
camera_info info;
ASSERT_EQ(0, cam_module_.GetCameraInfo(cam_id, &info))
<< "Can't get camera info for " << cam_id;
std::vector<int32_t> available_formats =
cam_module_.GetOutputFormats(cam_id);
for (const auto& format : available_formats) {
std::vector<ResolutionInfo> available_resolutions =
cam_module_.GetSortedOutputResolutions(cam_id, format);
size_t resolution_count = available_resolutions.size();
for (size_t i = 0; i < resolution_count; i++) {
int64_t stall_duration = cam_module_.GetOutputStallDuration(
cam_id, format, available_resolutions[i]);
if (stall_duration >= 0) {
if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
EXPECT_EQ(0, stall_duration)
<< "YUV_420_888 may not have a non-zero stall duration";
} else if (format == HAL_PIXEL_FORMAT_BLOB) {
// Stall duration should be in a reasonable range: larger size
// should normally have larger stall duration
if (i > 0) {
int64_t prev_duration = cam_module_.GetOutputStallDuration(
cam_id, format, available_resolutions[i - 1]);
EXPECT_LE(prev_duration / kToleranceFactor, stall_duration)
<< "Stall duration (format " << format << " and size "
<< available_resolutions[i].Width() << "x"
<< available_resolutions[i].Height()
<< ") is not in the right range";
}
}
} else {
ADD_FAILURE() << "Negative stall duration for format " << format;
}
int64_t min_duration = cam_module_.GetOutputMinFrameDuration(
cam_id, format, available_resolutions[i]);
if (AreAllCapabilitiesSupported(
const_cast<camera_metadata_t*>(
info.static_camera_characteristics),
std::vector<uint8_t>{
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR})) {
EXPECT_LT(0, min_duration)
<< "MANUAL_SENSOR capability, need positive min frame duration "
"for format "
<< format << " and size " << available_resolutions[i].Width()
<< "x" << available_resolutions[i].Height();
} else {
EXPECT_LE(0, min_duration)
<< "Need non-negative min frame duration for format " << format
<< " and size " << available_resolutions[i].Width() << "x"
<< available_resolutions[i].Height();
}
}
}
}
}
TEST_F(Camera3ModuleFixture, ChromeOSRequiredResolution) {
const int required_formats[] = {HAL_PIXEL_FORMAT_BLOB,
HAL_PIXEL_FORMAT_YCbCr_420_888,
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED};
const ResolutionInfo required_resolutions[] = {ResolutionInfo(1600, 1200),
ResolutionInfo(1280, 960)};
for (const auto& cam_id : cam_module_.GetCameraIds()) {
camera_info info;
ASSERT_EQ(0, cam_module_.GetCameraInfo(cam_id, &info))
<< "Can't get camera info for " << cam_id;
camera_metadata_ro_entry_t entry;
ASSERT_EQ(
0,
find_camera_metadata_ro_entry(
const_cast<camera_metadata_t*>(info.static_camera_characteristics),
ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, &entry))
<< "Can't find the sensor active array size.";
ASSERT_GE(entry.count, 2);
ResolutionInfo active_array(entry.data.i32[0], entry.data.i32[1]);
for (const auto& resolution : required_resolutions) {
if ((active_array.Width() >= resolution.Width()) &&
(active_array.Height() >= resolution.Height())) {
for (const auto& format : required_formats) {
auto resolutions =
cam_module_.GetSortedOutputResolutions(cam_id, format);
EXPECT_NE(resolutions.end(), std::find(resolutions.begin(),
resolutions.end(), resolution))
<< "Required size " << resolution.Width() << "x"
<< resolution.Height() << " not found for format " << format
<< " for camera " << cam_id;
}
}
}
}
}
} // namespace camera3_test
static void AddGtestFilterNegativePattern(std::string negative) {
using ::testing::GTEST_FLAG(filter);
GTEST_FLAG(filter)
.append((GTEST_FLAG(filter).find('-') == std::string::npos) ? "-" : ":")
.append(negative);
}
// Return -ENOENT for no facing specified, -EINVAL for invalid facing name.
static int GetCmdLineTestCameraFacing(const base::CommandLine& cmd_line) {
const std::string facing_names[] = {"back", "front"};
const auto& facing_name = cmd_line.GetSwitchValueASCII("camera_facing");
if (facing_name.empty())
return -ENOENT;
int idx = std::distance(
facing_names,
std::find(facing_names, facing_names + base::size(facing_names),
facing_name));
if (idx == base::size(facing_names)) {
ADD_FAILURE() << "Invalid facing name: " << facing_name;
return -EINVAL;
}
return idx;
}
bool InitializeTest(int* argc,
char*** argv,
cros::CameraMojoChannelManager* mojo_manager,
void** cam_hal_handle,
cros::cros_camera_hal_t** cros_camera_hal) {
// Set up logging so we can enable VLOGs with -v / --vmodule.
base::CommandLine::Init(*argc, *argv);
logging::LoggingSettings settings;
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
LOG_ASSERT(logging::InitLogging(settings));
if (geteuid() == 0) {
LOGF(WARNING)
<< "Running tests as root might leak some root owned resources, which "
"cannot be accessed by the user arc-camera.";
}
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
base::FilePath camera_hal_path =
cmd_line->GetSwitchValuePath("camera_hal_path");
int facing = GetCmdLineTestCameraFacing(*cmd_line);
if (facing != -ENOENT) {
if (facing == -EINVAL) {
LOG(ERROR) << "Invalid camera facing name.";
return false;
} else if (!camera_hal_path.empty() ||
!camera3_test::GetCmdLineTestCameraIds().empty()) {
LOGF(ERROR) << "Cannot specify both --camera_hal_path/--camera_ids and "
"--camera_facing.";
return false;
}
} else if (camera_hal_path.empty()) {
std::vector<base::FilePath> camera_hal_paths = cros::GetCameraHalPaths();
LOGF(INFO) << "camera_hal_path unspecified. Connecting to the camera "
"service via Mojo. To test against the HAL directly, add "
"`--camera_hal_path=` into command line argument.";
LOGF(INFO) << "List of possible paths:";
for (const auto& path : camera_hal_paths) {
LOGF(ERROR) << path.value();
}
}
// Open camera HAL and get module
if (facing != -ENOENT) {
camera3_test::GetModuleThread().Start();
camera3_test::InitCameraModuleByFacing(facing, mojo_manager, cam_hal_handle,
cros_camera_hal, &camera_hal_path);
} else if (!camera_hal_path.empty()) {
camera3_test::GetModuleThread().Start();
camera3_test::InitCameraModuleByHalPath(camera_hal_path, mojo_manager,
cam_hal_handle, cros_camera_hal);
} else {
if (camera3_test::CameraHalClient::GetInstance()->Start(
camera3_test::CameraModuleCallbacksAux::GetInstance()) != 0) {
return false;
}
}
camera3_test::InitPerfLog();
// Initialize gtest
::testing::InitGoogleTest(argc, *argv);
if (testing::Test::HasFailure()) {
return false;
}
if (camera_hal_path.value().find("usb") != std::string::npos) {
// Skip 3A algorithm sandbox IPC tests for USB HAL
AddGtestFilterNegativePattern("*Camera3AlgoSandboxIPCErrorTest*");
}
const std::vector<std::string> kIgnoreSensorOrientationTestBoards = {
"nocturne",
"scarlet",
};
std::string board = base::SysInfo::GetLsbReleaseBoard();
if (base::Contains(kIgnoreSensorOrientationTestBoards, board)) {
VLOG(1) << "Ignore SensorOrientationTest on " << board;
AddGtestFilterNegativePattern("*SensorOrientationTest/*");
}
return true;
}
#ifdef FUZZER
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
void* cam_hal_handle = NULL;
std::unique_ptr<cros::CameraMojoChannelManager> mojo_manager =
cros::CameraMojoChannelManager::CreateInstance();
cros::cros_camera_hal_t* cros_camera_hal;
if (!InitializeTest(argc, argv, mojo_manager.get(), &cam_hal_handle,
&cros_camera_hal)) {
exit(EXIT_FAILURE);
}
::testing::TestEventListeners& listeners =
::testing::UnitTest::GetInstance()->listeners();
delete listeners.Release(listeners.default_result_printer());
return 0;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
camera3_test::Camera3TestDataForwarder::GetInstance()->SetData(Data, Size);
ignore_result(RUN_ALL_TESTS());
return 0;
}
#else
int main(int argc, char** argv) {
// We have to make it leaky until the lifetime conflict in b/119926433 is
// resolved.
base::NoDestructor<base::AtExitManager> leaky_at_exit_manager;
int result = EXIT_FAILURE;
void* cam_hal_handle = NULL;
brillo::BaseMessageLoop message_loop;
message_loop.SetAsCurrent();
cros::cros_camera_hal_t* cros_camera_hal = nullptr;
std::unique_ptr<cros::CameraMojoChannelManager> mojo_manager =
cros::CameraMojoChannelManager::CreateInstance();
if (InitializeTest(&argc, &argv, mojo_manager.get(), &cam_hal_handle,
&cros_camera_hal)) {
result = RUN_ALL_TESTS();
}
camera3_test::GetModuleThread().Stop();
// TODO(b/151270948): We should report error here if it fails to find the
// symbol once all camera HALs have implemented the interface.
if (cros_camera_hal != nullptr) {
cros_camera_hal->tear_down();
}
mojo_manager.reset();
// Close Camera HAL
if (cam_hal_handle && dlclose(cam_hal_handle) != 0) {
PLOGF(ERROR) << "Failed to dlclose(cam_hal_handle)";
result = EXIT_FAILURE;
}
return result;
}
#endif