summaryrefslogtreecommitdiff
path: root/src/qcam/assets/feathericons/battery.svg
blob: 7fe87710b8bd1cd6b560900f146cf1676393e368 (plain)
1
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-battery"><rect x="1" y="6" width="18" height="12" rx="2" ry="2"></rect><line x1="23" y1="13" x2="23" y2="11"></line></svg>
a> 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * camera_sensor.cpp - A camera sensor
 */

#include "camera_sensor.h"

#include <algorithm>
#include <float.h>
#include <iomanip>
#include <limits.h>
#include <math.h>

#include <libcamera/property_ids.h>

#include "formats.h"
#include "utils.h"
#include "v4l2_subdevice.h"

/**
 * \file camera_sensor.h
 * \brief A camera sensor
 */

namespace libcamera {

LOG_DEFINE_CATEGORY(CameraSensor);

/**
 * \class CameraSensor
 * \brief A camera sensor based on V4L2 subdevices
 *
 * The CameraSensor class eases handling of sensors for pipeline handlers by
 * hiding the details of the V4L2 subdevice kernel API and caching sensor
 * information.
 *
 * The implementation is currently limited to sensors that expose a single V4L2
 * subdevice with a single pad, and support the same frame sizes for all
 * supported media bus codes. It will be extended to support more complex
 * devices as the needs arise.
 */

/**
 * \brief Construct a CameraSensor
 * \param[in] entity The media entity backing the camera sensor
 *
 * Once constructed the instance must be initialized with init().
 */
CameraSensor::CameraSensor(const MediaEntity *entity)
	: entity_(entity), properties_(properties::properties)
{
	subdev_ = new V4L2Subdevice(entity);
}

/**
 * \brief Destroy a CameraSensor
 */
CameraSensor::~CameraSensor()
{
	delete subdev_;
}

/**
 * \brief Initialize the camera sensor instance
 *
 * This method performs the initialisation steps of the CameraSensor that may
 * fail. It shall be called once and only once after constructing the instance.
 *
 * \return 0 on success or a negative error code otherwise
 */
int CameraSensor::init()
{
	int ret;

	if (entity_->pads().size() != 1) {
		LOG(CameraSensor, Error)
			<< "Sensors with more than one pad are not supported";
		return -EINVAL;
	}

	if (entity_->function() != MEDIA_ENT_F_CAM_SENSOR) {
		LOG(CameraSensor, Error)
			<< "Invalid sensor function "
			<< utils::hex(entity_->function());
		return -EINVAL;
	}

	ret = subdev_->open();
	if (ret < 0)
		return ret;

	/* Retrieve and store the camera sensor properties. */
	const ControlInfoMap &controls = subdev_->controls();
	int32_t propertyValue;

	/* Camera Location: default is front location. */
	const auto &locationControl = controls.find(V4L2_CID_CAMERA_SENSOR_LOCATION);
	if (locationControl != controls.end()) {
		int32_t v4l2Location =
			locationControl->second.def().get<int32_t>();

		switch (v4l2Location) {
		default:
			LOG(CameraSensor, Warning)
				<< "Unsupported camera location "
				<< v4l2Location << ", setting to Front";
			/* Fall-through */
		case V4L2_LOCATION_FRONT:
			propertyValue = properties::CameraLocationFront;
			break;
		case V4L2_LOCATION_BACK:
			propertyValue = properties::CameraLocationBack;
			break;
		case V4L2_LOCATION_EXTERNAL:
			propertyValue = properties::CameraLocationExternal;
			break;
		}
	} else {
		propertyValue = properties::CameraLocationFront;
	}
	properties_.set(properties::Location, propertyValue);

	/* Camera Rotation: default is 0 degrees. */
	const auto &rotationControl = controls.find(V4L2_CID_CAMERA_SENSOR_ROTATION);
	if (rotationControl != controls.end())
		propertyValue = rotationControl->second.def().get<int32_t>();
	else
		propertyValue = 0;
	properties_.set(properties::Rotation, propertyValue);

	/* Enumerate and cache media bus codes and sizes. */
	const ImageFormats formats = subdev_->formats(0);
	if (formats.isEmpty()) {
		LOG(CameraSensor, Error) << "No image format found";
		return -EINVAL;
	}

	mbusCodes_ = formats.formats();

	/*
	 * Extract the supported sizes from the first format as we only support
	 * sensors that offer the same frame sizes for all media bus codes.
	 * Verify this assumption and reject the sensor if it isn't true.
	 */
	const std::vector<SizeRange> &sizes = formats.sizes(mbusCodes_[0]);
	std::transform(sizes.begin(), sizes.end(), std::back_inserter(sizes_),
		       [](const SizeRange &range) { return range.max; });

	for (unsigned int code : mbusCodes_) {
		if (formats.sizes(code) != sizes) {
			LOG(CameraSensor, Error)
				<< "Frame sizes differ between media bus codes";
			return -EINVAL;
		}
	}

	/* Sort the media bus codes and sizes. */
	std::sort(mbusCodes_.begin(), mbusCodes_.end());
	std::sort(sizes_.begin(), sizes_.end());

	return 0;
}

/**
 * \fn CameraSensor::entity()
 * \brief Retrieve the sensor media entity
 * \return The sensor media entity
 */

/**
 * \fn CameraSensor::mbusCodes()
 * \brief Retrieve the media bus codes supported by the camera sensor
 * \return The supported media bus codes sorted in increasing order
 */

/**
 * \fn CameraSensor::sizes()
 * \brief Retrieve the frame sizes supported by the camera sensor
 * \return The supported frame sizes sorted in increasing order
 */

/**
 * \brief Retrieve the camera sensor resolution
 * \return The camera sensor resolution in pixels
 */
const Size &CameraSensor::resolution() const
{
	/*
	 * The sizes_ vector is sorted in ascending order, the resolution is
	 * thus the last element of the vector.
	 */
	return sizes_.back();
}

/**
 * \brief Retrieve the best sensor format for a desired output
 * \param[in] mbusCodes The list of acceptable media bus codes
 * \param[in] size The desired size
 *
 * Media bus codes are selected from \a mbusCodes, which lists all acceptable
 * codes in decreasing order of preference. This method selects the first code
 * from the list that is supported by the sensor. If none of the desired codes
 * is supported, it returns an error.
 *
 * \a size indicates the desired size at the output of the sensor. This method
 * selects the best size supported by the sensor according to the following
 * criteria.
 *
 * - The desired \a size shall fit in the sensor output size to avoid the need
 *   to up-scale.
 * - The sensor output size shall match the desired aspect ratio to avoid the
 *   need to crop the field of view.
 * - The sensor output size shall be as small as possible to lower the required
 *   bandwidth.
 *
 * The use of this method is optional, as the above criteria may not match the
 * needs of all pipeline handlers. Pipeline handlers may implement custom
 * sensor format selection when needed.
 *
 * The returned sensor output format is guaranteed to be acceptable by the
 * setFormat() method without any modification.
 *
 * \return The best sensor output format matching the desired media bus codes
 * and size on success, or an empty format otherwise.
 */
V4L2SubdeviceFormat CameraSensor::getFormat(const std::vector<unsigned int> &mbusCodes,
					    const Size &size) const
{
	V4L2SubdeviceFormat format{};

	for (unsigned int code : mbusCodes) {
		if (std::any_of(mbusCodes_.begin(), mbusCodes_.end(),
				[code](unsigned int c) { return c == code; })) {
			format.mbus_code = code;
			break;
		}
	}

	if (!format.mbus_code) {
		LOG(CameraSensor, Debug) << "No supported format found";
		return format;
	}

	unsigned int desiredArea = size.width * size.height;
	unsigned int bestArea = UINT_MAX;
	float desiredRatio = static_cast<float>(size.width) / size.height;
	float bestRatio = FLT_MAX;
	const Size *bestSize = nullptr;

	for (const Size &sz : sizes_) {
		if (sz.width < size.width || sz.height < size.height)
			continue;

		float ratio = static_cast<float>(sz.width) / sz.height;
		float ratioDiff = fabsf(ratio - desiredRatio);
		unsigned int area = sz.width * sz.height;
		unsigned int areaDiff = area - desiredArea;

		if (ratioDiff > bestRatio)
			continue;

		if (ratioDiff < bestRatio || areaDiff < bestArea) {
			bestRatio = ratioDiff;
			bestArea = areaDiff;
			bestSize = &sz;
		}
	}

	if (!bestSize) {
		LOG(CameraSensor, Debug) << "No supported size found";
		return format;
	}

	format.size = *bestSize;

	return format;
}

/**
 * \brief Set the sensor output format
 * \param[in] format The desired sensor output format
 * \return 0 on success or a negative error code otherwise
 */
int CameraSensor::setFormat(V4L2SubdeviceFormat *format)
{
	return subdev_->setFormat(0, format);
}

/**
 * \brief Retrieve the supported V4L2 controls and their information
 * \return A map of the V4L2 controls supported by the sensor
 */
const ControlInfoMap &CameraSensor::controls() const
{
	return subdev_->controls();
}

/**
 * \brief Read controls from the sensor
 * \param[inout] ctrls The list of controls to read
 *
 * This method reads the value of all controls contained in \a ctrls, and stores
 * their values in the corresponding \a ctrls entry.
 *
 * If any control in \a ctrls is not supported by the device, is disabled (i.e.
 * has the V4L2_CTRL_FLAG_DISABLED flag set), is a compound control, or if any
 * other error occurs during validation of the requested controls, no control is
 * read and this method returns -EINVAL.
 *
 * If an error occurs while reading the controls, the index of the first control
 * that couldn't be read is returned. The value of all controls below that index
 * are updated in \a ctrls, while the value of all the other controls are not
 * changed.
 *
 * \sa V4L2Device::getControls()
 *
 * \return 0 on success or an error code otherwise
 * \retval -EINVAL One of the control is not supported or not accessible
 * \retval i The index of the control that failed
 */
int CameraSensor::getControls(ControlList *ctrls)
{
	return subdev_->getControls(ctrls);
}

/**
 * \fn CameraSensor::properties()
 * \brief Retrieve the camera sensor properties
 * \return The list of camera sensor properties
 */

/**
 * \brief Write controls to the sensor
 * \param[in] ctrls The list of controls to write
 *