summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l
diff options
context:
space:
mode:
Diffstat (limited to 'v4l2-apps/libv4l')
-rw-r--r--v4l2-apps/libv4l/ChangeLog1
-rw-r--r--v4l2-apps/libv4l/TODO3
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c42
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h12
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/flip.c27
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h5
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c65
7 files changed, 97 insertions, 58 deletions
diff --git a/v4l2-apps/libv4l/ChangeLog b/v4l2-apps/libv4l/ChangeLog
index aa0a3ea3c..9bfecab85 100644
--- a/v4l2-apps/libv4l/ChangeLog
+++ b/v4l2-apps/libv4l/ChangeLog
@@ -9,6 +9,7 @@ libv4l-0.5.98
* Add ability to determine upside down cams based on DMI info
* Fix a bug in v4lconvert_uyvy_to_yuv420()
* Add support for separate vflipping and hflipping
+* Add fake controls controlling the software h- and v-flipping
libv4l-0.5.97
-------------
diff --git a/v4l2-apps/libv4l/TODO b/v4l2-apps/libv4l/TODO
index 94c40b84e..b676bfeb5 100644
--- a/v4l2-apps/libv4l/TODO
+++ b/v4l2-apps/libv4l/TODO
@@ -13,9 +13,6 @@
-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
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
index 1ffd05cc4..b120aa2fc 100644
--- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
@@ -198,12 +198,13 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data)
}
}
-struct v4lcontrol_data *v4lcontrol_create(int fd)
+struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
{
int shm_fd;
int i, init = 0;
char *s, shm_name[256];
struct v4l2_capability cap;
+ struct v4l2_queryctrl ctrl;
struct v4lcontrol_data *data = calloc(1, sizeof(struct v4lcontrol_data));
@@ -214,6 +215,17 @@ struct v4lcontrol_data *v4lcontrol_create(int fd)
v4lcontrol_init_flags(data);
+ /* 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)) {
+ ctrl.id = V4L2_CID_HFLIP;
+ if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1)
+ data->controls |= 1 << V4LCONTROL_HFLIP;
+ ctrl.id = V4L2_CID_VFLIP;
+ if (syscall(SYS_ioctl, data->fd, VIDIOC_QUERYCTRL, &ctrl) == -1)
+ data->controls |= 1 << V4LCONTROL_VFLIP;
+ }
+
/* Allow overriding through environment */
if ((s = getenv("LIBV4LCONTROL_FLAGS")))
data->flags = strtol(s, NULL, 0);
@@ -313,6 +325,26 @@ struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = {
.default_value = 255,
.flags = 0
},
+{
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0
+},
+{
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0
+},
};
int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
@@ -390,8 +422,14 @@ int v4lcontrol_get_flags(struct v4lcontrol_data *data)
int v4lcontrol_get_ctrl(struct v4lcontrol_data *data, int ctrl)
{
- if (data->controls & (1 << ctrl))
+ if (data->controls & (1 << ctrl)) {
+ /* Special case for devices with flipped input */
+ if ((ctrl == V4LCONTROL_HFLIP && (data->flags & V4LCONTROL_HFLIPPED)) ||
+ (ctrl == V4LCONTROL_VFLIP && (data->flags & V4LCONTROL_VFLIPPED)))
+ return !data->shm_values[ctrl];
+
return data->shm_values[ctrl];
+ }
return 0;
}
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h
index 28308bc55..43ef7c49f 100644
--- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.h
@@ -28,12 +28,18 @@
#define V4LCONTROL_ROTATED_90_JPEG 0x04
/* Controls */
-enum { V4LCONTROL_WHITEBALANCE, V4LCONTROL_NORMALIZE,
- V4LCONTROL_NORM_LOW_BOUND, V4LCONTROL_NORM_HIGH_BOUND, V4LCONTROL_COUNT };
+enum {
+ V4LCONTROL_WHITEBALANCE,
+ V4LCONTROL_NORMALIZE,
+ V4LCONTROL_NORM_LOW_BOUND,
+ V4LCONTROL_NORM_HIGH_BOUND,
+ V4LCONTROL_HFLIP,
+ V4LCONTROL_VFLIP,
+ V4LCONTROL_COUNT };
struct v4lcontrol_data;
-struct v4lcontrol_data* v4lcontrol_create(int fd);
+struct v4lcontrol_data* v4lcontrol_create(int fd, int always_needs_conversion);
void v4lcontrol_destroy(struct v4lcontrol_data *data);
/* Functions used by v4lprocessing to get the control state */
diff --git a/v4l2-apps/libv4l/libv4lconvert/flip.c b/v4l2-apps/libv4l/libv4lconvert/flip.c
index 5d881844a..8c4d8233c 100644
--- a/v4l2-apps/libv4l/libv4lconvert/flip.c
+++ b/v4l2-apps/libv4l/libv4lconvert/flip.c
@@ -222,24 +222,22 @@ void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
}
void v4lconvert_flip(unsigned char *src, unsigned char *dest,
- struct v4l2_format *fmt, int flags)
+ struct v4l2_format *fmt, int hflip, int vflip)
{
- switch (flags & (V4LCONTROL_VFLIPPED|V4LCONTROL_HFLIPPED)) {
-
- case V4LCONTROL_VFLIPPED:
+ if (vflip && hflip) {
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
- v4lconvert_vflip_rgbbgr24(src, dest, fmt);
+ v4lconvert_rotate180_rgbbgr24(src, dest, fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
- v4lconvert_vflip_yuv420(src, dest, fmt);
+ v4lconvert_rotate180_yuv420(src, dest, fmt->fmt.pix.width,
+ fmt->fmt.pix.height);
break;
}
- break;
-
- case V4LCONTROL_HFLIPPED:
+ } else if (hflip) {
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
@@ -250,22 +248,17 @@ void v4lconvert_flip(unsigned char *src, unsigned char *dest,
v4lconvert_hflip_yuv420(src, dest, fmt);
break;
}
- break;
-
- case (V4LCONTROL_VFLIPPED|V4LCONTROL_HFLIPPED):
+ } else if (vflip) {
switch (fmt->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
- v4lconvert_rotate180_rgbbgr24(src, dest, fmt->fmt.pix.width,
- fmt->fmt.pix.height);
+ v4lconvert_vflip_rgbbgr24(src, dest, fmt);
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
- v4lconvert_rotate180_yuv420(src, dest, fmt->fmt.pix.width,
- fmt->fmt.pix.height);
+ v4lconvert_vflip_yuv420(src, dest, fmt);
break;
}
- break;
}
/* Our newly written data has no padding */
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
index 2d34bd6a4..60e62af97 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
@@ -96,7 +96,8 @@
#define V4LCONVERT_IS_SN9C20X 0x02
/* Pixformat flags */
-#define V4LCONVERT_COMPRESSED 0x01
+#define V4LCONVERT_COMPRESSED 0x01 /* Compressed format */
+#define V4LCONVERT_NEEDS_CONVERSION 0x02 /* Apps likely wont know this */
struct v4lconvert_data {
int fd;
@@ -217,7 +218,7 @@ void v4lconvert_rotate90(unsigned char *src, unsigned char *dest,
struct v4l2_format *fmt);
void v4lconvert_flip(unsigned char *src, unsigned char *dest,
- struct v4l2_format *fmt, int flags);
+ struct v4l2_format *fmt, int hflip, int vflip);
void v4lconvert_crop(unsigned char *src, unsigned char *dest,
const struct v4l2_format *src_fmt, const struct v4l2_format *dest_fmt);
diff --git a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
index a175973ef..94539e376 100644
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
@@ -47,15 +47,15 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
{ V4L2_PIX_FMT_YUYV, 0 },
{ V4L2_PIX_FMT_YVYU, 0 },
{ V4L2_PIX_FMT_UYVY, 0 },
- { V4L2_PIX_FMT_SN9C20X_I420, 0 },
- { V4L2_PIX_FMT_SBGGR8, 0 },
- { V4L2_PIX_FMT_SGBRG8, 0 },
- { V4L2_PIX_FMT_SGRBG8, 0 },
- { V4L2_PIX_FMT_SRGGB8, 0 },
- { V4L2_PIX_FMT_SPCA501, 0 },
- { V4L2_PIX_FMT_SPCA505, 0 },
- { V4L2_PIX_FMT_SPCA508, 0 },
- { V4L2_PIX_FMT_HM12, 0 },
+ { V4L2_PIX_FMT_SN9C20X_I420, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SBGGR8, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SGBRG8, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SGRBG8, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SRGGB8, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SPCA501, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SPCA505, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_SPCA508, V4LCONVERT_NEEDS_CONVERSION },
+ { V4L2_PIX_FMT_HM12, V4LCONVERT_NEEDS_CONVERSION },
{ V4L2_PIX_FMT_MJPEG, V4LCONVERT_COMPRESSED },
{ V4L2_PIX_FMT_JPEG, V4LCONVERT_COMPRESSED },
{ V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED },
@@ -88,6 +88,10 @@ struct v4lconvert_data *v4lconvert_create(int fd)
int i, j;
struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data));
struct v4l2_capability cap;
+ /* This keeps tracks of devices which have only formats for which apps
+ most likely will need conversion and we can thus safely add software
+ processing controls without a performance impact. */
+ int always_needs_conversion = 1;
if (!data)
return NULL;
@@ -107,8 +111,13 @@ struct v4lconvert_data *v4lconvert_create(int fd)
if (fmt.pixelformat == supported_src_pixfmts[j].fmt) {
data->supported_src_formats |= 1 << j;
v4lconvert_get_framesizes(data, fmt.pixelformat, j);
+ if (!supported_src_pixfmts[j].flags)
+ always_needs_conversion = 0;
break;
}
+
+ if (j == ARRAY_SIZE(supported_src_pixfmts))
+ always_needs_conversion = 0;
}
data->no_formats = i;
@@ -121,7 +130,7 @@ struct v4lconvert_data *v4lconvert_create(int fd)
data->flags |= V4LCONVERT_IS_SN9C20X;
}
- data->control = v4lcontrol_create(fd);
+ data->control = v4lcontrol_create(fd, always_needs_conversion);
if (!data->control) {
free(data);
return NULL;
@@ -854,7 +863,8 @@ int v4lconvert_convert(struct v4lconvert_data *data,
const struct v4l2_format *dest_fmt, /* in */
unsigned char *src, int src_size, unsigned char *dest, int dest_size)
{
- int res, dest_needed, temp_needed, processing, convert = 0, crop = 0;
+ int res, dest_needed, temp_needed, processing, convert = 0;
+ int rotate90, vflip, hflip, crop;
unsigned char *convert1_dest = dest;
unsigned char *convert2_src = src, *convert2_dest = dest;
unsigned char *rotate90_src = src, *rotate90_dest = dest;
@@ -864,14 +874,15 @@ int v4lconvert_convert(struct v4lconvert_data *data,
struct v4l2_format my_dest_fmt = *dest_fmt;
processing = v4lprocessing_pre_processing(data->processing);
+ rotate90 = data->control_flags & V4LCONTROL_ROTATED_90_JPEG;
+ hflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_HFLIP);
+ vflip = v4lcontrol_get_ctrl(data->control, V4LCONTROL_VFLIP);
+ crop = my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width ||
+ my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height;
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))) ||
+ (src_fmt->fmt.pix.pixelformat == dest_fmt->fmt.pix.pixelformat &&
+ !processing && !rotate90 && !hflip && !vflip && !crop) ||
/* 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)) {
@@ -923,10 +934,6 @@ int v4lconvert_convert(struct v4lconvert_data *data,
else if (my_dest_fmt.fmt.pix.pixelformat != my_src_fmt.fmt.pix.pixelformat)
convert = 1;
- if (my_dest_fmt.fmt.pix.width != my_src_fmt.fmt.pix.width ||
- my_dest_fmt.fmt.pix.height != my_src_fmt.fmt.pix.height)
- crop = 1;
-
/* convert_pixfmt (only if convert == 2) -> processing -> convert_pixfmt ->
rotate -> flip -> crop, all steps are optional */
if (convert == 2) {
@@ -939,8 +946,7 @@ int v4lconvert_convert(struct v4lconvert_data *data,
convert2_src = convert1_dest;
}
- if (convert && ((data->control_flags & (V4LCONTROL_ROTATED_90_JPEG |
- V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED)) || crop)) {
+ if (convert && (rotate90 || hflip || vflip || crop)) {
convert2_dest = v4lconvert_alloc_buffer(data, temp_needed,
&data->convert2_buf, &data->convert2_buf_size);
if (!convert2_dest)
@@ -949,9 +955,7 @@ int v4lconvert_convert(struct v4lconvert_data *data,
rotate90_src = flip_src = crop_src = convert2_dest;
}
- if ((data->control_flags & V4LCONTROL_ROTATED_90_JPEG) &&
- ((data->control_flags & (V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED)) ||
- crop)) {
+ if (rotate90 && (hflip || vflip || crop)) {
rotate90_dest = v4lconvert_alloc_buffer(data, temp_needed,
&data->rotate90_buf, &data->rotate90_buf_size);
if (!rotate90_dest)
@@ -960,8 +964,7 @@ int v4lconvert_convert(struct v4lconvert_data *data,
flip_src = crop_src = rotate90_dest;
}
- if ((data->control_flags & (V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED)) &&
- crop) {
+ if ((vflip || hflip) && crop) {
flip_dest = v4lconvert_alloc_buffer(data, temp_needed, &data->flip_buf,
&data->flip_buf_size);
if (!flip_dest)
@@ -1001,11 +1004,11 @@ int v4lconvert_convert(struct v4lconvert_data *data,
if (processing)
v4lprocessing_processing(data->processing, rotate90_src, &my_src_fmt);
- if (data->control_flags & V4LCONTROL_ROTATED_90_JPEG)
+ if (rotate90)
v4lconvert_rotate90(rotate90_src, rotate90_dest, &my_src_fmt);
- if (data->control_flags & (V4LCONTROL_VFLIPPED | V4LCONTROL_HFLIPPED))
- v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, data->control_flags);
+ if (hflip || vflip)
+ v4lconvert_flip(flip_src, flip_dest, &my_src_fmt, hflip, vflip);
if (crop)
v4lconvert_crop(crop_src, dest, &my_src_fmt, &my_dest_fmt);