[PATCH v2 09/14] libcamera: v4l2_subdevice: Add V4L2Subdevice::Route structure

Kieran Bingham kieran.bingham at ideasonboard.com
Fri Mar 15 12:00:17 CET 2024


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 at ideasonboard.com>
> Reviewed-by: Jacopo Mondi <jacopo.mondi at 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 at 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
>


More information about the libcamera-devel mailing list