diff options
author | Michael Krufky <mkrufky@linuxtv.org> | 2008-09-25 08:37:12 -0400 |
---|---|---|
committer | Michael Krufky <mkrufky@linuxtv.org> | 2008-09-25 08:37:12 -0400 |
commit | 7e39de54b4ed06bb2ababbe72b16f195d796d8f0 (patch) | |
tree | 5a74da414f5b1aaa78712988a989a00a94736648 /v4l2-apps | |
parent | 968c43076f37c9f65df65fe50a1c643a82b1192b (diff) | |
parent | 9385e4874ef72f62d77800fe2eb47429d0854125 (diff) | |
download | mediapointer-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/ChangeLog | 14 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/Makefile | 2 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/include/libv4lconvert.h | 10 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4l1/libv4l1.c | 15 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4l1/log.c | 6 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4l2/libv4l2.c | 24 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c | 15 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h | 34 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c | 239 | ||||
-rw-r--r-- | v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c | 170 | ||||
-rw-r--r-- | v4l2-apps/util/v4l2-ctl.cpp | 336 |
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); } } |