summaryrefslogtreecommitdiff
path: root/src/libcamera/camera_sensor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcamera/camera_sensor.cpp')
-rw-r--r--src/libcamera/camera_sensor.cpp131
1 files changed, 63 insertions, 68 deletions
diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp
index 4154700a..31a916a9 100644
--- a/src/libcamera/camera_sensor.cpp
+++ b/src/libcamera/camera_sensor.cpp
@@ -119,8 +119,7 @@ LOG_DEFINE_CATEGORY(CameraSensor);
* 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
+ * subdevice with a single pad. It will be extended to support more complex
* devices as the needs arise.
*/
@@ -245,36 +244,34 @@ int CameraSensor::init()
propertyValue = 0;
properties_.set(properties::Rotation, propertyValue);
- /* Enumerate and cache media bus codes and sizes. */
- const ImageFormats formats = subdev_->formats(pad_);
- if (formats.isEmpty()) {
+ /* Enumerate, sort and cache media bus codes and sizes. */
+ formats_ = subdev_->formats(pad_);
+ if (formats_.isEmpty()) {
LOG(CameraSensor, Error) << "No image format found";
return -EINVAL;
}
- mbusCodes_ = formats.formats();
+ mbusCodes_ = formats_.formats();
+ std::sort(mbusCodes_.begin(), mbusCodes_.end());
- /*
- * 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;
- }
+ for (const auto &format : formats_.data()) {
+ const std::vector<SizeRange> &ranges = format.second;
+ std::transform(ranges.begin(), ranges.end(), std::back_inserter(sizes_),
+ [](const SizeRange &range) { return range.max; });
}
- /* Sort the media bus codes and sizes. */
- std::sort(mbusCodes_.begin(), mbusCodes_.end());
std::sort(sizes_.begin(), sizes_.end());
+ /* Remove duplicates. */
+ auto last = std::unique(sizes_.begin(), sizes_.end());
+ sizes_.erase(last, sizes_.end());
+
+ /*
+ * The sizes_ vector is sorted in ascending order, the resolution is
+ * thus the last element of the vector.
+ */
+ resolution_ = sizes_.back();
+
return 0;
}
@@ -303,21 +300,18 @@ int CameraSensor::init()
/**
* \fn CameraSensor::sizes()
* \brief Retrieve the frame sizes supported by the camera sensor
+ *
+ * The reported sizes span all media bus codes supported by the camera sensor.
+ * Not all sizes may be supported by all media bus codes.
+ *
* \return The supported frame sizes sorted in increasing order
*/
/**
+ * \fn CameraSensor::resolution()
* \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
@@ -325,13 +319,13 @@ const Size &CameraSensor::resolution() const
* \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.
+ * codes in decreasing order of preference. Media bus codes supported by the
+ * sensor but not listed in \a mbusCodes are ignored. 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.
+ * selects the best media bus code and 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.
@@ -339,6 +333,11 @@ const Size &CameraSensor::resolution() const
* need to crop the field of view.
* - The sensor output size shall be as small as possible to lower the required
* bandwidth.
+ * - The desired \a size shall be supported by one of the media bus code listed
+ * in \a mbusCodes.
+ *
+ * When multiple media bus codes can produce the same size, the code at the
+ * lowest position in \a mbusCodes is selected.
*
* 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
@@ -353,52 +352,48 @@ const Size &CameraSensor::resolution() const
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;
+ uint32_t bestCode = 0;
+
+ for (unsigned int code : mbusCodes) {
+ const std::vector<SizeRange> &ranges = formats_.sizes(code);
+
+ for (const SizeRange &range : ranges) {
+ const Size &sz = range.max;
- for (const Size &sz : sizes_) {
- if (sz.width < size.width || sz.height < size.height)
- continue;
+ 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;
+ 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)
+ continue;
- if (ratioDiff < bestRatio || areaDiff < bestArea) {
- bestRatio = ratioDiff;
- bestArea = areaDiff;
- bestSize = &sz;
+ if (ratioDiff < bestRatio || areaDiff < bestArea) {
+ bestRatio = ratioDiff;
+ bestArea = areaDiff;
+ bestSize = &sz;
+ bestCode = code;
+ }
}
}
if (!bestSize) {
- LOG(CameraSensor, Debug) << "No supported size found";
- return format;
+ LOG(CameraSensor, Debug) << "No supported format or size found";
+ return {};
}
- format.size = *bestSize;
+ V4L2SubdeviceFormat format{
+ .mbus_code = bestCode,
+ .size = *bestSize,
+ };
return format;
}
@@ -424,7 +419,7 @@ const ControlInfoMap &CameraSensor::controls() const
/**
* \brief Read controls from the sensor
- * \param[in] ids The list of control to read, specified by their ID
+ * \param[in] ids The list of controls to read, specified by their ID
*
* This method reads the value of all controls contained in \a ids, and returns
* their values as a ControlList.