From 88daba3d668156f00b45e4fb069fe4cc8a3aa810 Mon Sep 17 00:00:00 2001 From: mglocker Date: Sat, 19 Jul 2008 11:30:55 +0000 Subject: [PATCH] If a resolution which has been requested over VIDEO_TRY_FMT or VIDEO_S_FMT doesn't exactly match the devices available resolutions, return the next best matching resolution which we have. Makes some V4L2 apps happy when running them with the default resolution (no options). --- sys/dev/usb/uvideo.c | 99 +++++++++++++++++++++++--------------------- sys/dev/usb/uvideo.h | 8 +++- 2 files changed, 59 insertions(+), 48 deletions(-) diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c index d464fc92161..2a6e93efc0c 100644 --- a/sys/dev/usb/uvideo.c +++ b/sys/dev/usb/uvideo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvideo.c,v 1.55 2008/07/18 21:45:24 mglocker Exp $ */ +/* $OpenBSD: uvideo.c,v 1.56 2008/07/19 11:30:55 mglocker Exp $ */ /* * Copyright (c) 2008 Robert Nagy @@ -88,6 +88,8 @@ int uvideo_vs_parse_desc_alt(struct uvideo_softc *, int uvideo_vs_set_alt(struct uvideo_softc *, usbd_interface_handle, int); int uvideo_desc_len(const usb_descriptor_t *, int, int, int, int); +int uvideo_find_res(struct uvideo_softc *, int, int, int, + struct uvideo_res *); usbd_status uvideo_vs_negotation(struct uvideo_softc *, int); usbd_status uvideo_vs_set_probe(struct uvideo_softc *, uint8_t *); @@ -932,6 +934,41 @@ uvideo_desc_len(const usb_descriptor_t *desc, return (0); } +/* + * Find the next best matching resolution which we can offer and + * return it. + */ +int +uvideo_find_res(struct uvideo_softc *sc, int idx, int width, int height, + struct uvideo_res *r) +{ + int i, w, h, diff, diff_best, size_want, size_is; + + size_want = width * height; + + for (i = 1; i <= sc->sc_fmtgrp[idx].frame_num; i++) { + w = UGETW(sc->sc_fmtgrp[idx].frame[i]->wWidth); + h = UGETW(sc->sc_fmtgrp[idx].frame[i]->wHeight); + size_is = w * h; + if (size_is > size_want) + diff = size_is - size_want; + else + diff = size_want - size_is; + if (i == 1) + diff_best = diff; + if (diff <= diff_best) { + diff_best = diff; + r->width = w; + r->height = h; + r->fidx = i; + } + DPRINTF(1, "%s: %s: frame index %d: width=%d, height=%d\n", + DEVNAME(sc), __func__, i, w, h); + } + + return (0); +} + usbd_status uvideo_vs_negotation(struct uvideo_softc *sc, int commit) { @@ -2078,7 +2115,8 @@ uvideo_s_fmt(void *v, struct v4l2_format *fmt) struct uvideo_softc *sc = v; struct uvideo_format_group *fmtgrp_save; struct usb_video_frame_mjpeg_desc *frame_save; - int found, i, j, width, height; + struct uvideo_res r; + int found, i; usbd_status error; if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -2098,24 +2136,7 @@ uvideo_s_fmt(void *v, struct v4l2_format *fmt) return (EINVAL); /* search requested frame resolution */ - for (found = 0, j = 1; j <= sc->sc_fmtgrp[i].frame_num; j++) { - width = UGETW(sc->sc_fmtgrp[i].frame[j]->wWidth); - height = UGETW(sc->sc_fmtgrp[i].frame[j]->wHeight); - DPRINTF(1, "%s: %s: frame index %d: width=%d, height=%d\n", - DEVNAME(sc), __func__, j, width, height); - if (fmt->fmt.pix.width == width && - fmt->fmt.pix.height == height) { - found = 1; - break; - } - } - /* - * TODO - * If we don't have exactly the requested resolution we should - * search for the closest matching resolution which we can offer. - */ - if (found == 0) - return (EINVAL); + uvideo_find_res(sc, i, fmt->fmt.pix.width, fmt->fmt.pix.height, &r); /* * Do negotation. @@ -2125,8 +2146,8 @@ uvideo_s_fmt(void *v, struct v4l2_format *fmt) frame_save = sc->sc_fmtgrp_cur->frame_cur; /* set new format group */ sc->sc_fmtgrp_cur = &sc->sc_fmtgrp[i]; - sc->sc_fmtgrp[i].frame_cur = sc->sc_fmtgrp[i].frame[j]; - sc->sc_fmtgrp[i].format_dfidx = j; + sc->sc_fmtgrp[i].frame_cur = sc->sc_fmtgrp[i].frame[r.fidx]; + sc->sc_fmtgrp[i].format_dfidx = r.fidx; /* do device negotation with commit */ error = uvideo_vs_negotation(sc, 1); if (error != USBD_NORMAL_COMPLETION) { @@ -2137,11 +2158,11 @@ uvideo_s_fmt(void *v, struct v4l2_format *fmt) sc->sc_negotiated_flag = 1; /* offer closest resolution which we have found */ - fmt->fmt.pix.width = width; - fmt->fmt.pix.height = height; + fmt->fmt.pix.width = r.width; + fmt->fmt.pix.height = r.height; DPRINTF(1, "%s: %s: offered width=%d, height=%d\n", - DEVNAME(sc), __func__, width, height); + DEVNAME(sc), __func__, r.width, r.height); /* tell our sample buffer size */ fmt->fmt.pix.sizeimage = sc->sc_sample_buffer.buf_size; @@ -2323,7 +2344,8 @@ int uvideo_try_fmt(void *v, struct v4l2_format *fmt) { struct uvideo_softc *sc = v; - int found, i, j, width, height; + struct uvideo_res r; + int found, i; if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return (EINVAL); @@ -2342,31 +2364,14 @@ uvideo_try_fmt(void *v, struct v4l2_format *fmt) return (EINVAL); /* search requested frame resolution */ - for (found = 0, j = 1; j <= sc->sc_fmtgrp[i].frame_num; j++) { - width = UGETW(sc->sc_fmtgrp[i].frame[j]->wWidth); - height = UGETW(sc->sc_fmtgrp[i].frame[j]->wHeight); - DPRINTF(1, "%s: %s: frame index %d: width=%d, height=%d\n", - DEVNAME(sc), __func__, j, width, height); - if (fmt->fmt.pix.width == width && - fmt->fmt.pix.height == height) { - found = 1; - break; - } - } - /* - * TODO - * If we don't have exactly the requested resolution we should - * search for the closest matching resolution which we can offer. - */ - if (found == 0) - return (EINVAL); + uvideo_find_res(sc, i, fmt->fmt.pix.width, fmt->fmt.pix.height, &r); /* offer closest resolution which we have found */ - fmt->fmt.pix.width = width; - fmt->fmt.pix.height = height; + fmt->fmt.pix.width = r.width; + fmt->fmt.pix.height = r.height; DPRINTF(1, "%s: %s: offered width=%d, height=%d\n", - DEVNAME(sc), __func__, width, height); + DEVNAME(sc), __func__, r.width, r.height); /* tell our sample buffer size */ fmt->fmt.pix.sizeimage = sc->sc_sample_buffer.buf_size; diff --git a/sys/dev/usb/uvideo.h b/sys/dev/usb/uvideo.h index 0f5eebccec2..39fe01f12e2 100644 --- a/sys/dev/usb/uvideo.h +++ b/sys/dev/usb/uvideo.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvideo.h,v 1.22 2008/07/18 18:49:11 mglocker Exp $ */ +/* $OpenBSD: uvideo.h,v 1.23 2008/07/19 11:30:55 mglocker Exp $ */ /* * Copyright (c) 2007 Robert Nagy @@ -447,6 +447,12 @@ struct uvideo_format_group { struct usb_video_frame_mjpeg_desc *frame[UVIDEO_MAX_FRAME]; } __packed; +struct uvideo_res { + int width; + int height; + int fidx; +} __packed; + struct uvideo_softc { struct device sc_dev; usbd_device_handle sc_udev; -- 2.20.1