@@ -88,6 +88,247 @@ LIBDVBV5_DOMAIN="libdvbv5"
AC_DEFINE([LIBDVBV5_DOMAIN], "libdvbv5", [libdvbv5 domain])
AC_SUBST(LIBDVBV5_DOMAIN)
+# Configure paths for SDL
+# Sam Lantinga 9/21/99
+# stolen from Manish Singh
+# stolen back from Frank Belew
+# stolen from Manish Singh
+# Shamelessly stolen from Owen Taylor
+#
+# Changelog:
+# * also look for SDL2.framework under Mac OS X
+
+# serial 1
+
+dnl AM_PATH_SDL2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
+dnl
+AC_DEFUN([AM_PATH_SDL2],
+[dnl
+dnl Get the cflags and libraries from the sdl2-config script
+dnl
+AC_ARG_WITH(sdl-prefix,[ --with-sdl-prefix=PFX Prefix where SDL is installed (optional)],
+ sdl_prefix="$withval", sdl_prefix="")
+AC_ARG_WITH(sdl-exec-prefix,[ --with-sdl-exec-prefix=PFX Exec prefix where SDL is installed (optional)],
+ sdl_exec_prefix="$withval", sdl_exec_prefix="")
+AC_ARG_ENABLE(sdltest, [ --disable-sdltest Do not try to compile and run a test SDL program],
+ , enable_sdltest=yes)
+AC_ARG_ENABLE(sdlframework, [ --disable-sdlframework Do not search for SDL2.framework],
+ , search_sdl_framework=yes)
+
+AC_ARG_VAR(SDL2_FRAMEWORK, [Path to SDL2.framework])
+
+ min_sdl_version=ifelse([$1], ,2.0.0,$1)
+
+ if test "x$sdl_prefix$sdl_exec_prefix" = x ; then
+ PKG_CHECK_MODULES([SDL], [sdl2 >= $min_sdl_version],
+ [sdl_pc=yes],
+ [sdl_pc=no])
+ else
+ sdl_pc=no
+ if test x$sdl_exec_prefix != x ; then
+ sdl_config_args="$sdl_config_args --exec-prefix=$sdl_exec_prefix"
+ if test x${SDL2_CONFIG+set} != xset ; then
+ SDL2_CONFIG=$sdl_exec_prefix/bin/sdl2-config
+ fi
+ fi
+ if test x$sdl_prefix != x ; then
+ sdl_config_args="$sdl_config_args --prefix=$sdl_prefix"
+ if test x${SDL2_CONFIG+set} != xset ; then
+ SDL2_CONFIG=$sdl_prefix/bin/sdl2-config
+ fi
+ fi
+ fi
+
+ if test "x$sdl_pc" = xyes ; then
+ no_sdl=""
+ SDL2_CONFIG="pkg-config sdl2"
+ else
+ as_save_PATH="$PATH"
+ if test "x$prefix" != xNONE && test "$cross_compiling" != yes; then
+ PATH="$prefix/bin:$prefix/usr/bin:$PATH"
+ fi
+ AC_PATH_PROG(SDL2_CONFIG, sdl2-config, no, [$PATH])
+ PATH="$as_save_PATH"
+ no_sdl=""
+
+ if test "$SDL2_CONFIG" = "no" -a "x$search_sdl_framework" = "xyes"; then
+ AC_MSG_CHECKING(for SDL2.framework)
+ if test "x$SDL2_FRAMEWORK" != x; then
+ sdl_framework=$SDL2_FRAMEWORK
+ else
+ for d in / ~/ /System/; do
+ if test -d "$dLibrary/Frameworks/SDL2.framework"; then
+ sdl_framework="$dLibrary/Frameworks/SDL2.framework"
+ fi
+ done
+ fi
+
+ if test -d $sdl_framework; then
+ AC_MSG_RESULT($sdl_framework)
+ sdl_framework_dir=`dirname $sdl_framework`
+ SDL_CFLAGS="-F$sdl_framework_dir -Wl,-framework,SDL2 -I$sdl_framework/include"
+ SDL_LIBS="-F$sdl_framework_dir -Wl,-framework,SDL2"
+ else
+ no_sdl=yes
+ fi
+ fi
+
+ if test "$SDL2_CONFIG" != "no"; then
+ if test "x$sdl_pc" = "xno"; then
+ AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)
+ SDL_CFLAGS=`$SDL2_CONFIG $sdl_config_args --cflags`
+ SDL_LIBS=`$SDL2_CONFIG $sdl_config_args --libs`
+ fi
+
+ sdl_major_version=`$SDL2_CONFIG $sdl_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ sdl_minor_version=`$SDL2_CONFIG $sdl_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ sdl_micro_version=`$SDL2_CONFIG $sdl_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+ if test "x$enable_sdltest" = "xyes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_CXXFLAGS="$CXXFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $SDL_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
+ LIBS="$LIBS $SDL_LIBS"
+dnl
+dnl Now check if the installed SDL is sufficiently new. (Also sanity
+dnl checks the results of sdl2-config to some extent
+dnl
+ rm -f conf.sdltest
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SDL.h"
+
+char*
+my_strdup (char *str)
+{
+ char *new_str;
+
+ if (str)
+ {
+ new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
+ strcpy (new_str, str);
+ }
+ else
+ new_str = NULL;
+
+ return new_str;
+}
+
+int main (int argc, char *argv[])
+{
+ int major, minor, micro;
+ char *tmp_version;
+
+ /* This hangs on some systems (?)
+ system ("touch conf.sdltest");
+ */
+ { FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); }
+
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = my_strdup("$min_sdl_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) {
+ printf("%s, bad version string\n", "$min_sdl_version");
+ exit(1);
+ }
+
+ if (($sdl_major_version > major) ||
+ (($sdl_major_version == major) && ($sdl_minor_version > minor)) ||
+ (($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro)))
+ {
+ return 0;
+ }
+ else
+ {
+ printf("\n*** 'sdl2-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version);
+ printf("*** of SDL required is %d.%d.%d. If sdl2-config is correct, then it is\n", major, minor, micro);
+ printf("*** best to upgrade to the required version.\n");
+ printf("*** If sdl2-config was wrong, set the environment variable SDL2_CONFIG\n");
+ printf("*** to point to the correct copy of sdl2-config, and remove the file\n");
+ printf("*** config.cache before re-running configure\n");
+ return 1;
+ }
+}
+
+],, no_sdl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ LIBS="$ac_save_LIBS"
+
+ fi
+ if test "x$sdl_pc" = "xno"; then
+ if test "x$no_sdl" = "xyes"; then
+ AC_MSG_RESULT(no)
+ else
+ AC_MSG_RESULT(yes)
+ fi
+ fi
+ fi
+ fi
+ if test "x$no_sdl" = x ; then
+ ifelse([$2], , :, [$2])
+ else
+ if test "$SDL2_CONFIG" = "no" ; then
+ echo "*** The sdl2-config script installed by SDL could not be found"
+ echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the SDL2_CONFIG environment variable to the"
+ echo "*** full path to sdl2-config."
+ else
+ if test -f conf.sdltest ; then
+ :
+ else
+ echo "*** Could not run SDL test program, checking why..."
+ CFLAGS="$CFLAGS $SDL_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
+ LIBS="$LIBS $SDL_LIBS"
+ AC_TRY_LINK([
+#include <stdio.h>
+#include "SDL.h"
+
+int main(int argc, char *argv[])
+{ return 0; }
+#undef main
+#define main K_and_R_C_main
+], [ return 0; ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding SDL or finding the wrong"
+ echo "*** version of SDL. If it is not finding SDL, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means SDL was incorrectly installed"
+ echo "*** or that you have moved SDL since it was installed. In the latter case, you"
+ echo "*** may want to edit the sdl2-config script: $SDL2_CONFIG" ])
+ CFLAGS="$ac_save_CFLAGS"
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ SDL_CFLAGS=""
+ SDL_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(SDL_CFLAGS)
+ AC_SUBST(SDL_LIBS)
+ rm -f conf.sdltest
+])
+
+dnl Check for SDL
+SDL_VERSION=2.0
+AM_PATH_SDL2($SDL_VERSION, sdl_pkgconfig=yes, sdl_pkgconfig=no)
+
+AM_CONDITIONAL([HAVE_SDL], [test x$sdl_pkgconfig = xyes])
+
# Define localedir
AC_DEFUN([V4L_EXPAND_PREFIX], [
$1=$2
@@ -432,5 +673,6 @@ compile time options summary
libudev : $have_libudev
QT version : $QT_VERSION
ALSA support : $alsa_pkgconfig
+ SDL support : $sdl_pkgconfig
EOF
@@ -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) $(SDL_LIBS) ../../lib/libv4l2/.libs/libv4l2.a ../../lib/libv4lconvert/.libs/libv4lconvert.a
+sdlcam_CFLAGS = -I../..
+v4l2gl_LDADD =
+
mc_nextgen_test_CFLAGS = $(LIBUDEV_CFLAGS)
mc_nextgen_test_LDFLAGS = $(LIBUDEV_LIBS)
new file mode 100644
@@ -0,0 +1,1093 @@
+/*
+ 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, LGPLv2 or later.
+*/
+
+#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>
+
+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;
+ res = v4l2_ioctl(fd, VIDIOC_G_CTRL, &ctrl);
+ if (res < 0)
+ printf("Get control %ld 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;
+}
+
+#define SIZE 1296*984*3
+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 */
+ int factor;
+
+ /* These should go separately */
+ int do_focus, do_exposure, do_flash, do_white;
+ double focus_min;
+
+ 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);
+ }
+
+ 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 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_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 = m->bx - 10;
+ int y = m->by+m->sy*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 = m->wx-m->bx + 30;
+ int y = m->by+m->sy*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 = m->bx+cam_convert_focus(m, dioptr)*m->sx;
+ int y = m->by - 20;
+
+ if (dioptr > m->focus_min)
+ return;
+ sdl_paint_image(m, cm_xpm, x, y);
+ sdl_number(m, x-12, y-15, 1, 3, f);
+}
+
+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_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);
+
+ 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, -2, -1, 1);
+ sdl_paint_button(m, ok_xpm, -1, -1, 1);
+
+ sdl_paint_ui_exposure(m, 10);
+ sdl_paint_ui_exposure(m, 100);
+ sdl_paint_ui_exposure(m, 999);
+
+ 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);
+
+ 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 = m->bx;
+ int oy = m->by+m->sy;
+ SDL_Rect rcDest = { ox, oy, m->sx, 25 /* m->by */ };
+
+ SDL_FillRect(m->screen, &rcDest, SDL_MapRGB( m->liveview->format, 30, 30, 30 ));
+ ox+=40;
+ sdl_number(m, ox, oy, 2, 3, avg*1000);
+
+ {
+ double focus, gain, exposure;
+
+ exposure = v4l2_g_ctrl(m->fd, V4L2_CID_EXPOSURE_ABSOLUTE);
+ gain = v4l2_g_ctrl(m->fd, 0x00980913);
+ focus = cam_get_focus_diopter(m);
+
+ ox+=40;
+ double x = usec_to_time(exposure);
+ if (x > 999) x = 999;
+ sdl_number(m, ox, oy, 2, 3, x);
+
+ ox+=40;
+ x = (gain / 10);
+ sdl_number(m, ox, oy, 2, 1, x);
+
+ ox+=20;
+ x = focus; /* diopters */
+ if (x == 0)
+ x = 999;
+ else
+ x = 100/x; /* centimeters */
+ sdl_number(m, ox, oy, 2, 3, x);
+ }
+
+ SDL_UpdateWindowSurfaceRects(m->window, &rcDest, 1);
+}
+
+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 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;
+ case SDLK_SPACE: /* save_image(); */ printf("Should save jpeg.\n"); break;
+ default: printf("Unknown key %d / %c", c, c);
+ }
+}
+
+static int 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)
+{
+ if (!m->window)
+ return;
+ sdl_begin_paint(m);
+
+ for (int y = 0; y < m->sy; y++)
+ for (int x = 0; x < m->sx; x++) {
+ pixel p = buf_pixel(fmt, buf, x*m->factor, y*m->factor);
+ p.alpha = 128;
+ sfc_put_pixel(m->liveview, x, y, &p);
+ }
+
+ 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(struct sdl *m, struct dev_info *dev, int _factor)
+{
+ 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->wx = 800;
+ m->wy = 429;
+
+ m->window = SDL_CreateWindow("Camera", SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED, m->wx, m->wy,
+ SDL_WINDOW_SHOWN);
+ if (m->window == NULL) {
+ printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
+ exit(1);
+ }
+
+ m->screen = SDL_GetWindowSurface(m->window);
+ if (!m->screen) {
+ printf("Couldn't create screen\n");
+ exit(1);
+ }
+
+ m->sx = dev->fmt.fmt.pix.width;
+ m->sy = dev->fmt.fmt.pix.height;
+ m->factor = _factor;
+
+ m->sx /= m->factor;
+ m->sy /= m->factor;
+
+ m->bx = (m->wx-m->sx)/2;
+ m->by = (m->wy-m->sy)/2;
+
+ m->nx = 6;
+ m->ny = 4;
+
+ 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);
+ }
+
+ m->do_flash = 1;
+ m->do_focus = 0;
+ m->do_exposure = 1;
+ m->focus_min = 5;
+ sdl_paint_ui(m);
+ sdl_sync_settings(m);
+}
+
+static struct sdl sdl;
+
+static void pgm_write(struct dev_info *dev, struct v4l2_format *fmt, unsigned char *img, char *out_name)
+{
+ FILE *fout;
+ int size = fmt->fmt.pix.width * fmt->fmt.pix.height;
+ char swapped[size*2];
+
+ fout = fopen(out_name, "w");
+ if (!fout) {
+ perror("Cannot open image");
+ exit(EXIT_FAILURE);
+ }
+ switch (fmt->fmt.pix.pixelformat) {
+ /* ?? cinfo.in_color_space = JCS_YCbCr; */
+ case V4L2_PIX_FMT_SGRBG10:
+ printf("ok\n");
+ break;
+ default:
+ printf("Bad pixel format\n");
+ exit(1);
+ }
+
+ for (int i=0; i<size*2; i+=2) {
+ swapped[i] = img[i+1];
+ swapped[i+1] = img[i];
+ }
+
+ fprintf(fout, "P5\n# SDLcam raw image\n# ");
+ {
+ double focus, gain, exposure;
+
+ exposure = v4l2_get_control(dev->fd, V4L2_CID_EXPOSURE_ABSOLUTE) / 65536.;
+ gain = v4l2_get_control(dev->fd, 0x00980913) / 65536.;
+ focus = v4l2_get_control(dev->fd, V4L2_CID_FOCUS_ABSOLUTE) / 65536.;
+
+ fprintf(fout, "Exposure %f, gain %f, focus %f\n", exposure, gain, focus);
+ }
+ fprintf(fout, "%d %d\n1023\n",
+ fmt->fmt.pix.width, fmt->fmt.pix.height);
+ fwrite(swapped, size, 2, fout);
+ fclose(fout);
+}
+
+static void any_write(struct dev_info *dev)
+{
+ char name[1024];
+ unsigned char *buf;
+ time_t t = time(NULL);
+
+ buf = dev->buf;
+
+ if (1) {
+ sprintf(name, "/data/tmp/delme_%d.%s", (int) t, "pgm");
+
+ if (dev->fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_SGRBG10)
+ printf("Not in bayer10, can't write raw.\n");
+ else
+ pgm_write(dev, &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);
+ 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 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 -2:
+ v4l2_s_ctrl(m->fd, V4L2_CID_AUTO_FOCUS_STATUS, 1);
+ 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);
+
+ int bx = event.button.x - m->bx;
+ int by = event.button.y - m->by;
+
+ /*
+ AF | Focus | Aexp
+ -------------------------------
+ ISO | | time
+ -------------------------------
+ Quit |Fl | nF|F!| Shoot
+ */
+ if ((ax == 0) && (ay == -1)) {
+ cam_set_focus(m, ((float) bx)/m->sx);
+ return;
+ }
+ if ((ax == -1) && (ay == 0)) {
+ m->do_exposure = 0;
+ v4l2_set_control(m->fd, 0x00980913, (65536 * by)/m->sy);
+ sdl_sync_settings(m);
+ return;
+ }
+ if ((ax == 1) && (ay == 0)) {
+ m->do_exposure = 0;
+ cam_set_exposure(m, ((double) by)/m->sy);
+ sdl_sync_settings(m);
+ return;
+ }
+ if ((ax == 0) && (ay == 1)) {
+ /* Below */
+ }
+}
+
+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)
+{
+ struct v4l2_format *fmt = &dev->fmt;
+
+ dev->fd = v4l2_open("/dev/video0", O_RDWR);
+
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_SGRBG10;
+ fmt->fmt.pix.field = V4L2_FIELD_NONE;
+ fmt->fmt.pix.width = 1296;
+ fmt->fmt.pix.height = 984;
+
+ 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);
+
+ sdl_init(&sdl, &dev, 5);
+
+ 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)
+ 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;
+}
Add simple SDL-based application for capturing photos. Manual focus/gain/exposure can be set, flash can be controlled and autofocus/autogain can be selected if camera supports that. It is already useful for testing autofocus/autogain improvements to the libraries on Nokia N900. Signed-off-by: Pavel Machek <pavel@ucw.cz>