Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 09 Aug 2026 17:01:44 +0000
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Cc:        Abdelkader Boudih <freebsd@seuros.com>
Subject:   git: 33fd5d168d32 - main - uvideo: do not reject unsupported pixel formats
Message-ID:  <6a78b278.3b176.4fdc42cf@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by adrian:

URL: https://cgit.FreeBSD.org/src/commit/?id=33fd5d168d329f861e679a50c4b2431334bfcaf7

commit 33fd5d168d329f861e679a50c4b2431334bfcaf7
Author:     Abdelkader Boudih <freebsd@seuros.com>
AuthorDate: 2026-08-09 16:59:44 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-08-09 16:59:46 +0000

    uvideo: do not reject unsupported pixel formats
    
    Reviewed by:    adrian, bapt
    Differential Revision:  https://reviews.freebsd.org/D58503
---
 sys/dev/usb/video/uvideo.c | 90 ++++++++++++++++++++++++++++++++++------------
 1 file changed, 67 insertions(+), 23 deletions(-)

diff --git a/sys/dev/usb/video/uvideo.c b/sys/dev/usb/video/uvideo.c
index 1e19ab42d869..e682f0ae6952 100644
--- a/sys/dev/usb/video/uvideo.c
+++ b/sys/dev/usb/video/uvideo.c
@@ -150,6 +150,9 @@ static int	uvideo_hw_querycap(device_t, struct video_caps *);
 static int	uvideo_hw_enum_format(device_t, uint32_t, struct video_format *);
 static int	uvideo_hw_get_format(device_t, struct video_format *);
 static int	uvideo_hw_try_format(device_t, struct video_format *);
+static int	uvideo_select_fmtgrp(struct uvideo_softc *, uint32_t);
+static uint32_t	uvideo_bytesperline(struct uvideo_format_group *, uint32_t);
+static uint32_t	uvideo_frame_sizeimage(struct usb_video_frame_desc *);
 static int	uvideo_hw_set_format(device_t, const struct video_format *);
 static int	uvideo_hw_enum_framesizes(device_t, struct video_frmsizeenum *);
 static int	uvideo_hw_enum_frameintervals(device_t,
@@ -2754,6 +2757,8 @@ uvideo_hw_get_format(device_t dev, struct video_format *fmt)
 	if (frame != NULL) {
 		fmt->width = UGETW(UVIDEO_FRAME_FIELD(frame, wWidth));
 		fmt->height = UGETW(UVIDEO_FRAME_FIELD(frame, wHeight));
+		fmt->bytesperline = uvideo_bytesperline(sc->sc_fmtgrp_cur,
+		    fmt->width);
 	}
 	fmt->sizeimage = UGETDW(sc->sc_desc_probe.dwMaxVideoFrameSize);
 
@@ -2766,31 +2771,78 @@ uvideo_hw_get_format(device_t dev, struct video_format *fmt)
 	return (0);
 }
 
+/*
+ * VIDIOC_TRY_FMT and VIDIOC_S_FMT must not fail on an unsupported
+ * pixel format; they substitute one the device does support.
+ */
+static int
+uvideo_select_fmtgrp(struct uvideo_softc *sc, uint32_t pixelformat)
+{
+	int i;
+
+	for (i = 0; i < sc->sc_fmtgrp_num; i++) {
+		if (pixelformat == sc->sc_fmtgrp[i].pixelformat)
+			return (i);
+	}
+	if (sc->sc_fmtgrp_cur != NULL)
+		return (sc->sc_fmtgrp_cur - sc->sc_fmtgrp);
+	return (0);
+}
+
+static uint32_t
+uvideo_bytesperline(struct uvideo_format_group *fmtgrp, uint32_t width)
+{
+	uint8_t bpp;
+
+	switch (fmtgrp->format->bDescriptorSubtype) {
+	case UDESCSUB_VS_FORMAT_UNCOMPRESSED:
+		bpp = fmtgrp->format->u.uc.bBitsPerPixel;
+		break;
+	case UDESCSUB_VS_FORMAT_FRAME_BASED:
+		bpp = fmtgrp->format->u.fb.bBitsPerPixel;
+		break;
+	default:
+		return (0);	/* compressed */
+	}
+	return (width * bpp / 8);
+}
+
+static uint32_t
+uvideo_frame_sizeimage(struct usb_video_frame_desc *frame)
+{
+
+	switch (frame->bDescriptorSubtype) {
+	case UDESCSUB_VS_FRAME_UNCOMPRESSED:
+	case UDESCSUB_VS_FRAME_MJPEG:
+		return (UGETDW(frame->u.uc.dwMaxVideoFrameBufferSize));
+	default:
+		return (0);
+	}
+}
+
 static int
 uvideo_hw_try_format(device_t dev, struct video_format *fmt)
 {
 	struct uvideo_softc *sc = device_get_softc(dev);
+	struct usb_video_frame_desc *frame;
 	struct uvideo_res r;
-	int found, i;
-
-	for (found = 0, i = 0; i < sc->sc_fmtgrp_num; i++) {
-		if (fmt->pixelformat == sc->sc_fmtgrp[i].pixelformat) {
-			found = 1;
-			break;
-		}
-	}
-	if (found == 0)
-		return (EINVAL);
+	int i;
 
-	if (sc->sc_fmtgrp[i].frame_num == 0)
+	i = uvideo_select_fmtgrp(sc, fmt->pixelformat);
+	if (i >= sc->sc_fmtgrp_num || sc->sc_fmtgrp[i].frame_num == 0)
 		return (EINVAL);
 
 	uvideo_find_res(sc, i, fmt->width, fmt->height, &r);
+	frame = sc->sc_fmtgrp[i].frame[r.fidx];
 
+	fmt->pixelformat = sc->sc_fmtgrp[i].pixelformat;
 	fmt->width = r.width;
 	fmt->height = r.height;
 	fmt->field = V4L2_FIELD_NONE;
-	fmt->sizeimage = UGETDW(sc->sc_desc_probe.dwMaxVideoFrameSize);
+	fmt->bytesperline = uvideo_bytesperline(&sc->sc_fmtgrp[i], r.width);
+	fmt->sizeimage = uvideo_frame_sizeimage(frame);
+	if (fmt->sizeimage == 0)
+		fmt->sizeimage = UGETDW(sc->sc_desc_probe.dwMaxVideoFrameSize);
 
 	if (sc->sc_fmtgrp[i].has_colorformat) {
 		fmt->colorspace = sc->sc_fmtgrp[i].colorspace;
@@ -2808,19 +2860,11 @@ uvideo_hw_set_format(device_t dev, const struct video_format *fmt)
 	struct uvideo_format_group *fmtgrp_save;
 	struct usb_video_frame_desc *frame_save;
 	struct uvideo_res r;
-	int found, i;
+	int i;
 	usb_error_t error;
 
-	for (found = 0, i = 0; i < sc->sc_fmtgrp_num; i++) {
-		if (fmt->pixelformat == sc->sc_fmtgrp[i].pixelformat) {
-			found = 1;
-			break;
-		}
-	}
-	if (found == 0)
-		return (EINVAL);
-
-	if (sc->sc_fmtgrp[i].frame_num == 0)
+	i = uvideo_select_fmtgrp(sc, fmt->pixelformat);
+	if (i >= sc->sc_fmtgrp_num || sc->sc_fmtgrp[i].frame_num == 0)
 		return (EINVAL);
 
 	uvideo_find_res(sc, i, fmt->width, fmt->height, &r);


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a78b278.3b176.4fdc42cf>