Index: Makefile.in =================================================================== --- Makefile.in (revision 468) +++ Makefile.in (working copy) @@ -37,7 +37,7 @@ OBJ = motion.o logger.o conf.o draw.o jpegutils.o vloopback_motion.o $(VIDEO_OBJ) \ netcam.o netcam_ftp.o netcam_jpeg.o netcam_wget.o track.o \ alg.o event.o picture.o rotate.o webhttpd.o \ - stream.o @FFMPEG_OBJ@ + stream.o @FFMPEG_OBJ@ @SDL_OBJ@ SRC = $(OBJ:.o=.c) DOC = CHANGELOG COPYING CREDITS INSTALL README motion_guide.html EXAMPLES = *.conf motion.init-Debian motion.init-RH motion.init-FreeBSD.sh Index: sdl.c =================================================================== --- sdl.c (revision 0) +++ sdl.c (revision 0) @@ -0,0 +1,179 @@ +/* + * sdl.c + * + * sdl functions for motion. + * Copyright 2009 by Peter Holik (peter@holik.at) + * This software is distributed under the GNU public license version 2 + * See also the file 'COPYING'. + */ +#include "sdl.h" +#include + +static int cur_width; +static int cur_height; +static int is_full_screen; +static int fs_screen_width; +static int fs_screen_height; + +static SDL_Surface *screen; +static SDL_Overlay *overlay; + +static int sdl_video_open(int width, int height) +{ + int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL; + int w,h; + + if (is_full_screen) flags |= SDL_FULLSCREEN; + else flags |= SDL_RESIZABLE; + + if (is_full_screen && fs_screen_width) { + w = fs_screen_width; + h = fs_screen_height; + } else if (width > fs_screen_width || height > fs_screen_height) { + w = fs_screen_width; + h = fs_screen_height; + } else { + w = width; + h = height; + } + /* 32 because framebuffer is usually initalized to 8 and + you have to use fbset with -depth to make it working */ + screen = SDL_SetVideoMode(w, h, 32, flags); + + if (!screen) { + motion_log(LOG_ERR, 1,"%s: Unable to set video mode: %s", __FUNCTION__, + SDL_GetError()); + return -1; + } + motion_log(LOG_INFO, 0, "%s: SDL dimension %d x %d fullscreen %d BytesPerPixel %d", + __FUNCTION__, screen->w, screen->h, is_full_screen, + screen->format->BytesPerPixel); + + SDL_WM_SetCaption("motion", "motion"); + SDL_ShowCursor(SDL_DISABLE); + + if (cur_width != width || cur_height != height) { + cur_width = width; + cur_height = height; + + if (overlay) SDL_FreeYUVOverlay(overlay); + + overlay = SDL_CreateYUVOverlay(cur_width, cur_height, + SDL_YV12_OVERLAY, screen); + if (!overlay) { + motion_log(LOG_ERR, 1, "%s: Could not create overlay: %s", + __FUNCTION__, SDL_GetError()); + sdl_stop(); + } else + motion_log(LOG_INFO, 0, "%s: SDL created %dx%dx%d %s overlay", + __FUNCTION__, overlay->w,overlay->h,overlay->planes, + overlay->hw_overlay?"hardware":"software"); + } + return overlay == NULL; +} + +int sdl_start(int width, int height) +{ + putenv("SDL_NOMOUSE=1"); + + if (screen) return 0; + + motion_log(LOG_INFO, 0, "%s: SDL start", __FUNCTION__); + + if (SDL_Init(SDL_INIT_VIDEO)) { + motion_log(LOG_ERR, 1, "%s: Could not initialize SDL - %s", + __FUNCTION__, SDL_GetError()); + return -1; + } + const SDL_VideoInfo *vi = SDL_GetVideoInfo(); + fs_screen_width = vi->current_w; + fs_screen_height = vi->current_h; + + if (sdl_video_open(width, height)) return -1; + + SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE); + SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); + SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE); + SDL_EventState(SDL_USEREVENT, SDL_IGNORE); + SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_IGNORE); + SDL_EventState(SDL_MOUSEBUTTONUP, SDL_IGNORE); + SDL_EventState(SDL_KEYUP, SDL_IGNORE); + SDL_EventState(SDL_JOYBUTTONDOWN, SDL_IGNORE); + SDL_EventState(SDL_JOYBUTTONUP, SDL_IGNORE); + SDL_EventState(SDL_JOYAXISMOTION, SDL_IGNORE); + SDL_EventState(SDL_JOYBALLMOTION, SDL_IGNORE); + SDL_EventState(SDL_JOYHATMOTION, SDL_IGNORE); + SDL_EventState(SDL_VIDEORESIZE, SDL_IGNORE); + + return 0; +} + +void sdl_put(unsigned char *image, int width, int height) +{ + SDL_Event event; + + if (screen && overlay) { + SDL_Rect rect; + float aspect_ratio = (float)width / height; + int pic_width, pic_height; + + if (width != cur_width || height != cur_height) + sdl_video_open(width, height); + + if (SDL_MUSTLOCK(screen)) + if (SDL_LockSurface(screen) < 0) return; + + SDL_LockYUVOverlay(overlay); + memcpy(overlay->pixels[0], image, width * height); + memcpy(overlay->pixels[2], image + (width * height), (width * height / 4)); + memcpy(overlay->pixels[1], image + (width * height * 5 / 4), (width * height / 4)); + SDL_UnlockYUVOverlay(overlay); + + if (SDL_MUSTLOCK(screen)) + SDL_UnlockSurface(screen); + + pic_height = screen->h; + pic_width = pic_height * aspect_ratio; + if (pic_width > screen->w) { + pic_width = screen->w; + pic_height = pic_width / aspect_ratio; + } + rect.x = (screen->w - pic_width) / 2; + rect.y = (screen->h - pic_height) / 2; + rect.w = pic_width; + rect.h = pic_height; + + if (SDL_DisplayYUVOverlay(overlay, &rect)) + motion_log(LOG_ERR, 1, "%s: SDL_DisplayYUVOverlay: %s", + __FUNCTION__, SDL_GetError()); + + if (SDL_PollEvent(&event)) { + if ((event.type == SDL_QUIT || + (event.type == SDL_KEYDOWN && + event.key.keysym.sym == SDLK_ESCAPE))) + sdl_stop(); + else if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_f) { + is_full_screen = !is_full_screen; + sdl_video_open(width, height); + } + else if (event.type == SDL_VIDEORESIZE) + screen = SDL_SetVideoMode(event.resize.w, event.resize.h, + screen->format->BitsPerPixel, + screen->flags); + } + } +} + +void sdl_stop(void) +{ + if (screen) { + motion_log(LOG_INFO, 0, "%s: SDL quit", __FUNCTION__); + SDL_ShowCursor(SDL_ENABLE); + if (overlay) { + SDL_FreeYUVOverlay(overlay); + overlay = NULL; + } + SDL_Quit(); + screen = NULL; + } +} Index: conf.c =================================================================== --- conf.c (revision 468) +++ conf.c (working copy) @@ -86,6 +86,9 @@ ffmpeg_bps: DEF_FFMPEG_BPS, ffmpeg_vbr: DEF_FFMPEG_VBR, ffmpeg_video_codec: DEF_FFMPEG_CODEC, +#ifdef HAVE_SDL + sdl_threadnr: 0, +#endif ipv6_enabled: 0, stream_port: 0, stream_quality: 50, @@ -741,7 +744,20 @@ print_bool }, #endif /* HAVE_FFMPEG */ +#ifdef HAVE_SDL { + "sdl_threadnr", + "\n############################################################\n" + "# SDL Window\n" + "############################################################\n\n" + "# Number of motion thread to show in SDL Window (default: 0 = disabled)", + 1, + CONF_OFFSET(sdl_threadnr), + copy_int, + print_int + }, +#endif /* HAVE_SDL */ + { "use_extpipe", "\n############################################################\n" "# External pipe to video encoder\n" Index: sdl.h =================================================================== --- sdl.h (revision 0) +++ sdl.h (revision 0) @@ -0,0 +1,17 @@ +/* sdl.h + * + * Include file for sdl.c + * Copyright 2009 by Peter Holik (peter@holik.at) + * This software is distributed under the GNU public license version 2 + * See also the file 'COPYING'. + */ +#ifndef _INCLUDE_SDL_H +#define _INCLUDE_SDL_H + +#include "motion.h" + +int sdl_start(int width, int height); +void sdl_put(unsigned char *image, int width, int height); +void sdl_stop(void); + +#endif Index: conf.h =================================================================== --- conf.h (revision 468) +++ conf.h (working copy) @@ -62,6 +62,9 @@ int ffmpeg_vbr; int ffmpeg_deinterlace; const char *ffmpeg_video_codec; +#ifdef HAVE_SDL + int sdl_threadnr; +#endif int ipv6_enabled; int stream_port; int stream_quality; Index: configure.in =================================================================== --- configure.in (revision 468) +++ configure.in (working copy) @@ -206,6 +206,44 @@ fi +# +# Check for sdl library +# +SDL_SUPPORT="no" +AC_ARG_WITH(sdl, +[ --with-sdl Compile with sdl support.], +[], +[withval="no"]) +AC_MSG_CHECKING(for sdl) +if test "x$withval" = "xno"; then + AC_MSG_RESULT(skipped) +else + if test "${FreeBSD}" != ""; then + CONFIG_SDL='sdl11-config' + else + CONFIG_SDL='sdl-config' + fi + if test -z "`($CONFIG_SDL --version) 2>/dev/null`" ;then + AC_MSG_RESULT(no) + if test "$withval" = "yes"; then + echo "" + echo "****************************************************" + echo "* sdl-config could not be found. Please install it *" + echo "* and remove the --with-sdl configure argument. *" + echo "* libSDL can be found at http://www.libsdl.org *" + echo "****************************************************" + echo "" + fi + else + AC_MSG_RESULT(yes) + SDL_SUPPORT="yes" + TEMP_LIBS="$TEMP_LIBS `${CONFIG_SDL} --libs`" + TEMP_CFLAGS="${TEMP_CFLAGS} `${CONFIG_SDL} --cflags`" + AC_DEFINE([HAVE_SDL],1,[Define to 1 if you have SDL support]) + SDL_OBJ="sdl.o" + AC_SUBST(SDL_OBJ) + fi +fi # # Check for the special mmx accelerated jpeg library @@ -1192,6 +1230,12 @@ fi fi +if test "${SDL_SUPPORT}" = "yes"; then + echo "SDL support: Yes" +else + echo "SDL support: No" +fi + if test "${FFMPEG_OK}" = "found"; then echo "FFmpeg support: Yes" else Index: motion.c =================================================================== --- motion.c (revision 468) +++ motion.c (working copy) @@ -1946,6 +1946,10 @@ if (cnt->conf.setup_mode) { event(cnt, EVENT_IMAGE, cnt->imgs.out, NULL, &cnt->pipe, cnt->currenttime_tm); event(cnt, EVENT_STREAM, cnt->imgs.out, NULL, NULL, cnt->currenttime_tm); +#ifdef HAVE_SDL + if (cnt_list[0]->conf.sdl_threadnr == cnt->threadnr) + event(cnt, EVENT_SDL_PUT, cnt->imgs.out, NULL, NULL, cnt->currenttime_tm); +#endif } else { event(cnt, EVENT_IMAGE, cnt->current_image->image, NULL, &cnt->pipe, &cnt->current_image->timestamp_tm); @@ -1953,6 +1957,11 @@ if (!cnt->conf.stream_motion || cnt->shots == 1) event(cnt, EVENT_STREAM, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); +#ifdef HAVE_SDL + if (cnt_list[0]->conf.sdl_threadnr == cnt->threadnr) + event(cnt, EVENT_SDL_PUT, cnt->current_image->image, NULL, NULL, + &cnt->current_image->timestamp_tm); +#endif } event(cnt, EVENT_IMAGEM, cnt->imgs.out, NULL, &cnt->mpipe, cnt->currenttime_tm); @@ -2528,6 +2537,11 @@ start_motion_thread(cnt_list[i], &thread_attr); } +#ifdef HAVE_SDL + if (cnt_list[0]->conf.sdl_threadnr > 0) + sdl_start(cnt_list[cnt_list[1] != NULL ? cnt_list[0]->conf.sdl_threadnr : 0]->conf.width, + cnt_list[cnt_list[1] != NULL ? cnt_list[0]->conf.sdl_threadnr : 0]->conf.height); +#endif /* Create a thread for the control interface if requested. Create it * detached and with 'motion_web_control' as the thread function. */ @@ -2608,6 +2622,9 @@ } while (restart); /* loop if we're supposed to restart */ +#ifdef HAVE_SDL + sdl_stop(); +#endif // Be sure that http control exits fine cnt_list[0]->finish = 1; SLEEP(1, 0); Index: motion.h =================================================================== --- motion.h (revision 468) +++ motion.h (working copy) @@ -62,6 +62,9 @@ #include "stream.h" #include "webhttpd.h" +#ifdef HAVE_SDL +#include "sdl.h" +#endif /** * ATTRIBUTE_UNUSED: * Index: motion-dist.conf.in =================================================================== --- motion-dist.conf.in (revision 468) +++ motion-dist.conf.in (working copy) @@ -301,7 +301,13 @@ # (default: off) ffmpeg_deinterlace off +############################################################ +# SDL Window +############################################################ +# Number of motion thread to show in SDL Window (default: 0 = disabled) +0 + ############################################################ # External pipe to video encoder # Replacement for FFMPEG builtin encoder for ffmpeg_output_movies only. Index: config.h.in =================================================================== --- config.h.in (revision 468) +++ config.h.in (working copy) @@ -24,6 +24,9 @@ /* Define to 1 if you have PostgreSQL support */ #undef HAVE_PGSQL +/* Define to 1 if you have SDL support */ +#undef HAVE_SDL + /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H Index: event.c =================================================================== --- event.c (revision 468) +++ event.c (working copy) @@ -227,6 +227,16 @@ stream_put(cnt, img); } +#ifdef HAVE_SDL +static void event_sdl_put(struct context *cnt, int type ATTRIBUTE_UNUSED, + unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, + void *dummy2 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) +{ + sdl_put(img, cnt->imgs.width, cnt->imgs.height); +} +#endif + + #if !defined(WITHOUT_V4L) && !defined(BSD) static void event_vid_putpipe(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy ATTRIBUTE_UNUSED, void *devpipe, @@ -766,6 +776,12 @@ EVENT_IMAGE_SNAPSHOT, event_image_snapshot }, +#ifdef HAVE_SDL + { + EVENT_SDL_PUT, + event_sdl_put + }, +#endif #if !defined(WITHOUT_V4L) && !defined(BSD) { EVENT_IMAGE, Index: event.h =================================================================== --- event.h (revision 468) +++ event.h (working copy) @@ -30,6 +30,7 @@ #define EVENT_AREA_DETECTED 17 #define EVENT_CAMERA_LOST 18 #define EVENT_FFMPEG_PUT 19 +#define EVENT_SDL_PUT 20 typedef void(* event_handler)(struct context *, int, unsigned char *, char *, void *, struct tm *); Index: logger.c =================================================================== --- logger.c (revision 468) +++ logger.c (working copy) @@ -77,7 +77,7 @@ { int errno_save, n; char buf[1024]; -#if (!defined(BSD)) && (!(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE) +#if (!defined(BSD)) char msg_buf[100]; #endif va_list ap;