meta-digi/meta-digi-dey/recipes-digi/dey-examples/files/v4l2_test/v4l2_preview_test.c

495 lines
12 KiB
C

/*
* v4l2_preview_test.c
*
* Copyright (C) 2012 by Digi International Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* Description: V4L2 preview test application.
*
* Video overlay, framebuffer overlay or previewing stores images directly into
* the video memory of the graphics card. Video overlays are accessible through
* /dev/video after a VIDIOC_S_FMT to overlay (the default for /dev/video is
* video capture).
*
* V4L2 API @ http://v4l2spec.bytesex.org/
*
*/
#include <pthread.h>
#include <sched.h>
#include "v4l2_defs.h"
int verbose = 0;
int fb_fg_fd = -1;
static int should_stop = 0;
static void signal_handler(int signum, siginfo_t * info, void *myact)
{
switch (signum) {
case SIGHUP:
case SIGTERM:
case SIGINT:
should_stop = TRUE;
/* FALLTHROUGH */
default:
log("signal %d caught\n", signum);
break;
}
}
/**
* Prints online help
*
* @fd file to print on
*/
static void printUsage(FILE * fd)
{
fprintf(fd, "V4L2 preview test application.\n\n"
"Usage: v4l_preview_test -d </dev/video0> -o </dev/fb0> -h <height> "
"-w <width> -t <top> -l <left> [-r] [-v] [-?]\n\n"
" -d V4L2 capture device, by default /dev/video0\n"
" -o V4L2 output (framebuffer) device, by default /dev/fb0\n"
" -h Video height in pixels\n"
" -w Video width in pixels\n"
" -t Video top offset in pixels\n"
" -l Video left offset in pixels\n"
" -x Non destructive overlay (do not overwrite framebuffer)\n"
" Setting '-x' discards the output device option '-o' and\n"
" uses the overlay background framebuffer.\n"
" -r RGB565 (default is UYVY)\n"
" -u YUYV (default is UYVY)\n"
" -v Verbose mode\n"
" -? This help\n\n");
}
static void *v4l2_camera_thread(void *pargs)
{
struct fb_fix_screeninfo fb_fix;
struct fb_var_screeninfo fb_var;
ARGUMENTS *args = pargs;
/* Check overlay is supported */
if (!v4l2_is_capability_supported(args->fd_in, V4L2_CAP_VIDEO_OVERLAY)) {
printf("Overlay not supported\n");
return ((void *)-EINVAL);
}
/* Check requested image format is supported by capture device */
if (!v4l2_is_format_supported(args->fd_in, args->options.format)) {
printf("Requested format not supported.\n");
return ((void *)-EINVAL);
}
/* Obtain framebuffer parameters */
if ((args->fd_out = v4l2_fb_get_info(args->fb_device, &fb_fix, &fb_var)) < 0) {
printf("Unable to open %s: %s\n", args->fb_device, strerror(errno));
exit(-1);
}
/* Set video output */
if (v4l2_set_output(args->fd_in, &fb_fix) < 0) {
printf("\nUnable to set current video output.\n");
exit(-1);
}
/* Restore default cropping - no zoom */
v4l2_reset_cropping_rectangle(args->fd_in);
/* Set size in overlay */
v4l2_set_format_overlay(args->fd_in,
args->options.top, args->options.left,
args->options.height, args->options.width);
/* Now the overlay functionality is available */
/* Obtain overlay framebuffer's fd */
v4l2_mxc_find_overlay(&fb_fix, &fb_fg_fd);
/* Draws over the fb (destructive) and sets image format */
v4l2_overlay_set_framebuffer(args->fd_in, &fb_fix, &fb_var,
args->options.non_destructive);
v4l2_overlay_control(args->fd_in, 1);
while (should_stop != TRUE)
sleep(1);
v4l2_overlay_control(args->fd_in, 0);
close(args->fd_in);
close(args->fd_out);
if (fb_fg_fd > 0)
close(fb_fg_fd);
return NULL;
}
static void v4l2_display_menu(int non_destructive)
{
printf("\t[h]display the operation Help\n");
printf("\t[x]eXit\n");
printf("\t[r]Rotate input\n");
printf("\t[b]adjust Brightness\n");
printf("\t[s]adjust Saturation\n");
printf("\t[c]adjust Color balance\n");
printf("\t[z]automatic Zoom\n");
printf("\t[a]zoom Area\n");
if (non_destructive) {
/* These options are only available in non_destructive overlay */
printf("\t[g]set Global transparency\n");
printf("\t[l]set Local transparency\n");
}
printf("\nChoose option: ");
}
static int cmd_rotate(int fd)
{
unsigned int rotate = 0;
printf("Rotation options:\n");
printf("\t0 - No rotation\n");
printf("\t1 - Vertical flip\n");
printf("\t2 - Horizontal flip\n");
printf("\t3 - Rotate 180 degree\n");
printf("\t4 - Rotate 90 degree\n");
printf("\t5 - Rotate 90 degree right and vertical flip\n");
printf("\t6 - Rotate 90 degree right and horizontal flip\n");
printf("\t7 - Rotate 90 degree left\n");
printf("Choose rotation: ");
scanf("%u", &rotate);
if (rotate > 7) {
printf("Invalid value\n");
return -1;
}
return v4l2_rotate(fd, rotate);
}
static int cmd_brightness(int fd)
{
int brightness = 0;
int ret = -1;
/* Read current brightness value */
v4l2_get_brightness(fd, &brightness);
printf("Enter brightness [0-100%%] (current: %u%%): ", brightness);
if ((scanf("%u", &brightness)) != 1 || should_stop) {
return ret;
}
if (brightness > 100 || brightness < 0) {
printf("Brightness value [%d] out of range.\n", brightness);
} else {
ret = v4l2_set_brightness(fd, brightness);
}
return ret;
}
static int cmd_saturation(int fd)
{
int saturation;
int ret = -1;
/* Read current saturation value */
v4l2_get_saturation(fd, &saturation);
printf("Enter saturation (valid values are 0, 25, 37, 50, 75, 100 and 150) [0-150%%] (current: %u%%): ", saturation);
if (scanf("%u", &saturation) != 1 || should_stop)
return ret;
if (saturation > 150 || saturation < 0) {
printf("Saturation value [%d] out of range.\n", saturation);
} else {
ret = v4l2_set_saturation(fd, saturation);
}
return ret;
}
static int cmd_zoom(int fd)
{
int zoom;
int ret = -1;
printf("Enter zooming percentage [100 - 300]%%: ");
if ((scanf("%i", &zoom)) != 1)
return ret;
if (zoom < 100 || zoom > 300) {
printf("Zoom value [%d] out of range.\n", zoom);
} else {
ret = v4l2_zoom(fd, zoom);
}
return ret;
}
static int cmd_area_zoom(int fd)
{
struct v4l2_rect zoom_rectangle;
int ret = -1;
printf("Enter rectangle's values (top, left, width [>=8], height [>=8]): ");
if ((scanf("%d,%d,%d,%d", &zoom_rectangle.top, &zoom_rectangle.left,
&zoom_rectangle.width, &zoom_rectangle.height)) != 4 || should_stop) {
printf("Enter four parameters\n");
return ret;
} else {
ret = v4l2_area_zoom(fd, &zoom_rectangle);
}
return ret;
}
static int cmd_color_balance(int fd, char cmd)
{
int ret = -1;
int red, blue, black;
red = blue = black = 0;
switch (cmd) {
case 'r':
if (v4l2_get_red_balance(fd, &red) < 0) {
printf("\n[ERROR] Unable to get Red balance\n\n");
} else {
printf("Enter Red balance value (current: %d): ", red);
scanf("%u", &red);
ret = v4l2_set_red_balance(fd, red);
}
break;
case 'b':
if (v4l2_get_blue_balance(fd, &blue) < 0) {
printf("\n[ERROR] Unable to get Blue balance\n\n");
} else {
printf("Enter Blue balance value (current: %d): ", blue);
scanf("%u", &blue);
ret = v4l2_set_blue_balance(fd, blue);
}
break;
case 'w':
printf("\nNot implemented (yet...)\n\n");
break;
case 'l':
if (v4l2_get_black_level(fd, &black) < 0) {
printf("\n[ERROR] Unable to get Black level\n\n");
} else {
printf("Enter Black level value (current: %d): ", black);
scanf("%u", &black);
ret = v4l2_set_black_level(fd, black);
}
break;
default:
break;
}
return ret;
}
static int cmd_global_alpha(int fd)
{
int ret = -1;
int alpha_value;
printf("Enter alpha_value global transparency [0-100%%]: ");
if (scanf("%d", &alpha_value) != 1 || should_stop)
return ret;
if (alpha_value > 100 || alpha_value < 0) {
printf("Alpha value [%d] out of range.\n", alpha_value);
return ret;
}
ret = v4l2_global_alpha_set(fd, 1, alpha_value);
return ret;
}
static int cmd_local_alpha(ARGUMENTS * args)
{
int ret = -1;
struct v4l2_rect alpha_rectangle;
int alpha_value;
printf("Enter rectangle's values (top, left, width, height): ");
if ((scanf("%d,%d,%d,%d", &alpha_rectangle.top, &alpha_rectangle.left,
&alpha_rectangle.width, &alpha_rectangle.height)) != 4 || should_stop) {
printf("Enter four parameters\n");
return ret;
} else {
printf("Enter rectangle's transparency [0-100%%]: ");
if (scanf("%d", &alpha_value) != 1 || should_stop)
return ret;
if (alpha_value > 100 || alpha_value < 0) {
printf("Alpha value [%d] out of range.\n", alpha_value);
return ret;
}
ret = v4l2_local_alpha_set(args, fb_fg_fd, &alpha_rectangle, alpha_value);
}
return ret;
}
static void display_color_balance_menu(void)
{
printf("Color balance:\n");
printf("\t[r]adjust Red balance\n");
printf("\t[b]adjust Blue balance\n");
printf("\t[w]adjust White balance\n");
printf("\t[l]adjust bLack level\n");
printf("Choose option: ");
}
int main(int argc, char **argv)
{
int opt;
int retval = 0;
ARGUMENTS args;
pthread_t v4l2_camera_th;
int ret = 0;
char cmd[64] = "";
struct sigaction act;
char fb_device_flag = 0; /* fb_device set in command line */
/* Signal handling */
memset(&act, 0, sizeof(struct sigaction));
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = signal_handler;
if ((ret = sigaction(SIGINT, &act, NULL)) < 0) {
log("Signal installation error: %d\n", SIGINT);
return -1;
}
/* Initialize options */
memset(&args, 0, sizeof(args));
args.options.width = 640;
args.options.height = 480;
args.options.format = V4L2_PIX_FMT_UYVY;
strcpy(args.fb_device, "/dev/fb0");
strcpy(args.v4l2_device, "/dev/video0");
/* Input processing */
while ((opt = getopt(argc, argv, "w:d:h:l:t:o:xvru?")) != -1) {
switch (opt) {
case '?':
printUsage(stderr);
return 1;
case 'd':
strncpy(args.v4l2_device, optarg, sizeof(args.v4l2_device) - 1);
args.v4l2_device[sizeof(args.v4l2_device) - 1] = '\0';
break;
case 'w':
args.options.width = atoi(optarg);
break;
case 't':
args.options.top = atoi(optarg);
break;
case 'l':
args.options.left = atoi(optarg);
break;
case 'h':
args.options.height = atoi(optarg);
break;
case 'o':
strncpy(args.fb_device, optarg, sizeof(args.fb_device) - 1);
args.fb_device[sizeof(args.fb_device) - 1] = '\0';
fb_device_flag = 1;
break;
case 'r':
args.options.format = V4L2_PIX_FMT_RGB565;
break;
case 'u':
args.options.format = V4L2_PIX_FMT_YUYV;
break;
case 'x':
args.options.non_destructive = 1;
break;
case 'v':
verbose = 1;
break;
}
}
/* Input validation */
if (args.options.height == 0 || args.options.width == 0) {
printf("Invalid input: Display height and width cannot be zero.\n");
exit(-EINVAL);
}
if (args.options.non_destructive) {
if (fb_device_flag) {
printf("\n[WARNING] The application will discard '-o' option and use"
" the overlay background framebuffer device.\n");
}
if (v4l2_get_overlay_bg(args.fb_device) < 0) {
printf("Unable to find overlay background framebuffer device\n");
exit(-1);
}
}
printf("\nVideo height %d width %d top %d left %d\n\n",
args.options.height, args.options.width, args.options.top, args.options.left);
/* Open input device */
if ((args.fd_in = open(args.v4l2_device, O_RDWR, 0)) < 0) {
printf("Unable to open %s: %s\n", args.v4l2_device, strerror(errno));
exit(-1);
}
log("Opened %s\n", args.v4l2_device);
log("V4L2 preview test application started.\n");
if (pthread_create(&v4l2_camera_th, NULL, v4l2_camera_thread, (void *)&args)) {
exit(-1);
}
while (should_stop != TRUE) {
v4l2_display_menu(args.options.non_destructive);
cmd[0] = ' ';
errno = 0;
scanf("%s", cmd);
switch (cmd[0]) {
case 'x': /* Exit */
should_stop = TRUE;
break;
case 'h': /* Help */
/* Nothing to do, as the help is shown in each iteration */
break;
case 'r':
cmd_rotate(args.fd_in);
break;
case 'b':
cmd_brightness(args.fd_in);
break;
case 's':
cmd_saturation(args.fd_in);
break;
case 'z':
cmd_zoom(args.fd_in);
break;
case 'a':
cmd_area_zoom(args.fd_in);
break;
case 'c':
display_color_balance_menu();
scanf("%s", cmd);
cmd_color_balance(args.fd_in, cmd[0]);
break;
case 'g':
if (args.options.non_destructive)
cmd_global_alpha(args.fd_out);
break;
case 'l':
if (args.options.non_destructive)
cmd_local_alpha(&args);
break;
default:
break;
}
}
if (pthread_join(v4l2_camera_th, NULL)) {
exit(-1);
}
log("V4L2 preview test application finished.\n");
return retval;
}