@@ -19,6 +19,8 @@
#include <libcamera/base/utils.h>
+#include <libcamera/transform.h>
+
#include "libcamera/internal/bayer_format.h"
#include "libcamera/internal/camera_lens.h"
#include "libcamera/internal/camera_sensor_properties.h"
@@ -108,18 +110,45 @@ int CameraSensor::init()
return ret;
/*
- * Clear any flips to be sure we get the "native" Bayer order. This is
- * harmless for sensors where the flips don't affect the Bayer order.
+ * We want to get the native mbus codes for the sensor, without any flips.
+ * We can't clear any flips here, so we have to read the current values
+ * (if the flip controls exist), decide whether they actually modify any
+ * output Bayer pattern, and finally undo their effect on the formats.
+ *
+ * First, check if the flip controls exist and if so read them.
*/
- ControlList ctrls(subdev_->controls());
- if (subdev_->controls().find(V4L2_CID_HFLIP) != subdev_->controls().end())
- ctrls.set(V4L2_CID_HFLIP, 0);
- if (subdev_->controls().find(V4L2_CID_VFLIP) != subdev_->controls().end())
- ctrls.set(V4L2_CID_VFLIP, 0);
- subdev_->setControls(&ctrls);
+ std::vector<uint32_t> flipCtrlIds;
+ const struct v4l2_query_ext_ctrl *hflipInfo = subdev_->controlInfo(V4L2_CID_HFLIP);
+ const struct v4l2_query_ext_ctrl *vflipInfo = subdev_->controlInfo(V4L2_CID_VFLIP);
+ if (hflipInfo)
+ flipCtrlIds.push_back(V4L2_CID_HFLIP);
+ if (vflipInfo)
+ flipCtrlIds.push_back(V4L2_CID_VFLIP);
+ ControlList flipCtrls = subdev_->getControls(flipCtrlIds);
+
+ /* Now construct a transform that would undo any flips. */
+ Transform transform = Transform::Identity;
+ if (hflipInfo && flipCtrls.get(V4L2_CID_HFLIP).get<int>() &&
+ (hflipInfo->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT))
+ transform |= Transform::HFlip;
+ if (vflipInfo && flipCtrls.get(V4L2_CID_VFLIP).get<int>() &&
+ (vflipInfo->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT))
+ transform |= Transform::VFlip;
+
+ /* Finally get the formats, and apply the transform to the mbus codes. */
+ auto formats = subdev_->formats(pad_);
+ for (const auto &format : formats) {
+ unsigned int mbusCode = format.first;
+ BayerFormat bayerFormat = BayerFormat::fromMbusCode(mbusCode);
+
+ if (bayerFormat.isValid())
+ mbusCode = bayerFormat.transform(transform).toMbusCode();
+
+ if (mbusCode)
+ formats_[mbusCode] = std::move(format.second);
+ }
/* Enumerate, sort and cache media bus codes and sizes. */
- formats_ = subdev_->formats(pad_);
if (formats_.empty()) {
LOG(CameraSensor, Error) << "No image format found";
return -EINVAL;
@@ -189,7 +218,7 @@ int CameraSensor::init()
* \todo The control API ought to have a flag to specify if a control
* is read-only which could be used below.
*/
- const ControlInfo hblank = ctrls.infoMap()->at(V4L2_CID_HBLANK);
+ const ControlInfo hblank = subdev_->controls().at(V4L2_CID_HBLANK);
const int32_t hblankMin = hblank.min().get<int32_t>();
const int32_t hblankMax = hblank.max().get<int32_t>();