Message ID | 20240315001613.2033-10-laurent.pinchart@ideasonboard.com |
---|---|
State | Accepted |
Commit | c5a8152af269e798297debcf6ab1bfb5ed82ebc1 |
Headers | show |
Series |
|
Related | show |
Quoting Laurent Pinchart (2024-03-15 00:16:08) > The V4L2Subdevice class deals with streams in two places: > > - In routing tables, streams as expressed as a pad number and a stream > number in a v4l2_subdev_route instance. > - In the format and selection get and set functions, streams as > expressed using the Stream structure, which binds the pad number and > stream number. > > Expressing streams in different ways requires pipeline handlers and > other helpers to convert between the two representations. This isn't > much of an issue yet as libcamera has little stream-aware code, but it > is expected to increasingly become a burden. > > To simplify the API, introduce a V4L2Subdevice::Route structure that > mimicks the kernel v4l2_subdev_route structure but represents streams as > V4L2Subdevice::Stream instances. This will improve seamless integration > of routes, formats and selection rectangles. > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> I got to the bottom without finding anything to comment on. So I guess that's a Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > --- > Changes since combined RFC: > > - Fix compilation in imx8-isi pipeline handler > - Fix indentation in comments > > Changes since v1: > > - Clear routing at the beginning of getRouting() and setRouting() > --- > include/libcamera/internal/v4l2_subdevice.h | 19 +++- > src/libcamera/pipeline/imx8-isi/imx8-isi.cpp | 14 +-- > src/libcamera/pipeline/simple/simple.cpp | 8 +- > src/libcamera/v4l2_subdevice.cpp | 108 +++++++++++++++++-- > 4 files changed, 123 insertions(+), 26 deletions(-) > > diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h > index 2939dc2411c6..01ed4c2fc397 100644 > --- a/include/libcamera/internal/v4l2_subdevice.h > +++ b/include/libcamera/internal/v4l2_subdevice.h > @@ -95,7 +95,23 @@ public: > unsigned int stream; > }; > > - using Routing = std::vector<struct v4l2_subdev_route>; > + struct Route { > + Route() > + : flags(0) > + { > + } > + > + Route(const Stream &snk, const Stream &src, uint32_t f) > + : sink(snk), source(src), flags(f) > + { > + } > + > + Stream sink; > + Stream source; > + uint32_t flags; > + }; > + > + using Routing = std::vector<Route>; > > explicit V4L2Subdevice(const MediaEntity *entity); > ~V4L2Subdevice(); > @@ -174,6 +190,7 @@ static inline bool operator!=(const V4L2Subdevice::Stream &lhs, > } > > std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream); > +std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Route &route); > std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Routing &routing); > > } /* namespace libcamera */ > diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp > index a3782aea2ba9..63082cea7e56 100644 > --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp > +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp > @@ -827,16 +827,10 @@ int PipelineHandlerISI::configure(Camera *camera, CameraConfiguration *c) > unsigned int xbarFirstSource = crossbar_->entity()->pads().size() / 2 + 1; > > for (const auto &[idx, config] : utils::enumerate(*c)) { > - struct v4l2_subdev_route route = { > - .sink_pad = data->xbarSink_, > - .sink_stream = 0, > - .source_pad = static_cast<uint32_t>(xbarFirstSource + idx), > - .source_stream = 0, > - .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, > - .reserved = {} > - }; > - > - routing.push_back(route); > + uint32_t sourcePad = xbarFirstSource + idx; > + routing.emplace_back(V4L2Subdevice::Stream{ data->xbarSink_, 0 }, > + V4L2Subdevice::Stream{ sourcePad, 0 }, > + V4L2_SUBDEV_ROUTE_FL_ACTIVE); > } > > int ret = crossbar_->setRouting(&routing, V4L2Subdevice::ActiveFormat); > diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp > index feea26fd124f..01f2a97798ba 100644 > --- a/src/libcamera/pipeline/simple/simple.cpp > +++ b/src/libcamera/pipeline/simple/simple.cpp > @@ -852,17 +852,17 @@ std::vector<const MediaPad *> SimpleCameraData::routedSourcePads(MediaPad *sink) > > std::vector<const MediaPad *> pads; > > - for (const struct v4l2_subdev_route &route : routing) { > - if (sink->index() != route.sink_pad || > + for (const V4L2Subdevice::Route &route : routing) { > + if (sink->index() != route.sink.pad || > !(route.flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) > continue; > > - const MediaPad *pad = entity->getPadByIndex(route.source_pad); > + const MediaPad *pad = entity->getPadByIndex(route.source.pad); > if (!pad) { > LOG(SimplePipeline, Warning) > << "Entity " << entity->name() > << " has invalid route source pad " > - << route.source_pad; > + << route.source.pad; > } > > pads.push_back(pad); > diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp > index deef681e0d3a..1076b7006b0b 100644 > --- a/src/libcamera/v4l2_subdevice.cpp > +++ b/src/libcamera/v4l2_subdevice.cpp > @@ -898,6 +898,53 @@ std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream) > return out; > } > > +/** > + * \class V4L2Subdevice::Route > + * \brief V4L2 subdevice routing table entry > + * > + * This class models a route in the subdevice routing table. It is similar to > + * the v4l2_subdev_route structure, but uses the V4L2Subdevice::Stream class > + * for easier usage with the V4L2Subdevice stream-aware functions. > + * > + * \var V4L2Subdevice::Route::sink > + * \brief The sink stream of the route > + * > + * \var V4L2Subdevice::Route::source > + * \brief The source stream of the route > + * > + * \var V4L2Subdevice::Route::flags > + * \brief The route flags (V4L2_SUBDEV_ROUTE_FL_*) > + */ > + > +/** > + * \fn V4L2Subdevice::Route::Route() > + * \brief Construct a Route with default streams > + */ > + > +/** > + * \fn V4L2Subdevice::Route::Route(const Stream &sink, const Stream &source, > + * uint32_t flags) > + * \brief Construct a Route from \a sink to \a source > + * \param[in] sink The sink stream > + * \param[in] source The source stream > + * \param[in] flags The route flags > + */ > + > +/** > + * \brief Insert a text representation of a V4L2Subdevice::Route into an > + * output stream > + * \param[in] out The output stream > + * \param[in] route The V4L2Subdevice::Route > + * \return The output stream \a out > + */ > +std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Route &route) > +{ > + out << route.sink << " -> " << route.source > + << " (" << utils::hex(route.flags) << ")"; > + > + return out; > +} > + > /** > * \typedef V4L2Subdevice::Routing > * \brief V4L2 subdevice routing table > @@ -907,7 +954,7 @@ std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream) > > /** > * \brief Insert a text representation of a V4L2Subdevice::Routing into an > - * output stream > + * output stream > * \param[in] out The output stream > * \param[in] routing The V4L2Subdevice::Routing > * \return The output stream \a out > @@ -915,10 +962,7 @@ std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream) > std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Routing &routing) > { > for (const auto &[i, route] : utils::enumerate(routing)) { > - out << "[" << i << "] " > - << route.sink_pad << "/" << route.sink_stream << " -> " > - << route.source_pad << "/" << route.source_stream > - << " (" << utils::hex(route.flags) << ")"; > + out << "[" << i << "] " << route; > if (i != routing.size() - 1) > out << ", "; > } > @@ -1272,6 +1316,30 @@ int V4L2Subdevice::setFormat(const Stream &stream, V4L2SubdeviceFormat *format, > * \return 0 on success or a negative error code otherwise > */ > > +namespace { > + > +void routeFromKernel(V4L2Subdevice::Route &route, > + const struct v4l2_subdev_route &kroute) > +{ > + route.sink.pad = kroute.sink_pad; > + route.sink.stream = kroute.sink_stream; > + route.source.pad = kroute.source_pad; > + route.source.stream = kroute.source_stream; > + route.flags = kroute.flags; > +} > + > +void routeToKernel(const V4L2Subdevice::Route &route, > + struct v4l2_subdev_route &kroute) > +{ > + kroute.sink_pad = route.sink.pad; > + kroute.sink_stream = route.sink.stream; > + kroute.source_pad = route.source.pad; > + kroute.source_stream = route.source.stream; > + kroute.flags = route.flags; > +} > + > +} /* namespace */ > + > /** > * \brief Retrieve the subdevice's internal routing table > * \param[out] routing The routing table > @@ -1282,6 +1350,8 @@ int V4L2Subdevice::setFormat(const Stream &stream, V4L2SubdeviceFormat *format, > */ > int V4L2Subdevice::getRouting(Routing *routing, Whence whence) > { > + routing->clear(); > + > if (!caps_.hasStreams()) > return 0; > > @@ -1300,8 +1370,8 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) > return ret; > } > > - routing->resize(rt.num_routes); > - rt.routes = reinterpret_cast<uintptr_t>(routing->data()); > + std::vector<struct v4l2_subdev_route> routes{ rt.num_routes }; > + rt.routes = reinterpret_cast<uintptr_t>(routes.data()); > > ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); > if (ret) { > @@ -1310,11 +1380,16 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) > return ret; > } > > - if (rt.num_routes != routing->size()) { > + if (rt.num_routes != routes.size()) { > LOG(V4L2, Error) << "Invalid number of routes"; > return -EINVAL; > } > > + routing->resize(rt.num_routes); > + > + for (const auto &[i, route] : utils::enumerate(routes)) > + routeFromKernel((*routing)[i], route); > + > return 0; > } > > @@ -1332,13 +1407,20 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) > */ > int V4L2Subdevice::setRouting(Routing *routing, Whence whence) > { > - if (!caps_.hasStreams()) > + if (!caps_.hasStreams()) { > + routing->clear(); > return 0; > + } > + > + std::vector<struct v4l2_subdev_route> routes{ routing->size() }; > + > + for (const auto &[i, route] : utils::enumerate(*routing)) > + routeToKernel(route, routes[i]); > > struct v4l2_subdev_routing rt = {}; > rt.which = whence; > - rt.num_routes = routing->size(); > - rt.routes = reinterpret_cast<uintptr_t>(routing->data()); > + rt.num_routes = routes.size(); > + rt.routes = reinterpret_cast<uintptr_t>(routes.data()); > > int ret = ioctl(VIDIOC_SUBDEV_S_ROUTING, &rt); > if (ret) { > @@ -1346,8 +1428,12 @@ int V4L2Subdevice::setRouting(Routing *routing, Whence whence) > return ret; > } > > + routes.resize(rt.num_routes); > routing->resize(rt.num_routes); > > + for (const auto &[i, route] : utils::enumerate(routes)) > + routeFromKernel((*routing)[i], route); > + > return 0; > } > > -- > Regards, > > Laurent Pinchart >
diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h index 2939dc2411c6..01ed4c2fc397 100644 --- a/include/libcamera/internal/v4l2_subdevice.h +++ b/include/libcamera/internal/v4l2_subdevice.h @@ -95,7 +95,23 @@ public: unsigned int stream; }; - using Routing = std::vector<struct v4l2_subdev_route>; + struct Route { + Route() + : flags(0) + { + } + + Route(const Stream &snk, const Stream &src, uint32_t f) + : sink(snk), source(src), flags(f) + { + } + + Stream sink; + Stream source; + uint32_t flags; + }; + + using Routing = std::vector<Route>; explicit V4L2Subdevice(const MediaEntity *entity); ~V4L2Subdevice(); @@ -174,6 +190,7 @@ static inline bool operator!=(const V4L2Subdevice::Stream &lhs, } std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream); +std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Route &route); std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Routing &routing); } /* namespace libcamera */ diff --git a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp index a3782aea2ba9..63082cea7e56 100644 --- a/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp +++ b/src/libcamera/pipeline/imx8-isi/imx8-isi.cpp @@ -827,16 +827,10 @@ int PipelineHandlerISI::configure(Camera *camera, CameraConfiguration *c) unsigned int xbarFirstSource = crossbar_->entity()->pads().size() / 2 + 1; for (const auto &[idx, config] : utils::enumerate(*c)) { - struct v4l2_subdev_route route = { - .sink_pad = data->xbarSink_, - .sink_stream = 0, - .source_pad = static_cast<uint32_t>(xbarFirstSource + idx), - .source_stream = 0, - .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, - .reserved = {} - }; - - routing.push_back(route); + uint32_t sourcePad = xbarFirstSource + idx; + routing.emplace_back(V4L2Subdevice::Stream{ data->xbarSink_, 0 }, + V4L2Subdevice::Stream{ sourcePad, 0 }, + V4L2_SUBDEV_ROUTE_FL_ACTIVE); } int ret = crossbar_->setRouting(&routing, V4L2Subdevice::ActiveFormat); diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index feea26fd124f..01f2a97798ba 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -852,17 +852,17 @@ std::vector<const MediaPad *> SimpleCameraData::routedSourcePads(MediaPad *sink) std::vector<const MediaPad *> pads; - for (const struct v4l2_subdev_route &route : routing) { - if (sink->index() != route.sink_pad || + for (const V4L2Subdevice::Route &route : routing) { + if (sink->index() != route.sink.pad || !(route.flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) continue; - const MediaPad *pad = entity->getPadByIndex(route.source_pad); + const MediaPad *pad = entity->getPadByIndex(route.source.pad); if (!pad) { LOG(SimplePipeline, Warning) << "Entity " << entity->name() << " has invalid route source pad " - << route.source_pad; + << route.source.pad; } pads.push_back(pad); diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index deef681e0d3a..1076b7006b0b 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -898,6 +898,53 @@ std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream) return out; } +/** + * \class V4L2Subdevice::Route + * \brief V4L2 subdevice routing table entry + * + * This class models a route in the subdevice routing table. It is similar to + * the v4l2_subdev_route structure, but uses the V4L2Subdevice::Stream class + * for easier usage with the V4L2Subdevice stream-aware functions. + * + * \var V4L2Subdevice::Route::sink + * \brief The sink stream of the route + * + * \var V4L2Subdevice::Route::source + * \brief The source stream of the route + * + * \var V4L2Subdevice::Route::flags + * \brief The route flags (V4L2_SUBDEV_ROUTE_FL_*) + */ + +/** + * \fn V4L2Subdevice::Route::Route() + * \brief Construct a Route with default streams + */ + +/** + * \fn V4L2Subdevice::Route::Route(const Stream &sink, const Stream &source, + * uint32_t flags) + * \brief Construct a Route from \a sink to \a source + * \param[in] sink The sink stream + * \param[in] source The source stream + * \param[in] flags The route flags + */ + +/** + * \brief Insert a text representation of a V4L2Subdevice::Route into an + * output stream + * \param[in] out The output stream + * \param[in] route The V4L2Subdevice::Route + * \return The output stream \a out + */ +std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Route &route) +{ + out << route.sink << " -> " << route.source + << " (" << utils::hex(route.flags) << ")"; + + return out; +} + /** * \typedef V4L2Subdevice::Routing * \brief V4L2 subdevice routing table @@ -907,7 +954,7 @@ std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream) /** * \brief Insert a text representation of a V4L2Subdevice::Routing into an - * output stream + * output stream * \param[in] out The output stream * \param[in] routing The V4L2Subdevice::Routing * \return The output stream \a out @@ -915,10 +962,7 @@ std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Stream &stream) std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Routing &routing) { for (const auto &[i, route] : utils::enumerate(routing)) { - out << "[" << i << "] " - << route.sink_pad << "/" << route.sink_stream << " -> " - << route.source_pad << "/" << route.source_stream - << " (" << utils::hex(route.flags) << ")"; + out << "[" << i << "] " << route; if (i != routing.size() - 1) out << ", "; } @@ -1272,6 +1316,30 @@ int V4L2Subdevice::setFormat(const Stream &stream, V4L2SubdeviceFormat *format, * \return 0 on success or a negative error code otherwise */ +namespace { + +void routeFromKernel(V4L2Subdevice::Route &route, + const struct v4l2_subdev_route &kroute) +{ + route.sink.pad = kroute.sink_pad; + route.sink.stream = kroute.sink_stream; + route.source.pad = kroute.source_pad; + route.source.stream = kroute.source_stream; + route.flags = kroute.flags; +} + +void routeToKernel(const V4L2Subdevice::Route &route, + struct v4l2_subdev_route &kroute) +{ + kroute.sink_pad = route.sink.pad; + kroute.sink_stream = route.sink.stream; + kroute.source_pad = route.source.pad; + kroute.source_stream = route.source.stream; + kroute.flags = route.flags; +} + +} /* namespace */ + /** * \brief Retrieve the subdevice's internal routing table * \param[out] routing The routing table @@ -1282,6 +1350,8 @@ int V4L2Subdevice::setFormat(const Stream &stream, V4L2SubdeviceFormat *format, */ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) { + routing->clear(); + if (!caps_.hasStreams()) return 0; @@ -1300,8 +1370,8 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) return ret; } - routing->resize(rt.num_routes); - rt.routes = reinterpret_cast<uintptr_t>(routing->data()); + std::vector<struct v4l2_subdev_route> routes{ rt.num_routes }; + rt.routes = reinterpret_cast<uintptr_t>(routes.data()); ret = ioctl(VIDIOC_SUBDEV_G_ROUTING, &rt); if (ret) { @@ -1310,11 +1380,16 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) return ret; } - if (rt.num_routes != routing->size()) { + if (rt.num_routes != routes.size()) { LOG(V4L2, Error) << "Invalid number of routes"; return -EINVAL; } + routing->resize(rt.num_routes); + + for (const auto &[i, route] : utils::enumerate(routes)) + routeFromKernel((*routing)[i], route); + return 0; } @@ -1332,13 +1407,20 @@ int V4L2Subdevice::getRouting(Routing *routing, Whence whence) */ int V4L2Subdevice::setRouting(Routing *routing, Whence whence) { - if (!caps_.hasStreams()) + if (!caps_.hasStreams()) { + routing->clear(); return 0; + } + + std::vector<struct v4l2_subdev_route> routes{ routing->size() }; + + for (const auto &[i, route] : utils::enumerate(*routing)) + routeToKernel(route, routes[i]); struct v4l2_subdev_routing rt = {}; rt.which = whence; - rt.num_routes = routing->size(); - rt.routes = reinterpret_cast<uintptr_t>(routing->data()); + rt.num_routes = routes.size(); + rt.routes = reinterpret_cast<uintptr_t>(routes.data()); int ret = ioctl(VIDIOC_SUBDEV_S_ROUTING, &rt); if (ret) { @@ -1346,8 +1428,12 @@ int V4L2Subdevice::setRouting(Routing *routing, Whence whence) return ret; } + routes.resize(rt.num_routes); routing->resize(rt.num_routes); + for (const auto &[i, route] : utils::enumerate(routes)) + routeFromKernel((*routing)[i], route); + return 0; }