From ced2a9337bd3fdf8553cbcc77860b892e40e4d7c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 11 May 2011 21:23:23 +0200 Subject: [PATCH] libv4l: detect (usb) connection speed And use it for determining the optimal source format. Signed-off-by: Hans de Goede --- lib/libv4lconvert/control/libv4lcontrol-priv.h | 1 + lib/libv4lconvert/control/libv4lcontrol.c | 77 ++++++++++++++++++++------ lib/libv4lconvert/control/libv4lcontrol.h | 2 + lib/libv4lconvert/libv4lconvert.c | 5 +- 4 files changed, 64 insertions(+), 21 deletions(-) diff --git a/lib/libv4lconvert/control/libv4lcontrol-priv.h b/lib/libv4lconvert/control/libv4lcontrol-priv.h index 22cdf34..2807c3a 100644 --- a/lib/libv4lconvert/control/libv4lcontrol-priv.h +++ b/lib/libv4lconvert/control/libv4lcontrol-priv.h @@ -31,6 +31,7 @@ struct v4lcontrol_flags_info; struct v4lcontrol_data { int fd; /* Device fd */ + int bandwidth; /* Connection bandwidth (0 = unknown) */ int flags; /* Flags for this device */ int priv_flags; /* Internal use only flags */ int controls; /* Which controls to use for this device */ diff --git a/lib/libv4lconvert/control/libv4lcontrol.c b/lib/libv4lconvert/control/libv4lcontrol.c index 6b3be9b..2b7a33b 100644 --- a/lib/libv4lconvert/control/libv4lcontrol.c +++ b/lib/libv4lconvert/control/libv4lcontrol.c @@ -627,8 +627,9 @@ static void v4lcontrol_get_dmi_string(const char *string, char *buf, int size) fclose(f); } -static int v4lcontrol_get_usb_ids(struct v4lcontrol_data *data, - unsigned short *vendor_id, unsigned short *product_id) +static int v4lcontrol_get_usb_info(struct v4lcontrol_data *data, + unsigned short *vendor_id, unsigned short *product_id, + int *speed) { FILE *f; int i, minor; @@ -642,7 +643,7 @@ static int v4lcontrol_get_usb_ids(struct v4lcontrol_data *data, /* find ourselve in sysfs */ for (i = 0; i < 256; i++) { snprintf(sysfs_name, sizeof(sysfs_name), - "/sys/class/video4linux/video%d/dev", i); + "/sys/class/video4linux/video%d/dev", i); f = fopen(sysfs_name, "r"); if (!f) continue; @@ -650,8 +651,8 @@ static int v4lcontrol_get_usb_ids(struct v4lcontrol_data *data, s = fgets(buf, sizeof(buf), f); fclose(f); - if (s && sscanf(buf, "%*d:%d%c", &minor, &c) == 2 && c == '\n' && - minor == minor(st.st_rdev)) + if (s && sscanf(buf, "%*d:%d%c", &minor, &c) == 2 && + c == '\n' && minor == minor(st.st_rdev)) break; } if (i == 256) @@ -659,23 +660,26 @@ static int v4lcontrol_get_usb_ids(struct v4lcontrol_data *data, /* Get vendor and product ID */ snprintf(sysfs_name, sizeof(sysfs_name), - "/sys/class/video4linux/video%d/device/modalias", i); + "/sys/class/video4linux/video%d/device/modalias", i); f = fopen(sysfs_name, "r"); if (f) { s = fgets(buf, sizeof(buf), f); fclose(f); - if (!s || sscanf(s, "usb:v%4hxp%4hx%c", vendor_id, product_id, &c) != 3 || - c != 'd') + if (!s || sscanf(s, "usb:v%4hxp%4hx%c", vendor_id, product_id, + &c) != 3 || c != 'd') return 0; /* Not an USB device */ + + snprintf(sysfs_name, sizeof(sysfs_name), + "/sys/class/video4linux/video%d/device/../speed", i); } else { /* Try again assuming the device link points to the usb device instead of the usb interface (bug in older versions of gspca) */ - /* Get product ID */ + /* Get vendor ID */ snprintf(sysfs_name, sizeof(sysfs_name), - "/sys/class/video4linux/video%d/device/idVendor", i); + "/sys/class/video4linux/video%d/device/idVendor", i); f = fopen(sysfs_name, "r"); if (!f) return 0; /* Not an USB device (or no sysfs) */ @@ -683,12 +687,13 @@ static int v4lcontrol_get_usb_ids(struct v4lcontrol_data *data, s = fgets(buf, sizeof(buf), f); fclose(f); - if (!s || sscanf(s, "%04hx%c", vendor_id, &c) != 2 || c != '\n') + if (!s || sscanf(s, "%04hx%c", vendor_id, &c) != 2 || + c != '\n') return 0; /* Should never happen */ /* Get product ID */ snprintf(sysfs_name, sizeof(sysfs_name), - "/sys/class/video4linux/video%d/device/idProduct", i); + "/sys/class/video4linux/video%d/device/idProduct", i); f = fopen(sysfs_name, "r"); if (!f) return 0; /* Should never happen */ @@ -696,10 +701,24 @@ static int v4lcontrol_get_usb_ids(struct v4lcontrol_data *data, s = fgets(buf, sizeof(buf), f); fclose(f); - if (!s || sscanf(s, "%04hx%c", product_id, &c) != 2 || c != '\n') + if (!s || sscanf(s, "%04hx%c", product_id, &c) != 2 || + c != '\n') return 0; /* Should never happen */ + + snprintf(sysfs_name, sizeof(sysfs_name), + "/sys/class/video4linux/video%d/device/speed", i); } + f = fopen(sysfs_name, "r"); + if (!f) + return 0; /* Should never happen */ + + s = fgets(buf, sizeof(buf), f); + fclose(f); + + if (!s || sscanf(s, "%d%c", speed, &c) != 2 || (c != '\n' && c != '.')) + return 0; /* Should never happen */ + return 1; } @@ -752,7 +771,7 @@ static void v4lcontrol_get_flags_from_db(struct v4lcontrol_data *data, struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) { int shm_fd; - int i, rc, got_usb_ids, init = 0; + int i, rc, got_usb_info, speed, init = 0; char *s, shm_name[256], pwd_buf[1024]; struct v4l2_capability cap; struct v4l2_queryctrl ctrl; @@ -779,9 +798,26 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) data->flags |= V4LCONTROL_VFLIPPED; } - got_usb_ids = v4lcontrol_get_usb_ids(data, &vendor_id, &product_id); - if (got_usb_ids) + got_usb_info = v4lcontrol_get_usb_info(data, &vendor_id, &product_id, + &speed); + if (got_usb_info) { v4lcontrol_get_flags_from_db(data, vendor_id, product_id); + switch (speed) { + case 12: + data->bandwidth = 1023 * 1000; + break; + case 480: + data->bandwidth = 3 * 1024 * 8000; + break; + case 5000: + data->bandwidth = 48 * 1024 * 8000; + break; + default: + /* heuh, low speed device, or ... ? */ + data->bandwidth = speed / 20; + } + } else + data->bandwidth = 0; /* Allow overriding through environment */ s = getenv("LIBV4LCONTROL_FLAGS"); @@ -842,7 +878,7 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) } if (getpwuid_r(geteuid(), &pwd, pwd_buf, sizeof(pwd_buf), &pwd_p) == 0) { - if (got_usb_ids) + if (got_usb_info) snprintf(shm_name, 256, "/libv4l-%s:%s:%04x:%04x:%s", pwd.pw_name, cap.bus_info, (int)vendor_id, (int)product_id, cap.card); else @@ -850,7 +886,7 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion) cap.bus_info, cap.card); } else { perror("libv4lcontrol: error getting username using uid instead"); - if (got_usb_ids) + if (got_usb_info) snprintf(shm_name, 256, "/libv4l-%lu:%s:%04x:%04x:%s", (unsigned long)geteuid(), cap.bus_info, (int)vendor_id, (int)product_id, cap.card); @@ -1083,6 +1119,11 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg) return SYS_IOCTL(data->fd, VIDIOC_S_CTRL, arg); } +int v4lcontrol_get_bandwidth(struct v4lcontrol_data *data) +{ + return data->bandwidth; +} + int v4lcontrol_get_flags(struct v4lcontrol_data *data) { return data->flags; diff --git a/lib/libv4lconvert/control/libv4lcontrol.h b/lib/libv4lconvert/control/libv4lcontrol.h index 974e97a..2543011 100644 --- a/lib/libv4lconvert/control/libv4lcontrol.h +++ b/lib/libv4lconvert/control/libv4lcontrol.h @@ -50,6 +50,8 @@ struct v4lcontrol_data; struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion); void v4lcontrol_destroy(struct v4lcontrol_data *data); +int v4lcontrol_get_bandwidth(struct v4lcontrol_data *data); + /* Functions used by v4lprocessing to get the control state */ int v4lcontrol_get_flags(struct v4lcontrol_data *data); int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl); diff --git a/lib/libv4lconvert/libv4lconvert.c b/lib/libv4lconvert/libv4lconvert.c index 7caa758..1a5f0be 100644 --- a/lib/libv4lconvert/libv4lconvert.c +++ b/lib/libv4lconvert/libv4lconvert.c @@ -117,8 +117,6 @@ struct v4lconvert_data *v4lconvert_create(int fd) data->fd = fd; data->decompress_pid = -1; - /* Default to usb 2 bandwidth and 30 fps for now */ - data->bandwidth = 3 * 1024 * 8000; /* 3 * 1024 byte packets * 8000 microframes */ data->fps = 30; /* Check supported formats */ @@ -160,6 +158,7 @@ struct v4lconvert_data *v4lconvert_create(int fd) return NULL; } data->control_flags = v4lcontrol_get_flags(data->control); + data->bandwidth = v4lcontrol_get_bandwidth(data->control); data->processing = v4lprocessing_create(fd, data->control); if (!data->processing) { @@ -287,7 +286,7 @@ static int v4lconvert_get_rank(struct v4lconvert_data *data, /* check bandwidth needed */ needed = src_width * src_height * data->fps * supported_src_pixfmts[src_index].bpp / 8; - if (needed > data->bandwidth) + if (data->bandwidth && needed > data->bandwidth) rank += 10; #if 0 printf("ranked: %c%c%c%c for %dx%d @ %d fps, needed: %d, bandwidth: %d, rank: %d\n", -- 2.7.4