From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Cc: linux-media@vger.kernel.org, sakari.ailus@linux.intel.com,
Jacopo Mondi <jacopo.mondi@ideasonboard.com>,
niklas.soderlund+renesas@ragnatech.se,
Mauro Carvalho Chehab <mchehab@kernel.org>,
Hans Verkuil <hverkuil-cisco@xs4all.nl>,
satish.nagireddy@getcruise.com
Subject: Re: [PATCH v4 1/8] v4l2-ctl: Add routing and streams support
Date: Mon, 24 Apr 2023 10:04:55 +0300 [thread overview]
Message-ID: <20230424070455.GC4926@pendragon.ideasonboard.com> (raw)
In-Reply-To: <20230421124428.393261-2-tomi.valkeinen@ideasonboard.com>
Hi Tomi,
Thank you for the patch.
On Fri, Apr 21, 2023 at 03:44:21PM +0300, Tomi Valkeinen wrote:
> Add support to get and set subdev routes and to get and set
> configurations per stream.
>
> Based on work from Jacopo Mondi <jacopo@jmondi.org> and
> Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> ---
> utils/v4l2-ctl/v4l2-ctl-subdev.cpp | 310 ++++++++++++++++++++++++++---
> utils/v4l2-ctl/v4l2-ctl.cpp | 2 +
> utils/v4l2-ctl/v4l2-ctl.h | 2 +
> 3 files changed, 281 insertions(+), 33 deletions(-)
>
> diff --git a/utils/v4l2-ctl/v4l2-ctl-subdev.cpp b/utils/v4l2-ctl/v4l2-ctl-subdev.cpp
> index 33cc1342..7ab64646 100644
> --- a/utils/v4l2-ctl/v4l2-ctl-subdev.cpp
> +++ b/utils/v4l2-ctl/v4l2-ctl-subdev.cpp
> @@ -1,5 +1,13 @@
> #include "v4l2-ctl.h"
>
> +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
It would be nice to put the 14 implementations of this macro to a common
header. Out of scope for this patch.
> +
> +/*
> + * The max value comes from a check in the kernel source code
> + * drivers/media/v4l2-core/v4l2-ioctl.c check_array_args()
> + */
> +#define NUM_ROUTES_MAX 256
> +
> struct mbus_name {
> const char *name;
> __u32 code;
> @@ -19,45 +27,57 @@ static const struct mbus_name mbus_names[] = {
> #define SelectionFlags (1L<<4)
>
> static __u32 list_mbus_codes_pad;
> +static __u32 list_mbus_codes_stream = 0;
> static __u32 get_fmt_pad;
> +static __u32 get_fmt_stream = 0;
> static __u32 get_sel_pad;
> +static __u32 get_sel_stream = 0;
> static __u32 get_fps_pad;
> +static __u32 get_fps_stream = 0;
> static int get_sel_target = -1;
> static unsigned int set_selection;
> static struct v4l2_subdev_selection vsel;
> static unsigned int set_fmt;
> static __u32 set_fmt_pad;
> +static __u32 set_fmt_stream = 0;
> static struct v4l2_mbus_framefmt ffmt;
> static struct v4l2_subdev_frame_size_enum frmsize;
> static struct v4l2_subdev_frame_interval_enum frmival;
> static __u32 set_fps_pad;
> +static __u32 set_fps_stream = 0;
> static double set_fps;
> +static struct v4l2_subdev_routing routing;
> +static struct v4l2_subdev_route routes[NUM_ROUTES_MAX];
>
> void subdev_usage()
> {
> printf("\nSub-Device options:\n"
> - " --list-subdev-mbus-codes <pad>\n"
> + " --list-subdev-mbus-codes pad=<pad>,stream=<stream>\n"
> " display supported mediabus codes for this pad (0 is default)\n"
> " [VIDIOC_SUBDEV_ENUM_MBUS_CODE]\n"
> - " --list-subdev-framesizes pad=<pad>,code=<code>\n"
> + " --list-subdev-framesizes pad=<pad>,stream=<stream>,code=<code>\n"
> " list supported framesizes for this pad and code\n"
> " [VIDIOC_SUBDEV_ENUM_FRAME_SIZE]\n"
> " <code> is the value of the mediabus code\n"
> - " --list-subdev-frameintervals pad=<pad>,width=<w>,height=<h>,code=<code>\n"
> + " --list-subdev-frameintervals pad=<pad>,stream=<stream>,width=<w>,height=<h>,code=<code>\n"
> " list supported frame intervals for this pad and code and\n"
> " the given width and height [VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL]\n"
> " <code> is the value of the mediabus code\n"
> - " --get-subdev-fmt [<pad>]\n"
> - " query the frame format for the given pad [VIDIOC_SUBDEV_G_FMT]\n"
> - " --get-subdev-selection pad=<pad>,target=<target>\n"
> + " --get-subdev-fmt pad=<pad>,stream=<stream>\n"
> + " query the frame format for the given pad and optional stream [VIDIOC_SUBDEV_G_FMT]\n"
> + " <pad> the pad to get the format from\n"
> + " <stream> the stream to get the format from (0 if not specified)\n"
> + " --get-subdev-selection pad=<pad>,stream=<stream>,target=<target>\n"
> " query the frame selection rectangle [VIDIOC_SUBDEV_G_SELECTION]\n"
> " See --set-subdev-selection command for the valid <target> values.\n"
> - " --get-subdev-fps [<pad>]\n"
> + " --get-subdev-fps pad=<pad>,stream=<stream>\n"
> " query the frame rate [VIDIOC_SUBDEV_G_FRAME_INTERVAL]\n"
> " --set-subdev-fmt (for testing only, otherwise use media-ctl)\n"
> - " --try-subdev-fmt pad=<pad>,width=<w>,height=<h>,code=<code>,field=<f>,colorspace=<c>,\n"
> + " --try-subdev-fmt pad=<pad>,stream=<stream>,width=<w>,height=<h>,code=<code>,field=<f>,colorspace=<c>,\n"
> " xfer=<xf>,ycbcr=<y>,hsv=<hsv>,quantization=<q>\n"
> - " set the frame format [VIDIOC_SUBDEV_S_FMT]\n"
> + " set the frame format for the given pad and optional stream [VIDIOC_SUBDEV_S_FMT]\n"
> + " <pad> the pad to get the format from\n"
> + " <stream> the stream to get the format from (0 if not specified)\n"
> " <code> is the value of the mediabus code\n"
> " <f> can be one of the following field layouts:\n"
> " any, none, top, bottom, interlaced, seq_tb, seq_bt,\n"
> @@ -74,31 +94,74 @@ void subdev_usage()
> " <q> can be one of the following quantization methods:\n"
> " default, full-range, lim-range\n"
> " --set-subdev-selection (for testing only, otherwise use media-ctl)\n"
> - " --try-subdev-selection pad=<pad>,target=<target>,flags=<flags>,\n"
> + " --try-subdev-selection pad=<pad>,stream=<stream>,target=<target>,flags=<flags>,\n"
> " top=<x>,left=<y>,width=<w>,height=<h>\n"
> " set the video capture selection rectangle [VIDIOC_SUBDEV_S_SELECTION]\n"
> " target=crop|crop_bounds|crop_default|compose|compose_bounds|\n"
> " compose_default|compose_padded|native_size\n"
> " flags=le|ge|keep-config\n"
> - " --set-subdev-fps pad=<pad>,fps=<fps> (for testing only, otherwise use media-ctl)\n"
> + " --set-subdev-fps pad=<pad>,stream=<stream>,fps=<fps> (for testing only, otherwise use media-ctl)\n"
> " set the frame rate [VIDIOC_SUBDEV_S_FRAME_INTERVAL]\n"
> + " --get-routing Print the route topology\n"
> + " --set-routing <routes>\n"
> + " Comma-separated list of route descriptors to setup\n"
> + "\n"
> + "Routes are defined as\n"
> + " routes = route { ',' route } ;\n"
> + " route = sink '->' source '[' flags ']' ;\n"
> + " sink = sink-pad '/' sink-stream ;\n"
> + " source = source-pad '/' source-stream ;\n"
> + "\n"
> + "where\n"
> + " sink-pad = Pad numeric identifier for sink\n"
> + " sink-stream = Stream numeric identifier for sink\n"
> + " source-pad = Pad numeric identifier for source\n"
> + " source-stream = Stream numeric identifier for source\n"
> + " flags = Route flags (0: inactive, 1: active)\n"
> );
> }
>
> void subdev_cmd(int ch, char *optarg)
> {
> char *value, *subs;
> + char *endp;
>
> switch (ch) {
> case OptListSubDevMBusCodes:
> - if (optarg)
> - list_mbus_codes_pad = strtoul(optarg, nullptr, 0);
> + if (optarg) {
> + /* Legacy pad-only parsing */
> + list_mbus_codes_pad = strtoul(optarg, &endp, 0);
> + if (*endp == 0)
> + break;
> + }
> +
> + subs = optarg;
> + while (subs && *subs != '\0') {
> + static constexpr const char *subopts[] = {
> + "pad",
> + "stream",
> + nullptr
> + };
> +
> + switch (parse_subopt(&subs, subopts, &value)) {
> + case 0:
> + list_mbus_codes_pad = strtoul(value, nullptr, 0);
> + break;
> + case 1:
> + list_mbus_codes_stream = strtoul(value, nullptr, 0);
> + break;
> + default:
> + subdev_usage();
> + std::exit(EXIT_FAILURE);
> + }
> + }
> break;
> case OptListSubDevFrameSizes:
> subs = optarg;
> while (*subs != '\0') {
> static constexpr const char *subopts[] = {
> "pad",
> + "stream",
> "code",
> nullptr
> };
> @@ -108,6 +171,9 @@ void subdev_cmd(int ch, char *optarg)
> frmsize.pad = strtoul(value, nullptr, 0);
> break;
> case 1:
> + frmsize.stream = strtoul(value, nullptr, 0);
> + break;
> + case 2:
> frmsize.code = strtoul(value, nullptr, 0);
> break;
> default:
> @@ -121,6 +187,7 @@ void subdev_cmd(int ch, char *optarg)
> while (*subs != '\0') {
> static constexpr const char *subopts[] = {
> "pad",
> + "stream",
> "code",
> "width",
> "height",
> @@ -132,12 +199,15 @@ void subdev_cmd(int ch, char *optarg)
> frmival.pad = strtoul(value, nullptr, 0);
> break;
> case 1:
> - frmival.code = strtoul(value, nullptr, 0);
> + frmival.stream = strtoul(value, nullptr, 0);
> break;
> case 2:
> - frmival.width = strtoul(value, nullptr, 0);
> + frmival.code = strtoul(value, nullptr, 0);
> break;
> case 3:
> + frmival.width = strtoul(value, nullptr, 0);
> + break;
> + case 4:
> frmival.height = strtoul(value, nullptr, 0);
> break;
> default:
> @@ -147,14 +217,40 @@ void subdev_cmd(int ch, char *optarg)
> }
> break;
> case OptGetSubDevFormat:
> - if (optarg)
> - get_fmt_pad = strtoul(optarg, nullptr, 0);
> + if (optarg) {
> + /* Legacy pad-only parsing */
> + get_fmt_pad = strtoul(optarg, &endp, 0);
> + if (*endp == 0)
> + break;
> + }
> +
> + subs = optarg;
> + while (subs && *subs != '\0') {
> + static constexpr const char *subopts[] = {
> + "pad",
> + "stream",
> + nullptr
> + };
> +
> + switch (parse_subopt(&subs, subopts, &value)) {
> + case 0:
> + get_fmt_pad = strtoul(value, nullptr, 0);
> + break;
> + case 1:
> + get_fmt_stream = strtoul(value, nullptr, 0);
> + break;
> + default:
> + subdev_usage();
> + std::exit(EXIT_FAILURE);
> + }
> + }
> break;
> case OptGetSubDevSelection:
> subs = optarg;
> while (*subs != '\0') {
> static constexpr const char *subopts[] = {
> "pad",
> + "stream",
> "target",
> nullptr
> };
> @@ -165,6 +261,9 @@ void subdev_cmd(int ch, char *optarg)
> get_sel_pad = strtoul(value, nullptr, 0);
> break;
> case 1:
> + get_sel_stream = strtoul(value, nullptr, 0);
> + break;
> + case 2:
> if (parse_selection_target(value, target)) {
> fprintf(stderr, "Unknown selection target\n");
> subdev_usage();
> @@ -179,8 +278,33 @@ void subdev_cmd(int ch, char *optarg)
> }
> break;
> case OptGetSubDevFPS:
> - if (optarg)
> - get_fps_pad = strtoul(optarg, nullptr, 0);
> + if (optarg) {
> + /* Legacy pad-only parsing */
> + get_fps_pad = strtoul(optarg, &endp, 0);
> + if (*endp == 0)
> + break;
> + }
> +
> + subs = optarg;
> + while (subs && *subs != '\0') {
> + static constexpr const char *subopts[] = {
> + "pad",
> + "stream",
> + nullptr
> + };
> +
> + switch (parse_subopt(&subs, subopts, &value)) {
> + case 0:
> + get_fps_pad = strtoul(value, nullptr, 0);
> + break;
> + case 1:
> + get_fps_stream = strtoul(value, nullptr, 0);
> + break;
> + default:
> + subdev_usage();
> + std::exit(EXIT_FAILURE);
> + }
> + }
> break;
> case OptSetSubDevFormat:
> case OptTrySubDevFormat:
> @@ -198,6 +322,7 @@ void subdev_cmd(int ch, char *optarg)
> "quantization",
> "xfer",
> "pad",
> + "stream",
> nullptr
> };
>
> @@ -244,6 +369,9 @@ void subdev_cmd(int ch, char *optarg)
> case 9:
> set_fmt_pad = strtoul(value, nullptr, 0);
> break;
> + case 10:
> + set_fmt_stream = strtoul(value, nullptr, 0);
> + break;
> default:
> fprintf(stderr, "Unknown option\n");
> subdev_usage();
> @@ -264,6 +392,7 @@ void subdev_cmd(int ch, char *optarg)
> "width",
> "height",
> "pad",
> + "stream",
> nullptr
> };
>
> @@ -298,6 +427,9 @@ void subdev_cmd(int ch, char *optarg)
> case 6:
> vsel.pad = strtoul(value, nullptr, 0);
> break;
> + case 7:
> + vsel.stream = strtoul(value, nullptr, 0);
> + break;
> default:
> fprintf(stderr, "Unknown option\n");
> subdev_usage();
> @@ -311,6 +443,7 @@ void subdev_cmd(int ch, char *optarg)
> while (*subs != '\0') {
> static constexpr const char *subopts[] = {
> "pad",
> + "stream",
> "fps",
> nullptr
> };
> @@ -320,6 +453,9 @@ void subdev_cmd(int ch, char *optarg)
> set_fps_pad = strtoul(value, nullptr, 0);
> break;
> case 1:
> + set_fps_stream = strtoul(value, nullptr, 0);
> + break;
> + case 2:
> set_fps = strtod(value, nullptr);
> break;
> default:
> @@ -329,6 +465,47 @@ void subdev_cmd(int ch, char *optarg)
> }
> }
> break;
> + case OptSetRouting: {
> + struct v4l2_subdev_route *r;
> + char *end, *ref, *tok;
> + unsigned int flags;
> +
> + memset(&routing, 0, sizeof(routing));
> + memset(routes, 0, sizeof(routes[0]) * NUM_ROUTES_MAX);
> + routing.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> + routing.num_routes = 0;
> + routing.routes = (__u64)routes;
> +
> + if (!optarg)
> + break;
> +
> + r = (v4l2_subdev_route *)routing.routes;
> + ref = end = strdup(optarg);
> + while ((tok = strsep(&end, ",")) != NULL) {
> + if (sscanf(tok, "%u/%u -> %u/%u [%u]",
> + &r->sink_pad, &r->sink_stream,
> + &r->source_pad, &r->source_stream,
> + &flags) != 5) {
Requiring a space around '->' isn't nice, especially as it's not present
in the help text. MC link parsing makes spaces optional, please do the
same here.
> + free(ref);
> + fprintf(stderr, "Invalid route information specified\n");
> + subdev_usage();
> + std::exit(EXIT_FAILURE);
> + }
> +
> + if (flags & ~(V4L2_SUBDEV_ROUTE_FL_ACTIVE)) {
> + fprintf(stderr, "Invalid route flags specified: %#x\n", flags);
> + subdev_usage();
> + std::exit(EXIT_FAILURE);
> + }
> +
> + r->flags = flags;
> +
> + r++;
> + routing.num_routes++;
> + }
> + free(ref);
> + break;
> + }
> default:
> break;
> }
> @@ -394,6 +571,7 @@ void subdev_set(cv4l_fd &_fd)
>
> memset(&fmt, 0, sizeof(fmt));
> fmt.pad = set_fmt_pad;
> + fmt.stream = set_fmt_stream;
> fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
>
> if (doioctl(fd, VIDIOC_SUBDEV_G_FMT, &fmt) == 0) {
> @@ -430,7 +608,7 @@ void subdev_set(cv4l_fd &_fd)
> else
> fmt.which = V4L2_SUBDEV_FORMAT_TRY;
>
> - printf("ioctl: VIDIOC_SUBDEV_S_FMT (pad=%u)\n", fmt.pad);
> + printf("ioctl: VIDIOC_SUBDEV_S_FMT (pad=%u,stream=%u)\n", fmt.pad, fmt.stream);
> ret = doioctl(fd, VIDIOC_SUBDEV_S_FMT, &fmt);
> if (ret == 0 && (verbose || !options[OptSetSubDevFormat]))
> print_framefmt(fmt.format);
> @@ -441,6 +619,7 @@ void subdev_set(cv4l_fd &_fd)
>
> memset(&sel, 0, sizeof(sel));
> sel.pad = vsel.pad;
> + sel.stream = vsel.stream;
> sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> sel.target = vsel.target;
>
> @@ -461,7 +640,7 @@ void subdev_set(cv4l_fd &_fd)
> else
> sel.which = V4L2_SUBDEV_FORMAT_TRY;
>
> - printf("ioctl: VIDIOC_SUBDEV_S_SELECTION (pad=%u)\n", sel.pad);
> + printf("ioctl: VIDIOC_SUBDEV_S_SELECTION (pad=%u,stream=%u)\n", sel.pad, sel.stream);
> int ret = doioctl(fd, VIDIOC_SUBDEV_S_SELECTION, &sel);
> if (ret == 0 && (verbose || !options[OptSetSubDevSelection]))
> print_subdev_selection(sel);
> @@ -472,6 +651,7 @@ void subdev_set(cv4l_fd &_fd)
>
> memset(&fival, 0, sizeof(fival));
> fival.pad = set_fps_pad;
> + fival.stream = set_fps_stream;
>
> if (set_fps <= 0) {
> fprintf(stderr, "invalid fps %f\n", set_fps);
> @@ -482,7 +662,7 @@ void subdev_set(cv4l_fd &_fd)
> fival.interval.denominator = static_cast<uint32_t>(set_fps * fival.interval.numerator);
> printf("Note: --set-subdev-fps is only for testing.\n"
> "Normally media-ctl is used to configure the video pipeline.\n");
> - printf("ioctl: VIDIOC_SUBDEV_S_FRAME_INTERVAL (pad=%u)\n", fival.pad);
> + printf("ioctl: VIDIOC_SUBDEV_S_FRAME_INTERVAL (pad=%u,stream=%u)\n", fival.pad, fival.stream);
> if (doioctl(fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival) == 0) {
> if (!fival.interval.denominator || !fival.interval.numerator)
> printf("\tFrames per second: invalid (%d/%d)\n",
> @@ -493,6 +673,55 @@ void subdev_set(cv4l_fd &_fd)
> fival.interval.denominator, fival.interval.numerator);
> }
> }
> + if (options[OptSetRouting]) {
> + if (doioctl(fd, VIDIOC_SUBDEV_S_ROUTING, &routing) == 0)
> + printf("Routing set\n");
> + }
> +}
> +
> +struct flag_name {
> + __u32 flag;
> + const char *name;
> +};
> +
> +static void print_flags(const struct flag_name *flag_names, unsigned int num_entries, __u32 flags)
> +{
> + bool first = true;
> + unsigned int i;
> +
> + for (i = 0; i < num_entries; i++) {
> + if (!(flags & flag_names[i].flag))
> + continue;
> + if (!first)
> + printf(",");
> + printf("%s", flag_names[i].name);
> + flags &= ~flag_names[i].flag;
> + first = false;
> + }
> +
> + if (flags) {
> + if (!first)
> + printf(",");
> + printf("0x%x", flags);
> + }
> +}
This could also be a helper shared by multiple source files.
> +
> +static void print_routes(const struct v4l2_subdev_routing *r)
> +{
> + unsigned int i;
> + struct v4l2_subdev_route *routes = (struct v4l2_subdev_route *)r->routes;
> +
> + static const struct flag_name route_flags[] = {
> + { V4L2_SUBDEV_ROUTE_FL_ACTIVE, "ACTIVE" },
> + };
> +
> + for (i = 0; i < r->num_routes; i++) {
> + printf("%d/%d -> %d/%d [",
The values are unsigned, %u.
> + routes[i].sink_pad, routes[i].sink_stream,
> + routes[i].source_pad, routes[i].source_stream);
> + print_flags(route_flags, ARRAY_SIZE(route_flags), routes[i].flags);
> + printf("]\n");
> + }
> }
>
> void subdev_get(cv4l_fd &_fd)
> @@ -505,8 +734,9 @@ void subdev_get(cv4l_fd &_fd)
> memset(&fmt, 0, sizeof(fmt));
> fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> fmt.pad = get_fmt_pad;
> + fmt.stream = get_fmt_stream;
>
> - printf("ioctl: VIDIOC_SUBDEV_G_FMT (pad=%u)\n", fmt.pad);
> + printf("ioctl: VIDIOC_SUBDEV_G_FMT (pad=%u, stream=%u)\n", fmt.pad, fmt.stream);
In some places you have a space after the comma, in some places you
don't. I prefer the space personally but I'm fine with either as long as
it's consistent.
> if (doioctl(fd, VIDIOC_SUBDEV_G_FMT, &fmt) == 0)
> print_framefmt(fmt.format);
> }
> @@ -518,8 +748,9 @@ void subdev_get(cv4l_fd &_fd)
> memset(&sel, 0, sizeof(sel));
> sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> sel.pad = get_sel_pad;
> + sel.stream = get_sel_stream;
>
> - printf("ioctl: VIDIOC_SUBDEV_G_SELECTION (pad=%u)\n", sel.pad);
> + printf("ioctl: VIDIOC_SUBDEV_G_SELECTION (pad=%u,stream=%u)\n", sel.pad, sel.stream);
> if (options[OptAll] || get_sel_target == -1) {
> while (valid_seltarget_at_idx(idx)) {
> sel.target = seltarget_at_idx(idx);
> @@ -538,8 +769,9 @@ void subdev_get(cv4l_fd &_fd)
>
> memset(&fival, 0, sizeof(fival));
> fival.pad = get_fps_pad;
> + fival.stream = get_fps_stream;
>
> - printf("ioctl: VIDIOC_SUBDEV_G_FRAME_INTERVAL (pad=%u)\n", fival.pad);
> + printf("ioctl: VIDIOC_SUBDEV_G_FRAME_INTERVAL (pad=%u,stream=%u)\n", fival.pad, fival.stream);
> if (doioctl(fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &fival) == 0) {
> if (!fival.interval.denominator || !fival.interval.numerator)
> printf("\tFrames per second: invalid (%d/%d)\n",
> @@ -550,6 +782,17 @@ void subdev_get(cv4l_fd &_fd)
> fival.interval.denominator, fival.interval.numerator);
> }
> }
> +
> + if (options[OptGetRouting]) {
> + memset(&routing, 0, sizeof(routing));
> + memset(routes, 0, sizeof(routes[0]) * NUM_ROUTES_MAX);
> + routing.which = V4L2_SUBDEV_FORMAT_ACTIVE;
> + routing.num_routes = NUM_ROUTES_MAX;
> + routing.routes = (__u64)routes;
> +
> + if (doioctl(fd, VIDIOC_SUBDEV_G_ROUTING, &routing) == 0)
> + print_routes(&routing);
> + }
> }
>
> static void print_mbus_code(__u32 code)
> @@ -566,11 +809,12 @@ static void print_mbus_code(__u32 code)
> printf("\t0x%04x", code);
> }
>
> -static void print_mbus_codes(int fd, __u32 pad)
> +static void print_mbus_codes(int fd, __u32 pad, __u32 stream)
> {
> struct v4l2_subdev_mbus_code_enum mbus_code = {};
>
> mbus_code.pad = pad;
> + mbus_code.stream = stream;
> mbus_code.which = V4L2_SUBDEV_FORMAT_TRY;
>
> for (;;) {
> @@ -623,13 +867,13 @@ void subdev_list(cv4l_fd &_fd)
> int fd = _fd.g_fd();
>
> if (options[OptListSubDevMBusCodes]) {
> - printf("ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE (pad=%u)\n",
> - list_mbus_codes_pad);
> - print_mbus_codes(fd, list_mbus_codes_pad);
> + printf("ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE (pad=%u,stream=%u)\n",
> + list_mbus_codes_pad, list_mbus_codes_stream);
> + print_mbus_codes(fd, list_mbus_codes_pad, list_mbus_codes_stream);
> }
> if (options[OptListSubDevFrameSizes]) {
> - printf("ioctl: VIDIOC_SUBDEV_ENUM_FRAME_SIZE (pad=%u)\n",
> - frmsize.pad);
> + printf("ioctl: VIDIOC_SUBDEV_ENUM_FRAME_SIZE (pad=%u,stream=%u)\n",
> + frmsize.pad, frmsize.stream);
> frmsize.index = 0;
> frmsize.which = V4L2_SUBDEV_FORMAT_TRY;
> while (test_ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &frmsize) >= 0) {
> @@ -638,8 +882,8 @@ void subdev_list(cv4l_fd &_fd)
> }
> }
> if (options[OptListSubDevFrameIntervals]) {
> - printf("ioctl: VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL (pad=%u)\n",
> - frmival.pad);
> + printf("ioctl: VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL (pad=%u,stream=%u)\n",
> + frmival.pad, frmival.stream);
> frmival.index = 0;
> frmival.which = V4L2_SUBDEV_FORMAT_TRY;
> while (test_ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &frmival) >= 0) {
> diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp
> index 8585278f..1cfb50f7 100644
> --- a/utils/v4l2-ctl/v4l2-ctl.cpp
> +++ b/utils/v4l2-ctl/v4l2-ctl.cpp
> @@ -64,6 +64,8 @@ static struct option long_options[] = {
> {"get-fmt-video-out", no_argument, nullptr, OptGetVideoOutFormat},
> {"set-fmt-video-out", required_argument, nullptr, OptSetVideoOutFormat},
> {"try-fmt-video-out", required_argument, nullptr, OptTryVideoOutFormat},
> + {"set-routing", required_argument, 0, OptSetRouting},
> + {"get-routing", no_argument, 0, OptGetRouting},
Maybe get before set as for other options ?
> {"help", no_argument, nullptr, OptHelp},
> {"help-tuner", no_argument, nullptr, OptHelpTuner},
> {"help-io", no_argument, nullptr, OptHelpIO},
> diff --git a/utils/v4l2-ctl/v4l2-ctl.h b/utils/v4l2-ctl/v4l2-ctl.h
> index 8f2726ea..9396c974 100644
> --- a/utils/v4l2-ctl/v4l2-ctl.h
> +++ b/utils/v4l2-ctl/v4l2-ctl.h
> @@ -191,6 +191,8 @@ enum Option {
> OptInfoEdid,
> OptShowEdid,
> OptFixEdidChecksums,
> + OptSetRouting,
> + OptGetRouting,
> OptFreqSeek,
> OptEncoderCmd,
> OptTryEncoderCmd,
--
Regards,
Laurent Pinchart
next prev parent reply other threads:[~2023-04-24 7:05 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-21 12:44 [PATCH v4 0/8] v4l-utils: Support multiplexed streams Tomi Valkeinen
2023-04-21 12:44 ` [PATCH v4 1/8] v4l2-ctl: Add routing and streams support Tomi Valkeinen
2023-04-24 7:04 ` Laurent Pinchart [this message]
2023-05-29 7:02 ` Tomi Valkeinen
2023-05-29 7:47 ` Laurent Pinchart
2023-04-21 12:44 ` [PATCH v4 2/8] media-ctl: Add support for routes and streams Tomi Valkeinen
2023-04-24 7:29 ` Laurent Pinchart
2023-05-29 7:34 ` Tomi Valkeinen
2023-05-29 7:49 ` Laurent Pinchart
2023-05-29 8:14 ` Tomi Valkeinen
2023-04-21 12:44 ` [PATCH v4 3/8] v4l2-ctl/compliance: Add routing and streams multiplexed streams Tomi Valkeinen
2023-04-21 12:44 ` [PATCH v4 4/8] v4l2-ctl/compliance: Add simple routing test Tomi Valkeinen
2023-04-24 8:04 ` Laurent Pinchart
2023-04-21 12:44 ` [PATCH v4 5/8] HACK: include/linux: Add client capabilities Tomi Valkeinen
2023-04-24 7:32 ` Laurent Pinchart
2023-05-25 14:05 ` Hans Verkuil
2023-05-26 8:19 ` Tomi Valkeinen
2023-04-21 12:44 ` [PATCH v4 6/8] media-ctl: Check for Streams API support Tomi Valkeinen
2023-04-24 7:54 ` Laurent Pinchart
2023-04-21 12:44 ` [PATCH v4 7/8] utils/common: Set V4L2_SUBDEV_CLIENT_CAP_STREAMS for subdevs Tomi Valkeinen
2023-04-24 8:01 ` Laurent Pinchart
2023-04-21 12:44 ` [PATCH v4 8/8] v4l2-ctl: Check for Streams API support Tomi Valkeinen
2023-04-24 8:03 ` Laurent Pinchart
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230424070455.GC4926@pendragon.ideasonboard.com \
--to=laurent.pinchart@ideasonboard.com \
--cc=hverkuil-cisco@xs4all.nl \
--cc=jacopo.mondi@ideasonboard.com \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=niklas.soderlund+renesas@ragnatech.se \
--cc=sakari.ailus@linux.intel.com \
--cc=satish.nagireddy@getcruise.com \
--cc=tomi.valkeinen@ideasonboard.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox