summaryrefslogtreecommitdiff
path: root/v4l2-apps
diff options
context:
space:
mode:
authorMichael Krufky <mkrufky@linuxtv.org>2008-09-25 08:37:12 -0400
committerMichael Krufky <mkrufky@linuxtv.org>2008-09-25 08:37:12 -0400
commit7e39de54b4ed06bb2ababbe72b16f195d796d8f0 (patch)
tree5a74da414f5b1aaa78712988a989a00a94736648 /v4l2-apps
parent968c43076f37c9f65df65fe50a1c643a82b1192b (diff)
parent9385e4874ef72f62d77800fe2eb47429d0854125 (diff)
downloadmediapointer-dvb-s2-7e39de54b4ed06bb2ababbe72b16f195d796d8f0.tar.gz
mediapointer-dvb-s2-7e39de54b4ed06bb2ababbe72b16f195d796d8f0.tar.bz2
merge: ~pb/v4l-dvb
From: Michael Krufky <mkrufky@linuxtv.org> Priority: normal Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Diffstat (limited to 'v4l2-apps')
-rw-r--r--v4l2-apps/lib/libv4l/ChangeLog14
-rw-r--r--v4l2-apps/lib/libv4l/Makefile2
-rw-r--r--v4l2-apps/lib/libv4l/include/libv4lconvert.h10
-rw-r--r--v4l2-apps/lib/libv4l/libv4l1/libv4l1.c15
-rw-r--r--v4l2-apps/lib/libv4l/libv4l1/log.c6
-rw-r--r--v4l2-apps/lib/libv4l/libv4l2/libv4l2.c24
-rw-r--r--v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c15
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h34
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c239
-rw-r--r--v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c170
-rw-r--r--v4l2-apps/util/v4l2-ctl.cpp336
11 files changed, 766 insertions, 99 deletions
diff --git a/v4l2-apps/lib/libv4l/ChangeLog b/v4l2-apps/lib/libv4l/ChangeLog
index eefe0028b..dd53eced9 100644
--- a/v4l2-apps/lib/libv4l/ChangeLog
+++ b/v4l2-apps/lib/libv4l/ChangeLog
@@ -1,3 +1,17 @@
+libv4l-0.5.0
+------------
+* Add support for enumerating framesizes and frameintervals of emulated
+ formats when the driver supports it for the real format
+* Make sure the video device always gets opened RW even if the application
+ asks for RO
+* Add Genius E-Messenger 112 (093a:2476) to list of cams which have their
+ sensor upside down
+
+libv4l-0.4.3
+------------
+* Add suport for YUYV and YVYU packed pixel formats (Jean-Francois Moine)
+* Prefer compressed pixformats for resolutions > 176x144
+
libv4l-0.4.2
------------
* The bayer pixel order in gspca's sonixb driver was different from that in
diff --git a/v4l2-apps/lib/libv4l/Makefile b/v4l2-apps/lib/libv4l/Makefile
index 92928271a..4c99c3167 100644
--- a/v4l2-apps/lib/libv4l/Makefile
+++ b/v4l2-apps/lib/libv4l/Makefile
@@ -1,5 +1,5 @@
LIB_RELEASE=0
-V4L2_LIB_VERSION=$(LIB_RELEASE).4.2
+V4L2_LIB_VERSION=$(LIB_RELEASE).5.0
all clean install:
$(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@
diff --git a/v4l2-apps/lib/libv4l/include/libv4lconvert.h b/v4l2-apps/lib/libv4l/include/libv4lconvert.h
index 87e41ceaa..626c43473 100644
--- a/v4l2-apps/lib/libv4l/include/libv4lconvert.h
+++ b/v4l2-apps/lib/libv4l/include/libv4lconvert.h
@@ -71,6 +71,16 @@ LIBV4L_PUBLIC int v4lconvert_convert(struct v4lconvert_data *data,
/* get a string describing the last error*/
LIBV4L_PUBLIC const char *v4lconvert_get_error_message(struct v4lconvert_data *data);
+/* Just like VIDIOC_ENUM_FRAMESIZE, except that the framesizes of emulated
+ formats can be enumerated as well. */
+LIBV4L_PUBLIC int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
+ struct v4l2_frmsizeenum *frmsize);
+
+/* Just like VIDIOC_ENUM_FRAMEINTERVALS, except that the intervals of emulated
+ formats can be enumerated as well. */
+LIBV4L_PUBLIC int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
+ struct v4l2_frmivalenum *frmival);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c b/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c
index 39f2d29e0..797c8768a 100644
--- a/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c
+++ b/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c
@@ -259,6 +259,15 @@ int v4l1_open (const char *file, int oflag, ...)
struct v4l2_format fmt2;
struct v4l2_input input2;
struct v4l2_standard standard2;
+ int v4l_device = 0;
+
+ /* check if we're opening a video4linux2 device */
+ if (!strncmp(file, "/dev/video", 10) || !strncmp(file, "/dev/v4l/", 9)) {
+ /* Some apps open the device read only, but we need rw rights as the
+ buffers *MUST* be mapped rw */
+ oflag = (oflag & ~O_ACCMODE) | O_RDWR;
+ v4l_device = 1;
+ }
/* original open code */
if (oflag & O_CREAT)
@@ -276,11 +285,7 @@ int v4l1_open (const char *file, int oflag, ...)
fd = syscall(SYS_open, file, oflag);
/* end of original open code */
- if (fd == -1)
- return fd;
-
- /* check if we're opening a video4linux2 device */
- if (strncmp(file, "/dev/video", 10) && strncmp(file, "/dev/v4l/", 9))
+ if (fd == -1 || !v4l_device)
return fd;
/* check that this is an v4l2 device, no need to emulate v4l1 on
diff --git a/v4l2-apps/lib/libv4l/libv4l1/log.c b/v4l2-apps/lib/libv4l/libv4l1/log.c
index 74ce0f20b..9ff0cea46 100644
--- a/v4l2-apps/lib/libv4l/libv4l1/log.c
+++ b/v4l2-apps/lib/libv4l/libv4l1/log.c
@@ -66,6 +66,7 @@ static const char *v4l1_ioctls[] = {
void v4l1_log_ioctl(unsigned long int request, void *arg, int result)
{
const char *ioctl_str = "unknown";
+ char buf[40];
if (!v4l1_log_file)
return;
@@ -77,6 +78,11 @@ void v4l1_log_ioctl(unsigned long int request, void *arg, int result)
if (_IOC_TYPE(request) == 'v' && _IOC_NR(request) < ARRAY_SIZE(v4l1_ioctls))
ioctl_str = v4l1_ioctls[_IOC_NR(request)];
+ else {
+ snprintf(buf, sizeof(buf), "unknown request: %c %d\n",
+ (int)_IOC_TYPE(request), (int)_IOC_NR(request));
+ ioctl_str = buf;
+ }
fprintf(v4l1_log_file, "request == %s\n", ioctl_str);
diff --git a/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c b/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c
index 7029f69c3..b4a10afac 100644
--- a/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c
+++ b/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c
@@ -649,6 +649,11 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
(devices[index].flags & V4L2_ENABLE_ENUM_FMT_EMULATION))
is_capture_request = 1;
break;
+ case VIDIOC_ENUM_FRAMESIZES:
+ case VIDIOC_ENUM_FRAMEINTERVALS:
+ if (devices[index].flags & V4L2_ENABLE_ENUM_FMT_EMULATION)
+ is_capture_request = 1;
+ break;
case VIDIOC_TRY_FMT:
if (((struct v4l2_format *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
is_capture_request = 1;
@@ -714,6 +719,14 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
result = v4lconvert_enum_fmt(devices[index].convert, arg);
break;
+ case VIDIOC_ENUM_FRAMESIZES:
+ result = v4lconvert_enum_framesizes(devices[index].convert, arg);
+ break;
+
+ case VIDIOC_ENUM_FRAMEINTERVALS:
+ result = v4lconvert_enum_frameintervals(devices[index].convert, arg);
+ break;
+
case VIDIOC_TRY_FMT:
result = v4lconvert_try_format(devices[index].convert, arg, NULL);
break;
@@ -739,6 +752,17 @@ int v4l2_ioctl (int fd, unsigned long int request, ...)
if (result)
break;
+ if (src_fmt.fmt.pix.pixelformat != dest_fmt->fmt.pix.pixelformat &&
+ v4l2_log_file) {
+ int pixfmt = src_fmt.fmt.pix.pixelformat;
+
+ fprintf(v4l2_log_file, "VIDIOC_S_FMT converting from: %c%c%c%c\n",
+ pixfmt & 0xff,
+ (pixfmt >> 8) & 0xff,
+ (pixfmt >> 16) & 0xff,
+ pixfmt >> 24);
+ }
+
/* Maybe after try format has adjusted width/height etc, to whats
available nothing has changed (on the cam side) ? */
if (!memcmp(&devices[index].src_fmt, &src_fmt, sizeof(src_fmt))) {
diff --git a/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c b/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c
index e8756f338..307a03ce5 100644
--- a/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c
+++ b/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c
@@ -53,6 +53,15 @@ LIBV4L_PUBLIC int open (const char *file, int oflag, ...)
{
int fd;
struct v4l2_capability cap;
+ int v4l_device = 0;
+
+ /* check if we're opening a video4linux2 device */
+ if (!strncmp(file, "/dev/video", 10) || !strncmp(file, "/dev/v4l/", 9)) {
+ /* Some apps open the device read only, but we need rw rights as the
+ buffers *MUST* be mapped rw */
+ oflag = (oflag & ~O_ACCMODE) | O_RDWR;
+ v4l_device = 1;
+ }
/* original open code */
if (oflag & O_CREAT)
@@ -70,11 +79,7 @@ LIBV4L_PUBLIC int open (const char *file, int oflag, ...)
fd = syscall(SYS_open, file, oflag);
/* end of original open code */
- if (fd == -1)
- return fd;
-
- /* check if we're opening a video4linux2 device */
- if (strncmp(file, "/dev/video", 10) && strncmp(file, "/dev/v4l/", 9))
+ if (fd == -1 || !v4l_device)
return fd;
/* check that this is an v4l2 device, libv4l2 only supports v4l2 devices */
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h
index 915c33283..0c4eff6ce 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h
@@ -59,14 +59,23 @@
#define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R','G','G','B')
#endif
+#ifndef V4L2_PIX_FMT_YVYU
+#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U')
+#endif
+
#define V4LCONVERT_ERROR_MSG_SIZE 256
+#define V4LCONVERT_MAX_FRAMESIZES 16
#define V4LCONVERT_ERR(...) \
snprintf(data->error_msg, V4LCONVERT_ERROR_MSG_SIZE, \
"v4l-convert: error " __VA_ARGS__)
+/* Card flags */
#define V4LCONVERT_UPSIDE_DOWN 0x01
+/* Pixformat flags */
+#define V4LCONVERT_COMPRESSED 0x01
+
struct v4lconvert_data {
int fd;
int flags; /* bitfield */
@@ -74,6 +83,8 @@ struct v4lconvert_data {
unsigned int no_formats;
char error_msg[V4LCONVERT_ERROR_MSG_SIZE];
struct jdec_private *jdec;
+ struct v4l2_frmsizeenum framesizes[V4LCONVERT_MAX_FRAMESIZES];
+ unsigned int no_framesizes;
};
struct v4lconvert_flags_info {
@@ -81,12 +92,35 @@ struct v4lconvert_flags_info {
int flags;
};
+struct v4lconvert_pixfmt {
+ unsigned int fmt;
+ int flags;
+};
+
void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dst,
int width, int height);
void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dst,
int width, int height);
+void v4lconvert_yuyv_to_rgb24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yuyv_to_bgr24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yvyu_to_rgb24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yvyu_to_bgr24(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
+void v4lconvert_yvyu_to_yuv420(const unsigned char *src, unsigned char *dst,
+ int width, int height);
+
void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst,
int width, int height);
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c
index 4b48bfac4..93bc67c7e 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c
@@ -30,37 +30,45 @@
/* Note for proper functioning of v4lconvert_enum_fmt the first entries in
supported_src_pixfmts must match with the entries in supported_dst_pixfmts */
#define SUPPORTED_DST_PIXFMTS \
- V4L2_PIX_FMT_RGB24, \
- V4L2_PIX_FMT_BGR24, \
- V4L2_PIX_FMT_YUV420
+ { V4L2_PIX_FMT_RGB24, 0 }, \
+ { V4L2_PIX_FMT_BGR24, 0 }, \
+ { V4L2_PIX_FMT_YUV420, 0 }
-static const unsigned int supported_src_pixfmts[] = {
+static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
+ unsigned int pixelformat);
+
+/* Note uncompressed formats must go first so that they are prefered by
+ v4lconvert_try_format for low resolutions */
+static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
SUPPORTED_DST_PIXFMTS,
- V4L2_PIX_FMT_MJPEG,
- V4L2_PIX_FMT_JPEG,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_PIX_FMT_SGBRG8,
- V4L2_PIX_FMT_SGRBG8,
- V4L2_PIX_FMT_SRGGB8,
- V4L2_PIX_FMT_SPCA501,
- V4L2_PIX_FMT_SPCA505,
- V4L2_PIX_FMT_SPCA508,
- V4L2_PIX_FMT_SPCA561,
- V4L2_PIX_FMT_SN9C10X,
- V4L2_PIX_FMT_PAC207,
- V4L2_PIX_FMT_PJPG,
+ { V4L2_PIX_FMT_YUYV, 0 },
+ { V4L2_PIX_FMT_YVYU, 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_MJPEG, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_JPEG, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_PAC207, V4LCONVERT_COMPRESSED },
+ { V4L2_PIX_FMT_PJPG, V4LCONVERT_COMPRESSED },
};
-static const unsigned int supported_dst_pixfmts[] = {
+static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = {
SUPPORTED_DST_PIXFMTS
};
/* List of cams which need special flags */
static const struct v4lconvert_flags_info v4lconvert_flags[] = {
- { "USB Camera (0471:0325)", V4LCONVERT_UPSIDE_DOWN }, /* SPC200NC */
- { "USB Camera (0471:0326)", V4LCONVERT_UPSIDE_DOWN }, /* SPC300NC */
{ "SPC 200NC ", V4LCONVERT_UPSIDE_DOWN },
{ "SPC 300NC ", V4LCONVERT_UPSIDE_DOWN },
+ { "USB Camera (0471:0325)", V4LCONVERT_UPSIDE_DOWN }, /* SPC200NC */
+ { "USB Camera (0471:0326)", V4LCONVERT_UPSIDE_DOWN }, /* SPC300NC */
+ { "USB Camera (093a:2476)", V4LCONVERT_UPSIDE_DOWN }, /* Genius E-M 112 */
};
struct v4lconvert_data *v4lconvert_create(int fd)
@@ -85,10 +93,12 @@ struct v4lconvert_data *v4lconvert_create(int fd)
break;
for (j = 0; j < ARRAY_SIZE(supported_src_pixfmts); j++)
- if (fmt.pixelformat == supported_src_pixfmts[j]) {
+ if (fmt.pixelformat == supported_src_pixfmts[j].fmt) {
data->supported_src_formats |= 1 << j;
break;
}
+
+ v4lconvert_get_framesizes(data, fmt.pixelformat);
}
data->no_formats = i;
@@ -115,6 +125,17 @@ void v4lconvert_destroy(struct v4lconvert_data *data)
free(data);
}
+static int v4lconvert_supported_dst_format(unsigned int pixelformat)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
+ if (supported_dst_pixfmts[i].fmt == pixelformat)
+ break;
+
+ return i != ARRAY_SIZE(supported_dst_pixfmts);
+}
+
/* See libv4lconvert.h for description of in / out parameters */
int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
{
@@ -128,7 +149,7 @@ int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
if (!(data->supported_src_formats & (1 << i))) {
- faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i];
+ faked_fmts[no_faked_fmts] = supported_dst_pixfmts[i].fmt;
no_faked_fmts++;
}
@@ -159,12 +180,8 @@ int v4lconvert_try_format(struct v4lconvert_data *data,
unsigned int desired_pixfmt = dest_fmt->fmt.pix.pixelformat;
struct v4l2_format try_fmt, closest_fmt = { .type = 0 };
- for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
- if (supported_dst_pixfmts[i] == desired_pixfmt)
- break;
-
/* Can we do conversion to the requested format & type? */
- if (i == ARRAY_SIZE(supported_dst_pixfmts) ||
+ if (!v4lconvert_supported_dst_format(desired_pixfmt) ||
dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
int ret = syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, dest_fmt);
if (src_fmt)
@@ -178,11 +195,11 @@ int v4lconvert_try_format(struct v4lconvert_data *data,
continue;
try_fmt = *dest_fmt;
- try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i];
+ try_fmt.fmt.pix.pixelformat = supported_src_pixfmts[i].fmt;
if (!syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, &try_fmt))
{
- if (try_fmt.fmt.pix.pixelformat == supported_src_pixfmts[i]) {
+ if (try_fmt.fmt.pix.pixelformat == supported_src_pixfmts[i].fmt) {
int size_x_diff = abs((int)try_fmt.fmt.pix.width -
(int)dest_fmt->fmt.pix.width);
int size_y_diff = abs((int)try_fmt.fmt.pix.height -
@@ -191,7 +208,9 @@ int v4lconvert_try_format(struct v4lconvert_data *data,
size_y_diff * size_y_diff;
if (size_diff < closest_fmt_size_diff ||
(size_diff == closest_fmt_size_diff &&
- try_fmt.fmt.pix.pixelformat == desired_pixfmt)) {
+ (supported_src_pixfmts[i].fmt == desired_pixfmt ||
+ ((try_fmt.fmt.pix.width > 176 || try_fmt.fmt.pix.height > 144) &&
+ (supported_src_pixfmts[i].flags & V4LCONVERT_COMPRESSED))))) {
closest_fmt_size_diff = size_diff;
closest_fmt = try_fmt;
}
@@ -237,8 +256,6 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data,
const struct v4l2_format *src_fmt, /* in */
const struct v4l2_format *dest_fmt) /* in */
{
- int i;
-
if(memcmp(src_fmt, dest_fmt, sizeof(*src_fmt)))
return 1; /* Formats differ */
@@ -246,11 +263,7 @@ int v4lconvert_needs_conversion(struct v4lconvert_data *data,
return 0; /* Formats identical and we don't need flip */
/* Formats are identical, but we need flip, do we support the dest_fmt? */
- for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++)
- if (supported_dst_pixfmts[i] == dest_fmt->fmt.pix.pixelformat)
- break;
-
- if (i == ARRAY_SIZE(supported_dst_pixfmts))
+ 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 */
@@ -518,6 +531,40 @@ int v4lconvert_convert(struct v4lconvert_data *data,
}
break;
+ case V4L2_PIX_FMT_YUYV:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ v4lconvert_yuyv_to_rgb24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_yuyv_to_bgr24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ default:
+ v4lconvert_yuyv_to_yuv420(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ }
+ break;
+
+ case V4L2_PIX_FMT_YVYU:
+ switch (dest_fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24:
+ v4lconvert_yvyu_to_rgb24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ v4lconvert_yvyu_to_bgr24(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ default:
+ v4lconvert_yvyu_to_yuv420(src, dest, dest_fmt->fmt.pix.width,
+ dest_fmt->fmt.pix.height);
+ break;
+ }
+ break;
+
default:
V4LCONVERT_ERR("Unknown src format in conversion\n");
errno = EINVAL;
@@ -570,3 +617,121 @@ const char *v4lconvert_get_error_message(struct v4lconvert_data *data)
{
return data->error_msg;
}
+
+static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
+ unsigned int pixelformat)
+{
+ int i, j, match;
+ struct v4l2_frmsizeenum frmsize = { .pixel_format = pixelformat };
+
+ for (i = 0; ; i++) {
+ frmsize.index = i;
+ if (syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMESIZES, &frmsize))
+ break;
+
+ /* We got a framesize, check we don't have the same one already */
+ match = 0;
+ for (j = 0; j < data->no_framesizes && !match; j++) {
+ if (frmsize.type != data->framesizes[j].type)
+ continue;
+
+ switch(frmsize.type) {
+ case V4L2_FRMSIZE_TYPE_DISCRETE:
+ if(!memcmp(&frmsize.discrete, &data->framesizes[j].discrete,
+ sizeof(frmsize.discrete)))
+ match = 1;
+ break;
+ case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+ case V4L2_FRMSIZE_TYPE_STEPWISE:
+ if(!memcmp(&frmsize.stepwise, &data->framesizes[j].stepwise,
+ sizeof(frmsize.stepwise)))
+ match = 1;
+ break;
+ }
+ }
+ /* Add this framesize if it is not already in our list */
+ if (!match) {
+ if (data->no_framesizes == V4LCONVERT_MAX_FRAMESIZES) {
+ fprintf(stderr,
+ "libv4lconvert: warning more framesizes then I can handle!\n");
+ return;
+ }
+ data->framesizes[data->no_framesizes].type = frmsize.type;
+ switch(frmsize.type) {
+ case V4L2_FRMSIZE_TYPE_DISCRETE:
+ data->framesizes[data->no_framesizes].discrete = frmsize.discrete;
+ break;
+ case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+ case V4L2_FRMSIZE_TYPE_STEPWISE:
+ data->framesizes[data->no_framesizes].stepwise = frmsize.stepwise;
+ break;
+ }
+ data->no_framesizes++;
+ }
+ }
+}
+
+int v4lconvert_enum_framesizes(struct v4lconvert_data *data,
+ struct v4l2_frmsizeenum *frmsize)
+{
+ if (!v4lconvert_supported_dst_format(frmsize->pixel_format))
+ return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMESIZES, frmsize);
+
+ if (frmsize->index >= data->no_framesizes) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ frmsize->type = data->framesizes[frmsize->index].type;
+ switch(frmsize->type) {
+ case V4L2_FRMSIZE_TYPE_DISCRETE:
+ frmsize->discrete = data->framesizes[frmsize->index].discrete;
+ break;
+ case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+ case V4L2_FRMSIZE_TYPE_STEPWISE:
+ frmsize->stepwise = data->framesizes[frmsize->index].stepwise;
+ break;
+ }
+
+ return 0;
+}
+
+int v4lconvert_enum_frameintervals(struct v4lconvert_data *data,
+ struct v4l2_frmivalenum *frmival)
+{
+ int res;
+ struct v4l2_format src_fmt, dest_fmt;
+
+ if (!v4lconvert_supported_dst_format(frmival->pixel_format))
+ return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
+
+ /* Check which format we will be using to convert to frmival->pixel_format */
+ memset(&dest_fmt, 0, sizeof(dest_fmt));
+ dest_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dest_fmt.fmt.pix.pixelformat = frmival->pixel_format;
+ dest_fmt.fmt.pix.width = frmival->width;
+ dest_fmt.fmt.pix.height = frmival->height;
+ if ((res = v4lconvert_try_format(data, &dest_fmt, &src_fmt)))
+ return res;
+
+ /* Check the requested format is supported exactly as requested */
+ if (dest_fmt.fmt.pix.pixelformat != frmival->pixel_format ||
+ dest_fmt.fmt.pix.width != frmival->width ||
+ dest_fmt.fmt.pix.height != frmival->height) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Enumerate the frameintervals of the source format we will be using */
+ frmival->pixel_format = src_fmt.fmt.pix.pixelformat;
+ frmival->width = src_fmt.fmt.pix.width;
+ frmival->height = src_fmt.fmt.pix.height;
+ res = syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FRAMEINTERVALS, frmival);
+
+ /* Restore the requested format in the frmival struct */
+ frmival->pixel_format = dest_fmt.fmt.pix.pixelformat;
+ frmival->width = dest_fmt.fmt.pix.width;
+ frmival->height = dest_fmt.fmt.pix.height;
+
+ return res;
+}
diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c
index 883d62330..0f26b227a 100644
--- a/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c
@@ -130,6 +130,176 @@ void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dest,
}
}
+void v4lconvert_yuyv_to_bgr24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int j;
+
+ while (--height >= 0) {
+ for (j = 0; j < width; j += 2) {
+ int u = src[1];
+ int v = src[3];
+ int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
+ int rg = (((u - 128) << 1) + (u - 128) +
+ ((v - 128) << 2) + ((v - 128) << 1)) >> 3;
+ int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
+
+ *dest++ = CLIP(src[0] + u1);
+ *dest++ = CLIP(src[0] - rg);
+ *dest++ = CLIP(src[0] + v1);
+
+ *dest++ = CLIP(src[2] + u1);
+ *dest++ = CLIP(src[2] - rg);
+ *dest++ = CLIP(src[2] + v1);
+ src += 4;
+ }
+ }
+}
+
+void v4lconvert_yuyv_to_rgb24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int j;
+
+ while (--height >= 0) {
+ for (j = 0; j < width; j += 2) {
+ int u = src[1];
+ int v = src[3];
+ int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
+ int rg = (((u - 128) << 1) + (u - 128) +
+ ((v - 128) << 2) + ((v - 128) << 1)) >> 3;
+ int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
+
+ *dest++ = CLIP(src[0] + v1);
+ *dest++ = CLIP(src[0] - rg);
+ *dest++ = CLIP(src[0] + u1);
+
+ *dest++ = CLIP(src[2] + v1);
+ *dest++ = CLIP(src[2] - rg);
+ *dest++ = CLIP(src[2] + u1);
+ src += 4;
+ }
+ }
+}
+
+void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int i, j;
+ const unsigned char *src1;
+ unsigned char *vdest;
+
+ /* copy the Y values */
+ src1 = src;
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j += 2) {
+ *dest++ = src1[0];
+ *dest++ = src1[2];
+ src1 += 4;
+ }
+ }
+
+ /* copy the U and V values */
+ src++; /* point to V */
+ src1 = src + width * 2; /* next line */
+ vdest = dest + width * height / 4;
+ for (i = 0; i < height; i += 2) {
+ for (j = 0; j < width; j += 2) {
+ *dest++ = ((int) src[0] + src1[0]) / 2; /* U */
+ *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */
+ src += 4;
+ src1 += 4;
+ }
+ src = src1;
+ src1 += width * 2;
+ }
+}
+
+void v4lconvert_yvyu_to_bgr24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int j;
+
+ while (--height >= 0) {
+ for (j = 0; j < width; j += 2) {
+ int u = src[3];
+ int v = src[1];
+ int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
+ int rg = (((u - 128) << 1) + (u - 128) +
+ ((v - 128) << 2) + ((v - 128) << 1)) >> 3;
+ int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
+
+ *dest++ = CLIP(src[0] + u1);
+ *dest++ = CLIP(src[0] - rg);
+ *dest++ = CLIP(src[0] + v1);
+
+ *dest++ = CLIP(src[2] + u1);
+ *dest++ = CLIP(src[2] - rg);
+ *dest++ = CLIP(src[2] + v1);
+ src += 4;
+ }
+ }
+}
+
+void v4lconvert_yvyu_to_rgb24(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int j;
+
+ while (--height >= 0) {
+ for (j = 0; j < width; j += 2) {
+ int u = src[3];
+ int v = src[1];
+ int u1 = (((u - 128) << 7) + (u - 128)) >> 6;
+ int rg = (((u - 128) << 1) + (u - 128) +
+ ((v - 128) << 2) + ((v - 128) << 1)) >> 3;
+ int v1 = (((v - 128) << 1) + (v - 128)) >> 1;
+
+ *dest++ = CLIP(src[0] + v1);
+ *dest++ = CLIP(src[0] - rg);
+ *dest++ = CLIP(src[0] + u1);
+
+ *dest++ = CLIP(src[2] + v1);
+ *dest++ = CLIP(src[2] - rg);
+ *dest++ = CLIP(src[2] + u1);
+ src += 4;
+ }
+ }
+}
+
+void v4lconvert_yvyu_to_yuv420(const unsigned char *src, unsigned char *dest,
+ int width, int height)
+{
+ int i, j;
+ const unsigned char *src1;
+ unsigned char *vdest;
+
+ /* copy the Y values */
+ src1 = src;
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j += 2) {
+ *dest++ = src1[0];
+ *dest++ = src1[2];
+ src1 += 4;
+ }
+ }
+
+ /* copy the U and V values */
+ src++; /* point to V */
+ src1 = src + width * 2; /* next line */
+ vdest = dest + width * height / 4;
+ for (i = 0; i < height; i += 2) {
+ for (j = 0; j < width; j += 2) {
+ *dest++ = ((int) src[2] + src1[2]) / 2; /* U */
+ *vdest++ = ((int) src[0] + src1[0]) / 2; /* V */
+ src += 4;
+ src1 += 4;
+ }
+ src = src1;
+ src1 += width * 2;
+ }
+}
+
void v4lconvert_swap_rgb(const unsigned char *src, unsigned char *dst,
int width, int height)
{
diff --git a/v4l2-apps/util/v4l2-ctl.cpp b/v4l2-apps/util/v4l2-ctl.cpp
index 1c765cf96..417721c57 100644
--- a/v4l2-apps/util/v4l2-ctl.cpp
+++ b/v4l2-apps/util/v4l2-ctl.cpp
@@ -34,6 +34,7 @@
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/time.h>
+#include <dirent.h>
#include <math.h>
#include <sys/klog.h>
@@ -43,6 +44,7 @@
#include <vector>
#include <map>
#include <string>
+#include <algorithm>
/* Short option list
@@ -77,15 +79,25 @@ enum Option {
OptSetVideoFormat = 'v',
OptGetSlicedVbiOutFormat = 128,
- OptSetSlicedVbiOutFormat,
OptGetOverlayFormat,
- //OptSetOverlayFormat, TODO
OptGetOutputOverlayFormat,
- OptSetOutputOverlayFormat,
OptGetVbiFormat,
- //OptSetVbiFormat, TODO
OptGetVbiOutFormat,
+ OptGetVideoOutFormat,
+ OptSetSlicedVbiOutFormat,
+ OptSetOutputOverlayFormat,
+ OptSetOverlayFormat,
+ //OptSetVbiFormat, TODO
//OptSetVbiOutFormat, TODO
+ OptSetVideoOutFormat,
+ OptTryVideoOutFormat,
+ OptTrySlicedVbiOutFormat,
+ OptTrySlicedVbiFormat,
+ OptTryVideoFormat,
+ OptTryOutputOverlayFormat,
+ OptTryOverlayFormat,
+ //OptTryVbiFormat, TODO
+ //OptTryVbiOutFormat, TODO
OptAll,
OptStreamOff,
OptStreamOn,
@@ -94,8 +106,6 @@ enum Option {
OptLogStatus,
OptVerbose,
OptSilent,
- OptGetVideoOutFormat,
- OptSetVideoOutFormat,
OptGetSlicedVbiCap,
OptGetSlicedVbiOutCap,
OptGetFBuf,
@@ -119,12 +129,14 @@ enum Option {
OptGetOverlayCropCap,
OptGetOutputOverlayCropCap,
OptOverlay,
+ OptListDevices,
OptLast = 256
};
static char options[OptLast];
static int app_result;
+static int verbose;
static unsigned capabilities;
@@ -143,6 +155,9 @@ static ctrl_get_list get_ctrls;
typedef std::map<std::string,std::string> ctrl_set_map;
static ctrl_set_map set_ctrls;
+typedef std::vector<std::string> dev_vec;
+typedef std::map<std::string, std::string> dev_map;
+
typedef struct {
unsigned flag;
const char *str;
@@ -162,6 +177,9 @@ static const flag_def service_def[] = {
#define FmtChromaKey (1L<<2)
#define FmtGlobalAlpha (1L<<3)
#define FmtPixelFormat (1L<<4)
+#define FmtLeft (1L<<5)
+#define FmtTop (1L<<6)
+#define FmtField (1L<<7)
/* crop specified */
#define CropWidth (1L<<0)
@@ -176,8 +194,10 @@ static struct option long_options[] = {
{"device", required_argument, 0, OptSetDevice},
{"get-fmt-video", no_argument, 0, OptGetVideoFormat},
{"set-fmt-video", required_argument, 0, OptSetVideoFormat},
+ {"try-fmt-video", required_argument, 0, OptTryVideoFormat},
{"get-fmt-video-out", no_argument, 0, OptGetVideoOutFormat},
{"set-fmt-video-out", required_argument, 0, OptSetVideoOutFormat},
+ {"try-fmt-video-out", required_argument, 0, OptTryVideoOutFormat},
{"help", no_argument, 0, OptHelp},
{"get-output", no_argument, 0, OptGetOutput},
{"set-output", required_argument, 0, OptSetOutput},
@@ -207,12 +227,17 @@ static struct option long_options[] = {
{"verbose", no_argument, 0, OptVerbose},
{"log-status", no_argument, 0, OptLogStatus},
{"get-fmt-overlay", no_argument, 0, OptGetOverlayFormat},
+ {"set-fmt-overlay", required_argument, 0, OptSetOverlayFormat},
+ {"try-fmt-overlay", required_argument, 0, OptTryOverlayFormat},
{"get-fmt-output-overlay", no_argument, 0, OptGetOutputOverlayFormat},
{"set-fmt-output-overlay", required_argument, 0, OptSetOutputOverlayFormat},
+ {"try-fmt-output-overlay", required_argument, 0, OptTryOutputOverlayFormat},
{"get-fmt-sliced-vbi", no_argument, 0, OptGetSlicedVbiFormat},
{"set-fmt-sliced-vbi", required_argument, 0, OptSetSlicedVbiFormat},
+ {"try-fmt-sliced-vbi", required_argument, 0, OptTrySlicedVbiFormat},
{"get-fmt-sliced-vbi-out", no_argument, 0, OptGetSlicedVbiOutFormat},
{"set-fmt-sliced-vbi-out", required_argument, 0, OptSetSlicedVbiOutFormat},
+ {"try-fmt-sliced-vbi-out", required_argument, 0, OptTrySlicedVbiOutFormat},
{"get-fmt-vbi", no_argument, 0, OptGetVbiFormat},
{"get-fmt-vbi-out", no_argument, 0, OptGetVbiOutFormat},
{"get-sliced-vbi-cap", no_argument, 0, OptGetSlicedVbiCap},
@@ -232,6 +257,7 @@ static struct option long_options[] = {
{"get-crop-output-overlay", no_argument, 0, OptGetOutputOverlayCrop},
{"set-crop-output-overlay", required_argument, 0, OptSetOutputOverlayCrop},
{"overlay", required_argument, 0, OptOverlay},
+ {"list-devices", no_argument, 0, OptListDevices},
{0, 0, 0, 0}
};
@@ -240,16 +266,6 @@ static void usage(void)
printf("Usage:\n");
printf("Common options:\n"
" --all display all information available\n"
- " -B, --get-fmt-sliced-vbi\n"
- " query the sliced VBI capture format [VIDIOC_G_FMT]\n"
- " -b, --set-fmt-sliced-vbi=<mode>\n"
- " set the sliced VBI capture format to <mode> [VIDIOC_S_FMT]\n"
- " <mode> is a comma separated list of:\n"
- " off: turn off sliced VBI (cannot be combined with other modes)\n"
- " teletext: teletext (PAL/SECAM)\n"
- " cc: closed caption (NTSC)\n"
- " wss: widescreen signal (PAL/SECAM)\n"
- " vps: VPS (PAL/SECAM)\n"
" -C, --get-ctrl=<ctrl>[,<ctrl>...]\n"
" get the value of the controls [VIDIOC_G_EXT_CTRLS]\n"
" -c, --set-ctrl=<ctrl>=<val>[,<ctrl>=<val>...]\n"
@@ -292,27 +308,46 @@ static void usage(void)
" set the video capture format [VIDIOC_S_FMT]\n"
" pixelformat is either the format index as reported by\n"
" --list-formats, or the fourcc value as a string\n"
+ " --list-devices list all v4l devices\n"
" --silent only set the result code, do not print any messages\n"
" --verbose turn on verbose ioctl status reporting\n"
"\n");
printf("Uncommon options:\n"
+ " --try-fmt-video=width=<w>,height=<h>,pixelformat=<f>\n"
+ " try the video capture format [VIDIOC_TRY_FMT]\n"
+ " pixelformat is either the format index as reported by\n"
+ " --list-formats, or the fourcc value as a string\n"
" --get-fmt-video-out\n"
" query the video output format [VIDIOC_G_FMT]\n"
" --set-fmt-video-out=width=<w>,height=<h>\n"
" set the video output format [VIDIOC_S_FMT]\n"
+ " --try-fmt-video-out=width=<w>,height=<h>\n"
+ " try the video output format [VIDIOC_TRY_FMT]\n"
" --get-fmt-overlay query the video overlay format [VIDIOC_G_FMT]\n"
" --get-fmt-output-overlay\n"
" query the video output overlay format [VIDIOC_G_FMT]\n"
- " --set-fmt-output-overlay=chromakey=<key>,global_alpha=<alpha>\n"
- " set the video output overlay format [VIDIOC_S_FMT]\n"
+ " --set-fmt-overlay\n"
+ " --try-fmt-overlay\n"
+ " --set-fmt-output-overlay\n"
+ " --try-fmt-output-overlay=chromakey=<key>,global_alpha=<alpha>,\n"
+ " top=<t>,left=<l>,width=<w>,height=<h>,field=<f>\n"
+ " set/try the video or video output overlay format [VIDIOC_TRY_FMT]\n"
+ " <f> can be one of:\n"
+ " any, none, top, bottom, interlaced, seq_tb, seq_bt, alternate,\n"
+ " interlaced_tb, interlaced_bt\n"
" --get-sliced-vbi-cap\n"
" query the sliced VBI capture capabilities [VIDIOC_G_SLICED_VBI_CAP]\n"
" --get-sliced-vbi-out-cap\n"
" query the sliced VBI output capabilities [VIDIOC_G_SLICED_VBI_CAP]\n"
+ " -B, --get-fmt-sliced-vbi\n"
+ " query the sliced VBI capture format [VIDIOC_G_FMT]\n"
" --get-fmt-sliced-vbi-out\n"
" query the sliced VBI output format [VIDIOC_G_FMT]\n"
- " --set-fmt-sliced-vbi-out=<mode>\n"
- " set the sliced VBI output format to <mode> [VIDIOC_S_FMT]\n"
+ " -b, --set-fmt-sliced-vbi\n"
+ " --try-fmt-sliced-vbi\n"
+ " --set-fmt-sliced-vbi-out\n"
+ " --try-fmt-sliced-vbi-out=<mode>\n"
+ " (try to) set the sliced VBI capture/output format to <mode> [VIDIOC_S/TRY_FMT]\n"
" <mode> is a comma separated list of:\n"
" off: turn off sliced VBI (cannot be combined with other modes)\n"
" teletext: teletext (PAL/SECAM)\n"
@@ -1021,12 +1056,91 @@ static int doioctl(int fd, int request, void *parm, const char *name)
if (options[OptSilent]) return retVal;
if (retVal < 0)
printf("%s: failed: %s\n", name, strerror(errno));
- else if (options[OptVerbose])
+ else if (verbose)
printf("%s: ok\n", name);
return retVal;
}
+static bool is_v4l_dev(const char *name)
+{
+ return !memcmp(name, "vtx", 3) ||
+ !memcmp(name, "video", 5) ||
+ !memcmp(name, "radio", 5) ||
+ !memcmp(name, "vbi", 3);
+}
+
+static int calc_node_val(const char *s)
+{
+ int n = 0;
+
+ s = strrchr(s, '/') + 1;
+ if (!memcmp(s, "video", 5)) n = 0;
+ else if (!memcmp(s, "radio", 5)) n = 0x100;
+ else if (!memcmp(s, "vbi", 3)) n = 0x200;
+ else if (!memcmp(s, "vtx", 3)) n = 0x300;
+ n += atol(s + (n >= 0x200 ? 3 : 5));
+ return n;
+}
+
+static bool sort_on_device_name(const std::string &s1, const std::string &s2)
+{
+ int n1 = calc_node_val(s1.c_str());
+ int n2 = calc_node_val(s2.c_str());
+
+ return n1 < n2;
+}
+
+static void list_devices()
+{
+ DIR *dp;
+ struct dirent *ep;
+ dev_vec files;
+ dev_map cards;
+ struct v4l2_capability vcap;
+
+ dp = opendir("/dev");
+ if (dp == NULL) {
+ perror ("Couldn't open the directory");
+ return;
+ }
+ while (ep = readdir(dp))
+ if (is_v4l_dev(ep->d_name))
+ files.push_back(std::string("/dev/") + ep->d_name);
+ closedir(dp);
+
+#if 0
+ dp = opendir("/dev/v4l");
+ if (dp) {
+ while (ep = readdir(dp))
+ if (is_v4l_dev(ep->d_name))
+ files.push_back(std::string("/dev/v4l/") + ep->d_name);
+ closedir(dp);
+ }
+#endif
+
+ std::sort(files.begin(), files.end(), sort_on_device_name);
+
+ for (dev_vec::iterator iter = files.begin();
+ iter != files.end(); ++iter) {
+ int fd = open(iter->c_str(), O_RDWR);
+ std::string bus_info;
+
+ if (fd < 0)
+ continue;
+ doioctl(fd, VIDIOC_QUERYCAP, &vcap, "VIDIOC_QUERYCAP");
+ close(fd);
+ bus_info = (const char *)vcap.bus_info;
+ if (cards[bus_info].empty())
+ cards[bus_info] += std::string((char *)vcap.card) + " (" + bus_info + "):\n";
+ cards[bus_info] += "\t" + (*iter) + "\n";
+ }
+ for (dev_map::iterator iter = cards.begin();
+ iter != cards.end(); ++iter) {
+ printf("%s\n", iter->second.c_str());
+ }
+}
+
static int parse_subopt(char **subs, const char * const *subopts, char **value)
{
int opt = getsubopt(subs, (char * const *)subopts, value);
@@ -1131,6 +1245,21 @@ static void parse_crop(char *optarg, unsigned int &set_crop, v4l2_rect &vcrop)
}
}
+static enum v4l2_field parse_field(const char *s)
+{
+ if (!strcmp(s, "any")) return V4L2_FIELD_ANY;
+ if (!strcmp(s, "none")) return V4L2_FIELD_NONE;
+ if (!strcmp(s, "top")) return V4L2_FIELD_TOP;
+ if (!strcmp(s, "bottom")) return V4L2_FIELD_BOTTOM;
+ if (!strcmp(s, "interlaced")) return V4L2_FIELD_INTERLACED;
+ if (!strcmp(s, "seq_tb")) return V4L2_FIELD_SEQ_TB;
+ if (!strcmp(s, "seq_bt")) return V4L2_FIELD_SEQ_BT;
+ if (!strcmp(s, "alternate")) return V4L2_FIELD_ALTERNATE;
+ if (!strcmp(s, "interlaced_tb")) return V4L2_FIELD_INTERLACED_TB;
+ if (!strcmp(s, "interlaced_bt")) return V4L2_FIELD_INTERLACED_BT;
+ return V4L2_FIELD_ANY;
+}
+
int main(int argc, char **argv)
{
char *value, *subs;
@@ -1146,6 +1275,7 @@ int main(int argc, char **argv)
unsigned int set_crop_overlay = 0;
unsigned int set_crop_out_overlay = 0;
unsigned int set_fbuf = 0;
+ unsigned int set_overlay_fmt = 0;
unsigned int set_overlay_fmt_out = 0;
int mode = V4L2_TUNER_MODE_STEREO; /* set audio mode */
@@ -1159,6 +1289,7 @@ int main(int argc, char **argv)
struct v4l2_format vbi_fmt_out; /* set_format/get_format for sliced VBI output */
struct v4l2_format raw_fmt; /* set_format/get_format for VBI */
struct v4l2_format raw_fmt_out; /* set_format/get_format for VBI output */
+ struct v4l2_format overlay_fmt; /* set_format/get_format video overlay */
struct v4l2_format overlay_fmt_out; /* set_format/get_format video overlay output */
struct v4l2_tuner tuner; /* set_tuner/get_tuner */
struct v4l2_capability vcap; /* list_cap */
@@ -1178,14 +1309,18 @@ int main(int argc, char **argv)
struct v4l2_frequency vf; /* get_freq/set_freq */
struct v4l2_standard vs; /* list_std */
int overlay; /* overlay */
+ unsigned int *set_overlay_fmt_ptr;
+ struct v4l2_format *overlay_fmt_ptr;
char short_options[26 * 2 * 2 + 1];
int idx = 0;
+ int ret;
memset(&vfmt, 0, sizeof(vfmt));
memset(&vbi_fmt, 0, sizeof(vbi_fmt));
memset(&raw_fmt, 0, sizeof(raw_fmt));
memset(&vfmt_out, 0, sizeof(vfmt_out));
memset(&vbi_fmt_out, 0, sizeof(vbi_fmt_out));
+ memset(&overlay_fmt, 0, sizeof(overlay_fmt));
memset(&overlay_fmt_out, 0, sizeof(overlay_fmt_out));
memset(&raw_fmt_out, 0, sizeof(raw_fmt_out));
memset(&tuner, 0, sizeof(tuner));
@@ -1238,6 +1373,7 @@ int main(int argc, char **argv)
}
break;
case OptSetVideoFormat:
+ case OptTryVideoFormat:
subs = optarg;
while (*subs != '\0') {
static const char *const subopts[] = {
@@ -1269,6 +1405,7 @@ int main(int argc, char **argv)
}
break;
case OptSetVideoOutFormat:
+ case OptTryVideoOutFormat:
subs = optarg;
while (*subs != '\0') {
static const char *const subopts[] = {
@@ -1289,23 +1426,63 @@ int main(int argc, char **argv)
}
}
break;
+ case OptSetOverlayFormat:
+ case OptTryOverlayFormat:
case OptSetOutputOverlayFormat:
+ case OptTryOutputOverlayFormat:
+ switch (ch) {
+ case OptSetOverlayFormat:
+ case OptTryOverlayFormat:
+ set_overlay_fmt_ptr = &set_overlay_fmt;
+ overlay_fmt_ptr = &overlay_fmt;
+ break;
+ case OptSetOutputOverlayFormat:
+ case OptTryOutputOverlayFormat:
+ set_overlay_fmt_ptr = &set_overlay_fmt_out;
+ overlay_fmt_ptr = &overlay_fmt_out;
+ break;
+ }
subs = optarg;
while (*subs != '\0') {
static const char *const subopts[] = {
"chromakey",
"global_alpha",
+ "left",
+ "top",
+ "width",
+ "height",
+ "field",
NULL
};
switch (parse_subopt(&subs, subopts, &value)) {
case 0:
- overlay_fmt_out.fmt.win.chromakey = strtol(value, 0L, 0);
- set_overlay_fmt_out |= FmtChromaKey;
+ overlay_fmt_ptr->fmt.win.chromakey = strtol(value, 0L, 0);
+ *set_overlay_fmt_ptr |= FmtChromaKey;
break;
case 1:
- overlay_fmt_out.fmt.win.global_alpha = strtol(value, 0L, 0);
- set_overlay_fmt_out |= FmtGlobalAlpha;
+ overlay_fmt_ptr->fmt.win.global_alpha = strtol(value, 0L, 0);
+ *set_overlay_fmt_ptr |= FmtGlobalAlpha;
+ break;
+ case 2:
+ overlay_fmt_ptr->fmt.win.w.left = strtol(value, 0L, 0);
+ *set_overlay_fmt_ptr |= FmtLeft;
+ break;
+ case 3:
+ overlay_fmt_ptr->fmt.win.w.top = strtol(value, 0L, 0);
+ *set_overlay_fmt_ptr |= FmtTop;
+ break;
+ case 4:
+ overlay_fmt_ptr->fmt.win.w.width = strtol(value, 0L, 0);
+ *set_overlay_fmt_ptr |= FmtWidth;
+ break;
+ case 5:
+ overlay_fmt_ptr->fmt.win.w.height = strtol(value, 0L, 0);
+ *set_overlay_fmt_ptr |= FmtHeight;
+ break;
+ case 6:
+ overlay_fmt_ptr->fmt.win.field = parse_field(value);
+ *set_overlay_fmt_ptr |= FmtField;
break;
}
}
@@ -1439,11 +1616,13 @@ int main(int argc, char **argv)
break;
case OptSetSlicedVbiFormat:
case OptSetSlicedVbiOutFormat:
+ case OptTrySlicedVbiFormat:
+ case OptTrySlicedVbiOutFormat:
{
bool foundOff = false;
v4l2_format *fmt = &vbi_fmt;
- if (ch == OptSetSlicedVbiOutFormat)
+ if (ch == OptSetSlicedVbiOutFormat || ch == OptTrySlicedVbiOutFormat)
fmt = &vbi_fmt_out;
fmt->fmt.sliced.service_set = 0;
subs = optarg;
@@ -1486,6 +1665,9 @@ int main(int argc, char **argv)
}
break;
}
+ case OptListDevices:
+ list_devices();
+ break;
case ':':
fprintf(stderr, "Option `%s' requires a value\n",
argv[optind]);
@@ -1513,6 +1695,7 @@ int main(int argc, char **argv)
exit(1);
}
+ verbose = options[OptVerbose];
doioctl(fd, VIDIOC_QUERYCAP, &vcap, "VIDIOC_QUERYCAP");
capabilities = vcap.capabilities;
find_controls(fd);
@@ -1550,6 +1733,7 @@ int main(int argc, char **argv)
options[OptGetFBuf] = 1;
options[OptGetCropCap] = 1;
options[OptGetOutputCropCap] = 1;
+ options[OptSilent] = 1;
}
/* Information Opts */
@@ -1632,7 +1816,7 @@ int main(int argc, char **argv)
}
}
- if (options[OptSetVideoFormat]) {
+ if (options[OptSetVideoFormat] || options[OptTryVideoFormat]) {
struct v4l2_format in_vfmt;
in_vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -1653,12 +1837,17 @@ int main(int argc, char **argv)
in_vfmt.fmt.pix.pixelformat = fmt.pixelformat;
}
}
- doioctl(fd, VIDIOC_S_FMT, &in_vfmt, "VIDIOC_S_FMT");
+ if (options[OptSetVideoFormat])
+ ret = doioctl(fd, VIDIOC_S_FMT, &in_vfmt, "VIDIOC_S_FMT");
+ else
+ ret = doioctl(fd, VIDIOC_TRY_FMT, &in_vfmt, "VIDIOC_TRY_FMT");
+ if (ret == 0 && verbose)
+ printfmt(in_vfmt);
}
}
set_vid_fmt_error:
- if (options[OptSetVideoOutFormat]) {
+ if (options[OptSetVideoOutFormat] || options[OptTryVideoOutFormat]) {
struct v4l2_format in_vfmt;
in_vfmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
@@ -1667,35 +1856,65 @@ set_vid_fmt_error:
in_vfmt.fmt.pix.width = vfmt_out.fmt.pix.width;
if (set_fmts_out & FmtHeight)
in_vfmt.fmt.pix.height = vfmt_out.fmt.pix.height;
- doioctl(fd, VIDIOC_S_FMT, &in_vfmt, "VIDIOC_S_FMT");
+
+ if (options[OptSetVideoOutFormat])
+ ret = doioctl(fd, VIDIOC_S_FMT, &in_vfmt, "VIDIOC_S_FMT");
+ else
+ ret = doioctl(fd, VIDIOC_TRY_FMT, &in_vfmt, "VIDIOC_TRY_FMT");
+ if (ret == 0 && verbose)
+ printfmt(in_vfmt);
}
}
- if (options[OptSetSlicedVbiFormat]) {
- if (vbi_fmt.fmt.sliced.service_set == 0) {
- // switch to raw mode
- vbi_fmt.type = V4L2_BUF_TYPE_VBI_CAPTURE;
- if (doioctl(fd, VIDIOC_G_FMT, &vbi_fmt, "VIDIOC_G_FMT") == 0)
- doioctl(fd, VIDIOC_S_FMT, &vbi_fmt, "VIDIOC_S_FMT");
- } else {
- vbi_fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
- doioctl(fd, VIDIOC_S_FMT, &vbi_fmt, "VIDIOC_S_FMT");
- }
+ if (options[OptSetSlicedVbiFormat] || options[OptTrySlicedVbiFormat]) {
+ vbi_fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+ if (options[OptSetSlicedVbiFormat])
+ ret = doioctl(fd, VIDIOC_S_FMT, &vbi_fmt, "VIDIOC_S_FMT");
+ else
+ ret = doioctl(fd, VIDIOC_TRY_FMT, &vbi_fmt, "VIDIOC_TRY_FMT");
+ if (ret == 0 && verbose)
+ printfmt(vbi_fmt);
}
- if (options[OptSetSlicedVbiOutFormat]) {
- if (vbi_fmt_out.fmt.sliced.service_set == 0) {
- // switch to raw mode
- vbi_fmt_out.type = V4L2_BUF_TYPE_VBI_OUTPUT;
- if (doioctl(fd, VIDIOC_G_FMT, &vbi_fmt_out, "VIDIOC_G_FMT") == 0)
- doioctl(fd, VIDIOC_S_FMT, &vbi_fmt_out, "VIDIOC_S_FMT");
- } else {
- vbi_fmt_out.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
- doioctl(fd, VIDIOC_S_FMT, &vbi_fmt_out, "VIDIOC_S_FMT");
+ if (options[OptSetSlicedVbiOutFormat] || options[OptTrySlicedVbiOutFormat]) {
+ vbi_fmt_out.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
+ if (options[OptSetSlicedVbiOutFormat])
+ ret = doioctl(fd, VIDIOC_S_FMT, &vbi_fmt_out, "VIDIOC_S_FMT");
+ else
+ ret = doioctl(fd, VIDIOC_TRY_FMT, &vbi_fmt_out, "VIDIOC_TRY_FMT");
+ if (ret == 0 && verbose)
+ printfmt(vbi_fmt_out);
+ }
+
+ if (options[OptSetOverlayFormat] || options[OptTryOverlayFormat]) {
+ struct v4l2_format fmt;
+
+ fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+ if (doioctl(fd, VIDIOC_G_FMT, &fmt, "VIDIOC_G_FMT") == 0) {
+ if (set_overlay_fmt & FmtChromaKey)
+ fmt.fmt.win.chromakey = overlay_fmt.fmt.win.chromakey;
+ if (set_overlay_fmt & FmtGlobalAlpha)
+ fmt.fmt.win.global_alpha = overlay_fmt.fmt.win.global_alpha;
+ if (set_overlay_fmt & FmtLeft)
+ fmt.fmt.win.w.left = overlay_fmt.fmt.win.w.left;
+ if (set_overlay_fmt & FmtTop)
+ fmt.fmt.win.w.top = overlay_fmt.fmt.win.w.top;
+ if (set_overlay_fmt & FmtWidth)
+ fmt.fmt.win.w.width = overlay_fmt.fmt.win.w.width;
+ if (set_overlay_fmt & FmtHeight)
+ fmt.fmt.win.w.height = overlay_fmt.fmt.win.w.height;
+ if (set_overlay_fmt & FmtField)
+ fmt.fmt.win.field = overlay_fmt.fmt.win.field;
+ if (options[OptSetOverlayFormat])
+ ret = doioctl(fd, VIDIOC_S_FMT, &fmt, "VIDIOC_S_FMT");
+ else
+ ret = doioctl(fd, VIDIOC_TRY_FMT, &fmt, "VIDIOC_TRY_FMT");
+ if (ret == 0 && verbose)
+ printfmt(fmt);
}
}
- if (options[OptSetOutputOverlayFormat]) {
+ if (options[OptSetOutputOverlayFormat] || options[OptTryOutputOverlayFormat]) {
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY;
@@ -1704,7 +1923,22 @@ set_vid_fmt_error:
fmt.fmt.win.chromakey = overlay_fmt_out.fmt.win.chromakey;
if (set_overlay_fmt_out & FmtGlobalAlpha)
fmt.fmt.win.global_alpha = overlay_fmt_out.fmt.win.global_alpha;
- doioctl(fd, VIDIOC_S_FMT, &fmt, "VIDIOC_S_FMT");
+ if (set_overlay_fmt_out & FmtLeft)
+ fmt.fmt.win.w.left = overlay_fmt_out.fmt.win.w.left;
+ if (set_overlay_fmt_out & FmtTop)
+ fmt.fmt.win.w.top = overlay_fmt_out.fmt.win.w.top;
+ if (set_overlay_fmt_out & FmtWidth)
+ fmt.fmt.win.w.width = overlay_fmt_out.fmt.win.w.width;
+ if (set_overlay_fmt_out & FmtHeight)
+ fmt.fmt.win.w.height = overlay_fmt_out.fmt.win.w.height;
+ if (set_overlay_fmt_out & FmtField)
+ fmt.fmt.win.field = overlay_fmt_out.fmt.win.field;
+ if (options[OptSetOutputOverlayFormat])
+ ret = doioctl(fd, VIDIOC_S_FMT, &fmt, "VIDIOC_S_FMT");
+ else
+ ret = doioctl(fd, VIDIOC_TRY_FMT, &fmt, "VIDIOC_TRY_FMT");
+ if (ret == 0 && verbose)
+ printfmt(fmt);
}
}