Re: [patch] libv4l2: SDL test application

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Pavel,

On 10/28/2017 09:57 PM, Pavel Machek wrote:
> Add support for simple SDL test application. Allows taking jpeg
> snapshots, and is meant to run on phone with touchscreen. Not
> particulary useful on PC with webcam, but should work.

When I try to build this I get:

make[3]: Entering directory '/home/hans/work/src/v4l/v4l-utils/contrib/test'
  CCLD     sdlcam
/usr/bin/ld: sdlcam-sdlcam.o: undefined reference to symbol 'log2@@GLIBC_2.2.5'
//lib/x86_64-linux-gnu/libm.so.6: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
Makefile:561: recipe for target 'sdlcam' failed
make[3]: *** [sdlcam] Error 1
make[3]: Leaving directory '/home/hans/work/src/v4l/v4l-utils/contrib/test'
Makefile:475: recipe for target 'all-recursive' failed
make[2]: *** [all-recursive] Error 1
make[2]: Leaving directory '/home/hans/work/src/v4l/v4l-utils/contrib'
Makefile:589: recipe for target 'all-recursive' failed
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory '/home/hans/work/src/v4l/v4l-utils'
Makefile:516: recipe for target 'all' failed
make: *** [all] Error 2

I had to add -lm -ldl -lrt to sdlcam_LDFLAGS. Is that correct?

Regards,

	Hans

