blob: 7cf29d7d14c244a757fed43c27f1aa14e83ac966 [file] [log] [blame]
/*
* Copyright 2021 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 "camera/features/feature_profile.h"
#include <iomanip>
#include <string>
#include <utility>
#include "cros-camera/common.h"
namespace cros {
namespace {
base::Optional<FeatureProfile::FeatureType> GetFeatureType(
const std::string& feature_key) {
if (feature_key == "face_detection") {
return FeatureProfile::FeatureType::kFaceDetection;
} else if (feature_key == "gcam_ae") {
return FeatureProfile::FeatureType::kGcamAe;
} else if (feature_key == "hdrnet") {
return FeatureProfile::FeatureType::kHdrnet;
}
return base::nullopt;
}
} // namespace
FeatureProfile::FeatureProfile(base::Optional<base::Value> feature_config,
base::Optional<DeviceConfig> device_config)
: config_file_(base::FilePath(kFeatureProfileFilePath)),
device_config_(device_config ? std::move(device_config).value()
: DeviceConfig::Create()) {
if (feature_config.has_value()) {
OnOptionsUpdated(feature_config.value());
} else {
config_file_.SetCallback(base::BindRepeating(
&FeatureProfile::OnOptionsUpdated, base::Unretained(this)));
}
}
bool FeatureProfile::IsEnabled(FeatureType feature) const {
return feature_settings_.find(feature) != feature_settings_.end();
}
base::FilePath FeatureProfile::GetConfigFilePath(FeatureType feature) const {
auto setting = feature_settings_.find(feature);
if (setting == feature_settings_.end()) {
return base::FilePath();
}
return setting->second.config_file_path;
}
void FeatureProfile::OnOptionsUpdated(const base::Value& json_values) {
// Feature config file schema:
//
// {
// <model>: {
// "feature_set": [
// {"type": <feature_type>, "config_file_path": <config_file_path>},
// ...
// ]
// },
// ...
// }
//
// <model>: String of device model name, e.g. "redrix".
// <feature_type>: String for the type of the feature, e.g. "face_detection"
// or "hdrnet".
// <config_file_path>: String specifying the path to the feature config file.
constexpr char kKeyFeatureSet[] = "feature_set";
constexpr char kKeyType[] = "type";
constexpr char kKeyConfigFilePath[] = "config_file_path";
if (!device_config_.has_value()) {
LOGF(WARNING) << "Device config is invalid, cannot determine model name";
return;
}
if (!json_values.is_dict()) {
LOGF(ERROR) << "Feature config must be a dict";
return;
}
// Get the per-model feature profile from the top-level.
const base::Value* feature_profile =
json_values.FindDictKey(device_config_->GetModelName());
if (feature_profile == nullptr) {
LOGF(ERROR) << "Cannot find feature profile as dict for device model "
<< std::quoted(device_config_->GetModelName());
return;
}
// Extract "feature_set" info from the feature profile.
const base::Value* feature_set = feature_profile->FindListKey(kKeyFeatureSet);
if (feature_set == nullptr) {
LOGF(ERROR) << "Cannot find " << std::quoted(kKeyFeatureSet)
<< " as list in the feature profile of "
<< std::quoted(device_config_->GetModelName());
return;
}
// Construct the complete feature settings.
for (const auto& v : feature_set->GetList()) {
if (!v.is_dict()) {
LOGF(ERROR) << "Feature setting in " << std::quoted(kKeyFeatureSet)
<< " must be a dict";
continue;
}
const std::string* type_str = v.FindStringKey(kKeyType);
if (type_str == nullptr) {
LOGF(ERROR) << "Malformed feature setting: Cannot find key "
<< std::quoted(kKeyType);
continue;
}
base::Optional<FeatureType> type = GetFeatureType(*type_str);
if (!type.has_value()) {
LOGF(ERROR) << "Unknown feature " << std::quoted(*type_str);
continue;
}
const std::string* path_str = v.FindStringKey(kKeyConfigFilePath);
if (type_str == nullptr) {
LOGF(ERROR) << "Malformed feature setting: Cannot find key "
<< std::quoted(kKeyConfigFilePath);
continue;
}
feature_settings_.insert(
{*type, {.config_file_path = base::FilePath(*path_str)}});
}
}
} // namespace cros