From c81889b6030fa1326e06dc47e0eadc8f4fbb1d2a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 11 Apr 2013 10:23:45 +0200 Subject: [PATCH] v4l2-ctl: split off test pattern generation in a separate source. A lot more test patterns are planned, so having this in a separate source simplified development. Signed-off-by: Hans Verkuil --- utils/v4l2-ctl/Makefile.am | 2 +- utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 290 +---------------------------- utils/v4l2-ctl/v4l2-ctl-test-patterns.cpp | 299 ++++++++++++++++++++++++++++++ utils/v4l2-ctl/v4l2-ctl.h | 4 + 4 files changed, 305 insertions(+), 290 deletions(-) create mode 100644 utils/v4l2-ctl/v4l2-ctl-test-patterns.cpp diff --git a/utils/v4l2-ctl/Makefile.am b/utils/v4l2-ctl/Makefile.am index bfcb6fe..b5744e7 100644 --- a/utils/v4l2-ctl/Makefile.am +++ b/utils/v4l2-ctl/Makefile.am @@ -8,5 +8,5 @@ ivtv_ctl_LDFLAGS = -lm v4l2_ctl_SOURCES = v4l2-ctl.cpp v4l2-ctl.h v4l2-ctl-common.cpp v4l2-ctl-tuner.cpp \ v4l2-ctl-io.cpp v4l2-ctl-stds.cpp v4l2-ctl-vidcap.cpp v4l2-ctl-vidout.cpp \ v4l2-ctl-overlay.cpp v4l2-ctl-vbi.cpp v4l2-ctl-selection.cpp v4l2-ctl-misc.cpp \ - v4l2-ctl-streaming.cpp + v4l2-ctl-streaming.cpp v4l2-ctl-test-patterns.cpp v4l2_ctl_LDADD = ../../lib/libv4l2/libv4l2.la ../../lib/libv4lconvert/libv4lconvert.la diff --git a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp index 42c35eb..c340f08 100644 --- a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp +++ b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp @@ -31,8 +31,6 @@ static unsigned reqbufs_count_out = 3; static char *file_cap; static char *file_out; -#define NUM_PATTERNS (4) - void streaming_usage(void) { printf("\nVideo Streaming options:\n" @@ -197,7 +195,6 @@ void streaming_cmd(int ch, char *optarg) break; case OptStreamPattern: stream_pat = strtoul(optarg, 0L, 0); - stream_pat %= NUM_PATTERNS; break; case OptStreamTo: file_cap = optarg; @@ -225,291 +222,6 @@ void streaming_cmd(int ch, char *optarg) } } -/* Note: the code to create the test patterns is derived from the vivi.c kernel - driver. */ - -/* Bars and Colors should match positions */ - -enum colors { - WHITE, - AMBER, - CYAN, - GREEN, - MAGENTA, - RED, - BLUE, - BLACK, - TEXT_BLACK, -}; - -/* R G B */ -#define COLOR_WHITE {204, 204, 204} -#define COLOR_AMBER {208, 208, 0} -#define COLOR_CYAN { 0, 206, 206} -#define COLOR_GREEN { 0, 239, 0} -#define COLOR_MAGENTA {239, 0, 239} -#define COLOR_RED {205, 0, 0} -#define COLOR_BLUE { 0, 0, 205} -#define COLOR_BLACK { 0, 0, 0} - -struct bar_std { - __u8 bar[9][3]; -}; - -static struct bar_std bars[NUM_PATTERNS] = { - { /* Standard ITU-R color bar sequence */ - { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN, - COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK } - }, { - { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, - COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK } - }, { - { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, - COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK } - }, { - { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, - COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK } - }, -}; - -#define TO_Y(r, g, b) \ - (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16) -/* RGB to V(Cr) Color transform */ -#define TO_V(r, g, b) \ - (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128) -/* RGB to U(Cb) Color transform */ -#define TO_U(r, g, b) \ - (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) - -static __u8 calc_bars[9][3]; -static int pixel_size; - -/* precalculate color bar values to speed up rendering */ -static bool precalculate_bars(__u32 pixfmt, int pattern) -{ - __u8 r, g, b; - int k, is_yuv; - - pixel_size = 2; - for (k = 0; k < 9; k++) { - r = bars[pattern].bar[k][0]; - g = bars[pattern].bar[k][1]; - b = bars[pattern].bar[k][2]; - is_yuv = 0; - - switch (pixfmt) { - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_VYUY: - is_yuv = 1; - break; - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - r >>= 3; - g >>= 2; - b >>= 3; - break; - case V4L2_PIX_FMT_RGB555: - case V4L2_PIX_FMT_RGB555X: - r >>= 3; - g >>= 3; - b >>= 3; - break; - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - pixel_size = 3; - break; - case V4L2_PIX_FMT_RGB32: - case V4L2_PIX_FMT_BGR32: - pixel_size = 4; - break; - default: - return false; - } - - if (is_yuv) { - calc_bars[k][0] = TO_Y(r, g, b); /* Luma */ - calc_bars[k][1] = TO_U(r, g, b); /* Cb */ - calc_bars[k][2] = TO_V(r, g, b); /* Cr */ - } else { - calc_bars[k][0] = r; - calc_bars[k][1] = g; - calc_bars[k][2] = b; - } - } - return true; -} - -/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */ -static void gen_twopix(__u8 *buf, __u32 pixfmt, int colorpos, bool odd) -{ - __u8 r_y, g_u, b_v; - int color; - - r_y = calc_bars[colorpos][0]; /* R or precalculated Y */ - g_u = calc_bars[colorpos][1]; /* G or precalculated U */ - b_v = calc_bars[colorpos][2]; /* B or precalculated V */ - - for (color = 0; color < pixel_size; color++) { - __u8 *p = buf + color; - - switch (pixfmt) { - case V4L2_PIX_FMT_YUYV: - switch (color) { - case 0: - *p = r_y; - break; - case 1: - *p = odd ? b_v : g_u; - break; - } - break; - case V4L2_PIX_FMT_UYVY: - switch (color) { - case 0: - *p = odd ? b_v : g_u; - break; - case 1: - *p = r_y; - break; - } - break; - case V4L2_PIX_FMT_YVYU: - switch (color) { - case 0: - *p = r_y; - break; - case 1: - *p = odd ? g_u : b_v; - break; - } - break; - case V4L2_PIX_FMT_VYUY: - switch (color) { - case 0: - *p = odd ? g_u : b_v; - break; - case 1: - *p = r_y; - break; - } - break; - case V4L2_PIX_FMT_RGB565: - switch (color) { - case 0: - *p = (g_u << 5) | b_v; - break; - case 1: - *p = (r_y << 3) | (g_u >> 3); - break; - } - break; - case V4L2_PIX_FMT_RGB565X: - switch (color) { - case 0: - *p = (r_y << 3) | (g_u >> 3); - break; - case 1: - *p = (g_u << 5) | b_v; - break; - } - break; - case V4L2_PIX_FMT_RGB555: - switch (color) { - case 0: - *p = (g_u << 5) | b_v; - break; - case 1: - *p = (r_y << 2) | (g_u >> 3); - break; - } - break; - case V4L2_PIX_FMT_RGB555X: - switch (color) { - case 0: - *p = (r_y << 2) | (g_u >> 3); - break; - case 1: - *p = (g_u << 5) | b_v; - break; - } - break; - case V4L2_PIX_FMT_RGB24: - switch (color) { - case 0: - *p = r_y; - break; - case 1: - *p = g_u; - break; - case 2: - *p = b_v; - break; - } - break; - case V4L2_PIX_FMT_BGR24: - switch (color) { - case 0: - *p = b_v; - break; - case 1: - *p = g_u; - break; - case 2: - *p = r_y; - break; - } - break; - case V4L2_PIX_FMT_RGB32: - switch (color) { - case 0: - *p = 0; - break; - case 1: - *p = r_y; - break; - case 2: - *p = g_u; - break; - case 3: - *p = b_v; - break; - } - break; - case V4L2_PIX_FMT_BGR32: - switch (color) { - case 0: - *p = b_v; - break; - case 1: - *p = g_u; - break; - case 2: - *p = r_y; - break; - case 3: - *p = 0; - break; - } - break; - } - } -} - -static void fill_buffer(void *buffer, struct v4l2_pix_format *pix) -{ - for (unsigned y = 0; y < pix->height; y++) { - __u8 *ptr = (__u8 *)buffer + y * pix->bytesperline; - - for (unsigned x = 0; x < pix->width; x++) { - int colorpos = x / (pix->width / 8) % 8; - - gen_twopix(ptr + x * pixel_size, pix->pixelformat, colorpos, x & 1); - } - } -} - static bool fill_buffer_from_file(void *buffers[], unsigned buffer_lengths[], unsigned buf_index, unsigned num_planes, FILE *fin) { @@ -605,7 +317,7 @@ static void do_setup_out_buffers(int fd, struct v4l2_requestbuffers *reqbufs, fmt.type = reqbufs->type; doioctl(fd, VIDIOC_G_FMT, &fmt); - if (!precalculate_bars(fmt.fmt.pix.pixelformat, stream_pat % NUM_PATTERNS)) { + if (!precalculate_bars(fmt.fmt.pix.pixelformat, stream_pat)) { fprintf(stderr, "unsupported pixelformat\n"); return; } diff --git a/utils/v4l2-ctl/v4l2-ctl-test-patterns.cpp b/utils/v4l2-ctl/v4l2-ctl-test-patterns.cpp new file mode 100644 index 0000000..f7aebac --- /dev/null +++ b/utils/v4l2-ctl/v4l2-ctl-test-patterns.cpp @@ -0,0 +1,299 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include "v4l2-ctl.h" + +#define NUM_PATTERNS (4) + + +/* Note: the code to create the test patterns is derived from the vivi.c kernel + driver. */ + +/* Bars and Colors should match positions */ + +enum colors { + WHITE, + AMBER, + CYAN, + GREEN, + MAGENTA, + RED, + BLUE, + BLACK, + TEXT_BLACK, +}; + +/* R G B */ +#define COLOR_WHITE {204, 204, 204} +#define COLOR_AMBER {208, 208, 0} +#define COLOR_CYAN { 0, 206, 206} +#define COLOR_GREEN { 0, 239, 0} +#define COLOR_MAGENTA {239, 0, 239} +#define COLOR_RED {205, 0, 0} +#define COLOR_BLUE { 0, 0, 205} +#define COLOR_BLACK { 0, 0, 0} + +struct bar_std { + __u8 bar[9][3]; +}; + +static struct bar_std bars[NUM_PATTERNS] = { + { /* Standard ITU-R color bar sequence */ + { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN, + COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK } + }, { + { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, + COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK } + }, { + { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, + COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK } + }, { + { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, + COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK } + }, +}; + +#define TO_Y(r, g, b) \ + (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16) +/* RGB to V(Cr) Color transform */ +#define TO_V(r, g, b) \ + (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128) +/* RGB to U(Cb) Color transform */ +#define TO_U(r, g, b) \ + (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) + +static __u8 calc_bars[9][3]; +static int pixel_size; + +/* precalculate color bar values to speed up rendering */ +bool precalculate_bars(__u32 pixfmt, unsigned pattern) +{ + __u8 r, g, b; + int k, is_yuv; + + pattern %= NUM_PATTERNS; + pixel_size = 2; + for (k = 0; k < 9; k++) { + r = bars[pattern].bar[k][0]; + g = bars[pattern].bar[k][1]; + b = bars[pattern].bar[k][2]; + is_yuv = 0; + + switch (pixfmt) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + is_yuv = 1; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + r >>= 3; + g >>= 2; + b >>= 3; + break; + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB555X: + r >>= 3; + g >>= 3; + b >>= 3; + break; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + pixel_size = 3; + break; + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: + pixel_size = 4; + break; + default: + return false; + } + + if (is_yuv) { + calc_bars[k][0] = TO_Y(r, g, b); /* Luma */ + calc_bars[k][1] = TO_U(r, g, b); /* Cb */ + calc_bars[k][2] = TO_V(r, g, b); /* Cr */ + } else { + calc_bars[k][0] = r; + calc_bars[k][1] = g; + calc_bars[k][2] = b; + } + } + return true; +} + +/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */ +static void gen_twopix(__u8 *buf, __u32 pixfmt, int colorpos, bool odd) +{ + __u8 r_y, g_u, b_v; + int color; + + r_y = calc_bars[colorpos][0]; /* R or precalculated Y */ + g_u = calc_bars[colorpos][1]; /* G or precalculated U */ + b_v = calc_bars[colorpos][2]; /* B or precalculated V */ + + for (color = 0; color < pixel_size; color++) { + __u8 *p = buf + color; + + switch (pixfmt) { + case V4L2_PIX_FMT_YUYV: + switch (color) { + case 0: + *p = r_y; + break; + case 1: + *p = odd ? b_v : g_u; + break; + } + break; + case V4L2_PIX_FMT_UYVY: + switch (color) { + case 0: + *p = odd ? b_v : g_u; + break; + case 1: + *p = r_y; + break; + } + break; + case V4L2_PIX_FMT_YVYU: + switch (color) { + case 0: + *p = r_y; + break; + case 1: + *p = odd ? g_u : b_v; + break; + } + break; + case V4L2_PIX_FMT_VYUY: + switch (color) { + case 0: + *p = odd ? g_u : b_v; + break; + case 1: + *p = r_y; + break; + } + break; + case V4L2_PIX_FMT_RGB565: + switch (color) { + case 0: + *p = (g_u << 5) | b_v; + break; + case 1: + *p = (r_y << 3) | (g_u >> 3); + break; + } + break; + case V4L2_PIX_FMT_RGB565X: + switch (color) { + case 0: + *p = (r_y << 3) | (g_u >> 3); + break; + case 1: + *p = (g_u << 5) | b_v; + break; + } + break; + case V4L2_PIX_FMT_RGB555: + switch (color) { + case 0: + *p = (g_u << 5) | b_v; + break; + case 1: + *p = (r_y << 2) | (g_u >> 3); + break; + } + break; + case V4L2_PIX_FMT_RGB555X: + switch (color) { + case 0: + *p = (r_y << 2) | (g_u >> 3); + break; + case 1: + *p = (g_u << 5) | b_v; + break; + } + break; + case V4L2_PIX_FMT_RGB24: + switch (color) { + case 0: + *p = r_y; + break; + case 1: + *p = g_u; + break; + case 2: + *p = b_v; + break; + } + break; + case V4L2_PIX_FMT_BGR24: + switch (color) { + case 0: + *p = b_v; + break; + case 1: + *p = g_u; + break; + case 2: + *p = r_y; + break; + } + break; + case V4L2_PIX_FMT_RGB32: + switch (color) { + case 0: + *p = 0; + break; + case 1: + *p = r_y; + break; + case 2: + *p = g_u; + break; + case 3: + *p = b_v; + break; + } + break; + case V4L2_PIX_FMT_BGR32: + switch (color) { + case 0: + *p = b_v; + break; + case 1: + *p = g_u; + break; + case 2: + *p = r_y; + break; + case 3: + *p = 0; + break; + } + break; + } + } +} + +void fill_buffer(void *buffer, struct v4l2_pix_format *pix) +{ + for (unsigned y = 0; y < pix->height; y++) { + __u8 *ptr = (__u8 *)buffer + y * pix->bytesperline; + + for (unsigned x = 0; x < pix->width; x++) { + int colorpos = x / (pix->width / 8) % 8; + + gen_twopix(ptr + x * pixel_size, pix->pixelformat, colorpos, x & 1); + } + } +} diff --git a/utils/v4l2-ctl/v4l2-ctl.h b/utils/v4l2-ctl/v4l2-ctl.h index 146dbe7..29898bd 100644 --- a/utils/v4l2-ctl/v4l2-ctl.h +++ b/utils/v4l2-ctl/v4l2-ctl.h @@ -277,4 +277,8 @@ void streaming_cmd(int ch, char *optarg); void streaming_set(int fd); void streaming_list(int fd); +// v4l2-ctl-test-patterns.cpp +void fill_buffer(void *buffer, struct v4l2_pix_format *pix); +bool precalculate_bars(__u32 pixfmt, unsigned pattern); + #endif -- 2.7.4