diff options
author | hans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain> | 2009-04-14 15:03:07 +0200 |
---|---|---|
committer | hans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain> | 2009-04-14 15:03:07 +0200 |
commit | 58d3334b54c207b8e04e7035969e0c2acfa1ce73 (patch) | |
tree | 79bfcb91241d0468871696b189ac8ee344ea1ed0 | |
parent | 10a09b9ec6e08fb95c36f26d7f69834b0387386b (diff) | |
download | mediapointer-dvb-s2-58d3334b54c207b8e04e7035969e0c2acfa1ce73.tar.gz mediapointer-dvb-s2-58d3334b54c207b8e04e7035969e0c2acfa1ce73.tar.bz2 |
libv4l: Only allow supported destination formats when doing processing
From: Hans de Goede <hdegoede@redhat.com>
Only report / allow supported destination formats in enum_fmt / try_fmt /
g_fmt / s_fmt when processing, rotating or flipping.
Priority: normal
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r-- | v4l2-apps/libv4l/ChangeLog | 8 | ||||
-rw-r--r-- | v4l2-apps/libv4l/TODO | 14 | ||||
-rw-r--r-- | v4l2-apps/libv4l/include/libv4lconvert.h | 21 | ||||
-rw-r--r-- | v4l2-apps/libv4l/libv4l1/libv4l1.c | 17 | ||||
-rw-r--r-- | v4l2-apps/libv4l/libv4l2/libv4l2.c | 8 | ||||
-rw-r--r-- | v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c | 5 | ||||
-rw-r--r-- | v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h | 5 | ||||
-rw-r--r-- | v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c | 91 |
8 files changed, 127 insertions, 42 deletions
diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog index 52b429687..3a7d3f3a8 100644 --- a/v4l2-apps/libv4l/ChangeLog +++ b/v4l2-apps/libv4l/ChangeLog @@ -8,6 +8,14 @@ libv4l-0.5.97 for example v4l2ucp is there. The initial version of this code was written by 3 of my computer science students: Elmar Kleijn, Sjoerd Piepenbrink and Radjnies Bhansingh +* Currently whitebalancing gets enabled based on USB-ID's and it only gets + enabled for Pixart webcam's. You can force it being enabled with other + webcams by setting the environment variable LIBV4LCONTROL_CONTROLS, this + sets a bitmask enabling certain v4l2 controls which control the video + processing set it to 15 to enable both whitebalancing and normalize. You + can then change the settings using a v4l2 control panel like v4l2ucp +* Only report / allow supported destination formats in enum_fmt / try_fmt / + g_fmt / s_fmt when processing, rotating or flipping. * Add dependency generation to libv4l by: Gilles Gigan <gilles.gigan@gmail.com> * Add support to use orientation from VIDIOC_ENUMINPUT by: Adam Baker <linux@baker-net.org.uk> diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO index f1aac5a95..94c40b84e 100644 --- a/v4l2-apps/libv4l/TODO +++ b/v4l2-apps/libv4l/TODO @@ -10,11 +10,19 @@ -take the possibility of pitch != width into account everywhere --only report faked formats in list formats and only allow setting fake - formats when processing or flipping. - -make updating of parameters happen based on time elapsed rather then frames -add fake flip controls on devices where we are already limiting the formats which can be set + +-add reverse cropping (adding black borders) to get from 320x232 -> + 320x240, for zc3xx webcams with a broken (last row of jpeg blocks missing) + 320x240 mode + +-add software auto exposure (for spca561 cams) + +-change video processing to use a per component lookup table for easy combining of + of different effects in 1 pass + +-add gamma correction video processing diff --git a/v4l2-apps/libv4l/include/libv4lconvert.h b/v4l2-apps/libv4l/include/libv4lconvert.h index fcc31dace..7901b35dc 100644 --- a/v4l2-apps/libv4l/include/libv4lconvert.h +++ b/v4l2-apps/libv4l/include/libv4lconvert.h @@ -42,18 +42,30 @@ struct v4lconvert_data; LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd); LIBV4L_PUBLIC void v4lconvert_destroy(struct v4lconvert_data *data); +/* When doing flipping / rotating / video-processing, only supported + destination formats can be used (as flipping / rotating / video-processing + is not supported on other formats). This function can be used to query + if that is the case. */ +LIBV4L_PUBLIC int v4lconvert_supported_dst_fmt_only( + struct v4lconvert_data *data); + /* With regards to dest_fmt just like VIDIOC_TRY_FMT, except that the try format will succeed and return the requested V4L2_PIX_FMT_foo in dest_fmt if the cam has a format from which v4lconvert can convert to dest_fmt. The real format to which the cam should be set is returned through src_fmt - when not NULL. */ + when not NULL. + Note that just like the real VIDIOC_TRY_FMT this function will change the + dest_fmt when not supported. This includes changing it to a supported + destination format when trying a native format of the camera and + v4lconvert_supported_dst_fmt_only() returns true. */ LIBV4L_PUBLIC int v4lconvert_try_format(struct v4lconvert_data *data, struct v4l2_format *dest_fmt, /* in / out */ struct v4l2_format *src_fmt /* out */ ); -/* Just like VIDIOC_ENUM_FMT, except that the emulated formats are added at - the end of the list */ +/* Like VIDIOC_ENUM_FMT, but the emulated formats are added at the end of the + list, except if flipping / processing is active for the device, then only + supported destination formats are listed */ LIBV4L_PUBLIC int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt); /* Is conversion necessary or can the app use the data directly? */ @@ -89,6 +101,9 @@ LIBV4L_PUBLIC int v4lconvert_vidioc_g_ctrl(struct v4lconvert_data *data, LIBV4L_PUBLIC int v4lconvert_vidioc_s_ctrl(struct v4lconvert_data *data, void *arg); +/* Is the passed in pixelformat supported as destination format ? */ +LIBV4L_PUBLIC int v4lconvert_supported_dst_format(unsigned int pixelformat); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/v4l2-apps/libv4l/libv4l1/libv4l1.c b/v4l2-apps/libv4l/libv4l1/libv4l1.c index 797c8768a..a7de0af8e 100644 --- a/v4l2-apps/libv4l/libv4l1/libv4l1.c +++ b/v4l2-apps/libv4l/libv4l1/libv4l1.c @@ -155,8 +155,10 @@ static int v4l1_set_format(int index, unsigned int width, /* Do we need to change the resolution / format ? */ if (width == devices[index].width && height == devices[index].height && - v4l2_pixfmt == devices[index].v4l2_pixfmt) + v4l2_pixfmt == devices[index].v4l2_pixfmt) { + devices[index].v4l1_pal = v4l1_pal; return 0; + } /* Get current settings, apply our changes and try the new setting */ if ((result = v4l2_ioctl(devices[index].fd, VIDIOC_G_FMT, &fmt2))) { @@ -308,19 +310,18 @@ int v4l1_open (const char *file, int oflag, ...) if (!v4l2_log_file) v4l2_log_file = v4l1_log_file; - /* Get initial width, height and pixelformat */ - fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (syscall(SYS_ioctl, fd, VIDIOC_G_FMT, &fmt2)) { + /* Register with libv4l2, as we use that todo format conversion and read() + emulation for us */ + if (v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION) == -1) { int saved_err = errno; - V4L1_LOG_ERR("getting pixformat: %s\n", strerror(errno)); syscall(SYS_close, fd); errno = saved_err; return -1; } - /* Register with libv4l2, as we use that todo format conversion and read() - emulation for us */ - if (v4l2_fd_open(fd, V4L2_ENABLE_ENUM_FMT_EMULATION) == -1) { + /* Get initial width, height and pixelformat */ + fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (v4l2_ioctl(fd, VIDIOC_G_FMT, &fmt2)) { int saved_err = errno; syscall(SYS_close, fd); errno = saved_err; diff --git a/v4l2-apps/libv4l/libv4l2/libv4l2.c b/v4l2-apps/libv4l/libv4l2/libv4l2.c index 91e0193ee..8d01b034c 100644 --- a/v4l2-apps/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/libv4l/libv4l2/libv4l2.c @@ -516,6 +516,14 @@ int v4l2_fd_open(int fd, int v4l2_flags) V4L2_LOG("open: %d\n", fd); + if (v4lconvert_supported_dst_fmt_only(convert) && + !v4lconvert_supported_dst_format(fmt.fmt.pix.pixelformat)) { + V4L2_LOG("open %d: setting pixelformat to RGB24\n", fd); + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; + v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt); + V4L2_LOG("open %d: done setting pixelformat\n", fd); + } + return fd; } diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c index de8b608f9..b09ffc582 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c @@ -339,3 +339,8 @@ int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl) return 0; } + +/* See the comment about this in libv4lconvert.h */ +int v4lcontrol_needs_conversion(struct v4lcontrol_data *data) { + return data->flags || data->controls; +} diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h index 344e68055..28308bc55 100644 --- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h +++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h @@ -39,6 +39,11 @@ void v4lcontrol_destroy(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); +/* Check if we must go through the conversion path (and thus alloc conversion + buffers, etc. in libv4l2). Note this always return 1 if we *may* need + rotate90 / flipping / processing, as if we actually need this may change + on the fly while the stream is active. */ +int v4lcontrol_needs_conversion(struct v4lcontrol_data *data); /* Functions used by v4lconvert to pass vidioc calls from libv4l2 */ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg); diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c index 5ec85324e..2e029a81c 100644 --- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c @@ -155,7 +155,7 @@ void v4lconvert_destroy(struct v4lconvert_data *data) free(data); } -static int v4lconvert_supported_dst_format(unsigned int pixelformat) +int v4lconvert_supported_dst_format(unsigned int pixelformat) { int i; @@ -166,6 +166,12 @@ static int v4lconvert_supported_dst_format(unsigned int pixelformat) return i != ARRAY_SIZE(supported_dst_pixfmts); } +int v4lconvert_supported_dst_fmt_only(struct v4lconvert_data *data) +{ + return v4lcontrol_needs_conversion(data->control) && + data->supported_src_formats; +} + /* See libv4lconvert.h for description of in / out parameters */ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt) { @@ -173,17 +179,22 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt) unsigned int faked_fmts[ARRAY_SIZE(supported_dst_pixfmts)]; if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - fmt->index < data->no_formats || - !data->supported_src_formats) + (!v4lconvert_supported_dst_fmt_only(data) && + fmt->index < data->no_formats)) return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FMT, fmt); for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) - if (!(data->supported_src_formats & (1 << i))) { + if (v4lconvert_supported_dst_fmt_only(data) || + !(data->supported_src_formats & (1 << i))) { faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i].fmt; no_faked_fmts++; } - i = fmt->index - data->no_formats; + if (!v4lconvert_supported_dst_fmt_only(data)) + i = fmt->index - data->no_formats; + else + i = fmt->index; + if (i >= no_faked_fmts) { errno = EINVAL; return -1; @@ -333,7 +344,14 @@ int v4lconvert_try_format(struct v4lconvert_data *data, int i, result; unsigned int desired_width = dest_fmt->fmt.pix.width; unsigned int desired_height = dest_fmt->fmt.pix.height; - struct v4l2_format try_src, try_dest = *dest_fmt; + struct v4l2_format try_src, try_dest; + + if (dest_fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + v4lconvert_supported_dst_fmt_only(data) && + !v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) + dest_fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; + + try_dest = *dest_fmt; /* Can we do conversion to the requested format & type? */ if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat) || @@ -398,19 +416,14 @@ 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) - return 1; /* Formats differ */ - - if (!(data->control_flags & (V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED))) - return 0; /* Formats identical and we don't need flip */ + 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; - /* Formats are identical, but we need flip, do we support the dest_fmt? */ - if (!v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) - return 0; /* Needs flip but we cannot do it :( */ - else - return 1; /* Needs flip and thus conversion */ + return 0; } static int v4lconvert_processing_needs_double_conversion( @@ -494,12 +507,9 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, /* Check for (pixart) rotated JPEG */ if (header_width == height && header_height == width) { if (!(data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) { - fprintf(stderr, - "libv4lconvert: Unknown cam with 90° rotated JPEG, " - "please report this to <hdegoede@redhat.com>\n"); - V4LCONVERT_ERR("JPEG needs 90 degree rotation\n"); - data->control_flags |= V4LCONTROL_ROTATED_90_JPEG; - errno = EAGAIN; + V4LCONVERT_ERR("JPEG needs 90° rotation, please report " + "this to <hdegoede@redhat.com>\n"); + errno = EIO; return -1; } fmt->fmt.pix.width = header_width; @@ -511,6 +521,13 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data, errno = EIO; return -1; } + } else if ((data->control_flags & V4LCONTROL_ROTATED_90_JPEG)) { + fprintf(stderr, "libv4lconvert: expected 90° rotated JPEG, but got " + "normal JPEG, please report this to <hdegoede@redhat.com>\n"); + V4LCONVERT_ERR("expected 90° rotated JPEG, but got normal JPEG\n"); + errno = EAGAIN; + data->control_flags &= ~V4LCONTROL_ROTATED_90_JPEG; + return -1; } components[0] = dest; @@ -831,8 +848,18 @@ int v4lconvert_convert(struct v4lconvert_data *data, struct v4l2_format my_src_fmt = *src_fmt; struct v4l2_format my_dest_fmt = *dest_fmt; - /* Special case when no conversion is needed */ - if (!v4lconvert_needs_conversion(data, src_fmt, dest_fmt)) { + processing = v4lprocessing_pre_processing(data->processing); + + if (/* If no conversion/processing is needed */ + (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 && + !processing && + !(data->control_flags & (V4LCONTROL_ROTATED_90_JPEG | + V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED))) || + /* or if we should do processing/rotating/flipping but the app tries to + use the native cam format, we just return an unprocessed frame copy */ + !v4lconvert_supported_dst_format(dest_fmt->fmt.pix.pixelformat)) { int to_copy = MIN(dest_size, src_size); memcpy(dest, src, to_copy); return to_copy; @@ -871,7 +898,6 @@ int v4lconvert_convert(struct v4lconvert_data *data, return -1; } - processing = v4lprocessing_pre_processing(data->processing); /* Sometimes we need foo -> rgb -> bar as video processing (whitebalance, etc.) can only be done on rgb data */ @@ -1040,8 +1066,13 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data, int v4lconvert_enum_framesizes(struct v4lconvert_data *data, struct v4l2_frmsizeenum *frmsize) { - if (!v4lconvert_supported_dst_format(frmsize->pixel_format)) + if (!v4lconvert_supported_dst_format(frmsize->pixel_format)) { + if (v4lconvert_supported_dst_fmt_only(data)) { + errno = EINVAL; + return -1; + } return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize); + } if (frmsize->index >= data->no_framesizes) { errno = EINVAL; @@ -1069,6 +1100,10 @@ int v4lconvert_enum_frameintervals(struct v4lconvert_data *data, struct v4l2_format src_fmt, dest_fmt; if (!v4lconvert_supported_dst_format(frmival->pixel_format)) { + if (v4lconvert_supported_dst_fmt_only(data)) { + errno = EINVAL; + return -1; + } res = syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival); if (res) V4LCONVERT_ERR("%s\n", strerror(errno)); |