> 
> Signed-off-by: Pavel Machek <pavel@xxxxxx>
> 
> diff --git a/configure.ac b/configure.ac
> index f3691be..f6540c2 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -439,6 +439,9 @@ AC_ARG_ENABLE(gconv,
>     esac]
>  )
>  
> +PKG_CHECK_MODULES([SDL2], [sdl2 SDL2_image], [sdl_pc=yes], [sdl_pc=no])
> +AM_CONDITIONAL([HAVE_SDL], [test x$sdl_pc = xyes])
> +
>  # Check if backtrace functions are defined
>  AC_SEARCH_LIBS([backtrace], [execinfo], [
>    AC_DEFINE(HAVE_BACKTRACE, [1], [glibc has functions to provide stack backtrace])
> @@ -507,6 +510,7 @@ compile time options summary
>      pthread                    : $have_pthread
>      QT version                 : $QT_VERSION
>      ALSA support               : $USE_ALSA
> +    SDL support		       : $sdl_pc
>  
>      build dynamic libs         : $enable_shared
>      build static libs          : $enable_static
> diff --git a/contrib/test/Makefile.am b/contrib/test/Makefile.am
> index 4641e21..0f97ce2 100644
> --- a/contrib/test/Makefile.am
> +++ b/contrib/test/Makefile.am
> @@ -16,6 +16,10 @@ if HAVE_GLU
>  noinst_PROGRAMS += v4l2gl
>  endif
>  
> +if HAVE_SDL
> +noinst_PROGRAMS += sdlcam
> +endif
> +
>  driver_test_SOURCES = driver-test.c
>  driver_test_LDADD = ../../utils/libv4l2util/libv4l2util.la
>  
> @@ -31,6 +35,10 @@ v4l2gl_SOURCES = v4l2gl.c
>  v4l2gl_LDFLAGS = $(X11_LIBS) $(GL_LIBS) $(GLU_LIBS) $(ARGP_LIBS)
>  v4l2gl_LDADD = ../../lib/libv4l2/libv4l2.la ../../lib/libv4lconvert/libv4lconvert.la
>  
> +sdlcam_LDFLAGS = $(JPEG_LIBS) $(SDL2_LIBS)
> +sdlcam_CFLAGS = -I../.. $(SDL2_CFLAGS)
> +sdlcam_LDADD = ../../lib/libv4l2/.libs/libv4l2.a  ../../lib/libv4lconvert/.libs/libv4lconvert.a
> +
>  mc_nextgen_test_CFLAGS = $(LIBUDEV_CFLAGS)
>  mc_nextgen_test_LDFLAGS = $(LIBUDEV_LIBS)
>  
> diff --git a/contrib/test/sdlcam.c b/contrib/test/sdlcam.c
> new file mode 100644
> index 0000000..cc43a10
> --- /dev/null
> +++ b/contrib/test/sdlcam.c
> @@ -0,0 +1,1250 @@
> +/*
> +   Digital still camera.
> +
> +   SDL based, suitable for camera phone such as Nokia N900. In
> +   particular, we support focus, gain and exposure control, but not
> +   aperture control or lens zoom.
> +
> +   Copyright 2017 Pavel Machek, LGPL
> +
> +   Needs sdl2, sdl2_image libraries. sudo aptitude install libsdl2-dev
> +   libsdl2-image-dev on Debian systems.
> +*/
> +
> +#include <time.h>
> +#include <errno.h>
> +#include <stdarg.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/mman.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/time.h>
> +#include <sys/ioctl.h>
> +#include <fcntl.h>
> +
> +#include <jpeglib.h>
> +
> +#include "libv4l2.h"
> +#include <linux/videodev2.h>
> +#include "libv4l-plugin.h"
> +
> +#include <SDL2/SDL.h>
> +#include <SDL2/SDL_image.h>
> +
> +#define PICDIR "."
> +#define SX 2592
> +#define SY 1968
> +#define SIZE SX*SY*3
> +
> +static void fmt_print(struct v4l2_format *fmt)
> +{
> +	int f;
> +	printf("Format: %dx%d. ", fmt->fmt.pix.width, fmt->fmt.pix.height);
> +	printf("%x ", fmt->fmt.pix.pixelformat);
> +	f = fmt->fmt.pix.pixelformat;
> +	for (int i=0; i<4; i++) {
> +		printf("%c", f & 0xff);
> +		f >>= 8;
> +	}
> +	printf("\n");
> +}
> +
> +static double dtime(void)
> +{
> +	static double start = 0.0;
> +	struct timeval now;
> +
> +	gettimeofday(&now, NULL);
> +
> +	double n = now.tv_sec + now.tv_usec / 1000000.;
> +	if (!start)
> +		start = n;
> +	return n - start;
> +}
> +
> +static long v4l2_g_ctrl(int fd, long id)
> +{
> +	int res;
> +	struct v4l2_control ctrl;
> +	ctrl.id = id;
> +	ctrl.value = 0;
> +	res = v4l2_ioctl(fd, VIDIOC_G_CTRL, &ctrl);
> +	if (res < 0)
> +		printf("Get control %lx failed\n", id);
> +	return ctrl.value;
> +}
> +
> +static int v4l2_s_ctrl(int fd, long id, long value)
> +{
> +	int res;
> +	struct v4l2_control ctrl;
> +	ctrl.id = id;
> +	ctrl.value = value;
> +	res = v4l2_ioctl(fd, VIDIOC_S_CTRL, &ctrl);
> +	if (res < 0)
> +		printf("Set control %lx %ld failed\n", id, value);
> +	return res;
> +}
> +
> +static int v4l2_set_focus(int fd, int diopt)
> +{
> +	if (v4l2_s_ctrl(fd, V4L2_CID_FOCUS_ABSOLUTE, diopt) < 0) {
> +		printf("Could not set focus\n");
> +	}
> +	return 0;
> +}
> +
> +struct dev_info {
> +	int fd;
> +	struct v4l2_format fmt;
> +
> +	unsigned char buf[SIZE];
> +	int debug;
> +#define D_TIMING 1
> +};
> +
> +struct sdl {
> +	SDL_Window *window;
> +	SDL_Surface *screen, *liveview;
> +
> +	int wx, wy; /* Window size */
> +	int sx, sy; /* Live view size */
> +	int bx, by; /* Border size */
> +	int nx, ny; /* Number of buttons */
> +	float factor;
> +
> +	/* These should go separately */
> +	int do_focus, do_exposure, do_flash, do_white, do_big, do_full;
> +	double zoom;
> +	double focus_min;
> +
> +	int slider_mode;
> +#define M_BIAS 0
> +#define M_EXPOSURE 1
> +#define M_GAIN 2
> +#define M_FOCUS 3
> +#define M_NUM 4
> +
> +	int fd;
> +
> +	struct dev_info *dev;
> +};
> +
> +typedef struct {
> +	uint8_t r, g, b, alpha;
> +} pixel;
> +
> +#define d_raw 1
> +
> +static void sfc_put_pixel(SDL_Surface* liveview, int x, int y, pixel *p)
> +{
> +	Uint32* p_liveview = (Uint32*)liveview->pixels;
> +	p_liveview += y*liveview->w+x;
> +	*p_liveview = SDL_MapRGBA(liveview->format, p->r, p->g, p->b, p->alpha);
> +}
> +
> +static void sdl_begin_paint(struct sdl *m)
> +{
> +	/* Fill the surface white */
> +	SDL_FillRect(m->liveview, NULL, SDL_MapRGB( m->liveview->format, 0, 0, 0 ));
> +
> +	SDL_LockSurface(m->liveview);
> +}
> +
> +static void sdl_finish_paint(struct sdl *m) {
> +	SDL_UnlockSurface(m->liveview);
> +	SDL_Rect rcDest = { m->bx, m->by, m->sx, m->sy };
> +
> +	SDL_BlitSurface(m->liveview, NULL, m->screen, &rcDest);
> +	SDL_UpdateWindowSurfaceRects(m->window, &rcDest, 1);
> +}
> +
> +static void sdl_paint_image(struct sdl *m, char **xpm, int x, int y) {
> +	SDL_Surface *image = IMG_ReadXPMFromArray(xpm);
> +	if (!image) {
> +		printf("IMG_Load: %s\n", IMG_GetError());
> +		exit(1);
> +	}
> +
> +	int x_pos = x - image->w/2, y_pos = y - image->h/2;
> +
> +	SDL_Rect rcDest = { x_pos, y_pos, image->w, image->h };
> +	int r = SDL_BlitSurface(image, NULL, m->screen, &rcDest);
> +
> +	if (r) {
> +		printf("Error blitting: %s\n", SDL_GetError());
> +		exit(1);
> +	}
> +	SDL_FreeSurface(image);
> +}
> +
> +static void cam_exposure_limits(struct sdl *m, struct v4l2_queryctrl *qctrl)
> +{
> +	qctrl->id = V4L2_CID_EXPOSURE_ABSOLUTE;
> +
> +	if (v4l2_ioctl(m->fd, VIDIOC_QUERYCTRL, qctrl)) {
> +		printf("Exposure absolute limits failed\n");
> +		exit(1);
> +	}
> +
> +	/* Minimum of 11300 gets approximately same range on ISO and
> +	 * exposure axis. */
> +	if (qctrl->minimum < 500)
> +		qctrl->minimum = 500;
> +}
> +
> +static void cam_set_exposure(struct sdl *m, double v)
> +{
> +	int cid = V4L2_CID_EXPOSURE_ABSOLUTE;
> +	double res;
> +	double range;
> +	struct v4l2_queryctrl qctrl = { .id = cid };
> +	struct v4l2_control ctrl = { .id = cid };
> +
> +	cam_exposure_limits(m, &qctrl);
> +
> +	if (v4l2_ioctl(m->fd, VIDIOC_G_CTRL, &ctrl)) {
> +		printf("Can't get exposure parameters\n");
> +		exit(1);
> +	}
> +
> +	range = log2(qctrl.maximum) - log2(qctrl.minimum);
> +	res = log2(qctrl.minimum) + v*range;
> +	res = exp2(res);
> +
> +	v4l2_s_ctrl(m->fd, V4L2_CID_EXPOSURE_ABSOLUTE, res);
> +}
> +
> +static double cam_convert_exposure(struct sdl *m, int v)
> +{
> +	int cid = V4L2_CID_EXPOSURE_ABSOLUTE;
> +	double res;
> +	struct v4l2_queryctrl qctrl = { .id = cid };
> +
> +	cam_exposure_limits(m, &qctrl);
> +	res = (log2(v) - log2(qctrl.minimum)) / (log2(qctrl.maximum) - log2(qctrl.minimum));
> +
> +	return res;
> +}
> +
> +static double cam_get_exposure(struct sdl *m)
> +{
> +	int cid = V4L2_CID_EXPOSURE_ABSOLUTE;
> +	struct v4l2_control ctrl = { .id = cid };
> +
> +	if (v4l2_ioctl(m->fd, VIDIOC_G_CTRL, &ctrl))
> +		return -1;
> +
> +	return cam_convert_exposure(m, ctrl.value);
> +}
> +
> +static int cam_get_gain_iso(struct dev_info *dev)
> +{
> +	double x;
> +
> +	x = v4l2_g_ctrl(dev->fd, 0x00980913);
> +	x = (x / 10); /* EV */
> +	x = exp2(x);
> +	x = 100*x;
> +	return x;
> +}
> +
> +static void cam_set_focus(struct sdl *m, double val)
> +{
> +	v4l2_s_ctrl(m->fd, V4L2_CID_FOCUS_ABSOLUTE, (val * m->focus_min) * (1023. / 20));
> +}
> +
> +static double cam_convert_focus(struct sdl *m, double diopter)
> +{
> +	return diopter / m->focus_min;
> +}
> +
> +static double cam_get_focus_diopter(struct sdl *m)
> +{
> +	return (v4l2_g_ctrl(m->fd, V4L2_CID_FOCUS_ABSOLUTE) * 20.) / 1023.;
> +}
> +
> +static double cam_get_focus(struct sdl *m)
> +{
> +	return cam_convert_focus(m, cam_get_focus_diopter(m));
> +}
> +
> +static void sdl_line_color(struct sdl *m, int x1, int y1, int x2, int y2, Uint32 color)
> +{
> +	SDL_Rect rcDest = { x1, y1, x2-x1+1, y2-y1+1};
> +
> +	SDL_FillRect(m->screen, &rcDest, color);
> +}
> +
> +static void sdl_line(struct sdl *m, int x1, int y1, int x2, int y2)
> +{
> +	sdl_line_color(m, x1, y1, x2, y2, SDL_MapRGB( m->liveview->format, 255, 255, 255 ));
> +}
> +
> +static void sdl_digit(struct sdl *m, int x, int y, int s, int i)
> +{
> +	unsigned char gr[] = { 0x5f, 0x0a, 0x76, 0x7a, 0x2b,
> +			       0x79, 0x7d, 0x1a, 0x7f, 0x7b };
> +	unsigned char g = gr[i];
> +	/*
> +              10
> +	    01  02
> +              20
> +            04  08
> +	      40
> +	*/
> +
> +	if (g & 1) sdl_line(m, x, y, x, y+s);
> +	if (g & 2) sdl_line(m, x+s, y, x+s, y+s);
> +	if (g & 4) sdl_line(m, x, y+s, x, y+s+s);
> +	if (g & 8) sdl_line(m, x+s, y+s, x+s, y+s+s);
> +
> +	if (g & 0x10) sdl_line(m, x, y, x+s, y);
> +	if (g & 0x20) sdl_line(m, x, y+s, x+s, y+s);
> +	if (g & 0x40) sdl_line(m, x, y+s+s, x+s, y+s+s);
> +}
> +
> +static void sdl_number(struct sdl *m, int x, int y, int s, int digits, int i)
> +{
> +	int tot = s * 5;
> +	x += tot * digits;
> +	for (int j=0; j<digits; j++) {
> +		sdl_digit(m, x+2, y+4, s*3, i%10);
> +		i /= 10;
> +		x -= tot;
> +	}
> +}
> +
> +static void sdl_icon_pos(struct sdl *m, int *x, int *y, double val)
> +{
> +	*x = m->wx - 10;
> +	*y = val * m->wy;
> +}
> +
> +static void sdl_paint_ui_iso(struct sdl *m, double y_, int i)
> +{
> +	static char *iso_xpm[] = {
> +		"16 12 2 1",
> +		"x c #ffffff",
> +		". c #000000",
> +		"................",
> +		"................",
> +		"................",
> +		".x..xx..x.......",
> +		".x.x...x.x......",
> +		".x..x..x.x......",
> +		".x...x.x.x......",
> +		".x.xx...x.......",
> +		"................",
> +		"................",
> +		"................",
> +		"................",
> +	};
> +
> +	int x, y;
> +
> +	sdl_icon_pos(m, &x, &y, y_);
> +	sdl_number(m, x-35, y-10, 1, 3, i);
> +	sdl_paint_image(m, iso_xpm, x, y);
> +}
> +
> +static void sdl_paint_ui_exposure(struct sdl *m, int t)
> +{
> +	static char *time_1_xpm[] = {
> +		"16 12 2 1",
> +		"x c #ffffff",
> +		". c #000000",
> +		"......x.........",
> +		".....x..........",
> +		"....x...........",
> +		"...x............",
> +		"................",
> +		".xxx.xxxx.xxxx..",
> +		"x....x....x.....",
> +		".xx..xxx..x.....",
> +		"...x.x....x.....",
> +		"...x.x....x.....",
> +		"xxx..xxxx.xxxx..",
> +		"................",
> +	};
> +	int x, y;
> +
> +	sdl_icon_pos(m, &x, &y, cam_convert_exposure(m, 1000000/t));
> +	sdl_number(m, x-35, y-10, 1, 3, t);
> +	sdl_paint_image(m, time_1_xpm, x, y);
> +}
> +
> +static void sdl_paint_boolean(struct sdl *m, char **image, int x, int y, int yes)
> +{
> +	static char *not_xpm[] = {
> +		"16 12 2 1",
> +		"x c #ffffff",
> +		". c #000000",
> +		"......xxxxx.....",
> +		"....xx.....xx...",
> +		"...x.........x..",
> +		"..x........xx.x.",
> +		"..x......xx...x.",
> +		".x.....xx......x",
> +		".x...xx........x",
> +		"..xxx.........x.",
> +		"..x...........x.",
> +		"...x.........x..",
> +		"....xx.....xx...",
> +		"......xxxxx.....",
> +	};
> +
> +	sdl_paint_image(m, image, x, y);
> +	if (!yes)
> +		sdl_paint_image(m, not_xpm,  16+x, y);
> +}
> +
> +static void sdl_paint_button(struct sdl *m, char **image, int x, int y, int yes)
> +{
> +	int bsx = m->wx/m->nx;
> +	int bsy = m->wy/m->ny;
> +	if (x < 0)
> +		x += m->nx;
> +	if (y < 0)
> +		y += m->ny;
> +	x = bsx/2 + x*bsx;
> +	y = bsy/2 + y*bsy;
> +	sdl_paint_boolean(m, image, x, y, yes);
> +}
> +
> +static void sdl_paint_ui_focus(struct sdl *m, int f)
> +{
> +	static char *cm_xpm[] = {
> +		"16 9 2 1",
> +		"# c #ffffff",
> +		". c #000000",
> +		"................",
> +		"................",
> +		"................",
> +		"....###..#.#.##.",
> +		"...#.....##.#..#",
> +		"...#.....#..#..#",
> +		"...#.....#..#..#",
> +		"....###..#..#..#",
> +		"................",
> +	};
> +	double dioptr = 1/(f/100.);
> +	int x, y;
> +
> +	if (dioptr > m->focus_min)
> +		return;
> +
> +	sdl_icon_pos(m, &x, &y, cam_convert_focus(m, dioptr));
> +	sdl_paint_image(m, cm_xpm, x, y);
> +	sdl_number(m, x-12, y-15, 1, 3, f);
> +}
> +
> +static void sdl_paint_ui_bias(struct sdl *m, double v)
> +{
> +	static char *bias_xpm[] = {
> +		"16 12 2 1",
> +		"# c #ffffff",
> +		". c #000000",
> +		"...#............",
> +		"...#.......#....",
> +		".#####....#.....",
> +		"...#.....#......",
> +		"...#....#.......",
> +		".......#........",
> +		"......#...#####.",
> +		".....#..........",
> +		"....#...........",
> +		"...#............",
> +		"................",
> +		"................",
> +	};
> +	int x, y;
> +
> +	sdl_icon_pos(m, &x, &y, v);
> +	sdl_paint_image(m, bias_xpm, x, y);
> +}
> +
> +static void sdl_paint_slider(struct sdl *m)
> +{
> +	switch (m->slider_mode) {
> +	case M_BIAS:
> +		sdl_paint_ui_bias(m, 0.5);
> +		return;
> +	case M_EXPOSURE:
> +		sdl_paint_ui_exposure(m, 10);
> +		sdl_paint_ui_exposure(m, 100);
> +		sdl_paint_ui_exposure(m, 999);
> +		return;
> +	case M_GAIN:
> +		sdl_paint_ui_iso(m, 0/4., 100);
> +		sdl_paint_ui_iso(m, 1/4., 200);
> +		sdl_paint_ui_iso(m, 2/4., 400);
> +		sdl_paint_ui_iso(m, 3/4., 800);
> +		return;
> +	case M_FOCUS:
> +		sdl_paint_ui_focus(m, 100);
> +		sdl_paint_ui_focus(m, 40);
> +		sdl_paint_ui_focus(m, 25);
> +		sdl_paint_ui_focus(m, 16);
> +		sdl_paint_ui_focus(m, 10);
> +		sdl_paint_ui_focus(m, 8);
> +		sdl_paint_ui_focus(m, 6);
> +		return;
> +	}
> +}
> +
> +static void sdl_paint_ui(struct sdl *m)
> +{
> +	static char *wait_xpm[] = {
> +		"16 9 2 1",
> +		"# c #ffffff",
> +		". c #000000",
> +		"....########....",
> +		".....#....#.....",
> +		".....#....#.....",
> +		"......#..#......",
> +		".......##.......",
> +		"......#..#......",
> +		".....#....#.....",
> +		".....#....#.....",
> +		"....########....",
> +	};
> +
> +	static char *ok_xpm[] = {
> +		"16 9 2 1",
> +		"# c #ffffff",
> +		". c #000000",
> +		"...............#",
> +		"............###.",
> +		"..........##....",
> +		"#.......##......",
> +		".#.....#........",
> +		"..#...#.........",
> +		"..#..#..........",
> +		"...##...........",
> +		"...#............",
> +	};
> +
> +	static char *exit_xpm[] = {
> +		"16 9 2 1",
> +		"x c #ffffff",
> +		". c #000000",
> +		"....x......x....",
> +		".....x....x.....",
> +		"......x..x......",
> +		".......xx.......",
> +		".......xx.......",
> +		"......x..x......",
> +		".....x....x.....",
> +		"....x......x....",
> +		"................",
> +	};
> +
> +	static char *af_xpm[] = {
> +		"16 12 2 1",
> +		"x c #ffffff",
> +		". c #000000",
> +		"................",
> +		"................",
> +		".....xxxxxxx....",
> +		".....x..........",
> +		".....x..........",
> +		".x...xxxxx......",
> +		"x.x..x..........",
> +		"xxx..x..........",
> +		"x.x..x..........",
> +		"x.x..x..........",
> +		"................",
> +		"................",
> +	};
> +
> +	static char *ae_xpm[] = {
> +		"16 12 2 1",
> +		"x c #ffffff",
> +		". c #000000",
> +		"................",
> +		"................",
> +		".....xxxxxxx....",
> +		".....x..........",
> +		".....x..........",
> +		".x...xxxxx......",
> +		"x.x..x..........",
> +		"xxx..x..........",
> +		"x.x..x..........",
> +		"x.x..xxxxxxx....",
> +		"................",
> +		"................",
> +	};
> +
> +	static char *focus_xpm[] = {
> +		"16 12 2 1",
> +		"# c #ffffff",
> +		". c #000000",
> +		"................",
> +		"................",
> +		"###..........###",
> +		"#..............#",
> +		"#.....####.....#",
> +		".....#....#.....",
> +		".....#....#.....",
> +		"#.....####.....#",
> +		"#..............#",
> +		"###..........###",
> +		"................",
> +		"................",
> +	};
> +
> +	static char *flash_xpm[] = {
> +		"16 12 2 1",
> +		"# c #ffffff",
> +		". c #000000",
> +		"................",
> +		"..........#.....",
> +		"........##......",
> +		".......##.......",
> +		"......##........",
> +		".....########...",
> +		"..........##....",
> +		".......#.##.....",
> +		".......###......",
> +		".......####.....",
> +		"................",
> +		"................",
> +	};
> +
> +	static char *wb_xpm[] = {
> +		"16 12 2 1",
> +		"# c #ffffff",
> +		". c #000000",
> +		"................",
> +		"................",
> +		"................",
> +		"#.....#..####...",
> +		"#.....#..#...#..",
> +		"#..#..#..####...",
> +		"#..#..#..#...#..",
> +		".##.##...####...",
> +		"................",
> +		"................",
> +		"................",
> +		"................",
> +	};
> +/* Template for more xpm's:
> +	static char *empty_xpm[] = {
> +		"16 12 2 1",
> +		"# c #ffffff",
> +		". c #000000",
> +		"................",
> +		"................",
> +		"................",
> +		"................",
> +		"................",
> +		"................",
> +		"................",
> +		"................",
> +		"................",
> +		"................",
> +		"................",
> +		"................",
> +	};
> +*/
> +	SDL_FillRect(m->screen, NULL, SDL_MapRGB( m->liveview->format, 0, 0, 0 ));
> +
> +	{
> +		/* Paint grid */
> +		int x, y;
> +		int nx = m->nx;
> +		for (x=1; x<nx; x++) {
> +			int x_ = (x*m->wx)/nx;
> +			sdl_line_color(m, x_, 1, x_, m->wy-1, SDL_MapRGB( m->liveview->format, 40, 40, 40 ));
> +		}
> +
> +		int ny = m->ny;
> +		for (y=1; y<nx; y++) {
> +			int y_ = (y*m->wy)/ny;
> +			sdl_line_color(m, 1, y_, m->wx-1, y_, SDL_MapRGB( m->liveview->format, 40, 40, 40 ));
> +		}
> +
> +	}
> +
> +	sdl_paint_image(m, wait_xpm,  m->wx/2,     m->wy/2);
> +
> +
> +	sdl_paint_button(m, af_xpm, 0,  0, m->do_focus);
> +	sdl_paint_button(m, ae_xpm, -1, 0, m->do_exposure);
> +
> +	sdl_paint_button(m, exit_xpm,   0, -1, 1);
> +	sdl_paint_button(m, flash_xpm,  1, -1, m->do_flash);
> +	sdl_paint_button(m, wb_xpm,     2, -1, m->do_white);
> +	sdl_paint_button(m, focus_xpm, -1, -2, 1);
> +	sdl_paint_button(m, ok_xpm,    -1, -1, 1);
> +
> +	sdl_paint_slider(m);
> +	SDL_UpdateWindowSurface(m->window);
> +}
> +
> +static double usec_to_time(double v)
> +{
> +	return 1/(v*.000001);
> +}
> +
> +static void sdl_status(struct sdl *m, double avg)
> +{
> +	int ox = 0;
> +	int oy = m->wy/2;
> +	int s = 3;
> +	SDL_Rect rcDest = { ox, oy, s*25, s*40 };
> +
> +	SDL_FillRect(m->screen, &rcDest, SDL_MapRGB( m->liveview->format, 30, 30, 30 ));
> +
> +	sdl_number(m, ox, oy, s, 3, avg*1000);
> +	oy += s*10;
> +
> +	{
> +		double focus, gain, exposure;
> +
> +		exposure = v4l2_g_ctrl(m->fd, V4L2_CID_EXPOSURE_ABSOLUTE);
> +		gain = cam_get_gain_iso(m->dev);
> +		focus = cam_get_focus_diopter(m);
> +
> +		double x = usec_to_time(exposure);
> +		if (x > 999) x = 999;
> +		sdl_number(m, ox, oy, s, 3, x);
> +
> +		oy += s*10;
> +		if (gain > 999)
> +			gain = 999;
> +		sdl_number(m, ox, oy, s, 3, gain);
> +
> +		oy += s*10;
> +		x = focus; /* diopters */
> +		if (x == 0)
> +			x = 999;
> +		else
> +			x = 100/x; /* centimeters */
> +		sdl_number(m, ox, oy, s, 3, x);
> +	}
> +
> +	SDL_UpdateWindowSurfaceRects(m->window, &rcDest, 1);
> +}
> +static pixel buf_pixel(struct v4l2_format *fmt, unsigned char *buf, int x, int y)
> +{
> +	pixel p = { 0, 0, 0, 0 };
> +	int pos = x + y*fmt->fmt.pix.width;
> +
> +	p.alpha = 128;
> +
> +	switch (fmt->fmt.pix.pixelformat) {
> +	case V4L2_PIX_FMT_SGRBG10:
> +		{
> +			short *b2 = (void *)buf;
> +			x &= ~1;
> +			y &= ~1;
> +			p.g = b2[x + y*fmt->fmt.pix.width] /4;
> +			p.r = b2[x + y*fmt->fmt.pix.width+1] /4;
> +			p.b = b2[x + (y+1)*fmt->fmt.pix.width] /4;
> +		}
> +		break;
> +
> +	case V4L2_PIX_FMT_RGB24:
> +		pos *= 3;
> +		p.r = buf[pos];
> +		p.g = buf[pos+1];
> +		p.b = buf[pos+2];
> +		break;
> +
> +	default:
> +		printf("Wrong pixel format!\n");
> +		fmt_print(fmt);
> +		exit(1);
> +	}
> +
> +	return p;
> +}
> +
> +static char *fmt_name(struct v4l2_format *fmt)
> +{
> +	switch (fmt->fmt.pix.pixelformat) {
> +	case V4L2_PIX_FMT_SGRBG10:
> +		return "GRBG10";
> +	case V4L2_PIX_FMT_RGB24:
> +		return "RGB24";
> +	default:
> +		return "unknown";
> +	}
> +}
> +
> +static void sdl_handle_focus(struct sdl *m, float how)
> +{
> +	v4l2_set_control(m->fd, V4L2_CID_FOCUS_ABSOLUTE, 65535. * how);
> +}
> +
> +static void sdl_key(struct sdl *m, int c)
> +{
> +	switch (c) {
> +	case 27: exit(1); break;
> +	case 'q': sdl_handle_focus(m, 0.); break;
> +	case 'w': sdl_handle_focus(m, 1/6.); break;
> +	case 'e': sdl_handle_focus(m, 1/3.); break;
> +	case 'r': sdl_handle_focus(m, 1/2.); break;
> +	case 't': sdl_handle_focus(m, 1/1); break;
> +	case 'y': sdl_handle_focus(m, 1/.8); break;
> +	case 'u': sdl_handle_focus(m, 1/.5); break;
> +	case 'i': sdl_handle_focus(m, 1/.2); break;
> +	case 'o': sdl_handle_focus(m, 1/.1); break;
> +	case 'p': sdl_handle_focus(m, 1/.05); break;
> +	default: printf("Unknown key %d / %c", c, c);
> +	}
> +}
> +
> +static int sdl_render_statistics(struct sdl *m)
> +{
> +	pixel white;
> +	double focus, gain, exposure;
> +
> +	white.r = (Uint8)0xff;
> +	white.g = (Uint8)0xff;
> +	white.b = (Uint8)0xff;
> +	white.alpha = (Uint8)128;
> +
> +	exposure = cam_get_exposure(m);
> +	gain = v4l2_get_control(m->fd, 0x00980913) / 65535.;
> +	focus = cam_get_focus(m);
> +
> +	for (int x=0; x<m->sx && x<m->sx*focus; x++)
> +		sfc_put_pixel(m->liveview, x, 0, &white);
> +
> +	for (int y=0; y<m->sy && y<m->sy*gain; y++)
> +		sfc_put_pixel(m->liveview, 0, y, &white);
> +
> +	for (int y=0; y<m->sy && y<m->sy*exposure; y++)
> +		sfc_put_pixel(m->liveview, m->sx-1, y, &white);
> +
> +	for (int x=0; x<m->sx; x++)
> +		sfc_put_pixel(m->liveview, x, m->sy-1, &white);
> +
> +	return 0;
> +}
> +
> +static void sdl_render(struct sdl *m, unsigned char *buf, struct v4l2_format *fmt)
> +{
> +	float zoom = m->zoom;
> +	if (!m->window)
> +		return;
> +
> +	sdl_begin_paint(m);
> +	int x0 = (fmt->fmt.pix.width - m->sx*m->factor/zoom)/2;
> +	int y0 = (fmt->fmt.pix.height - m->sy*m->factor/zoom)/2;
> +
> +	for (int y = 0; y < m->sy; y++)
> +		for (int x = 0; x < m->sx; x++) {
> +			int x1 = x0+x*m->factor/zoom;
> +			int y1 = y0+y*m->factor/zoom;
> +			pixel p = buf_pixel(fmt, buf, x1, y1);
> +			p.alpha = 128;
> +			sfc_put_pixel(m->liveview, x, y, &p);
> +		}
> +
> +	sdl_render_statistics(m);
> +	sdl_finish_paint(m);
> +}
> +
> +static void sdl_sync_settings(struct sdl *m)
> +{
> +	printf("Autofocus: "); v4l2_s_ctrl(m->fd, V4L2_CID_FOCUS_AUTO, m->do_focus);
> +	printf("Autogain: " ); v4l2_s_ctrl(m->fd, V4L2_CID_AUTOGAIN, m->do_exposure);
> +	printf("Autowhite: "); v4l2_s_ctrl(m->fd, V4L2_CID_AUTO_WHITE_BALANCE, m->do_white);
> +	v4l2_s_ctrl(m->fd, 0x009c0901, m->do_flash ? 2 : 0);
> +}
> +
> +static void sdl_init_window(struct sdl *m)
> +{
> +	if (m->do_full) {
> +		m->wx = 800;
> +		m->wy = 480;
> +	} else {
> +		m->wx = 800;
> +		m->wy = 429;
> +	}
> +
> +	SDL_SetWindowFullscreen(m->window, m->do_full*SDL_WINDOW_FULLSCREEN_DESKTOP);
> +
> +	m->screen = SDL_GetWindowSurface(m->window);
> +	if (!m->screen) {
> +		printf("Couldn't create screen\n");
> +		exit(1);
> +	}
> +}
> +
> +static void sdl_init(struct sdl *m, struct dev_info *dev)
> +{
> +	m->fd = dev->fd;
> +	m->dev = dev;
> +
> +	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
> +		printf("Could not init SDL\n");
> +		exit(1);
> +	}
> +
> +	atexit(SDL_Quit);
> +
> +	m->nx = 6;
> +	m->ny = 4;
> +
> +	m->do_flash = 1;
> +	m->do_focus = 0;
> +	m->do_exposure = 1;
> +	m->focus_min = 5;
> +	m->do_white = 0;
> +	m->do_big = 0;
> +	m->do_full = 0;
> +	m->zoom = 1;
> +
> +	m->window = SDL_CreateWindow("Camera", SDL_WINDOWPOS_UNDEFINED,
> +				     SDL_WINDOWPOS_UNDEFINED, 800, 429,
> +				     SDL_WINDOW_SHOWN |
> +				     m->do_full * SDL_WINDOW_FULLSCREEN_DESKTOP);
> +	if (m->window == NULL) {
> +		printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
> +		exit(1);
> +	}
> +
> +	sdl_init_window(m);
> +}
> +
> +static void sdl_set_size(struct sdl *m, int _sx)
> +{
> +	m->sx = _sx;
> +	m->factor = (float) m->dev->fmt.fmt.pix.width / m->sx;
> +	m->sy = m->dev->fmt.fmt.pix.height / m->factor;
> +
> +	m->bx = (m->wx-m->sx)/2;
> +	m->by = (m->wy-m->sy)/2;
> +
> +	m->liveview = SDL_CreateRGBSurface(0,m->sx,m->sy,32,0,0,0,0);
> +	if (!m->liveview) {
> +		printf("Couldn't create liveview\n");
> +		exit(1);
> +	}
> +
> +	sdl_paint_ui(m);
> +	sdl_sync_settings(m);
> +}
> +
> +static struct sdl sdl;
> +
> +static void ppm_write(struct v4l2_format *fmt, unsigned char *img, char *out_name)
> +{
> +	FILE *fout;
> +	fout = fopen(out_name, "w");
> +	if (!fout) {
> +		perror("Cannot open image");
> +		exit(EXIT_FAILURE);
> +	}
> +	switch (fmt->fmt.pix.pixelformat) {
> +	case V4L2_PIX_FMT_RGB24:
> +		printf("ok\n");
> +		break;
> +	default:
> +		printf("Bad pixel format\n");
> +		exit(1);
> +	}
> +
> +	fprintf(fout, "P6\n%d %d 255\n",
> +		fmt->fmt.pix.width, fmt->fmt.pix.height);
> +	fwrite(img, fmt->fmt.pix.width, 3*fmt->fmt.pix.height, fout);
> +	fclose(fout);
> +}
> +
> +/**
> +   Write image to jpeg file.
> +   \param img image to write
> +*/
> +static void jpeg_write(struct v4l2_format *fmt, unsigned char *img, char *jpegFilename)
> +{
> +	struct jpeg_compress_struct cinfo;
> +	struct jpeg_error_mgr jerr;
> +
> +	JSAMPROW row_pointer[1];
> +	FILE *outfile = fopen(jpegFilename, "wb");
> +	if (!outfile) {
> +		printf("Can't open jpeg for writing.\n");
> +		exit(2);
> +	}
> +
> +	/* create jpeg data */
> +	cinfo.err = jpeg_std_error(&jerr);
> +	jpeg_create_compress(&cinfo);
> +	jpeg_stdio_dest(&cinfo, outfile);
> +
> +	/* set image parameters */
> +	cinfo.image_width = fmt->fmt.pix.width;
> +	cinfo.image_height = fmt->fmt.pix.height;
> +	cinfo.input_components = 3;
> +	switch (fmt->fmt.pix.pixelformat) {
> +	case V4L2_PIX_FMT_SGRBG10:
> +	case V4L2_PIX_FMT_RGB24:
> +		cinfo.in_color_space = JCS_RGB;
> +		break;
> +	default:
> +		printf("Need to specify colorspace!\n");
> +		exit(1);
> +	}
> +
> +	/* set jpeg compression parameters to default */
> +	jpeg_set_defaults(&cinfo);
> +	jpeg_set_quality(&cinfo, 90, TRUE);
> +
> +	jpeg_start_compress(&cinfo, TRUE);
> +
> +	/* feed data */
> +	while (cinfo.next_scanline < cinfo.image_height) {
> +		row_pointer[0] = &img[cinfo.next_scanline * cinfo.image_width *  cinfo.input_components];
> +		jpeg_write_scanlines(&cinfo, row_pointer, 1);
> +	}
> +
> +	jpeg_finish_compress(&cinfo);
> +	jpeg_destroy_compress(&cinfo);
> +	fclose(outfile);
> +}
> +
> +static void any_write(struct dev_info *dev)
> +{
> +	char name[1024];
> +	unsigned char *buf;
> +	time_t t = time(NULL);
> +	int ppm = 0;
> +
> +	buf = dev->buf;
> +
> +	sprintf(name, PICDIR "/delme_%d.%s", (int) t, ppm ? "ppm" : "jpg");
> +	if (dev->fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) {
> +		printf("Wrong pixel format\n");
> +		exit(1);
> +	}
> +	if (ppm)
> +		ppm_write(&dev->fmt, buf, name);
> +	else
> +		jpeg_write(&dev->fmt, buf, name);
> +}
> +
> +static void sdl_mouse(struct sdl *m, SDL_Event event)
> +{
> +	int ax = 0, ay = 0;
> +	int nx = event.button.x / (m->wx/m->nx), ny = event.button.y / (m->wy/m->ny);
> +	if (nx >= m->nx/2)
> +		nx -= m->nx;
> +	if (ny >= m->ny/2)
> +		ny -= m->ny;
> +
> +	printf("Button %d %d\n", nx, ny);
> +
> +	/* Virtual slider */
> +	if (nx == -2) {
> +		double value = (double) event.button.y / m->wy;
> +		switch (m->slider_mode) {
> +		case M_BIAS: {
> +			double ev = value - .5; /* -.5 .. +.5 */
> +			ev *= 3000;
> +			printf("Exposure bias: %f mEV %d\n", ev, (int) ev);
> +			if (v4l2_s_ctrl(m->fd, V4L2_CID_AUTO_EXPOSURE_BIAS, ev) < 0) {
> +				printf("Could not set exposure bias\n");
> +			}
> +		}
> +			return;
> +		case M_EXPOSURE:
> +			m->do_exposure = 0;
> +			cam_set_exposure(m, value);
> +			sdl_sync_settings(m);
> +			return;
> +		case M_GAIN:
> +			m->do_exposure = 0;
> +			v4l2_set_control(m->fd, 0x00980913, value * 65535);
> +			sdl_sync_settings(m);
> +			return;
> +		case M_FOCUS:
> +			cam_set_focus(m, value);
> +			return;
> +		}
> +	}
> +
> +	switch (ny) {
> +	case 0:
> +		switch (nx) {
> +		case 0:
> +			m->do_focus ^= 1;
> +			sdl_paint_ui(m);
> +			sdl_sync_settings(m);
> +			return;
> +		case -1:
> +			m->do_exposure ^= 1;
> +			sdl_paint_ui(m);
> +			sdl_sync_settings(m);
> +			return;
> +		}
> +		break;
> +	case 1:
> +		switch (nx) {
> +		case -1:
> +			m->slider_mode = (m->slider_mode + 1) % M_NUM;
> +			sdl_paint_ui(m);
> +		}
> +		break;
> +	case -2:
> +		switch (nx) {
> +		case -1:
> +			v4l2_s_ctrl(m->fd, V4L2_CID_AUTO_FOCUS_STATUS, 1);
> +			return;
> +		break;
> +		}
> +	case -1:
> +		switch (nx) {
> +		case 0:
> +			exit(0);
> +		case 1:
> +			m->do_flash ^= 1;
> +			sdl_paint_ui(m);
> +			sdl_sync_settings(m);
> +			return;
> +		case 2:
> +			m->do_white ^= 1;
> +			sdl_paint_ui(m);
> +			sdl_sync_settings(m);
> +			return;
> +		case -3:
> +			m->do_big ^= 1;
> +			if (m->do_big)
> +				sdl_set_size(m, m->do_full ? 630:512);
> +			else
> +				sdl_set_size(m, 256);
> +			return;
> +		case -1:
> +			sdl_paint_ui(m);
> +			any_write(m->dev);
> +			return;
> +		}
> +		break;
> +	}
> +
> +	if (event.button.x > m->wx-m->bx)
> +		ax = 1;
> +	if (event.button.x < m->bx)
> +		ax = -1;
> +
> +	if (event.button.y > m->wy-m->by)
> +		ay = 1;
> +	if (event.button.y < m->by)
> +		ay = -1;
> +
> +	printf("mouse button at...%d, %d area %d, %d\n", event.button.x, event.button.y,
> +	       ax, ay);
> +}
> +
> +static void sdl_iteration(struct sdl *m)
> +{
> +	SDL_Event event;
> +
> +	while(SDL_PollEvent(&event)) {
> +		switch(event.type) {
> +		case SDL_QUIT:
> +			exit(1);
> +			break;
> +		case SDL_KEYDOWN:
> +			printf("key pressed... %c\n", event.key.keysym.sym);
> +			/* SDLK_A, SDLK_LEFT, SDLK_RETURN, SDLK_BACKSPACE, SDLK_SPACE */
> +			switch (event.key.keysym.sym) {
> +			default: sdl_key(m, event.key.keysym.sym);
> +			}
> +			break;
> +		case SDL_WINDOWEVENT:
> +			if (event.window.event == SDL_WINDOWEVENT_EXPOSED)
> +				sdl_paint_ui(m);
> +			break;
> +		case SDL_MOUSEBUTTONDOWN:
> +			sdl_mouse(m, event);
> +			break;
> +		}
> +	}
> +}
> +
> +static void cam_open(struct dev_info *dev, char *name)
> +{
> +	struct v4l2_format *fmt = &dev->fmt;
> +
> +	dev->fd = v4l2_open(name, O_RDWR);
> +	if (dev->fd < 0) {
> +		printf("video %s open failed: %m\n", name);
> +		exit(1);
> +	}
> +
> +	fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +	fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
> +	fmt->fmt.pix.field = V4L2_FIELD_NONE;
> +	fmt->fmt.pix.width = SX;
> +	fmt->fmt.pix.height = SY;
> +
> +	v4l2_s_ctrl(dev->fd, V4L2_CID_AUTO_FOCUS_STATUS, 0);
> +	v4l2_set_focus(dev->fd, 50);
> +
> +	printf("ioctl = %d\n", v4l2_ioctl(dev->fd, VIDIOC_S_FMT, fmt));
> +
> +	printf("capture is %lx %s %d x %d\n", (unsigned long) fmt->fmt.pix.pixelformat, fmt_name(fmt), fmt->fmt.pix.width, fmt->fmt.pix.height);
> +}
> +
> +/* ------------------------------------------------------------------ */
> +
> +
> +static struct dev_info dev;
> +
> +int main(void)
> +{
> +	int i;
> +	struct v4l2_format *fmt = &dev.fmt;
> +
> +	dtime();
> +	cam_open(&dev, "/dev/video0");
> +
> +	sdl_init(&sdl, &dev);
> +	sdl_set_size(&sdl, 256);
> +
> +	double loop = dtime(), max = 0, avg = .200;
> +	if (dev.debug & D_TIMING)
> +		printf("startup took %f\n", loop);
> +
> +	for (i=0; i<500000; i++) {
> +		int num = v4l2_read(dev.fd, dev.buf, SIZE);
> +		if (num < 0) {
> +			printf("Could not read frame\n");
> +			return 1;
> +		}
> +		{
> +			double d = dtime();
> +			sdl_render(&sdl, dev.buf, fmt);
> +			if (dev.debug & D_TIMING)
> +				printf("Render took %f\n", dtime() - d);
> +		}
> +		{
> +			double d = dtime();
> +			for (int i = 0; i<1; i++)
> +				sdl_status(&sdl, avg);
> +			if (dev.debug & D_TIMING)
> +				printf("Status took %f\n", dtime() - d);
> +		}
> +
> +		sdl_iteration(&sdl);
> +		double now = dtime();
> +		if (now - loop > max)
> +			max = now - loop;
> +		double c = 0.03;
> +		avg = (now - loop) * c + avg * (1-c);
> +		if (dev.debug & D_TIMING)
> +			printf("Iteration %f, maximum %f, average %f\n", now-loop, max, avg);
> +		loop = now;
> +	}
> +	return 0;
> +}
> 
> 




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux