/* Is conversion necessary ? */ int v4lconvert_needs_conversion(struct v4lconvert_data *data, const struct v4l2_format *src_fmt, /* in */ const struct v4l2_format *dest_fmt) /* in */ { if (src_fmt->fmt.pix.width != dest_fmt->fmt.pix.width || src_fmt->fmt.pix.height != dest_fmt->fmt.pix.height || src_fmt->fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat || (v4lcontrol_needs_conversion(data->control) && v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat))) return 1; return 0; }
struct v4lcontrol_data *v4lcontrol_create(int fd, void *dev_ops_priv, const struct libv4l_dev_ops *dev_ops, int always_needs_conversion) { int shm_fd; 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; struct passwd pwd, *pwd_p; unsigned short vendor_id = 0; unsigned short product_id = 0; struct v4l2_input input; struct v4lcontrol_data *data = calloc(1, sizeof(struct v4lcontrol_data)); if (!data) { fprintf(stderr, "libv4lcontrol: error: out of memory!\n"); return NULL; } data->fd = fd; data->dev_ops = dev_ops; data->dev_ops_priv = dev_ops_priv; /* Check if the driver has indicated some form of flipping is needed */ if ((data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_G_INPUT, &input.index) == 0) && (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_ENUMINPUT, &input) == 0)) { if (input.status & V4L2_IN_ST_HFLIP) data->flags |= V4LCONTROL_HFLIPPED; if (input.status & V4L2_IN_ST_VFLIP) data->flags |= V4LCONTROL_VFLIPPED; } s = getenv("LIBV4LCONTROL_SYSFS_PREFIX"); if (!s) s = ""; got_usb_info = v4lcontrol_get_usb_info(data, s, &vendor_id, &product_id, &speed); if (got_usb_info) { v4lcontrol_get_flags_from_db(data, s, 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"); if (s) data->flags = strtol(s, NULL, 0); ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; if (data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_QUERYCTRL, &ctrl) == 0) data->priv_flags |= V4LCONTROL_SUPPORTS_NEXT_CTRL; /* If the device always needs conversion, we can add fake controls at no cost (no cost when not activated by the user that is) */ if (always_needs_conversion || v4lcontrol_needs_conversion(data)) { for (i = 0; i < V4LCONTROL_AUTO_ENABLE_COUNT; i++) { ctrl.id = fake_controls[i].id; rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_QUERYCTRL, &ctrl); if (rc == -1 || (rc == 0 && (ctrl.flags & V4L2_CTRL_FLAG_DISABLED))) data->controls |= 1 << i; } } /* Check if a camera does not have hardware autogain and has the necessary controls, before enabling sw autogain, even if this is requested by flags. This is necessary because some cameras share a USB-ID, but can have different sensors with / without autogain or the necessary controls. */ while (data->flags & V4LCONTROL_WANTS_AUTOGAIN) { ctrl.id = V4L2_CID_AUTOGAIN; rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_QUERYCTRL, &ctrl); if (rc == 0 && !(ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) break; ctrl.id = V4L2_CID_EXPOSURE; rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_QUERYCTRL, &ctrl); if (rc != 0 || (ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) break; ctrl.id = V4L2_CID_GAIN; rc = data->dev_ops->ioctl(data->dev_ops_priv, data->fd, VIDIOC_QUERYCTRL, &ctrl); if (rc != 0 || (ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) break; data->controls |= 1 << V4LCONTROL_AUTOGAIN | 1 << V4LCONTROL_AUTOGAIN_TARGET; break; } /* Allow overriding through environment */ s = getenv("LIBV4LCONTROL_CONTROLS"); if (s) data->controls = strtol(s, NULL, 0); if (data->controls == 0) return data; /* No need to create a shared memory segment */ if (data->dev_ops->ioctl(data->dev_ops_priv, fd, VIDIOC_QUERYCAP, &cap)) { perror("libv4lcontrol: error querying device capabilities"); goto error; } if (getpwuid_r(geteuid(), &pwd, pwd_buf, sizeof(pwd_buf), &pwd_p) == 0) { 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 snprintf(shm_name, 256, "/libv4l-%s:%s:%s", pwd.pw_name, cap.bus_info, cap.card); } else { perror("libv4lcontrol: error getting username using uid instead"); 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); else snprintf(shm_name, 256, "/libv4l-%lu:%s:%s", (unsigned long)geteuid(), cap.bus_info, cap.card); } /* / is not allowed inside shm names */ for (i = 1; shm_name[i]; i++) if (shm_name[i] == '/') shm_name[i] = '-'; #ifndef ANDROID /* Open the shared memory object identified by shm_name */ shm_fd = shm_open(shm_name, (O_CREAT | O_EXCL | O_RDWR), (S_IREAD | S_IWRITE)); if (shm_fd >= 0) init = 1; else shm_fd = shm_open(shm_name, O_RDWR, (S_IREAD | S_IWRITE)); if (shm_fd >= 0) { /* Set the shared memory size */ ftruncate(shm_fd, V4LCONTROL_SHM_SIZE); /* Retreive a pointer to the shm object */ data->shm_values = mmap(NULL, V4LCONTROL_SHM_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, shm_fd, 0); close(shm_fd); if (data->shm_values == MAP_FAILED) { perror("libv4lcontrol: error shm mmap failed"); data->shm_values = NULL; } } else perror("libv4lcontrol: error creating shm segment failed"); #endif /* Fall back to malloc */ if (data->shm_values == NULL) { fprintf(stderr, "libv4lcontrol: falling back to malloc-ed memory for controls\n"); data->shm_values = malloc(V4LCONTROL_SHM_SIZE); if (!data->shm_values) { fprintf(stderr, "libv4lcontrol: error: out of memory!\n"); goto error; } init = 1; data->priv_flags |= V4LCONTROL_MEMORY_IS_MALLOCED; } if (init) { /* Initialize the new shm object we created */ memset(data->shm_values, 0, V4LCONTROL_SHM_SIZE); for (i = 0; i < V4LCONTROL_COUNT; i++) data->shm_values[i] = fake_controls[i].default_value; if (data->flags & V4LCONTROL_WANTS_WB) data->shm_values[V4LCONTROL_WHITEBALANCE] = 1; if (data->flags_info && data->flags_info->default_gamma) data->shm_values[V4LCONTROL_GAMMA] = data->flags_info->default_gamma; } return data; error: free(data); return NULL; }
int v4lconvert_supported_dst_fmt_only(struct v4lconvert_data *data) { return v4lcontrol_needs_conversion(data->control) && data->supported_src_formats; }