/*
* Copyright (C) 2017 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 "CameraConfiguration.h"
#define LOG_TAG "CameraConfiguration"
#include <android-base/file.h>
#include <android-base/strings.h>
#include <cutils/log.h>
#include <json/json.h>
#include <json/reader.h>
#include <stdlib.h>
namespace cvd {
namespace {
////////////////////// Device Personality keys //////////////////////
//
// **** Camera ****
//
// Example segment (transcribed to constants):
//
// kCameraDefinitionsKey: [
// {
// kCameraDefinitionOrientationKey: "front",
// kCameraDefinitionHalVersionKey: "1",
// kCameraDefinitionResolutionsKey: [
// {
// kCameraDefinitionResolutionWidthKey: "1600",
// kCameraDefinitionResolutionHeightKey: "1200",
// },
// {
// kCameraDefinitionResolutionWidthKey: "1280",
// kCameraDefinitionResolutionHeightKey: "800",
// }
// ]
// },
// {
// kCameraDefinitionOrientationKey: "back",
// kCameraDefinitionHalVersionKey: "1",
// kCameraDefinitionResolutionsKey: [
// {
// kCameraDefinitionResolutionWidthKey: "1024",
// kCameraDefinitionResolutionHeightKey: "768",
// },
// {
// kCameraDefinitionResolutionWidthKey: "800",
// kCameraDefinitionResolutionHeightKey: "600",
// }
// ]
// }
// ]
//
// Location of the camera configuration files.
const char* const kConfigurationFileLocation = "/vendor/etc/config/camera.json";
//
// Array of camera definitions for all cameras available on the device (array).
// Top Level Key.
const char* const kCameraDefinitionsKey = "camera_definitions";
// Camera orientation of currently defined camera (string).
// Currently supported values:
// - "back",
// - "front".
const char* const kCameraDefinitionOrientationKey = "orientation";
// Camera HAL version of currently defined camera (int).
// Currently supported values:
// - 1 (Camera HALv1)
// - 2 (Camera HALv2)
// - 3 (Camera HALv3)
const char* const kCameraDefinitionHalVersionKey = "hal_version";
// Array of resolutions supported by camera (array).
const char* const kCameraDefinitionResolutionsKey = "resolutions";
// Width of currently defined resolution (int).
// Must be divisible by 8.
const char* const kCameraDefinitionResolutionWidthKey = "width";
// Height of currently defined resolution (int).
// Must be divisible by 8.
const char* const kCameraDefinitionResolutionHeightKey = "height";
// Convert string value to camera orientation.
bool ValueToCameraOrientation(const std::string& value,
CameraDefinition::Orientation* orientation) {
if (value == "back") {
*orientation = CameraDefinition::kBack;
return true;
} else if (value == "front") {
*orientation = CameraDefinition::kFront;
return true;
}
ALOGE("%s: Invalid camera orientation: %s.", __FUNCTION__, value.c_str());
return false;
}
// Convert string value to camera HAL version.
bool ValueToCameraHalVersion(const std::string& value,
CameraDefinition::HalVersion* hal_version) {
int temp;
char* endptr;
temp = strtol(value.c_str(), &endptr, 10);
if (endptr != value.c_str() + value.size()) {
ALOGE("%s: Invalid camera HAL version. Expected number, got %s.",
__FUNCTION__, value.c_str());
return false;
}
switch (temp) {
case 1:
*hal_version = CameraDefinition::kHalV1;
break;
case 2:
*hal_version = CameraDefinition::kHalV2;
break;
case 3:
*hal_version = CameraDefinition::kHalV3;
break;
default:
ALOGE("%s: Invalid camera HAL version. Version %d not supported.",
__FUNCTION__, temp);
return false;
}
return true;
}
bool ValueToCameraResolution(const std::string& width,
const std::string& height,
CameraDefinition::Resolution* resolution) {
char* endptr;
resolution->width = strtol(width.c_str(), &endptr, 10);
if (endptr != width.c_str() + width.size()) {
ALOGE("%s: Invalid camera resolution width. Expected number, got %s.",
__FUNCTION__, width.c_str());
return false;
}
resolution->height = strtol(height.c_str(), &endptr, 10);
if (endptr != height.c_str() + height.size()) {
ALOGE("%s: Invalid camera resolution height. Expected number, got %s.",
__FUNCTION__, height.c_str());
return false;
}
// Validate width and height parameters are sane.
if (resolution->width <= 0 || resolution->height <= 0) {
ALOGE("%s: Invalid camera resolution: %dx%d", __FUNCTION__,
resolution->width, resolution->height);
return false;
}
// Validate width and height divisible by 8.
if ((resolution->width & 7) != 0 || (resolution->height & 7) != 0) {
ALOGE(
"%s: Invalid camera resolution: width and height must be "
"divisible by 8, got %dx%d (%dx%d).",
__FUNCTION__, resolution->width, resolution->height,
resolution->width & 7, resolution->height & 7);
return false;
}
return true;
}
// Process camera definitions.
// Returns true, if definitions were sane.
bool ConfigureCameras(const Json::Value& value,
std::vector<CameraDefinition>* cameras) {
if (!value.isObject()) {
ALOGE("%s: Configuration root is not an object", __FUNCTION__);
return false;
}
if (!value.isMember(kCameraDefinitionsKey)) return true;
for (Json::ValueConstIterator iter = value[kCameraDefinitionsKey].begin();
iter != value[kCameraDefinitionsKey].end(); ++iter) {
cameras->push_back(CameraDefinition());
CameraDefinition& camera = cameras->back();
if (!iter->isObject()) {
ALOGE("%s: Camera definition is not an object", __FUNCTION__);
continue;
}
// Camera without orientation -> invalid setting.
if (!iter->isMember(kCameraDefinitionOrientationKey)) {
ALOGE("%s: Invalid camera definition: key %s is missing.", __FUNCTION__,
kCameraDefinitionOrientationKey);
return false;
}
if (!ValueToCameraOrientation(
(*iter)[kCameraDefinitionOrientationKey].asString(),
&camera.orientation))
return false;
// Camera without HAL version -> invalid setting.
if (!(*iter).isMember(kCameraDefinitionHalVersionKey)) {
ALOGE("%s: Invalid camera definition: key %s is missing.", __FUNCTION__,
kCameraDefinitionHalVersionKey);
return false;
}
if (!ValueToCameraHalVersion(
(*iter)[kCameraDefinitionHalVersionKey].asString(),
&camera.hal_version))
return false;
// Camera without resolutions -> invalid setting.
if (!iter->isMember(kCameraDefinitionResolutionsKey)) {
ALOGE("%s: Invalid camera definition: key %s is missing.", __FUNCTION__,
kCameraDefinitionResolutionsKey);
return false;
}
const Json::Value& json_resolutions =
(*iter)[kCameraDefinitionResolutionsKey];
// Resolutions not an array, or an empty array -> invalid setting.
if (!json_resolutions.isArray() || json_resolutions.empty()) {
ALOGE("%s: Invalid camera definition: %s is not an array or is empty.",
__FUNCTION__, kCameraDefinitionResolutionsKey);
return false;
}
// Process all resolutions.
for (Json::ValueConstIterator json_res_iter = json_resolutions.begin();
json_res_iter != json_resolutions.end(); ++json_res_iter) {
// Check presence of width and height keys.
if (!json_res_iter->isObject()) {
ALOGE("%s: Camera resolution item is not an object", __FUNCTION__);
continue;
}
if (!json_res_iter->isMember(kCameraDefinitionResolutionWidthKey) ||
!json_res_iter->isMember(kCameraDefinitionResolutionHeightKey)) {
ALOGE(
"%s: Invalid camera resolution: keys %s and %s are both required.",
__FUNCTION__, kCameraDefinitionResolutionWidthKey,
kCameraDefinitionResolutionHeightKey);
return false;
}
camera.resolutions.push_back(CameraDefinition::Resolution());
CameraDefinition::Resolution& resolution = camera.resolutions.back();
if (!ValueToCameraResolution(
(*json_res_iter)[kCameraDefinitionResolutionWidthKey].asString(),
(*json_res_iter)[kCameraDefinitionResolutionHeightKey].asString(),
&resolution))
return false;
}
}
return true;
}
} // namespace
bool CameraConfiguration::Init() {
cameras_.clear();
std::string config;
if (!android::base::ReadFileToString(kConfigurationFileLocation, &config)) {
ALOGE("%s: Could not open configuration file: %s", __FUNCTION__,
kConfigurationFileLocation);
return false;
}
Json::Reader config_reader;
Json::Value root;
if (!config_reader.parse(config, root)) {
ALOGE("Could not parse configuration file: %s",
config_reader.getFormattedErrorMessages().c_str());
return false;
}
return ConfigureCameras(root, &cameras_);
}
} // namespace cvd