diff options
author | Jacopo Mondi <jacopo@jmondi.org> | 2022-03-30 12:27:03 +0200 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2022-08-03 17:44:28 +0300 |
commit | 495aac658dcedd7622b4108daf6c8ca4d8327599 (patch) | |
tree | d33e94bc936fa202a9aa1a88416739a8620da9bd | |
parent | 39d491761956b9c0e8c01ba5fc0a27558b90016e (diff) |
libcamera: v4l2_subdevice: Add support for the V4L2 subdev routing API
Extend the V4L2Subdevice class to support getting and setting routing
tables.
Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Tested-by: Jacopo Mondi <jacopo@jmondi.org>
-rw-r--r-- | include/libcamera/internal/v4l2_subdevice.h | 9 | ||||
-rw-r--r-- | src/libcamera/v4l2_subdevice.cpp | 106 |
2 files changed, 115 insertions, 0 deletions
diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index a1d3144c..00be17bb 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -61,6 +61,12 @@ public: ActiveFormat = V4L2_SUBDEV_FORMAT_ACTIVE, }; + class Routing : public std::vector<struct v4l2_subdev_route> + { + public: + std::string toString() const; + }; + explicit V4L2Subdevice(const MediaEntity *entity); ~V4L2Subdevice(); @@ -80,6 +86,9 @@ public: int setFormat(unsigned int pad, V4L2SubdeviceFormat *format, Whence whence = ActiveFormat); + int getRouting(Routing *routing, Whence whence = ActiveFormat); + int setRouting(Routing *routing, Whence whence = ActiveFormat); + const std::string &model(); const V4L2SubdeviceCapability &caps() const { return caps_; } diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index a1672b23..e5d20f2c 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -289,6 +289,33 @@ std::ostream &operator<<(std::ostream &out, const V4L2SubdeviceFormat &f) */ /** + * \class V4L2Subdevice::Routing + * \brief V4L2 subdevice routing table + * + * This class stores a subdevice routing table as a vector of routes. + */ + +/** + * \brief Assemble and return a string describing the routing table + * \return A string describing the routing table + */ +std::string V4L2Subdevice::Routing::toString() const +{ + std::stringstream routing; + + for (const auto &[i, route] : utils::enumerate(*this)) { + routing << "[" << i << "] " + << route.sink_pad << "/" << route.sink_stream << " -> " + << route.source_pad << "/" << route.source_stream + << " (" << utils::hex(route.flags) << ")"; + if (i != size() - 1) + routing << ", "; + } + + return routing.str(); +} + +/** * \brief Create a V4L2 subdevice from a MediaEntity using its device node * path */ @@ -518,6 +545,85 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format, } /** + * \brief Retrieve the subdevice's internal routing table + * \param[out] routing The routing table + * \param[in] whence The routing table to get, \ref V4L2Subdevice::ActiveFormat + * "ActiveFormat" or \ref V4L2Subdevice::TryFormat "TryFormat" + * + * \return 0 on success or a negative error code otherwise + */ +int V4L2Subdevice::getRouting(Routing *routing, Whence whence) +{ + if (!caps_.hasStreams()) + return 0; + + struct v4l2_subdev_routing rt = {}; + + rt.which = whence; + + int ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); + if (ret == 0 || ret == -ENOTTY) + return ret; + + if (ret != -ENOSPC) { + LOG(V4L2, Error) + << "Failed to retrieve number of routes: " + << strerror(-ret); + return ret; + } + + routing->resize(rt.num_routes); + rt.routes = reinterpret_cast<uintptr_t>(routing->data()); + + ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); + if (ret) { + LOG(V4L2, Error) + << "Failed to retrieve routes: " << strerror(-ret); + return ret; + } + + if (rt.num_routes != routing->size()) { + LOG(V4L2, Error) << "Invalid number of routes"; + return -EINVAL; + } + + return 0; +} + +/** + * \brief Set a routing table on the V4L2 subdevice + * \param[inout] routing The routing table + * \param[in] whence The routing table to set, \ref V4L2Subdevice::ActiveFormat + * "ActiveFormat" or \ref V4L2Subdevice::TryFormat "TryFormat" + * + * Apply to the V4L2 subdevice the routing table \a routing and update its + * content to reflect the actually applied routing table as getRouting() would + * do. + * + * \return 0 on success or a negative error code otherwise + */ +int V4L2Subdevice::setRouting(Routing *routing, Whence whence) +{ + if (!caps_.hasStreams()) + return 0; + + struct v4l2_subdev_routing rt = {}; + rt.which = whence; + rt.num_routes = routing->size(); + rt.routes = reinterpret_cast<uintptr_t>(routing->data()); + + int ret = ioctl(VIDIOC_SUBDEV_S_ROUTING, &rt); + if (ret) { + LOG(V4L2, Error) << "Failed to set routes: " << strerror(-ret); + return ret; + } + + routing->resize(rt.num_routes); + + return 0; +} + +/** * \brief Retrieve the model name of the device * * The model name allows identification of the specific device model. This can |