diff --git a/.gitignore b/.gitignore index 9e38ca5..9eefd5d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,21 @@ *.log .svn/ *.o +autom4te.cache +aclocal.m4 +.depend +motion +config.h +config.status +config.h.in +Makefile +configure +motion-dist.conf +motion.init-Debian +motion.init-FreeBSD.sh +motion.service +motion.spec +camera1-dist.conf +camera2-dist.conf +camera3-dist.conf +camera4-dist.conf diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..79eb3aa --- /dev/null +++ b/.travis.yml @@ -0,0 +1,42 @@ +before_script: + - autoreconf -fiv + - avplay -version +script: ./configure && make + +matrix: + include: + - os: linux + language: c + compiler: gcc + addons: + apt: + packages: + - libavformat-dev + - libavcodec-dev + - libav-tools + - libavutil-dev + - libswscale-dev + - ffmpeg + - libjpeg8-dev + - libv4l-dev + - libzip-dev + - os: linux + language: c + compiler: gcc + sudo: rquired + dist: trusty + addons: + apt: + sources: + - sourceline: 'ppa:mc3man/trusty-media' + packages: + - libavformat-dev + - libavcodec-dev + - libav-tools + - libavutil-dev + - libswscale-dev + - ffmpeg + - libjpeg8-dev + - libv4l-dev + - libzip-dev + diff --git a/CHANGELOG b/CHANGELOG index 10ca2c2..084d5cb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,73 @@ -SVN trunk Summary of Changes +Summary of Changes + * ffmpeg_variable_bitrate to values of 0-100 and ffmpeg fixes + * Better messages for pkg-config + * Fix timelapse crash when selecting mpeg4 +Version 3.4.1 Changes Below + * Added suggestion for including pkgconf as part of build requirements + * Swap sequence of user ffmpeg path and PKG_CONFIG_PATH + * Allow : in non standard locations of netcam_url path. + * Eliminated the use of coded_frame (Was a redundant assignment) + * Revise HEVC to use H264 for older ffmpeg + * Add HEVC codec option for newer ffmpeg (momo-i) + * Makefile changes to align with Debian package and fixes from previous changes + * Revise description for netcam_url in configuration file. + * Change default for ffmpeg in configure.ac (Issue 795002,82) + To compile without ffmpeg now requires --without-ffmpeg option + * Change prefix to use sysconfdir instead. Install threadX.conf files to threadx-dist.conf + * Revise configure.ac to use pkg-config for ffmpeg(Rex Feany) + * Revise PIX_FMT to be able to use older ffmpeg versions. + * Revise PIX_FMT for newer ffmpeg(Rex Feany) + * Add patch for ports on proxy netcams from GVautier (issue 144906) + * Add patch from JonGuess(issue 151452) for treatment of partial netcam images. + * Consolidate the Sqlite3 options into the code standard. + * Draft revised motion_guide.html with new options. + * Revise manual to have current options. + * Tab/Space cleanup and validation security issue addressed. (issue 071831) + * Add preview to webcontrol page(issue 172526) + * Additional container fixes(requests/bugs 201900,110304,001656,050731) + * Remove depreciated deinterlace option + * Remove avformat_network_init call. Call was not needed and was leaking memory + * Add extra container options for ffmpeg videos + * Remove extra bytes before SOI marker on netcam images. + * Updated handling of lastsnap to permit subdirectory specification. + * Handle MJPEG streams from some Logitech webcams which send AVI1 instead of JFIF. + * Fix missing header for some builds(Jim Dodgen) + * Sqlite3 revisions (Jim Dodgen) + * Add new config options to the motion-dist.conf + * Allow text format specifiers to take a width like printf would. (David Fries) + * Allow text format specifiers to take a width like printf would. (David Fries) + * Add power_line_frequency configuration item to improve image quality. (David Fries) + * Fix webhttpd race condition crash with SIGHUP, add it to running thread counter (David Fries) + * Fix the GOP size for the created videos + * Fix netcam ftp functionality + * Fix Typo on the log level + * Fixed the network ftp image option. + * Lock thread on ffmpeg/libav init and open_codec + * Revise version number generated by script to indicate Unofficial-Git-'hash' + * Revised Changelog description for version 3.4 + * Merge OpenBSD fixes from sthen pull request + * Revised picture.c to allow for modulo 8 pictures and adjusted netcam modules accordingly as well.(closes 135313) + * Changes to ffmpeg.h/ffmpeg.c to allow for compiling without ffmpeg/libav or with older versions. + * Merge mymalloc, free and casting changes from Alfred Klomp + * Merge bug fix for sizeof from Alfred Klomp + * Rewrote timelapse so that it works(closes 180501) + * Merge tosiara changes for version number + * Add copyright file for features added since 3.2.12 + * Cleanup ffmpeg.c and plug memory leak + * Add support for latest version of ffmpeg/libav + * Tidy up packaging changes + * Add packaging fixes (infinity0) + * Revise version.sh to put out the git commit. + * Rollback revision to allow for a formal pull request. + * Reimplement changes not to be included in pull request from tosiara commit 9ebee031 + * Implement requirement of modulo 16 to avoid seg fault when opening stream + * Add debian build files from trusty(14.04) + * Revise default values for motion.conf + * Revise CHANGELOG to conform with debian format + * Revised debian packaging files + * Implement new sequence for this file (CHANGELOG) newest to oldest. + +Summary of Changes that were proposed to maintainer for a version 3.4 Features * Insert Blanking frames http://www.lavrsen.dk/twiki/bin/view/Motion/FeatureRequest2007x12x16x132522 (Dag Erlandsson) @@ -49,6 +118,39 @@ Features http://www.lavrsen.dk/foswiki/bin/view/Motion/OggTimelapse (Michael Luich) * Added support for ffmpeg 0.11 new API. * Added RSTP support for netcam ( merge https://github.com/hyperbolic2346/motion ) + * Merge tosiara/rtsp branch (commit 46cfcf31d, 2014/05/21) (Mr-Dave) + * 3fps bugfix from SVN rev559 (tosiara, Joerg Weber) + * Buffer overflow vulnerabilities (hyperbolic2346) + * Redundand -- boundary prefix (torao) + * Removed compiler warnings: (Mr-Dave) + logger.c,jpegutils.c,netcam_ftp.c,track.c, + picture.c,webhttpd.c,stream.c,ffmpeg.c + * Bug fix as part of warnings in webhttpd.c fixed(Mr-Dave) + * Removed compiler warning regarding ffmpeg being newer than 0.4 version(Mr-Dave) + * New configure script and identification of ffmpeg version and additional libs. (Mr-Dave) + * Resolve additional compiler warnings in ffmpeg (Mr-Dave) + * Revised INSTALL with samples(Mr-Dave) + * Revisions for RTSP and code standard.(Mr-Dave) + * Plugged most memory leaks in RTSP. (Mr-Dave) + * Undo changes caused by code editor and other unnecessary changes (Mr-Dave) + * Moved call to netcam_shutdown_rtsp into netcam_cleanup where it belongs. (Mr-Dave) + * Regession fix for memory leaks and reconnection (Mr-Dave) + * Eliminated requirement to manually build FFMPEG for RTSP support. (Mr-Dave) + * Revised RTSP to support version 53 of libavformat (Mr-Dave) + * Revised FFMPEG.c to eliminate warnings and functions no longer supported by Libav/FFMPEG(Mr-Dave) + * Revised INSTALL to have sample PI configure option.(Mr-Dave) + * Revised configure.ac to generate compiler flag AVFMT_V53.(Mr-Dave) + * Revised INSTALL to indicate standard APT packages for RTSP (Mr-Dave) + * Revised configure.ac to recognize libavformat version 54 RTSP (Mr-Dave) + * Clean up the messaging for RTSP. + * Additional validations for RTSP connection and corrected free sequences + * Removed seg fault on failure to open first image, comments, isolation of RTSP + * Add AC_GNU_SOURCE macro to check for GNU C Library, fix compile when no FFMpeg. + * Implement inits of AV functions from bcl fork + * Add gray image upon disconnection + * Added tcp/udp transport config option from hyperbolic2346(commit 423ef7bb3) + * Revised comments to be in line with application standard. + * Restructure rtsp to handle rescaling and non YUV420 format, rotate, MJPEG input format Bugfixes * Avoid segfault detecting strerror_r() version GNU or SUSv3. (Angel Carpintero) @@ -98,7 +200,7 @@ Bugfixes http://www.lavrsen.dk/foswiki/bin/view/Motion/BugReport2010x04x28x054348 -3.2.11.1 Sumary of Changes +3.2.11.1 Summary of Changes Bugfixes * Fix Segfault on reload or quit for vloopback (maybe other v4l1 devices too) (Peter Holik) diff --git a/CREDITS b/CREDITS index 89390a7..02434b1 100644 --- a/CREDITS +++ b/CREDITS @@ -473,6 +473,11 @@ Mark Feenstra Miguel Freitas * Came up with the round robing idea. +David Fries + * Fix webhttpd race condition crash with SIGHUP, add it to running thread counter + * Allow text format specifiers to take a width like printf would. + * Add power_line_frequency configuration item to improve image quality. + Aaron Gage * Pointed me to the vid_mmap/int problem when calling SYNC in video.c diff --git a/FAQ b/FAQ index f4cc8ff..d34b806 100644 --- a/FAQ +++ b/FAQ @@ -1,24 +1,2 @@ This FAQ is no longer kept up to date -Look at this URL for a more up to date wiki based FAQ -http://www.lavrsen.dk/twiki/bin/view/Motion/FrequentlyAskedQuestions - -Q: motion crashes while parsing the config file. - -A: Appearantly the behaviour of strtok in glibc has changed somewhat. - This problem should be fixed as of 2.3 - - -Q: Were does motion look for the config file? - -A: First it will look for 'motion.conf' in the current directory, next it will - try to find '.motion/motion.conf' in your home directory (pointed to by - the HOME environment variable). If these don't exist it will try to open - '/usr/local/etc/motion.conf' if you specified /usr/local as the prefix to - configure (this is the default). - -Q: What codingstyle is used for motion? - -A: Motion follows the same style as the linux kernel. - Read Documentation/Codingstyle in the kernel tree for some good reasons. - Also be aware that motion is multithreaded and as such all functions should - be reentrant, using static variables is usually a bad idea. +Look at the guide in /usr/share/doc/motion/motion_guide.html diff --git a/INSTALL b/INSTALL index 5063740..618f5ed 100644 --- a/INSTALL +++ b/INSTALL @@ -1,16 +1,46 @@ -Very simple: +The following is a brief overview of the building and installing instructions. -type: +For full instructions on how to build and install Motion, see the +motion_guide.html that is distributed with this source code. - ./configure +The building instructions vary based upon the base system and the desired options. +For most installs, it will be desired to include either ffmpeg or libav and these will +have associated dependencies which dictate the configuration options. -followed by: +Build Packages: + autoconf + automake + pkgconf + libtool + libjpeg8-dev + build-essential + libzip-dev - make +The option to include FFMPEG or Libav functionality in motion is a choice of one OR the other not both. +The packages and library names change frequently and vary across base operating systems. If ffmpeg or +libav are built and installed from source the custom motion configuration options will usually be needed. -And +FFMPEG Packages + ffmpeg + libavformat-dev + libavcodec-dev + libavutil-dev + libswscale-dev + +Libav Packages + libavformat-dev + libavcodec-dev + libavutil-dev + libav-tools + libswscale-dev +Once required packages are installed, execute: + autoreconf -fiv + ./configure + make make install - -Next read the README +Sample custom configuration options: + --prefix : Specify the install location for the motion package + --with-ffmpeg=[dir] : Specify the location in which ffmpeg/libav is installed. + diff --git a/Makefile.in b/Makefile.in index 546eeb1..22a77be 100644 --- a/Makefile.in +++ b/Makefile.in @@ -7,11 +7,12 @@ # Please read the file COPYING for more info. # ################################################################################ # Please visit the Motion home page: # -# http://www.lavrsen.dk/twiki/bin/view/Motion # +# https://motion-project.github.io/ # ################################################################################ CC = @CC@ INSTALL = install +INSTALL_DATA = ${INSTALL} -m 644 ################################################################################ # Install locations, controlled by setting configure flags. # @@ -23,24 +24,26 @@ mandir = @mandir@ sysconfdir = @sysconfdir@ datadir = @datadir@ datarootdir = @datarootdir@ -docdir = $(datadir)/doc/@PACKAGE_NAME@-@PACKAGE_VERSION@ -examplesdir = $(datadir)/@PACKAGE_NAME@-@PACKAGE_VERSION@/examples +docdir = $(datadir)/doc/@PACKAGE_NAME@ +examplesdir = $(datadir)/@PACKAGE_NAME@/examples ################################################################################ # These variables contain compiler flags, object files to build and files to # # install. # ################################################################################ -CFLAGS = @CFLAGS@ -Wall -DVERSION=\"@PACKAGE_VERSION@\" -Dsysconfdir=\"$(sysconfdir)\" +CFLAGS = @CFLAGS@ -Wall -DVERSION=\"@PACKAGE_VERSION@\" -Dsysconfdir=\"$(sysconfdir)\" @FFMPEG_CFLAGS@ @MMAL_CFLAGS@ LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ +LIBS = @LIBS@ @MMAL_LIBS@ @FFMPEG_LIBS@ VIDEO_OBJ = @VIDEO@ 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 md5.o @FFMPEG_OBJ@ @SDL_OBJ@ @RTPS_OBJ@ + stream.o md5.o netcam_rtsp.o \ + @FFMPEG_OBJ@ @MMAL_OBJ@ @SDL_OBJ@ SRC = $(OBJ:.o=.c) -DOC = CHANGELOG COPYING CREDITS INSTALL README motion_guide.html -EXAMPLES = *.conf motion.init-Debian motion.init-Fedora motion.init-FreeBSD.sh +DOC = CHANGELOG COPYING CREDITS README motion_guide.html mask1.png normal.jpg outputmotion1.jpg outputnormal1.jpg +EXAMPLES = *.conf motion.service +EXAMPLES_BIN = motion.init-Debian motion.init-FreeBSD.sh PROGS = motion DEPEND_FILE = .depend @@ -64,7 +67,6 @@ pre-build-info: @echo "Welcome to the setup procedure for Motion, the motion detection daemon! If you get" @echo "error messages during this procedure, please report them to the mailing list. The" @echo "Motion Guide contains all information you should need to get Motion up and running." - @echo "Run \"make updateguide\" to download the latest version of the Motion Guide." @echo @echo "Version: @PACKAGE_VERSION@" ifneq (,$(findstring freebsd,$(VIDEO_OBJ))) @@ -153,12 +155,12 @@ svn: svn update autotools: - @sed -i 's/.\/commit-version.sh/.\/version.sh/g' configure.in + @sed -i 's/.\/commit-version.sh/.\/version.sh/g' configure.ac autoconf ./configure --with-developer-flags autotools-git: - @sed -i 's/.\/git-commit-version.sh/.\/version.sh/g' configure.in + @sed -i 's/.\/git-commit-version.sh/.\/version.sh/g' configure.ac autoconf ./configure --with-developer-flags @@ -166,15 +168,15 @@ autotools-git: build-commit: distclean svn set-version all set-version: - @sed -i 's/.\/version.sh/.\/commit-version.sh/g' configure.in + @sed -i 's/.\/version.sh/.\/commit-version.sh/g' configure.ac autoconf - @sed -i 's/.\/commit-version.sh/.\/version.sh/g' configure.in + @sed -i 's/.\/commit-version.sh/.\/version.sh/g' configure.ac ./configure --with-developer-flags set-version-git: - @sed -i 's/.\/version.sh/.\/git-commit-version.sh/g' configure.in + @sed -i 's/.\/version.sh/.\/git-commit-version.sh/g' configure.ac autoconf - @sed -i 's/.\/git-commit-version.sh/.\/version.sh/g' configure.in + @sed -i 's/.\/git-commit-version.sh/.\/version.sh/g' configure.ac ./configure --with-developer-flags @@ -193,6 +195,7 @@ help: @echo "--------------------------------------------------------------------------------" @echo + ################################################################################ # INSTALL installs all relevant files. # ################################################################################ @@ -201,20 +204,30 @@ install: @echo "--------------------------------------------------------------------------------" mkdir -p $(DESTDIR)$(bindir) mkdir -p $(DESTDIR)$(mandir)/man1 - mkdir -p $(DESTDIR)$(sysconfdir) + mkdir -p $(DESTDIR)$(sysconfdir)/motion mkdir -p $(DESTDIR)$(docdir) mkdir -p $(DESTDIR)$(examplesdir) - $(INSTALL) motion.1 $(DESTDIR)$(mandir)/man1 - $(INSTALL) $(DOC) $(DESTDIR)$(docdir) - $(INSTALL) $(EXAMPLES) $(DESTDIR)$(examplesdir) - $(INSTALL) motion-dist.conf $(DESTDIR)$(sysconfdir) + @sed -i 's|$${prefix}|$(prefix)|' motion-dist.conf + @sed -i 's|$${prefix}|$(prefix)|' camera1-dist.conf + @sed -i 's|$${prefix}|$(prefix)|' camera2-dist.conf + @sed -i 's|$${prefix}|$(prefix)|' camera3-dist.conf + @sed -i 's|$${prefix}|$(prefix)|' camera4-dist.conf + $(INSTALL_DATA) motion.1 $(DESTDIR)$(mandir)/man1 + $(INSTALL_DATA) $(DOC) $(DESTDIR)$(docdir) + $(INSTALL_DATA) $(EXAMPLES) $(DESTDIR)$(examplesdir) + $(INSTALL) $(EXAMPLES_BIN) $(DESTDIR)$(examplesdir) + $(INSTALL_DATA) motion-dist.conf $(DESTDIR)$(sysconfdir)/motion + $(INSTALL_DATA) camera1-dist.conf $(DESTDIR)$(sysconfdir)/motion + $(INSTALL_DATA) camera2-dist.conf $(DESTDIR)$(sysconfdir)/motion + $(INSTALL_DATA) camera3-dist.conf $(DESTDIR)$(sysconfdir)/motion + $(INSTALL_DATA) camera4-dist.conf $(DESTDIR)$(sysconfdir)/motion for prog in $(PROGS); \ do \ ($(INSTALL) $$prog $(DESTDIR)$(bindir) ); \ done @echo "--------------------------------------------------------------------------------" @echo "Install complete! The default configuration file, motion-dist.conf, has been" - @echo "installed to $(sysconfdir). You need to rename/copy it to $(sysconfdir)/motion.conf" + @echo "installed to $(sysconfdir)/motion. You need to rename/copy it to motion.conf" @echo "for Motion to find it. More configuration examples as well as init scripts" @echo "can be found in $(examplesdir)." @echo @@ -230,7 +243,11 @@ uninstall remove: pre-build-info ($ rm -f $(bindir)/$$prog ); \ done rm -f $(mandir)/man1/motion.1 - rm -f $(sysconfdir)/motion-dist.conf + rm -f $(sysconfdir)/motion/motion-dist.conf + rm -f $(sysconfdir)/motion/camera1-dist.conf + rm -f $(sysconfdir)/motion/camera2-dist.conf + rm -f $(sysconfdir)/motion/camera3-dist.conf + rm -f $(sysconfdir)/motion/camera4-dist.conf rm -rf $(docdir) rm -rf $(examplesdir) @echo "--------------------------------------------------------------------------------" @@ -243,7 +260,7 @@ uninstall remove: pre-build-info ################################################################################ clean: pre-build-info @echo "Removing compiled files and binaries..." - @rm -f *~ *.jpg *.o $(PROGS) combine $(DEPEND_FILE) + @rm -f *~ *.o $(PROGS) combine $(DEPEND_FILE) ################################################################################ # DIST restores the directory to distribution state. # @@ -259,21 +276,10 @@ dist: distclean updateguide ################################################################################ distclean: clean @echo "Removing files generated by configure..." - @rm -f config.status config.log config.cache Makefile motion.init-Fedora motion.init-Debian motion.init-FreeBSD.sh - @rm -f thread1.conf thread2.conf thread3.conf thread4.conf motion-dist.conf motion-help.conf motion.spec + @rm -f config.status config.log config.cache Makefile motion.service motion.init-Debian motion.init-FreeBSD.sh + @rm -f camera1-dist.conf camera2-dist.conf camera3-dist.conf camera4-dist.conf motion-dist.conf motion-help.conf motion.spec @rm -rf autom4te.cache config.h @echo "You will need to re-run configure if you want to build Motion." @echo -################################################################################ -# UPDATEGUIDE downloads the Motion Guide from TWiki. # -################################################################################ -updateguide: pre-build-info - @echo "Downloading Motion Guide. If it fails, please check your Internet connection." - @echo - wget www.lavrsen.dk/twiki/bin/view/Motion/MotionGuideOneLargeDocument?skin=text -O motion_guide.tmp - @echo "Cleaning up and fixing links..." - @cat motion_guide.tmp | sed -e 's/\?skin=text//g;s,"/twiki/,"http://www.lavrsen.dk/twiki/,g' > motion_guide.html - @rm -f motion_guide.tmp - @echo "All done, you should now have an up-to-date local copy of the Motion guide." - @echo + diff --git a/README b/README index 624e03c..795ce87 100644 --- a/README +++ b/README @@ -41,20 +41,17 @@ Read the motion.1 manpage for more info And most of all read the Motion Guide for very detailed description of both installation and use. -The Motion Guide is part of the distribution (motion_guide.htm). -You are encouraged to look up an up to date version by visiting the Motion -homepage at -http://www.lavrsen.dk/twiki/bin/view/Motion/WebHome -and specifically the Motion Guide at -http://www.lavrsen.dk/twiki/bin/view/Motion/MotionGuide +The Motion Guide is part of the distribution (/usr/share/doc/motion/motion_guide.html). +You are encouraged to visit the Motion homepage at +https://motion-project.github.io/ Support: -Lots of resources at http://www.lavrsen.dk/twiki/bin/view/Motion/WebHome +Lots of resources at https://motion-project.github.io/ Please join the mailing list -http://www.lavrsen.dk/twiki/bin/view/Motion/MailingList +https://lists.sourceforge.net/lists/listinfo/motion-user Newbies and silly questions are welcome. We prefer support through the mailing list because more will have benefit from the answers. diff --git a/README.FreeBSD b/README.FreeBSD index 2980532..b204cd4 100644 --- a/README.FreeBSD +++ b/README.FreeBSD @@ -76,13 +76,4 @@ Packages needed (dependencies for 6.x): - And many others ... Any question / fix / suggestion please send it to motion mailing list. - - - http://www.lavrsen.dk/twiki/bin/view/Motion/FreeBSD - - * WEBCAMS - ---------- - http://www.lavrsen.dk/twiki/bin/view/Motion/HowtoMotionPwcFreeBSD - - Angel Carpintero - ack@telefonica.net + \ No newline at end of file diff --git a/README.axis_2100 b/README.axis_2100 deleted file mode 100644 index 67a870e..0000000 --- a/README.axis_2100 +++ /dev/null @@ -1,21 +0,0 @@ -Using motion with the Axis 2100 network camera - -First compile the motion binary as described in README and INSTALL -Then edit motion.conf: Add your axis cameras ip address to the netcam_url -paramter in the "Captute Device Options" section. - - To increase the performance use this urls : - - # for multipart jpeg - http://192.168.1.10/axis-cgi/mjpg/video.cgi?showlength=1 - - or - - # for single jpeg - http://192.168.1.10/axis-cgi/jpg/image.cgi?showlength=1 - -There are only two valid picture sizes for the axis camera: 320x240 and 640x480 - -TODO: - - - Make the IP changeable at run-time. diff --git a/alg.c b/alg.c index 93c260f..226ebd7 100644 --- a/alg.c +++ b/alg.c @@ -526,6 +526,8 @@ static int alg_labeling(struct context *cnt) int height = imgs->height; int labelsize = 0; int current_label = 2; + /* Keep track of the area just under the threshold. */ + int max_under = 0; cnt->current_image->total_labels = 0; imgs->labelsize_max = 0; @@ -534,7 +536,7 @@ static int alg_labeling(struct context *cnt) imgs->labels_above = 0; /* Init: 0 means no label set / not checked. */ - memset(labels, 0, width * height * sizeof(labels)); + memset(labels, 0, width * height * sizeof(*labels)); pixelpos = 0; for (iy = 0; iy < height - 1; iy++) { @@ -561,7 +563,8 @@ static int alg_labeling(struct context *cnt) labelsize = iflood(ix, iy, width, height, out, labels, current_label + 32768, current_label); imgs->labelgroup_max += labelsize; imgs->labels_above++; - } + } else if(max_under < labelsize) + max_under = labelsize; if (imgs->labelsize_max < labelsize) { imgs->labelsize_max = labelsize; @@ -579,8 +582,11 @@ static int alg_labeling(struct context *cnt) "Largest Label: %i", imgs->largest_label, imgs->labelsize_max, cnt->current_image->total_labels); - /* Return group of significant labels. */ - return imgs->labelgroup_max; + /* Return group of significant labels or if that's none, the next largest + * group (which is under the threshold, but especially for setup gives an + * idea how close it was). + */ + return imgs->labelgroup_max ? imgs->labelgroup_max : max_under; } /** @@ -1363,6 +1369,6 @@ void alg_update_reference_frame(struct context *cnt, int action) /* Copy fresh image */ memcpy(cnt->imgs.ref, cnt->imgs.image_virgin, cnt->imgs.size); /* Reset static objects */ - memset(cnt->imgs.ref_dyn, 0, cnt->imgs.motionsize * sizeof(cnt->imgs.ref_dyn)); + memset(cnt->imgs.ref_dyn, 0, cnt->imgs.motionsize * sizeof(*cnt->imgs.ref_dyn)); } } diff --git a/thread1.conf.in b/camera1-dist.conf.in similarity index 67% rename from thread1.conf.in rename to camera1-dist.conf.in index f6d5fe8..12f2410 100644 --- a/thread1.conf.in +++ b/camera1-dist.conf.in @@ -1,13 +1,17 @@ -# /usr/local/etc/thread1.conf +# @sysconfdir@/motion/camera1.conf # -# This config file was generated by @PACKAGE_NAME@ @PACKAGE_VERSION@ - - +# This config file was generated by @PACKAGE_NAME@ @PACKAGE_VERSION@ ########################################################### # Capture device options ############################################################ +# Camera Id +# Consistent identification number to assign to each camera across multiple +# invocations of Motion. +# Default: The order when the camera file was read +# camera_id = 1 + # Videodevice to be used for capturing (default /dev/video0) # for FreeBSD default is /dev/bktr0 videodevice /dev/video0 @@ -28,7 +32,7 @@ text_left CAMERA 1 # you can use conversion specifiers # %Y = year, %m = month, %d = date, # %H = hour, %M = minute, %S = second, -# %v = event, %q = frame number, %t = thread (camera) number, +# %v = event, %q = frame number, %t = camera id number, # %D = changed pixels, %N = noise level, # %i and %J = width and height of motion area, # %K and %L = X and Y coordinates of motion center @@ -38,7 +42,16 @@ text_left CAMERA 1 # Target base directory for pictures and films # Recommended to use absolute patch. (Default: current working directory) -target_dir /usr/local/apache2/htdocs/cam1 +#target_dir /tmp/motion/cam1 + +# File path for motion triggered images (jpeg or ppm) relative to target_dir +# Default: %v-%Y%m%d%H%M%S-%q +# Default value is equivalent to legacy oldlayout option +# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H/%M/%S-%q +# File extension .jpg or .ppm is automatically added so do not include this +# Set to 'preview' together with best-preview feature enables special naming +# convention for preview shots. See motion guide for details +picture_filename CAM1_%v-%Y%m%d%H%M%S-%q ############################################################ @@ -50,8 +63,9 @@ stream_port 8081 # Command to be executed when a picture (.ppm|.jpg) is saved (default: none) # The filename of the picture is appended as an argument for the command. -on_picture_save /usr/local/motion-extras/camparse1.pl +#on_picture_save /usr/local/motion-extras/camparse2.pl # Command to be executed when a movie file (.mpg|.avi) is closed. (default: none) # Filename of movie is appended as an argument for the command. -on_movie_end /usr/local/motion-extras/mpegparse1.pl +#on_movie_end /usr/local/motion-extras/mpegparse2.pl + diff --git a/thread2.conf.in b/camera2-dist.conf.in similarity index 67% rename from thread2.conf.in rename to camera2-dist.conf.in index d0b8b2a..65d54ea 100644 --- a/thread2.conf.in +++ b/camera2-dist.conf.in @@ -1,13 +1,17 @@ -# /usr/local/etc/thread2.conf +# @sysconfdir@/motion/camera2.conf # # This config file was generated by @PACKAGE_NAME@ @PACKAGE_VERSION@ - - ########################################################### # Capture device options ############################################################ +# Camera Id +# Consistent identification number to assign to each camera across multiple +# invocations of Motion. +# Default: The order when the camera file was read +# camera_id = 2 + # Videodevice to be used for capturing (default /dev/video0) # for FreeBSD default is /dev/bktr0 videodevice /dev/video1 @@ -28,7 +32,7 @@ text_left CAMERA 2 # you can use conversion specifiers # %Y = year, %m = month, %d = date, # %H = hour, %M = minute, %S = second, -# %v = event, %q = frame number, %t = thread (camera) number, +# %v = event, %q = frame number, %t = camera id number, # %D = changed pixels, %N = noise level, # %i and %J = width and height of motion area, # %K and %L = X and Y coordinates of motion center @@ -38,7 +42,16 @@ text_left CAMERA 2 # Target base directory for pictures and films # Recommended to use absolute patch. (Default: current working directory) -target_dir /usr/local/apache2/htdocs/cam2 +#target_dir /tmp/motion/cam2 + +# File path for motion triggered images (jpeg or ppm) relative to target_dir +# Default: %v-%Y%m%d%H%M%S-%q +# Default value is equivalent to legacy oldlayout option +# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H/%M/%S-%q +# File extension .jpg or .ppm is automatically added so do not include this +# Set to 'preview' together with best-preview feature enables special naming +# convention for preview shots. See motion guide for details +picture_filename CAM2_%v-%Y%m%d%H%M%S-%q ############################################################ @@ -50,9 +63,9 @@ stream_port 8082 # Command to be executed when a picture (.ppm|.jpg) is saved (default: none) # The filename of the picture is appended as an argument for the command. -on_picture_save /usr/local/motion-extras/camparse2.pl +#on_picture_save /usr/local/motion-extras/camparse2.pl # Command to be executed when a movie file (.mpg|.avi) is closed. (default: none) # Filename of movie is appended as an argument for the command. -on_movie_end /usr/local/motion-extras/mpegparse2.pl +#on_movie_end /usr/local/motion-extras/mpegparse2.pl diff --git a/thread3.conf.in b/camera3-dist.conf.in similarity index 67% rename from thread3.conf.in rename to camera3-dist.conf.in index 2192805..933f038 100644 --- a/thread3.conf.in +++ b/camera3-dist.conf.in @@ -1,13 +1,17 @@ -# /usr/local/etc/thread3.conf +# @sysconfdir@/motion/camera3.conf # -# This config file was generated by @PACKAGE_NAME@ @PACKAGE_VERSION@ - - +# This config file was generated by @PACKAGE_NAME@ @PACKAGE_VERSION@ ########################################################### # Capture device options ############################################################ +# Camera Id +# Consistent identification number to assign to each camera across multiple +# invocations of Motion. +# Default: The order when the camera file was read +# camera_id = 3 + # Videodevice to be used for capturing (default /dev/video0) # for FreeBSD default is /dev/bktr0 videodevice /dev/video2 @@ -28,7 +32,7 @@ text_left CAMERA 3 # you can use conversion specifiers # %Y = year, %m = month, %d = date, # %H = hour, %M = minute, %S = second, -# %v = event, %q = frame number, %t = thread (camera) number, +# %v = event, %q = frame number, %t = camera id number, # %D = changed pixels, %N = noise level, # %i and %J = width and height of motion area, # %K and %L = X and Y coordinates of motion center @@ -38,7 +42,16 @@ text_left CAMERA 3 # Target base directory for pictures and films # Recommended to use absolute patch. (Default: current working directory) -target_dir /usr/local/apache2/htdocs/cam3 +#target_dir /tmp/motion/cam3 + +# File path for motion triggered images (jpeg or ppm) relative to target_dir +# Default: %v-%Y%m%d%H%M%S-%q +# Default value is equivalent to legacy oldlayout option +# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H/%M/%S-%q +# File extension .jpg or .ppm is automatically added so do not include this +# Set to 'preview' together with best-preview feature enables special naming +# convention for preview shots. See motion guide for details +picture_filename CAM3_%v-%Y%m%d%H%M%S-%q ############################################################ @@ -50,11 +63,9 @@ stream_port 8083 # Command to be executed when a picture (.ppm|.jpg) is saved (default: none) # The filename of the picture is appended as an argument for the command. -on_picture_save /usr/local/motion-extras/camparse3.pl +#on_picture_save /usr/local/motion-extras/camparse2.pl # Command to be executed when a movie file (.mpg|.avi) is closed. (default: none) # Filename of movie is appended as an argument for the command. -on_movie_end /usr/local/motion-extras/mpegparse3.pl - - +#on_movie_end /usr/local/motion-extras/mpegparse2.pl diff --git a/thread4.conf.in b/camera4-dist.conf.in similarity index 58% rename from thread4.conf.in rename to camera4-dist.conf.in index 64a6363..8d3b13a 100644 --- a/thread4.conf.in +++ b/camera4-dist.conf.in @@ -1,38 +1,38 @@ -# /usr/local/etc/thread4.conf +# @sysconfdir@/motion/camera4.conf # -# This config file was generated by @PACKAGE_NAME@ @PACKAGE_VERSION@ +# This config file was generated by @PACKAGE_NAME@ @PACKAGE_VERSION@ ########################################################### # Capture device options ############################################################ -# URL to use if you are using a network camera, size will be autodetected (incl http:// ftp:// or file:///) -# Must be a URL that returns single jpeg pictures or a raw mjpeg stream. Default: Not defined -netcam_url http://192.168.1.6:8093/ +# Camera Id +# Consistent identification number to assign to each camera across multiple +# invocations of Motion. +# Default: The order when the camera file was read +# camera_id = 4 -# The setting for keep-alive of network socket, should improve performance on compatible net cameras. -# off: The historical implementation using HTTP/1.0, closing the socket after each http request. -# force: Use HTTP/1.0 requests with keep alive header to reuse the same connection. -# on: Use HTTP/1.1 requests that support keep alive as default. -# Default: off -netcam_keepalive force +# Videodevice to be used for capturing (default /dev/video0) +# for FreeBSD default is /dev/bktr0 +videodevice /dev/video3 -# Set less strict jpeg checks for network cameras with a poor/buggy firmware. -# Default: off -netcam_tolerant_check on +# The video input to be used (default: -1) +# Should normally be set to 1 for video/TV cards, and -1 for USB cameras +input -1 # Draw a user defined text on the images using same options as C function strftime(3) # Default: Not defined = no text # Text is placed in lower left corner text_left CAMERA 4 + ############################################################ # Target Directories and filenames For Images And Films # For the options snapshot_, picture_, mpeg_ and timelapse_filename # you can use conversion specifiers # %Y = year, %m = month, %d = date, # %H = hour, %M = minute, %S = second, -# %v = event, %q = frame number, %t = thread (camera) number, +# %v = event, %q = frame number, %t = camera id number, # %D = changed pixels, %N = noise level, # %i and %J = width and height of motion area, # %K and %L = X and Y coordinates of motion center @@ -42,7 +42,16 @@ text_left CAMERA 4 # Target base directory for pictures and films # Recommended to use absolute patch. (Default: current working directory) -target_dir /usr/local/apache2/htdocs/cam4 +#target_dir /tmp/motion/cam4 + +# File path for motion triggered images (jpeg or ppm) relative to target_dir +# Default: %v-%Y%m%d%H%M%S-%q +# Default value is equivalent to legacy oldlayout option +# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H/%M/%S-%q +# File extension .jpg or .ppm is automatically added so do not include this +# Set to 'preview' together with best-preview feature enables special naming +# convention for preview shots. See motion guide for details +picture_filename CAM4_%v-%Y%m%d%H%M%S-%q ############################################################ @@ -54,9 +63,9 @@ stream_port 8084 # Command to be executed when a picture (.ppm|.jpg) is saved (default: none) # The filename of the picture is appended as an argument for the command. -on_picture_save /usr/local/motion-extras/camparse4.pl +#on_picture_save /usr/local/motion-extras/camparse2.pl # Command to be executed when a movie file (.mpg|.avi) is closed. (default: none) # Filename of movie is appended as an argument for the command. -on_movie_end /usr/local/motion-extras/mpegparse4.pl +#on_movie_end /usr/local/motion-extras/mpegparse2.pl diff --git a/commit-version.sh b/commit-version.sh index 04b4bbd..56dfef9 100755 --- a/commit-version.sh +++ b/commit-version.sh @@ -1,5 +1,3 @@ #!/bin/sh - -SNV_VERSION=`cd "$1" && LC_ALL=C svn info 2> /dev/null | grep Revision | cut -d' ' -f2` -SNV_VERSION=`expr $SNV_VERSION + 1` -echo -n "trunkREV$SNV_VERSION" +SNV_VERSION=`git show -s --format=%h` +echo -n "3.4.1+git$SNV_VERSION" diff --git a/conf.c b/conf.c index 2da0da6..2080525 100644 --- a/conf.c +++ b/conf.c @@ -23,6 +23,10 @@ * 4. add a entry to the config_params array below, if your * option should be configurable by the config file. */ + +#include +#include + #include "motion.h" #if (defined(BSD) && !defined(PWCBSD)) @@ -31,6 +35,8 @@ #include "video.h" #endif /* BSD */ +#define EXTENSION ".conf" + #ifndef HAVE_GET_CURRENT_DIR_NAME char *get_current_dir_name(void) { @@ -43,9 +49,11 @@ char *get_current_dir_name(void) #define stripnewline(x) {if ((x)[strlen(x)-1]=='\n') (x)[strlen(x) - 1] = 0; } struct config conf_template = { + camera_name: NULL, width: DEF_WIDTH, height: DEF_HEIGHT, quality: DEF_QUALITY, + camera_id: 0, rotate_deg: 0, max_changes: DEF_CHANGES, threshold_tune: 0, @@ -71,6 +79,7 @@ struct config conf_template = { contrast: 0, saturation: 0, hue: 0, + power_line_frequency: -1, roundrobin_frames: 1, roundrobin_skip: 1, pre_capture: 0, @@ -95,6 +104,8 @@ struct config conf_template = { stream_limit: 0, stream_auth_method: 0, stream_authentication: NULL, + stream_preview_scale: 25, + stream_preview_newline: 0, webcontrol_port: 0, webcontrol_localhost: 1, webcontrol_html_output: 1, @@ -130,9 +141,7 @@ struct config conf_template = { database_user: NULL, database_password: NULL, database_port: 0, -#ifdef HAVE_SQLITE3 - sqlite3_db: NULL, -#endif + database_busy_timeout: 0, #endif /* defined(HAVE_MYSQL) || defined(HAVE_PGSQL) || define(HAVE_SQLITE3) */ on_picture_save: NULL, on_motion_detected: NULL, @@ -146,6 +155,11 @@ struct config conf_template = { netcam_keepalive: "off", netcam_proxy: NULL, netcam_tolerant_check: 0, + rtsp_uses_tcp: 1, +#ifdef HAVE_MMAL + mmalcam_name: NULL, + mmalcam_control_params: NULL, +#endif text_changes: 0, text_left: NULL, text_right: DEF_TIMESTAMP, @@ -159,16 +173,23 @@ struct config conf_template = { log_file: NULL, log_level: LEVEL_DEFAULT+10, log_type_str: NULL, + camera_dir: sysconfdir"/conf.d" }; static struct context **copy_bool(struct context **, const char *, int); static struct context **copy_int(struct context **, const char *, int); -static struct context **config_thread(struct context **cnt, const char *str, int val); +static struct context **config_camera(struct context **cnt, const char *str, int val); +static struct context **read_camera_dir(struct context **cnt, const char *str, + int val); static const char *print_bool(struct context **, char **, int, unsigned int); static const char *print_int(struct context **, char **, int, unsigned int); static const char *print_string(struct context **, char **, int, unsigned int); +static const char *print_camera(struct context **, char **, int, unsigned int); + +/* Deprcated thread config functions */ +static struct context **config_thread(struct context **cnt, const char *str, int val); static const char *print_thread(struct context **, char **, int, unsigned int); static void usage(void); @@ -211,6 +232,15 @@ config_param config_params[] = { print_bool }, { + "camera_name", + "# Name given to a camera. Shown in web interface and may be used with the specifier %$ for filenames and such.\n" + "# Default: not defined", + 0, + CONF_OFFSET(camera_name), + copy_string, + print_string + }, + { "logfile", "# Use a file to save logs messages, if not defined stderr and syslog is used. (default: not defined)", 1, @@ -220,7 +250,7 @@ config_param config_params[] = { }, { "log_level", - "# Level of log messages [1..9] (EMR, ALR, CRT, ERR, WRN, NTC, ERR, DBG, ALL). (default: 6 / NTC)", + "# Level of log messages [1..9] (EMG, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL). (default: 6 / NTC)", 1, CONF_OFFSET(log_level), copy_int, @@ -248,7 +278,7 @@ config_param config_params[] = { }, { "v4l2_palette", - "# v4l2_palette allows to choose preferable palette to be use by motion\n" + "# v4l2_palette allows one to choose preferable palette to be use by motion\n" "# to capture from those supported by your videodevice. (default: 17)\n" "# E.g. if your videodevice supports both V4L2_PIX_FMT_SBGGR8 and\n" "# V4L2_PIX_FMT_MJPEG then motion will by default use V4L2_PIX_FMT_MJPEG.\n" @@ -410,6 +440,36 @@ config_param config_params[] = { copy_bool, print_bool }, + { + "rtsp_uses_tcp", + "# RTSP connection uses TCP to communicate to the camera. Can prevent image corruption.\n" + "# Default: on", + 1, + CONF_OFFSET(rtsp_uses_tcp), + copy_bool, + print_bool + }, +#ifdef HAVE_MMAL + { + "mmalcam_name", + "# Name of camera to use if you are using a camera accessed through OpenMax/MMAL\n" + "# For the raspberry pi official camera, use vc.ril.camera" + "# Default: Not defined", + 0, + CONF_OFFSET(mmalcam_name), + copy_string, + print_string + }, + { + "mmalcam_control_params", + "# Camera control parameters (see raspivid/raspistill tool documentation)\n" + "# Default: Not defined", + 0, + CONF_OFFSET(mmalcam_control_params), + copy_string, + print_string + }, +#endif { "auto_brightness", "# Let motion regulate the brightness of a video device (default: off).\n" @@ -460,6 +520,22 @@ config_param config_params[] = { print_int }, { + "power_line_frequency", + "# Set the power line frequency to help cancel flicker by compensating\n" + "# for light intensity ripple. (default: -1).\n" + "# This can help reduce power line light flicker.\n" + "# Valuse :\n" + "# do not modify the device setting : -1\n" + "# V4L2_CID_POWER_LINE_FREQUENCY_DISABLED : 0\n" + "# V4L2_CID_POWER_LINE_FREQUENCY_50HZ : 1\n" + "# V4L2_CID_POWER_LINE_FREQUENCY_60HZ : 2\n" + "# V4L2_CID_POWER_LINE_FREQUENCY_AUTO : 3", + 0, + CONF_OFFSET(power_line_frequency), + copy_int, + print_int + }, + { "roundrobin_frames", "\n############################################################\n" "# Round Robin (multiple inputs on same video device name)\n" @@ -667,6 +743,16 @@ config_param config_params[] = { print_int }, { + "camera_id", + "Id used to label the camera when inserting data into SQL or saving the\n" + "camera image to disk. This is better than using thread ID so that there\n" + "always is a consistent label\n", + 0, + CONF_OFFSET(camera_id), + copy_int, + print_int + }, + { "picture_type", "# Type of output images\n" "# Valid values: jpeg, ppm (default: jpeg)", @@ -750,19 +836,21 @@ config_param config_params[] = { "# flv - gives you a flash video with extension .flv\n" "# ffv1 - FF video codec 1 for Lossless Encoding ( experimental )\n" "# mov - QuickTime ( testing )\n" - "# ogg - Ogg/Theora ( testing )", + "# ogg - Ogg/Theora ( testing )\n" + "# mp4 - MPEG-4 Part 14 H264 encoding\n" + "# mkv - Matroska H264 encoding\n" + "# hevc - H.265 / HEVC (High Efficiency Video Coding)", 0, CONF_OFFSET(ffmpeg_video_codec), copy_string, print_string }, { - "ffmpeg_deinterlace", - "# Use ffmpeg to deinterlace video. Necessary if you use an analog camera\n" - "# and see horizontal combing on moving objects in video or pictures.\n" - "# (default: off)", + "ffmpeg_duplicate_frames", + "# True to duplicate frames to achieve \"framerate\" fps, but enough\n" + "duplicated frames and the video appears to freeze once a second.", 0, - CONF_OFFSET(ffmpeg_deinterlace), + CONF_OFFSET(ffmpeg_duplicate_frames), copy_bool, print_bool }, @@ -820,7 +908,7 @@ config_param config_params[] = { "# Text Display\n" "# %Y = year, %m = month, %d = date,\n" "# %H = hour, %M = minute, %S = second, %T = HH:MM:SS,\n" - "# %v = event, %q = frame number, %t = thread (camera) number,\n" + "# %v = event, %q = frame number, %t = camera id,\n" "# %D = changed pixels, %N = noise level, \\n = new line,\n" "# %i and %J = width and height of motion area,\n" "# %K and %L = X and Y coordinates of motion center\n" @@ -869,7 +957,7 @@ config_param config_params[] = { copy_string, print_string }, - { + { "text_changes", "# Draw the number of changed pixed on the images (default: off)\n" "# Will normally be set to off except when you setup and adjust the motion settings\n" @@ -918,7 +1006,7 @@ config_param config_params[] = { "# you can use conversion specifiers\n" "# %Y = year, %m = month, %d = date,\n" "# %H = hour, %M = minute, %S = second,\n" - "# %v = event, %q = frame number, %t = thread (camera) number,\n" + "# %v = event, %q = frame number, %t = camera id,\n" "# %D = changed pixels, %N = noise level,\n" "# %i and %J = width and height of motion area,\n" "# %K and %L = X and Y coordinates of motion center\n" @@ -1073,6 +1161,22 @@ config_param config_params[] = { print_string }, { + "stream_preview_scale", + "# Percentage to scale the preview stream image (default: 25)\n", + 0, + CONF_OFFSET(stream_preview_scale), + copy_int, + print_int + }, + { + "stream_preview_newline", + "# Have stream preview image start on a new line (default: no)\n", + 0, + CONF_OFFSET(stream_preview_newline), + copy_bool, + print_bool + }, + { "webcontrol_port", "\n############################################################\n" "# HTTP Based Control\n" @@ -1482,20 +1586,14 @@ config_param config_params[] = { copy_int, print_int }, -#ifdef HAVE_SQLITE3 { - "sqlite3_db", - "\n############################################################\n" - "# Database Options For SQLite3\n" - "############################################################\n\n" - "# SQLite3 database to log to (default: not defined)", + "database_busy_timeout", + "# Database wait for unlock time (default: 0)", 0, - CONF_OFFSET(sqlite3_db), - copy_string, - print_string + CONF_OFFSET(database_busy_timeout), + copy_int, + print_int }, -#endif /* HAVE_SQLITE3 */ - #endif /* defined(HAVE_MYSQL) || defined(HAVE_PGSQL) || defined(HAVE_SQLITE3) */ { "video_pipe", @@ -1519,11 +1617,25 @@ config_param config_params[] = { print_string }, { + "camera", + "\n##############################################################\n" + "# Camera config files - One for each camera.\n" + "# Except if only one camera - You only need this config file.\n" + "# If you have more than one camera you MUST define one camera\n" + "# config file for each camera in addition to this config file.\n" + "##############################################################\n", + 1, + 0, + config_camera, + print_camera + }, + { "thread", "\n##############################################################\n" - "# Thread config files - One for each camera.\n" + "# Deprecated use camera instead of thread.\n" + "# Camera config files - One for each camera.\n" "# Except if only one camera - You only need this config file.\n" - "# If you have more than one camera you MUST define one thread\n" + "# If you have more than one camera you MUST define one camera\n" "# config file for each camera in addition to this config file.\n" "##############################################################\n", 1, @@ -1531,6 +1643,17 @@ config_param config_params[] = { config_thread, print_thread }, + /* using a conf.d style camera addition */ + { + "camera_dir", + "\n##############################################################\n" + "# Camera config directory - One for each camera.\n" + "##############################################################\n", + 1, + CONF_OFFSET(camera_dir), + read_camera_dir, + print_string + }, { NULL, NULL, 0, 0, NULL, NULL } }; @@ -1551,12 +1674,15 @@ static void conf_cmdline(struct context *cnt, int thread) * if necessary. This is accomplished by calling mystrcpy(); * see this function for more information. */ - while ((c = getopt(conf->argc, conf->argv, "c:d:hmns?p:k:l:")) != EOF) + while ((c = getopt(conf->argc, conf->argv, "bc:d:hmns?p:k:l:")) != EOF) switch (c) { case 'c': if (thread == -1) strcpy(cnt->conf_filename, optarg); break; + case 'b': + cnt->daemon = 1; + break; case 'n': cnt->daemon = 0; break; @@ -1569,20 +1695,26 @@ static void conf_cmdline(struct context *cnt, int thread) cnt->log_level = (unsigned int)atoi(optarg); break; case 'k': - if (thread == -1) - strcpy(cnt->log_type_str, optarg); + if (thread == -1) { + strncpy(cnt->log_type_str, optarg, sizeof(cnt->log_type_str) - 1); + cnt->log_type_str[sizeof(cnt->log_type_str) - 1] = '\0'; + } break; case 'p': - if (thread == -1) - strcpy(cnt->pid_file, optarg); + if (thread == -1) { + strncpy(cnt->pid_file, optarg, sizeof(cnt->pid_file) - 1); + cnt->pid_file[sizeof(cnt->pid_file) - 1] = '\0'; + } break; case 'l': - if (thread == -1) - strcpy(cnt->log_file, optarg); + if (thread == -1) { + strncpy(cnt->log_file, optarg, sizeof(cnt->log_file) - 1); + cnt->log_file[sizeof(cnt->log_file) - 1] = '\0'; + } break; case 'm': cnt->pause = 1; - break; + break; case 'h': case '?': default: @@ -1630,6 +1762,7 @@ struct context **conf_cmdparse(struct context **cnt, const char *cmd, const char * If the option is an int, copy_int is called. * If the option is a string, copy_string is called. * If the option is a thread, config_thread is called. + * If the option is a camera, config_camera is called. * The arguments to the function are: * cnt - a pointer to the context structure. * arg1 - a pointer to the new option value (represented as string). @@ -1677,7 +1810,7 @@ static struct context **conf_process(struct context **cnt, FILE *fp) /* Trim white space and any CR or LF at the end of the line. */ end = line + strlen(line) - 1; /* Point to the last non-null character in the string. */ - while (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r') + while (end >= line && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')) end--; *(end+1) = '\0'; @@ -1748,7 +1881,7 @@ void conf_print(struct context **cnt) MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Writing config file to %s", cnt[thread]->conf_filename); - conffile = myfopen(cnt[thread]->conf_filename, "w", 0); + conffile = myfopen(cnt[thread]->conf_filename, "w"); if (!conffile) continue; @@ -1784,7 +1917,7 @@ void conf_print(struct context **cnt) fprintf(conffile, "%s\n", val); if (strlen(val) == 0) - fprintf(conffile, "; thread /usr/local/etc/thread1.conf\n"); + fprintf(conffile, "; camera %s/motion/camera1.conf\n", sysconfdir); free(val); } else if (thread == 0) { @@ -1868,8 +2001,9 @@ struct context **conf_load(struct context **cnt) conf_cmdline(cnt[0], -1); if (cnt[0]->conf_filename[0]) { /* User has supplied filename on Command-line. */ - strcpy(filename, cnt[0]->conf_filename); - fp = fopen (filename, "r"); + strncpy(filename, cnt[0]->conf_filename, PATH_MAX-1); + filename[PATH_MAX-1] = '\0'; + fp = fopen (filename, "r"); } if (!fp) { /* Command-line didn't work, try current dir. */ @@ -1894,7 +2028,7 @@ struct context **conf_load(struct context **cnt) fp = fopen(filename, "r"); if (!fp) { - snprintf(filename, PATH_MAX, "%s/motion.conf", sysconfdir); + snprintf(filename, PATH_MAX, "%s/motion/motion.conf", sysconfdir); fp = fopen(filename, "r"); if (!fp) /* There is no config file.... use defaults. */ @@ -1905,11 +2039,12 @@ struct context **conf_load(struct context **cnt) /* Now we process the motion.conf config file and close it. */ if (fp) { - strcpy(cnt[0]->conf_filename, filename); - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Processing thread 0 - config file %s", - filename); - cnt = conf_process(cnt, fp); - myfclose(fp); + strncpy(cnt[0]->conf_filename, filename, sizeof(cnt[0]->conf_filename) - 1); + cnt[0]->conf_filename[sizeof(cnt[0]->conf_filename) - 1] = '\0'; + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Processing thread 0 - config file %s", + filename); + cnt = conf_process(cnt, fp); + myfclose(fp); } else { MOTION_LOG(CRT, TYPE_ALL, NO_ERRNO, "%s: Not config file to process using default values"); } @@ -2152,7 +2287,7 @@ char *mystrdup(const char *from) } else { stringlength = strlen(from); stringlength = (stringlength < PATH_MAX ? stringlength : PATH_MAX); - tmp = (char *)mymalloc(stringlength + 1); + tmp = mymalloc(stringlength + 1); strncpy(tmp, from, stringlength); /* @@ -2250,9 +2385,15 @@ static const char *print_int(struct context **cnt, char **str ATTRIBUTE_UNUSED, return retval; } - static const char *print_thread(struct context **cnt, char **str, int parm ATTRIBUTE_UNUSED, unsigned int threadnr) +{ + MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "thread config option deprecated use camera"); + return print_camera(cnt, str, parm, threadnr); +} + +static const char *print_camera(struct context **cnt, char **str, + int parm ATTRIBUTE_UNUSED, unsigned int threadnr) { char *retval; unsigned int i = 0; @@ -2265,8 +2406,8 @@ static const char *print_thread(struct context **cnt, char **str, while (cnt[++i]) { retval = myrealloc(retval, strlen(retval) + strlen(cnt[i]->conf_filename) + 10, - "print_thread"); - sprintf(retval + strlen(retval), "thread %s\n", cnt[i]->conf_filename); + "print_camera"); + sprintf(retval + strlen(retval), "camera %s\n", cnt[i]->conf_filename); } *str = retval; @@ -2275,9 +2416,63 @@ static const char *print_thread(struct context **cnt, char **str, } /** - * config_thread + * config_camera_dir + * Read the directory finding all *.conf files in the path + * when calls config_camera + */ + +static struct context **read_camera_dir(struct context **cnt, const char *str, + int val ATTRIBUTE_UNUSED) +{ + DIR *dp; + struct dirent *ep; + size_t name_len; + + char conf_file[PATH_MAX]; + + dp = opendir(str); + if (dp != NULL) + { + while( (ep = readdir(dp)) ) + { + name_len = strlen(ep->d_name); + if (name_len > strlen(EXTENSION) && + (strncmp(EXTENSION, + (ep->d_name + name_len - strlen(EXTENSION)), + strlen(EXTENSION)) == 0 + ) + ) + { + memset(conf_file, '\0', sizeof(conf_file)); + snprintf(conf_file, sizeof(conf_file) - 1, "%s/%s", + str, ep->d_name); + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, + "%s: Processing config file %s", conf_file ); + cnt = config_camera(cnt, conf_file, 0); + } + } + closedir(dp); + } + else + { + MOTION_LOG(ALR, TYPE_ALL, SHOW_ERRNO, "%s: Camera directory config " + "%s not found", str); + } + + return cnt; +} + +static struct context **config_thread(struct context **cnt, const char *str, + int val ATTRIBUTE_UNUSED) +{ + MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "thread config option deprecated use camera"); + return config_camera(cnt, str, val); +} + +/** + * config_camera * Is called during initial config file loading each time Motion - * finds a thread option in motion.conf + * finds a camera option in motion.conf * The size of the context array is increased and the main context's values are * copied to the new thread. * @@ -2286,7 +2481,7 @@ static const char *print_thread(struct context **cnt, char **str, * val - is not used. It is defined to be function header compatible with * copy_int, copy_bool and copy_string. */ -static struct context **config_thread(struct context **cnt, const char *str, +static struct context **config_camera(struct context **cnt, const char *str, int val ATTRIBUTE_UNUSED) { int i; @@ -2298,7 +2493,7 @@ static struct context **config_thread(struct context **cnt, const char *str, fp = fopen(str, "r"); if (!fp) { - MOTION_LOG(ALR, TYPE_ALL, SHOW_ERRNO, "%s: Thread config file %s not found", + MOTION_LOG(ALR, TYPE_ALL, SHOW_ERRNO, "%s: Camera config file %s not found", str); return cnt; } @@ -2314,7 +2509,7 @@ static struct context **config_thread(struct context **cnt, const char *str, * First thread is 0 so the number of threads is i + 1 * plus an extra for the NULL pointer. This gives i + 2 */ - cnt = myrealloc(cnt, sizeof(struct context *) * (i + 2), "config_thread"); + cnt = myrealloc(cnt, sizeof(struct context *) * (i + 2), "config_camera"); /* Now malloc space for an additional context structure for thread nr. i */ cnt[i] = mymalloc(sizeof(struct context)); @@ -2336,7 +2531,7 @@ static struct context **config_thread(struct context **cnt, const char *str, /* Process the thread's config file and notify user on console. */ strcpy(cnt[i]->conf_filename, str); - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Processing config file %s", + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Processing camera config file %s", str); conf_process(cnt + i, fp); @@ -2354,14 +2549,15 @@ static struct context **config_thread(struct context **cnt, const char *str, */ static void usage() { - printf("motion Version "VERSION", Copyright 2000-2005 Jeroen Vreeken/Folkert van Heusden/Kenneth Lavrsen\n"); + printf("motion Version "VERSION", Copyright 2000-2016 Jeroen Vreeken/Folkert van Heusden/Kenneth Lavrsen/Motion-Project maintainers\n"); printf("\nusage:\tmotion [options]\n"); printf("\n\n"); printf("Possible options:\n\n"); + printf("-b\t\t\tRun in background (daemon) mode.\n"); printf("-n\t\t\tRun in non-daemon mode.\n"); printf("-s\t\t\tRun in setup mode.\n"); printf("-c config\t\tFull path and filename of config file.\n"); - printf("-d level\t\tLog level (1-9) (EMR, ALR, CRT, ERR, WRN, NTC, ERR, DBG, ALL). default: 6 / NTC.\n"); + printf("-d level\t\tLog level (1-9) (EMG, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL). default: 6 / NTC.\n"); printf("-k type\t\t\tType of log (COR, STR, ENC, NET, DBL, EVT, TRK, VID, ALL). default: ALL.\n"); printf("-p process_id_file\tFull path and filename of process id file (pid file).\n"); printf("-l log file \t\tFull path and filename of log file.\n"); @@ -2369,6 +2565,6 @@ static void usage() printf("-h\t\t\tShow this screen.\n"); printf("\n"); printf("Motion is configured using a config file only. If none is supplied,\n"); - printf("it will read motion.conf from current directory, ~/.motion or %s.\n", sysconfdir); + printf("it will read motion.conf from current directory, ~/.motion or %s/motion.\n", sysconfdir); printf("\n"); } diff --git a/conf.h b/conf.h index b03397e..1e940df 100644 --- a/conf.h +++ b/conf.h @@ -15,21 +15,24 @@ #ifndef _INCLUDE_CONF_H #define _INCLUDE_CONF_H -/* +/* * More parameters may be added later. */ struct config { + const char *camera_name; unsigned int log_level; char *log_type_str; char *log_file; int setup_mode; int width; int height; + int camera_id; int quality; int rotate_deg; int max_changes; int threshold_tune; const char *output_pictures; + int ffmpeg_duplicate_frames; int motion_img; int emulate_motion; int event_gap; @@ -53,6 +56,7 @@ struct config { int contrast; int saturation; int hue; + int power_line_frequency; int roundrobin_frames; int roundrobin_skip; int pre_capture; @@ -62,7 +66,6 @@ struct config { int ffmpeg_output_debug; int ffmpeg_bps; int ffmpeg_vbr; - int ffmpeg_deinterlace; const char *ffmpeg_video_codec; #ifdef HAVE_SDL int sdl_threadnr; @@ -76,6 +79,8 @@ struct config { int stream_limit; int stream_auth_method; const char *stream_authentication; + int stream_preview_scale; + int stream_preview_newline; int webcontrol_port; int webcontrol_localhost; int webcontrol_html_output; @@ -83,8 +88,8 @@ struct config { unsigned long frequency; int tuner_number; int timelapse; - const char *timelapse_mode; -#if (defined(BSD)) + const char *timelapse_mode; +#if (defined(BSD) || defined(__FreeBSD_kernel__)) const char *tuner_device; #endif const char *video_device; @@ -109,7 +114,7 @@ struct config { const char *database_host; const char *database_user; const char *database_password; - const char *sqlite3_db; + int database_busy_timeout; int database_port; char *on_picture_save; char *on_area_detected; @@ -123,6 +128,11 @@ struct config { const char *netcam_keepalive; const char *netcam_proxy; unsigned int netcam_tolerant_check; + unsigned int rtsp_uses_tcp; +#ifdef HAVE_MMAL + const char *mmalcam_name; + const char *mmalcam_control_params; +#endif int text_changes; const char *text_left; const char *text_right; @@ -130,6 +140,7 @@ struct config { int text_double; const char *despeckle_filter; const char *area_detect; + const char *camera_dir; int minimum_motion_frames; const char *exif_text; char *pid_file; @@ -137,8 +148,8 @@ struct config { char **argv; }; -/** - * typedef for a param copy function. +/** + * typedef for a param copy function. */ typedef struct context ** (* conf_copy_func)(struct context **, const char *, int); typedef const char *(* conf_print_func)(struct context **, char **, int, unsigned int); @@ -153,7 +164,7 @@ typedef struct { int conf_value; /* pointer to a field in struct context */ conf_copy_func copy; /* a function to set the value in 'config' */ conf_print_func print; /* a function to output the value to a file */ -} config_param; +} config_param; extern config_param config_params[]; diff --git a/config.h.in b/config.h.in deleted file mode 100644 index 31262da..0000000 --- a/config.h.in +++ /dev/null @@ -1,127 +0,0 @@ -/* config.h.in. Generated from configure.in by autoheader. */ - -/* Define to 1 if you have the header file. */ -#undef HAVE_FCNTL_H - -/* Define to 1 if you have the `get_current_dir_name' function. */ -#undef HAVE_GET_CURRENT_DIR_NAME - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_VIDEODEV2_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_VIDEODEV_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have MySQL support */ -#undef HAVE_MYSQL - -/* 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 - -/* Define to 1 if you have SQLITE3 support */ -#undef HAVE_SQLITE3 - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_IOCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_MMAN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PARAM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_TIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* The size of `int', as computed by sizeof. */ -#undef SIZEOF_INT - -/* The size of `int *', as computed by sizeof. */ -#undef SIZEOF_INT_P - -/* The size of `long int', as computed by sizeof. */ -#undef SIZEOF_LONG_INT - -/* The size of `long long', as computed by sizeof. */ -#undef SIZEOF_LONG_LONG - -/* The size of `short', as computed by sizeof. */ -#undef SIZEOF_SHORT - -/* The size of `void *', as computed by sizeof. */ -#undef SIZEOF_VOID_P - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Define to empty if `const' does not conform to ANSI C. */ -#undef const - -/* Define to 1 if you have av_avformat_alloc_context support */ -#undef have_av_avformat_alloc_context - -/* Define to 1 if you have av_get_media_type_string support */ -#undef have_av_get_media_type_string - -/* Define to 1 if you have av_register_protocol support */ -#undef have_av_register_protocol - -/* Define to 1 if you have av_register_protocol2 support */ -#undef have_av_register_protocol2 - -/* Define to 1 if you have avformat_alloc_context support */ -#undef have_avformat_alloc_context diff --git a/configure b/configure deleted file mode 100755 index 57b6bde..0000000 --- a/configure +++ /dev/null @@ -1,7486 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for motion Git-28b7cb2a4297c78b9c08c9ce29a648aeb22120d0. -# -# -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : - -else - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : - as_have_required=yes -else - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : - -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : - CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : - break 2 -fi -fi - done;; - esac - as_found=false -done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } -IFS=$as_save_IFS - - - if test "x$CONFIG_SHELL" != x; then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." - else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, -$0: including any error possibly output before this -$0: message. Then install a modern shell, or manually run -$0: the script under such a shell if you do have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='motion' -PACKAGE_TARNAME='motion' -PACKAGE_VERSION='Git-28b7cb2a4297c78b9c08c9ce29a648aeb22120d0' -PACKAGE_STRING='motion Git-28b7cb2a4297c78b9c08c9ce29a648aeb22120d0' -PACKAGE_BUGREPORT='' -PACKAGE_URL='' - -ac_unique_file="motion.c" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_subst_vars='LTLIBOBJS -LIBOBJS -BIN_PATH -EGREP -GREP -CPP -RTPS_OBJ -FFMPEG_OBJ -SDL_OBJ -VIDEO -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -with_linuxthreads -with_pwcbsd -with_bktr -with_v4l -with_sdl -with_jpeg_turbo -with_jpeg_mmx -with_ffmpeg -with_ffmpeg_headers -with_sqlite3 -with_mysql -with_mysql_lib -with_mysql_include -with_pgsql -with_pgsql_lib -with_pgsql_include -with_optimizecpu -with_developer_flags -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -CPP' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures motion Git-28b7cb2a4297c78b9c08c9ce29a648aeb22120d0 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/motion] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of motion Git-28b7cb2a4297c78b9c08c9ce29a648aeb22120d0:";; - esac - cat <<\_ACEOF - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-linuxthreads Use linuxthreads in BSD instead of native pthreads - - - --with-pwcbsd Use pwcbsd based webcams ( only BSD ) - - - --without-bktr Exclude to use bktr subsystem , that usually useful - for devices as network cameras ( ONLY used in *BSD). - - - --without-v4l Exclude using v4l (video4linux) subsystem. - Makes Motion so it only supports network cameras. - - --without-sdl Compile without sdl support to get stream in SDL window. - - --with-jpeg-turbo=DIR Specify the prefix for the install path for - jpeg-turbo for optimized jpeg handling (optional). - - --with-jpeg-mmx=DIR Specify the prefix for the install path for - jpeg-mmx for optimized jpeg handling (optional). - If this is not specified motion will try to find - the library /usr/lib/libjpeg-mmx.a /usr/local/lib/libjpeg-mmx.a. - - --with-ffmpeg=DIR Specify the prefix for the install path for - libavcodec/libavformat (part of ffmpeg) be able to - encode mpeg movies realtime. - If this is not specified motion will try to find - the libraries in /usr and /usr/local. - - --with-ffmpeg-headers=DIR Specify the prefix for ffmpeg headers. - - --without-sqlite3 Disable sqlite3 support in motion. - - --without-mysql Disable mysql support in motion. - - --with-mysql-lib=DIR Normally, configure will scan all possible default - installation paths for mysql libs. When it fails, use - this command to tell configure where mysql libs - installation root directory is. - - --with-mysql-include=DIR Normally, configure will scan all possible default - installation paths for mysql include. When it fails, use - this command to tell configure where mysql include - installation root directory is. - - --without-pgsql Disable PostgreSQL support in motion. - - --with-pgsql-lib=DIR Normally, configure will scan all possible default - installation paths for pgsql libs. When it fails, use - this command to tell configure where pgsql libs - installation root directory is. - - --with-pgsql-include=DIR Normally, configure will scan all possible default - installation paths for pgsql include. When it fails, use - this command to tell configure where pgsql include - installation root directory is. - - --without-optimizecpu Exclude autodetecting platform and cpu type. - This will disable the compilation of gcc - optimizing code by platform and cpu. - - --with-developer-flags Causes practically all of the possible gcc - warning flags to be set. This may produce - a large amount of warnings. - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CPP C preprocessor - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to the package provider. -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -motion configure Git-28b7cb2a4297c78b9c08c9ce29a648aeb22120d0 -generated by GNU Autoconf 2.69 - -Copyright (C) 2012 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -# ac_fn_c_try_compile LINENO -# -------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_compile - -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - -# ac_fn_c_try_run LINENO -# ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_run - -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel - -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main () -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_func - -# ac_fn_c_check_type LINENO TYPE VAR INCLUDES -# ------------------------------------------- -# Tests whether TYPE exists after having included INCLUDES, setting cache -# variable VAR accordingly. -ac_fn_c_check_type () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof ($2)) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof (($2))) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - eval "$3=yes" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_type - -# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES -# -------------------------------------------- -# Tries to find the compile-time value of EXPR in a program that includes -# INCLUDES, setting VAR accordingly. Returns whether the value could be -# computed -ac_fn_c_compute_int () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) >= 0)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=0 ac_mid=0 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid; break -else - as_fn_arith $ac_mid + 1 && ac_lo=$as_val - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) < 0)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=-1 ac_mid=-1 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) >= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=$ac_mid; break -else - as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - ac_lo= ac_hi= -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid -else - as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in #(( -?*) eval "$3=\$ac_lo"; ac_retval=0 ;; -'') ac_retval=1 ;; -esac - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - return 1; - if (($2) < 0) - { - long int i = longval (); - if (i != ($2)) - return 1; - fprintf (f, "%ld", i); - } - else - { - unsigned long int i = ulongval (); - if (i != ($2)) - return 1; - fprintf (f, "%lu", i); - } - /* Do not output a trailing newline, as this causes \r\n confusion - on some platforms. */ - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - echo >>conftest.val; read $3 config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by motion $as_me Git-28b7cb2a4297c78b9c08c9ce29a648aeb22120d0, which was -generated by GNU Autoconf 2.69. Invocation command line was - - $ $0 $@ - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Save into config.log some information that might help in debugging. - { - echo - - $as_echo "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - $as_echo "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - $as_echo "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -$as_echo "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE -if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac -elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site -else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site -fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" -do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_config_headers="$ac_config_headers config.h" - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else - ac_file='' -fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -FILE *f = fopen ("conftest.out", "w"); - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -else - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC - -fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : - -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -THREAD_CFLAGS="" -THREAD_CHECK="/usr/include/pthread.h" - -Darwin="" -FreeBSD="" - -LINUXTHREADS="no" - -# Check whether --with-linuxthreads was given. -if test "${with_linuxthreads+set}" = set; then : - withval=$with_linuxthreads; LINUXTHREADS="$withval" - -fi - - -PWCBSD="no" - -# Check whether --with-pwcbsd was given. -if test "${with_pwcbsd+set}" = set; then : - withval=$with_pwcbsd; PWCBSD="$withval" - -fi - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Darwin" >&5 -$as_echo_n "checking for Darwin... " >&6; } -Darwin=`uname -a | grep "Darwin"` - -if test "${Darwin}" = ""; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for *BSD" >&5 -$as_echo_n "checking for *BSD... " >&6; } - - FreeBSD=`uname -a | grep "BSD"` - if test "${FreeBSD}" = ""; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - VIDEO="video.o video2.o video_common.o" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - if test "${LINUXTHREADS}" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking Linuxthreads" >&5 -$as_echo_n "checking Linuxthreads... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipping" >&5 -$as_echo "skipping" >&6; } - else - THREAD_CHECK="/usr/local/include/pthread/linuxthreads/pthread.h" - THREAD_LIB_CHECK="/usr/local/lib/liblthread.so" - fi - - if test "${PWCBSD}" != "no"; then - VIDEO="video.o video2.o video_common.o" - TEMP_CFLAGS="${CFLAGS} -I/usr/local/include -DPWCBSD" - else - VIDEO="video_freebsd.o" - TEMP_CFLAGS="${CFLAGS} -I/usr/local/include" - fi - - TEMP_LDFLAGS="${LDFLAGS} -L/usr/local/lib" - TEMP_LIBS="-L/usr/local/lib" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: Build with PWCBSD support $PWCBSD" >&5 -$as_echo "Build with PWCBSD support $PWCBSD" >&6; } - - fi -else - TEMP_CFLAGS="${CFLAGS} -I/sw/include" - TEMP_LDFLAGS="${LDFLAGS} -L/sw/lib" - TEMP_LIBS="-L/sw/lib" - VIDEO="video_freebsd.o" - FINK_LIB="-L/sw/lib" - Darwin="yes" - V4L="no" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $Darwin" >&5 -$as_echo "$Darwin" >&6; } -fi - - - - -# Checks for programs. -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -else - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC - -fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : - -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -TEMP_LIBS="-lm ${TEMP_LIBS}" -TEMP_CFLAGS="${TEMP_CFLAGS} ${CFLAGS}" -TEMP_LDFLAGS="${TEMP_LDFLAGS} ${LDFLAGS}" - -if test "${FreeBSD}" != "" && test "${PWCBSD}" = "no"; then - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking bktr headers in /usr/include/dev/bktr" >&5 -$as_echo_n "checking bktr headers in /usr/include/dev/bktr... " >&6; } - - if test -f /usr/include/dev/bktr/ioctl_meteor.h && test -f /usr/include/dev/bktr/ioctl_bt848.h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - TEMP_CFLAGS="${TEMP_CFLAGS} -DOLD_BKTR" - fi -# -# Check to Exclude BKTR -# -BKTR="yes" - -# Check whether --with-bktr was given. -if test "${with_bktr+set}" = set; then : - withval=$with_bktr; BKTR="$withval" - -fi - - - if test "${BKTR}" = "no"; then - TEMP_CFLAGS="${TEMP_CFLAGS} -DWITHOUT_V4L" - fi - -else - -# -# Check to Exclude V4L -# -V4L="yes" - -# Check whether --with-v4l was given. -if test "${with_v4l+set}" = set; then : - withval=$with_v4l; V4L="$withval" - -fi - - -fi - - -if test "${V4L}" = "no"; then - TEMP_CFLAGS="${TEMP_CFLAGS} -DWITHOUT_V4L" -fi - - -if test "${FreeBSD}" != "" && test "${LINUXTHREADS}" != "no" ; then - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linuxthreads" >&5 -$as_echo_n "checking for linuxthreads... " >&6; } - -# -# Check for thread header -# - if test -f "${THREAD_CHECK}"; then - HEADERS_THREAD_CFLAGS="-I/usr/local/include/pthread/linuxthreads" - THREADS="yes" - else - THREADS="no" - fi - -# -# Check for thread lib -# - if test -f "${THREAD_LIB_CHECK}" ; then - THREADS="yes" - LIB_THREAD="-llthread -llgcc_r" - else - THREADS="no" - fi - -# Checks for Library linuxthreads for FreeBSD -# -# linuxthreads on freeBSD, ports collection -# /usr/local/include/pthreads/linuxthreads/pthread.h -# #include -# /usr/local/lib/libpthread.so -# - - if test "${THREADS}" = "yes"; then - TEMP_CFLAGS="${HEADERS_THREAD_CFLAGS} $TEMP_CFLAGS -DWITH_LINUXTREADS" - TEMP_LIBS="$TEMP_LIBS ${LIB_THREAD}" - THREAD_CFLAGS="-D_THREAD_SAFE" - PTHREAD_SUPPORT="yes" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $THREADS" >&5 -$as_echo "$THREADS" >&6; } - else - PTHREAD_SUPPORT="no" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $THREADS" >&5 -$as_echo "$THREADS" >&6; } - echo - echo "You do not have linuxthread installed" - echo - fi - -elif test -f "${THREAD_CHECK}"; then - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking threads" >&5 -$as_echo_n "checking threads... " >&6; } - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -pthread_t th; pthread_join(th, 0); - pthread_attr_init(0); pthread_cleanup_push(0, 0); - pthread_create(0,0,0,0); pthread_cleanup_pop(0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - PTHREAD_LIB=yes -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -if test x$PTHREAD_LIB != xyes; then - - if test "${FreeBSD}" != ""; then - TEMP_LIBS="$TEMP_LIBS -pthread" - TEMP_CFLAGS="${TEMP_CFLAGS} -D_REENTRANT -D_THREAD_SAFE" - else - TEMP_LIBS="$TEMP_LIBS -lpthread" - TEMP_CFLAGS="${TEMP_CFLAGS} -D_REENTRANT" - fi - PTHREAD_SUPPORT="yes" -fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_SUPPORT" >&5 -$as_echo "$PTHREAD_SUPPORT" >&6; } - -else - echo - echo "You do not have threads support" - echo -fi - - -# -# Check for sdl library -# -SDL_SUPPORT="no" - -# Check whether --with-sdl was given. -if test "${with_sdl+set}" = set; then : - withval=$with_sdl; -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sdl" >&5 -$as_echo_n "checking for sdl... " >&6; } -if test "x$withval" = "xno"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipped" >&5 -$as_echo "skipped" >&6; } -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 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - 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 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - SDL_SUPPORT="yes" - TEMP_LIBS="$TEMP_LIBS `${CONFIG_SDL} --libs`" - TEMP_CFLAGS="${TEMP_CFLAGS} `${CONFIG_SDL} --cflags`" - -$as_echo "#define HAVE_SDL 1" >>confdefs.h - - SDL_OBJ="sdl.o" - - fi -fi - -# -# Check for the libjpeg-turbo library -# -JPEG_TURBO="no" -JPEG_TURBO_OK="not_found" - - -# Check whether --with-jpeg-turbo was given. -if test "${with_jpeg_turbo+set}" = set; then : - withval=$with_jpeg_turbo; JPEG_TURBO="$withval" - -fi - - -if test "${JPEG_TURBO}" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libjpeg-turbo" >&5 -$as_echo_n "checking for libjpeg-turbo... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipping" >&5 -$as_echo "skipping" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libjpeg-turbo in -> ${JPEG_TURBO} <-" >&5 -$as_echo_n "checking for libjpeg-turbo in -> ${JPEG_TURBO} <-... " >&6; } - if test -f ${JPEG_TURBO}/lib/libjpeg.a ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } - JPEG_TURBO_OK="found" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - fi -fi - - -if test "${JPEG_TURBO_OK}" = "found"; then - saved_CFLAGS="$CFLAGS" - saved_LIBS="$LIBS" - saved_LDFLAGS="$LDFLAGS" - LDFLAGS="-L${JPEG_TURBO}/lib" - CFLAGS="$CFLAGS -I${JPEG_TURBO}/include" - LIBS="$LIBS -L${JPEG_TURBO}/lib -ljpeg" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jpeg_start_compress in -ljpeg" >&5 -$as_echo_n "checking for jpeg_start_compress in -ljpeg... " >&6; } -if ${ac_cv_lib_jpeg_jpeg_start_compress+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ljpeg $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char jpeg_start_compress (); -int -main () -{ -return jpeg_start_compress (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_jpeg_jpeg_start_compress=yes -else - ac_cv_lib_jpeg_jpeg_start_compress=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jpeg_jpeg_start_compress" >&5 -$as_echo "$ac_cv_lib_jpeg_jpeg_start_compress" >&6; } -if test "x$ac_cv_lib_jpeg_jpeg_start_compress" = xyes; then : - TEMP_LIBS="$LIBS" - TEMP_CFLAGS="${CFLAGS}" - TEMP_LDFLAGS="$TEMP_LDFLAGS $LDFLAGS" - JPEG_SUPPORT="yes" -fi - - LIBS="$saved_LIBS" - CFLAGS="$saved_CFLAGS" - LDFLAGS="$saved_LDFLAGS" - JPEG_SUPPORT_TURBO="yes" -fi - - -# -# Check for the special mmx accelerated jpeg library -# -JPEG_MMX="no" -JPEG_MMX_OK="not_found" - -# Check whether --with-jpeg-mmx was given. -if test "${with_jpeg_mmx+set}" = set; then : - withval=$with_jpeg_mmx; JPEG_MMX="$withval" - -fi - - -# -# --without-jpeg-mmx or with-jpeg-mmx=no -# - -if test "${JPEG_MMX}" = "no" || test x$JPEG_SUPPORT != xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libjpeg-mmx" >&5 -$as_echo_n "checking for libjpeg-mmx... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipping" >&5 -$as_echo "skipping" >&6; } -elif test "${JPEG_MMX}" = "yes"; then - # AUTODETECT STATIC LIB - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libjpeg-mmx autodetecting" >&5 -$as_echo_n "checking for libjpeg-mmx autodetecting... " >&6; } - - if test -f /usr/lib/libjpeg-mmx.a ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } - JPEG_MMX_OK="found" - JPEG_MMX="/usr/lib" - elif test -f /usr/local/lib/libjpeg-mmx.a ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } - JPEG_MMX_OK="found" - JPEG_MMX="/usr/local/lib" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libjpeg-mmx in -> ${JPEG_MMX} <-" >&5 -$as_echo_n "checking for libjpeg-mmx in -> ${JPEG_MMX} <-... " >&6; } - if test -f ${JPEG_MMX}/libjpeg-mmx.a ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } - JPEG_MMX_OK="found" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - fi -fi - -if test "${JPEG_MMX_OK}" = "found"; then - saved_CFLAGS="$CFLAGS" - saved_LIBS="$LIBS" - CFLAGS="$CFLAGS -I${JPEG_MMX}" - LIBS="$LIBS -L${JPEG_MMX}" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jpeg_start_compress in -ljpeg-mmx" >&5 -$as_echo_n "checking for jpeg_start_compress in -ljpeg-mmx... " >&6; } -if ${ac_cv_lib_jpeg_mmx_jpeg_start_compress+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ljpeg-mmx $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char jpeg_start_compress (); -int -main () -{ -return jpeg_start_compress (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_jpeg_mmx_jpeg_start_compress=yes -else - ac_cv_lib_jpeg_mmx_jpeg_start_compress=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jpeg_mmx_jpeg_start_compress" >&5 -$as_echo "$ac_cv_lib_jpeg_mmx_jpeg_start_compress" >&6; } -if test "x$ac_cv_lib_jpeg_mmx_jpeg_start_compress" = xyes; then : - TEMP_LIBS="$TEMP_LIBS -ljpeg-mmx" - TEMP_CFLAGS="${TEMP_CFLAGS} -I${JPEG_MMX}" - JPEG_SUPPORT="yes" -fi - - LIBS="$saved_LIBS" - CFLAGS="$saved_CFLAGS" - JPEG_SUPPORT_MMX="yes" -fi - -# -# Look for _a_ jpeg lib that will work. -# -if test x$JPEG_SUPPORT != xyes ; then - # Checks for libraries - LDFLAGS=$TEMP_LDFLAGS - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jpeg_set_defaults in -ljpeg" >&5 -$as_echo_n "checking for jpeg_set_defaults in -ljpeg... " >&6; } -if ${ac_cv_lib_jpeg_jpeg_set_defaults+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ljpeg $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char jpeg_set_defaults (); -int -main () -{ -return jpeg_set_defaults (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_jpeg_jpeg_set_defaults=yes -else - ac_cv_lib_jpeg_jpeg_set_defaults=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jpeg_jpeg_set_defaults" >&5 -$as_echo "$ac_cv_lib_jpeg_jpeg_set_defaults" >&6; } -if test "x$ac_cv_lib_jpeg_jpeg_set_defaults" = xyes; then : - - TEMP_LIBS="$TEMP_LIBS -ljpeg" - JPEG_SUPPORT="yes" - -else - - echo - echo "You do not have libjpeg installed" - echo - - -fi - -fi - - -# -# Check for libavcodec and libavformat from ffmpeg -# -FFMPEG_DIR="yes" -FFMPEG_OK="no_found" -FFMPEG_OBJ="" - -# Check whether --with-ffmpeg was given. -if test "${with_ffmpeg+set}" = set; then : - withval=$with_ffmpeg; FFMPEG_DIR="$withval" - -fi - - -# -# ffmpeg headers custom location -# -FFMPEG_HEADERS_DIR="yes" - -# Check whether --with-ffmpeg_headers was given. -if test "${with_ffmpeg_headers+set}" = set; then : - withval=$with_ffmpeg_headers; FFMPEG_HEADERS_DIR="$withval" - -fi - - -# -# --without-ffmpeg or with-ffmpeg=no -# -if test "${FFMPEG_DIR}" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffmpeg" >&5 -$as_echo_n "checking for ffmpeg... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipping" >&5 -$as_echo "skipping" >&6; } -# -# with-ffmpeg= or nothing -# -else if test "${FFMPEG_DIR}" = "yes"; then - # AUTODETECT STATIC/SHARED LIB - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffmpeg autodetecting libraries" >&5 -$as_echo_n "checking for ffmpeg autodetecting libraries... " >&6; } - - if test -f /usr/lib64/libavcodec.a -o -f /usr/lib64/libavcodec.so && test -f /usr/lib64/libavformat.a -o -f /usr/lib64/libavformat.so ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found in /usr/lib64" >&5 -$as_echo "found in /usr/lib64" >&6; } - FFMPEG_OK="found" - FFMPEG_LIB="/usr/lib64" - FFMPEG_DIR="/usr" - elif test -f /usr/lib/libavcodec.a -o -f /usr/lib/libavcodec.so && test -f /usr/lib/libavformat.a -o -f /usr/lib/libavformat.so ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found in /usr/lib" >&5 -$as_echo "found in /usr/lib" >&6; } - FFMPEG_OK="found" - FFMPEG_LIB="/usr/lib" - FFMPEG_DIR="/usr" - elif test -f /usr/local/lib/libavcodec.a -o -f /usr/local/lib/libavcodec.so && test -f /usr/local/lib/libavformat.a -o -f /usr/local/lib/libavformat.so ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found in /usr/local/lib" >&5 -$as_echo "found in /usr/local/lib" >&6; } - FFMPEG_OK="found" - FFMPEG_LIB="/usr/local/lib" - FFMPEG_DIR="/usr/local" - elif test -f /usr/lib/x86_64-linux-gnu/libavcodec.a -o -f /usr/lib/x86_64-linux-gnu/libavcodec.so && test /usr/lib/x86_64-linux-gnu/libavformat.a -o -f /usr/lib/x86_64-linux-gnu/libavformat.so ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found in /usr/lib/x86_64-linux-gnu" >&5 -$as_echo "found in /usr/lib/x86_64-linux-gnu" >&6; } - FFMPEG_OK="found" - FFMPEG_LIB="/usr/lib/x86_64-linux-gnu" - FFMPEG_DIR="/usr" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - echo "" - echo "**********************************************" - echo "* libavcodec.a or libavcodec.so or *" - echo "* libavformat.a or libavformat.so not found: *" - echo "* ALL FFMPEG FEATURES DISABLED *" - echo "* *" - echo "* Please read the Motion Guide for help: *" - echo "* http://motion.sourceforge.net *" - echo "**********************************************" - echo "" - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffmpeg libraries in -> ${FFMPEG_DIR} <-" >&5 -$as_echo_n "checking for ffmpeg libraries in -> ${FFMPEG_DIR} <-... " >&6; } - if test -f ${FFMPEG_DIR}/lib/libavcodec.a -o -f ${FFMPEG_DIR}/lib/libavcodec.so && test -f ${FFMPEG_DIR}/lib/libavformat.a -o -f ${FFMPEG_DIR}/lib/libavformat.so ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } - FFMPEG_OK="found" - FFMPEG_LIB="${FFMPEG_DIR}/lib" - elif test -f ${FFMPEG_DIR}/libavcodec.a -o -f ${FFMPEG_DIR}/libavcodec.so && test -f ${FFMPEG_DIR}/libavformat.a -o -f ${FFMPEG_DIR}/libavformat.so ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } - FFMPEG_LIB="${FFMPEG_DIR}" - FFMPEG_OK="found" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - if test "${FFMPEG_OK}" != "found"; then - echo "" - echo "**********************************************" - echo "* libavcodec.a or libavcodec.so or *" - echo "* libavformat.a or libavformat.so not found: *" - echo "* ALL FFMPEG FEATURES DISABLED *" - echo "* *" - echo "* Please read the Motion Guide for help: *" - echo "* http://motion.sourceforge.net *" - echo "**********************************************" - echo "" - fi - fi -fi - -# -# Now check for ffmpeg headers ( avformat.h ) if ffmpeg libs were found -# - -if test "${FFMPEG_OK}" = "found"; then - if test "${FFMPEG_HEADERS_DIR}" = "yes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffmpeg headers in ${FFMPEG_DIR}" >&5 -$as_echo_n "checking for ffmpeg headers in ${FFMPEG_DIR}... " >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffmpeg headers in ${FFMPEG_HEADERS_DIR}" >&5 -$as_echo_n "checking for ffmpeg headers in ${FFMPEG_HEADERS_DIR}... " >&6; } - FFMPEG_DIR="${FFMPEG_HEADERS_DIR}" - fi - - if test -f ${FFMPEG_DIR}/include/avformat.h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${FFMPEG_DIR}/include/avformat.h" >&5 -$as_echo "found ${FFMPEG_DIR}/include/avformat.h" >&6; } - FFMPEG_CFLAGS="-I${FFMPEG_DIR}/include" - elif test -f ${FFMPEG_DIR}/avformat.h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${FFMPEG_DIR}/avformat.h" >&5 -$as_echo "found ${FFMPEG_DIR}/avformat.h" >&6; } - FFMPEG_CFLAGS="-I${FFMPEG_DIR}" - elif test -f ${FFMPEG_DIR}/include/ffmpeg/avformat.h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${FFMPEG_DIR}/include/ffmpeg/avformat.h" >&5 -$as_echo "found ${FFMPEG_DIR}/include/ffmpeg/avformat.h" >&6; } - FFMPEG_CFLAGS="-I${FFMPEG_DIR}/include/ffmpeg" - elif test -f ${FFMPEG_DIR}/include/libavformat/avformat.h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${FFMPEG_DIR}/include/libavformat/avformat.h" >&5 -$as_echo "found ${FFMPEG_DIR}/include/libavformat/avformat.h" >&6; } - FFMPEG_CFLAGS="-I${FFMPEG_DIR}/include -DFFMPEG_NEW_INCLUDES" - AVFORMAT="-I${FFMPEG_DIR}/include/libavformat" - elif test -f ${FFMPEG_DIR}/include/ffmpeg/libavformat/avformat.h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${FFMPEG_DIR}/include/ffmpeg/libavformat/avformat.h" >&5 -$as_echo "found ${FFMPEG_DIR}/include/ffmpeg/libavformat/avformat.h" >&6; } - FFMPEG_CFLAGS="-I${FFMPEG_DIR}/include/ffmpeg -DFFMPEG_NEW_INCLUDES" - AVFORMAT="-I${FFMPEG_DIR}/include/ffmpeg/libavformat" - elif test -f ${FFMPEG_DIR}/libavformat/avformat.h; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${FFMPEG_DIR}/libavformat/avformat.h" >&5 -$as_echo "found ${FFMPEG_DIR}/libavformat/avformat.h" >&6; } - FFMPEG_CFLAGS="-I${FFMPEG_DIR} -DFFMPEG_NEW_INCLUDES" - AVFORMAT="-I{FFMPEG_DIR}/libavformat" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - FFMPEG_OK="no_found" - echo "**********************************************" - echo "* avformat.h not found: *" - echo "* ALL FFMPEG FEATURES DISABLED *" - echo "* *" - echo "* Please read the Motion Guide for help: *" - echo "* http://motion.sourceforge.net *" - echo "**********************************************" - echo "" - fi - -# -# If ffmpeg libs and headers have been found -# - - if test "${FFMPEG_OK}" = "found"; then - TEMP_LIBS="$TEMP_LIBS -L${FFMPEG_LIB} -lavformat -lavcodec -lavutil -lm -lz" - TEMP_LDFLAGS="${TEMP_LDFLAGS} -L${FFMPEG_LIB}" - TEMP_CFLAGS="${TEMP_CFLAGS} -DHAVE_FFMPEG ${FFMPEG_CFLAGS}" - - FFMPEG_OBJ="ffmpeg.o" - - - RTPS_OBJ="netcam_rtsp.o" - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking file_protocol is defined in ffmpeg ?" >&5 -$as_echo_n "checking file_protocol is defined in ffmpeg ?... " >&6; } - saved_CFLAGS=$CFLAGS - saved_LIBS=$LIBS - - - CFLAGS="${FFMPEG_CFLAGS} ${AVFORMAT}" - LIBS="$TEMP_LIBS" - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - - #include - URLProtocol test_file_protocol; - int main(void){ - test_file_protocol.url_read = file_protocol.url_read; - return 0; - } - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - TEMP_CFLAGS="${TEMP_CFLAGS} -DHAVE_FFMPEG_NEW" - - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS=$saved_CFLAGS - LIBS=$saved_LIBS - fi -fi -fi - - -# -# Check SQLITE3 -# - -SQLITE3_SUPPORT="no" - -# Check whether --with-sqlite3 was given. -if test "${with_sqlite3+set}" = set; then : - withval=$with_sqlite3; SQLITE3="$withval" - # if not given argument, assume standard - -fi - - -if test "${SQLITE3}" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3" >&5 -$as_echo_n "checking for sqlite3... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipping" >&5 -$as_echo "skipping" >&6; } -else - saved_CFLAGS=$CFLAGS - saved_LIBS=$LIBS - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_open in -lsqlite3" >&5 -$as_echo_n "checking for sqlite3_open in -lsqlite3... " >&6; } -if ${ac_cv_lib_sqlite3_sqlite3_open+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsqlite3 $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char sqlite3_open (); -int -main () -{ -return sqlite3_open (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_sqlite3_sqlite3_open=yes -else - ac_cv_lib_sqlite3_sqlite3_open=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_open" >&5 -$as_echo "$ac_cv_lib_sqlite3_sqlite3_open" >&6; } -if test "x$ac_cv_lib_sqlite3_sqlite3_open" = xyes; then : - - TEMP_LIBS="$TEMP_LIBS -lsqlite3" - SQLITE3_SUPPORT="yes" - -$as_echo "#define HAVE_SQLITE3 1" >>confdefs.h - - - -fi - - - CFLAGS=$saved_CFLAGS - LIBS=$saved_LIBS -fi - - -# -# Check Mysql -# - -MYSQL="yes" -MYSQL_SUPPORT="no" -MYSQL_HEADERS="yes" -MYSQL_LIBS="yes" - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql support" >&5 -$as_echo_n "checking for mysql support... " >&6; } - - -# Check whether --with-mysql was given. -if test "${with_mysql+set}" = set; then : - withval=$with_mysql; MYSQL="$withval" -# if not given argument, assume standard - -fi - - - -# Check whether --with-mysql-lib was given. -if test "${with_mysql_lib+set}" = set; then : - withval=$with_mysql_lib; MYSQL_LIBS="$withval" -# if not given argument, assume standard - -fi - - - - -# Check whether --with-mysql-include was given. -if test "${with_mysql_include+set}" = set; then : - withval=$with_mysql_include; MYSQL_HEADERS="$withval" -# if not given argument, assume standard - -fi - - - -if test "${MYSQL}" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipped" >&5 -$as_echo "skipped" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: testing" >&5 -$as_echo "testing" >&6; } - # ******* Search mysql headers ******* - - if test "${MYSQL_HEADERS}" = "yes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking autodect mysql headers" >&5 -$as_echo_n "checking autodect mysql headers... " >&6; } - # Autodetect - for w in /usr/include /usr/local/include /usr/mysql /usr/local/mysql /usr/local/mysql/include /opt /opt/mysql; do - # check for plain setups - if test -f $w/mysql.h; then - MYSQL_INCDIR=$w - break - fi - # check for "/usr/include/" type setups - if test -f $w/mysql/mysql.h; then - MYSQL_INCDIR=$w/mysql - break - fi - # check for "/usr//include" type setups - if test -f $w/mysql/include/mysql.h; then - MYSQL_INCDIR=$w/mysql/include - break - fi - done - elif test "${MYSQL_HEADERS}" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql headers" >&5 -$as_echo_n "checking for mysql headers... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipped" >&5 -$as_echo "skipped" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql headers in $MYSQL_HEADERS" >&5 -$as_echo_n "checking for mysql headers in $MYSQL_HEADERS... " >&6; } - # Manual detection for - if test -f $MYSQL_HEADERS/mysql.h; then - MYSQL_INCDIR=$MYSQL_HEADERS - fi - fi - - if test -z "$MYSQL_INCDIR" ; then - MYSQL_HEADERS="no" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - echo "Invalid MySQL directory - unable to find mysql.h." - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MYSQL_INCDIR yes" >&5 -$as_echo "$MYSQL_INCDIR yes" >&6; } - MYSQL_HEADERS="yes" - fi - - - if test "${MYSQL_HEADERS}" = "yes"; then - - # ******* Search mysql libs ********* - if test "${MYSQL_LIBS}" = "yes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking autodect mysql libs" >&5 -$as_echo_n "checking autodect mysql libs... " >&6; } - # Autodetect - for w in /usr/lib64 /usr/lib /usr/local/lib /usr/mysql /usr/local/mysql /usr/local/mysql/lib /opt /opt/mysql /usr/lib/x86_64-linux-gnu; do - # check for plain setups - if test -f $w/libmysqlclient.a -o -f $w/libmysqlclient.so; then - MYSQL_LIBDIR=$w - break - fi - # check for "/usr/lib/" type setups - if test -f $w/mysql/libmysqlclient.a -o -f $w/mysql/libmysqlclient.so; then - MYSQL_LIBDIR=$w/mysql - break - fi - # check for "/usr//lib" type setups - if test -f $w/mysql/lib/libmysqlclient.a -o -f $w/mysql/lib/libmysqlclient.so; then - MYSQL_LIBDIR=$w/mysql/lib - break - fi - done - elif test "${MYSQL_LIBS}" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql libs" >&5 -$as_echo_n "checking for mysql libs... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipped" >&5 -$as_echo "skipped" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql libs in $MYSQL_LIBS" >&5 -$as_echo_n "checking for mysql libs in $MYSQL_LIBS... " >&6; } - # Manual detection for - if test -f $MYSQL_LIBS/libmysqlclient.a -o -f $MYSQL_LIBS/libmysqlclient.so; then - MYSQL_LIBDIR=$MYSQL_LIBS - fi - fi - - - if test -z "$MYSQL_LIBDIR" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - echo "Invalid MySQL directory - unable to find libmysqlclient.a or libmysqlclient.so." - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MYSQL_LIBDIR" >&5 -$as_echo "$MYSQL_LIBDIR" >&6; } - #LDFLAGS="-L$MYSQL_LIBDIR" - saved_CFLAGS=$CFLAGS - saved_LIBS=$LIBS - CFLAGS="-I$MYSQL_INCDIR" - LIBS="-L$MYSQL_LIBDIR" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmysqlclient" >&5 -$as_echo_n "checking for mysql_init in -lmysqlclient... " >&6; } -if ${ac_cv_lib_mysqlclient_mysql_init+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lmysqlclient $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char mysql_init (); -int -main () -{ -return mysql_init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_mysqlclient_mysql_init=yes -else - ac_cv_lib_mysqlclient_mysql_init=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mysqlclient_mysql_init" >&5 -$as_echo "$ac_cv_lib_mysqlclient_mysql_init" >&6; } -if test "x$ac_cv_lib_mysqlclient_mysql_init" = xyes; then : - - TEMP_LIBS="$TEMP_LIBS -L$MYSQL_LIBDIR -lmysqlclient -lz" - TEMP_CFLAGS="$TEMP_CFLAGS -I$MYSQL_INCDIR" - MYSQL_SUPPORT="yes" - -$as_echo "#define HAVE_MYSQL 1" >>confdefs.h - - -else - as_fn_error $? "MySQL support can't build without MySQL libraries" "$LINENO" 5 -fi - - CFLAGS=$saved_CFLAGS - LIBS=$saved_LIBS - fi - - # end mysql-include , mysql-libs - fi - -# end Mysql detection -fi - - -# -# Check PostgreSQL -# -PGSQL="yes" -PGSQL_SUPPORT="no" -PGSQL_HEADERS="yes" -PGSQL_LIBS="yes" - - - - -# Check whether --with-pgsql was given. -if test "${with_pgsql+set}" = set; then : - withval=$with_pgsql; PGSQL="$withval" -# if not given argument, assume standard - -fi - - - -# Check whether --with-pgsql-lib was given. -if test "${with_pgsql_lib+set}" = set; then : - withval=$with_pgsql_lib; PGSQL_LIBS="$withval" -# if not given argument, assume standard - -fi - - - -# Check whether --with-pgsql-include was given. -if test "${with_pgsql_include+set}" = set; then : - withval=$with_pgsql_include; PGSQL_HEADERS="$withval" -# if not given argument, assume standard - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PostgreSQL" >&5 -$as_echo_n "checking for PostgreSQL... " >&6; } - -if test "${PGSQL}" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipped" >&5 -$as_echo "skipped" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: testing" >&5 -$as_echo "testing" >&6; } - - # ******* Search pgsql headers ******* - if test "${PGSQL_HEADERS}" = "yes"; then - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking autodect pgsql headers" >&5 -$as_echo_n "checking autodect pgsql headers... " >&6; } - # Autodetect - for i in /usr /usr/local /usr/local/pgsql $PHP_PGSQL; do - if test -r $i/include/libpq-fe.h; then PGSQL_DIR=$i; PGSQL_INCDIR=$i/include - elif test -r $i/include/pgsql/libpq-fe.h; then PGSQL_DIR=$i; PGSQL_INCDIR=$i/include/pgsql - elif test -r $i/include/postgresql/libpq-fe.h; then PGSQL_DIR=$i; PGSQL_INCDIR=$i/include/postgresql - fi - done - - elif test "${PGSQL_HEADERS}" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pgsql headers" >&5 -$as_echo_n "checking for pgsql headers... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipped" >&5 -$as_echo "skipped" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pgsql headers in $PGSQL_HEADERS" >&5 -$as_echo_n "checking for pgsql headers in $PGSQL_HEADERS... " >&6; } - # Manual detection for - if test -f $PGSQL_HEADERS/libpq-fe.h; then - PGSQL_INCDIR=$PGSQL_HEADERS - fi - fi - - if test -z "$PGSQL_INCDIR" ; then - PGSQL_HEADERS="no" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - echo "Invalid PostgreSQL directory - unable to find libpq-fe.h." - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes $PGSQL_INCDIR" >&5 -$as_echo "yes $PGSQL_INCDIR" >&6; } - PGSQL_HEADERS="yes" - fi - - - if test "${PGSQL_HEADERS}" = "yes"; then - - # ******* Search pgsql libs ********* - if test "${PGSQL_LIBS}" = "yes"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking autodect pgsql libs" >&5 -$as_echo_n "checking autodect pgsql libs... " >&6; } - # Autodetect - PGSQL_INCLUDE="-I$PGSQL_INCDIR" - PGSQL_LIBDIR=$PGSQL_DIR/lib - - if test -f /usr/lib64/libpq.so ; then - PGSQL_LIBDIR=/usr/lib64 - elif test -f $PGSQL_DIR/lib/pgsql/libpq.so ; then - PGSQL_LIBDIR=$PGSQL_DIR/lib/pgsql - elif test -f $PGSQL_DIR/lib/postgresql/libpq.so ; then - PGSQL_LIBDIR=$PGSQL_DIR/lib/postgresql - elif test -f $PGSQL_DIR/lib/libpq.so ; then - PGSQL_LIBDIR=$PGSQL_DIR/lib - else - PGSQL_LIBDIR="" - fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PGSQL_LIBDIR" >&5 -$as_echo "$PGSQL_LIBDIR" >&6; } - - elif test "${PGSQL_LIBS}" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pgsql libs" >&5 -$as_echo_n "checking for pgsql libs... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipped" >&5 -$as_echo "skipped" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pgsql libs in $PGSQL_LIBS" >&5 -$as_echo_n "checking for pgsql libs in $PGSQL_LIBS... " >&6; } - # Manual detection for - if test -f $PGSQL_LIBS/libpq.a -o -f $PGSQL_LIBS/libpq.so; then - PGSQL_LIBDIR=$PGSQL_LIBS - fi - fi - - - if test -z "$PGSQL_LIBDIR" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -$as_echo "not found" >&6; } - echo "Invalid PostgreSQL directory $PGSQL_LIBDIR - unable to find libpq.a or libpq.so." - else - #LDFLAGS="$TEMP_LDFLAGS -L$PGSQL_LIBDIR" - saved_CFLAGS=$CFLAGS - saved_LIBS=$LIBS - CFLAGS="-I$PGSQL_INCDIR" - LIBS="-L$PGSQL_LIBDIR" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PQconnectStart in -lpq" >&5 -$as_echo_n "checking for PQconnectStart in -lpq... " >&6; } -if ${ac_cv_lib_pq_PQconnectStart+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lpq $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char PQconnectStart (); -int -main () -{ -return PQconnectStart (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_pq_PQconnectStart=yes -else - ac_cv_lib_pq_PQconnectStart=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pq_PQconnectStart" >&5 -$as_echo "$ac_cv_lib_pq_PQconnectStart" >&6; } -if test "x$ac_cv_lib_pq_PQconnectStart" = xyes; then : - - PGSQL_SUPPORT="yes" - TEMP_LIBS="$TEMP_LIBS -L$PGSQL_LIBDIR -lpq" - TEMP_CFLAGS="$TEMP_CFLAGS -I$PGSQL_INCDIR" - -$as_echo "#define HAVE_PGSQL 1" >>confdefs.h - - -else - as_fn_error $? "PostgreSQL support can't build without PostgreSQL libraries" "$LINENO" 5 -fi - - LDFLAGS="" - CFLAGS=$saved_CFLAGS - LIBS=$saved_LIBS - fi - - fi # end pgsql-include , pgsql-libs - -# end PostgreSQL detection -fi - - -#Checks for header files. -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - -fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - -for ac_header in stdio.h unistd.h stdint.h fcntl.h time.h signal.h sys/ioctl.h sys/mman.h linux/videodev.h linux/videodev2.h sys/param.h sys/types.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - -for ac_func in get_current_dir_name -do : - ac_fn_c_check_func "$LINENO" "get_current_dir_name" "ac_cv_func_get_current_dir_name" -if test "x$ac_cv_func_get_current_dir_name" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GET_CURRENT_DIR_NAME 1 -_ACEOF - -fi -done - - -# Check if v4l2 is available -SUPPORTED_V4L2=false -SUPPORTED_V4L2_old=false - -if test "${V4L}" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for V42L support" >&5 -$as_echo_n "checking for V42L support... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: skipping" >&5 -$as_echo "skipping" >&6; } -else - ac_fn_c_check_type "$LINENO" "struct v4l2_buffer" "ac_cv_type_struct_v4l2_buffer" "#include - #include -" -if test "x$ac_cv_type_struct_v4l2_buffer" = xyes; then : - SUPPORTED_V4L2=true -else - SUPPORTED_V4L2=false -fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for V42L support" >&5 -$as_echo_n "checking for V42L support... " >&6; } - if test x$SUPPORTED_V4L2 = xtrue; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - TEMP_CFLAGS="${TEMP_CFLAGS} -DMOTION_V4L2" - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi - - # linux/videodev.h doesn't include videodev2.h - if test x$SUPPORTED_V4L2 = xfalse; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for V42L *old* support" >&5 -$as_echo_n "checking for V42L *old* support... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: testing" >&5 -$as_echo "testing" >&6; } - for ac_header in linux/videodev2.h -do : - ac_fn_c_check_header_compile "$LINENO" "linux/videodev2.h" "ac_cv_header_linux_videodev2_h" "#include -" -if test "x$ac_cv_header_linux_videodev2_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LINUX_VIDEODEV2_H 1 -_ACEOF - SUPPORTED_V4L2_old=true -fi - -done - - fi - - - if test x$SUPPORTED_V4L2_old = xtrue; then - TEMP_CFLAGS="${TEMP_CFLAGS} -DMOTION_V4L2 -DMOTION_V4L2_OLD" - SUPPORTED_V4L2=true - fi - -fi - - -# Check sizes of integer types -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 -$as_echo_n "checking size of short... " >&6; } -if ${ac_cv_sizeof_short+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_short" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (short) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_short=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 -$as_echo "$ac_cv_sizeof_short" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_SHORT $ac_cv_sizeof_short -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 -$as_echo_n "checking size of int... " >&6; } -if ${ac_cv_sizeof_int+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_int" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (int) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_int=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 -$as_echo "$ac_cv_sizeof_int" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_INT $ac_cv_sizeof_int -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long int" >&5 -$as_echo_n "checking size of long int... " >&6; } -if ${ac_cv_sizeof_long_int+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long int))" "ac_cv_sizeof_long_int" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_long_int" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long int) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long_int=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_int" >&5 -$as_echo "$ac_cv_sizeof_long_int" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG_INT $ac_cv_sizeof_long_int -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 -$as_echo_n "checking size of long long... " >&6; } -if ${ac_cv_sizeof_long_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_long_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long long) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long_long=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 -$as_echo "$ac_cv_sizeof_long_long" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int *" >&5 -$as_echo_n "checking size of int *... " >&6; } -if ${ac_cv_sizeof_int_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int *))" "ac_cv_sizeof_int_p" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_int_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (int *) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_int_p=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int_p" >&5 -$as_echo "$ac_cv_sizeof_int_p" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_INT_P $ac_cv_sizeof_int_p -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (void *) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_void_p=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF - - - -if test "$ac_cv_sizeof_short" = "4"; then - TEMP_CFLAGS="${TEMP_CFLAGS} -DTYPE_32BIT=\"short\"" -else - if test "$ac_cv_sizeof_int" = "4"; then - TEMP_CFLAGS="${TEMP_CFLAGS} -DTYPE_32BIT=\"int\"" - else - if test "$ac_cv_sizeof_long_int" = "4"; then - TEMP_CFLAGS="${TEMP_CFLAGS} -DTYPE_32BIT=\"long int\"" - fi - fi -fi - - -OPTIMIZECPU="yes" - - -# Check whether --with-optimizecpu was given. -if test "${with_optimizecpu+set}" = set; then : - withval=$with_optimizecpu; OPTIMIZECPU="$withval" - -fi - - -DEVELOPER_FLAGS="no" - - -# Check whether --with-developer-flags was given. -if test "${with_developer_flags+set}" = set; then : - withval=$with_developer_flags; DEVELOPER_FLAGS="$withval" - -fi - - -# Checks for typedefs, structures, and compiler characteristics. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 -$as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if ${ac_cv_c_const+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - -#ifndef __cplusplus - /* Ultrix mips cc rejects this sort of thing. */ - typedef int charset[2]; - const charset cs = { 0, 0 }; - /* SunOS 4.1.1 cc rejects this. */ - char const *const *pcpcc; - char **ppc; - /* NEC SVR4.0.2 mips cc rejects this. */ - struct point {int x, y;}; - static struct point const zero = {0,0}; - /* AIX XL C 1.02.0.0 rejects this. - It does not let you subtract one const X* pointer from another in - an arm of an if-expression whose if-part is not a constant - expression */ - const char *g = "string"; - pcpcc = &g + (g ? g-g : 0); - /* HPUX 7.0 cc rejects these. */ - ++pcpcc; - ppc = (char**) pcpcc; - pcpcc = (char const *const *) ppc; - { /* SCO 3.2v4 cc rejects this sort of thing. */ - char tx; - char *t = &tx; - char const *s = 0 ? (char *) 0 : (char const *) 0; - - *t++ = 0; - if (s) return 0; - } - { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ - int x[] = {25, 17}; - const int *foo = &x[0]; - ++foo; - } - { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ - typedef const int *iptr; - iptr p = 0; - ++p; - } - { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying - "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ - struct s { int j; const int *ap[3]; } bx; - struct s *b = &bx; b->j = 5; - } - { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ - const int foo = 10; - if (!foo) return 0; - } - return !cs[0] && !zero.x; -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_const=yes -else - ac_cv_c_const=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 -$as_echo "$ac_cv_c_const" >&6; } -if test $ac_cv_c_const = no; then - -$as_echo "#define const /**/" >>confdefs.h - -fi - - -if test "${FreeBSD}" != ""; then - OPTIMIZECPU="" -fi - -if test "${OPTIMIZECPU}" = "yes"; then - -# Try to autodetect cpu type -CPU_NAME="unknown" -CPU_TYPE="unknown" -if test -e "/proc/cpuinfo" ; then - intel[30]="-march=i386" - intel[32]="-march=i386" - intel[34]="-march=i386" - intel[40]="-march=i486" - intel[41]="-march=i486" - intel[42]="-march=i486" - intel[43]="-march=i486" - intel[44]="-march=i486" - intel[45]="-march=i486" - intel[47]="-march=i486" - intel[48]="-march=i486" - intel[51]="-march=pentium" - intel[52]="-march=pentium" - intel[54]="-march=pentium-mmx" - intel[56]="-march=pentium-mmx" - intel[61]="-march=pentiumpro" - intel[63]="-march=pentium2" - intel[65]="-march=pentium2" - intel[66]="-march=pentium2" - intel[67]="-march=pentium3" - intel[68]="-march=pentium3" - intel[610]="-march=pentium3" - intel[611]="-march=pentium3" - intel[150]="-march=pentium4" - intel[151]="-march=pentium4" - intel[152]="-march=pentium4" - intel[154]="-march=pentium4" - intel[614]="-march=prescott" - intel[628]="-march=core2" - amd[50]="-march=i586" - amd[51]="-march=i586" - amd[52]="-march=i586" - amd[53]="-march=i586" - amd[56]="-march=k6" - amd[57]="-march=k6" - amd[58]="-march=k6-2" - amd[510]="-march=k6-2" - amd[59]="-march=k6-3" - amd[513]="-march=k6-3" - amd[61]="-march=athlon" - amd[62]="-march=athlon" - amd[63]="-march=athlon" - amd[64]="-march=athlon" - amd[66]="-march=athlon" - amd[67]="-march=athlon" - amd[68]="-march=athlon" - amd[610]="-march=athlon" - amd[158]="-march=athlon-xp" - amd[154]="-march=k8" - amd[155]="-march=athlon64" - amd[1543]="-march=athlon64" - amd[1544]="-march=athlon64" - amd[1565]="-march=opteron" - amd[1572]="-march=k8" - via[67]="-march=c3" - via[68]="-march=c3" - via[69]="-march=i686" - via[610]="-march=i686" - - CPU_TYPE="known" - CPU_FAMILY=`cat /proc/cpuinfo | grep "cpu family" | head -n1` - CPU_MODEL=`cat /proc/cpuinfo | grep model[^\ ] | head -n1` - CPU_NAME=`cat /proc/cpuinfo | grep "model name" | head -n1` - CPU_FLAGS=`cat /proc/cpuinfo | grep "flags" | head -n1` - CPU_VENDOR=`cat /proc/cpuinfo | grep "vendor_id" | head -n1` - CPU_FAMILY=${CPU_FAMILY#*: } - CPU_MODEL=${CPU_MODEL#*: } - CPU_NAME=${CPU_NAME#*: } - CPU_FLAGS=${CPU_FLAGS#*: } - CPU_VENDOR=${CPU_VENDOR#*: } - if test "x${CPU_VENDOR}" = "xGenuineIntel" ; then - CPU_OPTIONS=${intel[$CPU_FAMILY$CPU_MODEL]} - fi - if test "x${CPU_VENDOR}" = "xAuthenticAMD" ; then - CPU_OPTIONS=${amd[$CPU_FAMILY$CPU_MODEL]} - fi - if test "x${CPU_VENDOR}" = "xCentaurHauls"; then - CPU_OPTIONS=${via[$CPU_FAMILY$CPU_MODEL]} - fi - if test "x${CPU_OPTIONS}" = "x" ; then - CPU_TYPE="unknown" - fi - CPU_EXT="" - for i in $CPU_FLAGS ; do - case $i in - fpu) - CPU_FPU="-mfpmath=387" - ;; - mmx) - CPU_EXT="$CPU_EXT -mmmx" - ;; - sse) - CPU_FPU="-mfpmath=sse -msse" - ;; - sse2) - CPU_FPU="-mfpmath=sse -msse2" - ;; - sse3) - CPU_FPU="-msse3" - ;; - ssse3) - CPU_FPU="-mfpmath=sse -msse2 -mssse3" - ;; - 3dnow) - CPU_EXT="$CPU_EXT -m3dnow" - ;; - esac - done - CPU_OPTIONS="$CPU_OPTIONS $CPU_FPU $CPU_EXT" -fi -if test "x${CPU_TYPE}" = "xunknown"; then - CPU_TYPE=`( uname -p ) 2>&1` - case $CPU_TYPE in - i386) - CPU_OPTIONS="-march=i386" - ;; - i486) - CPU_OPTIONS="-march=i486" - ;; - Pentium2) - CPU_OPTIONS="-march=pentium2" - ;; - Pentiumpro) - CPU_OPTIONS="-march=pentiumpro" - ;; - Pentium*) - CPU_OPTIONS="-march=pentium" - ;; - k6) - CPU_OPTIONS="-march=k6" - ;; - k6-2) - CPU_OPTIONS="-march=k6-2" - ;; - k6-3) - CPU_OPTIONS="-march=k6-3" - ;; - "VIA C3 Ezra") - CPU_OPTIONS="-march=c3" - CPU_TYPE="known" - ;; - *) - CPU_OPTIONS="" - CPU_TYPE="unknown" - ;; - esac - if test "x${CPU_TYPE}" = "xunknown"; then - CPU_TYPE=`( uname -m ) 2>&1` - case $CPU_TYPE in - i386) - CPU_OPTIONS="-march=i386" - ;; - i486) - CPU_OPTIONS="-march=i486" - ;; - i586) - CPU_OPTIONS="-march=i586" - ;; - i686) - CPU_OPTIONS="-march=i686" - ;; - Pentium2) - CPU_OPTIONS="-march=pentium2" - ;; - Pentiumpro) - CPU_OPTIONS="-march=pentiumpro" - ;; - k6) - CPU_OPTIONS="-march=k6" - ;; - k6-2) - CPU_OPTIONS="-march=k6-2" - ;; - k6-3) - CPU_OPTIONS="-march=k6-3" - ;; - *) - CPU_OPTIONS="-march=native -mtune=native" - ;; - esac - fi -fi -echo "Detected CPU: $CPU_NAME" -# Now we check if the compiler supports the detected cpu -COMPILER=$CC -for I in "$TMPDIR" "$TEMPDIR" "/tmp" ; do - test "$I" && break -done -TMPC="$I/cpu_test-$RANDOM-$$.c" -TMPO="$I/cpu_test-$RANDOM-$$.o" -cat > $TMPC << EOF -int main(void) { return 0; } -EOF -( $COMPILER $CPU_OPTIONS -o $TMPO $TMPC ) 2>&1 -TMP="$?" -rm -f $TMPO -rm -f $TMPC - - -if test "x${TMP}" = "x1" ; then - CPU_OPTIONS="" - echo "No CPU optimizations will be added" -else - echo "CPU optimization: $CPU_OPTIONS" -fi - -else - CPU_OPTIONS="" -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for bswap instruction" >&5 -$as_echo_n "checking for bswap instruction... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - -int -main () -{ -unsigned int __x=0; - register unsigned int __v; - __asm("bswap %0" : "=r" (__v) : "0" (__x)); - ; - return 0; -} - -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - - TEMP_CFLAGS="${TEMP_CFLAGS} -DHAVE_BSWAP" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - - -if test "${DEVELOPER_FLAGS}" = "yes"; then - TEMP_CFLAGS="${TEMP_CFLAGS} -W -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline -Wredundant-decls -Wno-long-long -ggdb -g3" -fi - -CFLAGS="${TEMP_CFLAGS} $UNAME_DEFS $CPU_OPTIONS" - -LIBS="${TEMP_LIBS}" -LDFLAGS="${TEMP_LDFLAGS}" - - -ac_fn_c_check_func "$LINENO" "avformat_alloc_context" "ac_cv_func_avformat_alloc_context" -if test "x$ac_cv_func_avformat_alloc_context" = xyes; then : - -$as_echo "#define have_avformat_alloc_context 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "av_avformat_alloc_context" "ac_cv_func_av_avformat_alloc_context" -if test "x$ac_cv_func_av_avformat_alloc_context" = xyes; then : - -$as_echo "#define have_av_avformat_alloc_context 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "av_register_protocol2" "ac_cv_func_av_register_protocol2" -if test "x$ac_cv_func_av_register_protocol2" = xyes; then : - -$as_echo "#define have_av_register_protocol2 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "av_register_protocol" "ac_cv_func_av_register_protocol" -if test "x$ac_cv_func_av_register_protocol" = xyes; then : - -$as_echo "#define have_av_register_protocol 1" >>confdefs.h - -fi - -ac_fn_c_check_func "$LINENO" "av_get_media_type_string" "ac_cv_func_av_get_media_type_string" -if test "x$ac_cv_func_av_get_media_type_string" = xyes; then : - -$as_echo "#define have_av_get_media_type_string 1" >>confdefs.h - -fi - - - -# -# Add the right exec path for rc scripts -# -if test $prefix = "NONE";then - BIN_PATH="$ac_default_prefix" - if test $exec_prefix = "NONE"; then - BIN_PATH="$BIN_PATH/bin" - else - BIN_PATH="$BIN_PATH/$bindir" - fi -else - if test $exec_prefix = "NONE";then - BIN_PATH="$prefix/bin" - else - BIN_PATH="$prefix/$bindir" - fi -fi - - - - -ac_config_files="$ac_config_files thread1.conf thread2.conf thread3.conf thread4.conf motion-dist.conf motion.init-FreeBSD.sh motion.init-Debian motion.init-Fedora motion.spec Makefile" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by motion $as_me Git-28b7cb2a4297c78b9c08c9ce29a648aeb22120d0, which was -generated by GNU Autoconf 2.69. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Report bugs to the package provider." - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" -ac_cs_version="\\ -motion config.status Git-28b7cb2a4297c78b9c08c9ce29a648aeb22120d0 -configured by $0, generated by GNU Autoconf 2.69, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2012 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; - --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - $as_echo "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "thread1.conf") CONFIG_FILES="$CONFIG_FILES thread1.conf" ;; - "thread2.conf") CONFIG_FILES="$CONFIG_FILES thread2.conf" ;; - "thread3.conf") CONFIG_FILES="$CONFIG_FILES thread3.conf" ;; - "thread4.conf") CONFIG_FILES="$CONFIG_FILES thread4.conf" ;; - "motion-dist.conf") CONFIG_FILES="$CONFIG_FILES motion-dist.conf" ;; - "motion.init-FreeBSD.sh") CONFIG_FILES="$CONFIG_FILES motion.init-FreeBSD.sh" ;; - "motion.init-Debian") CONFIG_FILES="$CONFIG_FILES motion.init-Debian" ;; - "motion.init-Fedora") CONFIG_FILES="$CONFIG_FILES motion.init-Fedora" ;; - "motion.spec") CONFIG_FILES="$CONFIG_FILES motion.spec" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >$CONFIG_STATUS || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script `defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >$CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - # Preserve the white space surrounding the "#". - print prefix "define", macro P[macro] D[macro] - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -$as_echo "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi - ;; - - - esac - -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - - -echo "" -echo " **************************" -echo " Configure status " -echo " ${PACKAGE_NAME} ${PACKAGE_VERSION}" -echo " **************************" -echo - - -if test "${Darwin}" != ""; then - echo "OS : Darwin" -elif test "${FreeBSD}" != ""; then - echo "OS : *BSD" -else - echo "OS : Linux" -fi - -if test "${PTHREAD_SUPPORT}" = "yes"; then - echo "pthread support: Yes" -else - echo "pthread support: No" - echo "**********************************************" - echo "** Fatal Error YOU MUST HAVE pthread Support *" - echo "**********************************************" -fi - - -if test "${JPEG_SUPPORT_TURBO}" = "yes"; then - echo "jpeg turbo support: Yes" -elif test "${JPEG_SUPPORT_MMX}" = "yes"; then - echo "jpeg-mmx support: Yes" -elif test "${JPEG_SUPPORT}" = "yes"; then - echo "jpeg support: Yes" -else - echo "jpeg support: No" - echo "**********************************************" - echo "** Fatal Error YOU MUST HAVE jpeg Support ***" - echo "**********************************************" -fi - -if test "${FreeBSD}" != ""; then - if test "${BKTR}" = "yes"; then - echo "BKTR included: Yes" - else - echo "BKTR included: No" - fi - - if test "${PWCBSD}" = "yes"; then - echo "PWCBSD include: Yes" - else - echo "PWCBSD include: No" - fi - -else - if test "${V4L}" = "yes"; then - echo "V4L support: Yes" - else - echo "V4L support: No" - fi - - if test x$SUPPORTED_V4L2 = xtrue; then - echo "V4L2 support: Yes" - else - echo "V4L2 support: No" - 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 - echo "FFmpeg support: No" -fi - -if test "${SQLITE3_SUPPORT}" = "yes"; then - echo "SQLite3 support: Yes" -else - echo "SQLite3 support: No" -fi - -if test "${MYSQL_SUPPORT}" = "yes"; then - echo "MYSQL support: Yes" -else - echo "MYSQL support: No" -fi - -if test "${PGSQL_SUPPORT}" = "yes"; then - echo "PostgreSQL support: Yes" -else - echo "PostgreSQL support: No" -fi -echo -echo "CFLAGS: $CFLAGS" -echo "LIBS: $LIBS" -echo "LDFLAGS: $LDFLAGS" -echo -echo "Install prefix: $prefix" -echo - diff --git a/configure.in b/configure.ac similarity index 71% rename from configure.in rename to configure.ac index f551e9a..5782fd6 100644 --- a/configure.in +++ b/configure.ac @@ -1,6 +1,7 @@ # Process this file with autoconf to produce a configure script AC_INIT(motion, esyscmd(['./version.sh'])) +AC_GNU_SOURCE AC_CONFIG_SRCDIR([motion.c]) AC_CONFIG_HEADERS(config.h) AC_PROG_CC @@ -36,7 +37,7 @@ if test "${Darwin}" = ""; then AC_MSG_RESULT(no) AC_MSG_CHECKING(for *BSD) - FreeBSD=`uname -a | grep "BSD"` + FreeBSD=`uname -a | grep "FreeBSD"` if test "${FreeBSD}" = ""; then AC_MSG_RESULT(no) VIDEO="video.o video2.o video_common.o" @@ -45,7 +46,7 @@ if test "${Darwin}" = ""; then if test "${LINUXTHREADS}" = "no"; then AC_MSG_CHECKING(Linuxthreads) AC_MSG_RESULT(skipping) - else + else THREAD_CHECK="/usr/local/include/pthread/linuxthreads/pthread.h" THREAD_LIB_CHECK="/usr/local/lib/liblthread.so" fi @@ -53,9 +54,9 @@ if test "${Darwin}" = ""; then if test "${PWCBSD}" != "no"; then VIDEO="video.o video2.o video_common.o" TEMP_CFLAGS="${CFLAGS} -I/usr/local/include -DPWCBSD" - else + else VIDEO="video_freebsd.o" - TEMP_CFLAGS="${CFLAGS} -I/usr/local/include" + TEMP_CFLAGS="${CFLAGS} -I/usr/local/include" fi TEMP_LDFLAGS="${LDFLAGS} -L/usr/local/lib" @@ -95,7 +96,7 @@ if test "${FreeBSD}" != "" && test "${PWCBSD}" = "no"; then TEMP_CFLAGS="${TEMP_CFLAGS} -DOLD_BKTR" fi # -# Check to Exclude BKTR +# Check to Exclude BKTR # BKTR="yes" AC_ARG_WITH(bktr, @@ -107,7 +108,7 @@ BKTR="$withval" ) if test "${BKTR}" = "no"; then - TEMP_CFLAGS="${TEMP_CFLAGS} -DWITHOUT_V4L" + TEMP_CFLAGS="${TEMP_CFLAGS} -DWITHOUT_V4L" fi else @@ -139,10 +140,10 @@ AC_MSG_CHECKING(for linuxthreads) # Check for thread header # if test -f "${THREAD_CHECK}"; then - HEADERS_THREAD_CFLAGS="-I/usr/local/include/pthread/linuxthreads" - THREADS="yes" + HEADERS_THREAD_CFLAGS="-I/usr/local/include/pthread/linuxthreads" + THREADS="yes" else - THREADS="no" + THREADS="no" fi # @@ -152,7 +153,7 @@ AC_MSG_CHECKING(for linuxthreads) THREADS="yes" LIB_THREAD="-llthread -llgcc_r" else - THREADS="no" + THREADS="no" fi # Checks for Library linuxthreads for FreeBSD @@ -198,46 +199,50 @@ if test x$PTHREAD_LIB != xyes; then fi PTHREAD_SUPPORT="yes" fi - AC_MSG_RESULT($PTHREAD_SUPPORT) + AC_MSG_RESULT($PTHREAD_SUPPORT) else - echo + echo echo "You do not have threads support" - echo + echo fi +if test "x$PTHREAD_SUPPORT" = "xyes"; then + AC_MSG_CHECKING([[for pthread_setname_np]]) + CFLAGS="$TEMP_CFLAGS" + LIBS="$TEMP_LIBS" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[#include ]], [[ pthread_setname_np(pthread_self(), "name")]])], + [AC_DEFINE([[HAVE_PTHREAD_SETNAME_NP]], [[1]], [Define if you have pthread_setname_np function.]) + AC_MSG_RESULT([[yes]])], + [AC_MSG_RESULT([[no]])] ) +fi + # # Check for sdl library # SDL_SUPPORT="no" AC_ARG_WITH(sdl, -[ --without-sdl Compile without sdl support to get stream in SDL window. +[ --with-sdl[=DIR] Specify the prefix for the install path for + sdl-config to get stream in SDL window (optional). ], [], -[]) -AC_MSG_CHECKING(for sdl) +[withval="no"]) if test "x$withval" = "xno"; then + AC_MSG_CHECKING(for sdl) AC_MSG_RESULT(skipped) else - if test "${FreeBSD}" != ""; then - CONFIG_SDL='sdl11-config' - else - CONFIG_SDL='sdl-config' - fi + AC_PATH_PROG([CONFIG_SDL], [sdl-config], [], [${PATH}:${withval}:${withval}/bin]) 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 + 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 "" else - AC_MSG_RESULT(yes) SDL_SUPPORT="yes" TEMP_LIBS="$TEMP_LIBS `${CONFIG_SDL} --libs`" TEMP_CFLAGS="${TEMP_CFLAGS} `${CONFIG_SDL} --cflags`" @@ -265,7 +270,7 @@ if test "${JPEG_TURBO}" = "no"; then AC_MSG_RESULT(skipping) else AC_MSG_CHECKING(for libjpeg-turbo in -> [${JPEG_TURBO}] <-) - if test -f ${JPEG_TURBO}/lib/libjpeg.a ; then + if test -f ${JPEG_TURBO}/lib/libjpeg.a -o -f ${JPEG_TURBO}/lib/libjpeg.so; then AC_MSG_RESULT(found) JPEG_TURBO_OK="found" else @@ -282,8 +287,8 @@ if test "${JPEG_TURBO_OK}" = "found"; then CFLAGS="$CFLAGS -I${JPEG_TURBO}/include" LIBS="$LIBS -L${JPEG_TURBO}/lib -ljpeg" AC_CHECK_LIB(jpeg, jpeg_start_compress, - [ TEMP_LIBS="$LIBS" - TEMP_CFLAGS="${CFLAGS}" + [ TEMP_LIBS="$TEMP_LIBS -L${JPEG_TURBO}/lib -ljpeg" + TEMP_CFLAGS="${TEMP_CFLAGS} -I${JPEG_TURBO}/include" TEMP_LDFLAGS="$TEMP_LDFLAGS $LDFLAGS" JPEG_SUPPORT="yes"],,) LIBS="$saved_LIBS" @@ -317,7 +322,7 @@ if test "${JPEG_MMX}" = "no" || test x$JPEG_SUPPORT != xyes; then elif test "${JPEG_MMX}" = "yes"; then # AUTODETECT STATIC LIB AC_MSG_CHECKING(for libjpeg-mmx autodetecting) - + if test -f /usr/lib/libjpeg-mmx.a ; then AC_MSG_RESULT(found) JPEG_MMX_OK="found" @@ -329,8 +334,8 @@ elif test "${JPEG_MMX}" = "yes"; then else AC_MSG_RESULT(not found) fi -else - AC_MSG_CHECKING(for libjpeg-mmx in -> [${JPEG_MMX}] <-) +else + AC_MSG_CHECKING(for libjpeg-mmx in -> [${JPEG_MMX}] <-) if test -f ${JPEG_MMX}/libjpeg-mmx.a ; then AC_MSG_RESULT(found) JPEG_MMX_OK="found" @@ -371,196 +376,74 @@ if test x$JPEG_SUPPORT != xyes ; then ) fi - # -# Check for libavcodec and libavformat from ffmpeg +# Check for the pkg-config. # -FFMPEG_DIR="yes" -FFMPEG_OK="no_found" -FFMPEG_OBJ="" -AC_ARG_WITH(ffmpeg, -[ --with-ffmpeg[=DIR] Specify the prefix for the install path for - libavcodec/libavformat (part of ffmpeg) be able to - encode mpeg movies realtime. - If this is not specified motion will try to find - the libraries in /usr and /usr/local. - ], -FFMPEG_DIR="$withval" -) -# -# ffmpeg headers custom location -# -FFMPEG_HEADERS_DIR="yes" -AC_ARG_WITH(ffmpeg_headers, -[ --with-ffmpeg-headers[=DIR] Specify the prefix for ffmpeg headers. - ], -FFMPEG_HEADERS_DIR="$withval" -) +AC_CHECK_PROG([PKGCONFIG],[pkg-config],[yes],[no]) +AM_CONDITIONAL([FOUND_PKGCONFIG], [test "x$PKGCONFIG" = xyes]) +AM_COND_IF([FOUND_PKGCONFIG],,[AC_MSG_ERROR([Required package 'pkg-config' not found, please check motion_guide.html and install necessary dependencies.])]) +# Check for raspberry pi mmal interface # -# --without-ffmpeg or with-ffmpeg=no -# -if test "${FFMPEG_DIR}" = "no"; then - AC_MSG_CHECKING(for ffmpeg) - AC_MSG_RESULT(skipping) -# -# with-ffmpeg= or nothing -# -else if test "${FFMPEG_DIR}" = "yes"; then - # AUTODETECT STATIC/SHARED LIB - AC_MSG_CHECKING(for ffmpeg autodetecting libraries) - - if test -f /usr/lib64/libavcodec.a -o -f /usr/lib64/libavcodec.so && test -f /usr/lib64/libavformat.a -o -f /usr/lib64/libavformat.so ; then - AC_MSG_RESULT(found in /usr/lib64) - FFMPEG_OK="found" - FFMPEG_LIB="/usr/lib64" - FFMPEG_DIR="/usr" - elif test -f /usr/lib/libavcodec.a -o -f /usr/lib/libavcodec.so && test -f /usr/lib/libavformat.a -o -f /usr/lib/libavformat.so ; then - AC_MSG_RESULT(found in /usr/lib) - FFMPEG_OK="found" - FFMPEG_LIB="/usr/lib" - FFMPEG_DIR="/usr" - elif test -f /usr/local/lib/libavcodec.a -o -f /usr/local/lib/libavcodec.so && test -f /usr/local/lib/libavformat.a -o -f /usr/local/lib/libavformat.so ; then - AC_MSG_RESULT(found in /usr/local/lib) - FFMPEG_OK="found" - FFMPEG_LIB="/usr/local/lib" - FFMPEG_DIR="/usr/local" - elif test -f /usr/lib/x86_64-linux-gnu/libavcodec.a -o -f /usr/lib/x86_64-linux-gnu/libavcodec.so && test /usr/lib/x86_64-linux-gnu/libavformat.a -o -f /usr/lib/x86_64-linux-gnu/libavformat.so ; then - AC_MSG_RESULT(found in /usr/lib/x86_64-linux-gnu) - FFMPEG_OK="found" - FFMPEG_LIB="/usr/lib/x86_64-linux-gnu" - FFMPEG_DIR="/usr" - else - AC_MSG_RESULT(not found) - echo "" - echo "**********************************************" - echo "* libavcodec.a or libavcodec.so or *" - echo "* libavformat.a or libavformat.so not found: *" - echo "* ALL FFMPEG FEATURES DISABLED *" - echo "* *" - echo "* Please read the Motion Guide for help: *" - echo "* http://motion.sourceforge.net *" - echo "**********************************************" - echo "" - fi -else - AC_MSG_CHECKING(for ffmpeg libraries in -> [${FFMPEG_DIR}] <-) - if test -f ${FFMPEG_DIR}/lib/libavcodec.a -o -f ${FFMPEG_DIR}/lib/libavcodec.so && test -f ${FFMPEG_DIR}/lib/libavformat.a -o -f ${FFMPEG_DIR}/lib/libavformat.so ; then - AC_MSG_RESULT(found) - FFMPEG_OK="found" - FFMPEG_LIB="${FFMPEG_DIR}/lib" - elif test -f ${FFMPEG_DIR}/libavcodec.a -o -f ${FFMPEG_DIR}/libavcodec.so && test -f ${FFMPEG_DIR}/libavformat.a -o -f ${FFMPEG_DIR}/libavformat.so ; then - AC_MSG_RESULT(found) - FFMPEG_LIB="${FFMPEG_DIR}" - FFMPEG_OK="found" - else - AC_MSG_RESULT(not found) - if test "${FFMPEG_OK}" != "found"; then - echo "" - echo "**********************************************" - echo "* libavcodec.a or libavcodec.so or *" - echo "* libavformat.a or libavformat.so not found: *" - echo "* ALL FFMPEG FEATURES DISABLED *" - echo "* *" - echo "* Please read the Motion Guide for help: *" - echo "* http://motion.sourceforge.net *" - echo "**********************************************" - echo "" - fi - fi +WITHOUT_MMAL="no" +AC_ARG_WITH([mmal], +AS_HELP_STRING([--without-mmal], + [Compile without RaspberyPi mmal camera support]), +WITHOUT_MMAL="yes", +WITHOUT_MMAL="no") + +if test "${WITHOUT_MMAL}" = "no"; then + HAVE_MMAL="" + LIBRASPBERRYPIDEVPATH="/opt/vc/include/interface/mmal" + + if test -d ${LIBRASPBERRYPIDEVPATH}; then + HAVE_MMAL="yes" + fi + + AS_IF([test "${HAVE_MMAL}" = "yes" ], [ + AC_SUBST(MMAL_CFLAGS) + AC_SUBST(MMAL_OBJ) + AC_SUBST(MMAL_LIBS) + MMAL_OBJ="mmalcam.o raspicam/RaspiCamControl.o raspicam/RaspiCLI.o" + MMAL_CFLAGS="-std=gnu99 -DHAVE_MMAL -Irasppicam -I/opt/vc/include" + MMAL_LIBS="-L/opt/vc/lib -lmmal_core -lmmal_util -lmmal_vc_client -lvcos -lvchostif -lvchiq_arm" + AC_DEFINE([HAVE_MMAL], 1, [Define to 1 if we want MMAL]) + ]) fi # -# Now check for ffmpeg headers ( avformat.h ) if ffmpeg libs were found -# - -if test "${FFMPEG_OK}" = "found"; then - if test "${FFMPEG_HEADERS_DIR}" = "yes"; then - AC_MSG_CHECKING(for ffmpeg headers in ${FFMPEG_DIR}) - else - AC_MSG_CHECKING(for ffmpeg headers in ${FFMPEG_HEADERS_DIR}) - FFMPEG_DIR="${FFMPEG_HEADERS_DIR}" - fi - - if test -f ${FFMPEG_DIR}/include/avformat.h; then - AC_MSG_RESULT(found ${FFMPEG_DIR}/include/avformat.h) - FFMPEG_CFLAGS="-I${FFMPEG_DIR}/include" - elif test -f ${FFMPEG_DIR}/avformat.h; then - AC_MSG_RESULT(found ${FFMPEG_DIR}/avformat.h) - FFMPEG_CFLAGS="-I${FFMPEG_DIR}" - elif test -f ${FFMPEG_DIR}/include/ffmpeg/avformat.h; then - AC_MSG_RESULT(found ${FFMPEG_DIR}/include/ffmpeg/avformat.h) - FFMPEG_CFLAGS="-I${FFMPEG_DIR}/include/ffmpeg" - elif test -f ${FFMPEG_DIR}/include/libavformat/avformat.h; then - AC_MSG_RESULT(found ${FFMPEG_DIR}/include/libavformat/avformat.h) - FFMPEG_CFLAGS="-I${FFMPEG_DIR}/include -DFFMPEG_NEW_INCLUDES" - AVFORMAT="-I${FFMPEG_DIR}/include/libavformat" - elif test -f ${FFMPEG_DIR}/include/ffmpeg/libavformat/avformat.h; then - AC_MSG_RESULT(found ${FFMPEG_DIR}/include/ffmpeg/libavformat/avformat.h) - FFMPEG_CFLAGS="-I${FFMPEG_DIR}/include/ffmpeg -DFFMPEG_NEW_INCLUDES" - AVFORMAT="-I${FFMPEG_DIR}/include/ffmpeg/libavformat" - elif test -f ${FFMPEG_DIR}/libavformat/avformat.h; then - AC_MSG_RESULT(found ${FFMPEG_DIR}/libavformat/avformat.h) - FFMPEG_CFLAGS="-I${FFMPEG_DIR} -DFFMPEG_NEW_INCLUDES" - AVFORMAT="-I{FFMPEG_DIR}/libavformat" - else - AC_MSG_RESULT(not found) - FFMPEG_OK="no_found" - echo "**********************************************" - echo "* avformat.h not found: *" - echo "* ALL FFMPEG FEATURES DISABLED *" - echo "* *" - echo "* Please read the Motion Guide for help: *" - echo "* http://motion.sourceforge.net *" - echo "**********************************************" - echo "" - fi - -# -# If ffmpeg libs and headers have been found +# Check for libavcodec and libavformat from ffmpeg # +FFMPEG_OBJ="" +AC_ARG_WITH([ffmpeg], + AS_HELP_STRING([--with-ffmpeg[=DIR]], [Build with FFMPEG support]), + [with_ffmpeg=$withval], + [with_ffmpeg=yes]) + +AS_IF([test "x$with_ffmpeg" != "xno"], [ + AS_IF([test "x$with_ffmpeg" != "xyes"], [ + PKG_CONFIG_PATH=${with_ffmpeg}/lib/pkgconfig:$PKG_CONFIG_PATH + export PKG_CONFIG_PATH + ]) - if test "${FFMPEG_OK}" = "found"; then - TEMP_LIBS="$TEMP_LIBS -L${FFMPEG_LIB} -lavformat -lavcodec -lavutil -lm -lz" - TEMP_LDFLAGS="${TEMP_LDFLAGS} -L${FFMPEG_LIB}" - TEMP_CFLAGS="${TEMP_CFLAGS} -DHAVE_FFMPEG ${FFMPEG_CFLAGS}" - - FFMPEG_OBJ="ffmpeg.o" - AC_SUBST(FFMPEG_OBJ) - - RTPS_OBJ="netcam_rtsp.o" - AC_SUBST(RTPS_OBJ) - - AC_MSG_CHECKING([file_protocol is defined in ffmpeg ?]) - saved_CFLAGS=$CFLAGS - saved_LIBS=$LIBS - - - CFLAGS="${FFMPEG_CFLAGS} ${AVFORMAT}" - LIBS="$TEMP_LIBS" - - AC_COMPILE_IFELSE([AC_LANG_SOURCE([ - [ - #include - URLProtocol test_file_protocol; - int main(void){ - test_file_protocol.url_read = file_protocol.url_read; - return 0; - } - ]])], - [AC_MSG_RESULT(yes)], - [ - AC_MSG_RESULT(no) - TEMP_CFLAGS="${TEMP_CFLAGS} -DHAVE_FFMPEG_NEW" - ] - ) - CFLAGS=$saved_CFLAGS - LIBS=$saved_LIBS - fi -fi -fi + AC_SUBST(FFMPEG_LIBS) + AC_SUBST(FFMPEG_CFLAGS) + FFMPEG_DEPS="libavutil libavformat libavcodec libswscale" + if pkg-config $FFMPEG_DEPS; then + FFMPEG_CFLAGS=`pkg-config --cflags $FFMPEG_DEPS` + FFMPEG_LIBS=`pkg-config --libs $FFMPEG_DEPS` + HAVE_FFMPEG="yes" + else + AC_MSG_ERROR([Required ffmpeg packages 'libavutil-dev libavformat-dev libavcodec-dev libswscale-dev' were not found. Please check motion_guide.html and install necessary dependencies or use the '--without-ffmpeg' configuration option.]) + fi +]) +AS_IF([test "${HAVE_FFMPEG}" = "yes" ], [ + FFMPEG_OBJ="ffmpeg.o" + AC_DEFINE([HAVE_FFMPEG], 1, [Define to 1 if FFMPEG is around]) +]) +AC_SUBST(FFMPEG_OBJ) # # Check SQLITE3 @@ -581,17 +464,28 @@ else saved_CFLAGS=$CFLAGS saved_LIBS=$LIBS - AC_CHECK_LIB(sqlite3, sqlite3_open, - [ - TEMP_LIBS="$TEMP_LIBS -lsqlite3" - SQLITE3_SUPPORT="yes" - AC_DEFINE([HAVE_SQLITE3],1,[Define to 1 if you have SQLITE3 support]) - ] - ) + # first we check to see if the sqlite3 amalgamation (sqlite3.c), is in with our source + # this is the preferred way to use sqlite + if test -f sqlite3.c; then + SQLITE3_SUPPORT="yes" + VIDEO="$VIDEO sqlite3.o" + TEMP_LIBS="$TEMP_LIBS -ldl" + AC_DEFINE([HAVE_SQLITE3],1,[Define to 1 if you have SQLITE3]) + AC_DEFINE([HAVE_SQLITE3_EMBEDDED],1,[Define to 1 if you have SQLITE3 embedded support]) + else + # if sqlite3.c is not found then we look for the shared library + AC_CHECK_LIB(sqlite3, sqlite3_open, + [ + TEMP_LIBS="$TEMP_LIBS -lsqlite3" + SQLITE3_SUPPORT="yes" + AC_DEFINE([HAVE_SQLITE3],1,[Define to 1 if you have SQLITE3 shared library support]) + ] + ) + fi CFLAGS=$saved_CFLAGS LIBS=$saved_LIBS -fi +fi # @@ -661,13 +555,13 @@ else fi done elif test "${MYSQL_HEADERS}" = "no"; then - AC_MSG_CHECKING(for mysql headers) + AC_MSG_CHECKING(for mysql headers) AC_MSG_RESULT(skipped) else AC_MSG_CHECKING(for mysql headers in $MYSQL_HEADERS) # Manual detection for - if test -f $MYSQL_HEADERS/mysql.h; then - MYSQL_INCDIR=$MYSQL_HEADERS + if test -f $MYSQL_HEADERS/mysql.h; then + MYSQL_INCDIR=$MYSQL_HEADERS fi fi @@ -686,7 +580,7 @@ else # ******* Search mysql libs ********* if test "${MYSQL_LIBS}" = "yes"; then AC_MSG_CHECKING(autodect mysql libs) - # Autodetect + # Autodetect for w in /usr/lib64 /usr/lib /usr/local/lib /usr/mysql /usr/local/mysql /usr/local/mysql/lib /opt /opt/mysql /usr/lib/x86_64-linux-gnu; do # check for plain setups if test -f $w/libmysqlclient.a -o -f $w/libmysqlclient.so; then @@ -705,7 +599,7 @@ else fi done elif test "${MYSQL_LIBS}" = "no"; then - AC_MSG_CHECKING(for mysql libs) + AC_MSG_CHECKING(for mysql libs) AC_MSG_RESULT(skipped) else AC_MSG_CHECKING(for mysql libs in $MYSQL_LIBS) @@ -726,13 +620,13 @@ else saved_LIBS=$LIBS CFLAGS="-I$MYSQL_INCDIR" LIBS="-L$MYSQL_LIBDIR" - AC_CHECK_LIB(mysqlclient,mysql_init,[ + AC_CHECK_LIB(mysqlclient,mysql_init,[ TEMP_LIBS="$TEMP_LIBS -L$MYSQL_LIBDIR -lmysqlclient -lz" TEMP_CFLAGS="$TEMP_CFLAGS -I$MYSQL_INCDIR" MYSQL_SUPPORT="yes" AC_DEFINE([HAVE_MYSQL],1,[Define to 1 if you have MySQL support]) ], - AC_MSG_ERROR(MySQL support can't build without MySQL libraries)) + AC_MSG_ERROR(MySQL support can't build without MySQL libraries)) CFLAGS=$saved_CFLAGS LIBS=$saved_LIBS fi @@ -752,7 +646,7 @@ PGSQL_SUPPORT="no" PGSQL_HEADERS="yes" PGSQL_LIBS="yes" -AC_DEFUN(PGSQL_INC_CHK,[if test -r $i$1/libpq-fe.h; then PGSQL_DIR=$i; PGSQL_INCDIR=$i$1]) +AC_DEFUN([PGSQL_INC_CHK],[if test -r $i$1/libpq-fe.h; then PGSQL_DIR=$i; PGSQL_INCDIR=$i$1]) AC_ARG_WITH(pgsql, [ --without-pgsql Disable PostgreSQL support in motion. @@ -799,15 +693,15 @@ else el[]PGSQL_INC_CHK(/include/postgresql) fi done - + elif test "${PGSQL_HEADERS}" = "no"; then - AC_MSG_CHECKING(for pgsql headers) + AC_MSG_CHECKING(for pgsql headers) AC_MSG_RESULT(skipped) else AC_MSG_CHECKING(for pgsql headers in $PGSQL_HEADERS) # Manual detection for - if test -f $PGSQL_HEADERS/libpq-fe.h; then - PGSQL_INCDIR=$PGSQL_HEADERS + if test -f $PGSQL_HEADERS/libpq-fe.h; then + PGSQL_INCDIR=$PGSQL_HEADERS fi fi @@ -833,10 +727,10 @@ else if test -f /usr/lib64/libpq.so ; then PGSQL_LIBDIR=/usr/lib64 elif test -f $PGSQL_DIR/lib/pgsql/libpq.so ; then - PGSQL_LIBDIR=$PGSQL_DIR/lib/pgsql + PGSQL_LIBDIR=$PGSQL_DIR/lib/pgsql elif test -f $PGSQL_DIR/lib/postgresql/libpq.so ; then PGSQL_LIBDIR=$PGSQL_DIR/lib/postgresql - elif test -f $PGSQL_DIR/lib/libpq.so ; then + elif test -f $PGSQL_DIR/lib/libpq.so ; then PGSQL_LIBDIR=$PGSQL_DIR/lib else PGSQL_LIBDIR="" @@ -845,7 +739,7 @@ else AC_MSG_RESULT($PGSQL_LIBDIR) elif test "${PGSQL_LIBS}" = "no"; then - AC_MSG_CHECKING(for pgsql libs) + AC_MSG_CHECKING(for pgsql libs) AC_MSG_RESULT(skipped) else AC_MSG_CHECKING(for pgsql libs in $PGSQL_LIBS) @@ -870,13 +764,13 @@ else TEMP_LIBS="$TEMP_LIBS -L$PGSQL_LIBDIR -lpq" TEMP_CFLAGS="$TEMP_CFLAGS -I$PGSQL_INCDIR" AC_DEFINE([HAVE_PGSQL],1,[Define to 1 if you have PostgreSQL support]) - ], + ], AC_MSG_ERROR(PostgreSQL support can't build without PostgreSQL libraries)) - LDFLAGS="" + LDFLAGS="" CFLAGS=$saved_CFLAGS LIBS=$saved_LIBS fi - + fi # end pgsql-include , pgsql-libs # end PostgreSQL detection @@ -885,7 +779,7 @@ fi #Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(stdio.h unistd.h stdint.h fcntl.h time.h signal.h sys/ioctl.h sys/mman.h linux/videodev.h linux/videodev2.h sys/param.h sys/types.h) +AC_CHECK_HEADERS(stdio.h unistd.h stdint.h fcntl.h time.h signal.h sys/ioctl.h sys/mman.h linux/videodev.h linux/videodev2.h sys/param.h sys/types.h sys/videoio.h) AC_CHECK_FUNCS(get_current_dir_name) @@ -897,17 +791,20 @@ if test "${V4L}" = "no"; then AC_MSG_CHECKING(for V42L support) AC_MSG_RESULT(skipping) else - AC_CHECK_TYPE([struct v4l2_buffer], - [SUPPORTED_V4L2=true], - [SUPPORTED_V4L2=false], - [#include - #include ]) - + AC_CHECK_TYPE([struct v4l2_buffer], + [SUPPORTED_V4L2=true], + [SUPPORTED_V4L2=false], + [#include + #ifdef HAVE_LINUX_VIDEODEV_H + #include + #elif HAVE_SYS_VIDEOIO_H + #include + #endif]) AC_MSG_CHECKING(for V42L support) if test x$SUPPORTED_V4L2 = xtrue; then AC_MSG_RESULT(yes) TEMP_CFLAGS="${TEMP_CFLAGS} -DMOTION_V4L2" - else + else AC_MSG_RESULT(no) fi @@ -979,7 +876,18 @@ if test "${OPTIMIZECPU}" = "yes"; then # Try to autodetect cpu type CPU_NAME="unknown" CPU_TYPE="unknown" -if test -e "/proc/cpuinfo" ; then +if test -e "/proc/device-tree/model"; then + # explicit test for RPI3 as /proc/cpuinfo reports armv7 even though + # it is armv8 + RPI3=`grep "Raspberry Pi 3 Model" /proc/device-tree/model` + if test "x${RPI3}" != "x"; then + CPU_NAME="Raspberry Pi 3" + CPU_TYPE="Raspberry Pi 3" + CPU_OPTIONS="-mcpu=cortex-a53 -mfpu=neon-fp-armv8" + fi +fi + +if test "x${CPU_TYPE}" = "xunknown" && test -e "/proc/cpuinfo" ; then intel[[30]]="-march=i386" intel[[32]]="-march=i386" intel[[34]]="-march=i386" @@ -1033,12 +941,12 @@ if test -e "/proc/cpuinfo" ; then amd[[1543]]="-march=athlon64" amd[[1544]]="-march=athlon64" amd[[1565]]="-march=opteron" - amd[[1572]]="-march=k8" + amd[[1572]]="-march=k8" via[[67]]="-march=c3" via[[68]]="-march=c3" - via[[69]]="-march=i686" + via[[69]]="-march=i686" via[[610]]="-march=i686" - + CPU_TYPE="known" CPU_FAMILY=`cat /proc/cpuinfo | grep "cpu family" | head -n1` CPU_MODEL=`cat /proc/cpuinfo | grep model[[^\ ]] | head -n1` @@ -1179,11 +1087,11 @@ rm -f $TMPO rm -f $TMPC -if test "x${TMP}" = "x1" ; then +if test "x${TMP}" = "x0" ; then + echo "CPU optimization: $CPU_OPTIONS" +else CPU_OPTIONS="" echo "No CPU optimizations will be added" -else - echo "CPU optimization: $CPU_OPTIONS" fi else @@ -1202,7 +1110,7 @@ AC_LINK_IFELSE([ TEMP_CFLAGS="${TEMP_CFLAGS} -DHAVE_BSWAP" AC_MSG_RESULT(yes) ], - [ + [ AC_MSG_RESULT(no) ]) @@ -1217,13 +1125,6 @@ LIBS="${TEMP_LIBS}" LDFLAGS="${TEMP_LDFLAGS}" -AC_CHECK_FUNC(avformat_alloc_context, AC_DEFINE([have_avformat_alloc_context],1,[Define to 1 if you have avformat_alloc_context support])) -AC_CHECK_FUNC(av_avformat_alloc_context, AC_DEFINE([have_av_avformat_alloc_context],1,[Define to 1 if you have av_avformat_alloc_context support])) -AC_CHECK_FUNC(av_register_protocol2, AC_DEFINE([have_av_register_protocol2],1,[Define to 1 if you have av_register_protocol2 support])) -AC_CHECK_FUNC(av_register_protocol, AC_DEFINE([have_av_register_protocol],1,[Define to 1 if you have av_register_protocol support])) -AC_CHECK_FUNC(av_get_media_type_string, AC_DEFINE([have_av_get_media_type_string],1,[Define to 1 if you have av_get_media_type_string support])) - - # # Add the right exec path for rc scripts # @@ -1242,18 +1143,17 @@ else fi fi - AC_SUBST(BIN_PATH) AC_CONFIG_FILES([ -thread1.conf -thread2.conf -thread3.conf -thread4.conf +camera1-dist.conf +camera2-dist.conf +camera3-dist.conf +camera4-dist.conf motion-dist.conf motion.init-FreeBSD.sh motion.init-Debian -motion.init-Fedora +motion.service motion.spec Makefile ]) @@ -1264,14 +1164,14 @@ echo " **************************" echo " Configure status " echo " ${PACKAGE_NAME} ${PACKAGE_VERSION}" echo " **************************" -echo +echo if test "${Darwin}" != ""; then echo "OS : Darwin" elif test "${FreeBSD}" != ""; then - echo "OS : *BSD" -else + echo "OS : *BSD" +else echo "OS : Linux" fi @@ -1281,7 +1181,7 @@ else echo "pthread support: No" echo "**********************************************" echo "** Fatal Error YOU MUST HAVE pthread Support *" - echo "**********************************************" + echo "**********************************************" fi @@ -1319,7 +1219,7 @@ else fi if test x$SUPPORTED_V4L2 = xtrue; then - echo "V4L2 support: Yes" + echo "V4L2 support: Yes" else echo "V4L2 support: No" fi @@ -1331,8 +1231,22 @@ else echo "SDL support: No" fi -if test "${FFMPEG_OK}" = "found"; then +if test "${HAVE_MMAL}" = "yes"; then + echo "MMAL support: Yes" + echo " ... MMAL_CFLAGS: $MMAL_CFLAGS" + echo " ... MMAL_OBJ: $MMAL_OBJ" + echo " ... MMAL_LIBS: $MMAL_LIBS" +elif test "${WITHOUT_MMAL}" = "yes"; then + echo "MMAL support: disabled" +else + echo "MMAL support: No" + echo " ... libraspberrypi-dev package not installed" +fi + +if test "${HAVE_FFMPEG}" = "yes"; then echo "FFmpeg support: Yes" + echo " ... FFMPEG_CFLAGS: $FFMPEG_CFLAGS" + echo " ... FFMPEG_LIBS: $FFMPEG_LIBS" else echo "FFmpeg support: No" fi @@ -1354,11 +1268,10 @@ if test "${PGSQL_SUPPORT}" = "yes"; then else echo "PostgreSQL support: No" fi -echo +echo echo "CFLAGS: $CFLAGS" echo "LIBS: $LIBS" echo "LDFLAGS: $LDFLAGS" echo echo "Install prefix: $prefix" echo - diff --git a/copyright b/copyright new file mode 100644 index 0000000..64f3f51 --- /dev/null +++ b/copyright @@ -0,0 +1,47 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: motion +Source: http://motion.sourceforge.net/ +License: GPL-2+ + +Files: * +Copyright: 1999-2014 motion authors; see CREDITS for details +License: GPL-2+ + +Files: md5.* +Copyright: 1991-1992 RSA Data Security, Inc +License: custom-RSA + +Files: netcam_wget.* +Copyright: 1995-2002 Free Software Foundation, Inc. +License: GPL-2+ + +Files: mmx.h +Copyright: 1997-2001 H. Dietz and R. Fisher +License: GPL-2+ + +Files: debian/* +Copyright: 2000-2014 motion Debian packagers; see debian/changelog for details +License: GPL-2+ + +License: GPL-2+ + On Debian systems, the complete text of the GNU General Public + License can be found in the file /usr/share/common-licenses/GPL-2'. + +License: custom-RSA + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + . + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + . + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + . + These notices must be retained in any copies of any part of this + documentation and/or software. diff --git a/event.c b/event.c index e93c8d5..8ca59b0 100644 --- a/event.c +++ b/event.c @@ -17,6 +17,44 @@ /* Various functions (most doing the actual action) */ +const char *eventList[] = { + "NULL", + "EVENT_FILECREATE", + "EVENT_MOTION", + "EVENT_FIRSTMOTION", + "EVENT_ENDMOTION", + "EVENT_STOP", + "EVENT_TIMELAPSE", + "EVENT_TIMELAPSEEND", + "EVENT_STREAM", + "EVENT_IMAGE_DETECTED", + "EVENT_IMAGEM_DETECTED", + "EVENT_IMAGE_SNAPSHOT", + "EVENT_IMAGE", + "EVENT_IMAGEM", + "EVENT_FILECLOSE", + "EVENT_DEBUG", + "EVENT_CRITICAL", + "EVENT_AREA_DETECTED", + "EVENT_CAMERA_LOST", + "EVENT_FFMPEG_PUT", + "EVENT_SDL_PUT", + "EVENT_LAST" +}; + +/** + * eventToString + * + * returns string label of the event + */ + /** + * Future use debug / notification function +static const char *eventToString(motion_event e) +{ + return eventList[(int)e]; +} +*/ + /** * exec_command * Execute 'command' with 'arg' as its argument. @@ -61,15 +99,16 @@ static void exec_command(struct context *cnt, char *command, char *filename, int */ static void event_newfile(struct context *cnt ATTRIBUTE_UNUSED, - int type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, - char *filename, void *ftype, struct tm *tm ATTRIBUTE_UNUSED) + motion_event type ATTRIBUTE_UNUSED, + unsigned char *dummy ATTRIBUTE_UNUSED, char *filename, void *ftype, + struct tm *tm ATTRIBUTE_UNUSED) { MOTION_LOG(NTC, TYPE_EVENTS, NO_ERRNO, "%s: File of type %ld saved to: %s", (unsigned long)ftype, filename); } -static void event_beep(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_beep(struct context *cnt, motion_event type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, char *filename ATTRIBUTE_UNUSED, void *ftype ATTRIBUTE_UNUSED, @@ -88,7 +127,8 @@ static void event_beep(struct context *cnt, int type ATTRIBUTE_UNUSED, * to the config parameter. */ static void on_picture_save_command(struct context *cnt, - int type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, + motion_event type ATTRIBUTE_UNUSED, + unsigned char *dummy ATTRIBUTE_UNUSED, char *filename, void *arg, struct tm *tm ATTRIBUTE_UNUSED) { int filetype = (unsigned long)arg; @@ -101,7 +141,8 @@ static void on_picture_save_command(struct context *cnt, } static void on_motion_detected_command(struct context *cnt, - int type ATTRIBUTE_UNUSED, unsigned char *dummy1 ATTRIBUTE_UNUSED, + motion_event type ATTRIBUTE_UNUSED, + unsigned char *dummy1 ATTRIBUTE_UNUSED, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { @@ -111,7 +152,8 @@ static void on_motion_detected_command(struct context *cnt, #if defined(HAVE_MYSQL) || defined(HAVE_PGSQL) || defined(HAVE_SQLITE3) -static void event_sqlnewfile(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_sqlnewfile(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, char *filename, void *arg, struct tm *tm ATTRIBUTE_UNUSED) { @@ -143,7 +185,7 @@ static void event_sqlnewfile(struct context *cnt, int type ATTRIBUTE_UNUSED, // Close connection before start a new connection mysql_close(cnt->database); - cnt->database = (MYSQL *) mymalloc(sizeof(MYSQL)); + cnt->database = mymalloc(sizeof(MYSQL)); mysql_init(cnt->database); if (!mysql_real_connect(cnt->database, cnt->conf.database_host, @@ -178,8 +220,8 @@ static void event_sqlnewfile(struct context *cnt, int type ATTRIBUTE_UNUSED, MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, "%s: Connection to PostgreSQL database '%s' failed: %s", cnt->conf.database_dbname, PQerrorMessage(cnt->database_pg)); - - // This function will close the connection to the server and attempt to reestablish a new connection to the same server, + + // This function will close the connection to the server and attempt to reestablish a new connection to the same server, // using all the same parameters previously used. This may be useful for error recovery if a working connection is lost PQreset(cnt->database_pg); @@ -194,12 +236,12 @@ static void event_sqlnewfile(struct context *cnt, int type ATTRIBUTE_UNUSED, } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO, "%s: PGSQL query [%s] failed", sqlquery); PQclear(res); - } + } } #endif /* HAVE_PGSQL */ #ifdef HAVE_SQLITE3 - if ((!strcmp(cnt->conf.database_type, "sqlite3")) && (cnt->conf.sqlite3_db)) { + if ((!strcmp(cnt->conf.database_type, "sqlite3")) && (cnt->conf.database_dbname)) { int res; char *errmsg = 0; res = sqlite3_exec(cnt->database_sqlite3, sqlquery, NULL, 0, &errmsg); @@ -215,7 +257,8 @@ static void event_sqlnewfile(struct context *cnt, int type ATTRIBUTE_UNUSED, #endif /* defined HAVE_MYSQL || defined HAVE_PGSQL || defined(HAVE_SQLITE3) */ -static void on_area_command(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void on_area_command(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *dummy1 ATTRIBUTE_UNUSED, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) @@ -224,7 +267,8 @@ static void on_area_command(struct context *cnt, int type ATTRIBUTE_UNUSED, exec_command(cnt, cnt->conf.on_area_detected, NULL, 0); } -static void on_event_start_command(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void on_event_start_command(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *dummy1 ATTRIBUTE_UNUSED, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) @@ -233,7 +277,8 @@ static void on_event_start_command(struct context *cnt, int type ATTRIBUTE_UNUSE exec_command(cnt, cnt->conf.on_event_start, NULL, 0); } -static void on_event_end_command(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void on_event_end_command(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *dummy1 ATTRIBUTE_UNUSED, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) @@ -242,7 +287,8 @@ static void on_event_end_command(struct context *cnt, int type ATTRIBUTE_UNUSED, exec_command(cnt, cnt->conf.on_event_end, NULL, 0); } -static void event_stop_stream(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_stop_stream(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *dummy1 ATTRIBUTE_UNUSED, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) @@ -251,7 +297,8 @@ static void event_stop_stream(struct context *cnt, int type ATTRIBUTE_UNUSED, stream_stop(cnt); } -static void event_stream_put(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_stream_put(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { @@ -260,7 +307,8 @@ static void event_stream_put(struct context *cnt, int type ATTRIBUTE_UNUSED, } #ifdef HAVE_SDL -static void event_sdl_put(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_sdl_put(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { @@ -270,7 +318,8 @@ static void event_sdl_put(struct context *cnt, int type ATTRIBUTE_UNUSED, #if defined(HAVE_LINUX_VIDEODEV_H) && !defined(WITHOUT_V4L) && !defined(BSD) -static void event_vid_putpipe(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_vid_putpipe(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy ATTRIBUTE_UNUSED, void *devpipe, struct tm *tm ATTRIBUTE_UNUSED) { @@ -289,7 +338,8 @@ const char *imageext(struct context *cnt) return "jpg"; } -static void event_image_detect(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_image_detect(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *newimg, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) { @@ -315,7 +365,8 @@ static void event_image_detect(struct context *cnt, int type ATTRIBUTE_UNUSED, } } -static void event_imagem_detect(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_imagem_detect(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *newimg ATTRIBUTE_UNUSED, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) { @@ -345,15 +396,21 @@ static void event_imagem_detect(struct context *cnt, int type ATTRIBUTE_UNUSED, } } -static void event_image_snapshot(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_image_snapshot(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) { char fullfilename[PATH_MAX]; + char filename[PATH_MAX]; + char filepath[PATH_MAX]; + int offset = 0; + int len = strlen(cnt->conf.snappath); + + if (len >= 9) + offset = len - 8; - if (strcmp(cnt->conf.snappath, "lastsnap")) { - char filename[PATH_MAX]; - char filepath[PATH_MAX]; + if (strcmp(cnt->conf.snappath+offset, "lastsnap")) { char linkpath[PATH_MAX]; const char *snappath; /* @@ -383,7 +440,9 @@ static void event_image_snapshot(struct context *cnt, int type ATTRIBUTE_UNUSED, return; } } else { - snprintf(fullfilename, PATH_MAX, "%s/lastsnap.%s", cnt->conf.filepath, imageext(cnt)); + mystrftime(cnt, filepath, sizeof(filepath), cnt->conf.snappath, currenttime_tm, NULL, 0); + snprintf(filename, PATH_MAX, "%s.%s", filepath, imageext(cnt)); + snprintf(fullfilename, PATH_MAX, "%s/%s", cnt->conf.filepath, filename); remove(fullfilename); put_picture(cnt, fullfilename, img, FTYPE_IMAGE_SNAPSHOT); } @@ -391,7 +450,8 @@ static void event_image_snapshot(struct context *cnt, int type ATTRIBUTE_UNUSED, cnt->snapshot = 0; } -static void event_camera_lost(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_camera_lost(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *img ATTRIBUTE_UNUSED, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm ATTRIBUTE_UNUSED) { @@ -399,7 +459,8 @@ static void event_camera_lost(struct context *cnt, int type ATTRIBUTE_UNUSED, exec_command(cnt, cnt->conf.on_camera_lost, NULL, 0); } -static void on_movie_end_command(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void on_movie_end_command(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, char *filename, void *arg, struct tm *tm ATTRIBUTE_UNUSED) { @@ -409,22 +470,24 @@ static void on_movie_end_command(struct context *cnt, int type ATTRIBUTE_UNUSED, exec_command(cnt, cnt->conf.on_movie_end, filename, filetype); } -static void event_extpipe_end(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_extpipe_end(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { if (cnt->extpipe_open) { cnt->extpipe_open = 0; fflush(cnt->extpipe); - MOTION_LOG(ERR, TYPE_EVENTS, NO_ERRNO, "%s: CLOSING: extpipe file desc %d, error state %d", + MOTION_LOG(NTC, TYPE_EVENTS, NO_ERRNO, "%s: CLOSING: extpipe file desc %d, error state %d", fileno(cnt->extpipe), ferror(cnt->extpipe)); - MOTION_LOG(ERR, TYPE_EVENTS, NO_ERRNO, "%s: pclose return: %d", + MOTION_LOG(NTC, TYPE_EVENTS, NO_ERRNO, "%s: pclose return: %d", pclose(cnt->extpipe)); event(cnt, EVENT_FILECLOSE, NULL, cnt->extpipefilename, (void *)FTYPE_MPEG, NULL); } } -static void event_create_extpipe(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_create_extpipe(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) { @@ -449,7 +512,7 @@ static void event_create_extpipe(struct context *cnt, int type ATTRIBUTE_UNUSED, snprintf(cnt->extpipefilename, PATH_MAX - 4, "%s/%s", cnt->conf.filepath, stamp); /* Open a dummy file to check if path is correct */ - fd_dummy = myfopen(cnt->extpipefilename, "w", 0); + fd_dummy = myfopen(cnt->extpipefilename, "w"); /* TODO: trigger some warning instead of only log an error message */ if (fd_dummy == NULL) { @@ -490,7 +553,8 @@ static void event_create_extpipe(struct context *cnt, int type ATTRIBUTE_UNUSED, } } -static void event_extpipe_put(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_extpipe_put(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { @@ -501,7 +565,7 @@ static void event_extpipe_put(struct context *cnt, int type ATTRIBUTE_UNUSED, /* Check that is open */ if ((cnt->extpipe_open) && (fileno(cnt->extpipe) > 0)) { if (!fwrite(img, cnt->imgs.size, 1, cnt->extpipe)) - MOTION_LOG(ERR, TYPE_EVENTS, SHOW_ERRNO, "%s: Error writting in pipe , state error %d", + MOTION_LOG(ERR, TYPE_EVENTS, SHOW_ERRNO, "%s: Error writing in pipe , state error %d", ferror(cnt->extpipe)); } else { MOTION_LOG(ERR, TYPE_EVENTS, NO_ERRNO, "%s: pipe %s not created or closed already ", @@ -511,7 +575,8 @@ static void event_extpipe_put(struct context *cnt, int type ATTRIBUTE_UNUSED, } -static void event_new_video(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_new_video(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { @@ -519,13 +584,9 @@ static void event_new_video(struct context *cnt, int type ATTRIBUTE_UNUSED, cnt->movie_fps = cnt->lastrate; - MOTION_LOG(NTC, TYPE_EVENTS, NO_ERRNO, "%s FPS %d", - cnt->movie_fps); + MOTION_LOG(NTC, TYPE_EVENTS, NO_ERRNO, "%s Source FPS %d", cnt->movie_fps); - if (cnt->movie_fps > 30) - cnt->movie_fps = 30; - else if (cnt->movie_fps < 2) - cnt->movie_fps = 2; + if (cnt->movie_fps < 2) cnt->movie_fps = 2; } #ifdef HAVE_FFMPEG @@ -537,7 +598,8 @@ static void grey2yuv420p(unsigned char *u, unsigned char *v, int width, int heig } -static void event_ffmpeg_newfile(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_ffmpeg_newfile(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) { @@ -546,6 +608,8 @@ static void event_ffmpeg_newfile(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *convbuf, *y, *u, *v; char stamp[PATH_MAX]; const char *moviepath; + const char *codec; + long codenbr; if (!cnt->conf.ffmpeg_output && !cnt->conf.ffmpeg_output_debug) return; @@ -565,9 +629,62 @@ static void event_ffmpeg_newfile(struct context *cnt, int type ATTRIBUTE_UNUSED, * motion movies get the same name as normal movies plus an appended 'm' * PATH_MAX - 4 to allow for .mpg to be appended without overflow */ - snprintf(cnt->motionfilename, PATH_MAX - 4, "%s/%sm", cnt->conf.filepath, stamp); - snprintf(cnt->newfilename, PATH_MAX - 4, "%s/%s", cnt->conf.filepath, stamp); + /* The following section allows for testing of all the various containers + * that Motion permits. The container type is pre-pended to the name of the + * file so that we can determine which container type created what movie. + * The intent for this is be used for developer testing when the ffmpeg libs + * change or the code inside our ffmpeg module changes. For each event, the + * container type will change. This way, you can turn on emulate motion, then + * specify a maximum movie time and let Motion run for days creating all the + * different types of movies checking for crashes, warnings, etc. + */ + codec = cnt->conf.ffmpeg_video_codec; + if (strcmp(codec, "ogg") == 0) { + MOTION_LOG(WRN, TYPE_ENCODER, NO_ERRNO, "%s The ogg container is no longer supported. Changing to mpeg4"); + codec = "mpeg4"; + } + if (strcmp(codec, "test") == 0) { + MOTION_LOG(NTC, TYPE_ENCODER, NO_ERRNO, "%s Running test of the various output formats."); + codenbr = cnt->event_nr % 10; + switch (codenbr) { + case 1: + codec = "mpeg4"; + break; + case 2: + codec = "msmpeg4"; + break; + case 3: + codec = "swf"; + break; + case 4: + codec = "flv"; + break; + case 5: + codec = "ffv1"; + break; + case 6: + codec = "mov"; + break; + case 7: + codec = "mp4"; + break; + case 8: + codec = "mkv"; + break; + case 9: + codec = "hevc"; + break; + default: + codec = "msmpeg4"; + break; + } + snprintf(cnt->motionfilename, PATH_MAX - 4, "%s/%s_%sm", cnt->conf.filepath, codec, stamp); + snprintf(cnt->newfilename, PATH_MAX - 4, "%s/%s_%s", cnt->conf.filepath, codec, stamp); + } else { + snprintf(cnt->motionfilename, PATH_MAX - 4, "%s/%sm", cnt->conf.filepath, stamp); + snprintf(cnt->newfilename, PATH_MAX - 4, "%s/%s", cnt->conf.filepath, stamp); + } if (cnt->conf.ffmpeg_output) { if (cnt->imgs.type == VIDEO_PALETTE_GREY) { convbuf = mymalloc((width * height) / 2); @@ -583,9 +700,9 @@ static void event_ffmpeg_newfile(struct context *cnt, int type ATTRIBUTE_UNUSED, } if ((cnt->ffmpeg_output = - ffmpeg_open((char *)cnt->conf.ffmpeg_video_codec, cnt->newfilename, y, u, v, + ffmpeg_open(codec, cnt->newfilename, y, u, v, cnt->imgs.width, cnt->imgs.height, cnt->movie_fps, cnt->conf.ffmpeg_bps, - cnt->conf.ffmpeg_vbr)) == NULL) { + cnt->conf.ffmpeg_vbr,TIMELAPSE_NONE)) == NULL) { MOTION_LOG(ERR, TYPE_EVENTS, SHOW_ERRNO, "%s: ffopen_open error creating (new) file [%s]", cnt->newfilename); cnt->finish = 1; @@ -611,9 +728,9 @@ static void event_ffmpeg_newfile(struct context *cnt, int type ATTRIBUTE_UNUSED, } if ((cnt->ffmpeg_output_debug = - ffmpeg_open((char *)cnt->conf.ffmpeg_video_codec, cnt->motionfilename, y, u, v, - cnt->imgs.width, cnt->imgs.height, cnt->movie_fps, cnt->conf.ffmpeg_bps, - cnt->conf.ffmpeg_vbr)) == NULL) { + ffmpeg_open(codec, cnt->motionfilename, y, u, v, + cnt->imgs.width, cnt->imgs.height, cnt->movie_fps, cnt->conf.ffmpeg_bps, + cnt->conf.ffmpeg_vbr,TIMELAPSE_NONE)) == NULL) { MOTION_LOG(ERR, TYPE_EVENTS, SHOW_ERRNO, "%s: ffopen_open error creating (motion) file [%s]", cnt->motionfilename); cnt->finish = 1; @@ -626,7 +743,7 @@ static void event_ffmpeg_newfile(struct context *cnt, int type ATTRIBUTE_UNUSED, } static void event_ffmpeg_timelapse(struct context *cnt, - int type ATTRIBUTE_UNUSED, unsigned char *img, + motion_event type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) { @@ -637,6 +754,8 @@ static void event_ffmpeg_timelapse(struct context *cnt, if (!cnt->ffmpeg_timelapse) { char tmp[PATH_MAX]; const char *timepath; + const char *codec_mpg = "mpg"; + const char *codec_mpeg = "mpeg4"; /* * conf.timepath would normally be defined but if someone deleted it by control interface @@ -665,10 +784,30 @@ static void event_ffmpeg_timelapse(struct context *cnt, v = u + (width * height) / 4; } - if ((cnt->ffmpeg_timelapse = - ffmpeg_open((char *)TIMELAPSE_CODEC, cnt->timelapsefilename, y, u, v, - cnt->imgs.width, cnt->imgs.height, 24, cnt->conf.ffmpeg_bps, - cnt->conf.ffmpeg_vbr)) == NULL) { + + if ((strcmp(cnt->conf.ffmpeg_video_codec,"mpg") == 0) || + (strcmp(cnt->conf.ffmpeg_video_codec,"swf") == 0) ){ + + if (strcmp(cnt->conf.ffmpeg_video_codec,"swf") == 0) { + MOTION_LOG(WRN, TYPE_EVENTS, NO_ERRNO, "%s: The swf container for timelapse no longer supported. Using mpg container."); + } + + MOTION_LOG(NTC, TYPE_EVENTS, NO_ERRNO, "%s: Timelapse using mpg codec."); + MOTION_LOG(NTC, TYPE_EVENTS, NO_ERRNO, "%s: Events will be appended to file"); + cnt->ffmpeg_timelapse = + ffmpeg_open(codec_mpg,cnt->timelapsefilename, y, u, v + ,cnt->imgs.width, cnt->imgs.height, cnt->conf.frame_limit + ,cnt->conf.ffmpeg_bps,cnt->conf.ffmpeg_vbr,TIMELAPSE_APPEND); + } else { + MOTION_LOG(NTC, TYPE_EVENTS, NO_ERRNO, "%s: Timelapse using mpeg4 codec."); + MOTION_LOG(NTC, TYPE_EVENTS, NO_ERRNO, "%s: Events will be trigger new files"); + cnt->ffmpeg_timelapse = + ffmpeg_open(codec_mpeg ,cnt->timelapsefilename, y, u, v + ,cnt->imgs.width, cnt->imgs.height, cnt->conf.frame_limit + ,cnt->conf.ffmpeg_bps,cnt->conf.ffmpeg_vbr,TIMELAPSE_NEW); + } + + if (cnt->ffmpeg_timelapse == NULL){ MOTION_LOG(ERR, TYPE_EVENTS, SHOW_ERRNO, "%s: ffopen_open error creating " "(timelapse) file [%s]", cnt->timelapsefilename); cnt->finish = 1; @@ -695,7 +834,8 @@ static void event_ffmpeg_timelapse(struct context *cnt, } -static void event_ffmpeg_put(struct context *cnt, int type ATTRIBUTE_UNUSED, +static void event_ffmpeg_put(struct context *cnt, + motion_event type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { @@ -706,11 +846,12 @@ static void event_ffmpeg_put(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *u, *v; if (cnt->imgs.type == VIDEO_PALETTE_GREY) - u = cnt->ffmpeg_timelapse->udata; + u = cnt->ffmpeg_output->udata; else u = y + (width * height); v = u + (width * height) / 4; + if (ffmpeg_put_other_image(cnt->ffmpeg_output, y, u, v) == -1) { cnt->finish = 1; cnt->restart = 0; @@ -726,14 +867,14 @@ static void event_ffmpeg_put(struct context *cnt, int type ATTRIBUTE_UNUSED, } static void event_ffmpeg_closefile(struct context *cnt, - int type ATTRIBUTE_UNUSED, unsigned char *dummy1 ATTRIBUTE_UNUSED, + motion_event type ATTRIBUTE_UNUSED, + unsigned char *dummy1 ATTRIBUTE_UNUSED, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { if (cnt->ffmpeg_output) { - if (cnt->ffmpeg_output->udata) - free(cnt->ffmpeg_output->udata); + free(cnt->ffmpeg_output->udata); ffmpeg_close(cnt->ffmpeg_output); cnt->ffmpeg_output = NULL; @@ -742,8 +883,7 @@ static void event_ffmpeg_closefile(struct context *cnt, } if (cnt->ffmpeg_output_debug) { - if (cnt->ffmpeg_output_debug->udata) - free(cnt->ffmpeg_output_debug->udata); + free(cnt->ffmpeg_output_debug->udata); ffmpeg_close(cnt->ffmpeg_output_debug); cnt->ffmpeg_output_debug = NULL; @@ -753,13 +893,13 @@ static void event_ffmpeg_closefile(struct context *cnt, } static void event_ffmpeg_timelapseend(struct context *cnt, - int type ATTRIBUTE_UNUSED, unsigned char *dummy1 ATTRIBUTE_UNUSED, + motion_event type ATTRIBUTE_UNUSED, + unsigned char *dummy1 ATTRIBUTE_UNUSED, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { if (cnt->ffmpeg_timelapse) { - if (cnt->ffmpeg_timelapse->udata) - free(cnt->ffmpeg_timelapse->udata); + free(cnt->ffmpeg_timelapse->udata); ffmpeg_close(cnt->ffmpeg_timelapse); cnt->ffmpeg_timelapse = NULL; @@ -776,7 +916,7 @@ static void event_ffmpeg_timelapseend(struct context *cnt, */ struct event_handlers { - int type; + motion_event type; event_handler handler; }; @@ -921,12 +1061,14 @@ struct event_handlers event_handlers[] = { * The split between unsigned images and signed filenames was introduced in 3.2.2 * as a code reading friendly solution to avoid a stream of compiler warnings in gcc 4.0. */ -void event(struct context *cnt, int type, unsigned char *image, char *filename, void *eventdata, struct tm *tm) +void event(struct context *cnt, motion_event type, unsigned char *image, + char *filename, void *eventdata, struct tm *tm) { int i=-1; while (event_handlers[++i].handler) { if (type == event_handlers[i].type) - event_handlers[i].handler(cnt, type, image, filename, eventdata, tm); + event_handlers[i].handler(cnt, type, image, filename, eventdata, + tm); } } diff --git a/event.h b/event.h index d226566..50ee69f 100644 --- a/event.h +++ b/event.h @@ -11,31 +11,36 @@ #ifndef _INCLUDE_EVENT_H_ #define _INCLUDE_EVENT_H_ -#define EVENT_FILECREATE 1 -#define EVENT_MOTION 2 -#define EVENT_FIRSTMOTION 3 -#define EVENT_ENDMOTION 4 -#define EVENT_STOP 5 -#define EVENT_TIMELAPSE 6 -#define EVENT_TIMELAPSEEND 7 -#define EVENT_STREAM 8 -#define EVENT_IMAGE_DETECTED 9 -#define EVENT_IMAGEM_DETECTED 10 -#define EVENT_IMAGE_SNAPSHOT 11 -#define EVENT_IMAGE 12 -#define EVENT_IMAGEM 13 -#define EVENT_FILECLOSE 14 -#define EVENT_DEBUG 15 -#define EVENT_CRITICAL 16 -#define EVENT_AREA_DETECTED 17 -#define EVENT_CAMERA_LOST 18 -#define EVENT_FFMPEG_PUT 19 -#define EVENT_SDL_PUT 20 +typedef enum { + EVENT_FILECREATE = 1, + EVENT_MOTION, + EVENT_FIRSTMOTION, + EVENT_ENDMOTION, + EVENT_STOP, + EVENT_TIMELAPSE, + EVENT_TIMELAPSEEND, + EVENT_STREAM, + EVENT_IMAGE_DETECTED, + EVENT_IMAGEM_DETECTED, + EVENT_IMAGE_SNAPSHOT, + EVENT_IMAGE, + EVENT_IMAGEM, + EVENT_FILECLOSE, + EVENT_DEBUG, + EVENT_CRITICAL, + EVENT_AREA_DETECTED, + EVENT_CAMERA_LOST, + EVENT_FFMPEG_PUT, + EVENT_SDL_PUT, + EVENT_LAST, +} motion_event; -typedef void(* event_handler)(struct context *, int, unsigned char *, char *, void *, struct tm *); +typedef void(* event_handler)(struct context *, motion_event, unsigned char *, + char *, void *, struct tm *); -void event(struct context *, int, unsigned char *, char *, void *, struct tm *); +void event(struct context *, motion_event, unsigned char *, char *, void *, + struct tm *); const char * imageext(struct context *); #endif /* _INCLUDE_EVENT_H_ */ diff --git a/ffmpeg.c b/ffmpeg.c index 57eeda4..6c94ab3 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -8,269 +8,179 @@ * The contents of this file has been derived from output_example.c * and apiexample.c from the FFmpeg distribution. * - */ + * This file has been modified so that only major versions greater than + * 53 are supported. + * Note that while the conditions are based upon LIBAVFORMAT, not all of the changes are + * specific to libavformat.h. Some changes could be related to other components of ffmpeg. + * This is for simplicity. The avformat version has historically changed at the same time + * as the other components so it is easier to have a single version number to track rather + * than the particular version numbers which are associated with each component. + * The libav variant also has different apis with the same major/minor version numbers. + * As such, it is occasionally necessary to look at the microversion number. Numbers + * greater than 100 for micro version indicate ffmpeg whereas numbers less than 100 + * indicate libav +*/ + + +#include "config.h" #ifdef HAVE_FFMPEG #include "ffmpeg.h" #include "motion.h" -#if LIBAVCODEC_BUILD > 4680 -/* - * FFmpeg after build 4680 doesn't have support for mpeg1 videos with - * non-standard framerates. Previous builds contained a broken hack - * that padded with B frames to obtain the correct framerate. - */ -# define FFMPEG_NO_NONSTD_MPEG1 -# ifdef __GNUC__ -/* #warning is a non-standard gcc extension */ -# warning ************************************************** -# warning Your version of FFmpeg is newer than version 0.4.8 -# warning Newer versions of ffmpeg do not support MPEG1 with -# warning non-standard framerate. MPEG1 will be disabled for -# warning normal video output. You can still use mpeg4 and -# warning and mpeg4ms which are both better in terms of size -# warning and quality. MPEG1 is always used for timelapse. -# warning Please read the Motion Guide for more information. -# warning Note that this is not an error message! -# warning ************************************************** -# endif /* __GNUC__ */ -#endif /* LIBAVCODEC_BUILD > 4680 */ - -#if defined LIBAVFORMAT_VERSION_MAJOR && defined LIBAVFORMAT_VERSION_MINOR -# if LIBAVFORMAT_VERSION_MAJOR < 53 && LIBAVFORMAT_VERSION_MINOR < 45 -# define GUESS_NO_DEPRECATED -# endif -#endif +#define AVSTREAM_CODEC_PTR(avs_ptr) (avs_ptr->codec) -#if LIBAVFORMAT_BUILD >= 4616 -/* - * The API for av_write_frame changed with FFmpeg version 0.4.9pre1. - * It now uses an AVPacket struct instead of direct parameters to the - * function. - */ -# define FFMPEG_AVWRITEFRAME_NEWAPI -#endif /* LIBAVFORMAT_BUILD >= 4616 */ -#if LIBAVFORMAT_BUILD >= 4629 -/* - * In this build/header version, the codec member of struct AVStream - * was changed to a pointer so changes to AVCodecContext shouldn't - * break binary compatibility with AVStream. - */ -# define AVSTREAM_CODEC_PTR(avs_ptr) (avs_ptr->codec) -#else -# define AVSTREAM_CODEC_PTR(avs_ptr) (&avs_ptr->codec) -#endif /* LIBAVFORMAT_BUILD >= 4629 */ - -// AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c) -// (54*2^16 | 6*2^8 | 100) -#if LIBAVFORMAT_BUILD >= 3540580 -#define FF_API_NEW_AVIO -#define URL_RDONLY AVIO_FLAG_READ /**< read-only */ -#define URL_WRONLY AVIO_FLAG_WRITE /**< write-only */ -#define URL_RDWR AVIO_FLAG_READ_WRITE /**< read-write pseudo flag */ -#endif +/**************************************************************************** + * The section below is the "my" section of functions. + * These are designed to be extremely simple version specific + * variants of the libav functions. + ****************************************************************************/ +#if (LIBAVFORMAT_VERSION_MAJOR >= 55) || ((LIBAVFORMAT_VERSION_MAJOR == 54) && (LIBAVFORMAT_VERSION_MINOR > 6)) +#define MY_FLAG_READ AVIO_FLAG_READ +#define MY_FLAG_WRITE AVIO_FLAG_WRITE +#define MY_FLAG_READ_WRITE AVIO_FLAG_READ_WRITE -/* - * Name of custom file protocol for appending to existing files instead - * of truncating. - */ -#define APPEND_PROTO "appfile" - -/* Some forward-declarations. */ -int ffmpeg_put_frame(struct ffmpeg *, AVFrame *); -void ffmpeg_cleanups(struct ffmpeg *); -AVFrame *ffmpeg_prepare_frame(struct ffmpeg *, unsigned char *, - unsigned char *, unsigned char *); +#else //Older versions -/* This is the trailer used to end mpeg1 videos. */ -static unsigned char mpeg1_trailer[] = {0x00, 0x00, 0x01, 0xb7}; +#define MY_FLAG_READ URL_RDONLY +#define MY_FLAG_WRITE URL_WRONLY +#define MY_FLAG_READ_WRITE URL_RDWR +#endif +/*********************************************/ +#if (LIBAVFORMAT_VERSION_MAJOR >= 56) -// FFMPEG API changed in 0.8 -#if defined FF_API_NEW_AVIO - -// TODO +#define MY_CODEC_ID_MSMPEG4V2 AV_CODEC_ID_MSMPEG4V2 +#define MY_CODEC_ID_FLV1 AV_CODEC_ID_FLV1 +#define MY_CODEC_ID_FFV1 AV_CODEC_ID_FFV1 +#define MY_CODEC_ID_NONE AV_CODEC_ID_NONE +#define MY_CODEC_ID_MPEG2VIDEO AV_CODEC_ID_MPEG2VIDEO +#define MY_CODEC_ID_H264 AV_CODEC_ID_H264 +#define MY_CODEC_ID_HEVC AV_CODEC_ID_HEVC - #else -/** - * file_open_append - * Append version of the file open function used in libavformat when opening - * an ordinary file. The original file open function truncates an existing - * file, but this version appends to it instead. - * - * Returns 0 on success and AVERROR(ENOENT) on error. - * - */ -static int file_open_append(URLContext *h, const char *filename, int flags) -{ - const char *colon; - const char *mode; - FILE *fh; - size_t bufsize = 0; - - /* Skip past the protocol part of filename. */ - colon = strchr(filename, ':'); - - if (colon) - filename = colon + 1; - - - if (flags & URL_RDWR) { - mode = "ab+"; - bufsize = BUFSIZE_1MEG; - } else if (flags & URL_WRONLY) { - mode = "ab"; - bufsize = BUFSIZE_1MEG; - } else { - mode = "rb"; - } - - fh = myfopen(filename, mode, bufsize); - if (fh == NULL) - return AVERROR(ENOENT); +#define MY_CODEC_ID_MSMPEG4V2 CODEC_ID_MSMPEG4V2 +#define MY_CODEC_ID_FLV1 CODEC_ID_FLV1 +#define MY_CODEC_ID_FFV1 CODEC_ID_FFV1 +#define MY_CODEC_ID_NONE CODEC_ID_NONE +#define MY_CODEC_ID_MPEG2VIDEO CODEC_ID_MPEG2VIDEO +#define MY_CODEC_ID_H264 CODEC_ID_H264 +#define MY_CODEC_ID_HEVC CODEC_ID_H264 - h->priv_data = (void *)fh; - return 0; +#endif +/*********************************************/ +AVFrame *my_frame_alloc(void){ + AVFrame *pic; +#if (LIBAVFORMAT_VERSION_MAJOR >= 55) + pic = av_frame_alloc(); +#else + pic = avcodec_alloc_frame(); +#endif + return pic; } - -/* - * URLProtocol entry for the append file protocol, which we use for mpeg1 videos - * in order to get append behavior with url_fopen. - * - * Libavformat uses protocols for achieving flexibility when handling files - * and other resources. A call to url_fopen will eventually be redirected to - * a protocol-specific open function. - * - * The remaining functions (for writing, seeking etc.) are set in ffmpeg_init. - */ -URLProtocol mpeg1_file_protocol = { - .name = APPEND_PROTO, - .url_open = file_open_append -}; - - -#ifdef HAVE_FFMPEG_NEW - -/* file_procotol has been removed from avio.h */ -#ifdef FFMPEG_NEW_INCLUDES -#include +/*********************************************/ +void my_frame_free(AVFrame *frame){ +#if (LIBAVFORMAT_VERSION_MAJOR >= 55) + av_frame_free(&frame); #else -#include "avstring.h" + av_freep(&frame); #endif - -/** - * file_open - * - */ -static int file_open(URLContext *h, const char *filename, int flags) -{ - const char *mode; - FILE *fh; - size_t bufsize = 0; - - av_strstart(filename, "file:", &filename); - - if (flags & URL_RDWR) { - mode = "wb+"; - bufsize = BUFSIZE_1MEG; - } else if (flags & URL_WRONLY) { - mode = "wb"; - bufsize = BUFSIZE_1MEG; - } else { - mode = "rb"; - } - fh = myfopen(filename, mode, bufsize); - if (fh == NULL) - return AVERROR(ENOENT); - h->priv_data = (void *)fh; - return 0; } - -/** - * file_read - */ -static int file_read(URLContext *h, unsigned char *buf, int size) -{ - FILE *fh = (FILE *)h->priv_data; - return fread(buf, 1, size, fh); +/*********************************************/ +int my_image_get_buffer_size(enum MyPixelFormat pix_fmt, int width, int height){ + int retcd = 0; +#if (LIBAVFORMAT_VERSION_MAJOR >= 57) + int align = 1; + retcd = av_image_get_buffer_size(pix_fmt, width, height, align); +#else + retcd = avpicture_get_size(pix_fmt, width, height); +#endif + return retcd; } - -/** - * file_write - */ -static int file_write(URLContext *h, unsigned char *buf, int size) -{ - FILE *fh = (FILE *)h->priv_data; - return fwrite(buf, 1, size, fh); +/*********************************************/ +int my_image_copy_to_buffer(AVFrame *frame, uint8_t *buffer_ptr, enum MyPixelFormat pix_fmt,int width, int height,int dest_size){ + int retcd = 0; +#if (LIBAVFORMAT_VERSION_MAJOR >= 57) + int align = 1; + retcd = av_image_copy_to_buffer((uint8_t *)buffer_ptr,dest_size + ,(const uint8_t * const*)frame,frame->linesize,pix_fmt,width,height,align); +#else + retcd = avpicture_layout((const AVPicture*)frame,pix_fmt,width,height + ,(unsigned char *)buffer_ptr,dest_size); +#endif + return retcd; } - -/** - * file_seek - */ -static int64_t file_seek(URLContext *h, int64_t pos, int whence) -{ - FILE *fh = (FILE *)h->priv_data; - if (fseek(fh, pos, whence)) - return -1; - return ftell(fh); +/*********************************************/ +int my_image_fill_arrays(AVFrame *frame,uint8_t *buffer_ptr,enum MyPixelFormat pix_fmt,int width,int height){ + int retcd = 0; +#if (LIBAVFORMAT_VERSION_MAJOR >= 57) + int align = 1; + retcd = av_image_fill_arrays( + frame->data + ,frame->linesize + ,buffer_ptr + ,pix_fmt + ,width + ,height + ,align + ); +#else + retcd = avpicture_fill( + (AVPicture *)frame + ,buffer_ptr + ,pix_fmt + ,width + ,height); +#endif + return retcd; } +/*********************************************/ +void my_packet_unref(AVPacket pkt){ +#if (LIBAVFORMAT_VERSION_MAJOR >= 57) + av_packet_unref(&pkt); +#else + av_free_packet(&pkt); +#endif +} +/*********************************************/ +/**************************************************************************** + **************************************************************************** + ****************************************************************************/ /** - * file_close + * timelapse_exists + * Determines whether the timelapse file exists + * + * Returns + * 0: File doesn't exist + * 1: File exists */ -static int file_close(URLContext *h) -{ - FILE *fh = (FILE *)h->priv_data; - return myfclose(fh); +static int timelapse_exists(const char *fname){ + FILE *file; + file = fopen(fname, "r"); + if (file) + { + fclose(file); + return 1; + } + return 0; } +static int timelapse_append(struct ffmpeg *ffmpeg, AVPacket pkt){ + FILE *file; -URLProtocol file_protocol = { - "file", - file_open, - file_read, - file_write, - file_seek, - file_close, -#if LIBAVFORMAT_BUILD >= (52<<16 | 31<<8) - NULL, - NULL, - NULL, -#endif -}; + file = fopen(ffmpeg->oc->filename, "a"); + if (!file) return -1; -#endif // HAVE_FFMPEG_NEW + fwrite(pkt.data,1,pkt.size,file); -#endif // FF_API_NEW_AVIO + fclose(file); -/** - * mpeg1_write_trailer - * We set AVOutputFormat->write_trailer to this function for mpeg1. That way, - * the mpeg1 video gets a proper trailer when it is closed. - * - * Returns 0 - * - */ -static int mpeg1_write_trailer(AVFormatContext *s) -{ -#if defined FF_API_NEW_AVIO - avio_write(s->pb, mpeg1_trailer, 4); - avio_flush(s->pb); -#elif LIBAVFORMAT_BUILD >= (52<<16) - put_buffer(s->pb, mpeg1_trailer, 4); - put_flush_packet(s->pb); -#else - put_buffer(&s->pb, mpeg1_trailer, 4); - put_flush_packet(&s->pb); -#endif /* FF_API_NEW_AVIO -- LIBAVFORMAT_BUILD >= (52<<16) */ - - return 0; /* success */ + return 0; } - /** * ffmpeg_init * Initializes for libavformat. @@ -278,42 +188,17 @@ static int mpeg1_write_trailer(AVFormatContext *s) * Returns * Function returns nothing. */ -void ffmpeg_init() -{ - MOTION_LOG(NTC, TYPE_ENCODER, NO_ERRNO, "%s: ffmpeg LIBAVCODEC_BUILD %d" - " LIBAVFORMAT_BUILD %d", LIBAVCODEC_BUILD, - LIBAVFORMAT_BUILD); - av_register_all(); +void ffmpeg_init(){ + MOTION_LOG(NTC, TYPE_ENCODER, NO_ERRNO, + "%s: ffmpeg libavcodec version %d.%d.%d" + " libavformat version %d.%d.%d" + , LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO + , LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO); -#if LIBAVCODEC_BUILD > 4680 + av_register_all(); + avcodec_register_all(); av_log_set_callback((void *)ffmpeg_avcodec_log); - av_log_set_level(AV_LOG_ERROR); -#endif - -#if defined FF_API_NEW_AVIO -#else - /* - * Copy the functions to use for the append file protocol from the standard - * file protocol. - */ - mpeg1_file_protocol.url_read = file_protocol.url_read; - mpeg1_file_protocol.url_write = file_protocol.url_write; - mpeg1_file_protocol.url_seek = file_protocol.url_seek; - mpeg1_file_protocol.url_close = file_protocol.url_close; - -/* Register the append file protocol. */ -#ifdef have_av_register_protocol2 - av_register_protocol2(&mpeg1_file_protocol, sizeof(mpeg1_file_protocol)); -#elif defined have_av_register_protocol - av_register_protocol(&mpeg1_file_protocol); -#else -# warning av_register_protocolXXX missing -#endif - -#endif // FF_API_NEW_AVIO - } - /** * get_oformat * Obtains the output format used for the specified codec. For mpeg4 codecs, @@ -323,104 +208,52 @@ void ffmpeg_init() * Returns * AVOutputFormat pointer or NULL if any error happens. */ -static AVOutputFormat *get_oformat(const char *codec, char *filename) -{ +static AVOutputFormat *get_oformat(const char *codec, char *filename){ const char *ext; AVOutputFormat *of = NULL; /* * Here, we use guess_format to automatically setup the codec information. * If we are using msmpeg4, manually set that codec here. - * We also dynamically add the file extension to the filename here. This was - * done to support both mpeg1 and mpeg4 codecs since they have different extensions. + * We also dynamically add the file extension to the filename here. */ - if ((strcmp(codec, TIMELAPSE_CODEC) == 0) -#ifndef FFMPEG_NO_NONSTD_MPEG1 - || (strcmp(codec, "mpeg1") == 0) -#endif - ) { + if (strcmp(codec, "tlapse") == 0) { ext = ".mpg"; - /* - * We use "mpeg1video" for raw mpeg1 format. Using "mpeg" would - * result in a muxed output file, which isn't appropriate here. - */ -#ifdef GUESS_NO_DEPRECATED - of = guess_format("mpeg1video", NULL, NULL); -#else - of = av_guess_format("mpeg1video", NULL, NULL); -#endif - /* But we want the trailer to be correctly written. */ - if (of) - of->write_trailer = mpeg1_write_trailer; - -#ifdef FFMPEG_NO_NONSTD_MPEG1 - } else if (strcmp(codec, "mpeg1") == 0) { - MOTION_LOG(WRN, TYPE_ENCODER, NO_ERRNO, "%s: *** mpeg1 support for normal" - " videos has been disabled ***"); - return NULL; -#endif + of = av_guess_format ("mpeg2video", NULL, NULL); + if (of) of->video_codec = MY_CODEC_ID_MPEG2VIDEO; } else if (strcmp(codec, "mpeg4") == 0) { ext = ".avi"; -#ifdef GUESS_NO_DEPRECATED - of = guess_format("mpeg1video", NULL, NULL); -#else of = av_guess_format("avi", NULL, NULL); -#endif } else if (strcmp(codec, "msmpeg4") == 0) { ext = ".avi"; -#ifdef GUESS_NO_DEPRECATED - of = guess_format("mpeg1video", NULL, NULL); -#else of = av_guess_format("avi", NULL, NULL); -#endif /* Manually override the codec id. */ - if (of) - of->video_codec = CODEC_ID_MSMPEG4V2; - + if (of) of->video_codec = MY_CODEC_ID_MSMPEG4V2; } else if (strcmp(codec, "swf") == 0) { ext = ".swf"; -#ifdef GUESS_NO_DEPRECATED - of = guess_format("mpeg1video", NULL, NULL); -#else of = av_guess_format("swf", NULL, NULL); -#endif } else if (strcmp(codec, "flv") == 0) { ext = ".flv"; -#ifdef GUESS_NO_DEPRECATED - of = guess_format("mpeg1video", NULL, NULL); -#else of = av_guess_format("flv", NULL, NULL); -#endif - of->video_codec = CODEC_ID_FLV1; + of->video_codec = MY_CODEC_ID_FLV1; } else if (strcmp(codec, "ffv1") == 0) { ext = ".avi"; -#ifdef GUESS_NO_DEPRECATED - of = guess_format("mpeg1video", NULL, NULL); -#else of = av_guess_format("avi", NULL, NULL); -#endif - /* - * Use the FFMPEG Lossless Video codec (experimental!). - * Requires strict_std_compliance to be <= -2 - */ - if (of) - of->video_codec = CODEC_ID_FFV1; - + if (of) of->video_codec = MY_CODEC_ID_FFV1; } else if (strcmp(codec, "mov") == 0) { ext = ".mov"; -#ifdef GUESS_NO_DEPRECATED - of = guess_format("mpeg1video", NULL, NULL); -#else of = av_guess_format("mov", NULL, NULL); -#endif - } - else if (strcmp (codec, "ogg") == 0) - { - ext = ".ogg"; -#ifdef GUESS_NO_DEPRECATED - of = guess_format ("ogg", NULL, NULL); -#else - of = av_guess_format ("ogg", NULL, NULL); -#endif + } else if (strcmp (codec, "mp4") == 0){ + ext = ".mp4"; + of = av_guess_format ("mp4", NULL, NULL); + of->video_codec = MY_CODEC_ID_H264; + } else if (strcmp (codec, "mkv") == 0){ + ext = ".mkv"; + of = av_guess_format ("matroska", NULL, NULL); + of->video_codec = MY_CODEC_ID_H264; + } else if (strcmp (codec, "hevc") == 0){ + ext = ".mp4"; + of = av_guess_format ("mp4", NULL, NULL); + of->video_codec = MY_CODEC_ID_HEVC; } else { MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: ffmpeg_video_codec option value" " %s is not supported", codec); @@ -428,8 +261,7 @@ static AVOutputFormat *get_oformat(const char *codec, char *filename) } if (!of) { - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Could not guess format for %s", - codec); + MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Could not guess format for %s", codec); return NULL; } @@ -438,7 +270,6 @@ static AVOutputFormat *get_oformat(const char *codec, char *filename) return of; } - /** * ffmpeg_open * Opens an mpeg file using the new libavformat method. Both mpeg1 @@ -449,47 +280,43 @@ static AVOutputFormat *get_oformat(const char *codec, char *filename) * Returns * A new allocated ffmpeg struct or NULL if any error happens. */ -struct ffmpeg *ffmpeg_open(char *ffmpeg_video_codec, char *filename, +struct ffmpeg *ffmpeg_open(const char *ffmpeg_video_codec, char *filename, unsigned char *y, unsigned char *u, unsigned char *v, - int width, int height, int rate, int bps, int vbr) + int width, int height, int rate, int bps, int vbr, int tlapse) { AVCodecContext *c; AVCodec *codec; struct ffmpeg *ffmpeg; - int is_mpeg1; - int ret; + int retcd; + char errstr[128]; + AVDictionary *opts = 0; + /* * Allocate space for our ffmpeg structure. This structure contains all the * codec and image information we need to generate movies. - * FIXME when motion exits we should close the movie to ensure that - * ffmpeg is freed. */ ffmpeg = mymalloc(sizeof(struct ffmpeg)); - memset(ffmpeg, 0, sizeof(struct ffmpeg)); - ffmpeg->vbr = vbr; + ffmpeg->tlapse = tlapse; /* Store codec name in ffmpeg->codec, with buffer overflow check. */ snprintf(ffmpeg->codec, sizeof(ffmpeg->codec), "%s", ffmpeg_video_codec); /* Allocation the output media context. */ -#ifdef have_avformat_alloc_context ffmpeg->oc = avformat_alloc_context(); -#elif defined have_av_avformat_alloc_context - ffmpeg->oc = av_alloc_format_context(); -#else - ffmpeg->oc = av_mallocz(sizeof(AVFormatContext)); -#endif if (!ffmpeg->oc) { - MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Memory error while allocating" - " output media context"); + MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Could not allocate output context"); ffmpeg_cleanups(ffmpeg); return NULL; } /* Setup output format */ - ffmpeg->oc->oformat = get_oformat(ffmpeg_video_codec, filename); + if (ffmpeg->tlapse == TIMELAPSE_APPEND){ + ffmpeg->oc->oformat = get_oformat("tlapse", filename); + } else { + ffmpeg->oc->oformat = get_oformat(ffmpeg_video_codec, filename); + } if (!ffmpeg->oc->oformat) { ffmpeg_cleanups(ffmpeg); return NULL; @@ -497,155 +324,136 @@ struct ffmpeg *ffmpeg_open(char *ffmpeg_video_codec, char *filename, snprintf(ffmpeg->oc->filename, sizeof(ffmpeg->oc->filename), "%s", filename); - /* Create a new video stream and initialize the codecs. */ ffmpeg->video_st = NULL; - if (ffmpeg->oc->oformat->video_codec != CODEC_ID_NONE) { -#if defined FF_API_NEW_AVIO - ffmpeg->video_st = avformat_new_stream(ffmpeg->oc, NULL /* Codec */); -#else - ffmpeg->video_st = av_new_stream(ffmpeg->oc, 0); -#endif + if (ffmpeg->oc->oformat->video_codec != MY_CODEC_ID_NONE) { + + codec = avcodec_find_encoder(ffmpeg->oc->oformat->video_codec); + if (!codec) { + MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Codec %s not found", ffmpeg_video_codec); + ffmpeg_cleanups(ffmpeg); + return NULL; + } + + ffmpeg->video_st = avformat_new_stream(ffmpeg->oc, codec); if (!ffmpeg->video_st) { - MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: av_new_stream - could" - " not alloc stream"); + MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Could not alloc stream"); ffmpeg_cleanups(ffmpeg); return NULL; } } else { /* We did not get a proper video codec. */ - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Failed to obtain a proper" - " video codec"); + MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Could not get the codec"); + ffmpeg_cleanups(ffmpeg); + return NULL; + } + + /* Only the newer codec and containers can handle the really fast FPS */ + if (((strcmp(ffmpeg_video_codec, "msmpeg4") == 0) || + (strcmp(ffmpeg_video_codec, "mpeg4") == 0) || + (strcmp(ffmpeg_video_codec, "swf") == 0) ) && (rate >100)){ + MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s The frame rate specified is too high for the ffmpeg movie type specified. Choose a different ffmpeg container or lower framerate. "); ffmpeg_cleanups(ffmpeg); return NULL; } ffmpeg->c = c = AVSTREAM_CODEC_PTR(ffmpeg->video_st); c->codec_id = ffmpeg->oc->oformat->video_codec; -#if LIBAVCODEC_VERSION_MAJOR < 53 - c->codec_type = CODEC_TYPE_VIDEO; -#else c->codec_type = AVMEDIA_TYPE_VIDEO; -#endif - is_mpeg1 = c->codec_id == CODEC_ID_MPEG1VIDEO; - - if (strcmp(ffmpeg_video_codec, "ffv1") == 0) - c->strict_std_compliance = -2; - - /* Uncomment to allow non-standard framerates. */ - //c->strict_std_compliance = -1; - - /* Set default parameters */ - c->bit_rate = bps; - c->width = width; - c->height = height; -#if LIBAVCODEC_BUILD >= 4754 - /* Frame rate = 1/time_base, so we set 1/rate, not rate/1 */ + c->bit_rate = bps; + c->width = width; + c->height = height; c->time_base.num = 1; c->time_base.den = rate; -#else - c->frame_rate = rate; - c->frame_rate_base = 1; -#endif /* LIBAVCODEC_BUILD >= 4754 */ - - MOTION_LOG(INF, TYPE_ENCODER, NO_ERRNO, "%s FPS %d", - rate); - - if (vbr) - c->flags |= CODEC_FLAG_QSCALE; - - /* - * Set codec specific parameters. - * Set intra frame distance in frames depending on codec. - */ - c->gop_size = is_mpeg1 ? 10 : 12; - - /* Some formats want stream headers to be separate. */ - if (!strcmp(ffmpeg->oc->oformat->name, "mp4") || - !strcmp(ffmpeg->oc->oformat->name, "mov") || - !strcmp(ffmpeg->oc->oformat->name, "3gp")) { - c->flags |= CODEC_FLAG_GLOBAL_HEADER; - } - -#if defined FF_API_NEW_AVIO -// pass the options to avformat_write_header directly -#else - /* Set the output parameters (must be done even if no parameters). */ - if (av_set_parameters(ffmpeg->oc, NULL) < 0) { - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: av_set_parameters error:" - " Invalid output format parameters"); - ffmpeg_cleanups(ffmpeg); - return NULL; + c->gop_size = 12; + c->pix_fmt = MY_PIX_FMT_YUV420P; + c->max_b_frames = 0; + + /* The selection of 8000 in the else is a subjective number based upon viewing output files */ + if (vbr > 0){ + if (vbr > 100) vbr = 100; + if (c->codec_id == MY_CODEC_ID_H264 || + c->codec_id == MY_CODEC_ID_HEVC){ + ffmpeg->vbr = (int)(( (100-vbr) * 51)/100); + } else { + ffmpeg->vbr =(int)(((100-vbr)*(100-vbr)*(100-vbr) * 8000) / 1000000) + 1; + } + } else { + ffmpeg->vbr = 0; } -#endif + MOTION_LOG(INF, TYPE_ENCODER, NO_ERRNO, "%s vbr/crf for codec: %d", ffmpeg->vbr); - /* Dump the format settings. This shows how the various streams relate to each other. */ - //dump_format(ffmpeg->oc, 0, filename, 1); + if (c->codec_id == MY_CODEC_ID_H264 || + c->codec_id == MY_CODEC_ID_HEVC){ + av_dict_set(&opts, "preset", "ultrafast", 0); - /* - * Now that all the parameters are set, we can open the video - * codec and allocate the necessary encode buffers. - */ - codec = avcodec_find_encoder(c->codec_id); - - if (!codec) { - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Codec %s not found", - ffmpeg_video_codec); - ffmpeg_cleanups(ffmpeg); - return NULL; + char crf[4]; + snprintf(crf, 4, "%d",ffmpeg->vbr); + av_dict_set(&opts, "crf", crf, 0); + av_dict_set(&opts, "tune", "zerolatency", 0); + } else { + if (ffmpeg->vbr) c->flags |= CODEC_FLAG_QSCALE; + c->global_quality=ffmpeg->vbr; } - /* Set the picture format - need in ffmpeg starting round April-May 2005 */ - c->pix_fmt = PIX_FMT_YUV420P; + if (strcmp(ffmpeg_video_codec, "ffv1") == 0) c->strict_std_compliance = -2; + c->flags |= CODEC_FLAG_GLOBAL_HEADER; - /* Get a mutex lock. */ pthread_mutex_lock(&global_lock); - - /* Open the codec */ -#if defined FF_API_NEW_AVIO - ret = avcodec_open2(c, codec, NULL /* options */ ); -#else - ret = avcodec_open(c, codec); -#endif - - if (ret < 0) { - /* Release the lock. */ + retcd = avcodec_open2(c, codec, &opts); + pthread_mutex_unlock(&global_lock); + if (retcd < 0) { + if (codec->supported_framerates) { + const AVRational *fps = codec->supported_framerates; + while (fps->num) { + MOTION_LOG(INF, TYPE_ENCODER, NO_ERRNO, "%s Reported FPS Supported %d/%d", fps->num, fps->den); + fps++; + } + } + int chkrate = 1; + pthread_mutex_lock(&global_lock); + while ((chkrate < 36) && (retcd != 0)) { + c->time_base.den = chkrate; + retcd = avcodec_open2(c, codec, &opts); + chkrate++; + } pthread_mutex_unlock(&global_lock); - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: avcodec_open - could not open codec %s", - ffmpeg_video_codec); - ffmpeg_cleanups(ffmpeg); - return NULL; - } + if (retcd < 0){ + av_strerror(retcd, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Could not open codec %s",errstr); + av_dict_free(&opts); + ffmpeg_cleanups(ffmpeg); + return NULL; + } - /* Release the lock. */ - pthread_mutex_unlock(&global_lock); + } + av_dict_free(&opts); + MOTION_LOG(NTC, TYPE_ENCODER, NO_ERRNO, "%s Selected Output FPS %d", c->time_base.den); + + ffmpeg->video_st->time_base.num = 1; + ffmpeg->video_st->time_base.den = 1000; + if ((strcmp(ffmpeg_video_codec, "swf") == 0) || + (ffmpeg->tlapse != TIMELAPSE_NONE) ) { + ffmpeg->video_st->time_base.num = 1; + ffmpeg->video_st->time_base.den = rate; + if ((rate > 50) && (strcmp(ffmpeg_video_codec, "swf") == 0)){ + MOTION_LOG(NTC, TYPE_ENCODER, NO_ERRNO, "%s The FPS could be too high for the SWF container. Consider other choices."); + } + } ffmpeg->video_outbuf = NULL; - if (!(ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE)) { - /* - * Allocate output buffer - * XXX: API change will be done - * ffmpeg->video_outbuf_size = 200000 - */ ffmpeg->video_outbuf_size = ffmpeg->c->width * 512; ffmpeg->video_outbuf = mymalloc(ffmpeg->video_outbuf_size); } - /* Allocate the encoded raw picture. */ - ffmpeg->picture = avcodec_alloc_frame(); + ffmpeg->picture = my_frame_alloc(); if (!ffmpeg->picture) { - MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: avcodec_alloc_frame -" - " could not alloc frame"); + MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: could not alloc frame"); ffmpeg_cleanups(ffmpeg); return NULL; } - /* Set variable bitrate if requested. */ - if (ffmpeg->vbr) - ffmpeg->picture->quality = ffmpeg->vbr; - - /* Set the frame data. */ ffmpeg->picture->data[0] = y; ffmpeg->picture->data[1] = u; @@ -655,73 +463,52 @@ struct ffmpeg *ffmpeg_open(char *ffmpeg_video_codec, char *filename, ffmpeg->picture->linesize[2] = ffmpeg->c->width / 2; /* Open the output file, if needed. */ - if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { - char file_proto[256]; - - /* - * Use append file protocol for mpeg1, to get the append behavior from - * url_fopen, but no protocol (=> default) for other codecs. - */ - if (is_mpeg1) -#if defined FF_API_NEW_AVIO - snprintf(file_proto, sizeof(file_proto), "%s", filename); -#else - snprintf(file_proto, sizeof(file_proto), APPEND_PROTO ":%s", filename); -#endif - else - snprintf(file_proto, sizeof(file_proto), "%s", filename); - - -#if defined FF_API_NEW_AVIO - if (avio_open(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { -#else - if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { -#endif - /* Path did not exist? */ - if (errno == ENOENT) { - /* Create path for file (don't use file_proto)... */ - if (create_path(filename) == -1) { + if ((timelapse_exists(filename) == 0) || (ffmpeg->tlapse != TIMELAPSE_APPEND)) { + if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { + if (avio_open(&ffmpeg->oc->pb, filename, MY_FLAG_WRITE) < 0) { + if (errno == ENOENT) { + if (create_path(filename) == -1) { + ffmpeg_cleanups(ffmpeg); + return NULL; + } + if (avio_open(&ffmpeg->oc->pb, filename, MY_FLAG_WRITE) < 0) { + MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: error opening file %s", filename); + ffmpeg_cleanups(ffmpeg); + return NULL; + } + /* Permission denied */ + } else if (errno == EACCES) { + MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO,"%s: Permission denied. %s",filename); ffmpeg_cleanups(ffmpeg); return NULL; - } - -#if defined FF_API_NEW_AVIO - if (avio_open(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { -#else - /* And retry opening the file (use file_proto). */ - if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { -#endif - MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: url_fopen -" - " error opening file %s", filename); + } else { + MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Error opening file %s", filename); ffmpeg_cleanups(ffmpeg); return NULL; } - /* Permission denied */ - } else if (errno == EACCES) { - MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, - "%s: url_fopen - error opening file %s" - " ... check access rights to target directory", - filename); - ffmpeg_cleanups(ffmpeg); - return NULL; - } else { - MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Error opening file %s", - filename); - ffmpeg_cleanups(ffmpeg); - return NULL; } } - } + gettimeofday(&ffmpeg->start_time, NULL); - /* Write the stream header, if any. */ -#if defined FF_API_NEW_AVIO - avformat_write_header(ffmpeg->oc, NULL); -#else - av_write_header(ffmpeg->oc); -#endif // FF_API_NEW_AVIO + /* Write the stream header, For the TIMELAPSE_APPEND + * we write the data via standard file I/O so we close the + * items here + */ + retcd = avformat_write_header(ffmpeg->oc, NULL); + if (retcd < 0){ + av_strerror(retcd, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Could not write ffmpeg header %s",errstr); + ffmpeg_cleanups(ffmpeg); + return NULL; + } + if (ffmpeg->tlapse == TIMELAPSE_APPEND) { + av_write_trailer(ffmpeg->oc); + avio_close(ffmpeg->oc->pb); + } + + } return ffmpeg; } - /** * ffmpeg_cleanups * Clean up ffmpeg struct if something was wrong. @@ -729,34 +516,19 @@ struct ffmpeg *ffmpeg_open(char *ffmpeg_video_codec, char *filename, * Returns * Function returns nothing. */ -void ffmpeg_cleanups(struct ffmpeg *ffmpeg) -{ - unsigned int i; +void ffmpeg_cleanups(struct ffmpeg *ffmpeg){ /* Close each codec */ if (ffmpeg->video_st) { pthread_mutex_lock(&global_lock); -#if LIBAVCODEC_BUILD > 4680 - if (ffmpeg->video_st->codec->priv_data != NULL) -#endif - avcodec_close(AVSTREAM_CODEC_PTR(ffmpeg->video_st)); + avcodec_close(AVSTREAM_CODEC_PTR(ffmpeg->video_st)); pthread_mutex_unlock(&global_lock); - av_freep(&ffmpeg->picture); - free(ffmpeg->video_outbuf); } - - /* Free the streams */ - for (i = 0; i < ffmpeg->oc->nb_streams; i++) - av_freep(&ffmpeg->oc->streams[i]); - - /* Free the stream */ - av_free(ffmpeg->oc); -#if LIBAVFORMAT_BUILD >= 4629 - av_free(ffmpeg->c); -#endif + free(ffmpeg->video_outbuf); + av_freep(&ffmpeg->picture); + avformat_free_context(ffmpeg->oc); free(ffmpeg); } - /** * ffmpeg_close * Closes a video file. @@ -764,46 +536,29 @@ void ffmpeg_cleanups(struct ffmpeg *ffmpeg) * Returns * Function returns nothing. */ -void ffmpeg_close(struct ffmpeg *ffmpeg) -{ - unsigned int i; +void ffmpeg_close(struct ffmpeg *ffmpeg){ + if (ffmpeg->tlapse != TIMELAPSE_APPEND) { + av_write_trailer(ffmpeg->oc); + } /* Close each codec */ if (ffmpeg->video_st) { pthread_mutex_lock(&global_lock); avcodec_close(AVSTREAM_CODEC_PTR(ffmpeg->video_st)); pthread_mutex_unlock(&global_lock); - av_freep(&ffmpeg->picture); - free(ffmpeg->video_outbuf); } - - /* Write the trailer, if any. */ - av_write_trailer(ffmpeg->oc); - - /* Free the streams. */ - for (i = 0; i < ffmpeg->oc->nb_streams; i++) - av_freep(&ffmpeg->oc->streams[i]); + av_freep(&ffmpeg->picture); + free(ffmpeg->video_outbuf); if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { - /* Close the output file. */ -#if defined FF_API_NEW_AVIO - avio_close(ffmpeg->oc->pb); -#elif LIBAVFORMAT_BUILD >= (52<<16) - url_fclose(ffmpeg->oc->pb); -#else - url_fclose(&ffmpeg->oc->pb); -#endif /* FF_API_NEW_AVIO -- LIBAVFORMAT_BUILD >= (52<<16) */ + if (ffmpeg->tlapse != TIMELAPSE_APPEND) { + avio_close(ffmpeg->oc->pb); + } } - - - /* Free the stream. */ - av_free(ffmpeg->oc); -#if LIBAVFORMAT_BUILD >= 4629 - av_free(ffmpeg->c); -#endif + avformat_free_context(ffmpeg->oc); free(ffmpeg); -} +} /** * ffmpeg_put_image * Puts the image pointed to by ffmpeg->picture. @@ -811,11 +566,33 @@ void ffmpeg_close(struct ffmpeg *ffmpeg) * Returns * value returned by ffmpeg_put_frame call. */ -int ffmpeg_put_image(struct ffmpeg *ffmpeg) -{ - return ffmpeg_put_frame(ffmpeg, ffmpeg->picture); -} +int ffmpeg_put_image(struct ffmpeg *ffmpeg){ + /* A return code of -2 is thrown by the put_frame + * when a image is buffered. For timelapse, we absolutely + * never want a frame buffered so we keep sending back the + * the same pic until it flushes or fails in a different way + */ + int retcd; + int cnt = 0; + + retcd = ffmpeg_put_frame(ffmpeg, ffmpeg->picture); + while ((retcd == -2) && (ffmpeg->tlapse != TIMELAPSE_NONE)) { + retcd = ffmpeg_put_frame(ffmpeg, ffmpeg->picture); + cnt++; + if (cnt > 50){ + MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Excessive attempts to clear buffered packet"); + retcd = -1; + } + } + //non timelapse buffered is ok + if (retcd == -2){ + retcd = 0; + MOTION_LOG(DBG, TYPE_ENCODER, NO_ERRNO, "%s: Buffered packet"); + } + + return retcd; +} /** * ffmpeg_put_other_image * Puts an arbitrary picture defined by y, u and v. @@ -826,23 +603,39 @@ int ffmpeg_put_image(struct ffmpeg *ffmpeg) * 0 if error allocating picture. */ int ffmpeg_put_other_image(struct ffmpeg *ffmpeg, unsigned char *y, - unsigned char *u, unsigned char *v) -{ + unsigned char *u, unsigned char *v){ AVFrame *picture; - int ret = 0; + int retcd = 0; + int cnt = 0; /* Allocate the encoded raw picture. */ picture = ffmpeg_prepare_frame(ffmpeg, y, u, v); if (picture) { - ret = ffmpeg_put_frame(ffmpeg, picture); - if (!ret) - av_free(picture); + /* A return code of -2 is thrown by the put_frame + * when a image is buffered. For timelapse, we absolutely + * never want a frame buffered so we keep sending back the + * the same pic until it flushes or fails in a different way + */ + retcd = ffmpeg_put_frame(ffmpeg, picture); + while ((retcd == -2) && (ffmpeg->tlapse != TIMELAPSE_NONE)) { + retcd = ffmpeg_put_frame(ffmpeg, picture); + cnt++; + if (cnt > 50){ + MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: Excessive attempts to clear buffered packet"); + retcd = -1; + } + } + //non timelapse buffered is ok + if (retcd == -2){ + retcd = 0; + MOTION_LOG(DBG, TYPE_ENCODER, NO_ERRNO, "%s: Buffered packet"); + } + av_free(picture); } - return ret; + return retcd; } - /** * ffmpeg_put_frame * Encodes and writes a video frame using the av_write_frame API. This is @@ -851,87 +644,115 @@ int ffmpeg_put_other_image(struct ffmpeg *ffmpeg, unsigned char *y, * Returns * Number of bytes written or -1 if any error happens. */ -int ffmpeg_put_frame(struct ffmpeg *ffmpeg, AVFrame *pic) -{ - int out_size, ret, got_packet_ptr; - -#ifdef FFMPEG_AVWRITEFRAME_NEWAPI +int ffmpeg_put_frame(struct ffmpeg *ffmpeg, AVFrame *pic){ +/** + * Since the logic,return values and conditions changed so + * dramatically between versions, the encoding of the frame + * is 100% blocked based upon Libav/FFMpeg version + */ +#if (LIBAVFORMAT_VERSION_MAJOR >= 55) || ((LIBAVFORMAT_VERSION_MAJOR == 54) && (LIBAVFORMAT_VERSION_MINOR > 6)) + int retcd; + int got_packet_ptr; AVPacket pkt; + char errstr[128]; + struct timeval tv1; + int64_t pts_interval; - av_init_packet(&pkt); /* Init static structure. */ - pkt.stream_index = ffmpeg->video_st->index; -#endif /* FFMPEG_AVWRITEFRAME_NEWAPI */ + gettimeofday(&tv1, NULL); + av_init_packet(&pkt); /* Init static structure. */ if (ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE) { - /* Raw video case. The API will change slightly in the near future for that. */ -#ifdef FFMPEG_AVWRITEFRAME_NEWAPI -# if LIBAVCODEC_VERSION_MAJOR < 53 - pkt.flags |= PKT_FLAG_KEY; -# else - pkt.flags |= AV_PKT_FLAG_KEY; -# endif + pkt.stream_index = ffmpeg->video_st->index; + pkt.flags |= AV_PKT_FLAG_KEY; pkt.data = (uint8_t *)pic; pkt.size = sizeof(AVPicture); - ret = av_write_frame(ffmpeg->oc, &pkt); -#else - ret = av_write_frame(ffmpeg->oc, ffmpeg->video_st->index, - (uint8_t *)pic, sizeof(AVPicture)); -#endif /* FFMPEG_AVWRITEFRAME_NEWAPI */ } else { - /* Encodes the image. */ -#if defined FF_API_NEW_AVIO - pkt.data = ffmpeg->video_outbuf; - pkt.size = ffmpeg->video_outbuf_size; - - out_size = avcodec_encode_video2(AVSTREAM_CODEC_PTR(ffmpeg->video_st), + pkt.data = NULL; + pkt.size = 0; + retcd = avcodec_encode_video2(AVSTREAM_CODEC_PTR(ffmpeg->video_st), &pkt, pic, &got_packet_ptr); - if (out_size < 0) - // Error encondig - out_size = 0; - else - out_size = pkt.size; -#else - out_size = avcodec_encode_video(AVSTREAM_CODEC_PTR(ffmpeg->video_st), + if (retcd < 0 ){ + av_strerror(retcd, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Error encoding video:%s",errstr); + //Packet is freed upon failure of encoding + return -1; + } + if (got_packet_ptr == 0){ + //Buffered packet. Throw special return code + my_packet_unref(pkt); + return -2; + } + } + if (ffmpeg->tlapse == TIMELAPSE_APPEND) { + retcd = timelapse_append(ffmpeg, pkt); + } else if (ffmpeg->tlapse == TIMELAPSE_NEW) { + retcd = av_write_frame(ffmpeg->oc, &pkt); + } else { + pts_interval = ((1000000L * (tv1.tv_sec - ffmpeg->start_time.tv_sec)) + tv1.tv_usec - ffmpeg->start_time.tv_usec) + 10000; + pkt.pts = av_rescale_q(pts_interval,(AVRational){1, 1000000L},ffmpeg->video_st->time_base); + if (pkt.pts < 1) pkt.pts = 1; + pkt.dts = pkt.pts; + retcd = av_write_frame(ffmpeg->oc, &pkt); + } +// MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: pts:%d dts:%d stream:%d interval %d",pkt.pts,pkt.dts,ffmpeg->video_st->time_base.den,pts_interval); + my_packet_unref(pkt); + + if (retcd != 0) { + MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Error while writing video frame"); + ffmpeg_cleanups(ffmpeg); + return -1; + } + + return retcd; + +#else // Old versions of Libav/FFmpeg + int retcd; + AVPacket pkt; + + av_init_packet(&pkt); /* Init static structure. */ + pkt.stream_index = ffmpeg->video_st->index; + if (ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE) { + // Raw video case. + pkt.size = sizeof(AVPicture); + pkt.data = (uint8_t *)pic; + pkt.flags |= AV_PKT_FLAG_KEY; + } else { + retcd = avcodec_encode_video(AVSTREAM_CODEC_PTR(ffmpeg->video_st), ffmpeg->video_outbuf, ffmpeg->video_outbuf_size, pic); -#endif - /* If zero size, it means the image was buffered. */ - if (out_size != 0) { - /* - * Writes the compressed frame in the media file. - * XXX: in case of B frames, the pts is not yet valid. - */ -#ifdef FFMPEG_AVWRITEFRAME_NEWAPI - pkt.pts = AVSTREAM_CODEC_PTR(ffmpeg->video_st)->coded_frame->pts; - - if (AVSTREAM_CODEC_PTR(ffmpeg->video_st)->coded_frame->key_frame) -# if LIBAVCODEC_VERSION_MAJOR < 53 - pkt.flags |= PKT_FLAG_KEY; -# else - pkt.flags |= AV_PKT_FLAG_KEY; -# endif - - pkt.data = ffmpeg->video_outbuf; - pkt.size = out_size; - ret = av_write_frame(ffmpeg->oc, &pkt); -#else - ret = av_write_frame(ffmpeg->oc, ffmpeg->video_st->index, - ffmpeg->video_outbuf, out_size); -#endif /* FFMPEG_AVWRITEFRAME_NEWAPI */ - - } else { - ret = 0; + if (retcd < 0 ){ + MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Error encoding video"); + my_packet_unref(pkt); + return -1; + } + if (retcd == 0 ){ + // No bytes encoded => buffered=>special handling + my_packet_unref(pkt); + return -2; } + + pkt.size = retcd; + pkt.data = ffmpeg->video_outbuf; + pkt.pts = AVSTREAM_CODEC_PTR(ffmpeg->video_st)->coded_frame->pts; + if (AVSTREAM_CODEC_PTR(ffmpeg->video_st)->coded_frame->key_frame) + pkt.flags |= AV_PKT_FLAG_KEY; } + if (ffmpeg->tlapse == TIMELAPSE_APPEND) { + retcd = timelapse_append(ffmpeg, pkt); + } else { + retcd = av_write_frame(ffmpeg->oc, &pkt); + } + my_packet_unref(pkt); - if (ret != 0) { - MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Error while writing" - " video frame"); + if (retcd != 0) { + MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Error while writing video frame"); ffmpeg_cleanups(ffmpeg); return -1; } - return ret; + return retcd; + +#endif } /** @@ -949,7 +770,7 @@ AVFrame *ffmpeg_prepare_frame(struct ffmpeg *ffmpeg, unsigned char *y, { AVFrame *picture; - picture = avcodec_alloc_frame(); + picture = my_frame_alloc(); if (!picture) { MOTION_LOG(ERR, TYPE_ENCODER, SHOW_ERRNO, "%s: Could not alloc frame"); @@ -960,6 +781,7 @@ AVFrame *ffmpeg_prepare_frame(struct ffmpeg *ffmpeg, unsigned char *y, if (ffmpeg->vbr) picture->quality = ffmpeg->vbr; + /* Setup pointers and line widths. */ picture->data[0] = y; picture->data[1] = u; @@ -968,45 +790,12 @@ AVFrame *ffmpeg_prepare_frame(struct ffmpeg *ffmpeg, unsigned char *y, picture->linesize[1] = ffmpeg->c->width / 2; picture->linesize[2] = ffmpeg->c->width / 2; - return picture; -} - + picture->format = ffmpeg->c->pix_fmt; + picture->width = ffmpeg->c->width; + picture->height = ffmpeg->c->height; -/** - * ffmpeg_deinterlace - * Make the image suitable for deinterlacing using ffmpeg, then deinterlace the picture. - * - * Parameters - * img image in YUV420P format - * width image width in pixels - * height image height in pixels - * - * Returns - * Function returns nothing. - * img contains deinterlaced image - */ -void ffmpeg_deinterlace(unsigned char *img, int width, int height) -{ - AVPicture picture; - int width2 = width / 2; - - picture.data[0] = img; - picture.data[1] = img + width * height; - picture.data[2] = picture.data[1] + (width * height) / 4; - picture.linesize[0] = width; - picture.linesize[1] = width2; - picture.linesize[2] = width2; - - /* We assume using 'PIX_FMT_YUV420P' always */ - avpicture_deinterlace(&picture, &picture, PIX_FMT_YUV420P, width, height); - -#if !defined(__SSE_MATH__) && (defined(__i386__) || defined(__x86_64__)) - __asm__ __volatile__ ( "emms"); -#endif - - return; + return picture; } - /** * ffmpeg_avcodec_log * Handle any logging output from the ffmpeg library avcodec. @@ -1023,13 +812,33 @@ void ffmpeg_deinterlace(unsigned char *img, int width, int height) void ffmpeg_avcodec_log(void *ignoreme ATTRIBUTE_UNUSED, int errno_flag, const char *fmt, va_list vl) { char buf[1024]; + char *end; /* Flatten the message coming in from avcodec. */ vsnprintf(buf, sizeof(buf), fmt, vl); + end = buf + strlen(buf); + if (end > buf && end[-1] == '\n') + { + *--end = 0; + } - /* If the debug_level is correct then send the message to the motion logging routine. */ - MOTION_LOG(INF, TYPE_ENCODER, NO_ERRNO, "%s: %s - flag %d", - buf, errno_flag); + /* If the debug_level is correct then send the message to the motion logging routine. + * While it is not really desired to look for specific text in the message, there does + * not seem another option. The specific messages indicated are lost camera which we + * have our own message and UE golomb is not something that is possible for us to fix. + * It is caused by the stream sent from the source camera + */ + if(strstr(buf, "No route to host") == NULL){ + if (strstr(buf, "Invalid UE golomb") != NULL) { + MOTION_LOG(DBG, TYPE_ENCODER, NO_ERRNO, "%s: %s", buf); + } else if (errno_flag <= AV_LOG_ERROR) { + MOTION_LOG(ERR, TYPE_ENCODER, NO_ERRNO, "%s: %s", buf); + } else if (errno_flag <= AV_LOG_WARNING) { + MOTION_LOG(NTC, TYPE_ENCODER, NO_ERRNO, "%s: %s", buf); + } else if (errno_flag < AV_LOG_DEBUG){ + MOTION_LOG(INF, TYPE_ENCODER, NO_ERRNO, "%s: %s", buf); + } + } } #endif /* HAVE_FFMPEG */ diff --git a/ffmpeg.h b/ffmpeg.h index a1e2e9d..65d5937 100644 --- a/ffmpeg.h +++ b/ffmpeg.h @@ -1,39 +1,37 @@ #ifndef _INCLUDE_FFMPEG_H_ #define _INCLUDE_FFMPEG_H_ +#include +#include + +#include "config.h" + #ifdef HAVE_FFMPEG -#include -#ifdef FFMPEG_NEW_INCLUDES +#include #include -#else -#include -#endif +#include +#include + +#if (LIBAVFORMAT_VERSION_MAJOR >= 56) -#ifndef AVERROR /* 0.4.8 & 0.4.9-pre1 */ +#define MY_PIX_FMT_YUV420P AV_PIX_FMT_YUV420P +#define MY_PIX_FMT_YUVJ420P AV_PIX_FMT_YUVJ420P +#define MyPixelFormat AVPixelFormat -#if EINVAL > 0 -#define AVERROR(e) (-(e)) -#define AVUNERROR(e) (-(e)) #else -/* Some platforms have E* and errno already negated. */ -#define AVERROR(e) (e) -#define AVUNERROR(e) (e) -#endif -#endif /* AVERROR */ - -#endif /* HAVE_FFMPEG */ +#define MY_PIX_FMT_YUV420P PIX_FMT_YUV420P +#define MY_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P +#define MyPixelFormat PixelFormat +#endif -#include -#include +#endif /* HAVE_FFMPEG */ -/* - * Define a codec name/identifier for timelapse videos, so that we can - * differentiate between normal mpeg1 videos and timelapse videos. - */ -#define TIMELAPSE_CODEC "mpeg1_tl" +#define TIMELAPSE_NONE 0 /* No timelapse, regular processing */ +#define TIMELAPSE_APPEND 1 /* Use append version of timelapse */ +#define TIMELAPSE_NEW 2 /* Use create new file version of timelapse */ struct ffmpeg { #ifdef HAVE_FFMPEG @@ -48,6 +46,8 @@ struct ffmpeg { void *udata; /* U & V planes for greyscale images */ int vbr; /* variable bitrate setting */ char codec[20]; /* codec name */ + int tlapse; + struct timeval start_time; #else int dummy; #endif @@ -56,23 +56,18 @@ struct ffmpeg { /* Initialize FFmpeg stuff. Needs to be called before ffmpeg_open. */ void ffmpeg_init(void); -/* - * Open an mpeg file. This is a generic interface for opening either an mpeg1 or - * an mpeg4 video. If non-standard mpeg1 isn't supported (FFmpeg build > 4680), - * calling this function with "mpeg1" as codec results in an error. To create a - * timelapse video, use TIMELAPSE_CODEC as codec name. - */ struct ffmpeg *ffmpeg_open( - char *ffmpeg_video_codec, - char *filename, + const char *ffmpeg_video_codec, + char *filename, unsigned char *y, /* YUV420 Y plane */ unsigned char *u, /* YUV420 U plane */ unsigned char *v, /* YUV420 V plane */ int width, - int height, + int height, int rate, /* framerate, fps */ int bps, /* bitrate; bits per second */ - int vbr /* variable bitrate */ + int vbr, /* variable bitrate */ + int tlapse ); /* Puts the image pointed to by the picture member of struct ffmpeg. */ @@ -80,19 +75,30 @@ int ffmpeg_put_image(struct ffmpeg *); /* Puts the image defined by u, y and v (YUV420 format). */ int ffmpeg_put_other_image( - struct ffmpeg *ffmpeg, - unsigned char *y, - unsigned char *u, + struct ffmpeg *ffmpeg, + unsigned char *y, + unsigned char *u, unsigned char *v ); /* Closes the mpeg file. */ void ffmpeg_close(struct ffmpeg *); -/* Deinterlace the image. */ -void ffmpeg_deinterlace(unsigned char *, int, int); - /* Setup an avcodec log handler. */ void ffmpeg_avcodec_log(void *, int, const char *, va_list); +#ifdef HAVE_FFMPEG +AVFrame *my_frame_alloc(void); +void my_frame_free(AVFrame *frame); +int ffmpeg_put_frame(struct ffmpeg *, AVFrame *); +void ffmpeg_cleanups(struct ffmpeg *); +AVFrame *ffmpeg_prepare_frame(struct ffmpeg *, unsigned char *, + unsigned char *, unsigned char *); +int my_image_get_buffer_size(enum MyPixelFormat pix_fmt, int width, int height); +int my_image_copy_to_buffer(AVFrame *frame,uint8_t *buffer_ptr,enum MyPixelFormat pix_fmt,int width,int height,int dest_size); +int my_image_fill_arrays(AVFrame *frame,uint8_t *buffer_ptr,enum MyPixelFormat pix_fmt,int width,int height); +void my_packet_unref(AVPacket pkt); + +#endif + #endif /* _INCLUDE_FFMPEG_H_ */ diff --git a/git-commit-version.sh b/git-commit-version.sh index 2a47df1..8797c30 100755 --- a/git-commit-version.sh +++ b/git-commit-version.sh @@ -1,5 +1,5 @@ #!/bin/sh -SNV_VERSION=`git show -s --format=%H` -echo -n "Git-$SNV_VERSION" +SNV_VERSION=`git show -s --format=%h` +echo -n "3.4.1+git$SNV_VERSION" diff --git a/jpegutils.c b/jpegutils.c index 9c9bc44..15d762d 100644 --- a/jpegutils.c +++ b/jpegutils.c @@ -265,6 +265,7 @@ struct my_error_mgr { static void my_error_exit(j_common_ptr cinfo) { + char buffer[JMSG_LENGTH_MAX]; /* cinfo->err really points to a my_error_mgr struct, so coerce pointer. */ struct my_error_mgr *myerr = (struct my_error_mgr *) cinfo->err; @@ -272,7 +273,9 @@ static void my_error_exit(j_common_ptr cinfo) * Always display the message. * We could postpone this until after returning, if we chose. */ - (*cinfo->err->output_message) (cinfo); + (*cinfo->err->format_message) (cinfo, buffer); + + MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: %s", buffer); /* Return control to the setjmp point. */ longjmp (myerr->setjmp_buffer, 1); @@ -280,14 +283,18 @@ static void my_error_exit(j_common_ptr cinfo) static void my_emit_message(j_common_ptr cinfo, int msg_level) { + char buffer[JMSG_LENGTH_MAX]; /* cinfo->err really points to a my_error_mgr struct, so coerce pointer. */ struct my_error_mgr *myerr = (struct my_error_mgr *) cinfo->err; if (msg_level < 0) - myerr->warning_seen = 1; + myerr->warning_seen++ ; - /* Call original emit_message() */ - (myerr->original_emit_message)(cinfo, msg_level); + //msg_level = 3 are the RST markers of the JPG which are not of much interest + if (msg_level < 3) { + (*cinfo->err->format_message) (cinfo, buffer); + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "%s: msg_level: %d, %s", msg_level, buffer); + } } #define MAX_LUMA_WIDTH 4096 @@ -478,7 +485,7 @@ int decode_jpeg_raw (unsigned char *jpeg_data, int len, if (setjmp (jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. */ jpeg_destroy_decompress (&dinfo); - return -1; + return 1; } jpeg_create_decompress (&dinfo); @@ -491,9 +498,9 @@ int decode_jpeg_raw (unsigned char *jpeg_data, int len, */ jpeg_read_header (&dinfo, TRUE); dinfo.raw_data_out = TRUE; -#if JPEG_LIB_VERSION >= 70 +#if JPEG_LIB_VERSION >= 70 dinfo.do_fancy_upsampling = FALSE; -#endif +#endif dinfo.out_color_space = JCS_YCbCr; dinfo.dct_method = JDCT_IFAST; guarantee_huff_tables(&dinfo); @@ -584,9 +591,9 @@ int decode_jpeg_raw (unsigned char *jpeg_data, int len, if (field > 0) { jpeg_read_header (&dinfo, TRUE); dinfo.raw_data_out = TRUE; -#if JPEG_LIB_VERSION >= 70 +#if JPEG_LIB_VERSION >= 70 dinfo.do_fancy_upsampling = FALSE; -#endif +#endif dinfo.out_color_space = JCS_YCbCr; dinfo.dct_method = JDCT_IFAST; jpeg_start_decompress (&dinfo); @@ -746,10 +753,19 @@ int decode_jpeg_raw (unsigned char *jpeg_data, int len, jpeg_destroy_decompress (&dinfo); - if (jerr.warning_seen) + /** + * The 10% was determined by trial. Perhaps a better + * threshold for discarding an image would be a function + * of the threshold for the trigger of motion. + */ + if (dinfo.output_height == 0){ return 1; - else - return 0; + } else { + if ( (jerr.warning_seen / dinfo.output_height) > 0.10) + return 1; + else + return 0; + } ERR_EXIT: jpeg_destroy_decompress (&dinfo); @@ -770,7 +786,7 @@ int decode_jpeg_gray_raw(unsigned char *jpeg_data, int len, unsigned int height, unsigned char *raw0, unsigned char *raw1, unsigned char *raw2) { - int numfields, hsf[3], field, yl, yc, xsl, xsc, xs, xd, hdown; + int numfields, field, yl, yc, xsl, xsc, xs, xd, hdown; unsigned int x, y, vsf[3]; JSAMPROW row0[16] = { buf0[0], buf0[1], buf0[2], buf0[3], @@ -805,7 +821,7 @@ int decode_jpeg_gray_raw(unsigned char *jpeg_data, int len, dinfo.raw_data_out = TRUE; #if JPEG_LIB_VERSION >= 70 dinfo.do_fancy_upsampling = FALSE; -#endif +#endif dinfo.out_color_space = JCS_GRAYSCALE; dinfo.dct_method = JDCT_IFAST; @@ -818,8 +834,7 @@ int decode_jpeg_gray_raw(unsigned char *jpeg_data, int len, guarantee_huff_tables(&dinfo); jpeg_start_decompress (&dinfo); - hsf[0] = 1; hsf[1] = 1; hsf[2] = 1; - vsf[0]= 1; vsf[1] = 1; vsf[2] = 1; + vsf[0] = 1; vsf[1] = 1; vsf[2] = 1; /* Height match image height or be exact twice the image height. */ @@ -874,7 +889,7 @@ int decode_jpeg_gray_raw(unsigned char *jpeg_data, int len, dinfo.raw_data_out = TRUE; #if JPEG_LIB_VERSION >= 70 dinfo.do_fancy_upsampling = FALSE; -#endif +#endif dinfo.out_color_space = JCS_GRAYSCALE; dinfo.dct_method = JDCT_IFAST; jpeg_start_decompress (&dinfo); diff --git a/logger.c b/logger.c index f76d2a3..6c46041 100644 --- a/logger.c +++ b/logger.c @@ -110,7 +110,7 @@ void set_log_mode(int mode) FILE * set_logfile(const char *logfile_name) { log_mode = LOGMODE_SYSLOG; /* Setup temporary to let log if myfopen fails */ - logfile = myfopen(logfile_name, "a", 0); + logfile = myfopen(logfile_name, "a"); /* If logfile was opened correctly */ if (logfile) @@ -212,26 +212,29 @@ void motion_log(int level, unsigned int type, int errno_flag, const char *fmt, . /* Next add the user's message. */ va_start(ap, fmt); n += vsnprintf(buf + n, sizeof(buf) - n, fmt, ap); + buf[1023] = '\0'; /* If errno_flag is set, add on the library error message. */ if (errno_flag) { - strncat(buf, ": ", 1024 - strlen(buf)); - n += 2; + size_t buf_len = strlen(buf); + + // just knock off 10 characters if we're that close... + if (buf_len + 10 > 1024) { + buf[1024 - 10] = '\0'; + buf_len = 1024 - 10; + } + + strncat(buf, ": ", 1024 - buf_len); + n += 2; /* * This is bad - apparently gcc/libc wants to use the non-standard GNU * version of strerror_r, which doesn't actually put the message into * my buffer :-(. I have put in a 'hack' to get around this. */ #if defined(XSI_STRERROR_R) -#warning "************************************" -#warning "* Using XSI-COMPLIANT strerror_r() *" -#warning "************************************" /* XSI-compliant strerror_r() */ strerror_r(errno_save, buf + n, sizeof(buf) - n); /* 2 for the ': ' */ #else -#warning "************************************" -#warning "* Using GNU-COMPLIANT strerror_r() *" -#warning "************************************" /* GNU-specific strerror_r() */ strncat(buf, strerror_r(errno_save, msg_buf, sizeof(msg_buf)), 1024 - strlen(buf)); #endif diff --git a/mask1.png b/mask1.png new file mode 100644 index 0000000..1d4350d Binary files /dev/null and b/mask1.png differ diff --git a/mmalcam.c b/mmalcam.c new file mode 100644 index 0000000..306e72b --- /dev/null +++ b/mmalcam.c @@ -0,0 +1,403 @@ +/* + * mmalcam.c + * + * Raspberry Pi camera module using MMAL API. + * + * Built upon functionality from the Raspberry Pi userland utility raspivid. + * + * Copyright 2013 by Nicholas Tuckett + * This software is distributed under the GNU public license version 2 + * See also the file 'COPYING'. + * + */ + +#include "interface/vcos/vcos.h" +#include "interface/mmal/mmal.h" +#include "interface/mmal/mmal_buffer.h" +#include "interface/mmal/mmal_port.h" +#include "interface/mmal/util/mmal_util.h" +#include "interface/mmal/util/mmal_util_params.h" +#include "interface/mmal/util/mmal_default_components.h" +#include "interface/mmal/util/mmal_connection.h" +#include "raspicam/RaspiCamControl.h" + +#include "motion.h" +#include "rotate.h" + +#define MMALCAM_OK 0 +#define MMALCAM_ERROR -1 + +#define MMAL_CAMERA_PREVIEW_PORT 0 +#define MMAL_CAMERA_VIDEO_PORT 1 +#define MMAL_CAMERA_CAPTURE_PORT 2 +#define VIDEO_FRAME_RATE_NUM 30 +#define VIDEO_FRAME_RATE_DEN 1 +#define VIDEO_OUTPUT_BUFFERS_NUM 3 + +const int MAX_BITRATE = 30000000; // 30Mbits/s + +static void parse_camera_control_params(const char *control_params_str, RASPICAM_CAMERA_PARAMETERS *camera_params) +{ + char *control_params_tok = alloca(strlen(control_params_str) + 1); + strcpy(control_params_tok, control_params_str); + + char *next_param = strtok(control_params_tok, " "); + + while (next_param != NULL) { + char *param_val = strtok(NULL, " "); + if (raspicamcontrol_parse_cmdline(camera_params, next_param + 1, param_val) < 2) { + next_param = param_val; + } else { + next_param = strtok(NULL, " "); + } + } +} + +static void check_disable_port(MMAL_PORT_T *port) +{ + if (port && port->is_enabled) { + mmal_port_disable(port); + } +} + +static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) +{ + if (buffer->cmd != MMAL_EVENT_PARAMETER_CHANGED) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "Received unexpected camera control callback event, 0x%08x", + buffer->cmd); + } + + mmal_buffer_header_release(buffer); +} + +static void camera_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) +{ + mmalcam_context_ptr mmalcam = (mmalcam_context_ptr) port->userdata; + mmal_queue_put(mmalcam->camera_buffer_queue, buffer); +} + +static void set_port_format(mmalcam_context_ptr mmalcam, MMAL_ES_FORMAT_T *format) +{ + format->encoding = MMAL_ENCODING_OPAQUE; + format->encoding_variant = MMAL_ENCODING_I420; + format->es->video.width = mmalcam->width; + format->es->video.height = mmalcam->height; + format->es->video.crop.x = 0; + format->es->video.crop.y = 0; + format->es->video.crop.width = mmalcam->width; + format->es->video.crop.height = mmalcam->height; +} + +static void set_video_port_format(mmalcam_context_ptr mmalcam, MMAL_ES_FORMAT_T *format) +{ + set_port_format(mmalcam, format); + format->es->video.frame_rate.num = mmalcam->framerate; + format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN; +} + +static int create_camera_component(mmalcam_context_ptr mmalcam, const char *mmalcam_name) +{ + MMAL_STATUS_T status; + MMAL_COMPONENT_T *camera_component; + MMAL_PORT_T *video_port = NULL; + + status = mmal_component_create(mmalcam_name, &camera_component); + + if (status != MMAL_SUCCESS) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "Failed to create MMAL camera component %s", mmalcam_name); + goto error; + } + + if (camera_component->output_num == 0) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "MMAL camera %s doesn't have output ports", mmalcam_name); + goto error; + } + + video_port = camera_component->output[MMAL_CAMERA_VIDEO_PORT]; + + status = mmal_port_enable(camera_component->control, camera_control_callback); + + if (status) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "Unable to enable control port : error %d", status); + goto error; + } + + // set up the camera configuration + { + MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = { + { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) }, + .max_stills_w = mmalcam->width, + .max_stills_h = mmalcam->height, + .stills_yuv422 = 0, + .one_shot_stills = 0, + .max_preview_video_w = mmalcam->width, + .max_preview_video_h = mmalcam->height, + .num_preview_video_frames = 3, + .stills_capture_circular_buffer_height = 0, + .fast_preview_resume = 0, + .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC }; + mmal_port_parameter_set(camera_component->control, &cam_config.hdr); + } + + set_video_port_format(mmalcam, video_port->format); + video_port->format->encoding = MMAL_ENCODING_I420; + status = mmal_port_format_commit(video_port); + + if (status) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "camera video format couldn't be set"); + goto error; + } + + // Ensure there are enough buffers to avoid dropping frames + if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) { + video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; + } + + status = mmal_component_enable(camera_component); + + if (status) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "camera component couldn't be enabled"); + goto error; + } + + raspicamcontrol_set_all_parameters(camera_component, mmalcam->camera_parameters); + mmalcam->camera_component = camera_component; + mmalcam->camera_capture_port = video_port; + mmalcam->camera_capture_port->userdata = (struct MMAL_PORT_USERDATA_T*) mmalcam; + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "MMAL camera component created"); + return MMALCAM_OK; + + error: if (mmalcam->camera_component != NULL ) { + mmal_component_destroy(camera_component); + mmalcam->camera_component = NULL; + } + + return MMALCAM_ERROR; +} + +static void destroy_camera_component(mmalcam_context_ptr mmalcam) +{ + if (mmalcam->camera_component) { + mmal_component_destroy(mmalcam->camera_component); + mmalcam->camera_component = NULL; + } +} + +static int create_camera_buffer_structures(mmalcam_context_ptr mmalcam) +{ + mmalcam->camera_buffer_pool = mmal_pool_create(mmalcam->camera_capture_port->buffer_num, + mmalcam->camera_capture_port->buffer_size); + if (mmalcam->camera_buffer_pool == NULL ) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "MMAL camera buffer pool creation failed"); + return MMALCAM_ERROR; + } + + mmalcam->camera_buffer_queue = mmal_queue_create(); + if (mmalcam->camera_buffer_queue == NULL ) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "MMAL camera buffer queue creation failed"); + return MMALCAM_ERROR; + } + + return MMALCAM_OK; +} + +static int send_pooled_buffers_to_port(MMAL_POOL_T *pool, MMAL_PORT_T *port) +{ + int num = mmal_queue_length(pool->queue); + + for (int i = 0; i < num; i++) { + MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(pool->queue); + + if (!buffer) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "Unable to get a required buffer %d from pool queue", i); + return MMALCAM_ERROR; + } + + if (mmal_port_send_buffer(port, buffer) != MMAL_SUCCESS) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "Unable to send a buffer to port (%d)", i); + return MMALCAM_ERROR; + } + } + + return MMALCAM_OK; +} + +static void destroy_camera_buffer_structures(mmalcam_context_ptr mmalcam) +{ + if (mmalcam->camera_buffer_queue != NULL ) { + mmal_queue_destroy(mmalcam->camera_buffer_queue); + mmalcam->camera_buffer_queue = NULL; + } + + if (mmalcam->camera_buffer_pool != NULL ) { + mmal_pool_destroy(mmalcam->camera_buffer_pool); + mmalcam->camera_buffer_pool = NULL; + } +} + +/** + * mmalcam_start + * + * This routine is called from the main motion thread. It's job is + * to open up the requested camera device via MMAL and do any required + * initialisation. + * + * Parameters: + * + * cnt Pointer to the motion context structure for this device. + * + * Returns: 0 on success + * -1 on any failure + */ + +int mmalcam_start(struct context *cnt) +{ + mmalcam_context_ptr mmalcam; + + cnt->mmalcam = (mmalcam_context*) mymalloc(sizeof(struct mmalcam_context)); + memset(cnt->mmalcam, 0, sizeof(mmalcam_context)); + mmalcam = cnt->mmalcam; + mmalcam->cnt = cnt; + + MOTION_LOG(ALR, TYPE_VIDEO, NO_ERRNO, + "%s: MMAL Camera thread starting... for camera (%s) of %d x %d at %d fps", + cnt->conf.mmalcam_name, cnt->conf.width, cnt->conf.height, cnt->conf.frame_limit); + + mmalcam->camera_parameters = (RASPICAM_CAMERA_PARAMETERS*)malloc(sizeof(RASPICAM_CAMERA_PARAMETERS)); + if (mmalcam->camera_parameters == NULL) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "camera params couldn't be allocated"); + return MMALCAM_ERROR; + } + + raspicamcontrol_set_defaults(mmalcam->camera_parameters); + mmalcam->width = cnt->conf.width; + mmalcam->height = cnt->conf.height; + mmalcam->framerate = cnt->conf.frame_limit; + + if (cnt->conf.mmalcam_control_params) { + parse_camera_control_params(cnt->conf.mmalcam_control_params, mmalcam->camera_parameters); + } + + cnt->imgs.width = mmalcam->width; + cnt->imgs.height = mmalcam->height; + cnt->imgs.size = (mmalcam->width * mmalcam->height * 3) / 2; + cnt->imgs.motionsize = mmalcam->width * mmalcam->height; + cnt->imgs.type = VIDEO_PALETTE_YUV420P; + + int retval = create_camera_component(mmalcam, cnt->conf.mmalcam_name); + + if (retval == 0) { + retval = create_camera_buffer_structures(mmalcam); + } + + if (retval == 0) { + if (mmal_port_enable(mmalcam->camera_capture_port, camera_buffer_callback)) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "MMAL camera capture port enabling failed"); + retval = MMALCAM_ERROR; + } + } + + if (retval == 0) { + if (mmal_port_parameter_set_boolean(mmalcam->camera_capture_port, MMAL_PARAMETER_CAPTURE, 1) + != MMAL_SUCCESS) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "MMAL camera capture start failed"); + retval = MMALCAM_ERROR; + } + } + + if (retval == 0) { + retval = send_pooled_buffers_to_port(mmalcam->camera_buffer_pool, mmalcam->camera_capture_port); + } + + return retval; +} + +/** + * mmalcam_cleanup + * + * This routine shuts down any MMAL resources, then releases any allocated data + * within the mmalcam context and frees the context itself. + * This function is also called from motion_init if first time connection + * fails and we start retrying until we get a valid first frame from the + * camera. + * + * Parameters: + * + * mmalcam Pointer to a mmalcam context + * + * Returns: Nothing. + * + */ +void mmalcam_cleanup(struct mmalcam_context *mmalcam) +{ + MOTION_LOG(ALR, TYPE_VIDEO, NO_ERRNO, "MMAL Camera cleanup"); + + if (mmalcam != NULL ) { + if (mmalcam->camera_component) { + check_disable_port(mmalcam->camera_capture_port); + mmal_component_disable(mmalcam->camera_component); + destroy_camera_buffer_structures(mmalcam); + destroy_camera_component(mmalcam); + } + + if (mmalcam->camera_parameters) { + free(mmalcam->camera_parameters); + } + + free(mmalcam); + } +} + +/** + * mmalcam_next + * + * This routine is called when the main 'motion' thread wants a new + * frame of video. It fetches the most recent frame available from + * the Pi camera already in YUV420P, and returns it to motion. + * + * Parameters: + * cnt Pointer to the context for this thread + * image Pointer to a buffer for the returned image + * + * Returns: Error code + */ +int mmalcam_next(struct context *cnt, unsigned char *map) +{ + mmalcam_context_ptr mmalcam; + + if ((!cnt) || (!cnt->mmalcam)) + return NETCAM_FATAL_ERROR; + + mmalcam = cnt->mmalcam; + + MMAL_BUFFER_HEADER_T *camera_buffer = mmal_queue_wait(mmalcam->camera_buffer_queue); + + if (camera_buffer->cmd == 0 && (camera_buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) + && camera_buffer->length == cnt->imgs.size) { + mmal_buffer_header_mem_lock(camera_buffer); + memcpy(map, camera_buffer->data, cnt->imgs.size); + mmal_buffer_header_mem_unlock(camera_buffer); + } else { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "%s: cmd %d flags %08x size %d/%d at %08x", + camera_buffer->cmd, camera_buffer->flags, camera_buffer->length, camera_buffer->alloc_size, camera_buffer->data); + } + + mmal_buffer_header_release(camera_buffer); + + if (mmalcam->camera_capture_port->is_enabled) { + MMAL_STATUS_T status; + MMAL_BUFFER_HEADER_T *new_buffer = mmal_queue_get(mmalcam->camera_buffer_pool->queue); + + if (new_buffer) { + status = mmal_port_send_buffer(mmalcam->camera_capture_port, new_buffer); + } + + if (!new_buffer || status != MMAL_SUCCESS) + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "Unable to return a buffer to the camera video port"); + } + + if (cnt->rotate_data.degrees > 0) + rotate_map(cnt, map); + + return 0; +} diff --git a/mmalcam.h b/mmalcam.h new file mode 100644 index 0000000..c44e6a5 --- /dev/null +++ b/mmalcam.h @@ -0,0 +1,34 @@ +/* + * mmalcam.h + * + * Include file for mmalcam.c + * + * Copyright 2013 by Nicholas Tuckett + * This software is distributed under the GNU public license version 2 + * See also the file 'COPYING'. + */ + +#ifndef MMALCAM_H_ +#define MMALCAM_H_ + +typedef struct mmalcam_context *mmalcam_context_ptr; + +typedef struct mmalcam_context { + struct context *cnt; /* pointer to parent motion + context structure */ + int width; + int height; + int framerate; + + struct MMAL_COMPONENT_T *camera_component; + struct MMAL_PORT_T *camera_capture_port; + struct MMAL_POOL_T *camera_buffer_pool; + struct MMAL_QUEUE_T *camera_buffer_queue; + struct raspicam_camera_parameters_s *camera_parameters; +} mmalcam_context; + +int mmalcam_start (struct context *); +int mmalcam_next (struct context *, unsigned char *); +void mmalcam_cleanup (struct mmalcam_context *); + +#endif /* MMALCAM_H_ */ diff --git a/motion-dist.conf.in b/motion-dist.conf.in index 630cbf8..881b41d 100644 --- a/motion-dist.conf.in +++ b/motion-dist.conf.in @@ -8,7 +8,7 @@ ############################################################ # Start in daemon (background) mode and release terminal (default: off) -daemon on +daemon off # File to store the process ID, also called pid file. (default: not defined) process_id_file /var/run/motion/motion.pid @@ -24,7 +24,7 @@ setup_mode off # Use a file to save logs messages, if not defined stderr and syslog is used. (default: not defined) ;logfile /tmp/motion.log -# Level of log messages [1..9] (EMR, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL). (default: 6 / NTC) +# Level of log messages [1..9] (EMG, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL). (default: 6 / NTC) log_level 6 # Filter to log messages by type (COR, STR, ENC, NET, DBL, EVT, TRK, VID, ALL). (default: ALL) @@ -38,7 +38,7 @@ log_type all # for FreeBSD default is /dev/bktr0 videodevice /dev/video0 -# v4l2_palette allows to choose preferable palette to be use by motion +# v4l2_palette allows one to choose preferable palette to be use by motion # to capture from those supported by your videodevice. (default: 17) # E.g. if your videodevice supports both V4L2_PIX_FMT_SBGGR8 and # V4L2_PIX_FMT_MJPEG then motion will by default use V4L2_PIX_FMT_MJPEG. @@ -73,6 +73,7 @@ v4l2_palette 17 # The video input to be used (default: -1) # Should normally be set to 0 or 1 for video/TV cards, and -1 for USB cameras +# Set to 0 for uvideo(4) on OpenBSD input -1 # The video norm to use (only for video capture and TV tuner cards) @@ -82,6 +83,15 @@ norm 0 # The frequency to set the tuner to (kHz) (only for TV tuner cards) (default: 0) frequency 0 +# Override the power line frequency for the webcam. (normally not necessary) +# Values: +# -1 : Do not modify device setting +# 0 : Power line frequency Disabled +# 1 : 50hz +# 2 : 60hz +# 3 : Auto +power_line_frequency -1 + # Rotate image this number of degrees. The rotation affects all saved images as # well as movies. Valid values: 0 (default = no rotation), 90, 180 and 270. rotate 0 @@ -101,8 +111,9 @@ framerate 2 # This option is used when you want to capture images at a rate lower than 2 per second. minimum_frame_time 0 -# URL to use if you are using a network camera, size will be autodetected (incl http:// ftp:// mjpg:// rstp:// or file:///) -# Must be a URL that returns single jpeg pictures or a raw mjpeg stream. Default: Not defined +# URL to use if you are using a network camera, size will be autodetected (incl http:// ftp:// mjpg:// rtsp:// mjpeg:// or file:///) +# Must be a URL that returns single jpeg pictures or a raw mjpeg stream. A trailing slash may be required for some cameras. +# Default: Not defined ; netcam_url value # Username and password for network camera (only if required). Default: not defined @@ -125,6 +136,18 @@ netcam_keepalive off # Default: off netcam_tolerant_check off +# RTSP connection uses TCP to communicate to the camera. Can prevent image corruption. +# Default: on +rtsp_uses_tcp on + +# Name of camera to use if you are using a camera accessed through OpenMax/MMAL +# Default: Not defined +; mmalcam_name vc.ril.camera + +# Camera control parameters (see raspivid/raspistill tool documentation) +# Default: Not defined +; mmalcam_control_params -hf + # Let motion regulate the brightness of a video device (default: off). # The auto_brightness feature uses the brightness option as its target value. # If brightness is zero auto_brightness will adjust to average brightness value 128. @@ -283,39 +306,46 @@ ffmpeg_timelapse_mode daily # Bitrate to be used by the ffmpeg encoder (default: 400000) # This option is ignored if ffmpeg_variable_bitrate is not 0 (disabled) -ffmpeg_bps 500000 +ffmpeg_bps 400000 # Enables and defines variable bitrate for the ffmpeg encoder. # ffmpeg_bps is ignored if variable bitrate is enabled. # Valid values: 0 (default) = fixed bitrate defined by ffmpeg_bps, -# or the range 2 - 31 where 2 means best quality and 31 is worst. +# or the range 1 - 100 where 1 means worst quality and 100 is best. ffmpeg_variable_bitrate 0 # Codec to used by ffmpeg for the video compression. -# Timelapse mpegs are always made in mpeg1 format independent from this option. -# Supported formats are: mpeg1 (ffmpeg-0.4.8 only), mpeg4 (default), and msmpeg4. -# mpeg1 - gives you files with extension .mpg +# Timelapse videos have two options. +# mpg - Creates mpg file with mpeg-2 encoding. +# If motion is shutdown and restarted, new pics will be appended +# to any previously created file with name indicated for timelapse. +# mpeg4 - Creates avi file with the default encoding. +# If motion is shutdown and restarted, new pics will create a +# new file with the name indicated for timelapse. +# Supported formats are: # mpeg4 or msmpeg4 - gives you files with extension .avi # msmpeg4 is recommended for use with Windows Media Player because # it requires no installation of codec on the Windows client. # swf - gives you a flash film with extension .swf # flv - gives you a flash video with extension .flv -# ffv1 - FF video codec 1 for Lossless Encoding ( experimental ) -# mov - QuickTime ( testing ) -# ogg - Ogg/Theora ( testing ) +# ffv1 - FF video codec 1 for Lossless Encoding +# mov - QuickTime +# mp4 - MPEG-4 Part 14 H264 encoding +# mkv - Matroska H264 encoding +# hevc - H.265 / HEVC (High Efficiency Video Coding) ffmpeg_video_codec mpeg4 -# Use ffmpeg to deinterlace video. Necessary if you use an analog camera -# and see horizontal combing on moving objects in video or pictures. -# (default: off) -ffmpeg_deinterlace off +# When creating videos, should frames be duplicated in order +# to keep up with the requested frames per second +# (default: true) +ffmpeg_duplicate_frames true ############################################################ # SDL Window ############################################################ # Number of motion thread to show in SDL Window (default: 0 = disabled) -sdl_threadnr 0 +#sdl_threadnr 0 ############################################################ # External pipe to video encoder @@ -329,8 +359,10 @@ use_extpipe off # External program (full path and opts) to pipe raw video to # Generally, use '-' for STDIN... -;extpipe mencoder -demuxer rawvideo -rawvideo w=320:h=240:i420 -ovc x264 -x264encopts bframes=4:frameref=1:subq=1:scenecut=-1:nob_adapt:threads=1:keyint=1000:8x8dct:vbv_bufsize=4000:crf=24:partitions=i8x8,i4x4:vbv_maxrate=800:no-chroma-me -vf denoise3d=16:12:48:4,pp=lb -of avi -o %f.avi - -fps %fps - +;extpipe mencoder -demuxer rawvideo -rawvideo w=%w:h=%h:i420 -ovc x264 -x264encopts bframes=4:frameref=1:subq=1:scenecut=-1:nob_adapt:threads=1:keyint=1000:8x8dct:vbv_bufsize=4000:crf=24:partitions=i8x8,i4x4:vbv_maxrate=800:no-chroma-me -vf denoise3d=16:12:48:4,pp=lb -of avi -o %f.avi - -fps %fps +;extpipe x264 - --input-res %wx%h --fps %fps --bitrate 2000 --preset ultrafast --quiet -o %f.mp4 +;extpipe mencoder -demuxer rawvideo -rawvideo w=%w:h=%h:fps=%fps -ovc x264 -x264encopts preset=ultrafast -of lavf -o %f.mp4 - -fps %fps +;extpipe ffmpeg -y -f rawvideo -pix_fmt yuv420p -video_size %wx%h -framerate %fps -i pipe:0 -vcodec libx264 -preset ultrafast -f mp4 %f.mp4 ############################################################ @@ -345,7 +377,7 @@ snapshot_interval 0 # Text Display # %Y = year, %m = month, %d = date, # %H = hour, %M = minute, %S = second, %T = HH:MM:SS, -# %v = event, %q = frame number, %t = thread (camera) number, +# %v = event, %q = frame number, %t = camera id number, # %D = changed pixels, %N = noise level, \n = new line, # %i and %J = width and height of motion area, # %K and %L = X and Y coordinates of motion center @@ -405,7 +437,7 @@ text_double off # you can use conversion specifiers # %Y = year, %m = month, %d = date, # %H = hour, %M = minute, %S = second, -# %v = event, %q = frame number, %t = thread (camera) number, +# %v = event, %q = frame number, %t = camera id number, # %D = changed pixels, %N = noise level, # %i and %J = width and height of motion area, # %K and %L = X and Y coordinates of motion center @@ -415,7 +447,7 @@ text_double off # Target base directory for pictures and films # Recommended to use absolute path. (Default: current working directory) -target_dir /usr/local/apache2/htdocs/cam1 +#target_dir /tmp/motion # File path for snapshots (jpeg or ppm) relative to target_dir # Default: %v-%Y%m%d%H%M%S-snapshot @@ -437,17 +469,12 @@ picture_filename %v-%Y%m%d%H%M%S-%q # File path for motion triggered ffmpeg films (movies) relative to target_dir # Default: %v-%Y%m%d%H%M%S -# Default value is equivalent to legacy oldlayout option -# For Motion 3.0 compatible mode choose: %Y/%m/%d/%H%M%S -# File extension .mpg or .avi is automatically added so do not include this -# This option was previously called ffmpeg_filename +# File extensions(.mpg .avi) are automatically added so do not include them movie_filename %v-%Y%m%d%H%M%S # File path for timelapse movies relative to target_dir # Default: %Y%m%d-timelapse -# Default value is near equivalent to legacy oldlayout option -# For Motion 3.0 compatible mode choose: %Y/%m/%d-timelapse -# File extension .mpg is automatically added so do not include this +# File extensions(.mpg .avi) are automatically added so do not include them timelapse_filename %Y%m%d-timelapse ############################################################ @@ -491,6 +518,13 @@ stream_auth_method 0 # Default: not defined (Disabled) ; stream_authentication username:password +# Percentage to scale the stream image for preview +# Default: 25 +; stream_preview_scale 25 + +# Have stream preview image start on a new line +# Default: no +; stream_preview_newline no ############################################################ # HTTP Based Control @@ -584,7 +618,7 @@ track_stepsize 40 # You can use conversion specifiers for the on_xxxx commands # %Y = year, %m = month, %d = date, # %H = hour, %M = minute, %S = second, -# %v = event, %q = frame number, %t = thread (camera) number, +# %v = event, %q = frame number, %t = camera id number, # %D = changed pixels, %N = noise level, # %i and %J = width and height of motion area, # %K and %L = X and Y coordinates of motion center @@ -657,7 +691,7 @@ quiet on # %f = filename with full path # Default value: # Create tables : -## +## # Mysql # CREATE TABLE security (camera int, filename char(80) not null, frame int, file_type int, time_stamp timestamp(14), event_time_stamp timestamp(14)); # @@ -676,6 +710,7 @@ quiet on ; database_type value # database to log to (default: not defined) +# for sqlite3, the full path and name for the database. ; database_dbname value # The host on which the database is located (default: localhost) @@ -691,12 +726,9 @@ quiet on # mysql 3306 , postgresql 5432 (default: not defined) ; database_port value -############################################################ -# Database Options For SQLite3 -############################################################ - -# SQLite3 database (file path) (default: not defined) -; sqlite3_db value +# Database wait time in milliseconds for locked database to +# be unlocked before returning database locked error (default 0) +; database_busy_timeout 0 @@ -714,19 +746,25 @@ quiet on ############################################################## -# Thread config files - One for each camera. +# camera config files - One for each camera. # Except if only one camera - You only need this config file. -# If you have more than one camera you MUST define one thread +# If you have more than one camera you MUST define one camera # config file for each camera in addition to this config file. ############################################################## # Remember: If you have more than one camera you must have one -# thread file for each camera. E.g. 2 cameras requires 3 files: -# This motion.conf file AND thread1.conf and thread2.conf. +# camera file for each camera. E.g. 2 cameras requires 3 files: +# This motion.conf file AND camera1.conf and camera2.conf. # Only put the options that are unique to each camera in the -# thread config files. -; thread /usr/local/etc/thread1.conf -; thread /usr/local/etc/thread2.conf -; thread /usr/local/etc/thread3.conf -; thread /usr/local/etc/thread4.conf +# camera config files. +; camera @sysconfdir@/motion/camera1.conf +; camera @sysconfdir@/motion/camera2.conf +; camera @sysconfdir@/motion/camera3.conf +; camera @sysconfdir@/motion/camera4.conf + +############################################################## +# Camera config directory - One for each camera. +############################################################## +# +; camera_dir @sysconfdir@/motion/conf.d diff --git a/motion.1 b/motion.1 index a023f83..4a31ffa 100644 --- a/motion.1 +++ b/motion.1 @@ -1,24 +1,26 @@ -.TH MOTION 1 2011-12-12 "Motion" "Motion Options and Config Files" +.TH MOTION 1 2016-08-25 "Motion" "Motion Options and Config Files" .SH NAME -motion \- Detect motion using a video4linux device +motion \- Detct motion using a video4linux device or network camera .SH SYNOPSIS -.B motion -[ -hmns ] [ -c config file path ] [ -d log level ] [ -k log type ] [ -p process_id_file ] [ -l logfile ] +.B motion [ \-hbnsm ] [ \-c config file path ] [ \-d level ] [ \-k level ] [ \-p process_id_file ][ \-l log_file ] .SH DESCRIPTION .I Motion -uses a video4linux device to detect motion. If motion is detected both normal -and motion pictures will be taken. Motion can also take actions to notify you +uses a video4linux device or network camera to detect motion. If motion is detected both normal +and motion pictures can be taken. Motion can also take actions to notify you if needed. Creation of automated snapshots is also possible. .SH OPTIONS .TP .B \-c -Full path and filename of config file. E.g. /home/kurt/motion.conf. Default is /usr/local/etc unless specified differently when building Motion. Many RPMs and debian packages will most likely use /etc or /etc/motion as default. +Full path and filename of config file. +For example: \fI /home/kurt/motion.conf \fR +The default is \fI /usr/local/etc/motion\fR unless specified differently when building Motion. +Many RPMs and Debian packages will use \fI/etc\fR or \fI/etc/motion\fR as the default. .TP .B \-h Show help screen. .TP -.B \-m -Disable motion detection at startup. +.B \-b +Run in daemon mode. .TP .B \-n Run in non-daemon mode. @@ -26,651 +28,1783 @@ Run in non-daemon mode. .B \-s Run in setup mode. Also forces non-daemon mode .TP -.B \-d log level -Set log level [1..9] (EMR, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL). (default: 6 / NTC) +.B \-d +Run with message log level 1-9. +.TP +.B \-k +Run with message log type 1-9 .TP -.B \-k log type -Set type of log (COR, STR, ENC, NET, DBL, EVT, TRK, VID, ALL). (default: ALL) +.B \-l +Full path and file name for the log file .TP .B \-p Full path and filename for process id file (pid file). E.g /var/run/motion.pid. Default is not defined. Pid file is only created when Motion is started in daemon mode. .TP -.B \-l -Full path and filename of log file. ( use -l syslog to log to stderr and syslog ) +.B \-m +Start in pause mode .TP .SH "CONFIG FILE OPTIONS" These are the options that can be used in the config file. .I They are overridden by the commandline! All number values are integer numbers (no decimals allowed). Boolean options can be on or off (values "1", "yes" and "on" all means true and any other value means false). + .TP -.B area_detect integer -Values: 0 - 999999999 / Default: Not defined -.br -Detect motion in predefined areas (1 - 9). Areas are numbered like that: 1 2 3 -.br -A script (on_area_detected) is started immediately when motion is 4 5 6 -.br -detected in one of the given areas, but only once during an event. 7 8 9 -.br -One or more areas can be specified with this option. Take care: This option does NOT restrict detection to these areas! (Default: not defined) -.TP -.B auto_brightness boolean -Values: on, off / Default: off -.br -Let motion regulate the brightness of a video device. Only recommended for cameras without auto brightness -.TP -.B brightness integer -Values: 0 - 255 / Default: 0 (disabled) -.br -The brightness level for the video device. -.TP -.B contrast boolean -Values: 0 - 255 / Default: 0 (disabled) -.br -The contrast level for the video device. -.TP -.B daemon boolean -Values: on, off / Default: off -.br -Start in daemon (background) mode and release terminal. This option must be placed in motion.conf and not in a thread config file. -.TP -.B database_dbname string -Values: Max 4095 characters / Default: Not defined -.br -Name of the database. -.TP -.B database_host string -Values: Max 4095 characters / Default: localhost -.br -IP address or domain name for the database server. Use "localhost" if motion and database runs on the same server. -.TP -.B database_password string -Values: Max 4095 characters / Default: Not defined -.br -The database password. -.TP -.B database_port integer -Values: 0 - 65535 / Default: Not defined -.br -The database server port number. +.B daemon +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +When specified as ON, Motion goes into daemon (background process) mode and releases the terminal. +.RE +.RE + .TP -.B database_type discrete strings -Values: mysql, postgresql / Default: Not defined -.br -The database type ( mysql , postgresql ). +.B process_id_file +.RS +.nf +Values: User specified string +Default: Not defined +Description: +.fi +.RS +File to store the process ID, also called pid file. +.RE +.RE + .TP -.B database_user string -Values: Max 4095 characters / Default: Not defined -.br -The database user name. +.B setup_mode +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Start in Setup-Mode, daemon disabled. +.RE +.RE + .TP -.B despeckle_filter string -Values: EedDl / Default: Not defined -.br -Despeckle motion image using combinations of (E/e)rode or (D/d)ilate. And ending with optional (l)abeling. +.B logfile +.RS +.nf +Values: User specified string +Default: Not Defined +Description: +.fi +.RS +File to save logs messages, if not defined stderr and syslog is used. +.RE +.RE + .TP -.B emulate_motion boolean -Values: on, off / Default: off -.br -Picture are saved continuously as if motion was detected all the time. +.B log_level +.RS +.nf +Values: 1 to 9 (EMG, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL) +Default: 6 / NTC +Description: +.fi +.RS +Specify the level of verbosity in the messages sent to the log. +.RE +.RE + .TP -.B event_gap integer -Values: 0 - 2147483647 / Default: 60 -.br -Event Gap is the seconds of no motion detection that triggers the end of an event. An event is defined as a series of motion images taken within a short timeframe. +.B log_type +.RS +.nf +Values: COR, STR, ENC, NET, DBL, EVT, TRK, VID, ALL +Default: ALL +Description: +.fi +.RS +Filter to log messages by type +.RE +.RE + .TP -.B exif_text string -Values: Max 4095 characters / Default: Not defined -.br -Text to include in a JPEG EXIF comment , may be any text, including conversion specifiers. The EXIF timestamp is included independent of this text. +.B videodevice +.RS +.nf +Values: User specified string +Default: /dev/video0 +Description: +.fi +.RS +String to specify the videodevice to be used for capturing. +For Linux, the format is usually /dev/videoX where X varies depending upon the video devices connected to the computer. +For FreeBSD the default device would be /dev/bktr0. +.RE +.RE + .TP -.B extpipe string -Values: Max 4095 characters / Default: Not defined -.br -pipe raw video to generally - 'STDIN', allowing to use an external video encoder. -.br -e.g. using memcoder : -.br -extpipe mencoder -demuxer rawvideo -rawvideo w=320:h=240:i420 -ovc x264 -x264encopts bframes=4:frameref=1:subq=1:scenecut=-1:nob_adapt: threads=1:keyint=1000:8x8dct:vbv_bufsize=4000:crf=24:partitions=i8x8,i4x4:vbv_maxrate=800:no-chroma-me -vf denoise3d=16:12:48:4,pp=lb -of avi -o %f.avi - -fps %fps +.B v4l2_palette +.RS +.nf +Values: 0 to 17 +.RS +V4L2_PIX_FMT_SN9C10X : 0 'S910' +V4L2_PIX_FMT_SBGGR16 : 1 'BYR2' +V4L2_PIX_FMT_SBGGR8 : 2 'BA81' +V4L2_PIX_FMT_SPCA561 : 3 'S561' +V4L2_PIX_FMT_SGBRG8 : 4 'GBRG' +V4L2_PIX_FMT_SGRBG8 : 5 'GRBG' +V4L2_PIX_FMT_PAC207 : 6 'P207' +V4L2_PIX_FMT_PJPG : 7 'PJPG' +V4L2_PIX_FMT_MJPEG : 8 'MJPEG' +V4L2_PIX_FMT_JPEG : 9 'JPEG' +V4L2_PIX_FMT_RGB24 : 10 'RGB3' +V4L2_PIX_FMT_SPCA501 : 11 'S501' +V4L2_PIX_FMT_SPCA505 : 12 'S505' +V4L2_PIX_FMT_SPCA508 : 13 'S508' +V4L2_PIX_FMT_UYVY : 14 'UYVY' +V4L2_PIX_FMT_YUYV : 15 'YUYV' +V4L2_PIX_FMT_YUV422P : 16 '422P' +V4L2_PIX_FMT_YUV420 : 17 'YU12' +.RE +Default: 17 +Description: +.fi +.RS +The v4l2_palette option allows users to choose the preferred palette to be use by motion to capture from the video device. +If the preferred palette is not available from the video device, Motion will attempt to use palettes that are supported. +.RE +.RE + .TP -.B ffmpeg_bps integer -Values: 0 - 9999999 / Default: 400000 -.br -Bitrate of movies produced by ffmpeg. Bitrate is bits per second. Default: 400000 (400kbps). Higher value mans better quality and larger files. Option requires that ffmpeg libraries are installed. +.B tunerdevice +.RS +.nf +Values: User Specified String +Default: /dev/tuner0 +Description: +.fi +.RS +Tuner device to be used for capturing images. +This is ONLY used for FreeBSD. +.RE +.RE + .TP -.B ffmpeg_output_debug_movies boolean -Values: on, off / Default: off -.br -Use ffmpeg libraries to encode motion type movies where you only see the pixels that changes. +.B input +.RS +.nf +Values: +.RS +\-1 : USB Cameras +0 : video/TV cards or uvideo(4) on OpenBSD +1 : video/TV cards +.RE +Default: \-1 +Description: +.fi +.RS +The video input to be used. +.RE +.RE + .TP -.B ffmpeg_output_movies boolean -Values: on, off / Default: off -.br -Use ffmpeg libraries to encode movies in realtime. +.B norm +.RS +.nf +Values: +.RS +0 (PAL) +1 (NTSC) +2 (SECAM) +3 (PAL NC no colour) +.RE +Default: 0 (PAL) +Description: +.fi +.RS +The video norm to use when capturing from TV tuner cards +.RE +.RE + .TP -.B ffmpeg_deinterlace boolean -Values: on, off / Default: off -.br -Use ffmpeg to deinterlace video. Necessary if you use an analog camera and see horizontal combing on moving objects in video or pictures. +.B frequency +.RS +.nf +Values: Dependent upon video device +Default: 0 +Description: +.fi +.RS +The frequency to set the tuner in kHz when using a TV tuner card. +.RE +.RE + .TP -.B ffmpeg_timelapse integer -Values: 0 - 2147483647 / Default: 0 (disabled) -.br -Create a timelapse movie saving a picture frame at the interval in seconds set by this parameter. Set it to 0 if not used. +.B power_line_frequency +.RS +.nf +Values: +.RS +-1 : Do not modify device setting +0 : Power line frequency Disabled +1 : 50hz +2 : 60hz +3 : Auto +.RE +Default: -1 +Description: +.fi +.RS +Override the power line frequency for the video device. +.RE +.RE + .TP -.B ffmpeg_timelapse_mode discrete strings -Values: hourly, daily, weekly-sunday, weekly-monday, monthly, manual / Default: daily -.br -The file rollover mode of the timelapse video. +.B rotate +.RS +.nf +Values: 0, 90, 180, 270 +Default: 0 +Description: +.fi +.RS +Rotate image this number of degrees. +The rotation affects all saved images as well as movies. +.RE +.RE + .TP -.B ffmpeg_variable_bitrate integer -Values: 0, 2 - 31 / Default: 0 (disabled) -.br -Enables and defines variable bitrate for the ffmpeg encoder. ffmpeg_bps is ignored if variable bitrate is enabled. Valid values: 0 (default) = fixed bitrate defined by ffmpeg_bps, or the range 2 - 31 where 2 means best quality and 31 is worst. +.B width +.RS +.nf +Values: Dependent upon video device +Default: 352 +Description: +.fi +.RS +Image width in pixels for the video device. +.RE +.RE + .TP -.B ffmpeg_video_codec discrete strings -Values: mpeg1 (ffmpeg-0.4.8 only), mpeg4, msmpeg4, swf , flv , ffv1, mov, ogg / Default: mpeg4 -.br -Codec to be used by ffmpeg for the video compression. Timelapse movies are always made in mpeg1 format independent from this option. +.B height +.RS +.nf +Values: Dependent upon video device +Default: off +Description: +.fi +.RS +Image height in pixels for the video device +.RE +.RE + .TP -.B framerate integer -Values: 2 - 100 / Default: 100 (no limit) -.br -Maximum number of frames to be captured from the camera per second. +.B framerate +.RS +.nf +Values: 2 - 100 +Default: 100 +Description: +.fi +.RS +The maximum number of frames to capture in 1 second. +The default of 100 will normally be limited by the capabilities of the video device. +Typical video devices have a maximum rate of 30. +.RE +.RE + .TP -.B frequency integer -Values: 0 - 999999 / Default: 0 (Not set) -.br -The frequency to set the tuner to (kHz). Valid range: per tuner spec, default: 0 (Don't set it) +.B minimum_frame_time +.RS +.nf +Values: 0 to unlimited +Default: 0 +Description: +.fi +.RS +The minimum time in seconds between capturing picture frames from the camera. +The default of 0 disables this option and relies upon the capture rate of the camera. +This option is used when you want to capture images at a rate lower than 2 per second. +.RE +.RE + .TP -.B height integer -Values: Device Dependent / Default: 288 -.br -The height of each frame in pixels. +.B netcam_url +.RS +.nf +Values: User specified string +Default: None +Description: +.fi +.RS +Full connection URL string to use to connect to a network camera. +The URL must provide a stream of images instead of only a static image. +The following prefixes are recognized + +.RS +http:// +ftp:// +mjpg:// +rtsp:// +mjpeg:// +file:// +.RE + +The connection string is camera specific. +It is usually the same as what other video playing applications would use to connect to the camera stream. +Motion currently only supports basic authentication for the cameras. +Digest is not currently supported. +Basic authentication can be specified in the URL or via the netcam_userpass option. +.RE +.RE + .TP -.B hue integer -Values: 0 - 255 / Default: 0 (disabled) -.br -The hue level for the video device. +.B netcam_userpass +.RS +.nf +Values: User specified string +Default: Not Defined +Description: +.fi +.RS +The user id and password required to access the network camera string. +only basic authentication is supported at this time. +Format is in user:password format when both a user name and password is required. +.RE +.RE + .TP -.B input integer -Values: -1 - 64, -1 = disabled / Default: -1 (disabled) -.br -Input channel to use expressed as an integer number starting from -1. Should normally be set to 1 for video/TV cards, and -1 for USB cameras. +.B netcam_keepalive +.RS +.nf +Values: +.RS +.fi +off: The historical implementation using HTTP/1.0, closing the socket after each http request. +.nf + +.fi +force: Use HTTP/1.0 requests with keep alive header to reuse the same connection. +.nf + +.fi +on: Use HTTP/1.1 requests that support keep alive as default. +.nf +.RE +Default: off +Description: +.fi +.RS +This setting is to keep-alive (open) the network socket between requests. +When used, this option should improve performance on compatible net cameras. +This option is not applicable for the rtsp:// and mjpeg:// formats. +.RE +.RE + .TP -.B ipv6_enabled boolean -Values: on, off / Default: off -.br -Enable or disable IPV6 for http control and stream. +.B netcam_proxy +.RS +.nf +Values: User specified string +Default: Not defined +Description: +.fi +.RS +If required, the URL to use for a netcam proxy server. +For example, "http://myproxy". +If a port number other than 80 is needed, append to the specification. +For examplet, "http://myproxy:1234". +.RE +.RE + .TP -.B lightswitch integer -Values: 0 - 100 / Default: 0 (disabled) -.br -Ignore sudden massive light intensity changes given as a percentage of the picture area that changed intensity. +.B netcam_tolerant_check +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Use a less strict jpeg validation for network cameras. +This can assist with cameras that have poor or buggy firmware. +.RE +.RE + .TP -.B locate_motion discrete strings -Values: on, off, redbox, center, redcross, preview / Default: off -.br -Locate and draw a box around the moving object. Value 'preview' makes Motion only draw a box on a saved preview jpeg image and not on the saved movie. +.B rtsp_uses_tcp +.RS +.nf +Values: on/off +Default: on +Description: +.fi +.RS +When using a RTSP connection for a network camera, use a TCP transport instead of UDP. +The UDP transport frequently results in "smeared" corrupt images. +.RE +.RE + .TP -.B logfile string -Values: Max 4095 characters / Default: Not defined -.br -Use a file to save logs messages, if not defined stderr and syslog is used. +.B auto_brightness +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +The auto_brightness feature uses the brightness option as its target value. +If brightness is zero auto_brightness will adjust to average brightness value 128. +only recommended for cameras without auto brightness. +.RE +.RE + .TP -.B logfile string -Values: Max 4095 characters / Default: Not defined -.br -Use a file to save logs messages, if not defined stderr and syslog is used. ( if syslog is set then will log to stderr and syslog ) +.B brightness +.RS +.nf +Values: 0 to 255 +Default: 0 (Disabled) +Description: +.fi +.RS +The initial brightness of a video device. +If auto_brightness is enabled, this value defines the average brightness level which Motion will try and adjust to. +.RE +.RE + .TP -.B log_level integer -Values: 1 - 9 / Default: 6 -.br -Level of log messages [1..9] (EMR, ALR, CRT, ERR, WRN, NTC, ERR, DBG, ALL). (default: 6 / NTC). +.B contrast +.RS +.nf +Values: 0 to 255 +Default: 0 (Disabled) +Description: +.fi +.RS +The contrast value to set for the video device. +.RE +.RE + .TP -.B log_type discrete strings -Values: STR, ENC, NET, DBL, EVT, TRK, VID, ALL / Default: ALL -.br -Filter to log messages by type (STR, ENC, NET, DBL, EVT, TRK, VID, ALL). +.B saturation +.RS +.nf +Values: 0 to 255 +Default: 0 (Disabled) +Description: +.fi +.RS +The saturation value to set for the video device. +.RE +.RE + .TP -.B mask_file string -Values: Max 4095 characters / Default: Not defined -.br -PGM file to use as a sensitivity mask. This picture MUST have the same width and height as the frames being captured and be in binary format. +.B hue +.RS +.nf +Values: 0 to 255 +Default: 0 (Disabled) +Description: +.fi +.RS +The hue value to set for the video device. +.RE +.RE + .TP -.B max_movie_time integer -Values: 0 (infinite) - 2147483647 / Default: 3600 -.br -The maximum length of a movie in seconds. Set this to zero for unlimited length. +.B roundrobin_frames +.RS +.nf +Values: 1 to unlimited +Default: 1 +Description: +.fi +.RS +Number of frames to capture in each roundrobin step +.RE +.RE + .TP -.B minimum_frame_time integer -Values: 0 - 2147483647 / Default: 0 -.br -Minimum time in seconds between the capturing picture frames from the camera. Default: 0 = disabled - the capture rate is given by the camera framerate. +.B roundrobin_skip +.RS +.nf +Values: 1 to unlimited +Default: 1 +Description: +.fi +.RS +Number of frames to skip before each roundrobin step +.RE +.RE + .TP -.B minimum_motion_frames integer -Values: 1 - 1000s / Default: 1 -.br -Picture frames must contain motion at least the specified number of frames in a row before they are detected as true motion. At the default of 1, all motion is detected. Valid range is 1 to thousands, but it is recommended to keep it within 1-5. +.B switchfilter +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Filter out noise generated by roundrobin +.RE +.RE + .TP -.B motion_video_pipe string -Values: Max 4095 characters / Default: Not defined -.br -The video4linux video loopback input device for motion images. If a particular pipe is to be used then use the device filename of this pipe, if a dash '-' is given motion will use /proc/video/vloopback/vloopbacks to locate a free pipe. Default: not set +.B threshold +.RS +.nf +Values: 1 to unlimited +Default: 1500 +Description: +.fi +.RS +Threshold for number of changed pixels in an image that triggers motion detection +.RE +.RE + .TP -.B movie_filename string -Values: Max 4095 characters / Default: %v-%Y%m%d%H%M%S -.br -File path for motion triggered ffmpeg movies relative to target_dir. This was previously called ffmpeg_filename. +.B threshold_tune +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Automatically tune the threshold down if possible. +.RE +.RE + .TP -.B netcam_tolerant_check boolean -Values: on, off / Default: off -.br -Set less strict jpeg checks for network cameras with a poor/buggy firmware. +.B noise_level +.RS +.nf +Values: 1 to unlimited +Default: 32 +Description: +.fi +.RS +Noise threshold for the motion detection. +.RE +.RE + .TP -.B netcam_keepalive discrete string -Values: off , force, on / Default: off -.br -The setting for keep-alive of network socket, should improve performance on compatible net cameras. +.B noise_tune +.RS +.nf +Values: on/off +Default: on +Description: +.fi +.RS +Automatically tune the noise threshold +.RE +.RE + .TP -.B netcam_proxy string -Values: Max 4095 characters / Default: Not defined -.br -URL to use for a netcam proxy server, if required. The syntax is http://myproxy:portnumber +.B despeckle_filter +.RS +.nf +Values: +.RS +e/E : erode +d/D : dilate +l : label +.RE +Default: EedDl +Description: +.fi +.RS +Despeckle motion image using (e)rode or (d)ilate or (l)abel. +The recommended value is EedDl. Any combination (and number of) of E, e, d, and D is valid. +(l)abeling must only be used once and the 'l' must be the last letter. +Comment out to disable +.RE +.RE + .TP -.B netcam_url string -Values: Max 4095 characters / Default: Not defined -.br -Specify an url to a downloadable jpeg file or raw mjpeg stream to use as input device. Such as an AXIS 2100 network camera. -.br -http:// ftp:// mjpg:// or file:/// ( mjpg:// is for network cameras with codec mjpeg ). +.B area_detect +.RS +.nf +Values: 1 to 9 +Default: Not Defined +Description: +.fi +.RS +When motion is detected in the predefined areas indicated below, +trigger the script indicated by the on_area_detected. +The trigger is only activated once during an event. +one or more areas can be specified with this option. +Note that this option is only used to trigger the indicated script. +It does not limit all motion detection events to only the area indicated. +.RS +Image Areas +.RE +.RS +123 +.RE +.RS +456 +.RE +.RS +789 +.RE +.RE +.RE + .TP -.B netcam_userpass string -Values: Max 4095 characters / Default: Not defined -.br -For network cameras protected by username and password, use this option for HTTP 1.1 Basic authentication. The string is specified as username:password. Do not specify this option for no authentication. +.B mask_file +.RS +.nf +Values: User specified string +Default: Not defined +Description: +.fi +.RS +When particular area should be ignored for motion, it can be accomplished using a PGM mask file. +The PGM mask file is a specially constructed mask file that allows the user to indicate the areas +for which motion should be monitored. +This option specifies the full path and name for the mask file. +.RE +.RE + .TP -.B noise_level integer -Values: 1 - 255 / Default: 32 -.br -The noise level is used as a threshold for distinguishing between noise and motion. +.B smart_mask_speed +.RS +.nf +Values: 0 to 10 +Default: 0 (off) +Description: +.fi +.RS +Speed of mask changes when creating a dynamic mask file. +.RE +.RE + .TP -.B noise_tune boolean -Values: on, off / Default: on -.br -Activates the automatic tuning of noise level. +.B lightswitch +.RS +.nf +Values: 0 to 100 +Default: 0 +Description: +.fi +.RS +Ignore sudden massive light intensity changes. +Value is a percentage of the picture area that changed intensity. +.RE +.RE + .TP -.B norm integer -Values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour) / Default: 0 (PAL) -.br -Select the norm of the video device. Values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour). Default: 0 (PAL) +.B minimum_motion_frames +.RS +.nf +Values: 1 to unlimited +Default: 1 +Description: +.fi +.RS +The minimum number of picture frames in a row that must contain motion before a event is triggered. +The default of 1 means that all motion is detected. +The recommended range is 1 to 5. +.RE +.RE + .TP -.B on_area_detected string -Values: Max 4095 characters / Default: Not defined -.br -Command to be executed when motion in a predefined area is detected, check option area_detect. +.B pre_capture +.RS +.nf +Values: 0 to unlimited +Default: 0 +Description: +.fi +.RS +The number of pre-captured (buffered) pictures from before motion was detected that will be output upon motion detection. +The recommended range is 0 to 5. +It is not recommended to use large values since it will cause Motion to skip frames. +To smooth movies use larger values of post_capture instead. +.RE +.RE + .TP -.B on_camera_lost -Values: Max 4095 characters / Default: Not defined -.br -Command to be executed when a camera can't be opened or if it is lost. You can use Conversion Specifiers and spaces as part of the command. Use %f for passing filename (with full path) to the command. +.B post_capture +.RS +.nf +Values: 0 to unlimited +Default: 0 +Description: +.fi +.RS +Number of frames to capture after motion is no longer detected. +.RE +.RE + .TP -.B on_event_end string -Values: Max 4095 characters / Default: Not defined -.br -Command to be executed when an event ends after a period of no motion. The period of no motion is defined by option event_gap. You can use Conversion Specifiers and spaces as part of the command. +.B event_gap +.RS +.nf +Values: -1 to unlimited +Default: 60 +Description: +.fi +.RS +The number of seconds of no motion that triggers the end of an event. +An event is defined as a series of motion images taken within a short timeframe. +The recommended value is 60 seconds. The value -1 is allowed and disables +events causing all Motion to be written to one single movie file and no pre_capture. +If set to 0, motion is running in gapless mode. +Movies don't have gaps anymore. +An event ends right after no more motion is detected and post_capture is over. +.RE +.RE + .TP -.B on_event_start string -Values: Max 4095 characters / Default: Not defined -.br -Command to be executed when an event starts. An event starts at first motion detected after a period of no motion defined by event_gap. You can use ConversionSpecifiers and spaces as part of the command. +.B max_movie_time +.RS +.nf +Values: 0 to unlimited +Default: 0 +Description: +.fi +.RS +Maximum length in seconds of a movie. +When value is exceeded a new movie file is created. +The value of 0 means that there is no limit. +.RE +.RE + .TP -.B on_motion_detected string -Values: Max 4095 characters / Default: Not defined -.br -Command to be executed when a motion frame is detected. You can use Conversion Specifiers and spaces as part of the command. +.B emulate_motion +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Always save images even if there was no motion. +.RE +.RE + .TP -.B on_movie_end string -Values: Max 4095 characters / Default: Not defined -.br -Command to be executed when an ffmpeg movie is closed at the end of an event. You can use Conversion Specifiers and spaces as part of the command. Use %f for passing filename (with full path) to the command. +.B output_pictures +.RS +.nf +Values: on, off, first, best, center +Default: on +Description: +.fi +.RS +Output pictures when motion is detected. +When set to 'first', only the first picture of an event is saved. +Picture with most motion of an event is saved when set to 'best'. +Picture with motion nearest center of picture is saved when set to 'center'. +Can be used as preview shot for the corresponding movie. +.RE +.RE + .TP -.B on_movie_start string -Values: Max 4095 characters / Default: Not defined -.br -Command to be executed when a movie is created. You can use Conversion Specifiers and spaces as part of the command. Use %f for passing filename (with full path) to the command. +.B output_debug_pictures +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Output pictures with only the pixels moving object (ghost images) +.RE +.RE + .TP -.B on_picture_save string -Values: Max 4095 characters / Default: Not defined -.br -Command to be executed when an image is saved. You can use Conversion Specifiers and spaces as part of the command. Use %f for passing filename (with full path) to the command. +.B quality +.RS +.nf +Values: 1 to 100 +Default: 75 +Description: +.fi +.RS +The quality (in percent) to be used by the jpeg compression +.RE +.RE + .TP -.B output_debug_pictures boolean -Values: on, off / Default: off -.br -Output pictures with only the moving object. This feature generates the special motion type movies where you only see the pixels that changes as a graytone image. If labelling is enabled you see the largest area in blue. Smartmask is shown in red. +.B picture_type +.RS +.nf +Values: jpeg/ppm +Default: jpeg +Description: +.fi +.RS +The file type of output images +.RE +.RE + .TP -.B output_pictures discrete strings -Values: on, off, first, best, center / Default: on -.br -Normal image is an image that is stored when motion is detected. It is the same image that was taken by the camera. I.e. not a motion image like defined by output_motion. Default is that normal images are stored. +.B ffmpeg_output_movies +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Use ffmpeg to encode movies of the motion. +.RE +.RE + .TP -.B picture_filename string -Values: Max 4095 characters / Default: %v-%Y%m%d%H%M%S-%q -.br -File path for motion triggered images (jpeg or ppm) relative to target_dir. Value 'preview' makes a jpeg filename with the same name body as the associated saved movie file. +.B ffmpeg_output_debug_movies +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Use ffmpeg to encode movies with only the pixels moving object (ghost images) +.RE +.RE + .TP -.B picture_type discrete strings -Values: jpeg , ppm / Default: jpeg -.br -Type of images motion will trigger when motion is detected. +.B ffmpeg_timelapse +.RS +.nf +Values: 0 to unlimited +Default: 0 +Description: +.fi +.RS +Number of seconds between frame captures for a timelapse movie. +Specify 0 to disable the timelapse. +.RE +.RE + .TP -.B post_capture integer -Values: 0 - 2147483647 / Default: 0 (disabled) +.B ffmpeg_timelapse_mode +.RS +.nf +Values: +.RS +hourly .br -Specifies the number of frames to be captured after motion has been detected. -.TP -.B pre_capture integer -Values: 0 - 100s / Default: 0 (disabled) +daily .br -Specifies the number of previous frames to be outputted at motion detection. Recommended range: 0 to 5, default=0. Do not use large values! Large values will cause Motion to skip video frames and cause unsmooth movies. To smooth movies use larger values of post_capture instead. -.TP -.B process_id_file string -Values: Max 4095 characters / Default: Not defined +weekly-sunday .br -File to store the process ID, also called pid file. Recommended value when used: /var/run/motion.pid -.TP -.B quality integer -Values: 1 - 100 / Default: 75 +weekly-monday .br -The quality for the jpeg images in percent. -.TP -.B quiet boolean -Values: on, off / Default: off +monthly .br -Be quiet, don't output beeps when detecting motion. +manual +.RE +Default: daily +Description: +.fi +.RS +File rollover mode for the timelapse video. +.RE +.RE + .TP -.B rotate discrete strings -Values: 0, 90, 180, 270 / Default: 0 (not rotated) -.br -Rotate image the given number of degrees. The rotation affects all saved images as well as movies. +.B ffmpeg_bps +.RS +.nf +Values: 0 to unlimited +Default: 400000 +Description: +.fi +.RS +Bitrate to be used by the ffmpeg encoder. +This option is ignored if ffmpeg_variable_bitrate is not 0. +.RE +.RE + .TP -.B roundrobin_frames integer -Values: 1 - 2147483647 / Default: 1 -.br -Specifies the number of frames to capture before switching inputs, this way also slow switching (e.g. every second) is possible. +.B ffmpeg_variable_bitrate +.RS +.nf +Values: 0 to 100 +Default: 0 +Description: +.fi +.RS +Enable and define the variable bitrate for the ffmpeg encoder. +ffmpeg_bps is ignored if variable bitrate is enabled. +When specified as 0, use the fixed bitrate defined by ffmpeg_bps. +When defined as 1 - 100 varies the quality of the movie. +A value of 1 is worst quality versus a value of 100 is best quality. +.RE +.RE + .TP -.B roundrobin_skip integer -Values: 1 - 2147483647 / Default: 1 -.br -Specifies the number of frames to skip after a switch. (1 if you are feeling lucky, 2 if you want to be safe). +.B ffmpeg_video_codec +.RS +.nf +Values: +.RS +Timelapse videos: +.RS +mpg - Creates mpg file with mpeg-2 encoding. +mpeg4 - Creates avi file with the default encoding. +.RE +Motion videos: +.RS +mpeg4 - Creates .avi file +msmpeg4 - Creates .avi file +swf - Flash film with extension .swf +flv - Flash video with extension .flv +ffv1 - FF video codec 1 for Lossless Encoding +mov - QuickTime +ogg - Ogg/Theora +mp4 - MPEG-4 Part 14 H264 encoding +mkv - Matroska H264 encoding +hevc - H.265 / HEVC (High Efficiency Video Coding) +.RE +.RE +Default: mpeg4 +Description: +.fi +.RS +The container and codec to use when creating videos. +When creating timelapse videos, there are only two options and the processing varies due to container/codec limitations. +For mpg timelapse videos, if motion is shutdown and restarted, new pics will be appended +to any previously created file with name indicated for timelapse. +For mpeg4 timelapse videos, if motion is shutdown and restarted, new pics will create a +new file with the name indicated for timelapse. +For regular motion videos, the container/codec must be available in the ffmpeg installed on the computer. +.RE +.RE + .TP -.B saturation integer -Values: 0 - 255 / Default: 0 (disabled) -.br -The colour saturation level for the video device. +.B ffmpeg_duplicate_frames +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +When creating videos, should frames be duplicated in order to keep up with the requested frames per second +.RE +.RE + .TP .B sdl_threadnr -Values: 0 - 2147483647 / Default: 0 (disabled) -.br -Number of motion thread to show in SDL Window (default: 0 = disabled) +.RS +.nf +Values: 0 to unlimited +Default: 0 +Description: +.fi +.RS +Number of motion thread to show in SDL Window +.RE +.RE + .TP -.B setup_mode boolean -Values: on, off / Default: off -.br -Run Motion in setup mode. +.B use_extpipe +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Use the external pipe in order to encode videos. +This is a replacement option for the FFMPEG builtin encoder for ffmpeg_output_movies only. +The options movie_filename and timelapse_filename are also used from the ffmpeg feature +.RE +.RE + .TP -.B smart_mask_speed integer -Values: 0 - 10 / Default: 0 (disabled) -.br -Slugginess of the smart mask. Default is 0 = DISABLED. 1 is slow, 10 is fast. +.B extpipe +.RS +.nf +Values: User specified string +Default: Not defined +Description: +.fi +.RS +Command line string to receive and process a pipe of images to encode. +Generally, use '-' for STDIN +.RE +.RE + .TP -.B snapshot_filename string -Values: Max 4095 characters / Default: %v-%Y%m%d%H%M%S-snapshot -.br -File path for snapshots (jpeg or ppm) relative to target_dir. +.B snapshot_interval +.RS +.nf +Values: 0 to unlimited +Default: 0 +Description: +.fi +.RS +When specified as 0, the snapshot feature is disabled. +When a value is specified, the value indicates the number of seconds between snapshots. +.RE +.RE + .TP -.B snapshot_interval integer -Values: 0 - 2147483647 / Default: 0 (disabled) -.br -Make automated snapshots every 'snapshot_interval' seconds. +.B locate_motion_mode +.RS +.nf +Values: on/off/preview +Default: off +Description: +.fi +.RS +When specified as 'on', locate and draw a box around the moving object. +When set 'preview', only draw a box in preview_shot pictures. +.RE +.RE + .TP -.B sql_log_picture boolean -Values: on, off / Default: on -.br -Log to the database when creating motion triggered image file. +.B locate_motion_style +.RS +.nf +Values: +.RS +.fi +box : Draw traditional box around the part of the image generating the motion +.nf + +.fi +redbox : Draw a red box around the part of the image generating the motion +.nf + +.fi +cross : Draw a cross on the part of the image generating the motion +.nf + +.fi +redcross : Draw a red cross on the part of the image generating the motion +.nf +.RE +Default: box +Description: +.fi +.RS +When locate_motion_mode is enable, this option specifies how the motion will be indicated on the image. +.RE +.RE + .TP -.B sql_log_movie boolean -Values: on, off / Default: off -.br -Log to the database when creating motion triggered movie file. +.B text_right +.RS +.nf +Values: User specified string +Default: %Y-%m-%d\n%T-%q +Description: +.fi +.RS +Text to place in lower right corner of image. Format specifiers follow C function strftime(3) +.RE +.RE + .TP -.B sql_log_snapshot boolean -Values: on, off / Default: on -.br -Log to the database when creating a snapshot image file. +.B text_left +.RS +.nf +Values: User specified string +Default: CAMERA %t +Description: +.fi +.RS +Text to place in lower left corner of image. Format specifiers follow C function strftime(3) +.RE +.RE + .TP -.B sql_log_timelapse boolean -Values: on, off / Default: off -.br -Log to the database when creating timelapse movie file +.B text_changes +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +When specified, draw the number of changed pixed on the images. +This option will normally be set to off except when you setup and adjust the motion settings. +The text is placed in upper right corner of the image. +.RE +.RE + .TP -.B sql_query string -Values: Max 4095 characters / Default: insert into security(camera, filename, frame, file_type, time_stamp, text_event) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C') -.br -SQL query string that is sent to the database. The values for each field are given by using convertion specifiers +.B text_event +.RS +.nf +Values: User specified string +Default: %Y%m%d%H%M%S +Description: +.fi +.RS +Define the value of the special event conversion specifier %C. +The user can use any conversion specifier in this option except %C. +Date and time values are from the timestamp of the first image in the current event. +The %C can be used filenames and text_left/right for creating +a unique identifier for each event. +.RE +.RE + .TP -.B stream_auth_method integer -Values: 0 = disabled , 1 = Basic authentication ,2 = MD5 digest (the safer authentication). / Default: 0 (disabled) -.br -Set the authentication method for stream. +.B text_double +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Draw characters at twice normal size on images. +.RE +.RE + .TP -.B stream_authentication string -Values: username:password / Default: not defined (disabled) -.br -Authentication for the stream. +.B exif_text +.RS +.nf +Values: User specified string +Default: Not defined +Description: +.fi +.RS +Text to include in a JPEG EXIF comment +.RE +.RE + .TP -.B stream_limit integer -Values: 0 - 2147483647 / Default: 0 (unlimited) -.br -Limit the number of frames to number frames. After 'stream_limit' number of frames the connection will be closed by motion. The value 0 means unlimited. +.B target_dir +.RS +.nf +Values: User specified string +Default: Not defined +Description: +.fi +.RS +Target base directory for pictures and films. +It is recommended to use an absolute path. +If this option is not defined, the current working directory is used. +This option accepts the conversion specifiers included at the end of this manual. +.RE +.RE + .TP -.B stream_localhost boolean -Values: on, off / Default: on -.br -Limits the access to the stream to the localhost. +.B snapshot_filename +.RS +.nf +Values: User specified string +Default: %v-%Y%m%d%H%M%S-snapshot +Description: +.fi +.RS +The file path for snapshots relative to target_dir. +The file extension .jpg or .ppm is automatically added so do not include this. +A symbolic link called lastsnap.jpg created in the target_dir will always +point to the latest snapshot, unless snapshot_filename is exactly 'lastsnap' +This option accepts the conversion specifiers included at the end of this manual. +.RE +.RE + .TP -.B stream_maxrate integer -Values: 1 - 100 / Default: 1 -.br -Limit the framerate of the stream in frames per second. Default is 1. Set the value to 100 for practically unlimited. +.B picture_filename +.RS +.nf +Values: User specified string +Default: %v-%Y%m%d%H%M%S-%q +Description: +.fi +.RS +The file path for motion triggered images (jpeg or ppm) relative to target_dir. +The file extension of .jpg or .ppm is automatically added so do not include this. +Set to 'preview' together with best-preview feature enables special naming +convention for preview shots. +This option accepts the conversion specifiers included at the end of this manual. +.RE +.RE + .TP -.B stream_motion boolean -Values: on, off / Default: off -.br -If set to 'on' Motion sends slows down the stream to 1 picture per second when no motion is detected. When motion is detected the stream runs as defined by stream_maxrate. When 'off' the stream always runs as defined by stream_maxrate. +.B movie_filename +.RS +.nf +Values: User specified string +Default: %v-%Y%m%d%H%M%S +Description: +.fi +.RS +File path for motion triggered ffmpeg films (movies) relative to target_dir. +The extensions(.swf, .avi, etc) are automatically added so do not include them +This option accepts the conversion specifiers included at the end of this manual. +.RE +.RE + .TP -.B stream_port integer -Values: 0 - 65535 / Default: 0 (disabled) -.br -TCP port on which motion will listen for incoming connects with its stream server. +.B timelapse_filename +.RS +.nf +Values: User specified string +Default: %Y%m%d-timelapse +Description: +.fi +.RS +File path for timelapse movies relative to target_dir. +The file extensions(.mpg .avi) are automatically added so do not include them +This option accepts the conversion specifiers included at the end of this manual. +.RE +.RE + .TP -.B stream_quality integer -Values: 1 - 100 / Default: 50 -.br -Quality setting in percent for the mjpeg picture frames transferred over the stream connection. Keep it low to restrict needed bandwidth. +.B ipv6_enabled +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Enable or disable IPV6 for http control and stream +.RE +.RE + .TP -.B switchfilter boolean -Values: on, off / Default: off -.br -Turns the switch filter on or off. The filter can distinguish between most switching noise and real motion. With this you can even set roundrobin_skip to 1 without generating much false detection. +.B stream_port +.RS +.nf +Values: 0 to port number limit +Default: 0 +Description: +.fi +.RS +This option is the port number that the mini-http server listens on for streams of the pictures. +.RE +.RE + .TP -.B target_dir string -Values: Max 4095 characters / Default: Not defined = current working directory -.br -Target directory for picture and movie files. +.B stream_quality +.RS +.nf +Values: 1 to 100 +Default: 50 +Description: +.fi +.RS +The quality in percent for the jpg images streamed. +.RE +.RE + .TP -.B text_changes boolean -Values: on, off / Default: off -.br -Turns the text showing changed pixels on/off. +.B stream_motion +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Output frames at 1 fps when no motion is detected and increase to the rate given by stream_maxrate when motion is detected +.RE +.RE + .TP -.B text_double boolean -Values: on, off / Default: off -.br -Draw characters at twice normal size on images. +.B stream_maxrate +.RS +.nf +Values: 1 to unlimited +Default: 1 +Description: +.fi +.RS +Maximum frame rate to send to stream +.RE +.RE + .TP -.B text_event string -Values: Max 4095 characters / Default: %Y%m%d%H%M%S -.br -This option defines the value of the special event conversion specifier %C. You can use any conversion specifier in this option except %C. Date and time values are from the timestamp of the first image in the current event. +.B stream_localhost +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Restrict stream connections to localhost only +.RE +.RE + .TP -.B text_left string -Values: Max 4095 characters / Default: Not defined -.br -User defined text overlayed on each in the lower left corner. Use A-Z, a-z, 0-9, " / ( ) @ ~ # < > | , . : - + _ \n and conversion specifiers (codes starting by a %). +.B stream_limit +.RS +.nf +Values: 0 to unlimited +Default: 0 +Description: +.fi +.RS +Limits the number of images per connection. +The default value of 0 means unlimited. +The number can be defined by multiplying actual stream rate by the desired number of seconds. +The actual stream rate is the smallest of the framerate and stream_maxrate. +.RE +.RE + .TP -.B text_right string -Values: Max 4095 characters / Default: %Y-%m-%d\n%T -.br -User defined text overlayed on each in the lower right corner. Use A-Z, a-z, 0-9, " / ( ) @ ~ # < > | , . : - + _ \n and conversion specifiers (codes starting by a %). Default: %Y-%m-%d\n%T = date in ISO format and time in 24 hour clock +.B stream_auth_method +.RS +.nf +Values: +.RS +0 = disabled +1 = Basic authentication +2 = MD5 digest (the safer authentication) +.RE +Default: 0 +Description: +.fi +.RS +The authentication method to use for viewing the stream. +.RE +.RE + .TP -.B thread string -Values: Max 4095 characters / Default: Not defined -.br -Specifies full path and filename for a thread config file. Each camera needs a thread config file containing the options that are unique to the camera. If you only have one camera you do not need thread config files. If you have two or more cameras you need one thread config file for each camera in addition to motion.conf. This option must be placed in motion.conf and not in a thread config file. +.B stream_authentication +.RS +.nf +Values: User specified string +Default: Not defined +Description: +.fi +.RS +The username and password to use for authentication of the stream. +The format is Username:Password +.RE +.RE + .TP -.B threshold integer -Values: 1 - 2147483647 / Default: 1500 -.br -Threshold for declaring motion. The threshold is the number of changed pixels counted after noise filtering, masking, despeckle, and labelling. +.B stream_preview_scale +.RS +.nf +Values: 1 to 100 +Default: 25 +Description: +.fi +.RS +This defines what percentage the stream image should be scaled to for the preview page +.RE +.RE + .TP -.B threshold_tune boolean -Values: on, off / Default: off -.br -Activates the automatic tuning of threshold level. +.B stream_preview_newline +.RS +.nf +Values: yes/no +Default: no +Description: +.fi +.RS +When the image is put on the preview page, should the image start on a new line. +This option allows the user to specify whether the preview images should be side by side +or stacked on the page. +.RE +.RE + .TP -.B timelapse_filename string -Values: Max 4095 characters / Default: %v-%Y%m%d-timelapse -.br -File path for timelapse movies relative to target_dir (ffmpeg only). +.B webcontrol_port +.RS +.nf +Values: 0 to maximum port number +Default: 0 +Description: +.fi +.RS +Port number for the web control / preview page. +.RE +.RE + .TP -.B track_auto boolean -Values: on, off / Default: off -.br -Enable auto tracking +.B webcontrol_localhost +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Restrict control connections to localhost only +.RE +.RE + .TP -.B track_iomojo_id integer -Values: 0 - 65535 / Default: 0 -.br -Use this option if you have an iomojo smilecam connected to the serial port instead of a general stepper motor controller. +.B webcontrol_html_output +.RS +.nf +Values: on/off +Default: on +Description: +.fi +.RS +Specified whether the web control/preview page should be raw or html format. Preview page is always html. +.RE +.RE + .TP -.B track_maxx integer -Values: 0 - 65535 / Default: 0 -.br -The maximum position for servo x. +.B webcontrol_authentication +.RS +.nf +Values: +.RS +0 = disabled +1 = Basic authentication +2 = MD5 digest (the safer authentication) +.RE +Default: 0 +Description: +.fi +.RS +The authentication method to use for viewing the web control. +.RE +.RE + .TP -.B track_maxy integer -Values: 0 - 65535 / Default: 0 -.br -The maximum position for servo y. +.B track_type +.RS +.nf +Values: +.RS +0 = none +1 = stepper +2 = iomojo +3 = pwc +4 = generic +5 = uvcvideo +6 = servo +.RE +Default: 0 +Description: +.fi +.RS +This option specifies the type of tracker. +The generic type enables the definition of motion center and motion size to +be used with the conversion specifiers for options like on_motion_detected +.RE +.RE + .TP -.B track_motorx integer -Values: 0 - 65535 / Default: 0 -.br -The motor number that is used for controlling the x-axis. +.B track_auto +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Enables/disables the automatic tracking. +.RE +.RE + .TP -.B track_motory integer -Values: 0 - 65535 / Default: 0 -.br -The motor number that is used for controlling the y-axis. +.B track_port +.RS +.nf +Values: User specified string +Default: Not defined +Description: +.fi +.RS +The serial port of the motor. For example /dev/ttyS0 +.RE +.RE + .TP -.B track_move_wait integer -Values: 0 - 65535 / Default: 10 -.br -Delay during which tracking is disabled after auto tracking has moved the camera. Delay is defined as number of picture frames. +.B Tracking options +.RS +.nf +track_motorx, track_motorx_reverse, track_motory, track_motory_reverse +track_maxx, track_minx, track_maxy, track_miny, track_homex, track_homey +track_iomojo_id, track_step_angle_x, track_step_angle_y, track_move_wait +track_speed, track_stepsize + +.fi +.RE +.RS +.nf +Values: device dependent +Default: 0 +Description: +.fi +.RS +These options specify the parameters for cameras with tracking capabilities. +.RE +.RE + .TP -.B track_port string -Values: Max 4095 characters / Default: Not defined -.br -This is the device name of the serial port to which the stepper motor interface is connected. +.B quiet +.RS +.nf +Values: on/off +Default: on +Description: +.fi +.RS +Do not sound beeps when detecting motion +.RE +.RE + .TP -.B track_speed integer -Values: 0 - 255 / Default: 255 -.br -Speed to set the motor to. +.B Script Options +.RS +.nf +on_event_start, on_event_end, on_picture_save +on_motion_detected, on_area_detected, on_movie_start +on_movie_end, on_camera_lost + +.fi +.RE +.RS +.nf +Values: User defined string +Default: Not defined +Description: +.fi +.RS +Specify the full path and file name for the script to execute when the indicated event occurs. +When a file name is required for the script, append a %f to the script string. +.RE +.RE + .TP -.B track_step_angle_x integer -Values: 0-90 / Default: 10 -.br -Angle in degrees the camera moves per step on the X-axis with auto tracking. Currently only used with pwc type cameras. +.B sql_log_picture +.RS +.nf +Values: on/off +Default: on +Description: +.fi +.RS +Log to the database when creating motion triggered picture file +.RE +.RE + .TP -.B track_step_angle_y integer -Values: 0-40 / Default: 10 -.br -Angle in degrees the camera moves per step on the Y-axis with auto tracking. Currently only used with pwc type cameras. +.B sql_log_snapshot +.RS +.nf +Values: on/off +Default: on +Description: +.fi +.RS +Log to the database when creating a snapshot image file +.RE +.RE + .TP -.B track_stepsize integer -Values: 0 - 255 / Default: 40 -.br -Number of steps to make. +.B sql_log_movie +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Log to the database when creating motion triggered movie file +.RE +.RE + .TP -.B track_type discrete strings -Values: 0 (none), 1 (stepper), 2 (iomojo), 3 (pwc), 4 (generic), 5 (uvcvideo) / Default: 0 (None) -.br -Type of tracker. +.B sql_log_timelapse +.RS +.nf +Values: on/off +Default: off +Description: +.fi +.RS +Log to the database when creating timelapse movies file +.RE +.RE + .TP -.B tunerdevice string -Values: Max 4095 characters / Default: /dev/tuner0 -.br -The tuner device used for controlling the tuner in a tuner card. This option is only used when Motion is compiled for FreeBSD. +.B sql_query +.RS +.nf +Values: User defined string +Default: Not defined +Description: +.fi +.RS +SQL statement to execute when a event occurs. +Use same conversion specifiers as for text features +Additional special conversion specifiers are +.RS +%n = the number representing the file_type +%f = filename with full path +.RE +Sample table set up (not sql_query): +.RS +Mysql: CREATE TABLE security (camera int, filename char(80) not null, frame int, file_type int, time_stamp timestamp(14), event_time_stamp timestamp(14)); +.RE +.RS +Postgresql: CREATE TABLE security (camera int, filename char(80) not null, frame int, file_type int, time_stamp timestamp without time zone, event_time_stamp timestamp without time zone); +.RE +Sample sql_query +.RS +insert into security(camera, filename, frame, file_type, time_stamp, text_event) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C') +.RE +.RE +.RE + .TP -.B use_extpipe boolean -Values: on, off / Default: off -.br -Enables extpipe to use an external video encoder feeding with YUV420 using a pipe . +.B database_type +.RS +.nf +Values: mysql, postgresql, sqlite3 +Default: Not defined +Description: +.fi +.RS +The type of database being used. +.RE +.RE + .TP -.B v4l2_palette discrete strings -Values: 0 - 8 / Default: 8 -.br -Allow to choose preferable palette to be use by motion to capture from those supported by your videodevice. +.B database_dbname +.RS +.nf +Values: User defined string +Default: Not defined +Description: +.fi +.RS +The name of the database being used (dbname). For Sqlite3, the full path to the database. +.RE +.RE + .TP -.B video_pipe string -Values: Max 4095 characters / Default: Not defined -.br -The video4linux video loopback input device for normal images. If a particular pipe is to be used then use the device filename of this pipe. If a dash '-' is given motion will use /proc/video/vloopback/vloopbacks to locate a free pipe. +.B database_host +.RS +.nf +Values: User defined string +Default: Not Defined +Description: +.fi +.RS +The name of the host on which the database is running. +.RE +.RE + .TP -.B videodevice string -Values: Max 4095 characters / Default: /dev/video0 (FreeBSD: /dev/bktr0) -.br -The video device to be used for capturing. Default for Linux is /dev/video0. for FreeBSD the default is /dev/bktr0. +.B database_user +.RS +.nf +Values: User defined string +Default: Not Defined +Description: +.fi +.RS +The username to access the database +.RE +.RE + .TP -.B webcontrol_authentication string -Values: Max 4096 characters / Default: Not defined -.br -To protect HTTP Control by username and password, use this option for HTTP 1.1 Basic authentication. The string is specified as username: password. Do not specify this option for no authentication. This option must be placed in motion.conf and not in a thread config file. +.B database_password +.RS +.nf +Values: User defined string +Default: Not Defined +Description: +.fi +.RS +The database password for the user to access the database. +.RE +.RE + .TP -.B webcontrol_html_output boolean -Values: on, off / Default: on -.br -Enable HTML in the answer sent back to a browser connecting to the webcontrol_port. This option must be placed in motion.conf and not in a thread config file. +.B database_port +.RS +.nf +Values: 0 to maximum port number +Default: Not defined +Description: +.fi +.RS +The port to use in order to access the database. +Default ports: mysql 3306 , postgresql 5432 +.RE +.RE + .TP -.B webcontrol_localhost boolean -Values: on, off / Default: on -.br -Limits the webcontrol to the localhost. This option must be placed in motion.conf and not in a thread config file. +.B database_busy_timeout +.RS +.nf +Values: 0 to unlimited +Default: 0 +Description: +.fi +.RS +Database wait time in milliseconds for locked database to be unlocked before returning database locked error +.RE +.RE + .TP -.B webcontrol_port integer -Values: 0 - 65535 / Default: 0 (disabled) -.br -Sets the port number for the http (html using browser) based remote webcontrol. This option must be placed in motion.conf and not in a thread config file. +.B video_pipe +.RS +.nf +Values: User specified string +Default: Not Defined +Description: +.fi +.RS +Output images to a video4linux loopback device. The value '-' means next available +.RE +.RE .TP -.B width integer -Values: Device Dependent / Default: 352 -.br -The width in pixels of each frame. Valid range is camera dependent. +.B motion_video_pipe +.RS +.nf +Values: User specified string +Default: Not Defined +Description: +.fi +.RS +Output motion images to a video4linux loopback device. The value '-' means next available +.RE +.RE + +.TP +.B thread +.RS +.nf +Values: User specified string +Default: Not Defined +Description: +.fi +.RS +This option specifies the full path and file name to individual thread files. +This option can be listed multiple times. +Each thread file should contain the options that are unique to that camera/video device. +Common options are obtained from the motion.conf file and values are overwritten from each +thread file. While the motion.conf includes four sample thread options, the actual +limit of threads is only dependent upon the machine capabilities. +Remember: If you have more than one camera you must have one +thread file for each camera. For example, 2 cameras would require 3 files: +The motion.conf file AND thread1.conf and thread2.conf. +only put the options that are unique to each camera in the +thread config files. +.RE +.RE + + + + + .SH SIGNALS Motion responds to the following signals: @@ -679,35 +1813,35 @@ Motion responds to the following signals: The config file will be reread. .TP .B SIGTERM -If needed motion will create a movie file of the last event and exit +If needed motion will create an mpeg file of the last event and exit .TP .B SIGUSR1 -Motion will create a movie file of the current event. +Motion will create an mpeg file of the current event. .SH NOTES .TP .B Snapshot A snapshot is a picture taken at regular intervals independently of any movement in the picture. .TP .B Motion image -A "motion" image/movie shows the pixels that have actually changed during the last frames. These pictures are not very useful for normal presentation to the public but they are quite useful for testing and tuning and making mask files as you can see exactly where motion sees something moving. Motion is shown in greytones. If labelling is enabled the largest area is marked as blue. Smart mask is shown in read. +A "motion" image/mpeg shows the pixels that have actually changed during the last frames. These pictures are not very useful for normal presentation to the public but they are quite useful for testing and tuning and making mask files as you can see exactly where motion sees something moving. Motion is shown in greytones. If labelling is enabled the largest area is marked as blue. Smart mask is shown in read. .TP .B Normal image A "normal" image is the real image taken by the camera with text overlayed. .TP .B Threads and config files -If Motion was invoked with command line option -c pathname Motion will expect the config file to be as specified. When you specify the config file on the command line with -c you can call it anything. +If Motion was invoked with command line option \-c pathname Motion will expect the config file to be as specified. When you specify the config file on the command line with \-c you can call it anything. .br -If you do not specify -c or the filename you give Motion does not exist, Motion will search for the configuration file called 'motion.conf' in the following order: +If you do not specify \-c or the filename you give Motion does not exist, Motion will search for the configuration file called 'motion.conf' in the following order: .br 1. Current directory from where motion was invoked .br 2. Then in a directory called '.motion' in the current users home directory (shell environment variable $HOME). E.g. /home/goofy/.motion/motion.conf .br -3. The directory defined by the --sysconfdir=DIR when running .configure during installation of Motion (If this option was not defined the default is /usr/local/etc/) +3. The motion/ subdirectory inside the directory defined by the \-\-sysconfdir=DIR when running .configure during installation of Motion (If this option was not defined the default is /usr/local/etc/) .br -If you have write access to /usr/local/etc then the editor recommends having only one motion.conf file in the default /usr/local/etc/ directory. +If you have write access to /usr/local/etc/motion then the editor recommends having only one motion.conf file in the default /usr/local/etc/motion directory. .br -Motion has a configuration file in the distribution package called motion-dist.conf. When you run 'make install' this files gets copied to the /usr/local/etc directory. +Motion has a configuration file in the distribution package called motion-dist.conf. When you run 'make install' this files gets copied to the /usr/local/etc/motion directory. .br The configuration file needs to be renamed from motion-dist.conf to motion.conf. The original file is called motion-dist.conf so that your perfectly working motion.conf file does not accidentally get overwritten when you re-install or upgrade to a newer version of Motion. .br @@ -737,12 +1871,12 @@ So always call the thread config files in the end of the motion.conf file. If yo .br If motion is built without specific features such as ffmpeg, mysql etc it will ignore the options that belongs to these features. You do not have to remove them or comment them out. .br -If you run the webcontrol command http://host:port/0/config/writeyes, motion will overwrite motion.conf and all the thread.conf files by autogenerated config files neatly formatted and only with the features included that Motion was built with. If you later re-build Motion with more features or upgrade to a new version, you can use your old config files, run the motion.conf.write command, and you will have new config files with the new options included all set to their default values. This makes upgrading very easy to do. +If you run the http control command http://host:port/0/config/writeyes, motion will overwrite motion.conf and all the thread.conf files by autogenerated config files neatly formatted and only with the features included that Motion was built with. If you later re-build Motion with more features or upgrade to a new version, you can use your old config files, run the motion.conf.write command, and you will have new config files with the new options included all set to their default values. This makes upgrading very easy to do. .TP .B Conversion Specifiers for Advanced Filename and Text Features -The table below shows all the supported Conversion Specifiers you can use in the options text_left, text_right, snapshot_filename, picture_filename, movie_filename, timelapse_filename, on_area_detected, on_camera_lost, on_event_start, on_event_end, on_picture_save, on_movie_start, on_movie_end, and on_motion_detected. +The table below shows all the supported Conversion Specifiers you can use in the options text_left, text_right, snapshot_filename, jpeg_filename, ffmpeg_filename, timelapse_filename, on_event_start, on_event_end, on_picture_save, on_movie_start, on_movie_end, and on_motion_detected. .br -In text_left and text_right you can additionally use '\n' for new line. +In text_left and text_right you can additionally use '\\n' for new line. .TP .B %a @@ -782,7 +1916,7 @@ Equivalent to %Y-%m-%d (the ISO 8601 date format). The hour as a decimal number using a 24-hour clock (range 00 to 23). .TP .B %i -Width of the rectangle containing the motion pixels (the rectangle that is shown on the image when locate_motion is on). +Width of the rectangle containing the motion pixels (the rectangle that is shown on the image when locate is on). .TP .B %I The hour as a decimal number using a 12-hour clock (range 01 to 12). @@ -791,7 +1925,7 @@ The hour as a decimal number using a 12-hour clock (range 01 to 12). The day of the year as a decimal number (range 001 to 366). .TP .B %J -Height of the rectangle containing the motion pixels (the rectangle that is shown on the image when locate_motion is on). +Height of the rectangle containing the motion pixels (the rectangle that is shown on the image when locate is on). .TP .B %k The hour (24-hour clock) as a decimal number (range 0 to 23); single digits are preceded by a blank. (See also %H.) @@ -827,7 +1961,7 @@ Either 'AM' or 'PM' according to the given time value, or the corresponding stri Like %p but in lowercase: `am' or `pm' or a corresponding string for the current locale. .TP .B %q -Picture frame number within current second. For jpeg filenames this should always be included in the filename if you save more then 1 picture per second to ensure unique filenames. It is not needed in filenames for movies. +Picture frame number within current second. For jpeg filenames this should always be included in the filename if you save more then 1 picture per second to ensure unique filenames. It is not needed in filenames for mpegs. .TP .B %Q Number of detected labels found by the despeckle feature @@ -888,14 +2022,13 @@ The time zone or name or abbreviation. .TP .B More information -Motion homepage: http://motion.sourceforge.net/ +Motion homepage: https://motion-project.github.io/ Motion Guide (user and installation guide): -.br -http://www.lavrsen.dk/twiki/bin/view/Motion/MotionGuide -.br -http://www.lavrsen.dk/twiki/bin/view/Motion/VideoFourLinuxLoopbackDevice +.br /usr/share/doc/motion/motion_guide.html .SH AUTHORS Jeroen Vreeken (pe1rxq@amsat.org), Folkert van Heusden, -Kenneth Lavrsen (kenneth@lavrsen.dk) +Kenneth Lavrsen (kenneth@lavrsen.dk), +Juan Angulo Moreno , +and many others diff --git a/motion.c b/motion.c index 5666770..49a880e 100644 --- a/motion.c +++ b/motion.c @@ -9,7 +9,7 @@ #include "ffmpeg.h" #include "motion.h" -#if (defined(BSD) && !defined(PWCBSD)) +#if (defined(BSD) && !defined(PWCBSD)) #include "video_freebsd.h" #else #include "video.h" @@ -25,6 +25,7 @@ /* Forward declarations */ static int motion_init(struct context *cnt); static void motion_cleanup(struct context *cnt); +static void setup_signals(struct sigaction *, struct sigaction *); /** @@ -61,7 +62,7 @@ volatile int threads_running = 0; /* Set this when we want main to end or restart */ volatile unsigned int finish = 0; -/* Log file used instead of stderr and syslog */ +/* Log file used instead of stderr and syslog */ FILE *ptr_logfile = NULL; /** @@ -78,7 +79,7 @@ unsigned int restart = 0; * * This routine is called from motion_loop to resize the image precapture ringbuffer * NOTE: This function clears all images in the old ring buffer - + * Parameters: * * cnt Pointer to the motion context structure @@ -88,12 +89,12 @@ unsigned int restart = 0; */ static void image_ring_resize(struct context *cnt, int new_size) { - /* + /* * Only resize if : * Not in an event and * decreasing at last position in new buffer - * increasing at last position in old buffer - * e.g. at end of smallest buffer + * increasing at last position in old buffer + * e.g. at end of smallest buffer */ if (cnt->event_nr != cnt->prev_event) { int smallest; @@ -102,7 +103,7 @@ static void image_ring_resize(struct context *cnt, int new_size) smallest = new_size; else /* Increasing */ smallest = cnt->imgs.image_ring_size; - + if (cnt->imgs.image_ring_in == smallest - 1 || smallest == 0) { MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Resizing pre_capture buffer to %d items", new_size); @@ -111,13 +112,13 @@ static void image_ring_resize(struct context *cnt, int new_size) struct image_data *tmp; tmp = mymalloc(new_size * sizeof(struct image_data)); - /* - * Copy all information from old to new - * Smallest is 0 at initial init + /* + * Copy all information from old to new + * Smallest is 0 at initial init */ - if (smallest > 0) + if (smallest > 0) memcpy(tmp, cnt->imgs.image_ring, sizeof(struct image_data) * smallest); - + /* In the new buffers, allocate image memory */ { @@ -127,12 +128,13 @@ static void image_ring_resize(struct context *cnt, int new_size) memset(tmp[i].image, 0x80, cnt->imgs.size); /* initialize to grey */ } } - + /* Free the old ring */ free(cnt->imgs.image_ring); /* Point to the new ring */ cnt->imgs.image_ring = tmp; + cnt->current_image = NULL; cnt->imgs.image_ring_size = new_size; } @@ -153,27 +155,28 @@ static void image_ring_resize(struct context *cnt, int new_size) static void image_ring_destroy(struct context *cnt) { int i; - + /* Exit if don't have any ring */ if (cnt->imgs.image_ring == NULL) return; /* Free all image buffers */ - for (i = 0; i < cnt->imgs.image_ring_size; i++) + for (i = 0; i < cnt->imgs.image_ring_size; i++) free(cnt->imgs.image_ring[i].image); - - + + /* Free the ring */ free(cnt->imgs.image_ring); cnt->imgs.image_ring = NULL; + cnt->current_image = NULL; cnt->imgs.image_ring_size = 0; } /** * image_save_as_preview * - * This routine is called when we detect motion and want to save a image in the preview buffer + * This routine is called when we detect motion and want to save an image in the preview buffer * * Parameters: * @@ -195,9 +198,9 @@ static void image_save_as_preview(struct context *cnt, struct image_data *img) /* Copy image */ memcpy(cnt->imgs.preview_image.image, img->image, cnt->imgs.size); - /* + /* * If we set output_all to yes and during the event - * there is no image with motion, diffs is 0, we are not going to save the preview event + * there is no image with motion, diffs is 0, we are not going to save the preview event */ if (cnt->imgs.preview_image.diffs == 0) cnt->imgs.preview_image.diffs = 1; @@ -217,7 +220,7 @@ static void image_save_as_preview(struct context *cnt, struct image_data *img) } else if (cnt->locate_motion_style == LOCATE_REDCROSS) { alg_draw_red_location(&img->location, &cnt->imgs, cnt->imgs.width, cnt->imgs.preview_image.image, LOCATE_REDCROSS, LOCATE_NORMAL, cnt->process_thisframe); - } + } } } @@ -297,7 +300,7 @@ static void sig_handler(int signo) switch(signo) { case SIGALRM: - /* + /* * Somebody (maybe we ourself) wants us to make a snapshot * This feature triggers snapshots on ALL threads that have * snapshot_interval different from 0. @@ -305,16 +308,16 @@ static void sig_handler(int signo) if (cnt_list) { i = -1; while (cnt_list[++i]) { - if (cnt_list[i]->conf.snapshot_interval) + if (cnt_list[i]->conf.snapshot_interval) cnt_list[i]->snapshot = 1; - + } } break; case SIGUSR1: - /* + /* * Ouch! We have been hit from the outside! Someone wants us to - * make a movie! + * make a movie! */ if (cnt_list) { i = -1; @@ -324,37 +327,41 @@ static void sig_handler(int signo) break; case SIGHUP: restart = 1; - /* + /* * Fall through, as the value of 'restart' is the only difference * between SIGHUP and the ones below. */ case SIGINT: case SIGQUIT: case SIGTERM: - /* + /* * Somebody wants us to quit! We should better finish the actual - * movie and end up! + * movie and end up! */ if (cnt_list) { i = -1; while (cnt_list[++i]) { cnt_list[i]->makemovie = 1; cnt_list[i]->finish = 1; - /* - * Don't restart thread when it ends, - * all threads restarts if global restart is set + cnt_list[i]->webcontrol_finish = 1; + /* + * Don't restart thread when it ends, + * all threads restarts if global restart is set */ cnt_list[i]->restart = 0; } } /* * Set flag we want to quit main check threads loop - * if restart is set (above) we start up again + * if restart is set (above) we start up again */ finish = 1; break; case SIGSEGV: exit(0); + case SIGVTALRM: + printf("SIGVTALRM went off\n"); + break; } } @@ -380,19 +387,19 @@ static void sigchild_handler(int signo ATTRIBUTE_UNUSED) static void motion_remove_pid(void) { if ((cnt_list[0]->daemon) && (cnt_list[0]->conf.pid_file) && (restart == 0)) { - if (!unlink(cnt_list[0]->conf.pid_file)) + if (!unlink(cnt_list[0]->conf.pid_file)) MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Removed process id file (pid file)."); - else + else MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Error removing pid file"); } - if (ptr_logfile) { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Closing logfile (%s).", + if (ptr_logfile) { + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Closing logfile (%s).", cnt_list[0]->conf.log_file); myfclose(ptr_logfile); set_log_mode(LOGMODE_SYSLOG); ptr_logfile = NULL; - } + } } @@ -424,12 +431,12 @@ static void motion_detected(struct context *cnt, int dev, struct image_data *img alg_draw_red_location(location, imgs, imgs->width, img->image, LOCATE_REDBOX, LOCATE_BOTH, cnt->process_thisframe); } else if (cnt->locate_motion_style == LOCATE_CROSS) { - alg_draw_location(location, imgs, imgs->width, img->image, LOCATE_CROSS, + alg_draw_location(location, imgs, imgs->width, img->image, LOCATE_CROSS, LOCATE_BOTH, cnt->process_thisframe); } else if (cnt->locate_motion_style == LOCATE_REDCROSS) { - alg_draw_red_location(location, imgs, imgs->width, img->image, LOCATE_REDCROSS, + alg_draw_red_location(location, imgs, imgs->width, img->image, LOCATE_REDCROSS, LOCATE_BOTH, cnt->process_thisframe); - } + } } /* Calculate how centric motion is if configured preview center*/ @@ -445,7 +452,7 @@ static void motion_detected(struct context *cnt, int dev, struct image_data *img if (img->flags & IMAGE_TRIGGER) { /* Take action if this is a new event and we have a trigger image */ if (cnt->event_nr != cnt->prev_event) { - /* + /* * Reset prev_event number to current event and save event time * in both time_t and struct tm format. */ @@ -453,7 +460,7 @@ static void motion_detected(struct context *cnt, int dev, struct image_data *img cnt->eventtime = img->timestamp; localtime_r(&cnt->eventtime, cnt->eventtime_tm); - /* + /* * Since this is a new event we create the event_text_string used for * the %C conversion specifier. We may already need it for * on_motion_detected_commend so it must be done now. @@ -464,13 +471,13 @@ static void motion_detected(struct context *cnt, int dev, struct image_data *img /* EVENT_FIRSTMOTION triggers on_event_start_command and event_ffmpeg_newfile */ event(cnt, EVENT_FIRSTMOTION, img->image, NULL, NULL, &img->timestamp_tm); - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Motion detected - starting event %d", + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Motion detected - starting event %d", cnt->event_nr); /* always save first motion frame as preview-shot, may be changed to an other one later */ - if (cnt->new_img & (NEWIMG_FIRST | NEWIMG_BEST | NEWIMG_CENTER)) + if (cnt->new_img & (NEWIMG_FIRST | NEWIMG_BEST | NEWIMG_CENTER)) image_save_as_preview(cnt, img); - + } /* EVENT_MOTION triggers event_beep and on_motion_detected_command */ @@ -479,27 +486,27 @@ static void motion_detected(struct context *cnt, int dev, struct image_data *img /* Limit framerate */ if (img->shot < conf->frame_limit) { - /* + /* * If config option stream_motion is enabled, send the latest motion detected image * to the stream but only if it is not the first shot within a second. This is to * avoid double frames since we already have sent a frame to the stream. * We also disable this in setup_mode. */ - if (conf->stream_motion && !conf->setup_mode && img->shot != 1) + if (conf->stream_motion && !conf->setup_mode && img->shot != 1) event(cnt, EVENT_STREAM, img->image, NULL, NULL, &img->timestamp_tm); - /* - * Save motion jpeg, if configured - * Output the image_out (motion) picture. + /* + * Save motion jpeg, if configured + * Output the image_out (motion) picture. */ - if (conf->motion_img) + if (conf->motion_img) event(cnt, EVENT_IMAGEM_DETECTED, NULL, NULL, NULL, &img->timestamp_tm); } /* if track enabled and auto track on */ - if (cnt->track.type && cnt->track.active) + if (cnt->track.type && cnt->track.active) cnt->moved = track_move(cnt, dev, location, imgs, 0); - + } /** @@ -516,10 +523,10 @@ static void motion_detected(struct context *cnt, int dev, struct image_data *img #define IMAGE_BUFFER_FLUSH ((unsigned int)-1) static void process_image_ring(struct context *cnt, unsigned int max_images) { - /* + /* * We are going to send an event, in the events there is still * some code that use cnt->current_image - * so set it temporary to our image + * so set it temporary to our image */ struct image_data *saved_current_image = cnt->current_image; @@ -548,42 +555,47 @@ static void process_image_ring(struct context *cnt, unsigned int max_images) else t = "Other"; - mystrftime(cnt, tmp, sizeof(tmp), "%H%M%S-%q", + mystrftime(cnt, tmp, sizeof(tmp), "%H%M%S-%q", &cnt->imgs.image_ring[cnt->imgs.image_ring_out].timestamp_tm, NULL, 0); - draw_text(cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, 10, 20, + draw_text(cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, 10, 20, cnt->imgs.width, tmp, cnt->conf.text_double); - draw_text(cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, 10, 30, + draw_text(cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, 10, 30, cnt->imgs.width, t, cnt->conf.text_double); } /* Output the picture to jpegs and ffmpeg */ event(cnt, EVENT_IMAGE_DETECTED, - cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, NULL, NULL, + cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, NULL, NULL, &cnt->imgs.image_ring[cnt->imgs.image_ring_out].timestamp_tm); - /* - * Check if we must add any "filler" frames into movie to keep up fps - * Only if we are recording videos ( ffmpeg or extenal pipe ) + /* + * Check if we must add any "filler" frames into movie to keep up fps + * Only if we are recording videos ( ffmpeg or extenal pipe ) + * While the overall elapsed time might be correct, if there are + * many duplicated frames, say 10 fps, 5 duplicated, the video will + * look like it is frozen every second for half a second. */ - if ((cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot == 0) && + if (!cnt->conf.ffmpeg_duplicate_frames) { + /* don't duplicate frames */ + } else if ((cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot == 0) && #ifdef HAVE_FFMPEG (cnt->ffmpeg_output || (cnt->conf.useextpipe && cnt->extpipe))) { #else (cnt->conf.useextpipe && cnt->extpipe)) { #endif - /* + /* * movie_last_shoot is -1 when file is created, - * we don't know how many frames there is in first sec + * we don't know how many frames there is in first sec */ if (cnt->movie_last_shot >= 0) { if (cnt_list[0]->log_level >= DBG) { int frames = cnt->movie_fps - (cnt->movie_last_shot + 1); if (frames > 0) { char tmp[15]; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: Added %d fillerframes into movie", + MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: Added %d fillerframes into movie", frames); sprintf(tmp, "Fillerframes %d", frames); - draw_text(cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, 10, 40, + draw_text(cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, 10, 40, cnt->imgs.width, tmp, cnt->conf.text_double); } } @@ -591,7 +603,7 @@ static void process_image_ring(struct context *cnt, unsigned int max_images) while ((cnt->movie_last_shot + 1) < cnt->movie_fps) { /* Add a filler frame into encoder */ event(cnt, EVENT_FFMPEG_PUT, - cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, NULL, NULL, + cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, NULL, NULL, &cnt->imgs.image_ring[cnt->imgs.image_ring_out].timestamp_tm); cnt->movie_last_shot++; @@ -603,9 +615,9 @@ static void process_image_ring(struct context *cnt, unsigned int max_images) cnt->movie_last_shot = -1; } - /* + /* * Save last shot added to movie - * only when we not are within first sec + * only when we not are within first sec */ if (cnt->movie_last_shot >= 0) cnt->movie_last_shot = cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot; @@ -661,7 +673,7 @@ static void process_image_ring(struct context *cnt, unsigned int max_images) * Returns: 0 OK * -1 Fatal error, open loopback error * -2 Fatal error, open SQL database error - * -3 Fatal error, image dimensions are not modulo 16 + * -3 Fatal error, image dimensions are not modulo 8 */ static int motion_init(struct context *cnt) { @@ -678,9 +690,9 @@ static int motion_init(struct context *cnt) cnt->smartmask_speed = 0; - /* + /* * We initialize cnt->event_nr to 1 and cnt->prev_event to 0 (not really needed) so - * that certain code below does not run until motion has been detected the first time + * that certain code below does not run until motion has been detected the first time */ cnt->event_nr = 1; cnt->prev_event = 0; @@ -688,8 +700,8 @@ static int motion_init(struct context *cnt) cnt->detecting_motion = 0; cnt->makemovie = 0; - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Thread %d started , motion detection %s", - (unsigned long)pthread_getspecific(tls_key_threadnr), cnt->pause ? "Disabled":"Enabled"); + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Camera %d started: motion detection %s", + cnt->conf.camera_id, cnt->pause ? "Disabled":"Enabled"); if (!cnt->conf.filepath) cnt->conf.filepath = mystrdup("."); @@ -697,13 +709,13 @@ static int motion_init(struct context *cnt) /* set the device settings */ cnt->video_dev = vid_start(cnt); - /* + /* * We failed to get an initial image from a camera * So we need to guess height and width based on the config * file options. */ if (cnt->video_dev == -1) { - MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: Could not fetch initial image from camera " + MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: Could not fetch initial image from camera " "Motion continues using width and height from config file(s)"); cnt->imgs.width = cnt->conf.width; cnt->imgs.height = cnt->conf.height; @@ -712,7 +724,7 @@ static int motion_init(struct context *cnt) cnt->imgs.type = VIDEO_PALETTE_YUV420P; } else if (cnt->video_dev == -2) { MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: Could not fetch initial image from camera " - "Motion only supports width and height modulo 16"); + "Motion only supports width and height modulo 8"); return -3; } @@ -720,16 +732,15 @@ static int motion_init(struct context *cnt) cnt->imgs.ref = mymalloc(cnt->imgs.size); cnt->imgs.out = mymalloc(cnt->imgs.size); - memset(cnt->imgs.out, 0, cnt->imgs.size); /* contains the moving objects of ref. frame */ - cnt->imgs.ref_dyn = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.ref_dyn)); + cnt->imgs.ref_dyn = mymalloc(cnt->imgs.motionsize * sizeof(*cnt->imgs.ref_dyn)); cnt->imgs.image_virgin = mymalloc(cnt->imgs.size); cnt->imgs.smartmask = mymalloc(cnt->imgs.motionsize); cnt->imgs.smartmask_final = mymalloc(cnt->imgs.motionsize); - cnt->imgs.smartmask_buffer = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.smartmask_buffer)); - cnt->imgs.labels = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.labels)); - cnt->imgs.labelsize = mymalloc((cnt->imgs.motionsize/2+1) * sizeof(cnt->imgs.labelsize)); + cnt->imgs.smartmask_buffer = mymalloc(cnt->imgs.motionsize * sizeof(*cnt->imgs.smartmask_buffer)); + cnt->imgs.labels = mymalloc(cnt->imgs.motionsize * sizeof(*cnt->imgs.labels)); + cnt->imgs.labelsize = mymalloc((cnt->imgs.motionsize/2+1) * sizeof(*cnt->imgs.labelsize)); /* Set output picture type */ if (!strcmp(cnt->conf.picture_type, "ppm")) @@ -740,13 +751,13 @@ static int motion_init(struct context *cnt) /* allocate buffer here for preview buffer */ cnt->imgs.preview_image.image = mymalloc(cnt->imgs.size); - /* - * Allocate a buffer for temp. usage in some places - * Only despeckle & bayer2rgb24() for now for now... + /* + * Allocate a buffer for temp. usage in some places + * Only despeckle & bayer2rgb24() for now for now... */ cnt->imgs.common_buffer = mymalloc(3 * cnt->imgs.width * cnt->imgs.height); - /* + /* * Now is a good time to init rotation data. Since vid_start has been * called, we know that we have imgs.width and imgs.height. When capturing * from a V4L device, these are copied from the corresponding conf values @@ -778,7 +789,7 @@ static int motion_init(struct context *cnt) /* create a reference frame */ alg_update_reference_frame(cnt, RESET_REF_FRAME); -#if defined(HAVE_LINUX_VIDEODEV_H) && !defined(WITHOUT_V4L) && !defined(BSD) +#if defined(HAVE_LINUX_VIDEODEV_H) && !defined(WITHOUT_V4L) && !defined(BSD) /* open video loopback devices if enabled */ if (cnt->conf.vidpipe) { MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Opening video loopback device for normal pictures"); @@ -787,19 +798,19 @@ static int motion_init(struct context *cnt) cnt->pipe = vid_startpipe(cnt->conf.vidpipe, cnt->imgs.width, cnt->imgs.height, cnt->imgs.type); if (cnt->pipe < 0) { - MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Failed to open video loopback for normal pictures"); + MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Failed to open video loopback for normal pictures"); return -1; } } if (cnt->conf.motionvidpipe) { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Opening video loopback device for motion pictures"); + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Opening video loopback device for motion pictures"); /* vid_startpipe should get the output dimensions */ cnt->mpipe = vid_startpipe(cnt->conf.motionvidpipe, cnt->imgs.width, cnt->imgs.height, cnt->imgs.type); if (cnt->mpipe < 0) { - MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Failed to open video loopback for motion pictures"); + MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Failed to open video loopback for motion pictures"); return -1; } } @@ -807,35 +818,43 @@ static int motion_init(struct context *cnt) #if defined(HAVE_MYSQL) || defined(HAVE_PGSQL) || defined(HAVE_SQLITE3) if (cnt->conf.database_type) { - MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s: Database backend %s", + MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s: Database backend %s", cnt->conf.database_type); - -#ifdef HAVE_SQLITE3 - if ((!strcmp(cnt->conf.database_type, "sqlite3")) && cnt->conf.sqlite3_db) { - MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s: DB %s", - cnt->conf.sqlite3_db); - if (sqlite3_open(cnt->conf.sqlite3_db, &cnt->database_sqlite3) != SQLITE_OK) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, "%s: Can't open database %s : %s\n", - cnt->conf.sqlite3_db, sqlite3_errmsg(cnt->database_sqlite3)); +#ifdef HAVE_SQLITE3 + /* if database_sqlite3 is NULL then we are using a non threaded version of + * sqlite3 and will need a seperate connection for each thread */ + if (cnt->database_sqlite3) { + MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s: SQLite3 using shared handle"); + } else if ((!strcmp(cnt->conf.database_type, "sqlite3")) && cnt->conf.database_dbname) { + MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s: SQLite3 Database filename %s", + cnt->conf.database_dbname); + if (sqlite3_open(cnt->conf.database_dbname, &cnt->database_sqlite3) != SQLITE_OK) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, "%s: Can't open database %s : %s", + cnt->conf.database_dbname, sqlite3_errmsg(cnt->database_sqlite3)); sqlite3_close(cnt->database_sqlite3); exit(1); } + MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s: database_busy_timeout %d msec", + cnt->conf.database_busy_timeout); + if (sqlite3_busy_timeout(cnt->database_sqlite3, cnt->conf.database_busy_timeout) != SQLITE_OK) + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, "%s: database_busy_timeout failed %s", + sqlite3_errmsg(cnt->database_sqlite3)); } #endif /* HAVE_SQLITE3 */ #ifdef HAVE_MYSQL - if ((!strcmp(cnt->conf.database_type, "mysql")) && (cnt->conf.database_dbname)) { + if ((!strcmp(cnt->conf.database_type, "mysql")) && (cnt->conf.database_dbname)) { // close database to be sure that we are not leaking mysql_close(cnt->database); - cnt->database = (MYSQL *) mymalloc(sizeof(MYSQL)); + cnt->database = mymalloc(sizeof(MYSQL)); mysql_init(cnt->database); if (!mysql_real_connect(cnt->database, cnt->conf.database_host, cnt->conf.database_user, cnt->conf.database_password, cnt->conf.database_dbname, 0, NULL, 0)) { MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, "%s: Cannot connect to MySQL database %s on host %s with user %s", - cnt->conf.database_dbname, cnt->conf.database_host, + cnt->conf.database_dbname, cnt->conf.database_host, cnt->conf.database_user); MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, "%s: MySQL error was %s", mysql_error(cnt->database)); return -2; @@ -851,7 +870,7 @@ static int motion_init(struct context *cnt) if ((!strcmp(cnt->conf.database_type, "postgresql")) && (cnt->conf.database_dbname)) { char connstring[255]; - /* + /* * Create the connection string. * Quote the values so we can have null values (blank) */ @@ -872,7 +891,7 @@ static int motion_init(struct context *cnt) } } #endif /* HAVE_PGSQL */ - + /* Set the sql mask file according to the SQL config options*/ @@ -886,8 +905,8 @@ static int motion_init(struct context *cnt) /* Load the mask file if any */ if (cnt->conf.mask_file) { - if ((picture = myfopen(cnt->conf.mask_file, "r", 0))) { - /* + if ((picture = myfopen(cnt->conf.mask_file, "r"))) { + /* * NOTE: The mask is expected to have the output dimensions. I.e., the mask * applies to the already rotated image, not the capture image. Thus, use * width and height from imgs. @@ -895,19 +914,19 @@ static int motion_init(struct context *cnt) cnt->imgs.mask = get_pgm(picture, cnt->imgs.width, cnt->imgs.height); myfclose(picture); } else { - MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Error opening mask file %s", + MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Error opening mask file %s", cnt->conf.mask_file); - /* + /* * Try to write an empty mask file to make it easier - * for the user to edit it + * for the user to edit it */ put_fixed_mask(cnt, cnt->conf.mask_file); } if (!cnt->imgs.mask) { - MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Failed to read mask image. Mask feature disabled."); + MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Failed to read mask image. Mask feature disabled."); } else { - MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, "%s: Maskfile \"%s\" loaded.", + MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, "%s: Maskfile \"%s\" loaded.", cnt->conf.mask_file); } } else { @@ -917,7 +936,7 @@ static int motion_init(struct context *cnt) /* Always initialize smart_mask - someone could turn it on later... */ memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize); memset(cnt->imgs.smartmask_final, 255, cnt->imgs.motionsize); - memset(cnt->imgs.smartmask_buffer, 0, cnt->imgs.motionsize*sizeof(cnt->imgs.smartmask_buffer)); + memset(cnt->imgs.smartmask_buffer, 0, cnt->imgs.motionsize * sizeof(*cnt->imgs.smartmask_buffer)); /* Set noise level */ cnt->noise = cnt->conf.noise; @@ -928,13 +947,13 @@ static int motion_init(struct context *cnt) /* Initialize stream server if stream port is specified to not 0 */ if (cnt->conf.stream_port) { if (stream_init(cnt) == -1) { - MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Problem enabling motion-stream server in port %d", + MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Problem enabling motion-stream server in port %d", cnt->conf.stream_port); cnt->finish = 1; - } else { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Started motion-stream server in port %d auth %s", + } else { + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Started motion-stream server in port %d auth %s", cnt->conf.stream_port, cnt->conf.stream_auth_method ? "Enabled":"Disabled"); - } + } } /* Prevent first few frames from triggering motion... */ @@ -962,65 +981,51 @@ static void motion_cleanup(struct context *cnt) /* Stop stream */ event(cnt, EVENT_STOP, NULL, NULL, NULL, NULL); +#ifdef HAVE_FFMPEG + event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, NULL); + event(cnt, EVENT_ENDMOTION, NULL, NULL, NULL, NULL); +#endif // HAVE_FFMPEG + if (cnt->video_dev >= 0) { - MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, "%s: Calling vid_close() from motion_cleanup"); + MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, "%s: Calling vid_close() from motion_cleanup"); vid_close(cnt); } - if (cnt->imgs.out) { - free(cnt->imgs.out); - cnt->imgs.out = NULL; - } + free(cnt->imgs.out); + cnt->imgs.out = NULL; - if (cnt->imgs.ref) { - free(cnt->imgs.ref); - cnt->imgs.ref = NULL; - } + free(cnt->imgs.ref); + cnt->imgs.ref = NULL; - if (cnt->imgs.ref_dyn) { - free(cnt->imgs.ref_dyn); - cnt->imgs.ref_dyn = NULL; - } + free(cnt->imgs.ref_dyn); + cnt->imgs.ref_dyn = NULL; - if (cnt->imgs.image_virgin) { - free(cnt->imgs.image_virgin); - cnt->imgs.image_virgin = NULL; - } + free(cnt->imgs.image_virgin); + cnt->imgs.image_virgin = NULL; - if (cnt->imgs.labels) { - free(cnt->imgs.labels); - cnt->imgs.labels = NULL; - } + free(cnt->imgs.labels); + cnt->imgs.labels = NULL; - if (cnt->imgs.labelsize) { - free(cnt->imgs.labelsize); - cnt->imgs.labelsize = NULL; - } + free(cnt->imgs.labelsize); + cnt->imgs.labelsize = NULL; - if (cnt->imgs.smartmask) { - free(cnt->imgs.smartmask); - cnt->imgs.smartmask = NULL; - } + free(cnt->imgs.smartmask); + cnt->imgs.smartmask = NULL; - if (cnt->imgs.smartmask_final) { - free(cnt->imgs.smartmask_final); - cnt->imgs.smartmask_final = NULL; - } + free(cnt->imgs.smartmask_final); + cnt->imgs.smartmask_final = NULL; - if (cnt->imgs.smartmask_buffer) { - free(cnt->imgs.smartmask_buffer); - cnt->imgs.smartmask_buffer = NULL; - } + free(cnt->imgs.smartmask_buffer); + cnt->imgs.smartmask_buffer = NULL; - if (cnt->imgs.common_buffer) { - free(cnt->imgs.common_buffer); - cnt->imgs.common_buffer = NULL; - } + if (cnt->imgs.mask) free(cnt->imgs.mask); + cnt->imgs.mask = NULL; - if (cnt->imgs.preview_image.image) { - free(cnt->imgs.preview_image.image); - cnt->imgs.preview_image.image = NULL; - } + free(cnt->imgs.common_buffer); + cnt->imgs.common_buffer = NULL; + + free(cnt->imgs.preview_image.image); + cnt->imgs.preview_image.image = NULL; image_ring_destroy(cnt); /* Cleanup the precapture ring buffer */ @@ -1037,21 +1042,17 @@ static void motion_cleanup(struct context *cnt) } /* Cleanup the current time structure */ - if (cnt->currenttime_tm) { - free(cnt->currenttime_tm); - cnt->currenttime_tm = NULL; - } + free(cnt->currenttime_tm); + cnt->currenttime_tm = NULL; /* Cleanup the event time structure */ - if (cnt->eventtime_tm) { - free(cnt->eventtime_tm); - cnt->eventtime_tm = NULL; - } + free(cnt->eventtime_tm); + cnt->eventtime_tm = NULL; if (cnt->conf.database_type) { #ifdef HAVE_MYSQL - if ( (!strcmp(cnt->conf.database_type, "mysql")) && (cnt->conf.database_dbname)) { - mysql_close(cnt->database); + if ( (!strcmp(cnt->conf.database_type, "mysql")) && (cnt->conf.database_dbname)) { + mysql_close(cnt->database); } #endif /* HAVE_MYSQL */ @@ -1059,12 +1060,13 @@ static void motion_cleanup(struct context *cnt) if ((!strcmp(cnt->conf.database_type, "postgresql")) && (cnt->conf.database_dbname)) { PQfinish(cnt->database_pg); } -#endif /* HAVE_PGSQL */ +#endif /* HAVE_PGSQL */ -#ifdef HAVE_SQLITE3 +#ifdef HAVE_SQLITE3 /* Close the SQLite database */ - if (cnt->conf.sqlite3_db) + if ((!strcmp(cnt->conf.database_type, "sqlite3")) && (cnt->conf.database_dbname)) { sqlite3_close(cnt->database_sqlite3); + } #endif /* HAVE_SQLITE3 */ } } @@ -1102,18 +1104,27 @@ static void *motion_loop(void *arg) unsigned int get_image = 1; /* Flag used to signal that we capture new image when we run the loop */ struct image_data *old_image; - /* +#ifdef HAVE_PTHREAD_SETNAME_NP + { + char tname[16]; + snprintf(tname, sizeof(tname), "ml%d%s%s", + cnt->threadnr, + cnt->conf.camera_name ? ":" : "", + cnt->conf.camera_name ? cnt->conf.camera_name : ""); + pthread_setname_np(pthread_self(), tname); + } +#endif + + /* * Next two variables are used for snapshot and timelapse feature * time_last_frame is set to 1 so that first coming timelapse or second = 0 * is acted upon. */ unsigned long int time_last_frame = 1, time_current_frame; - cnt->running = 1; - - if (motion_init(cnt) < 0) + if (motion_init(cnt) < 0) goto err; - + /* Initialize the double sized characters if needed. */ if (cnt->conf.text_double) @@ -1139,9 +1150,9 @@ static void *motion_loop(void *arg) area_maxx[2] = area_maxx[5] = area_maxx[8] = cnt->imgs.width; area_maxy[6] = area_maxy[7] = area_maxy[8] = cnt->imgs.height; - + /* Work out expected frame rate based on config setting */ - if (cnt->conf.frame_limit < 2) + if (cnt->conf.frame_limit < 2) cnt->conf.frame_limit = 2; required_frame_time = 1000000L / cnt->conf.frame_limit; @@ -1164,8 +1175,8 @@ static void *motion_loop(void *arg) cnt->moved = track_center(cnt, cnt->video_dev, 0, 0, 0); #ifdef __OpenBSD__ - /* - * FIXMARK + /* + * FIXMARK * Fixes zombie issue on OpenBSD 4.6 */ struct sigaction sig_handler_action; @@ -1174,8 +1185,8 @@ static void *motion_loop(void *arg) #endif /* - * MAIN MOTION LOOP BEGINS HERE - * Should go on forever... unless you bought vaporware :) + * MAIN MOTION LOOP BEGINS HERE + * Should go on forever... unless you bought vaporware :) */ while (!cnt->finish || cnt->makemovie) { @@ -1188,9 +1199,9 @@ static void *motion_loop(void *arg) gettimeofday(&tv1, NULL); timenow = tv1.tv_usec + 1000000L * tv1.tv_sec; - /* + /* * Calculate detection rate limit. Above 5fps we limit the detection - * rate to 3fps to reduce load at higher framerates. + * rate to 3fps to reduce load at higher framerates. */ cnt->process_thisframe = 0; rate_limit++; @@ -1199,10 +1210,10 @@ static void *motion_loop(void *arg) cnt->process_thisframe = 1; } - /* + /* * Since we don't have sanity checks done when options are set, * this sanity check must go in the main loop :(, before pre_captures - * are attempted. + * are attempted. */ if (cnt->conf.minimum_motion_frames < 1) cnt->conf.minimum_motion_frames = 1; @@ -1210,26 +1221,26 @@ static void *motion_loop(void *arg) if (cnt->conf.pre_capture < 0) cnt->conf.pre_capture = 0; - /* + /* * Check if our buffer is still the right size * If pre_capture or minimum_motion_frames has been changed * via the http remote control we need to re-size the ring buffer */ frame_buffer_size = cnt->conf.pre_capture + cnt->conf.minimum_motion_frames; - if (cnt->imgs.image_ring_size != frame_buffer_size) + if (cnt->imgs.image_ring_size != frame_buffer_size) image_ring_resize(cnt, frame_buffer_size); - + /* Get time for current frame */ cnt->currenttime = time(NULL); - /* + /* * localtime returns static data and is not threadsafe * so we use localtime_r which is reentrant and threadsafe */ localtime_r(&cnt->currenttime, cnt->currenttime_tm); - /* + /* * If we have started on a new second we reset the shots variable * lastrate is updated to be the number of the last frame. last rate * is used as the ffmpeg framerate when motion is detected. @@ -1238,14 +1249,14 @@ static void *motion_loop(void *arg) cnt->lastrate = cnt->shots + 1; cnt->shots = -1; lastframetime = cnt->currenttime; - + if (cnt->conf.minimum_frame_time) { minimum_frame_time_downcounter--; if (minimum_frame_time_downcounter == 0) get_image = 1; } else { get_image = 1; - } + } } @@ -1294,7 +1305,7 @@ static void *motion_loop(void *arg) cnt->current_image->timestamp_tm = old_image->timestamp_tm; cnt->current_image->shot = old_image->shot; cnt->current_image->cent_dist = old_image->cent_dist; - cnt->current_image->flags = old_image->flags; + cnt->current_image->flags = old_image->flags & (~IMAGE_SAVED); cnt->current_image->location = old_image->location; cnt->current_image->total_labels = old_image->total_labels; } @@ -1307,7 +1318,7 @@ static void *motion_loop(void *arg) cnt->current_image->shot = cnt->shots; /***** MOTION LOOP - RETRY INITIALIZING SECTION *****/ - /* + /* * If a camera is not available we keep on retrying every 10 seconds * until it shows up. */ @@ -1317,7 +1328,7 @@ static void *motion_loop(void *arg) "%s: Retrying until successful connection with camera"); cnt->video_dev = vid_start(cnt); - /* + /* * If the netcam has different dimensions than in the config file * we need to restart Motion to re-allocate all the buffers */ @@ -1329,9 +1340,9 @@ static void *motion_loop(void *arg) "image buffers to new picture dimensions"); cnt->conf.width = cnt->imgs.width; cnt->conf.height = cnt->imgs.height; - /* - * Break out of main loop terminating thread - * watchdog will start us again + /* + * Break out of main loop terminating thread + * watchdog will start us again */ break; } @@ -1340,7 +1351,7 @@ static void *motion_loop(void *arg) /***** MOTION LOOP - IMAGE CAPTURE SECTION *****/ - /* + /* * Fetch next frame from camera * If vid_next returns 0 all is well and we got a new picture * Any non zero value is an error. @@ -1366,19 +1377,13 @@ static void *motion_loop(void *arg) } cnt->missing_frame_counter = 0; -#ifdef HAVE_FFMPEG - /* Deinterlace the image with ffmpeg, before the image is modified. */ - if (cnt->conf.ffmpeg_deinterlace) - ffmpeg_deinterlace(cnt->current_image->image, cnt->imgs.width, cnt->imgs.height); -#endif - - /* + /* * Save the newly captured still virgin image to a buffer * which we will not alter with text and location graphics */ memcpy(cnt->imgs.image_virgin, cnt->current_image->image, cnt->imgs.size); - /* + /* * If the camera is a netcam we let the camera decide the pace. * Otherwise we will keep on adding duplicate frames. * By resetting the timer the framerate becomes maximum the rate @@ -1388,31 +1393,31 @@ static void *motion_loop(void *arg) gettimeofday(&tv1, NULL); timenow = tv1.tv_usec + 1000000L * tv1.tv_sec; } - // FATAL ERROR - leave the thread by breaking out of the main loop + // FATAL ERROR - leave the thread by breaking out of the main loop } else if (vid_return_code < 0) { /* Fatal error - Close video device */ - MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Video device fatal error - Closing video device"); + MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Video device fatal error - Closing video device"); vid_close(cnt); - /* + /* * Use virgin image, if we are not able to open it again next loop * a gray image with message is applied * flag lost_connection */ memcpy(cnt->current_image->image, cnt->imgs.image_virgin, cnt->imgs.size); cnt->lost_connection = 1; - /* NO FATAL ERROR - - * copy last image or show grey image with message + /* NO FATAL ERROR - + * copy last image or show grey image with message * flag on lost_connection if : - * vid_return_code == NETCAM_RESTART_ERROR + * vid_return_code == NETCAM_RESTART_ERROR * cnt->video_dev < 0 * cnt->missing_frame_counter > (MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) - */ - } else { + */ + } else { - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: vid_return_code %d", + MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: vid_return_code %d", vid_return_code); - /* + /* * Netcams that change dimensions while Motion is running will * require that Motion restarts to reinitialize all the many * buffers inside Motion. It will be a mess to try and recover any @@ -1421,24 +1426,24 @@ static void *motion_loop(void *arg) if (vid_return_code == NETCAM_RESTART_ERROR) { MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Restarting Motion thread to reinitialize all " "image buffers"); - /* - * Break out of main loop terminating thread - * watchdog will start us again - * Set lost_connection flag on + /* + * Break out of main loop terminating thread + * watchdog will start us again + * Set lost_connection flag on */ cnt->lost_connection = 1; break; } - /* - * First missed frame - store timestamp + /* + * First missed frame - store timestamp * Don't reset time when thread restarts */ if (cnt->connectionlosttime == 0) cnt->connectionlosttime = cnt->currenttime; - /* + /* * Increase missing_frame_counter * The first MISSING_FRAMES_TIMEOUT seconds we copy previous virgin image * After MISSING_FRAMES_TIMEOUT seconds we put a grey error image in the buffer @@ -1455,7 +1460,7 @@ static void *motion_loop(void *arg) char tmpout[80]; struct tm tmptime; cnt->lost_connection = 1; - + if (cnt->video_dev >= 0) tmpin = "CONNECTION TO CAMERA LOST\\nSINCE %Y-%m-%d %T"; else @@ -1469,17 +1474,17 @@ static void *motion_loop(void *arg) /* Write error message only once */ if (cnt->missing_frame_counter == MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Video signal lost - Adding grey image"); + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Video signal lost - Adding grey image"); // Event for lost video signal can be called from here event(cnt, EVENT_CAMERA_LOST, NULL, NULL, NULL, cnt->currenttime_tm); } - /* - * If we don't get a valid frame for a long time, try to close/reopen device - * Only try this when a device is open + /* + * If we don't get a valid frame for a long time, try to close/reopen device + * Only try this when a device is open */ - if ((cnt->video_dev > 0) && + if ((cnt->video_dev > 0) && (cnt->missing_frame_counter == (MISSING_FRAMES_TIMEOUT * 4) * cnt->conf.frame_limit)) { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Video signal still lost - " "Trying to close video device"); @@ -1490,7 +1495,7 @@ static void *motion_loop(void *arg) /***** MOTION LOOP - MOTION DETECTION SECTION *****/ - /* + /* * The actual motion detection takes place in the following * diffs is the number of pixels detected as changed * Make a differences picture in image_out @@ -1502,7 +1507,7 @@ static void *motion_loop(void *arg) */ if (cnt->process_thisframe) { if (cnt->threshold && !cnt->pause) { - /* + /* * If we've already detected motion and we want to see if there's * still motion, don't bother trying the fast one first. IF there's * motion, the alg_diff will trigger alg_diff_standard @@ -1521,7 +1526,7 @@ static void *motion_loop(void *arg) */ if (cnt->conf.lightswitch > 1 && !cnt->lost_connection) { if (alg_lightswitch(cnt, cnt->current_image->diffs)) { - MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, "%s: Lightswitch detected"); + MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, "%s: Lightswitch detected"); if (cnt->moved < 5) cnt->moved = 5; @@ -1531,7 +1536,7 @@ static void *motion_loop(void *arg) } } - /* + /* * Switchfilter feature tries to detect a change in the video signal * from one camera to the next. This is normally used in the Round * Robin feature. The algorithm is not very safe. @@ -1541,17 +1546,17 @@ static void *motion_loop(void *arg) * because with Round Robin this is controlled by roundrobin_skip. */ if (cnt->conf.switchfilter && cnt->current_image->diffs > cnt->threshold) { - cnt->current_image->diffs = alg_switchfilter(cnt, cnt->current_image->diffs, + cnt->current_image->diffs = alg_switchfilter(cnt, cnt->current_image->diffs, cnt->current_image->image); - + if (cnt->current_image->diffs <= cnt->threshold) { cnt->current_image->diffs = 0; - + MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, "%s: Switchfilter detected"); } } - /* + /* * Despeckle feature * First we run (as given by the despeckle_filter option iterations * of erode and dilate algorithms. @@ -1561,7 +1566,7 @@ static void *motion_loop(void *arg) cnt->current_image->total_labels = 0; cnt->imgs.largest_label = 0; olddiffs = 0; - + if (cnt->conf.despeckle_filter && cnt->current_image->diffs > 0) { olddiffs = cnt->current_image->diffs; cnt->current_image->diffs = alg_despeckle(cnt, olddiffs); @@ -1575,13 +1580,13 @@ static void *motion_loop(void *arg) } /* Manipulate smart_mask sensitivity (only every smartmask_ratio seconds) */ - if ((cnt->smartmask_speed && (cnt->event_nr != cnt->prev_event)) && + if ((cnt->smartmask_speed && (cnt->event_nr != cnt->prev_event)) && (!--smartmask_count)) { alg_tune_smartmask(cnt); smartmask_count = smartmask_ratio; } - /* + /* * cnt->moved is set by the tracking code when camera has been asked to move. * When camera is moving we do not want motion to detect motion or we will * get our camera chasing itself like crazy and we will get motion detected @@ -1597,16 +1602,16 @@ static void *motion_loop(void *arg) /***** MOTION LOOP - TUNING SECTION *****/ - /* + /* * If noise tuning was selected, do it now. but only when * no frames have been recorded and only once per second */ if ((cnt->conf.noise_tune && cnt->shots == 0) && (!cnt->detecting_motion && (cnt->current_image->diffs <= cnt->threshold))) alg_noise_tune(cnt, cnt->imgs.image_virgin); - - /* + + /* * If we are not noise tuning lets make sure that remote controlled * changes of noise_level are used. */ @@ -1614,7 +1619,7 @@ static void *motion_loop(void *arg) if (!cnt->conf.noise_tune) cnt->noise = cnt->conf.noise; - /* + /* * threshold tuning if enabled * if we are not threshold tuning lets make sure that remote controlled * changes of threshold are used. @@ -1624,20 +1629,20 @@ static void *motion_loop(void *arg) else cnt->threshold = cnt->conf.max_changes; - /* + /* * If motion is detected (cnt->current_image->diffs > cnt->threshold) and before we add text to the pictures * we find the center and size coordinates of the motion to be used for text overlays and later - * for adding the locate rectangle + * for adding the locate rectangle */ if (cnt->current_image->diffs > cnt->threshold) alg_locate_center_size(&cnt->imgs, cnt->imgs.width, cnt->imgs.height, &cnt->current_image->location); - /* - * Update reference frame. - * micro-lighswitch: trying to auto-detect lightswitch events. - * frontdoor illumination. Updates are rate-limited to 3 per second at - * framerates above 5fps to save CPU resources and to keep sensitivity - * at a constant level. + /* + * Update reference frame. + * micro-lighswitch: trying to auto-detect lightswitch events. + * frontdoor illumination. Updates are rate-limited to 3 per second at + * framerates above 5fps to save CPU resources and to keep sensitivity + * at a constant level. */ if ((cnt->current_image->diffs > cnt->threshold) && (cnt->conf.lightswitch == 1) && @@ -1651,7 +1656,7 @@ static void *motion_loop(void *arg) cnt->current_image->diffs = 0; cnt->lightswitch_framecounter = 0; - MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, "%s: micro-lightswitch!"); + MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, "%s: micro-lightswitch!"); } else { alg_update_reference_frame(cnt, UPDATE_REF_FRAME); } @@ -1663,7 +1668,7 @@ static void *motion_loop(void *arg) /***** MOTION LOOP - TEXT AND GRAPHICS OVERLAY SECTION *****/ - /* + /* * Some overlays on top of the motion image * Note that these now modifies the cnt->imgs.out so this buffer * can no longer be used for motion detection features until next @@ -1671,17 +1676,17 @@ static void *motion_loop(void *arg) */ /* Smartmask overlay */ - if (cnt->smartmask_speed && (cnt->conf.motion_img || cnt->conf.ffmpeg_output_debug || + if (cnt->smartmask_speed && (cnt->conf.motion_img || cnt->conf.ffmpeg_output_debug || cnt->conf.setup_mode)) overlay_smartmask(cnt, cnt->imgs.out); /* Largest labels overlay */ - if (cnt->imgs.largest_label && (cnt->conf.motion_img || cnt->conf.ffmpeg_output_debug || + if (cnt->imgs.largest_label && (cnt->conf.motion_img || cnt->conf.ffmpeg_output_debug || cnt->conf.setup_mode)) overlay_largest_label(cnt, cnt->imgs.out); /* Fixed mask overlay */ - if (cnt->imgs.mask && (cnt->conf.motion_img || cnt->conf.ffmpeg_output_debug || + if (cnt->imgs.mask && (cnt->conf.motion_img || cnt->conf.ffmpeg_output_debug || cnt->conf.setup_mode)) overlay_fixed_mask(cnt, cnt->imgs.out); @@ -1702,17 +1707,17 @@ static void *motion_loop(void *arg) else sprintf(tmp, "-"); - draw_text(cnt->current_image->image, cnt->imgs.width - 10, 10, + draw_text(cnt->current_image->image, cnt->imgs.width - 10, 10, cnt->imgs.width, tmp, cnt->conf.text_double); } - /* + /* * Add changed pixels to motion-images (for stream) in setup_mode - * and always overlay smartmask (not only when motion is detected) + * and always overlay smartmask (not only when motion is detected) */ if (cnt->conf.setup_mode) { char tmp[PATH_MAX]; - sprintf(tmp, "D:%5d L:%3d N:%3d", cnt->current_image->diffs, + sprintf(tmp, "D:%5d L:%3d N:%3d", cnt->current_image->diffs, cnt->current_image->total_labels, cnt->noise); draw_text(cnt->imgs.out, cnt->imgs.width - 10, cnt->imgs.height - 30 * text_size_factor, cnt->imgs.width, tmp, cnt->conf.text_double); @@ -1724,18 +1729,18 @@ static void *motion_loop(void *arg) /* Add text in lower left corner of the pictures */ if (cnt->conf.text_left) { char tmp[PATH_MAX]; - mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_left, + mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_left, &cnt->current_image->timestamp_tm, NULL, 0); - draw_text(cnt->current_image->image, 10, cnt->imgs.height - 10 * text_size_factor, + draw_text(cnt->current_image->image, 10, cnt->imgs.height - 10 * text_size_factor, cnt->imgs.width, tmp, cnt->conf.text_double); } /* Add text in lower right corner of the pictures */ if (cnt->conf.text_right) { char tmp[PATH_MAX]; - mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_right, + mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_right, &cnt->current_image->timestamp_tm, NULL, 0); - draw_text(cnt->current_image->image, cnt->imgs.width - 10, + draw_text(cnt->current_image->image, cnt->imgs.width - 10, cnt->imgs.height - 10 * text_size_factor, cnt->imgs.width, tmp, cnt->conf.text_double); } @@ -1747,11 +1752,11 @@ static void *motion_loop(void *arg) /* flag this image, it have motion */ cnt->current_image->flags |= IMAGE_MOTION; cnt->lightswitch_framecounter++; /* micro lightswitch */ - } else { + } else { cnt->lightswitch_framecounter = 0; - } + } - /* + /* * If motion has been detected we take action and start saving * pictures and movies etc by calling motion_detected(). * Is emulate_motion enabled we always call motion_detected() @@ -1768,14 +1773,14 @@ static void *motion_loop(void *arg) #endif /* Setup the postcap counter */ cnt->postcap = cnt->conf.post_capture; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: (Em) Init post capture %d", + MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: (Em) Init post capture %d", cnt->postcap); } cnt->current_image->flags |= (IMAGE_TRIGGER | IMAGE_SAVE); motion_detected(cnt, cnt->video_dev, cnt->current_image); } else if ((cnt->current_image->flags & IMAGE_MOTION) && (cnt->startup_frames == 0)) { - /* + /* * Did we detect motion (like the cat just walked in :) )? * If so, ensure the motion is sustained if minimum_motion_frames */ @@ -1785,13 +1790,13 @@ static void *motion_loop(void *arg) int pos = cnt->imgs.image_ring_in; for (i = 0; i < cnt->conf.minimum_motion_frames; i++) { - + if (cnt->imgs.image_ring[pos].flags & IMAGE_MOTION) frame_count++; - if (pos == 0) + if (pos == 0) pos = cnt->imgs.image_ring_size-1; - else + else pos--; } @@ -1802,23 +1807,23 @@ static void *motion_loop(void *arg) /* Setup the postcap counter */ cnt->postcap = cnt->conf.post_capture; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: Setup post capture %d", + MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: Setup post capture %d", cnt->postcap); /* Mark all images in image_ring to be saved */ - for (i = 0; i < cnt->imgs.image_ring_size; i++) + for (i = 0; i < cnt->imgs.image_ring_size; i++) cnt->imgs.image_ring[i].flags |= IMAGE_SAVE; - - } else if ((cnt->postcap) && + + } else if ((cnt->postcap) && #ifdef HAVE_FFMPEG (cnt->ffmpeg_output || (cnt->conf.useextpipe && cnt->extpipe))) { #else - (cnt->conf.useextpipe && cnt->extpipe)) { -#endif + (cnt->conf.useextpipe && cnt->extpipe)) { +#endif /* we have motion in this frame, but not enought frames for trigger. Check postcap */ cnt->current_image->flags |= (IMAGE_POSTCAP | IMAGE_SAVE); cnt->postcap--; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: post capture %d", + MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: post capture %d", cnt->postcap); } else { cnt->current_image->flags |= IMAGE_PRECAP; @@ -1826,16 +1831,16 @@ static void *motion_loop(void *arg) /* Always call motion_detected when we have a motion image */ motion_detected(cnt, cnt->video_dev, cnt->current_image); - } else if ((cnt->postcap) && + } else if ((cnt->postcap) && #ifdef HAVE_FFMPEG (cnt->ffmpeg_output || (cnt->conf.useextpipe && cnt->extpipe))) { #else - (cnt->conf.useextpipe && cnt->extpipe)) { + (cnt->conf.useextpipe && cnt->extpipe)) { #endif /* No motion, doing postcap */ cnt->current_image->flags |= (IMAGE_POSTCAP | IMAGE_SAVE); cnt->postcap--; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: post capture %d", + MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, "%s: post capture %d", cnt->postcap); } else { /* Done with postcap, so just have the image in the precap buffer */ @@ -1847,18 +1852,18 @@ static void *motion_loop(void *arg) } /* Update last frame saved time, so we can end event after gap time */ - if (cnt->current_image->flags & IMAGE_SAVE) + if (cnt->current_image->flags & IMAGE_SAVE) cnt->lasttime = cnt->current_image->timestamp; - - /* - * Simple hack to recognize motion in a specific area - * Do we need a new coversion specifier as well?? + + /* + * Simple hack to recognize motion in a specific area + * Do we need a new coversion specifier as well?? */ - if ((cnt->conf.area_detect) && (cnt->event_nr != area_once) && + if ((cnt->conf.area_detect) && (cnt->event_nr != area_once) && (cnt->current_image->flags & IMAGE_TRIGGER)) { j = strlen(cnt->conf.area_detect); - + for (i = 0; i < j; i++) { z = cnt->conf.area_detect[i] - 49; /* 1 becomes 0 */ if ((z >= 0) && (z < 9)) { @@ -1877,8 +1882,8 @@ static void *motion_loop(void *arg) } } } - - /* + + /* * Is the movie too long? Then make movies * First test for max_movie_time */ @@ -1886,11 +1891,11 @@ static void *motion_loop(void *arg) (cnt->currenttime - cnt->eventtime >= cnt->conf.max_movie_time)) cnt->makemovie = 1; - /* + /* * Now test for quiet longer than 'gap' OR make movie as decided in * previous statement. */ - if (((cnt->currenttime - cnt->lasttime >= cnt->conf.event_gap) && cnt->conf.event_gap > 0) || + if (((cnt->currenttime - cnt->lasttime >= cnt->conf.event_gap) && cnt->conf.event_gap > 0) || cnt->makemovie) { if (cnt->event_nr == cnt->prev_event || cnt->makemovie) { @@ -1905,14 +1910,14 @@ static void *motion_loop(void *arg) event(cnt, EVENT_ENDMOTION, NULL, NULL, NULL, cnt->currenttime_tm); - /* + /* * If tracking is enabled we center our camera so it does not * point to a place where it will miss the next action */ if (cnt->track.type) cnt->moved = track_center(cnt, cnt->video_dev, 0, 0, 0); - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: End of event %d", + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: End of event %d", cnt->event_nr); cnt->makemovie = 0; @@ -1923,7 +1928,7 @@ static void *motion_loop(void *arg) cnt->event_nr++; cnt->lightswitch_framecounter = 0; - /* + /* * And we unset the text_event_string to avoid that buffered * images get a timestamp from previous event. */ @@ -1971,7 +1976,7 @@ static void *motion_loop(void *arg) /***** MOTION LOOP - SNAPSHOT FEATURE SECTION *****/ - /* + /* * Did we get triggered to make a snapshot from control http? Then shoot a snap * If snapshot_interval is not zero and time since epoch MOD snapshot_interval = 0 then snap * We actually allow the time to run over the interval in case we have a delay @@ -1997,7 +2002,7 @@ static void *motion_loop(void *arg) if (cnt->conf.timelapse) { - /* + /* * Check to see if we should start a new timelapse file. We start one when * we are on the first shot, and and the seconds are zero. We must use the seconds * to prevent the timelapse file from getting reset multiple times during the minute. @@ -2017,44 +2022,44 @@ static void *motion_loop(void *arg) /* handle the hourly case */ } else if (strcasecmp(cnt->conf.timelapse_mode, "hourly") == 0) { event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); - - /* If we are weekly-sunday, raise timelapseend event at midnight on sunday */ + + /* If we are weekly-sunday, raise timelapseend event at midnight on sunday */ } else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-sunday") == 0) { - if (cnt->current_image->timestamp_tm.tm_wday == 0 && + if (cnt->current_image->timestamp_tm.tm_wday == 0 && cnt->current_image->timestamp_tm.tm_hour == 0) - event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, + event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); - /* If we are weekly-monday, raise timelapseend event at midnight on monday */ + /* If we are weekly-monday, raise timelapseend event at midnight on monday */ } else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-monday") == 0) { - if (cnt->current_image->timestamp_tm.tm_wday == 1 && + if (cnt->current_image->timestamp_tm.tm_wday == 1 && cnt->current_image->timestamp_tm.tm_hour == 0) - event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, + event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); - /* If we are monthly, raise timelapseend event at midnight on first day of month */ + /* If we are monthly, raise timelapseend event at midnight on first day of month */ } else if (strcasecmp(cnt->conf.timelapse_mode, "monthly") == 0) { - if (cnt->current_image->timestamp_tm.tm_mday == 1 && + if (cnt->current_image->timestamp_tm.tm_mday == 1 && cnt->current_image->timestamp_tm.tm_hour == 0) - event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, + event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); - /* If invalid we report in syslog once and continue in manual mode */ + /* If invalid we report in syslog once and continue in manual mode */ } else { MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Invalid timelapse_mode argument '%s'", cnt->conf.timelapse_mode); - MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%:s Defaulting to manual timelapse mode"); + MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%:s Defaulting to manual timelapse mode"); conf_cmdparse(&cnt, (char *)"ffmpeg_timelapse_mode",(char *)"manual"); } } - /* + /* * If ffmpeg timelapse is enabled and time since epoch MOD ffmpeg_timelaps = 0 * add a timelapse frame to the timelapse movie. */ - if (cnt->shots == 0 && time_current_frame % cnt->conf.timelapse <= + if (cnt->shots == 0 && time_current_frame % cnt->conf.timelapse <= time_last_frame % cnt->conf.timelapse) - event(cnt, EVENT_TIMELAPSE, cnt->current_image->image, NULL, NULL, + event(cnt, EVENT_TIMELAPSE, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); } else if (cnt->ffmpeg_timelapse) { - /* + /* * If timelapse movie is in progress but conf.timelapse is zero then close timelapse file * This is an important feature that allows manual roll-over of timelapse file using the http * remote control via a cron job. @@ -2069,7 +2074,7 @@ static void *motion_loop(void *arg) /***** MOTION LOOP - VIDEO LOOPBACK SECTION *****/ - /* + /* * Feed last image and motion image to video device pipes and the stream clients * In setup mode we send the special setup mode image to both stream and vloopback pipe * In normal mode we feed the latest image to vloopback device and we send @@ -2087,11 +2092,11 @@ static void *motion_loop(void *arg) event(cnt, EVENT_SDL_PUT, cnt->imgs.out, NULL, NULL, cnt->currenttime_tm); #endif } else { - event(cnt, EVENT_IMAGE, cnt->current_image->image, NULL, + event(cnt, EVENT_IMAGE, cnt->current_image->image, NULL, &cnt->pipe, &cnt->current_image->timestamp_tm); if (!cnt->conf.stream_motion || cnt->shots == 1) - event(cnt, EVENT_STREAM, cnt->current_image->image, NULL, NULL, + 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) @@ -2141,7 +2146,7 @@ static void *motion_loop(void *arg) cnt->conf.smart_mask_speed = 0; /* Has someone changed smart_mask_speed or framerate? */ - if (cnt->conf.smart_mask_speed != cnt->smartmask_speed || + if (cnt->conf.smart_mask_speed != cnt->smartmask_speed || smartmask_lastrate != cnt->lastrate) { if (cnt->conf.smart_mask_speed == 0) { memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize); @@ -2150,16 +2155,16 @@ static void *motion_loop(void *arg) smartmask_lastrate = cnt->lastrate; cnt->smartmask_speed = cnt->conf.smart_mask_speed; - /* + /* * Decay delay - based on smart_mask_speed (framerate independent) - * This is always 5*smartmask_speed seconds + * This is always 5*smartmask_speed seconds */ smartmask_ratio = 5 * cnt->lastrate * (11 - cnt->smartmask_speed); } #if defined(HAVE_MYSQL) || defined(HAVE_PGSQL) || defined(HAVE_SQLITE3) - /* + /* * Set the sql mask file according to the SQL config options * We update it for every frame in case the config was updated * via remote control. @@ -2176,9 +2181,9 @@ static void *motion_loop(void *arg) /***** MOTION LOOP - FRAMERATE TIMING AND SLEEPING SECTION *****/ - /* + /* * Work out expected frame rate based on config setting which may - * have changed from http-control + * have changed from http-control */ if (cnt->conf.frame_limit) required_frame_time = 1000000L / cnt->conf.frame_limit; @@ -2189,7 +2194,7 @@ static void *motion_loop(void *arg) gettimeofday(&tv2, NULL); elapsedtime = (tv2.tv_usec + 1000000L * tv2.tv_sec) - timenow; - /* + /* * Update history buffer but ignore first pass as timebefore * variable will be inaccurate */ @@ -2227,13 +2232,12 @@ static void *motion_loop(void *arg) } } - /* + /* * END OF MOTION MAIN LOOP * If code continues here it is because the thread is exiting or restarting */ err: - if (rolling_average_data) - free(rolling_average_data); + free(rolling_average_data); cnt->lost_connection = 1; MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Thread exiting"); @@ -2271,7 +2275,7 @@ static void *motion_loop(void *arg) static void become_daemon(void) { int i; - FILE *pidf = NULL; + FILE *pidf = NULL; struct sigaction sig_ign_action; /* Setup sig_ign_action */ @@ -2288,35 +2292,35 @@ static void become_daemon(void) MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Motion going to daemon mode"); exit(0); } - - /* + + /* * Create the pid file if defined, if failed exit * If we fail we report it. If we succeed we postpone the log entry till * later when we have closed stdout. Otherwise Motion hangs in the terminal waiting * for an enter. */ if (cnt_list[0]->conf.pid_file) { - pidf = myfopen(cnt_list[0]->conf.pid_file, "w+", 0); - + pidf = myfopen(cnt_list[0]->conf.pid_file, "w+"); + if (pidf) { (void)fprintf(pidf, "%d\n", getpid()); myfclose(pidf); } else { MOTION_LOG(EMG, TYPE_ALL, SHOW_ERRNO, "%s: Exit motion, cannot create process" " id file (pid file) %s", cnt_list[0]->conf.pid_file); - if (ptr_logfile) - myfclose(ptr_logfile); - exit(0); + if (ptr_logfile) + myfclose(ptr_logfile); + exit(0); } } - /* + /* * Changing dir to root enables people to unmount a disk - * without having to stop Motion + * without having to stop Motion */ - if (chdir("/")) + if (chdir("/")) MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Could not change directory"); - + #if (defined(BSD)) setpgrp(0, getpid()); @@ -2324,7 +2328,7 @@ static void become_daemon(void) setpgrp(); #endif /* BSD */ - + if ((i = open("/dev/tty", O_RDWR)) >= 0) { ioctl(i, TIOCNOTTY, NULL); close(i); @@ -2345,12 +2349,12 @@ static void become_daemon(void) dup2(i, STDERR_FILENO); close(i); } - + /* Now it is safe to add the PID creation to the logs */ if (pidf) MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Created process id file %s. Process ID is %d", cnt_list[0]->conf.pid_file, getpid()); - + sigaction(SIGTTOU, &sig_ign_action, NULL); sigaction(SIGTTIN, &sig_ign_action, NULL); sigaction(SIGTSTP, &sig_ign_action, NULL); @@ -2371,7 +2375,7 @@ static void become_daemon(void) */ static void cntlist_create(int argc, char *argv[]) { - /* + /* * cnt_list is an array of pointers to the context structures cnt for each thread. * First we reserve room for a pointer to thread 0's context structure * and a NULL pointer which indicates that end of the array of pointers to @@ -2388,7 +2392,7 @@ static void cntlist_create(int argc, char *argv[]) /* cnt_list[1] pointing to zero indicates no more thread context structures - they get added later */ cnt_list[1] = NULL; - /* + /* * Command line arguments are being pointed to from cnt_list[0] and we call conf_load which loads * the config options from motion.conf, thread config files and the command line. */ @@ -2415,9 +2419,9 @@ static void motion_shutdown(void) motion_remove_pid(); - while (cnt_list[++i]) + while (cnt_list[++i]) context_destroy(cnt_list[i]); - + free(cnt_list); cnt_list = NULL; #ifndef WITHOUT_V4L @@ -2445,23 +2449,24 @@ static void motion_startup(int daemonize, int argc, char *argv[]) /* Initialize our global mutex */ pthread_mutex_init(&global_lock, NULL); - /* + /* * Create the list of context structures and load the * configuration. */ cntlist_create(argc, argv); if ((cnt_list[0]->conf.log_level > ALL) || - (cnt_list[0]->conf.log_level == 0)) { + (cnt_list[0]->conf.log_level == 0)) { cnt_list[0]->conf.log_level = LEVEL_DEFAULT; cnt_list[0]->log_level = cnt_list[0]->conf.log_level; - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Using default log level (%s) (%d)", + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Using default log level (%s) (%d)", get_log_level_str(cnt_list[0]->log_level), SHOW_LEVEL_VALUE(cnt_list[0]->log_level)); } else { cnt_list[0]->log_level = cnt_list[0]->conf.log_level - 1; // Let's make syslog compatible } - //set_log_level(cnt_list[0]->log_level); + + //set_log_level(cnt_list[0]->log_level); #ifdef HAVE_SDL MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Motion "VERSION" Started with SDL support"); @@ -2475,7 +2480,7 @@ static void motion_startup(int daemonize, int argc, char *argv[]) if (ptr_logfile) { set_log_mode(LOGMODE_SYSLOG); - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Logging to file (%s)", + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Logging to file (%s)", cnt_list[0]->conf.log_file); set_log_mode(LOGMODE_FILE); } else { @@ -2487,15 +2492,15 @@ static void motion_startup(int daemonize, int argc, char *argv[]) MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Logging to syslog"); } - if ((cnt_list[0]->conf.log_type_str == NULL) || + if ((cnt_list[0]->conf.log_type_str == NULL) || !(cnt_list[0]->log_type = get_log_type(cnt_list[0]->conf.log_type_str))) { cnt_list[0]->log_type = TYPE_DEFAULT; cnt_list[0]->conf.log_type_str = mystrcpy(cnt_list[0]->conf.log_type_str, "ALL"); - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Using default log type (%s)", + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Using default log type (%s)", get_log_type_str(cnt_list[0]->log_type)); } - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Using log type (%s) log level (%s)", + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Using log type (%s) log level (%s)", get_log_type_str(cnt_list[0]->log_type), get_log_level_str(cnt_list[0]->log_level)); set_log_level(cnt_list[0]->log_level); @@ -2504,7 +2509,7 @@ static void motion_startup(int daemonize, int argc, char *argv[]) initialize_chars(); if (daemonize) { - /* + /* * If daemon mode is requested, and we're not going into setup mode, * become daemon. */ @@ -2554,6 +2559,10 @@ static void setup_signals(struct sigaction *sig_handler_action, struct sigaction sigaction(SIGQUIT, sig_handler_action, NULL); sigaction(SIGTERM, sig_handler_action, NULL); sigaction(SIGUSR1, sig_handler_action, NULL); + + /* use SIGVTALRM as a way to break out of the ioctl, don't restart */ + sig_handler_action->sa_flags = 0; + sigaction(SIGVTALRM, sig_handler_action, NULL); } /** @@ -2572,7 +2581,7 @@ static void start_motion_thread(struct context *cnt, pthread_attr_t *thread_attr { int i; - /* + /* * Check the stream port number for conflicts. * First we check for conflict with the control port. * Second we check for that two threads does not use the same port number @@ -2586,7 +2595,7 @@ static void start_motion_thread(struct context *cnt, pthread_attr_t *thread_attr MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Stream port number %d for thread %d conflicts with the control port", cnt->conf.stream_port, cnt->threadnr); - MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: Stream feature for thread %d is disabled.", + MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: Stream feature for thread %d is disabled.", cnt->threadnr); cnt->conf.stream_port = 0; } @@ -2601,14 +2610,14 @@ static void start_motion_thread(struct context *cnt, pthread_attr_t *thread_attr "%s: Stream port number %d for thread %d conflicts with thread %d", cnt->conf.stream_port, cnt->threadnr, cnt_list[i]->threadnr); MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, - "%s: Stream feature for thread %d is disabled.", + "%s: Stream feature for thread %d is disabled.", cnt->threadnr); cnt->conf.stream_port = 0; } } } - /* + /* * Update how many threads we have running. This is done within a * mutex lock to prevent multiple simultaneous updates to * 'threads_running'. @@ -2623,11 +2632,22 @@ static void start_motion_thread(struct context *cnt, pthread_attr_t *thread_attr /* Give the thread WATCHDOG_TMO to start */ cnt->watchdog = WATCHDOG_TMO; - /* + /* Flag it as running outside of the thread, otherwise if the main loop + * checked if it is was running before the thread set it to 1, it would + * start another thread for this device. */ + cnt->running = 1; + + /* * Create the actual thread. Use 'motion_loop' as the thread * function. */ - pthread_create(&cnt->thread_id, thread_attr, &motion_loop, cnt); + if (pthread_create(&cnt->thread_id, thread_attr, &motion_loop, cnt)) { + /* thread create failed, undo running state */ + cnt->running = 0; + pthread_mutex_lock(&global_lock); + threads_running--; + pthread_mutex_unlock(&global_lock); + } } /** @@ -2649,7 +2669,7 @@ int main (int argc, char **argv) pthread_attr_t thread_attr; pthread_t thread_id; - /* + /* * Setup signals and do some initialization. 1 in the call to * 'motion_startup' means that Motion will become a daemon if so has been * requested, and argc and argc are necessary for reading the command @@ -2662,14 +2682,48 @@ int main (int argc, char **argv) motion_startup(1, argc, argv); #ifdef HAVE_FFMPEG - /* + /* * FFMpeg initialization is only performed if FFMpeg support was found * and not disabled during the configure phase. */ ffmpeg_init(); #endif /* HAVE_FFMPEG */ +#ifdef HAVE_MYSQL + if (mysql_library_init(0, NULL, NULL)) { + fprintf(stderr, "could not initialize MySQL library\n"); + exit(1); + } +#endif /* HAVE_MYSQL */ +#ifdef HAVE_SQLITE3 + /* database_sqlite3 == NULL if not changed causes each thread to creat their own + * sqlite3 connection this will only happens when using a non-threaded sqlite version */ + cnt_list[0]->database_sqlite3=NULL; + if (cnt_list[0]->conf.database_type && ((!strcmp(cnt_list[0]->conf.database_type, "sqlite3")) && cnt_list[0]->conf.database_dbname)) { + MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s: SQLite3 Database filename %s", + cnt_list[0]->conf.database_dbname); + + int thread_safe = sqlite3_threadsafe(); + if (thread_safe > 0) { + MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s: SQLite3 is threadsafe"); + MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s: SQLite3 serialized %s", + (sqlite3_config(SQLITE_CONFIG_SERIALIZED)?"FAILED":"SUCCESS")); + if (sqlite3_open( cnt_list[0]->conf.database_dbname, &cnt_list[0]->database_sqlite3) != SQLITE_OK) { + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, "%s: Can't open database %s : %s", + cnt_list[0]->conf.database_dbname, sqlite3_errmsg( cnt_list[0]->database_sqlite3)); + sqlite3_close( cnt_list[0]->database_sqlite3); + exit(1); + } + MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s: database_busy_timeout %d msec", + cnt_list[0]->conf.database_busy_timeout); + if (sqlite3_busy_timeout( cnt_list[0]->database_sqlite3, cnt_list[0]->conf.database_busy_timeout) != SQLITE_OK) + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, "%s: database_busy_timeout failed %s", + sqlite3_errmsg( cnt_list[0]->database_sqlite3)); + } + + } +#endif /* HAVE_SQLITE3 */ - /* + /* * In setup mode, Motion is very communicative towards the user, which * allows the user to experiment with the config parameters in order to * optimize motion detection and stuff. @@ -2705,26 +2759,38 @@ int main (int argc, char **argv) MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: Motion restarted"); } - /* + /* * Start the motion threads. First 'cnt_list' item is global if 'thread' * option is used, so start at 1 then and 0 otherwise. */ for (i = cnt_list[1] != NULL ? 1 : 0; cnt_list[i]; i++) { /* If i is 0 it means no thread files and we then set the thread number to 1 */ cnt_list[i]->threadnr = i ? i : 1; + /* camera_id is not defined in the config, then the camera id needs to be generated. + * the load order will generate a # that will become the camera_id + */ + cnt_list[i]->conf.camera_id = cnt_list[i]->conf.camera_id ? cnt_list[i]->conf.camera_id: i; if (strcmp(cnt_list[i]->conf_filename, "")) - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Thread %d is from %s", - cnt_list[i]->threadnr, cnt_list[i]->conf_filename); + { + cnt_list[i]->conf_filename[sizeof(cnt_list[i]->conf_filename) - 1] = '\0'; + + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Camera %d is from %s", + cnt_list[i]->conf.camera_id, cnt_list[i]->conf_filename); + } - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Thread %d is device: %s input %d", - cnt_list[i]->threadnr, cnt_list[i]->conf.netcam_url ? + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Camera %d is device: %s input %d", + cnt_list[i]->conf.camera_id, cnt_list[i]->conf.netcam_url ? cnt_list[i]->conf.netcam_url : cnt_list[i]->conf.video_device, cnt_list[i]->conf.netcam_url ? -1 : cnt_list[i]->conf.input); - - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Stream port %d", - cnt_list[i]->conf.stream_port); + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Stream port %d", + cnt_list[i]->conf.stream_port); +#ifdef HAVE_SQLITE + /* this is done to share the seralized handle + * and supress creation of new handles in the threads */ + cnt_list[i]->database_sqlite3=cnt_list[0]->database_sqlite3; +#endif start_motion_thread(cnt_list[i], &thread_attr); } @@ -2734,25 +2800,38 @@ int main (int argc, char **argv) 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. */ - if (cnt_list[0]->conf.webcontrol_port) - pthread_create(&thread_id, &thread_attr, &motion_web_control, cnt_list); + if (cnt_list[0]->conf.webcontrol_port) { + pthread_mutex_lock(&global_lock); + threads_running++; + /* set outside the loop to avoid thread set vs main thread check */ + cnt_list[0]->webcontrol_running = 1; + pthread_mutex_unlock(&global_lock); + if (pthread_create(&thread_id, &thread_attr, &motion_web_control, + cnt_list)) { + /* thread create failed, undo running state */ + pthread_mutex_lock(&global_lock); + threads_running--; + cnt_list[0]->webcontrol_running = 0; + pthread_mutex_unlock(&global_lock); + } + } - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Waiting for threads to finish, pid: %d", + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Waiting for threads to finish, pid: %d", getpid()); - /* + /* * Crude way of waiting for all threads to finish - check the thread * counter (because we cannot do join on the detached threads). */ while (1) { SLEEP(1, 0); - /* - * Calculate how many threads runnig or wants to run + /* + * Calculate how many threads are running or wants to run * if zero and we want to finish, break out */ int motion_threads_running = 0; @@ -2761,46 +2840,67 @@ int main (int argc, char **argv) if (cnt_list[i]->running || cnt_list[i]->restart) motion_threads_running++; } + if (cnt_list[0]->conf.webcontrol_port && + cnt_list[0]->webcontrol_running) + motion_threads_running++; - if (((motion_threads_running == 0) && finish) || + if (((motion_threads_running == 0) && finish) || ((motion_threads_running == 0) && (threads_running == 0))) { MOTION_LOG(ALL, TYPE_ALL, NO_ERRNO, "%s: DEBUG-1 threads_running %d motion_threads_running %d " - ", finish %d", threads_running, motion_threads_running, finish); + ", finish %d", threads_running, motion_threads_running, finish); break; - } + } for (i = (cnt_list[1] != NULL ? 1 : 0); cnt_list[i]; i++) { /* Check if threads wants to be restarted */ if ((!cnt_list[i]->running) && (cnt_list[i]->restart)) { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Motion thread %d restart", + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Motion thread %d restart", cnt_list[i]->threadnr); start_motion_thread(cnt_list[i], &thread_attr); } if (cnt_list[i]->watchdog > WATCHDOG_OFF) { - cnt_list[i]->watchdog--; - - if (cnt_list[i]->watchdog == 0) { - MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Thread %d - Watchdog timeout, trying to do " - "a graceful restart", cnt_list[i]->threadnr); - cnt_list[i]->finish = 1; - } + if (cnt_list[i]->watchdog == WATCHDOG_KILL) { + /* if 0 then it finally did clean up (and will restart without any further action here) + * kill(, 0) == ESRCH means the thread is no longer running + * if it is no longer running with running set, then cleanup here so it can restart + */ + if(cnt_list[i]->running && pthread_kill(cnt_list[i]->thread_id, 0) == ESRCH) { + MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: cleaning Thread %d", cnt_list[i]->threadnr); + pthread_mutex_lock(&global_lock); + threads_running--; + pthread_mutex_unlock(&global_lock); + motion_cleanup(cnt_list[i]); + cnt_list[i]->running = 0; + cnt_list[i]->finish = 0; + } else { + /* keep sending signals so it doesn't get stuck in a blocking call */ + pthread_kill(cnt_list[i]->thread_id, SIGVTALRM); + } + } else { + cnt_list[i]->watchdog--; + + + if (cnt_list[i]->watchdog == 0) { + MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Thread %d - Watchdog timeout, trying to do " + "a graceful restart", cnt_list[i]->threadnr); + cnt_list[i]->finish = 1; + } - if (cnt_list[i]->watchdog == -60) { - MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Thread %d - Watchdog timeout, did NOT restart graceful," - "killing it!", cnt_list[i]->threadnr); - pthread_cancel(cnt_list[i]->thread_id); - pthread_mutex_lock(&global_lock); - threads_running--; - pthread_mutex_unlock(&global_lock); - motion_cleanup(cnt_list[i]); - cnt_list[i]->running = 0; - cnt_list[i]->finish = 0; + if (cnt_list[i]->watchdog == WATCHDOG_KILL) { + MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, "%s: Thread %d - Watchdog timeout, did NOT restart graceful," + "killing it!", cnt_list[i]->threadnr); + /* The problem is pthead_cancel might just wake up the thread so it runs to completition + * or it might not. In either case don't rip the carpet out under it by + * doing motion_cleanup until it no longer is running. + */ + pthread_cancel(cnt_list[i]->thread_id); + } } } } - MOTION_LOG(ALL, TYPE_ALL, NO_ERRNO, "%s: DEBUG-2 threads_running %d motion_threads_running %d finish %d", + MOTION_LOG(ALL, TYPE_ALL, NO_ERRNO, "%s: DEBUG-2 threads_running %d motion_threads_running %d finish %d", threads_running, motion_threads_running, finish); } /* Reset end main loop flag */ @@ -2820,7 +2920,7 @@ int main (int argc, char **argv) // Be sure that http control exits fine - cnt_list[0]->finish = 1; + cnt_list[0]->webcontrol_finish = 1; SLEEP(1, 0); MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: Motion terminating"); @@ -2855,9 +2955,9 @@ int main (int argc, char **argv) void * mymalloc(size_t nbytes) { void *dummy = calloc(nbytes, 1); - + if (!dummy) { - MOTION_LOG(EMG, TYPE_ALL, SHOW_ERRNO, "%s: Could not allocate %llu bytes of memory!", + MOTION_LOG(EMG, TYPE_ALL, SHOW_ERRNO, "%s: Could not allocate %llu bytes of memory!", (unsigned long long)nbytes); motion_remove_pid(); exit(1); @@ -2936,7 +3036,7 @@ int create_path(const char *path) buffer[start-path] = 0x00; if (mkdir(buffer, mode) == -1 && errno != EEXIST) { - MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Problem creating directory %s", + MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Problem creating directory %s", buffer); free(buffer); return -1; @@ -2946,20 +3046,13 @@ int create_path(const char *path) if (!start) MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, "%s: creating directory %s", buffer); - + free(buffer); } return 0; } -#define MYBUFCOUNT 32 -struct MyBuffer { - FILE* fh; - char* buffer; - size_t bufsize; -} buffers[MYBUFCOUNT]; - /** * myfopen * @@ -2967,101 +3060,42 @@ struct MyBuffer { * (which is: path does not exist), the path is created and then things are * tried again. This is faster then trying to create that path over and over * again. If someone removes the path after it was created, myfopen will - * recreate the path automatically. If the bufsize is set to > 0, we will - * allocate (or re-use) write buffers to use instead of the default ones. - * This gives us much higher throughput in many cases. + * recreate the path automatically. * * Parameters: * * path - path to the file to open * mode - open mode - * bufsize - size of write buffers, 0 == OS default * * Returns: the file stream object */ -FILE * myfopen(const char *path, const char *mode, size_t bufsize) +FILE * myfopen(const char *path, const char *mode) { - static int bufferInit = 0; - if (!bufferInit) { - bufferInit = 1; - memset(buffers, 0x00, sizeof(buffers)); - } /* first, just try to open the file */ FILE *dummy = fopen(path, mode); + if (dummy) return dummy; /* could not open file... */ - if (!dummy) { - /* path did not exist? */ - if (errno == ENOENT) { + /* path did not exist? */ + if (errno == ENOENT) { - /* create path for file... */ - if (create_path(path) == -1) - return NULL; + /* create path for file... */ + if (create_path(path) == -1) + return NULL; - /* and retry opening the file */ - dummy = fopen(path, mode); - } + /* and retry opening the file */ + dummy = fopen(path, mode); } - - if (dummy) { - if (bufsize > 0) { - int i = 0; - for (i = 0; i < MYBUFCOUNT; i++) { - int first = -1; - if (!buffers[i].fh) { - if (first == -1) - first = i; - if (buffers[i].buffer == NULL || - buffers[i].bufsize >= bufsize || - (i == (MYBUFCOUNT - 1) && first >= 0)) { - if (buffers[i].buffer == NULL) { - /* We are allocating a new buffer */ - buffers[i].fh = dummy; - buffers[i].buffer = mymalloc(bufsize); - buffers[i].bufsize = bufsize; - } - else if (buffers[i].bufsize >= bufsize) { - /* We are using an old buffer */ - buffers[i].fh = dummy; - } - else { - /* - * We are reusing an old buffer, but it is too - * small, realloc it - */ - i = first; - buffers[i].fh = dummy; - buffers[i].buffer = myrealloc(buffers[i].buffer, - bufsize, "myfopen"); - buffers[i].bufsize = bufsize; - } - - if (buffers[i].buffer == NULL) { - /* - * Our allocation failed, so just use the default - * OS buffers - */ - buffers[i].fh = NULL; - buffers[i].bufsize = 0; - } - else { - setvbuf(buffers[i].fh, buffers[i].buffer, - _IOFBF, buffers[i].bufsize); - } - break; - } - } - } - } - } else { + if (!dummy) { /* * Two possibilities * 1: there was an other error while trying to open the file for the * first time * 2: could still not open the file after the path was created */ - MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Error opening file %s with mode %s", + MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Error opening file %s with mode %s", path, mode); + return NULL; } return dummy; @@ -3070,30 +3104,17 @@ FILE * myfopen(const char *path, const char *mode, size_t bufsize) /** * myfclose * - * Motion-specific variant of fclose() + * Motion-specific variant of fclose() * * Returns: fclose() return value - */ + */ int myfclose(FILE* fh) { - int i = 0; int rval = fclose(fh); - if (rval != 0) + if (rval != 0) MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Error closing file"); - for (i = 0; i < MYBUFCOUNT; i++) { - if (buffers[i].fh == fh) { - buffers[i].fh = NULL; - if ( finish ) { - /* Free the buffers */ - if (buffers[i].buffer) - free(buffers[i].buffer); - buffers[i].buffer = NULL; - buffers[i].bufsize = 0; - } - } - } return rval; } @@ -3102,7 +3123,7 @@ int myfclose(FILE* fh) * * Motion-specific variant of strftime(3) that supports additional format * specifiers in the format string. - * + * * Parameters: * * cnt - current thread's context structure @@ -3123,6 +3144,7 @@ size_t mystrftime(const struct context *cnt, char *s, size_t max, const char *us char tempstring[PATH_MAX] = ""; char *format, *tempstr; const char *pos_userformat; + int width; format = formatstring; @@ -3135,13 +3157,19 @@ size_t mystrftime(const struct context *cnt, char *s, size_t max, const char *us for (pos_userformat = userformat; *pos_userformat; ++pos_userformat) { if (*pos_userformat == '%') { - /* + /* * Reset 'tempstr' to point to the beginning of 'tempstring', * otherwise we will eat up tempstring if there are many * format specifiers. */ tempstr = tempstring; tempstr[0] = '\0'; + width = 0; + while ('0' <= pos_userformat[1] && pos_userformat[1] <= '9') { + width *= 10; + width += pos_userformat[1] - '0'; + ++pos_userformat; + } switch (*++pos_userformat) { case '\0': // end of string @@ -3149,73 +3177,92 @@ size_t mystrftime(const struct context *cnt, char *s, size_t max, const char *us break; case 'v': // event - sprintf(tempstr, "%02d", cnt->event_nr); + sprintf(tempstr, "%0*d", width ? width : 2, cnt->event_nr); break; case 'q': // shots - sprintf(tempstr, "%02d", cnt->current_image->shot); + sprintf(tempstr, "%0*d", width ? width : 2, + cnt->current_image->shot); break; case 'D': // diffs - sprintf(tempstr, "%d", cnt->current_image->diffs); + sprintf(tempstr, "%*d", width, cnt->current_image->diffs); break; case 'N': // noise - sprintf(tempstr, "%d", cnt->noise); + sprintf(tempstr, "%*d", width, cnt->noise); break; case 'i': // motion width - sprintf(tempstr, "%d", cnt->current_image->location.width); + sprintf(tempstr, "%*d", width, + cnt->current_image->location.width); break; case 'J': // motion height - sprintf(tempstr, "%d", cnt->current_image->location.height); + sprintf(tempstr, "%*d", width, + cnt->current_image->location.height); break; case 'K': // motion center x - sprintf(tempstr, "%d", cnt->current_image->location.x); + sprintf(tempstr, "%*d", width, cnt->current_image->location.x); break; case 'L': // motion center y - sprintf(tempstr, "%d", cnt->current_image->location.y); + sprintf(tempstr, "%*d", width, cnt->current_image->location.y); break; case 'o': // threshold - sprintf(tempstr, "%d", cnt->threshold); + sprintf(tempstr, "%*d", width, cnt->threshold); break; case 'Q': // number of labels - sprintf(tempstr, "%d", cnt->current_image->total_labels); + sprintf(tempstr, "%*d", width, + cnt->current_image->total_labels); break; - case 't': // thread number - sprintf(tempstr, "%d",(int)(unsigned long) - pthread_getspecific(tls_key_threadnr)); + case 't': // camera id + sprintf(tempstr, "%*d", width, cnt->conf.camera_id); break; case 'C': // text_event if (cnt->text_event_string && cnt->text_event_string[0]) - snprintf(tempstr, PATH_MAX, "%s", cnt->text_event_string); + snprintf(tempstr, PATH_MAX, "%*s", width, + cnt->text_event_string); else ++pos_userformat; break; + case 'w': // picture width + sprintf(tempstr, "%*d", width, cnt->imgs.width); + break; + + case 'h': // picture height + sprintf(tempstr, "%*d", width, cnt->imgs.height); + break; + case 'f': // filename -- or %fps if ((*(pos_userformat+1) == 'p') && (*(pos_userformat+2) == 's')) { - sprintf(tempstr, "%d", cnt->movie_fps); + sprintf(tempstr, "%*d", width, cnt->movie_fps); pos_userformat += 2; break; } if (filename) - snprintf(tempstr, PATH_MAX, "%s", filename); + snprintf(tempstr, PATH_MAX, "%*s", width, filename); else ++pos_userformat; break; case 'n': // sqltype if (sqltype) - sprintf(tempstr, "%d", sqltype); + sprintf(tempstr, "%*d", width, sqltype); + else + ++pos_userformat; + break; + + case '$': // thread name + if (cnt->conf.camera_name && cnt->conf.camera_name[0]) + snprintf(tempstr, PATH_MAX, "%s", cnt->conf.camera_name); else ++pos_userformat; break; @@ -3226,7 +3273,7 @@ size_t mystrftime(const struct context *cnt, char *s, size_t max, const char *us continue; } - /* + /* * If a format specifier was found and used, copy the result from * 'tempstr' to 'format'. */ diff --git a/motion.h b/motion.h index c08d84f..b67add3 100644 --- a/motion.h +++ b/motion.h @@ -22,8 +22,12 @@ #endif #ifdef HAVE_SQLITE3 +#ifdef HAVE_SQLITE3_EMBEDDED +#include "sqlite3.h" +#else #include #endif +#endif #ifdef HAVE_PGSQL #include @@ -149,6 +153,7 @@ */ #define WATCHDOG_TMO 30 /* 30 sec max motion_loop interval */ +#define WATCHDOG_KILL -60 /* -60 sec grace period before calling thread cancel */ #define WATCHDOG_OFF -127 /* Turn off watchdog, used when we wants to quit a thread */ #define CONNECTION_KO "Lost connection" @@ -207,14 +212,16 @@ #define UPDATE_REF_FRAME 1 #define RESET_REF_FRAME 2 -#define BUFSIZE_1MEG (1024 * 1024) - /* Forward declaration, used in track.h */ struct images; #include "track.h" #include "netcam.h" +#ifdef HAVE_MMAL +#include "mmalcam.h" +#endif + /* * Structure to hold images information * The idea is that this should have all information about a picture e.g. diffs, timestamp etc. @@ -350,6 +357,9 @@ struct context { struct images imgs; struct trackoptions track; struct netcam_context *netcam; +#ifdef HAVE_MMAL + struct mmalcam_context *mmalcam; +#endif struct image_data *current_image; /* Pointer to a structure where the image, diffs etc is stored */ unsigned int new_img; @@ -370,6 +380,9 @@ struct context { volatile unsigned int restart; /* Restart the thread when it ends */ /* Is the motion thread running */ volatile unsigned int running; + /* Is the web control thread running */ + volatile unsigned int webcontrol_running; + volatile unsigned int webcontrol_finish; /* End the thread */ volatile int watchdog; pthread_t thread_id; @@ -449,7 +462,7 @@ extern pthread_key_t tls_key_threadnr; /* key for thread number */ int http_bindsock(int, int, int); void * mymalloc(size_t); void * myrealloc(void *, size_t, const char *); -FILE * myfopen(const char *, const char *, size_t); +FILE * myfopen(const char *, const char *); int myfclose(FILE *); size_t mystrftime(const struct context *, char *, size_t, const char *, const struct tm *, const char *, int); int create_path(const char *); diff --git a/motion.init-Fedora.in b/motion.init-Fedora.in deleted file mode 100644 index a21f955..0000000 --- a/motion.init-Fedora.in +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/bash -# -# motion Startup script for the Motion Detection System -# -# chkconfig: - 85 15 -# description: Motion detection system. It is used to detect movement based \ -# on compare images. -# processname: @PACKAGE_NAME@ -# pidfile: /var/run/@PACKAGE_NAME@.pid -# config: /etc/@PACKAGE_NAME@.conf -# -### BEGIN INIT INFO -# Provides: motion -# Required-Start: $local_fs -# Required-Stop: $local_fs -# Default-Start: -# Default-Stop: -# Short-Description: Start and stop motion detection system -# Description: The Motion detection system is used to detect movement based -# on image comparison. -### END INIT INFO - -# Source function library. -. /etc/rc.d/init.d/functions - -motion=${MOTION-/usr/bin/motion} -prog=motion -pidfile=/var/run/motion.pid -lockfile=/var/lock/subsys/motion - -start() { - [ -x $exec ] || exit 5 - [ -f $config ] || exit 6 - echo -n $"Starting $prog: " - # We try to determine which architecture we have so we can - # load libv4l to support more USB cameras. x86_64 and ppc64 - # are both supported by rpmfusion. - case $(uname -i) in - "x86_64" ) - #We load libv4l for 64 Bit x86 architectures - LD_PRELOAD=/usr/lib64/libv4l/v4l2convert.so daemon $motion 2> /dev/null ;; - "ppc64" ) - #We load libv4l for 64 Bit PPC architectures - LD_PRELOAD=/usr/lib64/libv4l/v4l2convert.so daemon $motion 2> /dev/null ;; - * ) - #Default case, we load libv4l for all 32 Bit architectures - LD_PRELOAD=/usr/lib/libv4l/v4l2convert.so daemon $motion 2> /dev/null ;; - esac - retval=$? - echo - [ $retval -eq 0 ] && touch $lockfile - return $retval -} - -stop() { - echo -n $"Stopping $prog: " - killproc $motion - retval=$? - echo - [ $retval = 0 ] && rm -f $lockfile -} - -restart() { - stop - start -} - -reload() { - echo -n $"Reloading $prog configuration: " - killproc $motion -HUP - retval=$? - echo - return $retval -} - -rh_status() { - # run checks to determine if the service is running or use generic status - status $prog -} - -rh_status_q() { - rh_status >/dev/null 2>&1 -} - - -# See how we were called. -case "$1" in - start) - rh_status_q && exit 0 - $1 - ;; - stop) - rh_status_q || exit 0 - $1 - ;; - restart) - $1 - ;; - reload) - rh_status_q || exit 7 - $1 - ;; - force-reload) - #force_reload - reload - ;; - status) - rh_status - ;; - condrestart|try-restart) - rh_status_q || exit 0 - restart - ;; - *) - echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" - exit 1 -esac -exit $? diff --git a/motion.init-FreeBSD.sh.in b/motion.init-FreeBSD.sh.in index a7b6e3d..5e99db4 100644 --- a/motion.init-FreeBSD.sh.in +++ b/motion.init-FreeBSD.sh.in @@ -20,7 +20,7 @@ rcvar=`set_rcvar` command="@BIN_PATH@/${name}" pidfile="/var/run/${name}.pid" -required_files="/usr/local/etc/${name}.conf" +required_files="/usr/local/etc/motion/${name}.conf" load_rc_config $name run_rc_command "$1" diff --git a/motion.service.in b/motion.service.in new file mode 100644 index 0000000..03ebd67 --- /dev/null +++ b/motion.service.in @@ -0,0 +1,12 @@ +[Unit] +Description=Motion daemon +After=local-fs.target network.target + +[Service] +PIDFile=/var/run/motion.pid +ExecStart=@BIN_PATH@/motion +Type=simple +StandardError=null + +[Install] +WantedBy=multi-user.target diff --git a/motion.spec.in b/motion.spec.in index 6cebd6c..41c04eb 100644 --- a/motion.spec.in +++ b/motion.spec.in @@ -5,8 +5,8 @@ Summary: A motion detection system Group: Applications/Multimedia License: GPLv2+ -URL: http://www.lavrsen.dk/twiki/bin/view/Motion/WebHome -Source0: http://prdownloads.sourceforge.net/%{name}/%{name}-%{version}.tar.gz +URL: https://motion-project.github.io/ +Source0: https://github.com/Motion-Project/motion BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: libjpeg-devel ffmpeg-devel zlib-devel diff --git a/motion_guide.html b/motion_guide.html index c23bb02..ecb12ea 100644 --- a/motion_guide.html +++ b/motion_guide.html @@ -1,1974 +1,2345 @@ -

Motion Guide - One Large Document.

+

Motion Guide

+

This version of the Guide is made for inclusion in the Motion download package for off line reading. -

-If you read this document from the distribution package of Motion or from some not up to date mirror you should know that the URL for the always up to date version is http://www.lavrsen.dk/twiki/bin/view/Motion/MotionGuide. If you are already on the new TWiki based Motion site clicking the link just mentioned will lead you to the index page for the Motion Guide documents. -


-This topic consists of the following subtopics: -MotionOverview, KnownProblems, InstallOverview, PrepareInstall, ConfigureScript, MakeInstall, UpgradingFromOlderVersion, RunningMotionConfigFiles, CommandLineOptions, ConfigFileOptions, SignalsKill, ErrorLogging, CaptureDeviceOptions, MotionDetectionSettings, ImageFileOutput, TuningMotion, MpegFilmsFFmpeg, SnapshotsWebCam, TextFeatures, AdvancedFilenames, ConversionSpecifiers, WebcamServer, RemoteControlHttp, ExternalCommands, TrackingControl, UsingDatabases, LoopbackDevice. -
-

-

-
-

-

Motion Guide - Installation

-

-

Motion Overview

-

-

What is Motion?

+

+

+ + + + + +

Overview

+
    +

    +

    What is Motion?

    +

    Motion is a program that monitors the video signal from one or more cameras and is able to detect if a significant part of the picture has changed. Or in other words, it can detect motion. -

    -The program is written in C and is made for the Linux operating system. -

    -Motion is a command line based tool. It has absolutely no graphical user interface. Everything is setup either via the command line or via a set of configuration files (simple ASCII files that can be edited by any ASCII editor). -

    +

    +The program is written in C and was made for the Linux operating system. Recent revisions have also made it available for BSD. +

    +Motion is a command line based tool with only limited support for configuration via a http interface. +The many configuration options are set via the command line or configuration files. + +

    The output from motion can be: -

      -
    • jpg files -
    • ppm format files -
    • mpeg video sequences -
    -

    -

    How do I get Motion and what does it cost?

    -Motion is an open source type of project. It does not cost anything. Motion is published under the GNU GENERAL PUBLIC LICENSE (GPL) version 2 or later. It may be a bit difficult to understand all the details of the license text (especially if your first language is not English). It means that you can get the program, install it and use it freely. You do not have to pay anything and you do not have to register anywhere or ask the author or publisher for permission. The GPL gives you both rights and some very reasonable duties when it comes to copying, distribution and modification of the program. So in very general terms you do not have to worry about licensing as a normal hobby user. If you want to use Motion in a commercial product, if you want to distribute either modified or original versions of Motion - for free or for a fee, you should read the license carefully. For more information about free software and the GPL, I encourage you to study the very interesting documents about the subject available the of the Free Software Foundation pages about the Philosophy of the GNU Project. -

    -

    Maintenance and Support

    -Both Motion and the Motion Guide are written by people that do all this as a hobby and without asking for any payments or donations. We have a life other than developing Motion and its documentation. This means that bugfixes and updates to this guide are done as our time and families allow it. You are however encouraged to participate and contribute in a very active mailing list. It is a list with a very "positive attitude" and with many contributors that propose features, post patches, discuss problems and patiently answer newbie questions with a very positive spirit. Expect 1-10 emails per day. -

    -To get motion direct your browser to the Motion Homepage. -

    -On the Download Files page you will find a links to the latest stable version both as sources and binaries for some of the most popular Linux distributions. You will also find links to development versions. Snapshot releases are special test releases that are normally very stable. Every day a Motion Daily Source Snap is created from the Motion Subversion -

    -Motion was originally written by Jeroen Vreeken who still actively participates in the development of Motion and later Folkert van Heusden continued as a lead programmer with Kenneth Lavrsen responsible for Motion Guide, website and releases on Sourceforge. -

    -From version 3.1.12 Motion is now project managed entirely by Kenneth Lavrsen, and the project now shift towards being developed by many contributers. -

    -For support we encourage you to join the mailing list instead of writing to Jeroen, Folkert or Kenneth directly. We are all very active on the mailing list and by using the mailing list much more users will have benefit of the answers. Newbies and stupid questions are welcome on the list. Contributions in the form of patches are also very welcome on the mailing list. -

    -

    Which version to download and use?

    -Versions 3.2.X are the current version. There is at the moment no development branch. The versions 3.1.X ended at 3.1.20 and there will be no more 3.1.X releases. If you use use a version older than 3.2.X you are encouraged to update. -

    -Since 3.1.13 quite many options have been renamed to make setting up Motion easier. From 3.1.17-18 some unfinished features have been removed. The Berkeley mpeg feature is now removed because the ffmpeg feature is now mature and much better working. At version 3.1.18 a new network camera feature was introduced replacing the old cURL based netcam code and introducing support of mjpeg streaming cameras. However this new code was quite difficult to get stable. During the development of 3.2.2 the network camera code was totally rewritten again learning from our experience and now finally it seems to be stable. -

    -Since 3.2.3 Debian users can find binary packages on the Motion Sourceforge file download page. You can find Debian versions of Motion in different Debian repositories but they are all out of date and hardly ever get updated. -

    -

    What features does Motion have?

    -See more description at the Motion Homepage.
      -
    • Taking snapshots of movement -
    • Watch multiple video devices at the same time -
    • Watch multiple inputs on one capture card at the same time -
    • Live streaming webcam (using multipart/x-mixed-replace) -
    • Real time creation of mpeg movies using libraries from ffmpeg -
    • Take automated snapshots on regular intervals -
    • Take automated snapshots at irregular intervals using cron -
    • Executing external program when detecting movement -
    • Execute external program at the beginning of an event of several motion detections. -
    • Execute external program at the end of an event of several motion detections. -
    • Execute external program when a picture is saved. -
    • Execute external program when a movie mpeg is created (opened) -
    • Execite external program when a movie mpeg ends (closed) -
    • Motion tracking -
    • Feed events to an MySQL or PostgreSQL database. -
    • Feed video back to a video4linux loopback for real time viewing -
    • Web interface using Motion Related Projects such as motion.cgi, Kenneths Webcam Package, Kevins Webpage, X-Motion and many more. -
    • User configurable and user defined on screen display. -
    • Control via simple web interface. -
    • Automatic noise and threshold control -
    • Ability to control the pan/tilt of a Logitech Sphere (or Orbit) camera -
    • Highly configurable display of text on images. -
    • High configurable definition of path and file names of the stored images and films. -
    -

    -You can find more information and links at the Motion Homepage. -

    -

    FreeBSD

    -

    -Motion is originally developed for Linux and it is still mainly developed and supported for this platform. From version 3.1.15 an experimental port has been made by Angel Carpintero. Not all features of Motion are supported at this time and it still needs a lot of test time on different hardware. Angel is very interested in feedback. Join the Motion Mailing List and give your feedback there. Patches for bugfixes and for enabling the missing features are very welcome. The rest of this guide is still mainly targeted for Linux users. Follow this topic to Install FreeBSD. -

    -

    MacOSX

    -

    -From Motion version 3.2.4 it is now also possible to build and install Motion under MacOSX. Feature set it the same as for FreeBSD. See the MacOSX topic for specific help how to install Motion and its dependencies on MacOSX. Again this port has been contributed by Angel Carpintero. -

    -

    Documentation

    +

    +
      +
    • jpg files
    • +
    • ppm format files
    • +
    • movie video sequences
    • +
    +

    +

    How do I get Motion and what does it cost?

    +

    +Motion is an open source type of project. It does not cost anything. Motion is published +under the GNU GENERAL PUBLIC LICENSE (GPL) version 2 or later. It may be a bit difficult to understand all the details of the license text (especially if your first language is not English). It means that you can get the program, install it and use it freely. You do not have to pay anything and you do not have to register anywhere or ask the author or publisher for permission. The GPL gives you both rights and some very reasonable duties when it comes to copying, distribution and modification of the program. So in very general terms you do not have to worry about licensing as a normal hobby user. If you want to use Motion in a commercial product, if you want to distribute either modified or original versions of Motion - for free or for a fee, you should read the license carefully. For more information about free software and the GPL, I encourage you to study the very interesting documents about the subject available the of the Free Software Foundation pages about the Philosophy of the GNU Project. +

    +

    Maintenance and Support

    +

    +Both Motion and the Motion Guide are written by people that do all this as a hobby and without asking for any payments or donations. We have a life other than developing Motion and its documentation. This means that bugfixes and updates to this guide are done as our time and families allow it. You are however encouraged to participate and contribute in a very active mailing list. It is a list with a very "positive attitude" and with many contributors that propose features, post patches, discuss problems and patiently answer newbie questions with a very positive spirit. Expect 1-10 emails per day. +

    +To get motion direct your browser to the Motion Homepage. +

    +On the Releases page you will find +links to the latest stable version both as sources and binaries for some of the most popular Linux distributions. +p>

    +Motion was originally written by Jeroen Vreeken and later Folkert van Heusden continued as a +lead programmer with Kenneth Lavrsen responsible for Motion Guide, website and releases on Sourceforge. +

    +From version 3.4.1 Motion is now managed on github via a many maintainers and contributors. +

    +For support we encourage you to join the mailing list instead of writing to the maintainers directly. +Newbies and stupid questions are welcome on the list. Contributions in the form of pull requests to the github +repository are also very welcome. +

    +

    Which version to download and use?

    +

    +The most current release version can be found on the github releases page here. The master branch of the github +repository represents the official development branch of Motion. Additional independent development forks exist +in other Github repos that contain additional bug fixes, enhanced features and updated documentation. +This guide is based upon the features and options included in the source code with which it is distributed. +It was re-written in September 2015 to reflect the changes and options in the code at that time. +The majority of the new options and changed names represent differences between the 3.2.12 version +and the legacy SVN trunk. +

    +Since 3.2.12 many options have been renamed to make setting up Motion easier. +

    +Motion is included in Debian and Ubuntu while RPM users currently must build from source. +

    +

    What features does Motion have?

    +

    +See more description at the Motion Homepage. +
      +
    • Taking snapshots of movement
    • +
    • Watch multiple video devices at the same time
    • +
    • Watch multiple inputs on one capture card at the same time
    • +
    • Live streaming webcam
    • +
    • Real time creation of movies using libraries from ffmpeg
    • +
    • Take automated snapshots on regular intervals
    • +
    • Take automated snapshots at irregular intervals using cron
    • +
    • Executing external program when a particular event occurs
    • +
    • Motion tracking
    • +
    • Feed events to an MySQL, PostgreSQL or SQLite3 database.
    • +
    • Feed video back to a video4linux loopback for real time viewing
    • +
    • Control via simple web interface.
    • +
    • Automatic noise and threshold control
    • +
    • Ability to control the pan/tilt of a tracking camera.
    • +
    • Highly configurable display of text on images.
    • +
    • Highly configurable definition of path and file names of the stored images and movies.
    • +
    +

    +

    FreeBSD

    +

    +Motion is originally developed for Linux and it is still mainly developed and supported for this platform. Thanks to contributions of Angel Carpintero, Motion now builds on BSD platforms. These platforms however have had only limited testing. +

    +

    MacOSX

    +

    +Starting with Motion version 3.2.4, it is now possible to build Motion under MacOSX thanks to Angel Carpintero. The features included are similar to BSD platforms and have had limited testing. +

    +

    Documentation

    +

    You have the following sources of information: -

    -

    -

    Supported Hardware

    -Input devices: Here we are thinking about the cameras. -

    +

    +
      +
    • This Motion Guide
    • +
    • The Frequently Asked Questions
    • +
    • The author of the program has written a description of the technology behind motion.
    • +
    • The man page. After installation simply type 'man motion' into a terminal screen.
    • +
    • The default motion.conf file (motion-dist.conf) that comes with the package.
    • +
    +

    +

    Supported Hardware

    +

    Motion supports video input from two kinds of sources. -

    -Standard video4linux devices (e.g. /dev/video0). Motion has no drivers for cameras. Installing the camera itself is outside the scope of this document. But here are some nice links.

    -Network cameras (which are actually cameras with a built in web server that can be connected directory to your network). -

    -

    -

    Known Problems

    -See also the Frequently Asked Questions and Bug Reports for known open bugs. -

    -Kernel 2.6 and pwc. Note that for kernel 2.6 there is a new release of the Philips WebCam (pwc) drivers 10.0.X. It is recommended to install this. At the time of this being written the 2.6.12+ kernels have a version of pwc built-in but it is a cripled version which can only support very small picture size. You can however download the latest source code of the pwc driver (at this time 10.0.11) and build it without having to rebuild your kernel. But you will need to have either the kernel sources or a special kernel-header package installed to compile it. See Installation of PWC page which is also hosted in this wiki. -

    -If you use use a Logitech Quickcam Orbit or Sphere using the driver pwc/pwcx and kernel 2.6.X you should replace the file in the Motion sources called pwc-ioctl.h with the one that comes with the your pwc version. Motion is shipped with 3 versions of pwc-ioctl.h-VERSION. Rename the one that fits your major pwc version number best to pwc-ioctl.h (after renaming the current to something else). There has been some small adjustments in the API that requires that you have the right header file. -

    -Camera picture dimensions must be multiple of 16 -Dimentions of camera image must have both height and width that are a multiple of 16. Thís is normally not a problem. All standard sizes like 640, 480, 352, 320, 288, 240, ...etc are multiples of 16. But if you intend to monitor a network camera which is saving jpeg images you may have to pay attention to the dimensions of the picture. -

    -ffmpeg_filename has changed name to movie_filename -The 3.2.5 release contains a motion_guide and man page in which it was forgotten to change ffmpeg_filename to movie_filename. Please note that the option that defines the filenames for mpeg movies is now called movie_filename. This change is made because we may soon implement alternatives to ffmpeg and then ffmpeg_filename will be a bad name. This is fixed in release 3.2.5.1. -

    -error: `time_current_frame' undeclared (first use in this function) -A bug in 3.2.5 and 3.2.5.1 where a bugfix related to snapshot feature has created a new bug when you compile Motion without ffmpeg libs installed. This is fixed in 3.2.6. -

    -

    -

    How do I install Motion?

    -Motion is mainly distributed as source files that you must compile yourself. There is also an RPM made on Fedora Core 3. And Debian packages are available for selected versions. -

    -The short overview of the steps to install Motion from sources.

      -
    • Preparation: Motion uses a number of shared libraries that must be installed on your computer before you can build Motion. The needed shared libraries depends on the features you wish to use. Features network camera, ffmpeg, MySQL and PostgreSQL needs specific shared libraries installed. See preparation section for more information. -
    -

      -
    • Download the motion source files (distributed as tar'ed and compressed files). Place the file in a place of your own choice. -
    -

      -
    • Untar and uncompress the file to the place you want the program installed. Editor recommends placing the motion source file directory in /usr/local. If you do not have write access to the /usr/local directory (you are under the mercy of an ignorant system administrator with a severe case of paranoia) - you can install the program in a directory in your home directory. You will then need to read the next section about how to configure before you compile the program. Below is shown the exact commands using version 3.2.X installed in /usr/local as an example (replace /path/to with the actual placement of the tar.gz file). -
    -
      -
      -cd /usr/local
      -tar -xvzf /path/to/motion-3.2.X.tar.gz
      -
      -
      -
    • You will now have created a directory called motion-3.2.X. You can rename it to motion (mv motion-3.1.X motion). I recommend creating a symbolic link to the current version. This way you can more easily experiment with different version simply by changing the link. -
    -
      -
      -ln -s motion-3.2.X motion
      -
      -
      -
    • Now change to the new directory -
    -
      -
      -cd motion
      -
      -
      -
    • Run configure. You can start with the defaults. If you need to modify the installation parameters you can read the next section. -
    -
      -
      -./configure
      -
      -
      -
    • Build the code -
    -
      -
      -make
      -
      -
      -
    • Install the code, manual page, etc -
    -
      -
      -make install
      -
      -
      -
    • In /etc/motion/etc you will find a file called motion-dist.conf. If it is the first time you install Motion - rename this file to motion.conf and edit as a minimum the settings: videodevice, input, norm, frequency, width, height and target_dir. That should get you going. -
    -

      -
    • Run the program. To enable more features you must modify the config file. -
    -
      -
      -motion
      -
      -
    -

    -

    -

    Preparation For Install

    -

    -Note: If you're using SuSE 9.2, you might want to ADDITIONALLY have a look at Compiling on SuSE 9.2. As mentioned on that page as well, you will still need to read the instructions here as well. -

    -Before you start you may need to install a number of shared libraries that Motion uses. If they are missing the feature will simply normally not be included. Most of these libraries can be found on the CDs of your distribution. A few will have to be downloaded from the Internet. Note that when you install software using pre-compiled binaries (Redhat type RPMs, Debian debs etc) you normally only get what is needed to run the programs themselves. In order to compile other programs from source that uses these pre-compiled libraries you also need to installed the development packages. These are normally called the same name as the package suffixed by -devel or -dev. These development packages contains the header files (xxx.h) that Motion needs to build with the shared libraries. If you build a library from sources you already have these header files. It is recommended to simply install the pre-compiled binary packages and their development brothers. -

    -This is a list of shared libraries used by Motion and the RPM packages that provides them. -

    -Motion will always need these libraries to be built and work - - - - -
    Library RPM Packages Debian Packages
    libm, libresolv, libdl, libpthread, libc, ld-linux, libcrypt, and libnsl glibc and glibc-devel libc6 , libc6-dev ,libglib1.2
    libjpeg libjpeg and libjpeg-devel libjpeg62 and libjpeg62-dev ( optional libjpeg-mmx-dev )
    libz zlib and zlib-devel zlib1g and zlib1g-dev
    -

    -For generating mpeg films with ffmpeg you need this library:
    -(See also the section Generating MPEG films with ffmpeg for how to install ffmpeg and libavformat/libavcodec)
    -Motion must be installed with revision 0.4.8 or 0.4.9pre1 of ffmpeg. Motion will also work with later CVS snapshots of ffmpeg but the API of the ffmpeg libraries changes all the time and without warning. If you have problems compiling Motion or with running an RPM of Motion you may try with an older CVS snapshot of ffmpeg. The Motion developers will like to know when ffmpeg changes and breaks Motion so we can fix it. Please file a bug report then with the exact date of the ffmpeg CVS version you have trouble with. -

    - - -
    Library RPM Packages Debian Packages
    libavcodec, libavformat ffmpeg and ffmpeg-devel or install from source libavcodec-dev libavcodec0d libavformat-dev libavformat0d (*)
    -

    -Debian has not provided deb packages for ffmpeg due patent issues. However this is about to change so checkout for availability of newer versions of debian ffmpeg debs. You can build yourself from source or from Christian Marillat website or apt repository. -

    -deb http://www.debian-multimedia.org stable main # ( etch )
    -deb http://www.debian-multimedia.org testing main # ( lenny )
    -deb http://www.debian-multimedia.org unstable main # ( sid )
    +

    +Standard video4linux devices (e.g. /dev/video0) and network cameras. Motion has no drivers for cameras. +Installing or configuring the camera itself is outside the scope of this document. Generally, if the device works with +other common video player software, it will work with Motion (and vice versa). As a result, it is +often convenient to first get the device working with other software and then use those connection options with Motion. +

    +

    +
+ +

Known Problems

+
    - -Add the suitable line to your /etc/apt/sources.list and run this: -
    -apt-get update ; apt-get -y install libavcodec-dev libavcodec0d libavformat-dev libavformat0d
    -
    -

    -For logging in MySQL you need this library: - - -
    Library RPM Packages Debian Packages
    libmysqlclient mysql and mysql-devel libmysqlclient15-off and libmysqlclient15-dev
    -

    -For logging in PostgreSQL you need this library: - - -
    Library RPM Packages Debian Packages
    libpq postgresql-libs and postgresql-devel libpq-dev and libpq4
    -

    -

    -

    Configure Script

    -Configure is script that you run to setup the build environment for the C-compiler. It generates the "Makefile" which the program "make" uses to compile and install the software. -

    -To run configure your current directory must be the motion directory. You type -

    +

    +See also the Frequently Asked Questions and Issues for known open issues. +

    +

    + +
+

Installation on Ubuntu and Debian

+
    + +

    +Motion is part of the Ubuntu and Debian repositories. +

    +Open up a terminal window and type: +

    +sudo apt-get install motion +

    +Before we start configuring Motion, we need to copy the config file to our Home folder so that the master copy won't be affected. Open a terminal and copy the configuration file to your Home folder with following commands: +

    +mkdir .motion +

    +(Note: This will create a hidden folder .motion in your Home directory.) +

    +sudo cp /etc/motion/motion.conf ~/.motion/motion.conf +

    +(Note: This command will copy the original motion configuration file to its location.) +

    +Now can open the configuration file for editing: +

    +sudo nano ~/.motion/motion.conf +

    +After you you have made all the appropriate adjustments to the configuration file, close it. +Then start motion in the terminal simply by typing: +

    +motion +

    +

    +
+ +

How to build Motion from source code

+
    + +

    +While Motion is included in the apt packages for Ubuntu and Debian, it can also be built from the source code +Source code is located in multiple locations depending upon the needs of the user + +

    +

    +
      + +

      +

      +In order to build Motion from source, many shared libraries must be installed. +The particular libraries needed will vary depending upon the features desired. +

      +Note that when you install software using pre-compiled binaries (Redhat type RPMs, Debian debs etc) +you normally only get what is needed to run the programs themselves. In order to compile other programs +from source that uses these pre-compiled libraries you also need to installed the development packages. +These are normally called the same name as the package suffixed by -devel or -dev. These development +packages contains the header files (xxx.h) that Motion needs to build with the shared libraries. If +you build a library from sources you already have these header files. It is recommended to simply +install the pre-compiled binary packages and their development brothers. +

      +Open a terminal and run the following commands to install the packages. +

      +Ubuntu / Debian Packages +
        +
      • Required
      • +
          +

          + sudo apt-get install autoconf automake build-essential pkgconf libtool libzip-dev libjpeg62 libjpeg62-dev +

          +
        +

        +
      • Optional Packages
      • +
          +
        • FFMpeg Functionality(Required for creating movies, using network cameras, etc. SEE NOTE BELOW!)
        • +
            +

            + sudo apt-get install libav-tools libavformat-dev libavcodec-dev libavutil-dev libswscale-dev +

            + OR (DO NOT RUN BOTH OF THESE COMMANDS!) +

            + sudo apt-get install ffmpeg libavformat-ffmpeg-dev libavcodec-ffmpeg-dev libavutil-ffmpeg-dev libswscale-ffmpeg-dev +

            +
          +
        • MySQL database functionality
        • +
            +

            + sudo apt-get install mysql-server libmysqlclient-dev +

            +
          +
        • PostgreSQL database functionality
        • +
            +

            + sudo apt-get install postgresql libpq-dev +

            +
          +
        • SQLite3 database functionality
        • +
            +

            + sudo apt-get install sqlite3 +

            +
          +
        • JPEG Turbo
        • +
            +

            + sudo apt-get install libjpeg-turbo8 libjpeg-turbo8-dev +

            +
          +
        • SDL
        • +
            +

            + sudo apt-get install libsdl1.2-dev +

            +
          + +
        + Important ffmpeg/libav note: Only ONE of the set of packages indicated above are needed by Motion. The set of + packages and whether they are Libav or ffmpeg is a user selection and possibly dependent upon which is + available in the Ubuntu/Debian repositories. The source code with the latest fixes will work with either Libav or + ffmpeg. Older source code may compile better using one or the other. It is important to note that many repositories + do NOT include both Libav and ffmpeg. They will only have one or the other. The default for the configure is to + require that ffmpeg or Libav are installed. Use the configure option to compile without the ffmpeg / libav functionality. +
      +

      +

      +openSUSE Packages +
        +
      • Required
      • +
          +

          + sudo zypper install autoconf automake libtool +

          + sudo zypper install --type pattern devel_basis +

          + sudo zypper install libjpeg8-devel +

          + sudo zypper install -t pattern devel_C_C++ +

          +
        +

        +
      • Optional Packages
      • +
          +
        • FFMpeg Functionality(Required for creating movies, using network cameras, etc. SEE NOTE BELOW!)
        • +
            +

            + sudo zypper ar -f -n packman-essentials http://packman.inode.at/suse/openSUSE_13.1/Essentials/ packman-essentials +

            + sudo zypper ar -f -n packman-multimedia http://packman.inode.at/suse/openSUSE_13.1/Multimedia/ packman-multimedia +

            + sudo zypper install libffmpeg-devel +

            +
          +
        • MySQL database functionality
        • +
            +

            + Not known by author +

            +
          +
        • PostgreSQL database functionality
        • +
            +

            + Not known by author +

            +
          +
        • SQLite3 database functionality
        • +
            +

            + Not known by author +

            +
          +
        + Important ffmpeg note: The ffmpeg libraries indicated above are provided by a external repository. This may + change in the future. Validate that the repository is still valid when doing the install on openSUSE systems. + The default for the configure is to require that ffmpeg or Libav are installed. Use the configure option to + compile without the ffmpeg / libav functionality. +
      +

      +

      +
    +

    Configure Script

    +
      +Motion uses a set tools called the "autotools" in order to generate the required scripts in order to +compile and install Motion. The next step after gathering all of the required and desired libraries is to +have the autotools create a configure script. To do this open a terminal and change to the directory with +the source code and type +

      +autoreconf +

      +If the 'configure' file exists and contains a valid script, the tool will return immediately since no additional work +needs to be completed. If the script needs updating, then it will take a moment to return. Once it has been executed, +a file called 'configure' will exist in the directory. Note that if the command is run as +

      +autoreconf -f +

      +The -f parameter instructs it to force a new configure file to be created. This can be preferable in certain +situations so that the configure script gets updated with the correct version number. +Once the 'configure' file is created, we can execute it. What the script does is interrogate the system and look +for all the needed items in order to compile Motion. In this process it looks to determine which optional components +have been installed on the system and if found sets flags to indicate for them to be included. If a particular library +is required by Motion and is not found, the configure script will issue an error. The error means that the library was +not found because it was either not installed or that it was installed into a location that the script could not find. +With the Motion configure script, once it has ended it also lists out all of the optional components that were located. +Note that if you KNOW that a particular component is installed yet the configure script reports it as not installed, then +it may be necessary to use one or more of the configure options described below to tell the script where to find +the particular component. + +

      +To run the configure your current directory must be the motion directory. You type +

      ./configure -

      -You can add the parameter ./configure --help to get help on the different switches. -

      -This is walk through of the options. -

      - - -

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +

      +You can add the parameter ./configure --help to get help on the different switches. +

      +When the configure script finishes you should validate that the options desired +were correctly identified by the configure. In particular, the ffmpeg option is occasionally not +found even if it is actually installed. Various users have indicated this to be a particular +problem with the PI. If using a PI and have this issue, you can use the following option +

      +./configure --with-ffmpeg=/usr/lib/arm-linux-gnueabihf +

      +For a long term option, you can edit the file +$HOME/.bashrc +and within it place the following two lines at the end +PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf:$PKG_CONFIG_PATH +export PKG_CONFIG_PATH +

      +The long term option will however only become effective the next time you get into the terminal shell. +

      + +
      Option Description
      Defaults for the options
      are specified in brackets [ ]
      Editors comment
      -h, --help display this help and exit  
      --help=short display options specific to this package This command shows the options special to motion. Recommended
      --help=recursive display the short help of all the included packages  
      -V, --version display version information and exit Gives no useful information
      -q, --quiet, --silent do not print `checking...' messages Not very useful. Output to screen is only a few lines anyway.
      --cache-file=FILE cache test results in FILE. [disabled] No function
      -C, --config-cach alias for `--cache-file=config.cache' No function
      -n, --no-create do not create output files Used for testing if other switches produce error - without writing anything to the disk
      --srcdir=DIR find the sources in DIR. [configure dir or `..'] DIR is a directory path. Editor recommends having the current directory being the motion installation directory and not using this switch. Then it defaults to the same directory as where the configure script is which is the current directory.
      Installation directories:    
      --prefix=PREFIX install architecture-independent files in PREFIX
      [/usr/local]
      The default /usr/local means that the executable binary "motion" is installed in /usr/local/bin, the manual page in /usr/local/man/man1, the document files in /usr/local/docs/motion-version, configuration file in /usr/local/etc, and some examples config files in /usr/local/examples/motion-versionEditor recommends keeping this default setting.
      If you are experimenting with many parallel versions it may be interesting to set the PREFIX to e.g. /usr/local/motion and then add /usr/local/motion/bin to your search path (or simply cd /usr/local/motion/bin before execution).
      This way you can change version just by changing the symbolic link in /usr/local/motion as suggested earlier in this guide.
      If you are installing the software on a machine where you have no access to the /usr/local but have write access to a home directory, then you should change this to point to a directory within your home tree.
      Example: --prefix=$HOME
      --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
      [PREFIX]
      If you set this it only defines an alternative installation directory for the executable binary.
      Note: The executable binary will be placed in a directory "bin" below the directory specified by this option
      Editor recommends leaving this as default (i.e. not setting it).
      --bindir=DIR user executables [EPREFIX/bin] With this option you can control exactly in which directory the executable binary is installed. The previous option automatically adds the bin directory. Here you are in fill control.
      --sbindir=DIR System admin executables [EPREFIX/sbin] Not used by motion. Ignore it.
      --libexecdir=DIR program executables [EPREFIX/libexec] Not used by motion. Ignore it.
      --datadir=DIR read-only architecture-independent data [PREFIX/share] Not used by motion. Ignore it.
      --sysconfdir=DIR read-only single-machine data [PREFIX/etc] This is where motion both installs the default configuration file and also where it later searches for it.
      Motion searches for the configuration file "motion.conf" in the following order:

        1. Current directory from where motion was invoked
        2. $HOME/.motion
        3. The sysconfig directory set by this switch. If not defined the default is /usr/local/etc/

      Editor recommends leaving this at default. Be careful if you run "make install" again. This will overwrite the motion.conf file that you have edited and experimented with for hours. Make sure to keep a copy in a safe place. Alternatively, copy the working file to the motion base install directory. Then make install will simply copy the same file back again.
      --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] Not used by motion. Ignore it.
      --localstatedir=DIR modifiable single-machine data [PREFIX/var] Not used by motion. Ignore it.
      --libdir=DIR object code libraries [EPREFIX/lib] Not used by motion. Ignore it.
      --includedir=DIR C header files [PREFIX/include] Not used by motion. Ignore it.
      --oldincludedir=DIR C header files for non-gcc [/usr/include] Not used by motion. Ignore it.
      --infodir=DIR info documentation [PREFIX/info] Not used by motion. Ignore it.
      --mandir=DIR man documentation [PREFIX/man] Editor recommends the default.
      Optional Packages:    
      --with-ffmpeg=DIR Specify the path for the directory prefix in which the library and headers are installed.
      If not specified configure will search in /usr/ and /usr/local/
      DIR is the directory PREFIX in which the ffmpeg shared libraries and their headers are installed.
      If you install ffmpeg from sources and use the default directories or if ffmpeg is installed as a binary package (RPM or deb) you do not need to specify the directory prefix. Configure will find the libraries automatically. If you installed ffmpeg from sources and specified a different --prefix when building ffmpeg you must use the same value for the DIR ( --with-ffmpeg=DIR).
      For more information on FFmpeg see the FFmpeg project home page.
      FFmpeg is a package that enables streamed video mpeg signal from your web camera to a browser.
      Editor recommends installing ffmpeg from source and in the directory /usr/local/ffmpeg and build ffmpeg with ./configure --enable-shared.
      This places libraries in /usr/local/lib and headers in /usr/local/include.
      --without-ffmpeg Do not compile with ffmpeg Use this if you do not want to compile with ffmpeg. If ffmpeg is not installed you do not need to specify that Motion must build without ffmpeg.
      --with-mysql-lib=DIR Lib directory of MySQL Normally, configure will scan all possible default installation paths for MySQL libs. When its fail, use this command to tell configure where MySQL libs installation root directory is.
      --with-mysql-include=DIR Include directory with headers for MySQL Normally, configure will scan all possible default installation paths for MySQL include. When its fail, use this command to tell configure where MySQL include installation directory is. This is the directory with the MySQL header files.
      --without-mysql Do not compile with MySQL support Use this if you do not want to include MySQL support in the package.
      This can also be useful if you get compilation errors related to MySQL and you actually do not need the feature anyway.
      --with-pgsql=DIR Include PostgreSQL support. DIR is the PostgreSQL base install directory, defaults to /usr/local/pgsql.
      Set DIR to "shared" to build as a dynamic library, or "shared,DIR" to build as a dynamic library and still specify DIR.
      Default is that make searches in the normal installation directories of most distributions.
      See section later about PostgreSQL about potential problem during compilation. There is an easy workaround for it.
      --without-pgsql Do not compile with PostgreSQL support Use this if you do not want to include PostgreSQL support in the package.
      This can also be useful if you get compilation errors related to PostgreSQL and you actually do not need the feature anyway.
      --without-v4l Exclude using v4l (video4linux) subsystem. Makes Motion so it only supports network cameras. Can be used if you do not need V4L support and maybe lack some of the libraries for it.
      --with-linuxthreads Use linuxthreads in BSD instead of native phtreads Only relevant for BSD. In Linux we always use this per default.
      --without-bktr Exclude to use bktr subsystem , that usually useful for devices as network cameras ONLY used in *BSD
      --with-jpeg-mmx=DIR Specify the prefix for the install path for jpeg-mmx for optimized jpeg handling (optional). If this is not specified motion will try to find the library /usr/lib/libjpeg-mmx.a /usr/local/lib/libjpeg-mmx.a. Considered experimental
      --without-optimizecpu Exclude autodetecting platform and cpu type. This will disable the compilation of gcc optimizing code by platform and cpu. Use this if the optimization causes problems. Typically if you build on some non X386 compatible CPU.
      Developers options    
      --with-developer-flags Add additional warning flags for the compiler. This option is for developers only. It produces a flood of warnings that helps the developer to write more robust code. These warnings are normally harmless but can sometimes be a latent defect.
      For more information about these flags, see CompileWithDeveloperFlags
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Options Description
      Defaults for the options are specified in brackets [ ]
      Editors comment
      -h, --help display this help and exit
      --help=short display options specific to this package This command shows the options special to motion. Recommended
      --help=recursive display the short help of all the included packages
      -V, --version display version information and exit Provides the version number of the source code and autotools
      -q, --quiet, --silent do not print `checking...' messages Illustrates only the results of the script.
      --cache-file=FILE cache test results in FILE. [disabled] No function
      -C, --config-cach alias for `--cache-file=config.cache' No function
      -n, --no-create do not create output files Used for testing if other switches produce error - without writing anything to the disk
      --srcdir=DIR find the sources in DIR. [configure dir or `..'] DIR is a directory path. Editor recommends having the current directory being the motion installation directory and not using this switch. Then it defaults to the same directory as where the configure script is which is the current directory.
      Installation directories:    
      --prefix=PREFIX install architecture-independent files in PREFIX
      [/usr/local]
      The default /usr/local means that

      The executable binary "motion" is installed in /usr/local/bin
      The manual page in /usr/local/man/man1
      The document files in /usr/local/docs/motion-version
      The configuration file in /usr/local/etc/motion
      The example config files in /usr/local/examples/motion-version

      The editor recommends keeping this default setting.
      If you are experimenting with many parallel versions it may be interesting to set the PREFIX to e.g. /usr/local/motion and then add /usr/local/motion/bin to your search path (or simply cd /usr/local/motion/bin before execution).
      This way you can change version just by changing the symbolic link in /usr/local/motion as suggested earlier in this guide.
      If you are installing the software on a machine where you have no access to the /usr/local but have write access to a home directory, then you should change this to point to a directory within your home tree.
      Example: --prefix=$HOME
      --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
      [PREFIX]
      If you set this it only defines an alternative installation directory for the executable binary.
      Note: The executable binary will be placed in a directory "bin" below the directory specified by this option
      Editor recommends leaving this as default (i.e. not setting it).
      --bindir=DIR user executables [EPREFIX/bin] With this option you can control exactly in which directory the executable binary is installed. The previous option automatically adds the bin directory. Here you are in fill control.
      --sbindir=DIR System admin executables [EPREFIX/sbin] Not used by motion. Ignore it.
      --libexecdir=DIR program executables [EPREFIX/libexec] Not used by motion. Ignore it.
      --datadir=DIR read-only architecture-independent data [PREFIX/share] Not used by motion. Ignore it.
      --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + This is where motion both installs the default configuration file and also where it later searches for it.
      + Motion searches for the configuration file "motion.conf" in the following order: +
      +

        1. Current directory from where motion was invoked +
        2. $HOME/.motion +
        3. The motion/ subdirectory inside the sysconfig directory set by this switch. If not defined the default is /usr/local/etc/
        +

      Editor recommends leaving this at default. Be careful if you run "make install" again. + This will overwrite the motion-dist.conf file that you may have edited. +
      --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] Not used by motion. Ignore it.
      --localstatedir=DIR modifiable single-machine data [PREFIX/var] Not used by motion. Ignore it.
      --libdir=DIR object code libraries [EPREFIX/lib] Not used by motion. Ignore it.
      --includedir=DIR C header files [PREFIX/include] Not used by motion. Ignore it.
      --oldincludedir=DIR C header files for non-gcc [/usr/include] Not used by motion. Ignore it.
      --infodir=DIR info documentation [PREFIX/info] Not used by motion. Ignore it.
      --mandir=DIR man documentation [PREFIX/man] Editor recommends the default.
      Optional Packages:    
      --with-linuxthreads Use linuxthreads in BSD instead of native phtreads Only relevant for BSD. In Linux we always use this per default.
      --with-pwcbsd Use pwcbsd based webcams ( only BSD ) This option allow to build motion to support V4L/V4L2 in BSD.
      --without-bktr Exclude to use bktr subsystem , that usually useful for devices as network cameras ONLY used in *BSD
      --without-v4l Exclude using v4l (video4linux) subsystem. Makes Motion so it only supports network cameras. Can be used if you do not need support and maybe lack some of the libraries for it.
      --with-jpeg-mmx=DIR Specify the prefix for the install path for jpeg-mmx for optimized jpeg handling (optional). If this is not specified motion will try to find the library /usr/lib/libjpeg-mmx.a /usr/local/lib/libjpeg-mmx.a. Considered experimental
      --with-ffmpeg=DIR Specify the path for the directory prefix in which the + library and headers are installed .
      If not specified configure will search in /usr/ and /usr/local/
      DIR is the directory PREFIX in which the ffmpeg shared libraries + and their headers are installed.
      If you install ffmpeg from sources and use the default directories or + if ffmpeg is installed as a binary package (RPM or deb) you may not need to specify the directory prefix. + Configure should find the libraries automatically. If you installed ffmpeg from sources and specified a + different --prefix when building ffmpeg you must use the same value for the DIR ( --with-ffmpeg=DIR) + or export that location to be included in the PKG_CONFIG_PATH + The option of --with-ffmpeg is the default for Motion. If the required libraries are not located, the + configure script will stop at the ffmpeg section and report which libraries need to be installed. + Once the required libraries are installed, run the script again. As noted previously, make sure + to install the -dev versions. + For more information on FFmpeg see the documentation for the FFmpeg project.
      --without-ffmpeg Do not compile with ffmpeg Use this if you do not want to compile with ffmpeg. If ffmpeg is not installed you must specify this option for Motion to build without ffmpeg.
      --with-mysql-lib=DIR Lib directory of MySQL Normally, configure will scan all possible default installation paths for MySQL libs. When its fail, use this command to tell configure where MySQL libs installation root directory is.
      --with-mysql-include=DIR Include directory with headers for MySQL Normally, configure will scan all possible default installation paths for MySQL include. When its fail, use this command to tell configure where MySQL include installation directory is. This is the directory with the MySQL header files.
      --without-mysql Do not compile with MySQL support Use this if you do not want to include MySQL support in the package.
      This can also be useful if you get compilation errors related to MySQL and you actually do not need the feature anyway.
      --with-pgsql-lib=DIR Normally, configure will scan all possible default installation paths for pgsql libs. When it fails, use
      this command to tell configure where pgsql libs installation root directory is.
       
      --with-pgsql-include=DIR Normally, configure will scan all possible default installation paths for pgsql include. When it fails, use this command to tell configure where pgsql include installation root directory is.  
      --without-pgsql Do not compile with PostgreSQL support Use this if you do not want to include PostgreSQL support in the package.
      This can also be useful if you get compilation errors related to PostgreSQL and you actually do not need the feature anyway.
      --without-sqlite3 Disable sqlite3 support in motion. Use this if you do not want to include SQLite3 support in the package.
      This can also be useful if you get compilation errors related to SQLite4 and you actually do not need the feature anyway.
      --without-optimizecpu Exclude autodetecting platform and cpu type. This will disable the compilation of gcc optimizing code by platform and cpu. Use this if the optimization causes problems. Typically if you build on some non X386 compatible CPU.
      --without-sdl Compile without sdl support.  
      --with-jpeg-turbo=DIR Specify the prefix for the install path for jpeg-turbo for optimized jpeg handling (optional).  
      --with-developer-flags Add additional warning flags for the compiler. This option is for developers only. It produces a flood of warnings that helps the developer to write more robust code. These warnings are normally harmless but can sometimes be a latent defect.
      - -
      -
      -

      -

      Make

      -When you run make, all the C-source files are automatically compiled and linked. Just look out for error messages. -

      -Make uses a file called "Makefile" which is generated by the "configure" script you just ran. If you have special needs you can manually edit this file. Next time you run configure a new Makefile will be generated and your changes are lost. -

      -ALERT! Attention! -

      -If you have run make before, you should run a make clean before running make again. This cleans out all the object files that were generated the previous time you ran make. If you do not run make clean first before you rebuild Motion you may not get the additional feature included. For example: If you built Motion without ffmpeg support and then add it later - and rebuild Motion without running make clean first - the ffmpeg feature does not get compiled into the Motion binary. -

      -First time you build motion run ./configure, make, make install. If you need to build it again (to run with different configure options) run ./configure, make clean, make, make install. -

      -

      Make Install

      -make install simply copies all the nice files that were generated during the compilation/linking that make did. -

      -Makes the directories (if they do not already exist)(path shown are the defaults): /usr/local/bin, usr/local/man/man1, /usr/local/etc, /usr/local/share/doc/motion-3.2.X, and /usr/local/share/doc/examples/motion-3.2.X. -

      -Copies the following files from the base motion directory (assuming the default PREFIX /usr/local was used when running configure - otherwise adjust to the actuals you chose)

        -
      • Executable binary "motion" to /usr/local/bin -
      • Manual page "motion.1" to /usr/local/man/man1 -
      • Document files "CHANGELOG, COPYING, CREDITS, INSTALL, and README to /usr/local/share/doc/motion-3.2.X -
      • Example configuration files "*.conf" to /usr/local/share/doc/examples/motion-3.2.X -
      • Configuration file "motion-dist.conf" to /usr/local/etc -
      -Note that the any existing files are overwritten. The default config file motion-dist.conf is named like this so that you do not get your working motion.conf file overwritten when you upgrade Motion. -

      -

      Un-install

      +

      +

      +
    +

    Make

    +
      + +Once the configure script has successfully finished and indicates all options desired, a 'makefile' is created. +The makefile builds the Motion program and links in all of the required libraries. To run the makefile, type +

      +make +

      +The makefile will go through each of the files and compile it. Depending upon the source code obtained, there may be many +warnings or possibly none. +

      +If the notifications indicate many many undefined references, then it is most likely that +an additional library needs to be added in via the configure switches. Many of these additional libraries are related +to the version of ffmpeg and how it was built or installed. The following is a sample of some of the extra libraries +that may need to be added. +

      + +-lavformat -lswscale -lavcodec -lavutil -lfdk-aac -lswresample -lm -lopus -lz -lva -lvpx -lx264 -lmp3lame -lbz2 -ldl -lvorbisenc -lvorbis -ltheoraenc -ltheoradec + +

      + +

      +Once the makefile has completed correctly, it will report 'build complete'. +

      +ALERT! +

      +If you have run make before, you should run a make clean before +running make again. This cleans out all the object files that were +generated the previous time you ran make. If you do not run make clean first +before you rebuild Motion you may not get the additional feature included. +For example: If you built Motion without ffmpeg support and then add it later and rebuild Motion +without running make clean first the ffmpeg feature does not get compiled into the Motion binary. +

      +First time you build motion run ./configure, make, make install. +If you need to build it again (to run with different configure options) run ./configure, +make clean, make, make install. +

      +

      Make Install

      +make install copies and installs all the files that were generated during the compilation/linking +that make did. +

      +Creates the directories (if they do not already exist)(path shown are the defaults): +
        +
      • /usr/local/bin
      • +
      • usr/local/man/man1
      • +
      • /usr/local/etc/motion
      • +
      • /usr/local/share/doc/motion-version
      • +
      • /usr/local/share/doc/examples/motion-version
      • +
      +

      + +Copies the following files from the base motion directory +(assuming the default PREFIX /usr/local was used when running configure. Otherwise adjust to the actuals you chose) +
        +
      • Executable binary "motion" to /usr/local/bin
      • +
      • Manual page "motion.1" to /usr/local/man/man1
      • +
      • Document files "CHANGELOG, COPYING, CREDITS, INSTALL, and README to /usr/local/share/doc/motion-version
      • +
      • Example configuration files "*.conf" to /usr/local/share/doc/examples/motion-version
      • +
      • Configuration file "motion-dist.conf" to /usr/local/etc/motion
      • +
      + +Note that the any existing files are overwritten. The default config file motion-dist.conf is named like +this so that you do not get your working motion.conf file overwritten when you upgrade Motion. + +

      +

      Un-install

      From the motion base installation directory you simply run make uninstall -

      +

      And delete the base installation directory in /usr/local and any link pointing to it. If you have forgotten where you installed it or someone else did it for you, simply search for the files and directories starting with motion. If the filenames and the directories match the names described in the "Make Install" section of this document, you can safely delete them. -

      -

      Additional Make Options

      +

      +

      Additional Make Options

      The make command can be run with several options. make, make install and make uninstall has already been described above. -

      -
      make clean
      deletes all the binary files (object files) and the motion binary generated by make. It also deletes temporary files and any jpg files that motion has saved in the motion source directory. It is very important to always run make clean before you run make if you change the configuration (like adding features such as ffmpeg) and rebuild motion. -
      -

      -
      make distclean
      deletes the files: config.status, config.log, config.cache, Makefile, and motion.spec. -
      -

      -
      make updateguide
      fetches a fresh new copy of this guide and place it in your motion source directory. Note that the pictures are not downloaded. -
      -

      -
      make dist
      performs make clean, make distclean and make updateguide in one single operation. -
      -

      -

      -

      Upgrading From Older Version

      -If you are upgrading from motion 3.0.X or from an older version of 3.1.X you should note that many options have been removed from version 3.1.13 and forward and many new have arrived. You still have most of the old features. The options have been changed for two reasons. New more flexible features and to simplify getting started with Motion. With 3.2.1 the changes are significant. -You should also note these major differences.
        -
      • The use of thread files has completely changed. Read the section "The Config Files" carefully. -
      • The mask file format has changed. Read the section about "Mask File" -
      • Pre_capture feature introduced in 3.1.12 -
      • Advanced filename feature enables very flexible filename definitions (3.1.13) -
      • onffmpegclose options enables running external scripts when mpeg file is closed (3.1.13) -
      • despeckle feature improves motion detection and noise immunity (3.1.13) -
      • Minimum_motion_frames feature prevents short noise events from being saved (3.1.14) -
      • If you use the database features you need to note that from version 3.1.15 and forward the fields have been redefined. Removed are second, minute, hour, day, month and year. Instead these six have been replaced by a real timestamp field called time_stamp. The relatively new field 'type' has been renamed to 'file_type' to avoid reserved SQL words. A new field 'text_left' has been added which stores the text given by the config option text_left. And last a field called 'camera' has been added which stores the thread number. -
      • From 3.1.15 the ffmpeg feature now also supports mpeg4 and msmpeg4. The build process of Motion now use ffmpeg libraries as shared libraries. The --with-libavcodec has been replaced by a --with-ffmpeg which only needed to specify if you are installing ffmpeg from sources in a non-standard location. If you have installed ffmpeg from sources already you will need to rebuild by running (from within the ffmpeg source file root) ./configure --enable-shared followed by make and make install. If you had installed ffmpeg from a binary RPM or deb you probably don't have to do anything. -
      • Rotate feature was introduced in 3.1.15 -
      • Berkeley mpeg feature has been removed in 3.1.18 (use ffmpeg - it is much better) -
      • Incomplete prediction feature was removed in 3.1.18. (lack of interest in finishing it) -
      • Smart Mask feature introduced in 3.1.18 -
      • output_normal can now also have the value "first" which means only save first jpg from each event (3.1.18) -
      • ffmpeg-0.4.9 is now supported. Motion detection mpegs can no longer be saved as mpeg1 (ffmpeg does not support non-standard framerates in 0.4.9) (3.1.18) -
      • Motion now supports most (not all) mjpeg streaming cameras (3.1.18). -
      • output_normal can now have values "first" or "best". It is used when you need to present a link to an mpeg movie shown as a single jpeg image. "First" saves the first picture frame in the new event. "Best" saves the picture frame with most motion content (most changed pixels) when the event is over. "on" still saves all motion detection picture frames plus pre and post captured images. With "best" you can set jpeg_filename = "preview" and it gets the same filename as the mpeg file but with extension .jpg. Option "locate" can also take the value "preview" which makes it only draw a rectangel on the jpeg but not on the mpeg movie. (3.2.1) -
      • The xmlrpc remote control interface is replaced by a much nicer http remote control interface. (3.2.1) -
      • All the options that calls external programs have been made much more generic. New onxxxx options have been added. Execute, sms and mail have been replaced by the generic on_event_start. (3.2.1) -
      • New setup mode makes setting all the detection options much easier. -
      • netcam now also supports proxies (3.2.2) and ftp (3.2.4) -
      • text on the pictures can be set to double size (3.2.2) -
      • Tracking with Logitech Sphere/Orbit improved (3.2.4) -
      • SQL database feature is now fully configurable so you can control which fields you have in the database. -
      • Many new conversion specifiers have been added which can be used both in filenames, commands, text, and SQL database features (3.2.2-3.2.4) -
      • Stepper motor tracking feature extended to also include a Y axis (3.2.5) -
      • ffmpeg_filename has been renamed to movie_filename to prepare for alternative implementation to mpeg files made with ffmpeg (3.2.5) -
      • New feature: ffmpeg_deinterlace which can de-interlace using the ffmpeg libs (3.2.5) -
      • New feature: minimum_frame_time which enables Motion to run at frame rates below 2. minimum_gap feature was removed since this was useless and the new minimum_frame_time feature replaces it with much better function. (3.2.7) -
      • New feature: process_id_file which writes a PID file when started and removes it when stopped (3.2.7) -
      • V4L2 support with many new supported palettes : V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_UYVY (3.2.8) -
      • ffmpeg_video_codec allow swf (3.2.8) -
      • V4L2 fix support for : V4L2_PIX_FMT_MJPEG (3.2.9) -
      • ffmpeg_video_codec allow flv and ffv1(3.2.9) -
      -

      -

      -The table below shows the new options in the left column, and obsolete options in the right column. If the there are options on both sides in a row it means that the options in the left column replaced the options in the right column. -

      - -

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      New Options Obsolete Options
      text_left (3.1.13)
      text_right (3.1.13)
      text_changes (3.1.13)
      drawtext_user (3.1.13)
      drawtext_shots (3.1.13)
      drawtext_changes (3.1.13)
      jpeg_filename (3.1.13)
      ffmpeg_filename (3.1.13)
      snapshot_filename (3.1.13)
      timelapse_filename (3.1.13)
      predict_filename (3.1.13)
      (predict_filename removed in 3.1.18)
      oldlayout (3.1.13)
      snapshots_overwrite (3.1.13)
      snapshot_interval (3.1.13) snapshots (3.1.13)
        realmotion (3.1.13)
      despeckle (3.1.13)  
      pre_capture (3.1.12)  
      ffmpeg_timelapse (v. 3.1.14) ffmpeg_timelaps (renamed v 3.1.14)
      ffmpeg_timelapse_mode (3.1.14)  
      sql_log_image (3.1.14)
      sql_log_snapshot (3.1.14)
      sql_log_mpeg (3.1.14)
      sql_log_timelapse (3.1.14)
      sql_log_prediction (3.1.14)
       
      minimum_motion_frames (3.1.14)  
      rotate (3.1.15)  
      ffmpeg_variable_bitrate (3.1.15)
      ffmpeg_video_codec (3.1.15)
       
        berkeley_single_directory (3.1.18)
      mpeg_encode (3.1.18)
      mpeg_encode_bin (3.1.18)
      adjust_rate off (3.1.18)
      jpg_cleanup (3.1.18)
        predict_filename (3.1.18)
      predict_enable (3.1.18)
      predict_threshold (3.1.18)
      predict_description (3.1.18)
      sql_log_prediction (3.1.18)
      brightness (3.1.18)
      contrast (3.1.18)
      saturation (3.1.18)
      hue (3.1.18)
       
      smart_mask_speed (3.1.18)  
      output_normal
      valid values are now "on", "off", "first" (3.1.18) and "best" (3.2.1)
       
      setup_mode (3.2.1) always_changes (3.2.1)
      locate
      valid values are now "on", "off", "preview" (3.2.1)
       
      jpeg_filename
      Besides normal path names the value "preview" has speciel meaning together with output_normal = "best" (3.2.1)
       
      control_html_output (3.2.1)  
      on_event_start (3.2.1)
      execute (3.2.1)
      sms (3.2.1)
      mail (3.2.1)
      on_event_end (3.2.1)
       
      on_motion_detected (3.2.1)
       
      on_picture_save (3.2.1)
      onsave (3.2.1)
      on_movie_start (3.2.1)
      on_movie_end (3.2.1)
      onmpeg (3.2.1)
      onffmpegclose (introduced 3.1.13)(renamed to on_movie_end 3.2.1)
      netcam_proxy (3.2.2)  
      text_double (3.2.2)  
      webcam_motion
      Feature has been heavily improved so it is actually usefull now (3.2.2).
       
      netcam_url
      Now also supports fetching single frame jpeg pictures via ftp using ftp:// syntax (3.2.4)
       
      track_step_angle_x (3.2.4)
      track_step_angle_y (3.2.4)
      Add better configuration of auto tracking with a Logitech Sphere/Orbit camera.
       
      track_move_wait (3.2.4)
      track_auto (3.2.4)
      Adds better configuration of auto tracking feature
       
      sql_query (3.2.4)
      Adds full flexibility of defining fields when using the SQL database features.
       
      track_maxy (3.2.5)
      track_motory (3.2.5)
       
      movie_filename (3.2.5) ffmpeg_filename (3.2.5)
      ffmpeg_deinterlace (3.2.5)  
      minimum_frame_time (3.2.7) minimum_gap (3.2.7)
      process_id_file (3.2.7)  
      ffmpeg_video_codec allow swf (3.2.8)  
      ffmpeg_video_codec allow flv and ffv1 (3.2.9)  
        night_compensate (3.2.10)
      low_cpu (3.2.10)
      - -
      -
      -

      -

      Running Motion

      -

      -

      Important Definitions

      -Motion is invoked from the command line. It has no GUI. Everything is controlled from config files. From version 3.2 the command line is only used to define location of config file and a few special runtime modes (setup and non-daemon). -

      -A few important definitions.

        -
      • A snapshot is a picture taken at regular intervals independently of any movement in the picture. -
      • A "motion" image/mpeg shows the pixels that have actually changed during the last frames. These pictures are not very useful for normal presentation to the public but they are quite useful for testing and tuning and making mask files as you can see exactly where motion sees something moving. Motion is shown in greytones. If labelling is enabled the largest area is marked as blue. Smart mask is shown in read. -
      • A "normal" image is the real image taken by the camera with text overlayed. -
      -

      - -

      The Config Files

      -

      +

      +
      +
      make clean
      +
      deletes all the binary files (object files) and the motion binary generated by make. It also deletes temporary files and any jpg files that motion has saved in the motion source directory. It is very important to always run make clean before you run make if you change the configuration (like adding features such as ffmpeg) and rebuild motion.
      +
      +

      +
      +
      make distclean
      +
      deletes the files: config.status, config.log, config.cache, Makefile, and motion.spec.
      +
      +

      +
      +
      make updateguide
      +
      fetches the copy of this guide from the web page and puts it in your motion source directory. Note that the pictures are not downloaded.
      +
      +

      +
      +
      make dist
      +
      performs make clean, make distclean and make updateguide in one single operation.
      +
      + +

      +

      + +
    +

    Upgrading From Older Version

    +
      + If you are upgrading from an older version of Motion you should note that many many options have been rename, added or removed. + The author recommends that you start by copying the configuration files from the older version to a safe location for reference only. + Then start with a clean copy of the new motion-dist.conf installed and make changes to it. +

      +

      +
    +

    Running Motion

    +
      + +

      +

      +
    + +
+ +

Important Definitions

+
    + +

    +Motion is invoked from the command line. It has no GUI. Everything is controlled from config files. +From version 3.2 the command line is only used to define location of config file and a few special +options. +

    +A few important definitions. +
      +
    • A snapshot is a picture taken at regular intervals independently of any movement in the picture.
    • +
    • A "motion" image/mpeg shows the pixels that have actually changed during the last frames. These pictures are not very useful for normal presentation to the public but they are quite useful for testing and tuning and making mask files as you can see exactly where motion sees something moving. Motion is shown in greytones. If labelling is enabled the largest area is marked as blue. Smart mask is shown in red.
    • +
    • A "normal" image is the real image taken by the camera with text overlayed.
    • +
    + +

    +

    +
+ +

The Configuration Files

+
    + +

    If Motion was invoked with command line option -c pathname Motion will expect the config file to be as specified. When you specify the config file on the command line with -c you can call it anything. -

    +

    If you do not specify -c or the filename you give Motion does not exist, Motion will search for the configuration file called 'motion.conf' in the following order: -

      -
    1. Current directory from where motion was invoked -
    2. Then in a directory called '.motion' in the current users home directory (shell environment variable $HOME). E.g. /home/goofy/.motion/motion.conf -
    3. The directory defined by the --sysconfdir=DIR when running .configure during installation of Motion
      (If this option was not defined the default is /usr/local/etc/) -
    -If you have write access to /usr/local/etc then the editor recommends having only one motion.conf file in the default /usr/local/etc/ directory. -

    -Motion has a configuration file in the distribution package called motion-dist.conf. When you run 'make install' this file gets copied to the /usr/local/etc directory. -

    +

    +
      +
    1. Current directory from where motion was invoked
    2. +
    3. Then in a directory called '.motion' in the current users home directory (shell environment variable $HOME). E.g. /home/goofy/.motion/motion.conf
    4. +
    5. The directory defined by the --sysconfdir=DIR when running .configure during installation of Motion
      (If this option was not defined the default is /usr/local/etc/motion)
    6. +
    + +If you have write access to /usr/local/etc/motion then the editor recommends having only one motion.conf file +in the default /usr/local/etc/motion directory. +

    +Motion has a configuration file in the distribution package called motion-dist.conf. When you run 'make install' this +file gets copied to the /usr/local/etc/motion directory. +

    The configuration file needs to be renamed from motion-dist.conf to motion.conf. The original file is called motion-dist.conf so that your perfectly working motion.conf file does not accidentally get overwritten when you re-install or upgrade to a newer version of Motion. -

    -If you have more than one camera you should not try and invoke Motion more times. Motion is made to work with more than one camera in a very elegant way and the way to do it is to create a number of thread config files. Motion will then create an extra tread of itself for each camera. If you only have one camera you only need the motion.conf file. The minute you have two or more cameras you must have one thread config file per camera besides the motion.conf file. -

    +

    +If you have more than one camera you should not try and invoke Motion more times. Motion is made to work with more than one camera in a very elegant way and the way to do it is to create a number of thread config files. Motion will then create an extra thread of itself for each camera. If you only have one camera you only need the motion.conf file. The minute you have two or more cameras you must have one thread config file per camera besides the motion.conf file. +

    So if you have for example two cameras you need motion.conf and two thread config files. Total of 3 config files. -

    +

    An option that is common to all cameras can be placed in motion.conf. (You can also put all parameters in the thread files but that makes a lot of editing when you change a common thing). -

    +

    An option that is unique to a camera must be defined in each thread file. -

    +

    It is often seen that people copy the entire motion.conf into the thread config files and change a few options. This works but it not recommended because it is more difficult to maintain and overview. Keep all the common options in motion.conf and the few unique only in the thread config files -

    +

    The first camera is defined in the first thread file called from motion.conf. The 2nd camera is defined in the 2nd thread file called from motion.conf etc. -

    +

    Any option defined in motion.conf will be used for all cameras except for the cameras in which the same option is defined in a thread config file. -

    -Motion reads its configuration parameters in the following sequence. If the same parameter exists more than one place the last one read wins.

      -
    1. Motion reads the configuration file motion.conf from the beginning of the file going down line by line. -
    2. If the option "thread" is defined in motion.conf, the thread configuration file(s) is/(are) read. -
    3. Motion continues reading the rest of the motion.conf file. Any options from here will overrule the same option previously defines in a thread config file. -
    4. Motion reads the command line option again overruling any previously defined options. -
    +

    +To make it clear, the thread files format and syntax is the same as motion.conf. An example of what you might want in a thread file as follows: assume you have two cameras, attached to one system. Create files thread0.conf and thread1.conf. At the end of motion.conf, uncomment out the lines that refer to them. The full contents of the thread files can be as simple as +

    + +

    +thread0.conf:

    videodevice /dev/video0

    stream_port 8081 +

    +

    +

    +thread1.conf:

    videodevice /dev/video1

    stream_port 8082 +

    +

    +

    +Motion reads its configuration parameters in the following sequence. If the same +parameter exists more than one place the last one read wins + + +
      +
    1. Motion reads the configuration file motion.conf from the beginning of the file going down line by line.
    2. +
    3. If the option "thread" is defined in motion.conf, the thread configuration file(s) is/(are) read.
    4. +
    5. Motion continues reading the rest of the motion.conf file. Any options from here will overrule the same option previously defines in a thread config file.
    6. +
    7. Motion reads the command line option again overruling any previously defined options.
    8. +
    So always call the thread config files in the end of the motion.conf file. If you define options in motion.conf AFTER the thread file calls, the same options in the thread files will never be used. So always put the thread file call at the end of motion.conf. -

    -Nearly all config options can be unique for a specific camera and placed in a thread config file. There are a few options that must be in motion.conf and cannot be in a thread config file: control_authentication, control_html_output, control_localhost, control_port, daemon, and thread. -

    -If motion is built without specific features such as ffmpeg, mysql etc it will ignore the options that belongs to these features. You do not have to remove them or comment them out. -

    +

    +Nearly all config options can be unique for a specific camera and placed in a thread config file. +There are a few options that must be in motion.conf and cannot be in a thread config +file: stream_auth_method, webcontrol_* , daemon, and thread. +

    +If motion is built without specific features such as ffmpeg, mysql etc it will ignore the options that belongs to these features. +

    If you run the http control command http://host:port/0/config/writeyes, motion will overwrite motion.conf and all the thread.conf files by autogenerated config files neatly formatted and only with the features included that Motion was built with. If you later re-build Motion with more features or upgrade to a new version, you can use your old config files, run the motion.conf.write command, and you will have new config files with the new options included all set to their default values. This makes upgrading very easy to do. -

    -

    -

    Command Line Options

    -

    -ALERT! In Motion 3.2.1 and forward most command line options have been removed and replaced them by an option to specify location to motion.conf and a few options related to setting up motion. There are now only few command line options left and they are basically all new. -

    + +

    +

    +
+ +

Command Line Options

+
    + +

    SYNOPSIS
    -motion [ -hns ] [ -c config file path]
    +motion [ -hbnsm ] [ -c config file path ] [ -d level ] [ -k level ] [ -p process_id_file ] [ -l log_file ]
     
    -

    - -

    - - - - - - - - - +

    +
      +
    • -c : Full path and filename of config file.
    • +
    • -h : Show help screen
    • +
    • -b : Run in daemon mode
    • +
    • -n : Run in non-daemon mode
    • +
    • -s : Run in setup mode. Also forces non-daemon mode.
    • +
    • -d : Run with message log level 1 - 9
    • +
    • -k : Run with message log type 1 - 9
    • +
    • -l : Full path and file name for log file
    • +
    • -p : Full path and file name for the process id file
    • +
    • -m : Start in pause mode
    • +
    +

    +

    + + +

    Signals (sent with e.g. kill command)

    +
      +

      +A signal can be sent from the command line by typing e.g. kill -s SIGHUP pid, where the last parameter is the process ID which you get by typing ps -ef ¦ grep motion. The PID is the first on the list which is the parent process for the threads. +Motion responds to the following signals: +

      +
    Option Description Editors comment
    -n Run in non-daemon mode. Instead of running Motion in the background Motion runs in the terminal window writing messages when things happen. If you have problems getting Motion to start or work, run Motion in this mode to get more messages that can help you solve the problem.
    -s Run in setup mode. Also forces non-daemon mode
    -c config file path Full path and filename of config file. E.g. /home/kurt/motion.conf. Default is /usr/local/etc unless specified differently when building Motion. Many RPMs and debian packages will most likely use /etc or /etc/motion as default
    -h Show help screen.  
    -d level Debugging mode This mode is used for developers to enable debug messages. Normal users will not need to use this mode unless a developer request to get additional information in the attempt to resolve a bug. Mainly the netcam code has debugging features. The level defines how much debugging info you get. A high number displays all debugging.
    -p process_id_file Full path of process ID file Full path and filename of process id file (PID file). This is optional. If none is given as command line option or in motion.conf (process_id_file) Motion will not create a PID file.
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Signal Description Editors comment
    SIGHUP The config file will be reread. This is a very useful signal when you experiment with settings in the config file.
    SIGTERM If needed motion will create an movie file of the last event and exit  
    SIGUSR1 Motion will create an movie file of the current event.  
    - -
    -
    -

    -

    -

    Config File Options

    + +

    +

    +
+ +

Error Logging

+
    + +

    +Motion reports errors to the console when it runs in non-daemon mode. And it outputs +even more information when run in setup mode. +

    +Error logging has been implemented so that errors during daemon (background) mode are logged in the syslog or to the user +specified log file. +

    +The log is in most Linux systems the file /var/log/messages (e.g. RedHat/Fedora) +or /var/log/syslog and /var/log/user.log (e.g. Debian). +

    +

    +
+ +

Basic Setup

+
    +

    + +Before you can start using Motion you need to know some basics about your camera. +Either you have a camera connected directly to your computer. In this case it is a video4linux type of camera. +Or you connect to a network camera using a normal web URL. +

    +For video4linux devices, the camera must be installed per the requirements of the camera. It is +out of the scope of this document to tell you how to do this and it depends on which type of camera. Once +the camera is installed it will have the device name(s) of /dev/video0, /dev/video1, /dev/video2... +

    +FreeBSD has a different naming of devices. When you build Motion for FreeBSD the default device name is /dev/bktr0. +Under FreeBSD a TV card has a special device for controlling the tuner (e.g. /dev/tuner0). The option tunerdevice +is only valid when Motion is built and running under FreeBSD. For Linux do not include this option in the config +file (remove or comment out). +

    +USB cameras take a lot of bandwidth. A USB camera connected to a USB 2 port or hub consumes virtually +all the bandwidth that the port can handle. Even with a small framesize and low framerate you should not expect to have +more than one camera per USB controller. If you need more than 1 USB camera it is possible to add extra USB PCI cards +to your computer. It is also possible that your computer has more than one controller for different USB slots. For +example, if the computer has six USB ports, the three on the left may be on controller A versus the three on the right +may be on controller B. In this situation, connecting two cameras to ports only on the left would not work due to +excessive bandwidth. However connecting one camera to port on the right and the other to the port on the left +may work since they are on different controllers. + +Motion permits the use of video cards that have discreet input channels. Since USB cameras do not have input channels, +the option input must be set to the value -1 for USB cameras. +

    + +Network cameras are set up via the netcam_url parameter. The latest versions of Motion support +rtsp format which many cameras now stream. The URL connection string to enter is specific to the camera and is +usually provided by the manufacturer. The connection string is the same as what would be used by other +video playing software such as VLC. If the camera does not stream via RTSP and instead uses a MJPEG, then Motion +can also view that format. See the option netcam_url for additional options. + +

    +Composite video cards are normally made with a chip called BT878 (older cards have a BT848). They +all use the Linux driver called 'bttv'. +

    +There are cards with more then one video input but still only one BT878 chip. They have a video multiplexer which +input is selected with the config option input. Input channel numbers start at 0 +(which is why the value -1 and not 0 disables input selection). There are video capture cards available +with 4 or 8 inputs but only one chip. They present themselves as one single video device and +you select input using the 'input' option. If you define e.g. 4 thread config files with the +same videodevice name but different input numbers Motion automatically +goes into round robin mode. +

    +Many TV tuner cards have the input channels: TV Tuner = 0, Standard composite video = 1, S-VHS = 3. +Others have TV=0, composite video 1= 1, composite video = 2, S-VHS = 3. +For video capture cards input 1 is normally the composite video input. +

    +Some capture cards are specially made for surveillance with for example 4 inputs. +Others have a TV tuner, a composite input (phono socket) and perhaps also a S-VHS input. +For all these cards the inputs are numbered. The numbering varies from card to card so the easiest +is to experiment for 5 minutes with a program that can show the videostream. +Use a program such as Camstream, xawtv or VLC to experiment with the values. +

    +If you use the TV tuner input you also need to set the frequency of the TV channel using the +option frequency. Otherwise set frequency to 0. +

    +Finally you need to set the TV norm. Values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour). Default is 0 (PAL). +If your camera is a PAL black and white you may get a better result with norm=3 (PAL no colour). +

    +

    +
+ +

Configuration Options

+
    + + +

    These are the options that can be used in the config file. -

    +

    All number values are integer numbers (no decimals allowed). Boolean options can be on or off. -

    -Some configuration options are only used if Motion is built on a system that has the matching software libraries installed (MySQL, PostgreSQL and FFMPEG). -

    -MySQL

      -
    • mysql_db, mysql_host, mysql_user, mysql_password -
    -

    -PostgreSQL

      -
    • pgsql_db, pgsql_host, pgsql_user, pgsql_password, pgsql_port -
    -

    -FFMPEG (libavcodec)

      -
    • ffmpeg_cap_new, ffmpeg_cap_motion, ffmpeg_filename, ffmpeg_timelapse, ffmpeg_timelapse_mode, ffmpeg_bps, ffmpeg_variable_bitrate, ffmpeg_video_codec -
    -

    -

    Options in Alphabetical Order.

    -

    -The table below lists all the Motion options in alphabetical order. Click on the option name to see a longer description of each. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +

    +Some configuration options are only used if Motion is built on a system that has the matching software libraries installed (MySQL, PostgreSQL, SQLite, FFMPEG, etc). +

    +

    + +System Processing +
      + +
    Option Range/Values
    Default
    Description
    auto_brightness Values: on, off
    Default: off
    Let motion regulate the brightness of a video device. Only recommended for cameras without auto brightness
    brightness Values: 0 - 255
    Default: 0 (disabled)
    The brightness level for the video device.
    contrast Values: 0 - 255
    Default: 0 (disabled)
    The contrast level for the video device.
    control_authentication Values: Max 4096 characters
    Default: Not defined
    To protect HTTP Control by username and password, use this option for HTTP 1.1 Basic authentication. The string is specified as username:password. Do not specify this option for no authentication. This option must be placed in motion.conf and not in a thread config file.
    control_html_output Values: on, off
    Default: on
    Enable HTML in the answer sent back to a browser connecting to the control_port. This option must be placed in motion.conf and not in a thread config file.
    control_localhost Values: on, off
    Default: on
    Limits the http (html) control to the localhost. This option must be placed in motion.conf and not in a thread config file.
    control_port Values: 0 - 65535
    Default: 0 (disabled)
    Sets the port number for the http (html using browser) based remote control. This option must be placed in motion.conf and not in a thread config file.
    daemon Values: on, off
    Default: off
    Start in daemon (background) mode and release terminal. This option must be placed in motion.conf and not in a thread config file.
    despeckle Values: EedDl
    Default: Not defined
    Despeckle motion image using combinations of (E/e)rode or (D/d)ilate. And ending with optional (l)abeling.
    ffmpeg_bps Values: 0 - 9999999
    Default: 400000
    Bitrate of mpegs produced by ffmpeg. Bitrate is bits per second. Default: 400000 (400kbps). Higher value mans better quality and larger files. Option requires that ffmpeg libraries are installed.
    ffmpeg_cap_motion Values: on, off
    Default: off
    Use ffmpeg libraries to encode motion type mpeg movies where you only see the pixels that changes.
    ffmpeg_cap_new Values: on, off
    Default: off
    Use ffmpeg libraries to encode mpeg movies in realtime.
    ffmpeg_deinterlace Values: on, off
    Default: off
    Use ffmpeg to deinterlace video. Necessary if you use an analog camera and see horizontal combing on moving objects in video or pictures.
    ffmpeg_filename (now called movie_filename) Values: Max 4095 characters
    Default: %v-%Y%m%d%H%M%S
    File path for motion triggered ffmpeg movies (mpeg) relative to target_dir. This option was renamed to movie_filename in 3.2.5 to enable better integration of alternative movie libraries to the current ffmpeg solution.
    ffmpeg_timelapse Values: 0 - 2147483647
    Default: 0 (disabled)
    Create a timelapse movie saving a picture frame at the interval in seconds set by this parameter. Set it to 0 if not used.
    ffmpeg_timelapse_mode Values: hourly, daily, weekly-sunday, weekly-monday, monthly, manual
    Default: daily
    The file rollover mode of the timelapse video.
    ffmpeg_variable_bitrate Values: 0, 2 - 31
    Default: 0 (disabled)
    Enables and defines variable bitrate for the ffmpeg encoder. ffmpeg_bps is ignored if variable bitrate is enabled. Valid values: 0 (default) = fixed bitrate defined by ffmpeg_bps, or the range 2 - 31 where 2 means best quality and 31 is worst.
    ffmpeg_video_codec Values: mpeg1 (ffmpeg-0.4.8 only), mpeg4, msmpeg4, swf, flv, ffv1
    Default: mpeg4
    Codec to be used by ffmpeg for the video compression. Timelapse mpegs are always made in mpeg1 format independent from this option.
    framerate Values: 2 - 100
    Default: 100 (no limit)
    Maximum number of frames to be captured from the camera per second.
    frequency Values: 0 - 999999
    Default: 0 (Not set)
    The frequency to set the tuner to (kHz). Valid range: per tuner spec, default: 0 (Don't set it)
    gap Values: 0 - 2147483647
    Default: 60
    Gap is the seconds of no motion detection that triggers the end of an event. An event is defined as a series of motion images taken within a short timeframe.
    height Values: Device Dependent
    Default: 288
    The height of each frame in pixels.
    hue Values: 0 - 255
    Default: 0 (disabled)
    The hue level for the video device.
    input Values: 0 - 7, 8 = disabled
    Default: 8 (disabled)
    Input channel to use expressed as an integer number starting from 0. Should normally be set to 1 for video/TV cards, and 8 for USB cameras.
    jpeg_filename Values: Max 4095 characters
    Default: %v-%Y%m%d%H%M%S-%q
    File path for motion triggered images (jpeg or ppm) relative to target_dir. Value 'preview' makes a jpeg filename with the same name body as the associated saved mpeg movie file.
    lightswitch Values: 0 - 100
    Default: 0 (disabled)
    Ignore sudden massive light intensity changes given as a percentage of the picture area that changed intensity.
    locate Values: on, off, preview
    Default: off
    Locate and draw a box around the moving object. Value 'preview' makes Motion only draw a box on a saved preview jpeg image and not on the saved mpeg movie.
    low_cpu Values: 0 - 100
    Default: 0 (disabled)
    When this option is not zero motion will be in a low cpu mode while not detecting motion. In low cpu mode Motion reduces the framerate to the value given for this option. Value zero means disabled.
    mask_file Values: Max 4095 characters
    Default: Not defined
    PGM file to use as a sensitivity mask. This picture MUST have the same width and height as the frames being captured and be in binary format.
    max_mpeg_time Values: 0 (infinite) - 2147483647
    Default: 3600
    The maximum length of an mpeg movie in seconds. Set this to zero for unlimited length.
    minimum_frame_time Values: 0 - 2147483647
    Default: 0
    Minimum time in seconds between the capturing picture frames from the camera. Default: 0 = disabled - the capture rate is given by the camera framerate.
    minimum_gap Values: 0 - 2147483647
    Default: 0 (no minimum)
    The minimum time between two shots in seconds.
    minimum_motion_frames Values: 1 - 1000s
    Default: 1
    Picture frames must contain motion at least the specified number of frames in a row before they are detected as true motion. At the default of 1, all motion is detected. Valid range is 1 to thousands, but it is recommended to keep it within 1-5.
    motion_video_pipe Values: Max 4095 characters
    Default: Not defined
    The video4linux video loopback input device for motion images. If a particular pipe is to be used then use the device filename of this pipe, if a dash '-' is given motion will use /proc/video/vloopback/vloopbacks to locate a free pipe. Default: not set
    movie_filename Values: Max 4095 characters
    Default: %v-%Y%m%d%H%M%S
    File path for motion triggered ffmpeg movies (mpeg) relative to target_dir. This was previously called ffmpeg_filename.
    mysql_db Values: Max 4095 characters
    Default: Not defined
    Name of the MySQL database.
    mysql_host Values: Max 4095 characters
    Default: localhost
    IP address or domain name for the MySQL server. Use "localhost" if motion and MySQL runs on the same server.
    mysql_password Values: Max 4095 characters
    Default: Not defined
    The MySQL password.
    mysql_user Values: Max 4095 characters
    Default: Not defined
    The MySQL user name.
    netcam_proxy Values: Max 4095 characters
    Default: Not defined
    URL to use for a netcam proxy server, if required. The syntax is http://myproxy:portnumber
    netcam_url Values: Max 4095 characters
    Default: Not defined
    Specify an url to a downloadable jpeg file or raw mjpeg stream to use as input device. Such as an AXIS 2100 network camera.
    netcam_userpass Values: Max 4095 characters
    Default: Not defined
    For network cameras protected by username and password, use this option for HTTP 1.1 Basic authentication. The string is specified as username:password. Do not specify this option for no authentication.
    night_compensate Values: on, off
    Default: off
    When this option is set the noise threshold will be lowered if the picture is dark. This will improve the sensitivity in dark places. However it might also increase the number of false alarms since most cameras also increase light sensitivity with their AGC (Automatic Gain Control) and this will increase noise.
    noise_level Values: 1 - 255
    Default: 32
    The noise level is used as a threshold for distinguishing between noise and motion.
    noise_tune Values: on, off
    Default: on
    Activates the automatic tuning of noise level.
    norm Values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour)
    Default: 0 (PAL)
    Select the norm of the video device. Values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour). Default: 0 (PAL)
    on_event_end Values: Max 4095 characters
    Default: Not defined
    Command to be executed when an event ends after a period of no motion. The period of no motion is defined by option gap. You can use Conversion Specifiers and spaces as part of the command.
    on_event_start Values: Max 4095 characters
    Default: Not defined
    Command to be executed when an event starts. An event starts at first motion detected after a period of no motion defined by gap. You can use ConversionSpecifiers and spaces as part of the command.
    on_motion_detected Values: Max 4095 characters
    Default: Not defined
    Command to be executed when a motion frame is detected. You can use Conversion Specifiers and spaces as part of the command.
    on_movie_end Values: Max 4095 characters
    Default: Not defined
    Command to be executed when an ffmpeg movie is closed at the end of an event. You can use Conversion Specifiers and spaces as part of the command. Use %f for passing filename (with full path) to the command.
    on_movie_start Values: Max 4095 characters
    Default: Not defined
    Command to be executed when an mpeg movie is created. You can use Conversion Specifiers and spaces as part of the command. Use %f for passing filename (with full path) to the command.
    on_picture_save Values: Max 4095 characters
    Default: Not defined
    Command to be executed when an image is saved. You can use Conversion Specifiers and spaces as part of the command. Use %f for passing filename (with full path) to the command.
    output_all Values: on, off
    Default: off
    Picture are saved continuously as if motion was detected all the time.
    output_motion Values: on, off
    Default: off
    Output pictures with only the moving object. This feature generates the special motion type movies where you only see the pixels that changes as a graytone image. If labelling is enabled you see the largest area in blue. Smartmask is shown in red.
    output_normal Values: on, off, first, best
    Default: on
    Normal image is an image that is stored when motion is detected. It is the same image that was taken by the camera. I.e. not a motion image like defined by output_motion. Default is that normal images are stored.
    pgsql_db Values: Max 4095 characters
    Default: Not defined
    Name of the PostgreSQL database.
    pgsql_host Values: Max 4095 characters
    Default: localhost
    IP address or domain name for the PostgreSQL server. Use "localhost" if motion and PostgreSQL runs on the same server.
    pgsql_password Values: Max 4095 characters
    Default: Not defined
    The PostgreSQL password.
    pgsql_port Values: 0 - 65535
    Default: 5432
    The PostgreSQL server port number.
    pgsql_user Values: Max 4095 characters
    Default: Not defined
    The PostgreSQL user name.
    post_capture Values: 0 - 2147483647
    Default: 0 (disabled)
    Specifies the number of frames to be captured after motion has been detected.
    ppm Values: on, off
    Default: off
    Output ppm images instead of jpeg. This uses less CPU time, but causes a LOT of hard disk I/O, and it is generally slower than jpeg.
    pre_capture Values: 0 - 100s
    Default: 0 (disabled)
    Specifies the number of previous frames to be outputted at motion detection. Recommended range: 0 to 5, default=0. Do not use large values! Large values will cause Motion to skip video frames and cause unsmooth mpegs. To smooth mpegs use larger values of post_capture instead.
    process_id_file Values: Max 4095 characters
    Default: Not defined
    File to store the process ID, also called pid file. Recommended value when used: /var/run/motion.pid
    quality Values: 1 - 100
    Default: 75
    The quality for the jpeg images in percent.
    quiet Values: on, off
    Default: off
    Be quiet, don't output beeps when detecting motion.
    rotate Values: 0, 90, 180, 270
    Default: 0 (not rotated)
    Rotate image the given number of degrees. The rotation affects all saved images as well as mpeg movies.
    roundrobin_frames Values: 1 - 2147483647
    Default: 1
    Specifies the number of frames to capture before switching inputs, this way also slow switching (e.g. every second) is possible.
    roundrobin_skip Values: 1 - 2147483647
    Default: 1
    Specifies the number of frames to skip after a switch. (1 if you are feeling lucky, 2 if you want to be safe).
    saturation Values: 0 - 255
    Default: 0 (disabled)
    The colour saturation level for the video device.
    setup_mode Values: on, off
    Default: off
    Run Motion in setup mode.
    smart_mask_speed Values: 0 - 10
    Default: 0 (disabled)
    Slugginess of the smart mask. Default is 0 = DISABLED. 1 is slow, 10 is fast.
    snapshot_filename Values: Max 4095 characters
    Default: %v-%Y%m%d%H%M%S-snapshot
    File path for snapshots (jpeg or ppm) relative to target_dir.
    snapshot_interval Values: 0 - 2147483647
    Default: 0 (disabled)
    Make automated snapshots every 'snapshot_interval' seconds.
    sql_log_image Values: on, off
    Default: on
    Log to the database when creating motion triggered image file.
    sql_log_mpeg Values: on, off
    Default: off
    Log to the database when creating motion triggered mpeg file.
    sql_log_snapshot Values: on, off
    Default: on
    Log to the database when creating a snapshot image file.
    sql_log_timelapse Values: on, off
    Default: off
    Log to the database when creating timelapse mpeg file
    sql_query Values: Max 4095 characters
    Default: insert into security(camera, filename, frame, file_type, time_stamp, text_event) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C')
    SQL query string that is sent to the database. The values for each field are given by using convertion specifiers
    switchfilter Values: on, off
    Default: off
    Turns the switch filter on or off. The filter can distinguish between most switching noise and real motion. With this you can even set roundrobin_skip to 1 without generating much false detection.
    target_dir Values: Max 4095 characters
    Default: Not defined = current working directory
    Target directory for picture and movie files.
    text_changes Values: on, off
    Default: off
    Turns the text showing changed pixels on/off.
    text_double Values: on, off
    Default: off
    Draw characters at twice normal size on images.
    text_event Values: Max 4095 characters
    Default: %Y%m%d%H%M%S
    This option defines the value of the speciel event conversion specifier %C. You can use any conversion specifier in this option except %C. Date and time values are from the timestamp of the first image in the current event.
    text_left Values: Max 4095 characters
    Default: Not defined
    User defined text overlayed on each in the lower left corner. Use A-Z, a-z, 0-9, " / ( ) @ ~ # < > \ , . : - + _ \n and conversion specifiers (codes starting by a %).
    text_right Values: Max 4095 characters
    Default: %Y-%m-%d\n%T
    User defined text overlayed on each in the lower right corner. Use A-Z, a-z, 0-9, " / ( ) @ ~ # < > , . : - + _ \n and conversion specifiers (codes starting by a %). Default: %Y-%m-%d\n%T = date in ISO format and time in 24 hour clock
    thread Values: Max 4095 characters
    Default: Not defined
    Specifies full path and filename for a thread config file. Each camera needs a thread config file containing the options that are unique to the camera. If you only have one camera you do not need thread config files. If you have two or more cameras you need one thread config file for each camera in addition to motion.conf. This option must be placed in motion.conf and not in a thread config file.
    threshold Values: 1 - 2147483647
    Default: 1500
    Threshold for declaring motion. The threshold is the number of changed pixels counted after noise filtering, masking, despeckle, and labelling.
    threshold_tune Values: on, off
    Default: off
    Activates the automatic tuning of threshold level.
    timelapse_filename Values: Max 4095 characters
    Default: %v-%Y%m%d-timelapse
    File path for timelapse mpegs relative to target_dir (ffmpeg only).
    track_auto Values: on, off
    Default: off
    Enable auto tracking
    track_iomojo_id Values: 0 - 2147483647
    Default: 0
    Use this option if you have an iomojo smilecam connected to the serial port instead of a general stepper motor controller.
    track_maxx Values: 0 - 2147483647
    Default: 0
    The maximum position for servo x.
    track_maxy Values: 0 - 2147483647
    Default: 0
    The maximum position for servo y.
    track_motorx Values: -1 - 2147483647
    Default: -1
    The motor number that is used for controlling the x-axis.
    track_motory Values: -1 - 2147483647
    Default: -1
    The motor number that is used for controlling the y-axis.
    track_move_wait Values: 0 - 2147483647
    Default: 10
    Delay during which tracking is disabled after auto tracking has moved the camera. Delay is defined as number of picture frames.
    track_port Values: Max 4095 characters
    Default: Not defined
    This is the device name of the serial port to which the stepper motor interface is connected.
    track_speed Values: 0 - 255
    Default: 255
    Speed to set the motor to.
    track_step_angle_x Values: 0-90
    Default: 10
    Angle in degrees the camera moves per step on the X-axis with auto tracking. Currently only used with pwc type cameras.
    track_step_angle_y Values: 0-40
    Default: 10
    Angle in degrees the camera moves per step on the Y-axis with auto tracking. Currently only used with pwc type cameras.
    track_stepsize Values: 0 - 255
    Default: 40
    Number of steps to make.
    track_type Values: 0 (none), 1 (stepper), 2 (iomojo), 3 (pwc), 4 (generic), 5 (uvcvideo)
    Default: 0 (None)
    Type of tracker.
    tunerdevice Values: Max 4095 characters
    Default: /dev/tuner0
    The tuner device used for controlling the tuner in a tuner card. This option is only used when Motion is compiled for FreeBSD.
    video_pipe Values: Max 4095 characters
    Default: Not defined
    The video4linux video loopback input device for normal images. If a particular pipe is to be used then use the device filename of this pipe. If a dash '-' is given motion will use /proc/video/vloopback/vloopbacks to locate a free pipe.
    videodevice Values: Max 4095 characters
    Default: /dev/video0 (FreeBSD: /dev/bktr0)
    The video device to be used for capturing. Default for Linux is /dev/video0. for FreeBSD the default is /dev/bktr0.
    webcam_limit Values: 0 - 2147483647
    Default: 0 (unlimited)
    Limit the number of frames to number frames. After 'webcam_limit' number of frames the connection will be closed by motion. The value 0 means unlimited.
    webcam_localhost Values: on, off
    Default: on
    Limits the access to the webcam to the localhost.
    webcam_maxrate Values: 1 - 100
    Default: 1
    Limit the framerate of the webcam in frames per second. Default is 1. Set the value to 100 for practically unlimited.
    webcam_motion Values: on, off
    Default: off
    If set to 'on' Motion sends slows down the webcam stream to 1 picture per second when no motion is detected. When motion is detected the stream runs as defined by webcam_maxrate. When 'off' the webcam stream always runs as defined by webcam_maxrate.
    webcam_port Values: 0 - 65535
    Default: 0 (disabled)
    TCP port on which motion will listen for incoming connects with its webcam server.
    webcam_quality Values: 1 - 100
    Default: 50
    Quality setting in percent for the mjpeg picture frames transferred over the webcam connection. Keep it low to restrict needed bandwidth.
    width Values: Device Dependent
    Default: 352
    The width in pixels of each frame. Valid range is camera dependent.
    + + + + + + + + + + + + + + + + + + + +
    daemon process_id_file setup_mode logfile
    log_level log_type sdl_threadnr thread
    -

    -

    -

    Signals (sent with e.g. kill command)

    -A signal can be sent from the command line by typing e.g. kill -s SIGHUP pid, where the last parameter is the process ID which you get by typing ps -ef ¦ grep motion. The PID is the first on the list which is the parent process for the threads. -Motion responds to the following signals: -

    - - - - + +

    +

    +

    + + +Video4Linux Devices +
      + +
    Signal Description Editors comment
    SIGHUP The config file will be reread. This is a very useful signal when you experiment with settings in the config file.
    SIGTERM If needed motion will create an mpeg file of the last event and exit  
    SIGUSR1 Motion will create an mpeg file of the current event.  
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    videodevice v4l2_palette tunerdevice input
    norm #frequency power_line_frequency auto_brightness
    brightness contrast saturation hue
    roundrobin_frames roundrobin_skip switchfilter
    +

    +

    +

    +
+ +Network Cameras + + +Image_Processing + + +Motion Detection + + +Script Execution + + +Output - General + + +Output - Picture + + +Output - Movie +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    max_movie_time ffmpeg_output_movies ffmpeg_output_debug_movies ffmpeg_timelapse
    ffmpeg_timelapse_mode ffmpeg_bps ffmpeg_variable_bitrate ffmpeg_video_codec
    ffmpeg_duplicate_frames movie_filename timelapse_filename
    -

    -

    -

    Error Logging

    -Motion reports errors to the console when it runs in non-daemon mode. And it outputs even more information when run in setup mode. -

    -Error logging has been implemented so that errors during daemon (background) mode are logged in the syslog. -

    -The syslog is in most Linux systems the file /var/log/messages (e.g. RedHat/Fedora) or /var/log/syslog and /var/log/user.log (e.g. Debian). -

    -

    -

    Motion Guide - Basic Features

    -

    -

    Capture Device Options - The Basic Setup

    -Before you can start using motion you need to know some basics about your camera. -Either you have a camera connected directly to your computer. In this case it is a video4linux type of camera. Or you connect to a network camera using a normal web URL. -

    -

    video4linux (V4L) devices

    -You need to install your camera with the right driver. It is out of scope of this document to tell you how to do this and it depends on which type of camera. -

    -Once installed the camera(s) will have the device names /dev/video0, /dev/video1, /dev/video2... -

    -FreeBSD has a different naming of devices. When you build Motion for FreeBSD the default device name is /dev/bktr0. Under FreeBSD a TV card has a special device for controlling the tuner (e.g. /dev/tuner0). The option tunerdevice is only valid when Motion is built and running under FreeBSD. For Linux do not include this option in the config file (remove or comment out). -

    -USB cameras take a lot of bandwidth. A USB camera connected to a USB 1.1 port or hub consumes all the bandwidth. Even with a small framesize and low framerate you should not expect to have more than one camera per USB 1.1 controller. If you need more than 1 USB camera add extra USB PCI cards to your computer. There exists cards that have 4 inputs each with their own controller and with full bandwidth. Many 4-input cards only have 1 controller. USB cameras do not have the feature of selecting input channels. To disable the input selection the option input must be set to the value 8 for USB cameras. -

    -Composite video cards are normally made with a chip called BT878 (older cards have a BT848). They all use the Linux driver called 'bttv'. -

    -There are cards with more then one video input but still only one BT878 chip. They have a video multiplexer which input is selected with the config option input. Input channel numbers start at 0 (which is why the value 8 and not 0 disables input selection). There are video capture cards available with 4 or 8 inputs but only one chip. They present themselves as one single video device and you select input using the 'input' option. If you define e.g. 4 thread config files with the same videodevice name but different input numbers Motion automatically goes into round robin mode. See the round robin section for more information. Many TV tuner cards have the input channels: TV Tuner = 0, Standard composite video = 1, S-VHS = 3. Other have TV=0, composite video 1= 1, composite video = 2, S-VHS = 3. For video capture cards input 1 is normally the composite video input. -

    -Some capture cards are specially made for surveillance with for example 4 inputs. Others have a TV tuner, a composite input (phono socket) and perhaps also a S-VHS input. For all these cards the inputs are numbered. The numbering varies from card to card so the easiest is to experiment for 5 minutes with a program that can show the videostream. Use a program such as Camstream or xawtv to experiment with the values. -

    -If you use the TV tuner input you also need to set the frequency of the TV channel using the option frequency. Otherwise set 'frequency' to 0. -

    -Finally you need to set the TV norm. Values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour). Default is 0 (PAL). If your camera is a PAL black and white you may get a better result with norm=3 (PAL no colour). -

    -If the netcam_url option is defined all the video4linux options are ignored so make sure the netcam_url option is commented out if you do not need it. -

    -These are the parameters used for video4linux devices -

    -

    + +

    +

    +

    +
+ +Output - Pipe + + +Stream and Webcontrol + + +Database + + +Tracking + + +Conversion Specifiers +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    %Y year %m month %d date
    %H hour %M minute %S second
    %T HH:MM:SS %v event %q frame number
    %t thread (camera) number %D changed pixels %N noise level
    %i width of motion area, %J height of motion area, %J height of motion area,
    %K X coordinates of motion center %L Y coordinates of motion center %C value defined by text_event
    %f filename with full path %n number indicating filetype
    +

    +The use of quotation marks around string is permitted. The conversion specifiers used have +the same options as for the C function strftime (3) plus the few that are unique to Motion. +

    +

    +
+ + +

System Processing

+
    + +

    +

    daemon

    +

    +
      +
    • Type: Boolean
    • +
    • Range / Valid values: on, off
    • +
    • Default: off
    • +
    +

    +When Motion is started, immediately go to daemon mode and release the terminal. +

    + +

    process_id_file

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values:
    • +
    • Default: Not Defined
    • +
    +

    +Specify the full path and file name in order to store the pid for processing. +

    + +

    setup_mode

    +

    +
      +
    • Type: Boolean
    • +
    • Range / Valid values: on, off
    • +
    • Default: off
    • +
    +

    +When this option is turned on, Motion starts in setup mode so that the +parameters can be set more easily. In setup mode two things happen: +With 'motion -s' Motion runs in console mode instead of daemon. It outputs a lot of +useful information for each frame from the camera. Each message is prefixed by [number] +where number is the camera number (thread number). +When you look at the webcam stream you see a black image with numbers. +What you see is the number of changed pixels, number of labeled areas and noise setting. +When something moves you see the pixels detected as Motion in black and white. The largest +labeled area (assuming despeckle is enabled and with the 'l' at the end) is blue. It is +only the blue areas which is counted as Motion. If smartmask is enabled you see this as red areas. + +Here is a suggestion how to initially setup Motion. +

    +
      +
    • Disable despeckle (comment it out in motion.conf).
    • +
    • Disable smartmask
    • +
    • Enable both http control and webcam by setting port numbers. Example 8080 for control and 8081 for webcam.
    • +
    • Start Motion in setup mode
    • +
    • View the webcam stream. Either with Iceweasel or with Firefox by entering in the address of + http://localhost:8080/ +
    • +
    • Open a new tab and connect to the http interface. + http://localhost:8080/ . + You can now control and change almost anything while Motion is running. To disable a feature enter a space.
    • +
    • Start by experimenting with noise level. Do this both during daylight and during darkness. + You will be surprised to see how much noise a camera makes during night. Try using the automatic + noise feature. It should work for most.
    • +
    • Now try the despeckle feature. Enable it using the recommended default EedDl. If this is not enough experiment. + Remember that the l must be the last letter.
    • +
    • Set the threshold to what you want to trigger Motion.
    • +
    +In normal mode you can use the same setting with two browser tabs and experiment with +settings of the camera if needed. +From the web interface you can ask Motion to write all your changes back to the config files +(motion.conf and thread config files). +

    + +

    logfile

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default: Not Defined
    • +
    +

    +Use this option to specify the full path and filename to use +for logging of the messages generated from Motion. If this option +is not defined, the stderr and syslog is used. Note that Motion +can generate a LOT of messages and as a result, this option should +be considered if the log_level is at any of the higher levels. + +

    + +

    log_level

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: 1 - 9
    • +
    • Default: 6
    • +
    +

    +This option specifies the level of verbosity of the messages sent from Motion. +At a level of 8(DBG), there are a LOT of messages. At a level of 1(EMR) virtually no +messages will be output. +

    +The various levels are [1..9] (EMR, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL). +

    +

    + +

    log_type

    +

    +
      +
    • Type: Discreet Strings
    • +
    • Range / Valid values: See Below
    • +
    • Default: ALL
    • +
    +

    +The different components of Motion use different log types. This option allows the +user to only show the messages from particular components. The choices for this option +are: COR, STR, ENC, NET, DBL, EVT, TRK, VID, ALL + +

    + +

    thread

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default: Not Defined
    • +
    +

    +The full path and file name for the thread file. +Motion allows for this line to be listed in the motion.conf file multiple +times. These specifications should be the LAST lines in the +motion.conf file. +See the Configuration Files section within +this guide for a completed discussion of what to put into the +thread0.conf, thread1.conf, threadX.conf files that would be specified +in this option. +

    + +

    sdl_threadnr

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default:
    • +
    +

    +The SDL option is optional and unusual. When SDL is included in the +building of Motion, there is the ability for Motion to create a SDL preview +window for the user. The author believes this option to be more of a proof +of concept on how to create a SDL window and show the image. (This same functionality +can be achieved via the stream options) To activate the SDL window, include SDL support in +the building of the Motion application. Start Motion and note the +thread number indicated. Once that is noted, specify that thread number (or 1 more than that number) +for this option. When Motion is started again, it will then create a SDL window to preview +the image. To close the window, press X. Author is not aware of any method to restart the +SDL window after it has been closed. + +

    +

    +
+ +

Video4Linux Device

+
    +

    +

    videodevice

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default: /dev/video0 (FreeBSD: /dev/bktr0)
    • +
    +

    +The video device to be used for capturing. Default for Linux is /dev/video0. for FreeBSD the default is /dev/bktr0. +See the Basic Setup +section of this guide for a additional discussion of this option. +

    +This is the video4linux device name. Ignore this for net cameras. +

    + +

    v4l2_palette

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default:
    • +
    +

    +The v4l2_palette allows the user to choose preferable palette to be use by Motion. Note that this +is only the preferred option. If the video device does not support the requested format, Motion will +loop through the available palettes to try to find one that is supported by both Motion and the device. +Motion will report the supported palettes of the device when Motion starts when the log_level +is specified as NTC or higher. The default of 17 is highly preferred since this the native +format that Motion uses internally. +
      +
    • V4L2_PIX_FMT_SN9C10X : 0 'S910'
    • +
    • V4L2_PIX_FMT_SBGGR16 : 1 'BYR2'
    • +
    • V4L2_PIX_FMT_SBGGR8 : 2 'BA81'
    • +
    • V4L2_PIX_FMT_SPCA561 : 3 'S561'
    • +
    • V4L2_PIX_FMT_SGBRG8 : 4 'GBRG'
    • +
    • V4L2_PIX_FMT_SGRBG8 : 5 'GRBG'
    • +
    • V4L2_PIX_FMT_PAC207 : 6 'P207'
    • +
    • V4L2_PIX_FMT_PJPG : 7 'PJPG'
    • +
    • V4L2_PIX_FMT_MJPEG : 8 'MJPEG'
    • +
    • V4L2_PIX_FMT_JPEG : 9 'JPEG'
    • +
    • V4L2_PIX_FMT_RGB24 : 10 'RGB3'
    • +
    • V4L2_PIX_FMT_SPCA501 : 11 'S501'
    • +
    • V4L2_PIX_FMT_SPCA505 : 12 'S505'
    • +
    • V4L2_PIX_FMT_SPCA508 : 13 'S508'
    • +
    • V4L2_PIX_FMT_UYVY : 14 'UYVY'
    • +
    • V4L2_PIX_FMT_YUYV : 15 'YUYV'
    • +
    • V4L2_PIX_FMT_YUV422P : 16 '422P'
    • +
    • V4L2_PIX_FMT_YUV420 : 17 'YU12'
    • + +
    + +

    + +

    tunerdevice

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default: /dev/tuner0
    • +
    +

    +The tuner device used for controlling the tuner in a tuner card. This option is only used when Motion is compiled +for FreeBSD. Make sure to remove or comment out this option when running Motion under Linux. +See the Basic Setup section of this guide for a additional discussion of this option. +

    + +

    input

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: -1, 0 - 7
    • +
    • Default: 1 (Disabled) /li> +
    +

    +Input channel to use expressed as an integer number starting from 0. +This option should normally be set to 1 for video/TV cards, and -1 for USB cameras. +This parameter is used only with video capture cards that has more than one input. +However if you set the input number to e.g. 1 for a USB camera Motion writes an error message +back. If you set it to -1 it does not give you any warning. +If you have a video capture card you can define the channel to tune to using this option. +If you are using a USB device, network camera or a capture card without tuner you should +set the value to the default -1. +Many TV tuner cards have the input channels: TV Tuner = 0, +Standard composite video = 1, S-VHS = 3. Other have TV=0, composite video 1= 1, +composite video = 2, S-VHS = 3. It is recommended to set the parameter to -1 for USB cameras as +your first try. For video capture cards input 1 is normally the composite video input. +

    + +

    norm

    +

    +
      +
    • Type: Discrete Strings
    • +
    • Range / Valid values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour)
    • +
    • Default: 0 (PAL)
    • +
    +

    +Select the norm of the video device. Values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour). Default: 0 (PAL) +This value is only used for capture cards using the BTTV driver. +

    + +

    frequency

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: 0 - 999999
    • +
    • Default: 0 (Not set)
    • +
    +

    +The frequency to set the tuner to (kHz) per the tuner specifications. The default is 0 meaning +not set. This option is only relevant if you have a TV tuner card where you can select the tuner frequency. +Your tuner card must support this feature. +

    + +

    power_line_frequency

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: -1 to 3
    • +
    • Default: -1
    • +
    +

    +This option allows the user to specify the power line frequency that is applicable to the user. This option +can help stabilize the images of some webcams that are sensitive to this frequency. This is not normally necessary. +
      +
    • -1 : Do not modify device setting
    • +
    • 0 : Power line frequency Disabled
    • +
    • 1 : 50hz
    • +
    • 2 : 60hz
    • +
    • 3 : Auto
    • +
    + +

    +

    auto_brightness

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    • Option Topic -
    -

    +

    +
      +
    • Type: Boolean
    • +
    • Range / Valid values: on, off
    • +
    • Default: off
    • +
    +

    Let motion regulate the brightness of a video device. Only recommended for cameras without auto brightness -

    -Motion will try to adjust the brightness of the video device if the images captured are too dark or too light. This option will be most useful for video devices like web cams, which sometimes don't have such an option in hardware. -

    -The auto_brightness feature will adjust the brightness of the device up or down until the value defined by the option brightness is reached (1 = dark, 255 = bright). If brightness is zero auto_brightness will try to adjust to the average brightness level 128. -

    -You need to know if the camera supports auto brightness. Most cameras have auto everything. If your video device already does this for you this option might cause oscillations. If you do not know assume that it has and do not use the Motion auto brightness feature. At least not to start with. -

    -

    -

    brightness

      -
    • Type: Integer -
    • Range / Valid values: 0 - 255 -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    -The brightness level for the video device. -

    -Value 0 means that Motion does not set the brightness value but leaves it unchanged. -

    -If this setting is used in conjunction with the auto_brightness feature then this setting is the average brightness level in the range 1 (dark) to 255 (bright) that the auto_brightness feature will try to achieve by adjusting the device brightness up and down. -

    -

    -

    contrast

      -
    • Type: Boolean -
    • Range / Valid values: 0 - 255 -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    -The contrast level for the video device. -

    -Disabled (Value 0) means that Motion does not set the contrast value. -

    -

    -

    framerate

    -

      -
    • Type: Integer -
    • Range / Valid values: 2 - 100 -
    • Default: 100 (no limit) -
    • Option Topic -
    -

    -Maximum number of frames to be captured from the camera per second. -

    -The faster you fetch pictures from the camera the more CPU load you get and the more pictures get included when Motion is detected. -

    -Motion will stop storing pictures if the framerate is set to less than 2. -

    -Set this parameter to the maximum number of images per second that you want to store either as images or as mpeg films. -

    -To set intervals longer than one second use the 'minimum_gap' option instead. -

    -

    -

    frequency

    -

      -
    • Type: Boolean -
    • Range / Valid values: 0 - 999999 -
    • Default: 0 (Not set) -
    • Option Topic -
    -

    -The frequency to set the tuner to (kHz). Valid range: per tuner spec, default: 0 (Don't set it) -

    -This option is only relevant if you have a TV tuner card where you can select the tuner frequency. Your tuner card must support this feature. -

    -

    -

    height

    -

      -
    • Type: Integer -
    • Range / Valid values: Device Dependent -
    • Default: 288 -
    • Option Topic -
    -

    -The height of each frame in pixels. -

    -The height of the image in pixels. Motion does not scale so should be set to the actual size of the v4l device. In case of a net camera motion sets the height to the height of the first image read. -

    -Motion actually set the size of the image coming from the video4linux device. -

    -Your camera or capture/TV card will not support any picture size. You must know which frame size (width and height) the camera supports. If you do not know start with width 320 and height 240 which most cameras and capture cards supports. -

    -For some device drivers like pwc (driver for Philips USB cameras) setting the size to a non-standard value makes the driver create an image of the nearest smaller size and create a gray band around the image to fit the size given by motion. Note that it is the driver and not motion that generates the gray band. Motion will try to detect motion in the entire image including the gray band. -

    -Motion requires that dimensions of camera image must have both height and width that are a multiple of 16. Thís is normally not a problem. All standard sizes like 640, 480, 352, 320, 288, 240, ...etc are multiples of 16. -

    -

    +Motion will try to adjust the brightness of the video device if the images captured are too dark or too light. +This option will be most useful for video devices which sometimes don't have such an option in +hardware. The auto_brightness feature will adjust the brightness of the device up or down until the value defined +by the option brightness is reached (1 = dark, 255 = bright). If brightness is zero auto_brightness will try to +adjust to the average brightness level 128. You need to know if the camera supports auto brightness. Most cameras +have auto everything. If your video device already does this for you this option might cause oscillations. If you +do not know assume that it has and do not use the Motion auto brightness feature. At least not to start with. +

    + +

    brightness

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: 0 - 255
    • +
    • Default: 0 (disabled)
    • +
    +

    +The brightness level for the video device. Value 0 means that Motion does not set the brightness value but +leaves it unchanged. If this setting is used in conjunction with the auto_brightness feature then this setting +is the average brightness level in the range 1 (dark) to 255 (bright) that the auto_brightness feature will try +to achieve by adjusting the device brightness up and down. +

    + +

    contrast

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: 0 - 255
    • +
    • Default: 0 (disabled)
    • +
    +

    +The contrast level for the video device. Disabled (Value 0) means that Motion does not set the contrast value. +

    + +

    saturation

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: 0 - 255
    • +
    • Default: 0 (disabled)
    • +
    +

    +The color saturation level for the video device. +

    +

    hue

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 255 -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: 0 - 255
    • +
    • Default: 0 (disabled)
    • +
    +

    The hue level for the video device. -

    -Normally only relevant for NTSC cameras. -

    -

    -

    input

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 7, 8 = disabled -
    • Default: 8 (disabled) -
    • Option Topic -
    -

    -Input channel to use expressed as an integer number starting from 0. Should normally be set to 1 for video/TV cards, and 8 for USB cameras. -

    -This parameter is really used only with video capture cards that has more than one input. -

    -However if you set the input number to e.g. 1 for a USB camera (ov511 or pwc driver) motion writes an error message back. If you set it to 8 it does not give you any warning. -

    -If you have a video capture card you can define the channel to tune to using this option. If you are using a USB device, network camera or a capture card without tuner you should set the value to the default 8. -

    -Many TV tuner cards have the input channels: TV Tuner = 0, Standard composite video = 1, S-VHS = 3. Other have TV=0, composite video 1= 1, composite video = 2, S-VHS = 3. It is recommended to set the parameter to 8 for USB cameras as your first try. For video capture cards input 1 is normally the composite video input. -

    -

    -

    minimum_frame_time

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 2147483647 -
    • Default: 0 -
    • Option Topic -
    -

    -Minimum time in seconds between the capturing picture frames from the camera. Default: 0 = disabled - the capture rate is given by the camera framerate. -

    -This option is used when you want to capture images at a rate lower than 2 per second. -

    -When this is enabled the framerate option is used only to set the pace the Motion service the webcam port etc. Running Motion at framerate 2 is normally fine. -

    -ALERT! This feature is introduced in Motion 3.2.7 -

    - -

    -

    -

    norm

    -

      -
    • Type: Discrete Strings -
    • Range / Valid values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour) -
    • Default: 0 (PAL) -
    • Option Topic -
    -

    -Select the norm of the video device. Values: 0 (PAL), 1 (NTSC), 2 (SECAM), 3 (PAL NC no colour). Default: 0 (PAL) -

    -This value is only used for capture cards using the BTTV driver. -

    -

    +

    + + +

    roundrobin_frames

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: 1 - 2147483647
    • +
    • Default: 1
    • +
    +

    +Specifies the number of frames to capture before switching inputs, this way also slow switching (e.g. every second) +is possible. The Round Robin feature is automatically activated where multiple threads are sharing the same video +device. Each thread can then set different input channels or frequencies to change camera. If multiple threads use +the same video device, they each can capture roundrobin_frames number of frames before having to share the device +with the other threads. +

    +The RoundRobin feature is automatically activated where multiple threads are sharing the same +video device (for example /dev/video0). Each thread can then set different input channels +to change camera with the input option or by tuning the tuner with the +frequency option. +Round Robin is not relevant for Network cameras or standard USB web cameras. +The Round Robin feature is used with video capture cards which have multiple inputs per video chip. +Note that round robin is not the ideal way to run multiple cameras. When the capture card changes +input it takes a little while before the decoder chip has syncronized to the new camera. You can +improve this if you have expensive cameras with a syncronize input. Only one camera can be decoded +at a time so if you have 4 cameras connected 3 of the camera threads will need to wait for their +turn. The fact that cameras have to take turns and the fact that you have to skip a few frames after +each turn dramatically lowers the possible framerate. You can get a high framerate by viewing each +camera for a long time. But then you may miss the action on one of the inactive cameras. If you can +afford it avoid Round Robin and buy the more expensive type of capture cards that has one decoder chip +per input. If you only need 2 or 3 cameras you can also simply put 2 or 3 cheap TV cards in the computer. +Linux has no problem working with multiple TV cards. (or better yet, it multiple cheap network cameras) +If multiple threads use the same video device, they each can capture roundrobin_frames number of frames +before having to share the device with the other threads. +When another thread wants to watch another input or frequency or size the first +roundrobin_skip number of frames are skipped to allow the device to settle. +The last option switch_filter is supposed to prevent the change of camera from being detected +as Motion. Its function is not perfect and sometimes prevents detection of real motion. You should start +with having the option disabled and then try with the option enabled to see if you can skip less frames +without loosing the detection of the type of motion you normally want to detect. + + +

    + +

    roundrobin_skip

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: 1 - 2147483647
    • +
    • Default: 1
    • +
    +

    +Specifies the number of frames to skip after a switch. (1 if you are feeling lucky, 2 if you want to be safe). +The Round Robin feature is automatically activated where multiple threads are sharing the same video device. +Each thread can then set different input channels or frequencies to change camera. +When another thread wants to watch another input or frequency or size the first roundrobin_ +skip number of frames are skipped to allow the device to settle. +

    + +

    switchfilter

    +

    +
      +
    • Type: Boolean
    • +
    • Range / Valid values: on, off
    • +
    • Default: off
    • +
    +

    +Turns the switch filter on or off. The filter can distinguish between most switching noise and real motion. With this +you can even set roundrobin_skip to 1 without generating much false detection. +This is a round robin related feature used when you have a capture card with multiple inputs (controlled by the +'input' option) on the same videodevice. +

    +

    +
+ +

Network Cameras

+
    +

    +Motion can connect to a network camera through a normal TCP socket. All you need to give it is the URL. +The URL given must return either one single jpeg picture or an mjpeg stream. For the time being Motion +cannot connect to a video stream such a mpeg, mpeg4, divx. The URL must return one single jpeg image, a mjpeg stream +a rtsp stream, file or ftp. When getting a still image, make sure to validate that the camera is serving up +a actual raw JPG file and not a HTML page with an embedded JPG which is the current +standard. +When the netcam_url is defined the video4linux options above are ignored. +If the connection to a network camera is lost, Motion will reuse the last good image for +approx 30 seconds. After 30 seconds the image is replaced by a grey image with a text +telling that the signal is lost and when the connection was lost. +This text and its date format is not configurable. + + +

    netcam_url

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default: Not defined
    • +
    +

    +URL to use if you are using a network camera, size will be autodetected +Available prefixes to the URL: +
      +
    • http://
    • +
    • ftp://
    • +
    • mjpg://
    • +
    • rtsp://
    • +
    • mjpeg://
    • +
    • file:///
    • +
    + +The prefixes of mjpg and mjpeg are not actual protocols and allow the user to specify +different formats and methods to access the network stream. They are internally translated +into http. For options such as rtsp, it is recommended that the connection string be +validated with other applications such as ffplay or VLC. + +

    +When the netcam_url is defined the video4linux options are ignored. +

    + +

    netcam_userpass

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default: Not defined
    • +
    +

    +The Username and password for the network camera. For http protocols, this +option is for HTTP 1.1 Basic authentication only. The string is specified as username:password. +To use no authentication simply remove this option. Digest authentication is only available for rtsp cameras. + +

    + +

    netcam_keepalive

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default:
    • +
    +

    +The setting for keep-alive of network socket, should improve performance on compatible net cameras. +
      +
    • off: The historical implementation using HTTP/1.0, closing the socket after each http request.
    • +
    • force: Use HTTP/1.0 requests with keep alive header to reuse the same connection.
    • +
    • on: Use HTTP/1.1 requests that support keep alive as default.
    • +
    + +

    + +

    netcam_proxy

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default: Not defined
    • +
    +

    +URL to use for a netcam proxy server, if required. The syntax is +http://myproxy:portnumber +Use this if you need to connect to a network camera through a proxy server. +Example of syntax: "http://myproxy.mydomain.com:1024 +If the proxy port number is 80 you can ommit the port number. Then the syntax is use "http://myproxy.mydomain.com" . +Leave this option undefined if you do not use a proxy server. +

    + +

    netcam_tolerant_check

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default:
    • +
    +

    +Use less strict jpeg checks for network cameras +

    + +

    rtsp_uses_tcp

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: on off
    • +
    • Default: on
    • +
    +

    +This option specifies the transport method for rtsp cameras. The TCP transport is highly preferred because +without this option the rtsp images are frequently corrupted and result in many false positive values and +images that appear to be smeared. Off indicates that UDP will be used. +

    +

    +
+ +

Image Processing

+
    +

    rotate

    -

      -
    • Type: Discrete Strings -
    • Range / Valid values: 0, 90, 180, 270 -
    • Default: 0 (not rotated) -
    • Option Topic -
    -

    -Rotate image the given number of degrees. The rotation affects all saved images as well as mpeg movies. -

    -The rotation feature is used when the camera is hanging upside down (180 degrees) or if you choose a picture format in portrait instead of the normal landscape (90 or 270 degrees). -

    -Note that the CPU load increases when using this feature with a value other than 0. Also note that Motion automatically swaps width and height if you rotate 90 or 270 degrees, so you don't have to touch these options. -

    -

    -

    saturation

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 255 -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    -The colour saturation level for the video device. -

    -

    -

    tunerdevice

    -

      -
    • Type: String -
    • Range / Valid values: Max 4095 characters -
    • Default: /dev/tuner0 -
    • Option Topic -
    -

    -The tuner device used for controlling the tuner in a tuner card. This option is only used when Motion is compiled for FreeBSD. -

    -Make sure to remove or comment out this option when running Motion under Linux. -

    -

    -

    videodevice

    -

      -
    • Type: String -
    • Range / Valid values: Max 4095 characters -
    • Default: /dev/video0 (FreeBSD: /dev/bktr0) -
    • Option Topic -
    -

    -The video device to be used for capturing. Default for Linux is /dev/video0. for FreeBSD the default is /dev/bktr0. -

    -This is the video4linux device name. Ignore this for net cameras. -

    -

    +

    +
      +
    • Type: Discrete Strings
    • +
    • Range / Valid values: 0, 90, 180, 270
    • +
    • Default: 0 (not rotated)
    • +
    +

    +Rotate image the given number of degrees. The rotation affects all saved images as well as movies. +The rotation feature is used when the camera is hanging upside down (180 degrees) or if you choose a picture +format in portrait instead of the normal landscape (90 or 270 degrees). +Note that the CPU load increases when using this feature with a value other than 0. Also note that +Motion automatically swaps width and height if you rotate 90 or 270 degrees, so you don't have to touch these options. +

    +

    width

    -

      -
    • Type: Integer -
    • Range / Valid values: Device Dependent -
    • Default: 352 -
    • Option Topic -
    -

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: Device Dependent
    • +
    • Default: 352
    • +
    +

    The width in pixels of each frame. Valid range is camera dependent. -

    Motion does not scale so should be set to the actual size of the v4l device. -

    -In case of a net camera motion sets the height to the height of the first image read. -

    +In case of a net camera motion sets the height to the height of the first image read +except for rtsp streams which does rescale the network camera image to the +requested dimensions. Note that this rescaling comes at a very high CPU cost so it +is recommended that the network camera send the image in the same dimensions as included +in the configuration file. Motion actually set the size of the image coming from the video4linux device. -

    -Your camera or capture/TV card will not support any picture size. You must know which frame size (width and height) the camera supports. If you do not know start with width 320 and height 240 which most cameras and capture cards supports. -

    -For some device drivers like pwc (driver for Philips USB cameras) setting the size to a non-standard value makes the driver create an image of the nearest smaller size and create a gray band around the image to fit the size given by motion. Note that it is the driver and not motion that generates the gray band. Motion will try to detect motion in the entire image including the gray band. -

    -Motion requires that dimensions of camera image must have both height and width that are a multiple of 16. Thís is normally not a problem. All standard sizes like 640, 480, 352, 320, 288, 240, ...etc are multiples of 16. -

    -

    -

    Network Cameras

    -Motion can connect to a network camera through a normal TCP socket. All you need to give it is the URL. The URL given must return either one single jpeg picture or an mjpeg stream. For the time being Motion cannot connect to a video stream such a mpeg, mpeg4, divx. The URL must return one single jpeg image or an mjpeg stream! You can connect through a proxy server. -

    -Also watch out that you do not use a URL that create an HTML page with an embedded jpg. What must be returned is the jpg picture itself or the raw mjpeg stream. -

    -When the netcam_url is defined all the video4linux options above are ignored!! -

    -If the connection to a network camera is lost - Motion will reuse the last good image for approx 30 seconds. AFter 30 seconds the image is replaced by a grey image with a text telling that the signal is lost and when the connection was lost. This text and its date format is not configurable and there are no plans to make it configurable in order to keep the number config options under control. -

    -Note that Motion requires that dimensions of camera image must have both height and width that are a multiple of 16. Thís is normally not a problem. All standard sizes like 640, 480, 352, 320, 288, 240, ...etc are multiples of 16. But if you intend to monitor a network camera which is saving jpeg images you may have to pay attention to the dimensions of the picture. -

    -The network camera feature has been completely re-written in Motion 3.2.2. We believe the netcam feature is much more stable now that it was in previous versions. Motion tries to reconnect to the camera if the connection is lost. There is no official standard for mjpeg and we know that there are probably still some cameras that are not yet supported. If you run into a problem please file a Bug Report with as much information about the format as possible. A binary raw dump of the first 2-3 frames with headers and boundary strings is very useful. You can see how to make it on the special topic NetcamMjpegStreamDumps. When you have the file you can upload it to the same topic. -

    -

    -

    netcam_proxy

    -

      -
    • Type: String -
    • Range / Valid values: Max 4095 characters -
    • Default: Not defined -
    • Option Topic -
    -

    -URL to use for a netcam proxy server, if required. The syntax is http://myproxy:portnumber -

    -Use this if you need to connect to a network camera through a proxy server. -

    -Example of syntax: "http://myproxy.mydomain.com:1024 -

    -If the proxy port number is 80 you can ommit the port number. Then the syntax is use "http://myproxy.mydomain.com" . -

    -Leave this option undefined if you do not use a proxy server. -

    -

    -

    netcam_url

    -

      -
    • Type: String -
    • Range / Valid values: Max 4095 characters -
    • Default: Not defined -
    • Option Topic -
    -

    -Specify an url to a downloadable jpeg file or raw mjpeg stream to use as input device. Such as an AXIS 2100 network camera. -

    -Example of URL: http://www.gate.com/pe1rxq/jeroen.jpg. -

    -Motion can connect to a network camera through a normal TCP socket. All you need to give it is the URL. The URL given must return either one single jpeg picture or an mjpeg stream. For the time being Motion cannot connect to a video stream such a mpeg, mpeg4, divx. The URL must return one single jpeg image or an mjpeg stream! -

    -Also watch out that you do not use a URL that create an HTML page with an embedded jpg. What must be returned is the jpg picture itself or the raw mjpeg stream. -

    -When the netcam_url is defined all the video4linux options are ignored!! -

    -Motion can also fetch jpeg pictures via ftp. You then use the ftp:// syntax instead. -

    -

    -

    netcam_userpass

    -

      -
    • Type: String -
    • Range / Valid values: Max 4095 characters -
    • Default: Not defined -
    • Option Topic -
    -

    -For network cameras protected by username and password, use this option for HTTP 1.1 Basic authentication. The string is specified as username:password. Do not specify this option for no authentication. -

    -To use no authentication simply remove this option from the config file comment it out with "#" or ";" in front. -

    -

    -

    - -

    Round Robin feature

    -This feature is automatically activated where multiple threads are sharing the same video device (for example /dev/video0). Each thread can then set different input channels to change camera with the input option or by tuning the tuner with frequency option. -

    -ALERT! Round Robin is not relevant for Network cameras or standard USB web cameras. The Round Robin feature is used with video capture cards which have multiple inputs per video chip. -

    -ALERT! Note that round robin is not the ideal way to run multiple cameras. When the capture card changes input it takes a little while before the decoder chip has syncronized to the new camera. You can improve this if you have expensive cameras with a syncronize input. Only one camera can be decoded at a time so if you have 4 cameras connected 3 of the camera threads will need to wait for their turn. The fact that cameras have to take turns and the fact that you have to skip a few frames after each turn dramatically lowers the possible framerate. You can get a high framerate by viewing each camera for a long time. But then you may miss the action on one of the inactive cameras. If you can affort it avoid Round Robin and buy the more expensive type of capture cards that has one decoder chip per input. If you only need 2 or 3 cameras you can also simply put 2 or 3 cheap TV cards in the computer. Linux has no problem working with multiple TV cards. -

      -
    • If multiple threads use the same video device, they each can capture roundrobin_frames number of frames before having to share the device with the other threads. -
    • When another thread wants to watch another input or frequency or size the first roundrobin_skip number of frames are skipped to allow the device to settle. -
    • The last option switch_filter is supposed to prevent the change of camera from being detected as Motion. Its function is not perfect and sometimes prevents detection of real motion. You should start with having the option disabled and then try with the option enabled to see if you can skip less frames without loosing the detection of the type of motion you normally want to detect. -
    -

    -These are the special Round Robin options -

    -

    -

    roundrobin_frames

    -

      -
    • Type: Integer -
    • Range / Valid values: 1 - 2147483647 -
    • Default: 1 -
    • Option Topic -
    -

    -Specifies the number of frames to capture before switching inputs, this way also slow switching (e.g. every second) is possible. -

    -The Round Robin feature is automatically activated where multiple threads are sharing the same video device. Each thread can then set different input channels or frequencies to change camera. -

    -If multiple threads use the same video device, they each can capture roundrobin_frames number of frames before having to share the device with the other threads. -

    -

    -

    roundrobin_skip

    -

      -
    • Type: Integer -
    • Range / Valid values: 1 - 2147483647 -
    • Default: 1 -
    • Option Topic -
    -

    -Specifies the number of frames to skip after a switch. (1 if you are feeling lucky, 2 if you want to be safe). -

    -The Round Robin feature is automatically activated where multiple threads are sharing the same video device. Each thread can then set different input channels or frequencies to change camera. -

    -When another thread wants to watch another input or frequency or size the first roundrobin_skip number of frames are skipped to allow the device to settle. -

    -

    -

    switchfilter

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    • Option Topic -
    -

    -Turns the switch filter on or off. The filter can distinguish between most switching noise and real motion. With this you can even set roundrobin_skip to 1 without generating much false detection. -

    -This is a round robin related feature used when you have a capture card with multiple inputs (controlled by the 'input' option) on the same videodevice. -

    -ALERT! This feature was seriously broken until Motion 3.2.4 -

    -

    -

    Motion Detection Settings

    -These are the options that controls the detection of motion. Further details follows after. -

    -

    +Your camera or capture/TV card will not support any picture size. You must know +which frame size (width and height) the camera supports. If you do not know start with +width 320 and height 240 which most cameras and capture cards supports. +For some device drivers like pwc (driver for Philips USB cameras) setting the +size to a non-standard value makes the driver create an image of the nearest +smaller size and create a gray band around the image to fit the size given by +motion. Note that it is the driver and not motion that generates the gray band. +Motion will try to detect motion in the entire image including the gray band. +Older versions of Motion required that dimensions of image must have both height and width that are a multiple of 16. +The latest versions have eliminated this requirement. +

    + +

    height

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: Device Dependent
    • +
    • Default: 288
    • +
    +

    +The height of the image in pixels. Motion does not scale so should be set to the actual size of the device. +In case of a net camera motion sets the height to the height of the first image read +except for rtsp streams which does rescale the network camera image to the +requested dimensions. Note that this rescaling comes at a very high CPU cost so it +is recommended that the network camera send the image in the same dimensions as included +in the configuration file. +Motion actually set the size of the image coming from the device. +Your camera or capture/TV card will not support any picture size. You must know which frame size +(width and height) the camera supports. If you do not know start with width 320 and height 240 which +most cameras and capture cards supports. +For some device drivers like pwc (driver for Philips USB cameras) setting the size to a non-standard value +makes the driver create an image of the nearest smaller size and create a gray band around the image to fit +the size given by motion. Note that it is the driver and not motion that generates the gray band. Motion will +try to detect motion in the entire image including the gray band. +Older versions of Motion required that dimensions of image must have both height and width that are a multiple of 16. +The latest versions have eliminated this requirement. +

    + +

    framerate

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: 2 - 100
    • +
    • Default: 100 (no limit)
    • +
    +

    +Maximum number of frames to be captured from the camera per second. +The faster you fetch pictures from the camera the more CPU load you +get and the more pictures get included when Motion is detected. +Motion will stop storing pictures if the framerate is set to less than 2. +Set this parameter to the maximum number of images per second that you want +to store either as images or as movies. +To set intervals longer than one second use the 'minimum_gap' option instead. +

    + +

    minimum_frame_time

    +

    +
      +
    • Type: Integer
    • +
    • Range / Valid values: 0 - 2147483647
    • +
    • Default: 0
    • +
    +

    +Minimum time in seconds between the capturing picture frames from the camera. Default: 0 = disabled - the capture +rate is given by the camera framerate. +This option is used when you want to capture images at a rate lower than 2 per second. +When this is enabled the framerate option is used only to set the pace the Motion service the +webcam port etc. + +

    +

    despeckle

    -

      -
    • Type: String -
    • Range / Valid values: EedDl -
    • Default: Not defined -
    • Option Topic -
    -

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: EedDl
    • +
    • Default: Not defined
    • +
    +

    Despeckle motion image using combinations of (E/e)rode or (D/d)ilate. And ending with optional (l)abeling. -

    -A way of tuning (by removing or enhancing) noise in the motion image. Options for the despeckle feature are any of 'e', 'E', 'd' or 'D'. This can be combined by a trailing 'l' (letter l) which enables the labeling feature. Default: Not Defined (Don't despeckle and label). -

    -Wind blowing grass and trees around or poor light conditions can cause a lot of dots (or noise) to appear in the motion image (See the section on Tuning Motion). This feature removes (or enhances!) this noise and so improves the reliability of motion. -

    -The 'e' option removes diamonds, 'E' removes squares and alternating eE will remove circles. Each e/E you add will shrink the noise by a pixel all the way around. So 'despeckle Ee' will remove circles of radius 2. However, this will also shrink the detection by 2 and will affect the threshold. So to remove noise and then restore the detected motion to its original size try 'despeckle EedD'. -

    -After the despeckle feature is done you can let the labeling feature search for areas of connected pixels and "label" each area. The program will now trigger motion based on the number of changed pixels in the largest area. In other words, the largest labeled area has to be above the threshold to trigger a motion detected. -

    -The value EedDl is a good starting point. The possible combinations are endless and it requires many experiments to find the best combination. Just remember that the labeling feature only works as intended if it runs after the despeckle feature. Ie. the letter 'l' must be the last letter and only one 'l'. -

    -If you have very few problems with false detections leave this option either blank or at EedD which will remove most of the single pixel noise. -A very detailed technical explanation of the despeckle part can be found at the webpage of the author of this feature Ian McConnell's Webcam: Motion Web Page -

    -

    -

    gap

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 2147483647 -
    • Default: 60 -
    • Option Topic -
    -

    -Gap is the seconds of no motion detection that triggers the end of an event. An event is defined as a series of motion images taken within a short timeframe. -

    -Recommended value is 60 seconds (Default). The value 0 is allowed (but not recommended) and disables events causing all Motion to be written to one single mpeg file and no pre_capture. You can force an event to end and a new to begin using the http control 'http://host:port/thread_number/action/makemovie'. Disabling events has bad side effects on noise_tune and smartmask. Both features can only work properly outside an event. When gap is set to 0, both features don't work properly anymore. -

    -An event is defined as a series of motion images taken within a short timeframe. E.g. a person walking through the room is an event that may have caused 10 single jpg images to be stored. This option defines how long a pause between detected motions that is needed to be defined as a new event. -

    -The gap timer starts after the last motion is detected and post_capture images have been saved and appended to open movie mpeg files. -

    -Any motion detected before the gap timer times out resets the gap timer so it starts counting over again. -

    -Detailed Description -

    -The option 'gap' is important. It defines how long a period of no motion detected it takes before we say an event is over. An event is defined as a series of motion images taken within a short timeframe. E.g. a person walking through the room is an event that may have caused 10 single jpg images to be stored. Motion detected includes post_captured frames set by the 'post_capture' option. The 'gap' option defines how long a pause between detected motions that is needed to be defined as a new event. A good starting value is 60 seconds. -

    -The way 'gap' works in more technical terms is:

      -
    • Gap is a timer that timeout 'gap' seconds after the last video frame with motion is detected. -
    • If 'post_capture' is activated then the gap timer starts counting after the last image of the post_capture buffer has been saved. -
    • The gap timer is reset and starts all over each time new motion is detected, so you will not miss any action by having a short 'gap' value. It will just create more events (e.g. more mpegs files) -
    -

    -The gap value impacts many functions in Motion.

      -
    • When the gap timer runs out the event number is increased by one next time motion is detected. When you use the %v conversion specifier in filenames or text features this means that the number in filename or text increased by one. -
    • The pre_capture feature only works at the beginning of an event. So if you have a very large 'gap' value pre_capture is not working very often. -
    • When you make mpegs using the ffmpeg features a new mpeg file is started at the beginning of an event when the first motion is detected. When 'gap' seconds has passed without motion (and post_captured frames saved) the mpeg files is completed and closed. -
    • Do not use large gap values to generate one large mpeg4 file. If Motion stops working this mpeg4 file never gets properly completed and closed and you will not be able to view it. -
    • Some of the tracking features sets the camera back to the center position when an event is over. -
    -

    -Note that 'gap' and 'minimum_gap' have nothing to do with each other. -

    -

    -

    lightswitch

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 100 -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    -Ignore sudden massive light intensity changes given as a percentage of the picture area that changed intensity. -

    -Experiment to see what works best for your application. -

    -Note: From version 3.1.17 (snap release 2 and on) this option has changed from a boolean (on or off) to a number in percent between 0 and 100. Zero means the option is disabled. -

    -The value defines the picture areas in percent that will trigger the lightswitch condition. When lightswitch is detected motion detection is disabled for 5 picture frames. This is to avoid false detection when light conditions change and when a camera changes sensitivity at low light. -

    -

    -

    low_cpu

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 100 -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    -When this option is not zero motion will be in a low cpu mode while not detecting motion. In low cpu mode Motion reduces the framerate to the value given for this option. Value zero means disabled. -

    -This is smart for running a server that also does other tasks such as running Apache, MySQL etc. Motion grabs this lower number of frames per second until it detects motion. Then it speeds up to normal speed and take pictures as set by the option "framerate". -

    -

    -

    mask_file

    -

      -
    • Type: String -
    • Range / Valid values: Max 4095 characters -
    • Default: Not defined -
    • Option Topic -
    -

    -PGM file to use as a sensitivity mask. This picture MUST have the same width and height as the frames being captured and be in binary format. -

    -Full path of the PGM (portable gray map) mask file (binary format). -

    -If you have one or more areas of the camera image in which you do NOT want motion detected (e.g. a tree that moves in the wind or a corner of the picture where you can see cars/pedestrians passing by) you need a mask file. This file is a picture that you create in your favorite photo editing program. The areas that you want detected must be white. The error that you want ignored must be black. The pgm image must be the same size (number of pixels high and wide) as the pictures that are taken by the camera (video4linux device). -

    -You can adjust sensitivity by using gray tones. -

    -If you do not have a mask file disable this option by not having it in the config file or comment it out ("#"or ";" as first character in line). -If you are using the rotate option, note that the mask is applied after the rotation. -

    -Detailed Description -

    -The mask file must be a pgm format image file (portable gray map). Note that you must choose the BINARY format. -

    -The feature is simple. Create an image of exact the same size as the ones you get from your video device (camera). Make a purely white picture and paint the areas that you want to mask out black. You can also make gray areas where you want to lower the sensitivity to motion. Normally you will stick to pure black and white. -

    -One easy method for generating the mask file is as follows. -

    -You can just take a motion captured picture, edit it with black and white for the mask and save it as a pgm file. -If you cannot save in this format save as a grayscale jpg and then you can convert it to pgm format with -

    -djpeg -grayscale -pnm [inputfile] > mask.pgm -

    -(assuming you have djpeg installed - part of the jpeg lib package). -

    -Note that the mask file option masks off the detection of motion. The entire picture is still shown on the picture. This means that you cannot use the feature to mask off an area that you do not want people to see. -

    -Below are an example of a webcam picture and a mask file to prevent the detection cars in the street. -

    -Normal picture. Notice the street is visible through the hedge. -

    -normal.jpg -

    -Mask file (converted to png format so it can be shown by your web browser) -

    - -
    mask1.png
    -

    -

    -

    max_mpeg_time

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 (infinite) - 2147483647 -
    • Default: 3600 -
    • Option Topic -
    -

    -The maximum length of an mpeg movie in seconds. Set this to zero for unlimited length. -

    -

    -

    - -

    -

    -

    minimum_gap

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 2147483647 -
    • Default: 0 (no minimum) -
    • Option Topic -
    -

    -The minimum time between two shots in seconds. -

    -This is the minimum gap between the storing pictures while detecting motion. -

    -The value zero means that pictures can be stored almost at the framerate of the camera. Normally you will set this to 0 -

    -This option has nothing to do with the 'gap' option. -

    -ALERT! From motion 3.2.7 this feature has been removed because it was in practical a useless feature. It prevented saving more than one picture per minimum_gap seconds but the capturing and motion detect was still run at full framerate loading the CPU heavily. From 3.2.7 a new feature called minimum_frame_time has been introduced which lower the capture rate. So it gives the same effect as minimum_gap did but additionally lower the CPU load significantly. -

    -

    -

    minimum_motion_frames

    -

      -
    • Type: Boolean -
    • Range / Valid values: 1 - 1000s -
    • Default: 1 -
    • Option Topic -
    -

    -Picture frames must contain motion at least the specified number of frames in a row before they are detected as true motion. At the default of 1, all motion is detected. Valid range is 1 to thousands, but it is recommended to keep it within 1-5. -

    -Note that the picture frames are buffered by Motion and once motion is detected also the first frames containing motion are saved so you will not miss anything. -

    -The feature is used when you get many false detections when the camera changes light sensitivity or light changes. -

    -Experiment for best setting. Even though Motion accepts large values you should set this to a relatively low number (below 10). For each step larger than 1 Motion reserves space in RAM for the picture frame buffer. If you have a large value Motion will miss many frames from the camera while it is processing the all the pictures in the buffer. -

    -

    -

    night_compensate

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    • Option Topic -
    -

    -When this option is set the noise threshold will be lowered if the picture is dark. This will improve the sensitivity in dark places. However it might also increase the number of false alarms since most cameras also increase light sensitivity with their AGC (Automatic Gain Control) and this will increase noise. -

    -It has normally been the advice not to use this with 'noise_tune' turned on. However the latest experience is that with the new improved noise_tune algorithm it actually works fine in combination with 'night_compensate'. -

    -

    -

    noise_level

    -

      -
    • Type: Integer -
    • Range / Valid values: 1 - 255 -
    • Default: 32 -
    • Option Topic -
    -

    -The noise level is used as a threshold for distinguishing between noise and motion. -

    -This is different from the threshold parameter. This is changes at pixel level. The purpose is to eliminate the changes generated by electric noise in the camera. Especially in complete darkness you can see the noise as small grey dots that come randomly in the picture. This noise can create false motion detection. What this parameter means is that the intensity of a pixel must change more than +/- the noise threshold parameter to be counted. -

    -

    -

    noise_tune

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: on -
    • Option Topic -
    -

    -Activates the automatic tuning of noise level. -

    -This feature makes Motion continuously adjust the noise threshold for distinguishing between noise and motion. The 'noise_level' setting is ignored when activating this feature. This is a new feature and new algorithm. It may give different results depending on camera and light conditions. Report your experience with it on the Motion mailing list. If it does not work well, deactivate the 'noise_tune' option and use the manual setting of 'noise_level' instead. -

    -

    -

    output_all

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    • Option Topic -
    -

    -Picture are saved continuously as if motion was detected all the time. -

    -This feature is not meant to be the normal mode of operation. Especially not if you have the output_normal or output_motion features enabled since it will keep on saving pictures on the disk and you will soon run out of disk space. So be careful with this command. -

    -If your frame rate is 10 pictures per second motion will save 10 new picture pr second until the disk is full. -

    -It does all the normal actions that are done when motion is detected. It saves pictures on the harddisk, execute external scripts, etc as fast as the frame rate of the camera. So it is probably a good idea to run with a low framerate when using this feature and to not use activate all the features that saves files on the disk. -

    -The idea of this feature is that you can turn the feature on and off for a short period of time to test or to generate continuous mpeg films when needed. -

    -

    -

    post_capture

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 2147483647 -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    -Specifies the number of frames to be captured after motion has been detected. -

    -The purpose of this is mainly to create smooth video clips each time motion is detected. Use it to you personal taste (and disk space).. -

    -This option is the preferred way to create continuous movies. Post_capture does not consume extra RAM and it does not create pauses in the movie even with large values. -

    -If you only store mpegs movies and do not have output_normal on, then the recommended post_capture value is what is equivalent to 1-5 seconds of movie. -

    -

    -

    pre_capture

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 100s -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    -Specifies the number of previous frames to be outputted at motion detection. Recommended range: 0 to 5, default=0. Do not use large values! Large values will cause Motion to skip video frames and cause unsmooth mpegs. To smooth mpegs use larger values of post_capture instead. -

    -Motion buffers the number of picture frames defined by 'pre_capture'. When motion is detected the pictures in the buffer are included in the video clip generated by ffmpeg. The effect is that it seems the program knew in advance that the event was going to take place and started the recording before it actually happened. This is a nice feature that give more complete video clips of an event. -

    -If pre_capture is set to 0 the feature is disabled. Keep this value below 5. -

    -The recommended value would be approx 0.5 second of video so the value should be defined so it fits the framerate and the desired pre-capture time. E.g. 0.5 second at 20 frames pr second would mean a value of 5. You should never use a value larger than 10. -

    -You can in theory have up to 100s of pre-captured frames but naturally this makes motion leave a larger footprint in the memory of the computer. More important Motion is processing all the buffered images including saving jpegs, encoding mpegs, writing to databases and executing external programs after the first image is detected as Motion. -

    -Motion will not grab another image until this is done. This means that even moderate values for pre_capture combined with high framerates will mean that you will miss quite many frames of Motion. It is therefore recommended to use relative small values for pre_capture. Depending on your chosen framerate and depending on the features enabled values from 1-5 are sensible. -

    -If you wish to create smooth mpegs during events using large pre_capture values will do the opposite! It will create a long pause where a lot of action is missed. -

    -To get a smooth mpeg use a large value for post_capture which does not cost any performance hit or RAM space. -

    -

    -

    smart_mask_speed

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 10 -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    -Slugginess of the smart mask. Default is 0 = DISABLED. 1 is slow, 10 is fast. -

    -Smartmask is a dynamic, self-learning mask. Smartmask will disable sensitivity in areas with frequent motion (like trees in the wind). Sensitivity is turned on again after some time of no more motion in this area. The built mask is a bit larger at the borders than the actual motion was. This way smartmask works more reliable when sudden moves occur under windy conditions. -

    -smart_mask_speed - tunes the slugginess of the mask. It accepts values from 0 (turned off) to 10 (fast). Fast means here that the mask is built quick, but it is also not staying very long with no more motion. Slow means that it takes a while until the mask is built but it also stays longer. A good start value for smart_mask_speed is 5. This setting is independent from the framerate. The attack and decay time is constant over all available framerates. -

    -When smartmask is enabled and motion is also configured to either write motion-images or motion-mpegs, the current smartmask is copied as an overlay into the black/white motion-pictures/mpegs in red colour. Same thing happens to the webcam stream when Motion runs in setup_mode. That way you can easily adjust smart_mask_speed. -

    -Detailed Description -

    -The mask_file option provides a static mask to turn off sensitivity in certain areas. This is very usefull to mask a street with cars passing by all day long etc... -

    -But imagine a scenario with large bushes and big trees where all the leaves are moving in the wind also triggering motion from time to time even with despeckle turned on. Of course you can also define a static mask here, but what if the bushes are growing during spring and summer? Well, you have to adapt the mask from time to time. What if the camera position moves slightly? What if someone grows new plants in your garden? You always have to setup a new static mask. -

    -The answer to this problem is the smart mask feature introduced in Motion 3.1.18. A dynamic, self-learing mask. -

    -Smart mask will disable sensitivity in areas with frequent motion (like trees in the wind). Sensitivity is turned on again after some time of no more motion in this area. The built mask is a bit larger at the borders than the actual motion. This way smartmask works more reliably when sudden moves occur under windy conditions. -

    -

    -

    threshold

    -

      -
    • Type: Integer -
    • Range / Valid values: 1 - 2147483647 -
    • Default: 1500 -
    • Option Topic -
    -

    -Threshold for declaring motion. The threshold is the number of changed pixels counted after noise filtering, masking, despeckle, and labelling. -

    -The 'threshold' option is the most important detection setting. When motion runs it compares the current image frame with the previous and counts the number of changed pixels after having processed the image with noise filtering, masking, despeckle and labeling. If more pixels than defined by 'threshold' have changed we assume that we have detected motion. Set the threshold as low as possible so that you get the motion you want detected but large enough so that you do not get detections from noise and plants moving. Note that the larger your frames are, the more pixels you have. So for large picture frame sizes you need a higher threshold. -

    -Use the -s (setup mode) command line option and/or the text_changes config file option to experiment to find the right threshold value. If you do not get small movements detected (see the mouse on the kitchen floor) lower the value. If motion detects too many birds or moving trees, increase the number. Practical values would be from a few hundred to 2000 indoors and 1000-10000 outdoors. -

    -

    -

    threshold_tune

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    • Option Topic -
    -

    -Activates the automatic tuning of threshold level. -

    -This feature makes Motion continuously adjust the threshold for declaring motion. -

    -The threshold setting is ignored when activating this feature. It may give different results depending on your camera, light conditions, indoor/outdoor, the motion to be detected etc. If it does not work well, deactivate the 'threshold_tune' option and use the manual setting of threshold instead. -

    -

    -

    Image File Output

    -The following options controls how Motion generates images when detection motion. -

    -

    -

    output_motion

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    • Option Topic -
    -

    -Output pictures with only the moving object. This feature generates the special motion type movies where you only see the pixels that changes as a graytone image. If labelling is enabled you see the largest area in blue. Smartmask is shown in red. -

    -Motion images shows the motion content of the pictures. This is good for tuning and testing but probably not very interesting for the general public. -

    -Default is not to store motion images. Motion pictures are stored the same place and with the same filename as normal motion triggered pictures except they have an "m" appended at the end of the filename before the .jpg or .ppm. E.g. the name can be 01-20020424232936-00m.jpg. -

    -

    -

    output_normal

    -

      -
    • Type: Discrete Strings -
    • Range / Valid values: on, off, first, best -
    • Default: on -
    • Option Topic -
    -

    -Normal image is an image that is stored when motion is detected. It is the same image that was taken by the camera. I.e. not a motion image like defined by output_motion. Default is that normal images are stored. -

    -If you set the value to 'first' Motion saves only the first motion detected picture per event. -

    -If you set it to "best" Motion saves the picture with most changed pixels during the event. This is useful if you store mpegs on a webserver and want to present a jpeg to show the content of the mpeg on a webpage. "best" requires a little more CPU power and resources compared to "first". -

    -Set to 'off' to don't write pictures ( jpeg or ppm ). -

    -

    -

    ppm

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    • Option Topic -
    -

    -Output ppm images instead of jpeg. This uses less CPU time, but causes a LOT of hard disk I/O, and it is generally slower than jpeg. -

    -The recommendation is to always use jpg except if you have a specific need to store high quality pictures without any quality loss. For web cameras you should always choose jpg. Note that the built in webcam server requires that this parameter is set to off. -

    -

    -

    quality

    -

      -
    • Type: Integer -
    • Range / Valid values: 1 - 100 -
    • Default: 75 -
    • Option Topic -
    -

    -The quality for the jpeg images in percent. -

    -100 means hardly compressed. A small number means a much smaller file size but also a less nice quality image to look at. 50 is a good compromise for most. -

    -

    -

    Tuning Motion

    -

    -Motion 3.2 introduces a new feature Setup Mode. This is a great new feature with really make tuning all the settings of Motion much more easy and transparent. In setup mode two things happen: -

      -
    1. With 'motion -s' Motion runs in console mode instead of daemon. It outputs a lot of useful information for each frame from the camera. Each message is prefixed by [number] where number is the camera number (thread number). -
    2. When you look at the mjpeg webcam stream you see a black image with numbers. What you see is the number of changed pixels, number of labeled areas and noise setting. When something moves you see the pixels detected as Motion in black and white. The largest labelled area (assuming despeckle is enabled and with the 'l' at the end) is blue. It is only the blue areas which is counted as Motion. If smartmask is enabled you see this as red areas. -
    -

    -Here is a suggestion how to initially setup Motion. -

      -
    • Disable despeckle (comment it out in motion.conf). -
    • Disable smartmask -
    • Enable both http control and webcam by setting port numbers. Example 8080 for control and 8081 for webcam. -
    • Start Motion in setup mode -
    • View the webcam stream. Either with Cambozola or with Firefox. http://localhost:8081/ Firefox often needs to reload the page before it works. Bug in Firefox. Internet Explorer cannot show the stream unless you make a webpage on your Apache with Cambozola applet. -
    • Open new browser window and connect to the http interface. http://localhost:8080/ . You can now control and change almost anything while Motion is running. You cannot resize the image. That was too hard to code. To disable a feature enter a space. -
    • Start by experimenting with noise level. Do this both during daylight and during darkness. You will be surprised to see how much noise a camera makes during night. Try using the automatic noise feature. It should work for most. -
    • Now try the despeckle feature. Enable it using the recommended default EedDl. If this is not enough experiment. Remember that the l must be the last letter. It is fun to play with. -
    • Set the threshold to what you want to trigger Motion. -
    -

    -In normal mode you can use the same setting with two browser windows and experiment with settings of the camera if needed. -

    -From the web interface you can ask Motion to write all your changes back to the config files (motion.conf and thread config files). It will even tidy them up for you so they look nice. -

    -There are two sets of options to adjust.

    -

    -


    -

    -Normal picture frame -

    -outputnormal1.jpg -

    -


    -Motion type picture frame with despeckle. Note that the largest area is blue and only this is counted as Motion. -

    -The Motion image shows how Motion maintains a "reference frame" which is not just the last picture frame but a matematical calculation of the past images. This enlarges real Motion and ensures that it is not easy to sneak in slowly. -

    -outputmotion1.jpg -


    -

    -

    -

    Generating MPEG films with ffmpeg

    -The ffmpeg option can generate mpeg films very fast and "on the fly". This means that the mpeg film is growing each time motion is detected. -

    -Some people on the Motion mailing list have had trouble building the ffmpeg package because they did not have the NASM assembler package installed. So pay attention to this if you run into problems. -

    -ffmpeg exists as binary packages for most distributions including RPMs and debian packages. -

    -Ffmpeg is an interesting project. The releases have not been very consistent over time. The official releases are out of date now. So we are forced to take our chance and checkout a version from their CVS server and hope that we are lucky in getting a version that works. See ffmpeg project page. We encourage the maintaners of such an important project to introduce better release schedules in the near future for the benefit of opensource software. -

    -In order to help people finding a version of ffmpeg that works we have started testing the Motion package with a selection of binaries and a CVS snapshot. The CVS source snapshot of ffmpeg which is certified with Motion is available on the Related projects file area on the Motion Sourceforge project -

    -Motion works with the following versions of ffmpeg:

      -
    • ffmpeg-0.4.8. With this release Motion supports mpeg1, mpeg4 and msmpeg4. Lately newer distributions have problems building this 2003 release of ffmpeg so many of you no longer have this option. -
    • ffmpeg-0.4.9pre1. Is supported starting from Motion version 3.1.18. With this release Motion supports mpeg4 and msmpeg4 but not mpeg1. The reason is that the ffmpeg team has decided no longer to support non-standard framerates in their mpeg1 encoder library. Also ffmpeg-0.4.9pre1 gives people problems on newer distributions. -
    • ffmpeg from CVS. This may work. We cannot continuously monitor and try every time a new source file is checked into ffmpeg. You will have to try. -
    • ffmpeg RPMs. Currently each Motion release is tested with the current Livna ffmpeg rpm package for Fedora. See the Download Files page for direct links to the version which has been certified with the latest Motion release. -
    • ffmpeg debian binaries. Latest versions from the debian repository for Debian Sarge works fine with Motion. -
    • Certified ffmpeg CVS snapshot for latest Motion release is available from the Motion Sourceforge Related Projects file area -
    -

    -The timelapse feature always runs mpeg1 with both ffmpeg 0.4.8 and 0.4.9 and newer. Motion simply creates the timelapse film with a standard mpeg1 framerate. Note : maximum size for timelapse files is 2GB. -

    -In principle Motion can be made to support many other formats. It requires additional coding in Motion. You are welcome to submit patches. All ffmpeg related code is in the source file ffmpeg.c. It is not trivial to do because the ffmpeg libraries not documented at all. All you have is a couple of code examples. -

    -To build ffpmeg from source follow these steps: -

    -Download the ffmpeg and untar it to /usr/local/ffmpeg. Then it should be a simple matter of entering the ffmpeg directory and run the commands -

    -

    -cd /usr/local/ffmpeg
    -./configure --enable-shared
    -make
    -make install
    -
    -

    -This creates the libavcodec.so and libavformat.so libraries under /usr/local/lib and header files under /usr/local/include/ffmpeg. -

    -You probably need to do one more step. -

    -Make sure you have 'root' privileges for the next steps. -

    -Open the file /etc/ld.so.conf in your favorite text editor. -

    -Add this line of text if it is not already there - otherwise go to the next step (ldconfig). -

    -/usr/local/lib -Run the command ldconfig. -

    -Motion should now be able to find the shared libraries for ffmpeg (libavcodec.so and libavformat.so) in /usr/local/lib. -

    -You can also find a pre-compiled binary package (e.g. rpm or deb) and install this. Normally an rpm will place the libavcodec.so under /usr/lib. -There are various RPMs available from different repositories. Some need additional RPMs that are actually not needed by Motion but need to be installed to satisfy dependencies. The editor has tried different RPMs of ffmpeg-0.4.8 and they all seem to work. -

    -Motion then need to be built by running ./configure, make and make install. -(Note that with earlier versions of motion you had to specify the location of libavcodec. Now configure searches for the shared library in /usr/lib and /usr/local/lib by default.) -

    -Note that if you install ffmpeg from source and already have ffmpeg installed from an RPM, the Motion configure may very well find the binary library from the rpm instead of the sources. Make sure to uninstall any old ffmpeg RPMs before you install ffmpeg from sources. -

    -These are the config file options related to ffmpeg. -

    -

    -

    ffmpeg_bps

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 9999999 -
    • Default: 400000 -
    • Option Topic -
    -

    -Bitrate of mpegs produced by ffmpeg. Bitrate is bits per second. Default: 400000 (400kbps). Higher value mans better quality and larger files. Option requires that ffmpeg libraries are installed. -

    -To use this feature you need to install the FFmpeg Streaming Multimedia System. -

    -Experiment to get the desired quality. The better quality the bigger files. This option is ignored if ffmpeg_variable_bitrate is not 0 (disabled). -

    -

    -

    ffmpeg_cap_motion

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    • Option Topic -
    -

    -Use ffmpeg libraries to encode motion type mpeg movies where you only see the pixels that changes. -

    -Works like ffmpeg_cap_new but outputs motion pixel type pictures instead. -

    -This feature generates the special motion type movie where you only see the pixels that changes as a graytone image. If labelling is enabled you see the largest area in blue. Smartmask is shown in red. The filename given is the same as the normal mpegs except they have an 'm' appended after the filename before the .mpg. E.g. 20040424181525m.mpg -

    -To use this feature you need to install the FFmpeg Streaming Multimedia System -

    -

    -

    ffmpeg_cap_new

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    • Option Topic -
    -

    -Use ffmpeg libraries to encode mpeg movies in realtime. -

    -Generates a new film at the beginning of each new event and appends to the film for each motion detected within the same event. The current event ends when the time defined by the 'gap' option has passed with no motion detected. At the next detection of motion a new mpeg film is started. -

    -To use this feature you need to install the FFmpeg Streaming Multimedia System -

    -Must not be included in config file without having ffmpeg installed. -

    -

    -

    ffmpeg_deinterlace

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    • Option Topic -
    -

    -Use ffmpeg to deinterlace video. Necessary if you use an analog camera and see horizontal combing on moving objects in video or pictures. -

    -To use this feature you need to install the FFmpeg Streaming Multimedia System -

    -Must not be included in config file without having ffmpeg installed. -

    -

    - -

    -

    -

    ffmpeg_timelapse

    -

      -
    • Type: Boolean -
    • Range / Valid values: 0 - 2147483647 -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    -Create a timelapse movie saving a picture frame at the interval in seconds set by this parameter. Set it to 0 if not used. -

    -This feature uses ffmpegs libavcodec to encode a timelaps movie saving a picture frame at the interval in seconds set by this parameter. Setting this option to 0 disables it. -

    -The feature gives your viewer the chance to watch the day pass by. It makes a nice effect to film flowers etc closeup during the day. Options like frame_rate, snapshot, gap etc have no impact on the ffmpeg timelapse function. -

    -Note that the timelapse format is always mpeg1 independent of ffmpeg_video_codec. This is because mpeg1 allows the timelapse to stop and the file to be reopened and more film appended. -

    -To use this feature you need to install the FFmpeg Streaming Multimedia System. -

    -(renamed from ffmpeg_timelaps to ffmpeg_timelapse in 3.1.14) -

    -

    -

    ffmpeg_timelapse_mode

    -

      -
    • Type: Discrete Strings -
    • Range / Valid values: hourly, daily, weekly-sunday, weekly-monday, monthly, manual -
    • Default: daily -
    • Option Topic -
    -

    -The file rollover mode of the timelapse video. -

    -Note that it is important that you use the conversion specifiers in ffmpeg_filename that ensure that the new timelapse file indeed is a new file. If the filename does not change Motion will simply append the timelapse pictures to the existing file. -

    -The value 'Manual' means that Motion does not automatically rollover to a new filename. You can do it manually using the http control interface by setting the option 'ffmpeg_timelapse' to 0 and then back to your chosen value. Value 'hourly' rolls over on the full hour. Value 'daily' which is the default rolls over at midnight. There are two weekly options because depending on where you come from a week may either start on Sunday or Monday. And 'monthly' naturally rolls over on the 1st of the month. -

    -

    -

    ffmpeg_variable_bitrate

    -

      -
    • Type: Integer -
    • Range / Valid values: 0, 2 - 31 -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    -Enables and defines variable bitrate for the ffmpeg encoder. ffmpeg_bps is ignored if variable bitrate is enabled. Valid values: 0 (default) = fixed bitrate defined by ffmpeg_bps, or the range 2 - 31 where 2 means best quality and 31 is worst. -

    -Experiment for the value that gives you the desired compromise between size and quality. -

    -

    -

    ffmpeg_video_codec

    -

      -
    • Type: Discrete Strings -
    • Range / Valid values: mpeg1 (ffmpeg-0.4.8 only), mpeg4, msmpeg4, swf, flv, ffv1 -
    • Default: mpeg4 -
    • Option Topic -
    -

    -Codec to be used by ffmpeg for the video compression. Timelapse mpegs are always made in mpeg1 format independent from this option. -

    -mpeg1 gives you files with extension .mpg. It is only supported by the old ffmpeg version 0.4.8. The ffmpeg team decided no longer to support non-standard framerates for mpeg1 from ffmpeg version 0.4.9pre1. -

    -mpeg4 or msmpeg4 give you files with extension .avi -

    -msmpeg4 is recommended for use with Windows Media Player because it requires with no installation of codec on the Windows client. -

    -swf gives you a flash film with extension .swf -

    -flv gives you a flash video with extension .flv -

    -ffv1 , FF video codec 1 for Lossless Encoding ( experimental ) -

    -This option does not affect the timelapse feature. Timelapse is always recorded in mpeg1 format because we need to be able to append to an existing file. mpeg4 does not easily allow this. -

    -

    -


    -

    -See also the section Advanced Filenames where the two additional options ffmpeg_filename and timelapse_filename are defined. -

    -If you want to use this feature you can read about the FFmpeg Streaming Multimedia System -

    -

    -

    Snapshots - The Traditional Periodic Web Camera

    -Motion can also act like a traditional web camera. -

    -

    -

    snapshot_interval

    -

      -
    • Type: Integer -
    • Range / Valid values: 0 - 2147483647 -
    • Default: 0 (disabled) -
    • Option Topic -
    -

    -Make automated snapshots every 'snapshot_interval' seconds. -

    -The snapshots are stored in the target directory + the directory/filename specified by the snapshot_filename option. -

    -This is the traditional web camera feature where a picture is taken at a regular interval independently of motion in the picture. -

    -

    -See the also snapshot_filename option in the section Advanced Filenames. -

    -

    -

    Text Features

    -Text features are highly flexible. You can taylor the text displayed on the images and films to your taste and you can add your own user defined text. -

    +A way of tuning (by removing or enhancing) noise in the motion image. Options for the despeckle feature are +any of 'e', 'E', 'd' or 'D'. This can be combined by a trailing 'l' (letter l) which enables the labeling +feature. Default: Not Defined (Don't despeckle and label). +Wind blowing grass and trees around or poor light conditions can cause a lot of dots (or noise) to appear in the +motion image (See the section on Tuning Motion). This feature removes (or enhances!) this noise and so improves +the reliability of motion. +The 'e' option removes diamonds, 'E' removes squares and alternating eE will remove circles. Each e/E you add will +shrink the noise by a pixel all the way around. So 'despeckle Ee' will remove circles of radius 2. However, this +will also shrink the detection by 2 and will affect the threshold. So to remove noise and then restore the detected +motion to its original size try 'despeckle EedD'. +After the despeckle feature is done you can let the labeling feature search for areas of connected pixels and "label" +each area. The program will now trigger motion based on the number of changed pixels in the largest area. In other words, +the largest labeled area has to be above the threshold to trigger a motion detected. +The value EedDl is a good starting point. The possible combinations are endless and it requires many experiments to +find the best combination. Just remember that the labeling feature only works as intended if it runs after the +despeckle feature. Ie. the letter 'l' must be the last letter and only one 'l'. +If you have very few problems with false detections leave this option either blank or at EedD which will remove +most of the single pixel noise. +A very detailed technical explanation of the despeckle part can be found at the webpage of the author of this +feature Ian McConnell's Webcam: Motion +Web Page + +

    + +

    locate_motion_mode

    +

    +
      +
    • Type: Boolean
    • +
    • Range / Valid values: on, off, preview
    • +
    • Default: off
    • +
    +

    +Locate and draw a box around the moving object. Value 'preview' makes Motion only draw a box on a +saved preview jpeg image and not on the saved movie. +

    + +

    locate_motion_style

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: box, redbox, cross, redcross
    • +
    • Default:
    • +
    +

    + Set the look and style of the locate box if enabled. +

    + + +

    text_left

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default:
    • +
    +User defined text overlayed on each in the lower left corner. +Use A-Z, a-z, 0-9, " / ( ) @ ~ # < > \ , . : - + _ \n and conversion specifiers +

    +If the option is not defined no text is displayed at this position. +

    +You can use Conversion Specifiers to define this field and also include +a new line specifier as \n and spaces if this option is enclosed in quotes. +

    +

    +By combining spaces and new lines '\n' you can place +your text anywhere on the picture. When setting the text using http remote control the text +must be URL encoded. The browser does this for you. If you need +to set it with a command line tool, use a browser first and let it make the encoded URL for you. Then +you can copy paste it to your script file or cron line or whatever you want to use. +

    +This is how the overlayed text is located. +

    + + + + +
    + + + + + + + + + +
    +

      





     

    +
    +

     CHANGES





     

    +
    +



    TEXT_LEFT

    +
    +

    TEXT_RIGHT
    YYYY-MM-DD
    HH:MM:SS 

    +
    +
    +

    +

    + +

    text_right

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default: %Y-%m-%d\n%T
    • +
    +

    +User defined text overlayed on each in the lower right corner. +Use A-Z, a-z, 0-9, " / ( ) @ ~ # < > \ , . : - + _ \n and conversion specifiers +

    +If the option is not defined no text is displayed at this position. +

    +You can use Conversion Specifiers to define this field and also include +a new line specifier as \n and spaces if this option is enclosed in quotes. +

    +

    +By combining spaces and new lines '\n' you can place +your text anywhere on the picture. When setting the text using http remote control the text +must be URL encoded. The browser does this for you. If you need +to set it with a command line tool, use a browser first and let it make the encoded URL for you. Then +you can copy paste it to your script file or cron line or whatever you want to use. +

    +A major difference from text_left is that if this option is undefined the +default is %Y-%m-%d\n%T which displays the date in ISO format YYYY-MM-DD and below the +time in 24 hour clock HH:MM:SS. +

    This is how the overlayed text is located. -

    +

    @@ -1993,1449 +2364,1051 @@

    locate

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off, preview -
    • Default: off -
    • Option Topic -
    -

    -Locate and draw a box around the moving object. Value 'preview' makes Motion only draw a box on a saved preview jpeg image and not on the saved mpeg movie. -

    -The value 'preview' only works when 'output_normal' is set to either 'first' or 'best'. -

    -

    +

    +

    +

    text_changes

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    • Option Topic -
    -

    +

    +
      +
    • Type: Boolean
    • +
    • Range / Valid values: on, off
    • +
    • Default: off
    • +
    +

    Turns the text showing changed pixels on/off. -

    -By setting this option to 'on' the number of pixels that changed compared to the reference frame is displayed in the upper right corner of the pictures. This is good for calibration and test. Maybe not so interesting for a greater public. Set it to your personal taste. -

    -

    +By setting this option to 'on' the number of pixels that changed compared to the +reference frame is displayed in the upper right corner of the pictures. This is good for calibration and testing. +This is how the overlayed text is located. +

    + + + + +
    + + + + + + + + + +
    +

      





     

    +
    +

     CHANGES





     

    +
    +



    TEXT_LEFT

    +
    +

    TEXT_RIGHT
    YYYY-MM-DD
    HH:MM:SS 

    +
    +
    +

    + +

    text_event

    +

    +
      +
    • Type: String
    • +
    • Range / Valid values: Max 4095 characters
    • +
    • Default: Default: %Y%m%d%H%M%S
    • +
    +

    +This option is special in that it defines the conversion specifier %C which can be used both for text +display and for filenames. This option defines the value of the special event conversion specifier %C. +You can use any conversion specifier in this option except %C. Date and time values are from the timestamp +of the first image in the current event. The idea is that %C can be used filenames and text_left/right for +creating a unique identifier for each event. Option text_event defines the value %C which then can be used in +filenames and text_right/text_left. The text_event/%C uses the time stamp for the first image detected in a new +event. %C is an empty string when no event is in progress (gap period expired). Pre_captured and +minimum_motion_frames images are time stamped before the event happens so %C in text_left/right does not +have any effect on those images. + +You can use Conversion Specifiers to define this field (except for +this option itself) + +

    +

    text_double

    -

      -
    • Type: Boolean -
    • Range / Valid values: on, off -
    • Default: off -
    -

    +

    +
      +
    • Type: Boolean
    • +
    • Range / Valid values: on, off
    • +
    • Default: off
    • +
    +

    Draw characters at twice normal size on images. -

    -This option makes the text defined by text_left, text_right and text_changes twice the normal size. This may be useful when using large picture formats such as 640 x 480. -

    - -

    -

    -

    text_event

    -

      -
    • Type: String -
    • Range / Valid values: Max 4095 characters -
    • Default: %Y%m%d%H%M%S -
    • Option Topic -
    -

    -This option defines the value of the speciel event conversion specifier %C. You can use any conversion specifier in this option except %C. Date and time values are from the timestamp of the first image in the current event. -

    -The idea is that %C can be used filenames and text_left/right for creating a unique identifier for each event. -

    -Option text_event defines the value %C which then can be used in filenames and text_right/text_left. The text_event/%C uses the time stamp for the first image detected in a new event. %C is an empty string when no event is in progress (gap period expired). Pre_captured and minimum_motion_frames images are time stamped before the event happens so %C in text_left/right does not have any effect on those images. -

    -

    -

    text_left

    -

      -
    • Type: String -
    • Range / Valid values: Max 4095 characters -
    • Default: Not defined -
    • Option Topic -
    -

    -User defined text overlayed on each in the lower left corner. Use A-Z, a-z, 0-9, " / ( ) @ ~ # < > \ , . : - + _ \n and conversion specifiers (codes starting by a %). -

    -text_left is displayed in the lower left corner of the pictures. If the option is not defined no text is displayed at this position. -

    -You can place the text in quotation marks to allow leading spaces. With a combination is spaces and newlines you can position the text anywhere on the picture. -

    -Detailed Description -

    -A conversion specifier is a code that starts by % (except newline which is \n). The conversion specifiers used has the same function as for the C function strftime (3). The most commonly used are:

      -
    • %Y = year -
    • %m = month as two digits -
    • %d = date -
    • %H = hour -
    • %M = minute -
    • %S = second -
    • %T = HH:MM:SS -
    -

    -These are unique to motion

      -
    • %v = event -
    • %q = frame number -
    • %t = thread (camera) number -
    • %D = changed pixels -
    • %N = noise level -
    • %i = width of motion area -
    • %J = height of motion area -
    • %K = X coordinate of motion center -
    • %L = Y coordinate of motion center -
    • %C = value defined by text_event -
    -

    -With a combination of text, spaces, new lines \n and conversion specifiers you have some very flexible text features. -

    -For a full list of conversion specifiers see the section Conversion Specifiers for Advanced Filename and Text Feature. -

    -

    -

    text_right

    -

      -
    • Type: String -
    • Range / Valid values: Max 4095 characters -
    • Default: %Y-%m-%d\n%T -
    • Option Topic -
    -

    -User defined text overlayed on each in the lower right corner. Use A-Z, a-z, 0-9, " / ( ) @ ~ # < > , . : - + _ \n and conversion specifiers (codes starting by a %). Default: %Y-%m-%d\n%T = date in ISO format and time in 24 hour clock -

    -text_right is displayed in the lower right corner of the pictures. If the option is not defined no text is displayed at this position. -

    -You can place the text in quotation marks to allow leading spaces. With a combination is spaces and newlines you can position the text anywhere on the picture. -

    -A major difference from text_left is that if this option is undefined the default is %Y-%m-%d\n%T which displays the date in ISO format YYYY-MM-DD and below the time in 24 hour clock HH:MM:SS. -

    +This option makes the text defined by text_left, text_right and text_changes twice the normal size. +This may be useful when using large picture formats such as 1280 x 720. +

    +

    + + +

    Motion Detection

    +
      +

      +

      emulate_motion

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: on off
      • +
      • Default: off
      • +
      +

      +Always save images even if there was no motion +

      + +

      threshold

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 1 - 2147483647
      • +
      • Default: 1500
      • +
      +

      +Threshold for declaring motion. The threshold is the number of changed + pixels counted after noise filtering, masking, despeckle, and labelling. + The 'threshold' option is the most important detection setting. When motion runs it compares + the current image frame with the previous and counts the number of changed pixels after having + processed the image with noise filtering, masking, despeckle and labeling. If more pixels than defined + by 'threshold' have changed we assume that we have detected motion. Set the threshold as low as possible + so that you get the motion you want detected but large enough so that you do not get detections from noise + and plants moving. Note that the larger your frames are, the more pixels you have. So for large picture frame + sizes you need a higher threshold. + Use the -s (setup mode) command line option and/or the text_changes config file option to experiment to find + the right threshold value. If you do not get small movements detected (see the mouse on the kitchen floor) lower + the value. If motion detects too many birds or moving trees, increase the number. (Unless of course + you are one of the many many users who use Motion to bird watch!) + Practical values would be from a few hundred to thousands. +

      + +

      threshold_tune

      +

      +
        +
      • Type: Boolean
      • +
      • Range / Valid values: on, off
      • +
      • Default: off
      • +
      +

      +Activate the automatic tuning of threshold level. +This feature makes Motion continuously adjust the threshold for declaring motion. +The threshold setting is ignored when activating this feature. It may give different results depending +on your camera, light conditions, indoor/outdoor, the motion to be detected etc. If it does not work well, +deactivate the 'threshold_tune' option and use the manual setting of threshold instead. + +

      + +

      noise_level

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 1 - 255
      • +
      • Default: 32
      • +
      +

      +The noise level is used as a threshold for distinguishing between noise and motion. +This is different from the threshold parameter. This is changes at pixel level. The purpose is to +eliminate the changes generated by electric noise in the camera. Especially in complete darkness +you can see the noise as small grey dots that come randomly in the picture. This noise can create +false motion detection. What this parameter means is that the intensity of a pixel must change more +than +/- the noise threshold parameter to be counted. +

      + +

      noise_tune

      +

      +
        +
      • Type: Boolean
      • +
      • Range / Valid values: on, off
      • +
      • Default: on
      • +
      +

      +Activates the automatic tuning of noise level. +This feature makes Motion continuously adjust the noise +threshold for distinguishing between noise and motion. +The 'noise_level' setting is ignored when activating this feature. +It may give different results depending on camera and light conditions. +

      + +

      area_detect

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default:
      • +
      +

      +Detect motion in predefined areas (1 - 9) and when Motion is detected in the area, execute the script. All of +motion detection still continue. This option is only to execute the on_area_detect script. +

      +Areas are numbered like +
        +
      • 1 2 3
      • +
      • 4 5 6
      • +
      • 7 8 9
      • + +
      + +

      + +

      mask_file

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: Not defined
      • +
      +

      +The full path and filename for the masking pgm file. +If needed, the mask will be resized to match the width and height of the frames being +captured. +If you have one or more areas of the camera image in which you do NOT want motion detected (e.g. a tree that +moves in the wind or a corner of the picture where you can see cars/pedestrians passing by) you need a mask file. +This file is a picture that you create in your favorite photo editing program. The areas that you want detected must +be white. The error that you want ignored must be black. The pgm image must be the same size (number of pixels high +and wide) as the pictures that are taken by the camera. +You can adjust sensitivity by using gray tones. +If you do not have a mask file disable this option by not having it in the config file or comment +it out. +If you are using the rotate option, note that the mask is applied after the rotation. Detailed Description -

      -A conversion specifier is a code that starts by % (except newline which is \n). The conversion specifiers used has the same function as for the C function strftime (3). The most commonly used are:

        -
      • %Y = year -
      • %m = month as two digits -
      • %d = date -
      • %H = hour -
      • %M = minute -
      • %S = second -
      • %T = HH:MM:SS -
      -

      -These are unique to motion

        -
      • %v = event -
      • %q = frame number -
      • %t = thread (camera) number -
      • %D = changed pixels -
      • %N = noise level -
      • %i = width of motion area -
      • %J = height of motion area -
      • %K = X coordinate of motion center -
      • %L = Y coordinate of motion center -
      • %C = value defined by text_event -
      -

      -With a combination of text, spaces, new lines \n and conversion specifiers you have some very flexible text features. -

      -For a full list of conversion specifiers see the section Conversion Specifiers for Advanced Filename and Text Feature. -

      -

      -

      Advanced Filenames

      -Motion has a very advanced and flexible automated filenaming feature. -

      -By using conversion specifiers (codes that consist of a '%' followed by a letter) you can build up the filenames including sub directories for pictures and movies using any combination of letters, numbers and conversion specifiers which are codes that represents time, date, event number and frame numbers. -

      -The option target_dir is the target directory for all snapshots, motion images and normal images. The default is the current working directory (current working directory of the terminal from which motion was started). You will normally always want to specify this parameter. -

      -Note that the options snapshot_filename, jpeg_filename, ffmpeg_filename, and timelapse_filename all allow specifying directories by using '/' in the filename. These will all be relative to target_dir. This means in principle that you can specify target_dir as '/' and be 100% flexible. It also means that Motion can write files all over your harddisk if you make a mistake. It is recommended to specify the target_dir as deep or detailed as possible for this reason. And note that targer_dir does not allow conversion specifiers. -

      -The conversion specifier %C which is defined by the option text_event is interesting in connection with filenames because it can be used to create files and directories for each event in a very flexible way. -

      -The convertion specifier %t (thread/camera number) is also very useful. Here is an example of filename definitions in motion.conf: -

      -

      -target_dir /usr/local/webcam
      -snapshot_filename cam%t/%v-%Y%m%d%H%M%S-snapshot
      -jpeg_filename cam%t/%v-%Y%m%d%H%M%S-%q
      -ffmpeg_filename cam%t/%v-%Y%m%d%H%M%S
      -timelapse_filename cam%t/%Y%m%d%H-timelapse
      -
      -

      -The smart thing is that this defines the filename of all your camera threads in motion.conf so you do not need to specify target dir and filenames in the thread config files. In the above example an mpegfile for camera thread 3 will be saved as a filename similar to /usr/local/webcam/cam3/28-20051128130840.avi -

      -NOTE: Unless you use the minimum_gap option to limit the number of shots to less then one per second - you must use the frame modifier %q as part of the jpeg_filename. Otherwise the pictures saved within the same second will overwrite each other. The %q in jpeg_filename ensures that each jpeg (or ppm) picture saved gets a unique filename. -

      -ALERT! Security Warning! Note that the flexibility of this feature also means you have to pay attention to the following.

        -
      • Anyone with access to the remote control port (http) can alter the values of these options and save files anywhere on your server with the same privileges as the user running Motion. Anyone can access your control port if you have not either limited access to localhost or limited access using firewalls in the server. You should always have a router between a machine running Motion with remote control enabled and the Internet and make sure the Motion control port is not accessible from the outside. -
      • Anyone with local access to the computer and edit rights to the motion.conf file can alter the values of these options and save files anywhere on your server with the same privileges as the user running Motion. Make sure the motion.conf file is maximum readonly to anyone else but the user running Motion. -
      • It is a good idea to run Motion as a harmless user. Not as root. -
      -

      -These are the advanced filename options in motion.conf -

      -

      -

      ffmpeg_filename (now called movie_filename)

      -

      -ALERT! This option was renamed to movie_filename in 3.2.5 to enable better integration of alternative movie libraries to the current ffmpeg solution. -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: %v-%Y%m%d%H%M%S -
      • Option Topic -
      -

      -File path for motion triggered ffmpeg movies (mpeg) relative to target_dir. This option was renamed to movie_filename in 3.2.5 to enable better integration of alternative movie libraries to the current ffmpeg solution. -

      -Default value is equivalent to legacy 'oldlayout' option -For Motion 3.0 compatible mode (directories based on date and time) choose: %Y/%m/%d/%H%M%S -

      -File extension .mpg or .avi is automatically added so do not include this. -

      -This option uses conversion specifiers which are codes that start by % and then a letter. The conversion specifiers used has the same function as for the C function strftime (3). The most commonly used are:

        -
      • %Y = year -
      • %m = month as two digits -
      • %d = date -
      • %H = hour -
      • %M = minute -
      • %S = second -
      • %T = HH:MM:SS -
      -

      -These are unique to motion

        -
      • %v = event -
      • %q = frame number -
      • %t = thread (camera) number -
      • %D = changed pixels -
      • %N = noise level -
      • %i = width of motion area -
      • %J = height of motion area -
      • %K = X coordinate of motion center -
      • %L = Y coordinate of motion center -
      • %C = value defined by text_event -
      -

      -If you are happy with the directory structures the way they were in earlier versions of motion use %v-%Y%m%d%H%M%S for 'oldlayout on' and %Y/%m/%d/%H%M%S for 'oldlayout off'. -

      -

      -

      jpeg_filename

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: %v-%Y%m%d%H%M%S-%q -
      • Option Topic -
      -

      -File path for motion triggered images (jpeg or ppm) relative to target_dir. Value 'preview' makes a jpeg filename with the same name body as the associated saved mpeg movie file. -

      -Default value is equivalent to legacy 'oldlayout' option. For Motion 3.0 compatible mode (directories based on date and time) choose: %Y/%m/%d/%H/%M/%S-%q -

      -This option uses conversion specifiers which are codes that start by % and then a letter. The conversion specifiers used has the same function as for the C function strftime (3). The most commonly used are:

        -
      • %Y = year -
      • %m = month as two digits -
      • %d = date -
      • %H = hour -
      • %M = minute -
      • %S = second -
      • %T = HH:MM:SS -
      -

      -These are unique to motion

        -
      • %v = event -
      • %q = frame number -
      • %t = thread (camera) number -
      • %D = changed pixels -
      • %N = noise level -
      • %i = width of motion area -
      • %J = height of motion area -
      • %K = X coordinate of motion center -
      • %L = Y coordinate of motion center -
      • %C = value defined by text_event -
      -

      -If you are happy with the directory structures the way they were in earlier versions of motion use %v-%Y%m%d%H%M%S-%q for 'oldlayout on' and %Y/%m/%d/%H/%M/%S-%q for 'oldlayout off'. -

      -The value 'preview' only works when 'output_normal' is set to 'best'. It makes Motion name the best preview jpeg file (image with most changed pixels during the event) with the same body name as the mpeg movie created during the same event. The purpose is to create a good single image that represents the saved mpeg moview so you can decide if you want to see it and spend time downloading it from a web page. -

      -

      -

      movie_filename

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: %v-%Y%m%d%H%M%S -
      • Option Topic -
      -

      -File path for motion triggered ffmpeg movies (mpeg) relative to target_dir. This was previously called ffmpeg_filename. -

      -ALERT! This option was renamed from ffmpeg_filename to movie_filename in Motion 3.2.5. -

      -Default value is equivalent to legacy 'oldlayout' option -For Motion 3.0 compatible mode (directories based on date and time) choose: %Y/%m/%d/%H%M%S -

      -File extension .mpg or .avi is automatically added so do not include this. -

      -This option uses conversion specifiers which are codes that start by % and then a letter. The conversion specifiers used has the same function as for the C function strftime (3). The most commonly used are:

        -
      • %Y = year -
      • %m = month as two digits -
      • %d = date -
      • %H = hour -
      • %M = minute -
      • %S = second -
      • %T = HH:MM:SS -
      -

      -These are unique to motion

        -
      • %v = event -
      • %q = frame number -
      • %t = thread (camera) number -
      • %D = changed pixels -
      • %N = noise level -
      • %i = width of motion area -
      • %J = height of motion area -
      • %K = X coordinate of motion center -
      • %L = Y coordinate of motion center -
      • %C = value defined by text_event -
      -

      -If you are happy with the directory structures the way they were in earlier versions of motion use %v-%Y%m%d%H%M%S for 'oldlayout on' and %Y/%m/%d/%H%M%S for 'oldlayout off'. -

      -

      -

      snapshot_filename

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: %v-%Y%m%d%H%M%S-snapshot -
      • Option Topic -
      -

      -File path for snapshots (jpeg or ppm) relative to target_dir. -

      -Default value is equivalent to legacy 'oldlayout' option. For Motion 3.0 compatible mode (directories based on date and time) choose: %Y/%m/%d/%H/%M/%S-snapshot -

      -File extension .jpg or .ppm is automatically added so do not include this -A symbolic link called lastsnap.jpg (or lastsnap.ppm) created in the target_dir will always point to the latest snapshot, unless snapshot_filename is exactly 'lastsnap' -

      -This option uses conversion specifiers which are codes that start by % and then a letter. The conversion specifiers used has the same function as for the C function strftime (3). The most commonly used are:

        -
      • %Y = year -
      • %m = month as two digits -
      • %d = date -
      • %H = hour -
      • %M = minute -
      • %S = second -
      • %T = HH:MM:SS -
      -

      -These are unique to motion

        -
      • %v = event -
      • %q = frame number -
      • %t = thread (camera) number -
      • %D = changed pixels -
      • %N = noise level -
      • %i = width of motion area -
      • %J = height of motion area -
      • %K = X coordinate of motion center -
      • %L = Y coordinate of motion center -
      • %C = value defined by text_event -
      -

      -If you are happy with the directory structures the way they were in earlier versions of motion use %v-%Y%m%d%H%M%S-snapshot for 'oldlayout on' and %Y/%m/%d/%H/%M/%S-snapshot for 'oldlayout off'. -

      -For the equivalent of the now obsolete option 'snap_overwrite' use the value 'lastsnap'. -

      -

      -

      target_dir

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined = current working directory -
      • Option Topic -
      -

      -Target directory for picture and movie files. -

      -This is the target directory for all snapshots, images files and movie files. The default is the current working directory (current working directory of the terminal from which motion was started). You will normally always want to specify this parameter as an absolute path. -

      -Note that the options snapshot_filename, jpeg_filename, ffmpeg_filename, and timelapse_filename all allows specifying directories. These will all be relative to 'target_dir'. This means in principle that you can specify target_dir as '/' and be 100% flexible. It also means that Motion can write files all over your harddisk if you make a mistake. It is recommended to specify the target_dir as deep or detailed as possible for this reason. -

      -

      -

      timelapse_filename

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: %v-%Y%m%d-timelapse -
      • Option Topic -
      -

      -File path for timelapse mpegs relative to target_dir (ffmpeg only). -

      -Default value is equivalent to legacy 'oldlayout' option. -

      -For Motion 3.0 compatible mode (directories based on date and time) choose: %Y/%m/%d-timelapse -

      -File extension .mpg is automatically added so do not include this. -

      -This option uses conversion specifiers which are codes that start by % and then a letter. The conversion specifiers used has the same function as for the C function strftime (3). The most commonly used are:

        -
      • %Y = year -
      • %m = month as two digits -
      • %d = date -
      • %H = hour -
      • %M = minute -
      • %S = second -
      • %T = HH:MM:SS -
      -

      -These are unique to motion

        -
      • %v = event -
      • %q = frame number -
      • %t = thread (camera) number -
      • %D = changed pixels -
      • %N = noise level -
      • %i = width of motion area -
      • %J = height of motion area -
      • %K = X coordinate of motion center -
      • %L = Y coordinate of motion center -
      • %C = value defined by text_event -
      -

      -If you are happy with the directory structures the way they were in earlier versions of motion use %v-%Y%m%d-timelapse for 'oldlayout on' and %Y/%m/%d-timelapse for 'oldlayout off'. -

      -

      -

      Conversion Specifiers for Advanced Filename and Text Features

      -The table below shows all the supported Conversion Specifiers you can use in the options text_event, text_left, text_right, sql_query, snapshot_filename, jpeg_filename, ffmpeg_filename, timelapse_filename, on_event_start, on_event_end, on_picture_save, on_movie_start, on_movie_end, and on_motion_detected. -

      -In text_left and text_right you can additionally use '\n' for new line. -

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      Conversion Specifier Description
      %a The abbreviated weekday name according to the current locale.
      %A The full weekday name according to the current locale.
      %b The abbreviated month name according to the current locale.
      %B The full month name according to the current locale.
      %c The preferred date and time representation for the current locale.
      %C Text defined by the text_event feature
      %d The day of the month as a decimal number (range 01 to 31).
      %D Number of pixels detected as Motion. If labelling is enabled the number is the number of pixels in the largest labelled motion area.
      %E Modifier: use alternative format, see below.
      %f File name - used in the on_picture_save, on_movie_start, on_movie_end, and sql_query features.
      %F Equivalent to %Y-%m-%d (the ISO 8601 date format).
      %H The hour as a decimal number using a 24-hour clock (range 00 to 23).
      %i Width of the rectangle containing the motion pixels (the rectangle that is shown on the image when locate is on).
      %I The hour as a decimal number using a 12-hour clock (range 01 to 12).
      %j The day of the year as a decimal number (range 001 to 366).
      %J Height of the rectangle containing the motion pixels (the rectangle that is shown on the image when locate is on).
      %k The hour (24-hour clock) as a decimal number (range 0 to 23); single digits are preceded by a blank. (See also %H.)
      %K X coordinate in pixels of the center point of motion. Origin is upper left corner.
      %l The hour (12-hour clock) as a decimal number (range 1 to 12); single digits are preceded by a blank. (See also %I.)
      %L Y coordinate in pixels of the center point of motion. Origin is upper left corner and number is positive moving downwards (I may change this soon).
      %m The month as a decimal number (range 01 to 12).
      %M The minute as a decimal number (range 00 to 59).
      %n Filetype as used in the on_picture_save, on_movie_start, on_movie_end, and sql_query features.
      %N Noise level.
      %o Threshold. The number of detected pixels required to trigger motion. When threshold_tune is 'on' this can be used to show the current tuned value of threshold.
      %p Either 'AM' or 'PM' according to the given time value, or the corresponding strings for the current locale. Noon is treated as `pm' and midnight as `am'.
      %P Like %p but in lowercase: `am' or `pm' or a corresponding string for the current locale.
      %q Picture frame number within current second. For jpeg filenames this should always be included in the filename if you save more then 1 picture per second to ensure unique filenames. It is not needed in filenames for mpegs.
      %Q Number of detected labels found by the despeckle feature
      %r The time in a.m. or p.m. notation.
      %R The time in 24-hour notation (%H:%M).
      %s The number of seconds since the Epoch, i.e., since 1970-01-01 00:00:00 UTC.
      %S The second as a decimal number (range 00 to 61).
      %t Thread number (camera number)
      %T The time in 24-hour notation (%H:%M:%S).
      %u The day of the week as a decimal, range 1 to 7, Monday being 1. See also %w.
      %U The week number of the current year as a decimal number, range 00 to 53, starting with the first Sunday as the first day of week 01. See also %V and %W.
      %v Event number. An event is a series of motion detections happening with less than 'gap' seconds between them.
      %V The ISO 8601:1988 week number of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the current year, and with Monday as the first day of the week. See also %U and %W.
      %w The day of the week as a decimal, range 0 to 6, Sunday being 0. See also %u.
      %W The week number of the current year as a decimal number, range 00 to 53, starting with the first Monday as the first day of week 01.
      %x The preferred date representation for the current locale without the time.
      %X The preferred time representation for the current locale without the date.
      %y The year as a decimal number without a century (range 00 to 99).
      %Y The year as a decimal number including the century.
      %z The time-zone as hour offset from GMT.
      %Z The time zone or name or abbreviation.
      -

      -

      -

      Webcam Server

      -Motion has simple webcam server built in. The video stream is in mjpeg format. -

      -Each thread can have its own webcam server. If you enable the webcam server (option webcam_port to a number different from 0) and you have more than one camera, you must make sure to include webcam_port in each thread config file and set webcam_port to different and unique port numbers or zero (disable). Otherwise each webcam server will use the setting from the motion.conf file and try to bind to the same port. If the webcam_port numbers are not different from each other Motion will disable the webcam feature. -

      -Note: The webcam server feature requires that the option ppm is set to off. (I.e. saved images are jpeg images). -

      -The webcam_maxrate and webcam_quality options are important to limit the load on your server and link. Don't set them too high unless you only use it on the localhost or on an internal LAN. The option webcam_quality is equivalent to the quality level for jpeg pictures. -

      -The webcam_limit option prevents people from loading your Network connection by streaming for hours and hours. The options defines the number of picture frames sent as mjpeg Motion will allow without re-connecting (e.g. clicking refresh in the browser). -

      -The option webcam_localhost is a security feature. When enabled you can only access the webserver on the same machine as Motion is running on. If you want to present a live webcam on your web site this feature must be disabled. -

      -The webserver generates a stream in "multipart jpeg" format (mjpeg). You cannot watch the stream with most browsers. Only certain versions of Netscape works. Mozilla and Firefox brosers can view the mjpeg stream but you often have to refresh the page once to get the streaming going. Internet Explorer cannot show the mjpeg stream. For public viewing this is not very useful. There exists a java applet called Cambozola which enabled any Java capable browser to show the stream. To enable the feature to a broad audience you should use this applet or similar. -

      -To use the webcam feature with Cambozola is actually very simple. -

      -1. Create a html page in which you will want the streamed picture. -

      -2. In the html page include this code -

      -

      -<applet code=com.charliemouse.cambozola.Viewer
      -    archive=cambozola.jar width="320" height="240" style="border-width:1; border-color:gray; border-style:solid;">
      -    <param name=url value="http://www.myurl.com:8081">
      -</applet>
      -
      -

      -Where the width and height is the image size of the video stream. -

      -Replace www.myurl.com:8081 by the real url and port number of your choice. -

      -3. In the same directory you place the cambozola.jar file. No need to build the java applet from source. Simply use the applet in the package. -

      -4. Enable the feature in motion.conf. -

      -You can also view the live webcam stream using MPlayer like this: -

      -

      mplayer -demuxer lavf http://www.myurl.com:8081/stream.mjpg
      -

      -Note that the stream.mjpg part is important, without it you will get a LAVF_check: no clue about this gibberish! error from libavformat. -

      -These are the special webcam parameters. -

      -

      -

      webcam_limit

      -

        -
      • Type: Integer -
      • Range / Valid values: 0 - 2147483647 -
      • Default: 0 (unlimited) -
      • Option Topic -
      -

      -Limit the number of frames to number frames. After 'webcam_limit' number of frames the connection will be closed by motion. The value 0 means unlimited. -

      -Number can be defined by multiplying actual webcam rate by desired number of seconds. Actual webcam rate is the smallest of the numbers framerate and webcam_maxrate. -

      -

      -

      webcam_localhost

      -

        -
      • Type: Boolean -
      • Range / Valid values: on, off -
      • Default: on -
      • Option Topic -
      -

      -Limits the access to the webcam to the localhost. -

      -By setting this to on, the webcam can only be accessed on the same machine on which Motion is running. -

      -

      -

      webcam_maxrate

      -

        -
      • Type: Integer -
      • Range / Valid values: 1 - 100 -
      • Default: 1 -
      • Option Topic -
      -

      -Limit the framerate of the webcam in frames per second. Default is 1. Set the value to 100 for practically unlimited. -

      -Don't set 'webcam_maxrate' too high unless you only use it on the localhost or on an internal LAN. -

      -

      -

      webcam_motion

      -

        -
      • Type: Boolean -
      • Range / Valid values: on, off -
      • Default: off -
      • Option Topic -
      -

      -If set to 'on' Motion sends slows down the webcam stream to 1 picture per second when no motion is detected. When motion is detected the stream runs as defined by webcam_maxrate. When 'off' the webcam stream always runs as defined by webcam_maxrate. -

      -Use this option to save bandwidth when there is not anything important to see from the camera anyway. -

      -Note that this feature was greatly improved from Motion version 3.2.2. Before 3.2.2 the option stopped the webcam stream except when Motion was detected. This made the feature not very useful because it made it difficult to connect to the webcam stream and most mjpeg viewers would timeout and give an error message. From 3.2.2 the feature has been greatly improved and actually quite recommendable. -

      -

      -

      -

      webcam_port

      -

        -
      • Type: Integer -
      • Range / Valid values: 0 - 65535 -
      • Default: 0 (disabled) -
      • Option Topic -
      -

      -TCP port on which motion will listen for incoming connects with its webcam server. -

      -Note that each camera thread must have its own unique port number and it must also be different from the control_port number. -

      -A good value to select is 8081 for camera 1, 8082 for camera 2, 8083 for camera 3 etc etc. -

      -

      -

      webcam_quality

      -

        -
      • Type: Integer -
      • Range / Valid values: 1 - 100 -
      • Default: 50 -
      • Option Topic -
      -

      -Quality setting in percent for the mjpeg picture frames transferred over the webcam connection. Keep it low to restrict needed bandwidth. -

      -The mjpeg stream consists of a header followed by jpeg frames separated by content-length and boundary string. The quality level defines the size of the individual jpeg pictures in the mjpeg stream. If you set it too high you need quite a high bandwidth to view the stream. -

      -

      Remote Control with http

      -

      -Motion can be remote controlled via a simple http interface. http is the language a normal web browser talks when it requests a web page. The web server answers back with some simple http headers followed by a webpage coded in HTML. -

      -Most Motion config options can be changed while Motion is running except options related to the size of the captured images and mask files which are loaded only when Motion starts. So only your fantasy sets the limit to what you can change combining cron and the remote control interface for Motion. -

      -So the most obvious tool to use to remote control Motion is any web browser. All commands are sent using the http GET method which simply means that the information is sent via the URL and maybe a query string. You can use any browser (Firefox, Mozilla, Internet Explorer, Konquerer, Opera etc). You can also use the text based browser lynx to control Motion from a console. It navigates fine through the very simple and minimalistic http control interface of Motion. -

      -The details about how to control Motion via the URL is described in detail in the Motion http API topic. -

      -But it is probably simpler to connect to the control port with a browser, navigate to the function you want, and copy the URL from the browser URL entry line. If your control_port is 8080 and you browse from the same machine on which Motion runs simply look up http://localhost:8080/ and navigate around. Connecting from a remote machine is done by using a domain name (example http://mydomain.com:8080/) or the IP address of the machine (example http://192.168.1.4:8080/). The option control_localhost must be off to allow connection from a remote machine. -

      -If you want to use a script or cron to automatically change Motion settings while Motion runs you use a program that can fetch a webpage. We simply just throw away the html page that Motion returns. Programs commonly available on Linux machines are wget and lwp-request. Here is an example of how to start and stop motion detection via cron. These two lines are added to /etc/crontab. -

      -

      -0 9 * * * root /usr/bin/lwp-request http://localhost:8080/0/detection/start > /dev/null
      -0 18 * * * root /usr/bin/lwp-request http://localhost:8080/0/detection/pause > /dev/null
      -
      -

      -If you want to use the http remote control from your own software (for example your own PHP front end) you can set the new motion.conf option html_output off. Then Motion answers back with very basic text only and no html around it. A bit like the xmlrpc interface did. -

      -To remote control Motion from a web pages you can for example use PHP. In PHP it takes this simple code line to send a remote commend to Motion. Here we pause motion detection for camera 2 -

      -readfile('http://localhost:8080/2/detection/pause'); -

      -What happened to XMLRPC? -

      -XMLRPC is replaced by a simpler http remote control interface. It is still being worked on but it is absolutely useable now and much nicer to work with than xmlrpc. Another advantage is that you do not need to install xmlrpc libraries. It is all written in standard C. -

      -ALERT! Security Warning! Note that this feature also means you have to pay attention to the following.

        -
      • Anyone with access to the remote control port (http) can alter the values of any options and save files anywhere on your server with the same privileges as the user running Motion. They can execute any command on your computer with the same privileges as the user running Motion. Anyone can access your control port if you have not either limited access to localhost or limited access using firewalls in the server. You should always have a router between a machine running Motion with remote control enabled and the Internet and make sure the Motion control port is not accessible from the outside. -
      • If you limit control port to localhost you still need to take care of any user logging into the server with any kind of terminal session. -
      • It is a good idea to run Motion as a harmless user. Not as root!! -
      -

      -These are the config file options that control Motion. -

      -These must be placed in motion.conf and not in a thread config file. -

      -

      -

      control_authentication

      -

        -
      • Type: String -
      • Range / Valid values: Max 4096 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -To protect HTTP Control by username and password, use this option for HTTP 1.1 Basic authentication. The string is specified as username:password. Do not specify this option for no authentication. This option must be placed in motion.conf and not in a thread config file. -

      -By setting this to on, the control using http (browser) can only be accessed using login and password ( following the Basic Authentication defined in HTTP RFC). -

      -

      -

      - -

      -

      -

      control_html_output

      -

        -
      • Type: Boolean -
      • Range / Valid values: on, off -
      • Default: on -
      • Option Topic -
      -

      -Enable HTML in the answer sent back to a browser connecting to the control_port. This option must be placed in motion.conf and not in a thread config file. -

      -The recommended value for most is "on" which means that you can navigate and control Motion with a normal browser. By setting this option to "off" the replies are in plain text which may be easier to parse for 3rd party programs that control Motion. -

      -

      -

      control_localhost

      -

        -
      • Type: Boolean -
      • Range / Valid values: on, off -
      • Default: on -
      • Option Topic -
      -

      -Limits the http (html) control to the localhost. This option must be placed in motion.conf and not in a thread config file. -

      -By setting this to on, the control using http (browser) can only be accessed on the same machine on which Motion is running. -

      -

      -

      control_port

      -

        -
      • Type: Integer -
      • Range / Valid values: 0 - 65535 -
      • Default: 0 (disabled) -
      • Option Topic -
      -

      -Sets the port number for the http (html using browser) based remote control. This option must be placed in motion.conf and not in a thread config file. -

      -This sets the TCP/IP port number to be used for control of motion using http (browser). Port numbers below 1024 normally requires that you have root privileges. Port 8080 is a fine choice of port to use for the purpose. -

      -

      -

      --- KennethLavrsen - 12 Apr 2005 -

      -

      -

      External Commands

      -Motion can execute external commands based on the motion detection and related events. They are all described in this section. The option quiet is also included in this section. -

      -A redesign of the external commands was due. They were not very easy to understand, not all were flexible enough and some were missing. So a new external command feature set was made for 3.2.1 and on. -

      -This is how the new script commands look like: -

      - - - - - - - +

      +The mask file must be a pgm format image file (portable gray map). Note that you must choose the BINARY format. +

      +To use this feature create an image of exact the same size as the ones you get from your camera. +Then make it purely white for the areas you want detected and +black for the areas you want ignored. You can also make gray areas where +you want to lower the sensitivity to motion. Normally you will stick to pure black and white. +

      +One method for generating the mask file is as follows. +

      +Take a motion captured picture, edit it with black and white for the mask and export it as a pgm file. +with a program such as gimp. + +If you cannot save in this format save as a grayscale jpg and then you can convert it to pgm format with +

      +djpeg -grayscale -pnm [inputfile] > mask.pgm + +

      +(assuming you have djpeg installed - part of the jpeg lib package). +

      +Note that the mask file option masks off the detection of motion. The entire picture is still shown on the picture. +This means that you cannot use the feature to mask off an area that you do not want people to see. +

      +Below are an example of a webcam picture and a mask file to prevent the detection cars in the street. +

      +Normal picture. Notice the street is visible through the hedge. +

      +normal.jpg +

      +Mask file (converted to png format so it can be shown by your web browser) +

      +
      Function Old Option New Option Argument Appended
      Start of event (first motion) execute on_event_start None
      End of event (no motion for gap seconds) New! on_event_end None
      Picture saved (jpg or ppm) onsave on_picture_save Filename of picture
      Movie starts (mpeg file opened) onmpeg on_movie_start Filename of movie
      Movie ends (mpeg file closed) onffmpegclose on_movie_end Filename of movie
      Motion detected (each single frame with Motion detected) New! on_motion_detected None
      + + +
      + mask1.png +
      -

      -Mail and sms has been removed because they were not configurable. If you want to send event-based mails or sms, just use one of those commands above and send the mail from that script. See What happened to mail and sms? -

      -

      -ALERT! Security Warning! Note that this feature also means you have to pay attention to the following.

        -
      • Anyone with access to the remote control port (http) can execute any command on your computer with the same privileges as the user running Motion. Anyone can access your control port if you have not either limited access to localhost or limited access using firewalls in the server. You should always have a router between a machine running Motion with remote control enabled and the Internet and make sure the Motion control port is not accessible from the outside. -
      • If you limit control port to localhost you still need to take care of any user logging into the server with any kind of GUI or terminal session. All it takes is a browser or single command line execution to change settings in Motion. -
      • It is a good idea to run Motion as a harmless user. Not as root!! -
      -

      -These are the options -

      -

      -

      on_event_end

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -Command to be executed when an event ends after a period of no motion. The period of no motion is defined by option gap. You can use Conversion Specifiers and spaces as part of the command. -

      -Full path name of the program/script. -

      -This can be any type of program or script. Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. -

      -The command is run when an event is over. I.e. the number of seconds defined by the time 'gap' has passed since the last detection of motion and motion closes the mpeg file. -

      -

      +

      + + +

      + +

      smart_mask_speed

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 0 - 10
      • +
      • Default: 0 (disabled)
      • +
      +

      +Speed for the smart mask. Default is 0 = DISABLED. 1 is slow, 10 is fast. +Smartmask is a dynamic, self-learning mask. Smartmask will disable sensitivity +in areas with frequent motion (like trees in the wind). Sensitivity is turned +on again after some time of no more motion in this area. The built mask is a bit +larger at the borders than the actual motion was. This way smartmask works more +reliable when sudden moves occur under windy conditions. +

      +Fast means here that the mask is built quick, but it is also not staying very long with no more motion. +Slow means that it takes a while until the mask is built but it also stays longer. A good start value +for smart_mask_speed is 5. This setting is independent from the framerate. The attack and decay time +is constant over all available framerates. +When smartmask is enabled and motion is also configured to either write motion-images or motion-mpegs, +the current smartmask is copied as an overlay into the black/white motion-pictures/mpegs in red colour. +Same thing happens to the webcam stream when Motion runs in setup_mode. That way you can +easily adjust smart_mask_speed. +

      +The mask_file option provides a static mask to turn off sensitivity in certain areas. +This is very useful to mask a street with cars passing by all day long etc... +

      +But imagine a scenario with large bushes and big trees where all the leaves are moving +in the wind also triggering motion from time to time even with despeckle turned on. Of +course you can also define a static mask here, but what if the bushes are growing during +spring and summer? Well, you have to adapt the mask from time to time. What if the camera +position moves slightly? What if someone grows new plants in your garden? You always have to setup a new static mask. +

      +The answer to this problem is the smart mask feature A dynamic, self-learing mask. +

      +Smart mask will disable sensitivity in areas with frequent motion (like trees in the wind). +Sensitivity is turned on again after some time of no more motion in this area. The built mask +is a bit larger at the borders than the actual motion. This way smartmask works more reliably +when sudden moves occur under windy conditions. + +

      + +

      lightswitch

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 0 - 100
      • +
      • Default: 0 (disabled)
      • +
      +

      +Ignore sudden massive light intensity changes given as a percentage of the picture area that changed intensity. +The value defines the picture areas in percent that will trigger the lightswitch condition. When lightswitch is +detected motion detection is disabled for 5 picture frames. This is to avoid false detection when light conditions +change and when a camera changes sensitivity at low light. +

      + +

      minimum_motion_frames

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 1 - 1000s
      • +
      • Default: 1
      • +
      +

      +Picture frames must contain motion at least the specified number of frames in a row before they are +detected as true motion. At the default of 1, all motion is detected. Valid range is 1 to thousands, +but it is recommended to keep it within 1-5. +Note that the picture frames are buffered by Motion and once motion is detected also the first frames +containing motion are saved so you will not miss anything. +The feature is used when you get many false detections when the camera changes light sensitivity or light changes. +Even though Motion accepts large values you should set this to a relatively low number +(below 10). For each step larger than 1 Motion reserves space in RAM for the picture frame buffer. If you have a +large value Motion will miss many frames from the camera while it is processing the all the pictures in the buffer. + +

      + +

      event_gap

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 0 - 2147483647
      • +
      • Default: 60
      • +
      +

      +The seconds of no motion detection that triggers the end of an event. +An event is defined as a series of motion images taken within a short timeframe. +The value -1 is allowed and disables + events causing all Motion to be written to one single movie file and no pre_capture. + If set to 0, motion is running in gapless mode. Movies don't have gaps anymore. An + event ends right after no more motion is detected and post_capture is over. + +Disabling events has bad side effects on +noise_tune and smartmask. Both features can only work properly outside an event. +When event_gap is set to -1, both features don't work properly anymore. +An event is defined as a series of motion images taken within a short timeframe. +E.g. a person walking through the room is an event that may have caused 10 single +jpg images to be stored. This option defines how long a pause between detected motions +that is needed to be defined as a new event. +The timer starts after the last motion is detected and post_capture images +have been saved and appended to open movie files. +Any motion detected before the gap timer times out resets the gap timer so it starts counting over again. +The option 'event_gap' is important. It defines how long a period of no motion detected it takes before we say an event is over. An event is defined as a series of motion images taken within a short timeframe. E.g. a person walking through the room is an event that may have caused 10 single jpg images to be stored. Motion detected includes post_captured frames set by the 'post_capture' option. The 'gap' option defines how long a pause between detected motions that is needed to be defined as a new event. A good starting value is 60 seconds. +The way 'gap' works in more technical terms is: +
        +
      • A timer that timeouts 'event_gap' seconds after the last video frame with motion is detected.
      • +
      • If 'post_capture' is activated then the gap timer starts counting after the last image of the post_capture buffer has been saved.
      • +
      • The gap timer is reset and starts all over each time new motion is detected, so you will not miss any action by having a short 'gap' value. It will just create more events (e.g. more mpegs files)
      • +
      +The gap value impacts many functions in Motion. +
        +
      • When the timer runs out the event number is increased by one next time motion is detected. + When you use the %v conversion specifier in filenames or text features this means that the + number in filename or text increased by one.
      • +
      • The pre_capture feature only works at the beginning of an event. So if you have a very large 'event_gap' + value pre_capture is not working very often.
      • +
      • When you make movies using the ffmpeg features a new movie file is started at the beginning of an event + when the first motion is detected. When 'event_gap' seconds has passed without motion (and post_captured frames + saved) the movie files are completed and closed.
      • +
      • Do not use large event_gap values to generate one large movie file. + If Motion stops working this movie file never gets properly completed and closed + you will not be able to view it.
      • +
      • Some of the tracking features sets the camera back to the center position when an event is over.
      • +
      + +Note that 'event_gap' and 'minimum_gap' have nothing to do with each other. +

      +

      +
    + +

    Script Execution

    +
      +

      +Motion can execute external commands based on the motion detection and related events. +They are described in the sections below. +

      +Security Warning! +

      +These features mean you have to pay attention to the following. +
        +
      • Anyone with access to the remote control port (http) can execute any command on your computer with +the same privileges as the user running Motion. +Anyone can access your control port if you have not either limited access to localhost or +limited access using firewalls in the server. +You should always have a router between a machine running Motion with remote control +enabled and the Internet and make sure the Motion control port is not accessible from the outside. +
      • +
      • If you limit control port to localhost you still need to take care of any user logging into the server +with any kind of GUI or terminal session. All it takes is a browser or single command line execution to +change settings in Motion. +
      • +
      • It is a good idea to run Motion as a harmless user. Not as root!!
      • +
      +

      + +

      +

      +

      on_event_start

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -Command to be executed when an event starts. An event starts at first motion detected after a period of no motion defined by gap. You can use ConversionSpecifiers and spaces as part of the command. -

      -Full path name of the program/script. -

      -This can be any type of program or script. Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. -

      -The command is run when an event starts. I.e. the first motion is detected since the last event. -

      -This option replaces the former options 'mail', 'sms' and 'execute'. -

      -

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: Default: Not defined
      • +
      +

      +The full path and file name of the program/script to be executed at the start of an event. +An event starts at first motion detected after a +period of no motion defined by gap. +

      +You can use Conversion Specifiers +and spaces as part of the command. This can be any type of program or script. +Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash +also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. +

      +

      + +

      on_event_end

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: Not defined
      • +
      +

      +The full path and file name of the program/script to be executed when a event ends. +An event ends after the event_gap has expired. +

      +You can use Conversion Specifiers +and spaces as part of the command. This can be any type of program or script. +Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash +also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. +

      +

      + +

      on_picture_save

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: Not defined
      • +
      +

      +The full path and file name of the program/script to be executed when a picture is saved. +

      +You can use Conversion Specifiers +and spaces as part of the command. This can be any type of program or script. +Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash +also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. +

      +Use %f for passing filename (with full path) to the command. +

      +

      +

      on_motion_detected

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -Command to be executed when a motion frame is detected. You can use Conversion Specifiers and spaces as part of the command. -

      -Do not write "none" if you do not want to execute commands. Simply do not include the option in the file or comment it out by placing a "#" or ";" as the first character on the line before the execute command. -

      -

      -

      on_movie_end

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -Command to be executed when an ffmpeg movie is closed at the end of an event. You can use Conversion Specifiers and spaces as part of the command. Use %f for passing filename (with full path) to the command. -

      -Full path name of the program/script. -

      -This can be any type of program or script. Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. -

      -The command is run when an event is over. I.e. the number of seconds defined by the time 'gap' has passed since the last detection of motion and motion closes the mpeg file. -

      -This option was previously called onffmpegclose. -

      -Note that from Motion 3.2.4 the path name of the picture file is no longer appended to the command. Instead you can use the conversion specifier %f to insert the picture filename (full path) anywhere in the command. -

      -Most common conversion specifiers -

        -
      • %Y = year, %m = month, %d = date -
      • %H = hour, %M = minute, %S = second -
      • %v = event -
      • %q = frame number -
      • %t = thread (camera) number -
      • %D = changed pixels -
      • %N = noise level -
      • %i and %J = width and height of motion area -
      • %K and %L = X and Y coordinates of motion center -
      • %C = value defined by text_event -
      • %f = filename with full path -
      • %n = number indicating filetype -
      -

      -

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: Not defined
      • +
      +

      +The full path and file name of the program/script to be executed when motion is detected. +

      +You can use Conversion Specifiers +and spaces as part of the command. This can be any type of program or script. +Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash +also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. +

      +

      + +

      on_area_detected

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default:
      • +
      +

      +The full path and file name of the program/script to be executed when motion is +detected in the predefined area indicated in the area_detect option. +

      +You can use Conversion Specifiers +and spaces as part of the command. This can be any type of program or script. +Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash +also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. +

      +

      +

      on_movie_start

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -Command to be executed when an mpeg movie is created. You can use Conversion Specifiers and spaces as part of the command. Use %f for passing filename (with full path) to the command. -

      -Full path name of the program/script. -

      -This can be any type of program or script. Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. When you use ffmpeg the film is generated on the fly and on_movie_start then runs when the new mpeg file is created. Often you will want to use the on_movie_end option which runs when the mpeg file is closed and the event is over. -

      -This option was previously called onmpeg. -

      -Note that from Motion 3.2.4 the path name of the picture file is no longer appended to the command. Instead you can use the conversion specifier %f to insert the picture filename (full path) anywhere in the command. -

      -Most common conversion specifiers -

        -
      • %Y = year, %m = month, %d = date -
      • %H = hour, %M = minute, %S = second -
      • %v = event -
      • %q = frame number -
      • %t = thread (camera) number -
      • %D = changed pixels -
      • %N = noise level -
      • %i and %J = width and height of motion area -
      • %K and %L = X and Y coordinates of motion center -
      • %C = value defined by text_event -
      • %f = filename with full path -
      • %n = number indicating filetype -
      -

      -

      -

      on_picture_save

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -Command to be executed when an image is saved. You can use Conversion Specifiers and spaces as part of the command. Use %f for passing filename (with full path) to the command. -

      -Full path name of the program/script. -

      -This can be any type of program or script. Remember to set the execution bit in the file access control list (chmod) and if it is a script type program such as perl or bash also remember the shebang line (e.g. #!/usr/bin/perl) as the first line of the script. -

      -Note that from Motion 3.2.4 the path name of the picture file is no longer appended to the command. Instead you can use the conversion specifier %f to insert the picture filename (full path) anywhere in the command. -

      -Most common conversion specifiers -

        -
      • %Y = year, %m = month, %d = date -
      • %H = hour, %M = minute, %S = second -
      • %v = event -
      • %q = frame number -
      • %t = thread (camera) number -
      • %D = changed pixels -
      • %N = noise level -
      • %i and %J = width and height of motion area -
      • %K and %L = X and Y coordinates of motion center -
      • %C = value defined by text_event -
      • %f = filename with full path -
      • %n = number indicating filetype -
      -

      -

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: Not defined
      • +
      +

      +The full path and file name of the program/script to be executed when a +new movie is being created. +

      +You can use Conversion Specifiers +and spaces as part of the command. This can be any type of program or script. +Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash +also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. +

      +Use %f for passing filename (with full path) to the command. +

      +

      + +

      on_movie_end

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: Not defined
      • +
      +

      +

      +The full path and file name of the program/script to be executed after a new +movie was created. +

      +You can use Conversion Specifiers +and spaces as part of the command. This can be any type of program or script. +Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash +also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. +

      +Use %f for passing filename (with full path) to the command. +

      +

      + +

      on_camera_lost

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default:
      • +
      +

      +The full path and file name of the command to be executed when a camera can't be opened or if it is lost +Note that there are situations when motion doesn't detect a lost camera. It is +dependent upon the camera and driver and it is advised that this option be tested +for each configuration. It has also been observed that there are also +situations in which the disconnection of the camera even hangs the PC in which +case this script will not be executed. +

      +You can use Conversion Specifiers +and spaces as part of the command. This can be any type of program or script. +Remember to set the execution bit in the ACL and if it is a script type program such as perl or bash +also remember the shebang line (e.g. #!/user/bin/perl) as the first line of the script. +

      +

      + +
    + +

    Output - General Options

    +
      + +

      quiet

      -

        -
      • Type: Boolean -
      • Range / Valid values: on, off -
      • Default: off -
      • Option Topic -
      -

      +

      +
        +
      • Type: Boolean
      • +
      • Range / Valid values: on, off
      • +
      • Default: off
      • +
      +

      Be quiet, don't output beeps when detecting motion. -

      Only works in non-daemon mode. -

      -

      -

      - -

      What happened to mail and sms?

      -The 6 new on_xxxxx options replace the former execute, mail and sms options. -

      -They are quite generic and flexible. These small bash scripts gives to the same functionality as mail and sms BUT you have all the flexibility you want to extend the messages, change the 'from' email address etc. -

      -

      Sending email at start of event

      -Script written by JoergWeber -
      -#!/bin/sh
      -
      -# Motion sample script to send an e-mail at start of an event.
      -# Replaces the former 'mail' option.
      -# Just define this script as 'on_event_start'-script in motion.conf like that:
      -# on_event_start send_mail "%Y-%m-%d %T"
      -
      -#change to suit your needs:
      -#location of 'mail' binary
      -MAIL="/usr/bin/mail"
      -#Destination e-mail address
      -TO="root@localhost"
      -#Subject of the e-mail
      -SUBJECT="Motion detected"
      -
      -#Don't change anything below this line
      -echo -e "This is an automated message generated by motion.\n\nMotion detected: $1\n\n" | $MAIL -s "$SUBJECT" $TO
      -
      -

      -

      Sending SMS at start of event

      -Script written by JoergWeber -

      -If you uncomment the line #/usr/local/bin/send_mail $1 you can combine both sending email and sms. -

      -#!/bin/sh
      +

      +

      + +

      pre_capture

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 0 - 100s
      • +
      • Default: 0 (disabled)
      • +
      +

      +Specifies the number of pre-captured (buffered) pictures from before motion +was detected that will be output at motion detection. +The recommended range is 0 to 5. It is not recommended to use large values. +Large values will cause Motion to skip video frames and cause unsmooth movies. +To smooth movies use larger values of post_capture instead. +

      +Motion buffers the number of picture frames defined by 'pre_capture'. When motion is detected the pictures in the +buffer are included in the movie. The effect is that it seems the program knew in advance +that the event was going to take place and started the recording before it actually happened. +This is a nice feature that give more complete video clips of an event. +

      +If pre_capture is set to 0 the feature is disabled. The recommended value would be approx 0.5 second of +video so the value should be defined so it fits the framerate and the desired pre-capture time. +You can in theory have up to 100s of pre-captured frames but naturally this makes motion leave a larger footprint in +the memory of the computer. +

      +More important Motion is processing all the buffered images including saving jpegs, +encoding the movie, writing to databases and executing external programs after the first image is detected as Motion. +

      +Motion will not grab another image until this is done. This means that even moderate values for pre_capture combined +with high framerates will mean that you will probably miss many frames of Motion. +

      +It is therefore recommended to use relatively small values for pre_capture. +Depending on your chosen framerate and depending on the features enabled values from 1-5 are sensible. +

      +If you wish to create a smooth movie during events using large pre_capture values will do the opposite! It will create +a long pause where a lot of action is missed. +

      +To get a smooth movie use a large value for post_capture which does not cost any performance hit or RAM +space. +

      +

      + +

      post_capture

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 0 - 2147483647
      • +
      • Default: 0 (disabled)
      • +
      +

      +Specifies the number of frames to be captured after motion has been detected. +The purpose of this is mainly to create smooth video clips each time motion is detected. Use it to you personal +taste (and disk space).. +This option is the preferred way to create continuous movies. Post_capture does not consume extra RAM and it +does not create pauses in the movie even with large values. +If you only store movies and do not have output_normal on, then the recommended post_capture value is what is +equivalent to 1-5 seconds of movie. +

      +

      + +

      target_dir

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: Not defined = current working directory
      • +
      +

      +The full path for the target directory for picture and movie files to be saved. +The default is the current working directory. This is the target directory for all snapshots, +images files and movie files. +You will normally always want to specify this parameter as an absolute path. +

      +Note that the file name options are all saved relative to this target_dir +This means in principle that you can specify target_dir as '/' and be 100% flexible. But this is +NOT recommended. It is recommended that this directory be specified as deep as possible. +

      +

      + +
    + +

    Output - Picture Options

    +
      + +

      +Motion can output different types of pictures. The normal picture is indicated below. +

      +outputnormal1.jpg +

      +The motion type picture or also referred to as a debug picture is shown +below. Note that the largest area is blue and only this is counted as Motion. +

      +The Motion image shows how Motion maintains a "reference frame" which is not just the last picture frame +but a mathematical calculation of the past images. This enlarges real Motion and ensures that it is not easy to +sneak in slowly. +

      +outputmotion1.jpg +

      +

      + + +

      output_pictures

      +

      +
        +
      • Type: Discrete Strings
      • +
      • Range / Valid values: on, off, first, best
      • +
      • Default: on
      • +
      +

      +This option controls the output of the normal image. +

      +'on' is the usual selection. +

      +If you set the value to 'first' Motion saves only the first motion detected picture per event. +If you set it to "best" Motion saves the picture with most changed pixels during the event. +This may be useful if you store movies on a server and want to present a jpeg to show the content of the movie +on a webpage. +

      +"best" requires a little more CPU power and resources compared to "first". +

      +'off' to don't write pictures +

      +

      + +

      output_debug_pictures

      +

      +
        +
      • Type: Boolean
      • +
      • Range / Valid values: on, off
      • +
      • Default: off
      • +
      +

      +Output pictures with only the moving object. +This feature generates the special motion type movies where you only see the pixels that +changes as a graytone image. If labelling is enabled you see the largest area in blue. +

      +If a Smartmask is specified, it is shown in red. +

      +Motion images shows the motion content of the pictures. +This is good for tuning and testing but probably not very interesting for the general public. +

      +Default is not to store these motion images. +Motion pictures are stored the same place and with the same filename as normal motion +triggered pictures except they have an "m" appended at the end of the filename before +the .jpg or .ppm. E.g. the name can be 01-20020424232936-00m.jpg. +

      +

      + +

      quality

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 1 - 100
      • +
      • Default: 75
      • +
      +

      +The quality for the jpeg images in percent. +100 means hardly compressed. A small number means a much smaller file size but also a less nice +quality image to look at. +

      +

      + +

      picture_type

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default:
      • +
      +

      +This option specifies the type of picture file to output. The recommendation is to always use jpg except +if you have a specific need to store high quality pictures without any quality loss. +

      +

      + +

      snapshot_interval

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 0 - 2147483647
      • +
      • Default: 0 (disabled)
      • +
      +

      +This parameter specifies the number of seconds between each snapshot +

      +

      + +

      snapshot_filename

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: %v-%Y%m%d%H%M%S-snapshot
      • +
      +

      +This option indicates the file name and optionally the path for the snapshots (jpeg or ppm) relative to target_dir. +

      +The file extension .jpg or .ppm is automatically added. +

      +A symbolic link called lastsnap.jpg (or lastsnap.ppm) is created in the target_dir and will always +point to the latest snapshot, unless snapshot_filename is exactly 'lastsnap' +

      +You can use Conversion Specifiers in this option. +

      +

      + +

      picture_filename

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: %v-%Y%m%d%H%M%S-%q
      • +
      +

      +This option indicates the file name and optionally the path for the pictures (jpeg or ppm) relative to target_dir. +

      +The file extension .jpg or .ppm is automatically added. +

      +You can use Conversion Specifiers in this option. +

      +

      + +

      exif_text

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default:
      • +
      +

      +Use this option to specify the text to include in a JPEG EXIF comment +The EXIF timestamp is included independent of this text. +

      +You can use Conversion Specifiers in this option. +

      +

      +
    + +

    Output - Movie Options

    +
      +

      +

      max_movie_time

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 0 (infinite) - 2147483647
      • +
      • Default: 3600
      • +
      +

      +The maximum length of a movie in seconds. Set this to zero for unlimited length. +

      +

      + +

      ffmpeg_output_movies

      +

      +
        +
      • Type: Boolean
      • +
      • Range / Valid values: on, off
      • +
      • Default: off
      • +
      +

      +Use ffmpeg libraries to encode movies of the motion. This option +generates a new movie at the beginning of each new event and appends to the +movie for each motion detected within the same event. +The current event ends when the time defined by the 'event_gap' option has passed with no motion detected. +At the next detection of motion a new movie is started. +

      +To use this feature you need to install ffmpeg or Libav. +

      +

      + +

      ffmpeg_output_debug_movies

      +

      +
        +
      • Type: Boolean
      • +
      • Range / Valid values: on, off
      • +
      • Default: off
      • +
      +

      +Use ffmpeg libraries to encode motion type movies where you only see the pixels that changes. +Works like ffmpeg_output_movies but outputs motion pixel type pictures instead. +This feature generates the special motion type movie where you only see the pixels +that changes as a graytone image. If labeling is enabled you see the largest area in blue. +Smartmask is shown in red. The filename given is the same as the normal movies except they +have an 'm' appended after the filename. +

      +

      + +

      ffmpeg_timelapse

      +

      +
        +
      • Type: Boolean
      • +
      • Range / Valid values: 0 - 2147483647
      • +
      • Default: 0 (disabled)
      • +
      +

      +Create a timelapse movie saving a picture frame at the interval in seconds set by this parameter. +

      +

      -# Motion sample script to send an sms at start of an event. -# Replaces the former 'sms' option. -# Just define this script as 'on_event_start'-script in motion.conf like that: -# on_event_start send_sms "%Y-%m-%d %T" -# -# If you want to send an e-mail message here as well, just uncomment the last -# line of this script. +

      ffmpeg_timelapse_mode

      +

      +
        +
      • Type: Discrete Strings
      • +
      • Range / Valid values: hourly, daily, weekly-sunday, weekly-monday, monthly, manual
      • +
      • Default: daily
      • +
      +

      +The file rollover mode of the timelapse video. +Note that it is important that you use the conversion specifiers in ffmpeg_filename that ensure that +the new timelapse file indeed is a new file. If the filename does not change Motion will simply append +the timelapse pictures to the existing file. +The value 'Manual' means that Motion does not automatically rollover to a new filename. You can do it +manually using the http control interface by setting the option 'ffmpeg_timelapse' to 0 and then back +to your chosen value. Value 'hourly' rolls over on the full hour. Value 'daily' which is the default +rolls over at midnight. There are two weekly options because depending on where you come from a week +may either start on Sunday or Monday. And 'monthly' naturally rolls over on the 1st of the month. +

      +

      -#change to suit your needs: -#location of 'sms-client' binary -SMS_CLIENT="/usr/bin/sms_client" -#Destination sms number -TO="12345" +

      ffmpeg_bps

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 0 - 9999999
      • +
      • Default: 400000
      • +
      +

      +Bitrate of movies produced by ffmpeg. Bitrate is bits per second. +Higher value mans better quality and larger files if the camera is on a fixed bitrate setting. +Experiment to get the desired quality. The better quality the bigger files. +This option is ignored if ffmpeg_variable_bitrate is not 0 (disabled). +

      +

      -#Don't change anything below this line -$SMS_CLIENT $TO "Motion detected $1" +

      ffmpeg_variable_bitrate

      +

      +
        +
      • Type: Integer
      • +
      • Range / Valid values: 0 - 100
      • +
      • Default: 0 (disabled)
      • +
      +

      +Enables and defines variable bitrate for the ffmpeg encoder. +The option of ffmpeg_bps is ignored if variable bitrate is enabled. +A value of 0 disables this option while values 1 - 100 varies the quality +of the movie. The value of 1 means worst quality and 100 is the best quality. +

      +Experiment for the value that gives you the desired compromise between size and quality. +

      +

      -#/usr/local/bin/send_mail $1 +

      ffmpeg_video_codec

      +

      +
        +
      • Type: Discrete Strings
      • +
      • Range / Valid values: mpeg1, mpeg4, msmpeg4, swf, flv, ffv1, mov, ogg, mp4, mkv, hevc
      • +
      • Default: mpeg4
      • +
      +

      +Codec to be used by ffmpeg for the video compression. +

      +Timelapse videos have two options. +
        +
      • mpg - Creates mpg file with mpeg-2 encoding. If motion is shutdown and restarted, new pics will be appended + to any previously created file with name indicated for timelapse.
      • +
      • mpeg4 - Creates avi file with the default encoding. If motion is shutdown and restarted, new pics will +create a new file with the name indicated for timelapse.
      • +
      +

      +Movie files have the following options +
        +
      • mpeg4 or msmpeg4 - gives you files with extension .avi
      • +
      • swf - gives you a flash film with extension .swf
      • +
      • flv - gives you a flash video with extension .flv
      • +
      • ffv1 - FF video codec 1 for Lossless Encoding
      • +
      • mov - QuickTime
      • +
      • ogg - Ogg/Theora
      • +
      • mp4 - MPEG-4 Part 14 H264 encoding
      • +
      • mkv - Matroska H264 encoding
      • +
      • hevc - H.265 / HEVC (High Efficiency Video Coding)
      • +
      - -

      -

      -

      Motion Guide - Special Features

      -

      -

      Tracking Control

      -This is still at the experimental stage. Read more about it motion tracking page. -

      -

      Tracking Feature with Logitech Quickcam Sphere/Orbit

      -Motion supports controlling the pan and tilt feature of a Logitech Quickcam Sphere/Orbit. -

      -Motion can move the camera to a fixed position given in degrees pan (left-right) and tilt (down-up). Movement can be set with absolute coordinates or relative to current position. There is also an auto tracking feature for the Logitech Quickcam Sphere/Orbit but it is not very mature. It is fun to play with but not very useful yet. See this topic of how KennethLavrsen controls his Sphere: LogitechSphereControl. -

      -For a detailed description of http remote control see the section Remote Control with http. -

      -List of tracking options -

      -

      track_auto

      -

        -
      • Type: Boolean -
      • Range / Valid values: on, off -
      • Default: off -
      • Option Topic -
      -

      -Enable auto tracking -

      -Requires a tracking camera type supported by Motion. -

      -

      -

      track_iomojo_id

      -

        -
      • Type: Integer -
      • Range / Valid values: 0 - 2147483647 -
      • Default: 0 -
      • Option Topic -
      -

      -Use this option if you have an iomojo smilecam connected to the serial port instead of a general stepper motor controller. -

      -Only used for iomojo camera. -

      -

      -

      track_maxx

      -

        -
      • Type: Integer -
      • Range / Valid values: 0 - 2147483647 -
      • Default: 0 -
      • Option Topic -
      -

      -The maximum position for servo x. -

      -Only used for stepper motor tracking. -

      -

      -

      track_maxy

      -

        -
      • Type: Integer -
      • Range / Valid values: 0 - 2147483647 -
      • Default: 0 -
      • Option Topic -
      -

      -The maximum position for servo y. -

      -Only used for stepper motor tracking. -

      - -

      -

      -

      track_motorx

      -

        -
      • Type: Integer -
      • Range / Valid values: -1 - 2147483647 -
      • Default: -1 -
      • Option Topic -
      -

      -The motor number that is used for controlling the x-axis. -

      -Only used for stepper motor tracking. -

      -

      -

      track_motory

      -

        -
      • Type: Integer -
      • Range / Valid values: -1 - 2147483647 -
      • Default: -1 -
      • Option Topic -
      -

      -The motor number that is used for controlling the y-axis. -

      -Only used for stepper motor tracking. -

      - -

      -

      -

      track_move_wait

      -

        -
      • Type: Integer -
      • Range / Valid values: 0 - 2147483647 -
      • Default: 10 -
      • Option Topic -
      -

      -Delay during which tracking is disabled after auto tracking has moved the camera. Delay is defined as number of picture frames. -

      -The actual delay is depending on the chosen framerate. If you want the camera to move maximum once every 2 seconds and the framerate is 10 then you need to set the track_move_wait value to 2 * 10 = 20. -

      -

      -

      track_port

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -This is the device name of the serial port to which the stepper motor interface is connected. -

      -Only used for stepper motor tracking. -

      -

      -

      track_speed

      -

        -
      • Type: Integer -
      • Range / Valid values: 0 - 255 -
      • Default: 255 -
      • Option Topic -
      -

      -Speed to set the motor to. -

      -Only used for stepper motor tracking. -

      -

      -

      track_step_angle_x

      -

        -
      • Type: Integer -
      • Range / Valid values: 0-90 -
      • Default: 10 -
      • Option Topic -
      -

      -Angle in degrees the camera moves per step on the X-axis with auto tracking. Currently only used with pwc type cameras. -

      -Requires a tracking camera type pwc. -

      -

      -

      track_step_angle_y

      -

        -
      • Type: Integer -
      • Range / Valid values: 0-40 -
      • Default: 10 -
      • Option Topic -
      -

      -Angle in degrees the camera moves per step on the Y-axis with auto tracking. Currently only used with pwc type cameras. -

      -Requires a tracking camera type pwc. -

      - -

      -

      -

      track_stepsize

      -

        -
      • Type: Integer -
      • Range / Valid values: 0 - 255 -
      • Default: 40 -
      • Option Topic -
      -

      -Number of steps to make. -

      -Only used for stepper motor tracking. -

      -

      -

      track_type

      -

        -
      • Type: Discrete Strings -
      • Range / Valid values: 0 (none), 1 (stepper), 2 (iomojo), 3 (pwc), 4 (generic), 5 (uvcvideo) -
      • Default: 0 (None) -
      • Option Topic -
      -

      -Type of tracker. -

      -Motion has special tracking options which use either a serial stepper motor controller, an iomojo smile cam or a Philips WebCam driver compatible pan/tilt camera such as the Logitech Quickcam Sphere or Orbit. -

      -To disable tracking, set this to 0 and the other track options are ignored. -

      -Value 1 is for the special Motion Tracking project using a stepper motor and a home made controller. -

      -Value 2 is for the iomojo smilecam -

      -Value 3 is for pwc type USB tracking cameras such as the Logitech Quickcam Sphere/Orbit which is driven by the pwc (Philips WebCam) driver. To use this camera your version of pwc must be at least 8.12. -

      -Value 4 is the generic track type. Currently it has no other function than enabling some of the internal Motion features related to tracking. Eventually more functionality will be implemented for this type. -

      -Value 5 is for uvcvideo type USB tracking cameras such as the Logitech Quickcam Sphere/Orbit MP (new Model) which is driven by the uvcvideo driver. This option was added in Motion 3.2.8. -

      -

      -

      Using Databases

      -Motion can be compiled with both MySQL and PostgreSQL database support. When enabled Motion adds a record to a table in the database as specified by the sql_query. The query contains the fields that are used and the value are given by using conversion specifiers for dynamic data like filename, time, number of detected pixels etc. Motion does not place any binary images in the database and it cannot remove old records. -

      -Motion only adds records to the database when files are created. The database contains records of saved files which means to get a record in the database the feature that enables for example motion detection, timelapse, snapshots etc must be enabled. The sql_log options defines which types of files are logged in the database. -

      -The following sql_log options are common to both MySQL and PostgreSQL. -

      -

      -

      sql_log_image

      -

        -
      • Type: Boolean -
      • Range / Valid values: on, off -
      • Default: on -
      • Option Topic -
      -

      -Log to the database when creating motion triggered image file. -

      -Configuration option common to MySQL and PostgreSQL. Motion must be built with MySQL or PostgreSQL support to use this feature. -

      -

      -

      sql_log_mpeg

      -

        -
      • Type: Boolean -
      • Range / Valid values: on, off -
      • Default: off -
      • Option Topic -
      -

      -Log to the database when creating motion triggered mpeg file. -

      -Configuration option common to MySQL and PostgreSQL. Motion must be built with MySQL or PostgreSQL support to use this feature. -

      -

      -

      sql_log_snapshot

      -

        -
      • Type: Boolean -
      • Range / Valid values: on, off -
      • Default: on -
      • Option Topic -
      -

      -Log to the database when creating a snapshot image file. -

      -Configuration option common to MySQL and PostgreSQL. Motion must be built with MySQL or PostgreSQL support to use this feature. -

      -

      -

      sql_log_timelapse

      -

        -
      • Type: Boolean -
      • Range / Valid values: on, off -
      • Default: off -
      • Option Topic -
      -

      -Log to the database when creating timelapse mpeg file -

      -Configuration option common to MySQL and PostgreSQL. Motion must be built with MySQL or PostgreSQL support to use this feature. -

      -

      -

      sql_query

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: insert into security(camera, filename, frame, file_type, time_stamp, text_event) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C') -
      • Option Topic -
      -

      -SQL query string that is sent to the database. The values for each field are given by using convertion specifiers -

      -Most common conversion specifiers -

        -
      • %Y = year, %m = month, %d = date -
      • %H = hour, %M = minute, %S = second -
      • %v = event -
      • %q = frame number -
      • %t = thread (camera) number -
      • %D = changed pixels -
      • %N = noise level -
      • %i and %J = width and height of motion area -
      • %K and %L = X and Y coordinates of motion center -
      • %C = value defined by text_event -
      • %f = filename with full path -
      • %n = number indicating filetype -
      -

      -

      -See the "MySQL" section for detailed information about the database itself. -

      -

      MySQL

      -You can use the MySQL database to register each file that is stored by motion. -

      -You need to generate a new database with a name of your own choice. You must enter this name in the config file (mysql_db option). The default value for the option sql_query requires that you create a new database in MySQL with a new table called "security" with the following fields: -

      -insert into security(camera, filename, frame, file_type, time_stamp, text_event) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C') -

        -
      • camera (int) - camera (thread) number -
      • filename (char60) - filename (full path) -
      • frame (int) - the number of the picture frame -
      • file_type (int) - file type as a number - see table below. -
      • time_stamp (timestamp) - timestamp for the picture in native database format -
      • text_event (timestamp) - The text from the text_event option which by default is compatible with timestamps in SQL. -
      -

      -Note from version 3.2.4 the introduction of sql_query completely redefines the way you setup the SQL feature. It is now 100% flexible and can easily be made compatible with your existing Motion database from earlier versions of Motion. -

      -These are the file type descriptions and the file type numbers stored in the database. -

      - - - - - - -
      Normal image 1
      Snapshot image 2
      Motion image (showing only pixels defined as motion) 4
      Normal mpeg image 8
      Motion mpeg (showing only pixels defined as motion) 16
      Timelapse mpeg 32
      -

      -You can create the table using the following SQL statement. -

      -CREATE TABLE security (camera int, filename char(80) not null, frame int, file_type int, time_stamp timestamp(14), text_event timestamp(14)); -

      -If you choose to use text_event for a non-timestamp value you can instead define something like. -

      -CREATE TABLE security (camera int, filename char(80) not null, frame int, file_type int, time_stamp timestamp(14), text_event char(40)); -

      -

      -Remember to update grant table to give access to the mysql username you choose for motion. -

      -It would be too much to go into detail about how to setup and use MySQL. After all this is a guide about Motion. However here are some hints and links. -

      -Setting Up a MySQL Based Website - A beginners guide from Linux Planet. -

      -Webmonkey PHP/!MySQL tutorial - Entertaining and easy to read. -

      -The phpMyAdmin homepage. The best and simplest tool to use MySQL (editors opinion). Requires Apache/PHP. -

      -The options for MySQL -

      -

      -

      mysql_db

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -Name of the MySQL database. -

      -MySQL CONFIG FILE OPTION. Motion must be built with MySQL libraries to use this feature. -

      -If you compiled motion with MySQL support you will need to set the mysql options if you want motion to log events to the database. -

      -

      -

      mysql_host

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: localhost -
      • Option Topic -
      -

      -IP address or domain name for the MySQL server. Use "localhost" if motion and MySQL runs on the same server. -

      -MySQL CONFIG FILE OPTION. Motion must be built with MySQL libraries to use this feature. -

      -

      -

      mysql_password

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -The MySQL password. -

      -MySQL CONFIG FILE OPTION. Motion must be built with MySQL libraries to use this feature. -

      -

      -

      mysql_user

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -The MySQL user name. -

      -MySQL CONFIG FILE OPTION. Motion must be built with MySQL libraries to use this feature. -

      -

      -

      -

      PostgreSQL

      -Same/similar as for MySQL above. -

      -The options for PostgreSQL -

      -

      -

      pgsql_db

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -Name of the PostgreSQL database. -

      -PostgreSQL CONFIG FILE OPTION. Motion must be built with PostgreSQL libraries to use this feature. -

      -If you compiled motion with PostgreSQL support you will need to set all the pgsql_ options if you want motion to log events to the database. -

      -

      -

      pgsql_host

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: localhost -
      • Option Topic -
      -

      -IP address or domain name for the PostgreSQL server. Use "localhost" if motion and PostgreSQL runs on the same server. -

      -PostgreSQL CONFIG FILE OPTION. Motion must be built with pgsql_db libraries to use this feature. -

      -

      -

      pgsql_password

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -The PostgreSQL password. -

      -PostgreSQL CONFIG FILE OPTION. Motion must be built with PostgreSQL libraries to use this feature. -

      -

      -

      pgsql_port

      -

        -
      • Type: Integer -
      • Range / Valid values: 0 - 65535 -
      • Default: 5432 -
      • Option Topic -
      -

      -The PostgreSQL server port number. -

      -PostgreSQL CONFIG FILE OPTION. Motion must be built with PostgreSQL libraries to use this feature. -

      -

      -

      pgsql_user

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -The PostgreSQL user name. -

      -PostgreSQL CONFIG FILE OPTION. Motion must be built with PostgreSQL libraries to use this feature. -

      -

      -

      Video4Linux Loopback Device

      -You can use this driver for looking at motion in realtime. The video4linux driver is written by the same author that first created Motion. You can find the source and a brief description at the video4linux loopback device web page. -

      -The video4linux device is a Kernel module which installs itself as a video pipe. It has an input and an output. The module simply takes anything that comes on its input and send it out at the output. The purpose of this is to create a standard video4linux type video device that other programs can then use. You may now ask: "What do I need that for?". -

      -Only one program can access a video device at a time. When motion is using a camera - no other program can access the same camera. But motion is made to be able to feed a video signal to the video loopback device. This way an additional program such as Camstream, Xawtv, a video stream server etc can watch the signal from a camera that motion uses already. What you see is not the live camera stream but the exact same picture that motion uses for detecting motion and the same pictures that are saved/streamed. You can also choose to see the "motion" type images where you see the pixels that are changing - live. Originally the video4linux pipe was used as an interface between Motion and a Webcam server. Since version 2.9 Motion has had its own webserver so this usage is no longer very relevant. -

      -When you install the video loopback device it will create an input - for example /dev/video5 and an output - for example /dev/video6. You can then tell motion to "pipe" the video signal to the /dev/video5 and look at the pictures live using e.g. Camstream on /dev/video6. Camstream is "fooled" to think it is looking at a real camera. -

      +

      +

      + +

      ffmpeg_duplicate_frames

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default:
      • +
      +

      +If the CPU can not keep up with the requested frame rate for the movies, should frames be +duplicated in order to keep up or should it be skipped. +

      +

      + +

      movie_filename

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: %v-%Y%m%d%H%M%S
      • +
      +

      +File path for motion triggered movies relative to target_dir. Note that the file +extension is automatically added to the name based upon the codec selected. +

      +You can use Conversion Specifiers in this option. +

      +

      + + +

      timelapse_filename

      +

      +
        +
      • Type: String
      • +
      • Range / Valid values: Max 4095 characters
      • +
      • Default: %v-%Y%m%d-timelapse
      • +
      +

      +File path for the timelapse movies relative to target_dir. Note that the file +extension is automatically added to the name based upon the codec selected. +

      +You can use Conversion Specifiers in this option. +

      +

      +
    + +

    Output - Pipe Options

    +
      + +

      +The video4linux driver is written by the same author that first created Motion. You can +find the source within apt packages. +

      +The video4linux device is a Kernel module which installs itself as a video pipe. +It has an input and an output. The module simply takes anything that comes on its input +and send it out at the output. The purpose of this is to create a standard video4linux type video +device that other programs can then use. You may now ask: "What do I need that for?". +

      +Only one program can access a video device at a time. When motion is using a camera - +no other program can access the same camera. But motion is made to be able to feed a video signal +to the video loopback device. This way an additional program can watch the signal from a camera that +motion uses already. What you see is not the live camera stream but the exact same picture that motion +uses for detecting motion and the same pictures that are saved/streamed. You can also choose to +see the "motion" type images where you see the pixels that are changing - live. +

      +When you install the video loopback device it will create an input - +for example /dev/video5 and an output - for example /dev/video6. You can then tell motion to "pipe" +the video signal to the /dev/video5 and look at the pictures live using e.g. Camstream on /dev/video6. +Camstream is "fooled" to think it is looking at a real camera. +

      Installing -

      +

      Installing the video loopback device is not difficult. At least not when you have this document available. -

      -First you must prepare your system for more video devices. You will need two extra devices for each video pipe that you want. -

      -For example if you have 4 cameras they will probably run at /dev/video0, /dev/video1, /dev/video2, and /dev/video3. So you will need additional 8 video devices. This is easy to do. -

      +

      +First you must prepare your system for more video devices. You will need two extra devices for each video +pipe that you want. +

      +For example if you have 4 cameras they will probably run at +/dev/video0, /dev/video1, /dev/video2, and /dev/video3. So you will need additional 8 video devices. +This is easy to do. +

       mknod /dev/video4 c 81 4
       mknod /dev/video5 c 81 5
      @@ -3446,97 +3419,926 @@ 

      video4linux loopback device . Place the file in a place of your own choice. -

      +

      +Download the latest via the apt packages and place the file in a place of your own choice. +

      Untar and uncompress the file to the place you want the program installed. Editor recommends /usr/local/vloopback. -

      +

      cd /usr/local -

      +

      tar -xvzf /path/to/vloopback-1.1-rc1.tar.gz -

      -You now have a directory called vloopback-1.1-rc1. You can rename it to vloopback (mv vloopback-1.1-rc1 vloopback). I recommend creating a symbolic link to the current version. This way you can more easily experiment with different versions simply by changing the link. -

      +

      +You now have a directory called vloopback-1.1-rc1. You can rename it to vloopback (mv vloopback-1.1-rc1 vloopback). +I recommend creating a symbolic link to the current version. This way you can more easily experiment with different +versions simply by changing the link. +

      ln -s vloopback-1.1-rc1 vloopback -

      +

      Now change to the new directory -

      +

      cd vloopback -

      +

      Build the code -

      +

      make -

      -There is a good chance that the make will not work and give you a long list of errors. To run make the following must be available on you machine.

        +

        +There is a good chance that the make will not work and give you a long list of errors. +To run make the following must be available on you machine.
        • The kernel source files must be installed. -
        • The source files must be available at /usr/src/linux.
          E.g. the new Red Hat 7.3 does not have a link to the sources called linux. Instead there is a link called linux-2.4. This is easy to fix. Just create a link to the real source tree. Do not rename! Add a link using this command (replacing the kernel version number with the one you have on your machine)
          ln -s /usr/src/linux-2.4.18-4 /usr/src/linux -
        • Alternatively you can change the vloopback makefile so that the "LINUXSRC=/usr/src/linux" line is changed to the actual path. I recommend the link solution since this may solve other similar problems that you can get when installing other software. -
        -

        -When compiling on a newer Linux distribution you may get a warning about a header file malloc.h. To remove this warning simply change the header reference as suggested by the warning. -

        +

      • The source files must be available at /usr/src/linux.
        E.g. +the new Red Hat 7.3 does not have a link to the sources called linux. Instead there is a link +called linux-2.4. This is easy to fix. Just create a link to the real source tree. Do not rename! +Add a link using this command (replacing the kernel version number with the one you have on your +machine)
        ln -s /usr/src/linux-2.4.18-4 /usr/src/linux +
      • Alternatively you can change the vloopback makefile so that the "LINUXSRC=/usr/src/linux" line is +changed to the actual path. I recommend the link solution since this may solve other similar problems that you +can get when installing other software. +
      +

      +When compiling on a newer Linux distribution you may get a warning about a header file malloc.h. +To remove this warning simply change the header reference as suggested by the warning. +

      In vloopback.c you replace the line -

      +

      #include <linux/malloc.h> -

      +

      with the line -

      +

      #include <linux/slab.h> -

      -Install the code you built as a Kernel module. There are two options: pipes should be set to the number of video loopbacks that you want. Probably one for each camera. The dev_offset defines which video device number will be the first. If dev_offset is not defined the vloopback module will install itself from the first available video device. If you want the cameras to be assigned to the lower video device numbers you must either load vloopback after loading the video device modules OR use the dev_offset option when loading vloopback. Vloopback then installs itself in the sequence input 0, output 0, input 1, output 1, input 2, output 2 etc. Here is shown the command for our example of 4 cameras and 4 loopback devices and the first loopback device offset to /dev/video4. -

      +

      +Install the code you built as a Kernel module. There are two options: +pipes should be set to the number of video loopbacks that you want. Probably one for each camera. +The dev_offset defines which video device number will be the first. If dev_offset is not defined the +vloopback module will install itself from the first available video device. If you want the cameras to be +assigned to the lower video device numbers you must either load vloopback after loading the video device +modules OR use the dev_offset option when loading vloopback. Vloopback then installs itself in the sequence +input 0, output 0, input 1, output 1, input 2, output 2 etc. Here is shown the command for our example of 4 +cameras and 4 loopback devices and the first loopback device offset to /dev/video4. +

      /sbin/insmod /usr/local/vloopback/vloopback.o pipes=4 dev_offset=4 -

      +

      When you run the command you may get a warning about tainting the Kernel. Just ignore this. You can choose to copy the vloopback.o file into a directory in the /lib/modules tree where the insmod/modprobe programs are already looking for modules. Then the command gets simpler (/sbin/insmod vloopback pipes=.....). -

      +

      If you want the loopback device to load during boot, you can place the call in one of the bootup scripts such as /etc/rc.d/rc.local. Vloopback should be loaded before you start motion. -

      +

      To activate the vloopback device in motion set the 'video_pipe' option in the motion.conf file. You can also view the special motion pictures where you see the changed pixels by setting the option 'motion_video_pipe' in motion.conf. When setting the video_pipe and/or motion_video_pipe options either specify the input device as e.g. /dev/video4. You can also set the parameter to '-' which means that motion will find the first vacant video loopback device input. If you have more than one camera you may want to control which loopback device each thread uses. Then you need to define the specific device name in motion.conf for the first camera and in each thread config file for the other cameras. If you set the video_pipe parameter to '-' in the motion.conf file and not setting it in the thread config files, motion automatically assign video devices in the same sequence as the threads are loaded. You can combine both video_pipe and motion_video_pipe but then naturally you will need twice as many pipes. -

      +

      De-activating should be done with this command -

      +

      /sbin/modprobe -r vloopback -

      -Description of the motion.conf options related to video loopback device. -

      -

      -

      motion_video_pipe

      -

        -
      • Type: String -
      • Range / Valid values: Max 4095 characters -
      • Default: Not defined -
      • Option Topic -
      -

      -The video4linux video loopback input device for motion images. If a particular pipe is to be used then use the device filename of this pipe, if a dash '-' is given motion will use /proc/video/vloopback/vloopbacks to locate a free pipe. Default: not set -

      -Using this you can view the results in real time. E.g. by using the program camstream. The difference between this option and the video-pipe option is that this option shows the motion version of the images instead of the normal images. -

      -Disable this option by not having it in the config file (or comment it out with "#" or ";"). -

      -

      +

      +

      + + +

      video_pipe

      -

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default:
        • +
        +

        +if a dash '-' is given motion will use /proc/video/vloopback/vloopbacks to locate a free pipe. Default: not set +The video4linux video loopback input device for normal images. If a particular pipe is to be used then use the +device filename of this pipe. If a dash '-' is given motion will use /proc/video/vloopback/vloopbacks to locate +a free pipe. +

        +

        + +

        motion_video_pipe

        +

        • Type: String
        • Range / Valid values: Max 4095 characters
        • Default: Not defined -
        • Option Topic
        -

        -The video4linux video loopback input device for normal images. If a particular pipe is to be used then use the device filename of this pipe. If a dash '-' is given motion will use /proc/video/vloopback/vloopbacks to locate a free pipe. -

        -Using this you can view the results in real time. E.g. by using the program camstream. -

        -Disable this option by not having it in the config file (or comment it out with "#" or ";"). -

        -

        -

        -

        --- KennethLavrsen - 13 Apr 2005 \ No newline at end of file +

        +The video4linux video loopback input device for motion images. +If a particular pipe is to be used then use the device filename of this pipe, +if a dash '-' is given motion will use /proc/video/vloopback/vloopbacks to locate a free pipe. Default: not set +

        +

        + +

        use_extpipe

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default:
        • +
        +

        +This option specifies whether to send the output to a +pipe for external encoding into a movie. +

        +Piping raw video to stdout has some advantages comparing to using built-in ffmpeg encoder. +First, this way you can use any encoder that supports RAW frames from stdin so you are not limited to the formats +that are currently implemented in motion. See examples in extpipe +Second, external encoder utilizes separate cpu core on a multi-core system so movie encoding is offloaded +from main motion thread to a separate core(s) giving noticeable performance boost +

        +Note that this option does not require the install or configure of the videoloop back +

        +

        + + +

        extpipe

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default:
        • +
        +

        +This option specifies the program name and options for the +program that will receive and process the images during a movie event. +

        +Note that this option does not require the install or configure of the videoloop back +

        +Sample: +

        +extpipe mencoder -demuxer rawvideo -rawvideo w=%w:h=%h:i420 -ovc x264 -x264encopts bframes=4:frameref=1:subq=1:scenecut=-1:nob_adapt:threads=1:keyint=1000:8x8dct:vbv_bufsize=4000:crf=24:partitions=i8x8,i4x4:vbv_maxrate=800:no-chroma-me -vf denoise3d=16:12:48:4,pp=lb -of avi -o %f.avi - -fps %fps +

        +extpipe x264 - --input-res %wx%h --fps %fps --bitrate 2000 --preset ultrafast --quiet -o %f.mp4 +

        +extpipe mencoder -demuxer rawvideo -rawvideo w=%w:h=%h:fps=%fps -ovc x264 -x264encopts preset=ultrafast -of lavf -o %f.mp4 - -fps %fps +

        +extpipe ffmpeg -y -f rawvideo -pix_fmt yuv420p -video_size %wx%h -framerate %fps -i pipe:0 -vcodec libx264 -preset ultrafast -f mp4 %f.mp4 +

        +

        + + +
      + +

      Steam and Webcontrol

      +
        + +Motion has simple webcam server built in. The server can be configured to +stream both the images as well allow for a very basic http control of these Motion parameters. +

        +Each thread can have its own stream and it is enabled by specifying +the port number. If there are multiple cameras, each camera must have +its own unique port number. +

        +The webserver generates a stream in "multipart jpeg" format (mjpeg). Some browsers can not display +images fed in this method. Alternatives are being considered for implementation within Motion to resolve +this limitation. The most straight forward around this limitation is to create a local +HTML page that references the raw stream. + +

        +Open up a text editor and paste in the following. + +<html> +<body bgcolor=000000> +<img src=http://yourmotionpc:yourstreamport/ border="0" width=25%></a> +</body> +</html> + +

        +Change the yourmotionpc with the IP or name of the computer running Motion. Also revise the port +number to be the one referenced for the stream. +

        +Save the file and then open it in your browser. +

        +

        +It may also be possible to view the stream via regular stream players such as VLC, mplayer, ffplay, avplay, etc. +by specifying the network stream as + +http://localhost:myportnumber/stream.mjpg + +

        +

        + +

        +Motion can be remote controlled via a simple http interface. +

        +Most Motion configuration options can be changed while Motion is running except +options related to the size of the captured images and mask files which +are loaded only when Motion starts. +

        +The most obvious tool to use to remote control Motion is any web browser. +All commands are sent using the http GET method which simply means that the information is +sent via the URL and maybe a query string. You can use any browser (Firefox, Mozilla, Internet Explorer +, etc). You can also use the text based browser lynx to control Motion from a console. +It navigates fine through the very simple and minimalistic http control interface of Motion. +

        +

        +But it is probably simpler to connect to the control port with a browser, navigate to the function +you want, and copy the URL from the browser URL entry line. +If your webcontrol_port is 8080 and you browse from the same machine +on which Motion runs simply look up +http://localhost:8080/ and navigate around. +Connecting from a remote machine is done by using a domain name (example + http://mydomain.com:8080/) or the + IP address of the machine (example + http://192.168.1.4:8080/). + The option webcontrol_localhost must be off to allow connection from a remote machine. +

        +If you want to use a script or cron to automatically change Motion settings while Motion runs you use a +program that can fetch a webpage. We simply just throw away the html page that Motion returns. Programs +commonly available on Linux machines are wget and lwp-request. Here is an example of how to start and +stop motion detection via cron. These two lines are added to /etc/crontab. +

        +
        +0 9 * * * root /usr/bin/lwp-request http://localhost:8080/0/detection/start > /dev/null
        +0 18 * * * root /usr/bin/lwp-request http://localhost:8080/0/detection/pause > /dev/null
        +
        +

        +If you want to use the http remote control from your own software (for example your own PHP front end) +you can set the new motion.conf option html_output off. Then Motion answers back with very basic text +only and no html around it. +

        +To remote control Motion from a web pages you can for example use PHP. +In PHP it takes this simple code line to send a remote commend to Motion. +Here we pause motion detection for camera 2 +

        +readfile('http://localhost:8080/2/detection/pause'); +

        + +

        +ALERT! Security Warning! This feature also means you have to pay attention +to the following. +
          +
        • Anyone with access to the remote control port (http) can alter the values of any options + and save files anywhere on your server with the same privileges as the user running Motion. + They can execute any command on your computer with the same privileges as the user running Motion. + Anyone can access your control port if you have not either limited access to localhost or limited + access using firewalls in the server. You should always have a router between a machine running + Motion with remote control enabled and the Internet and make sure the Motion control port is not + accessible from the outside.
        • +
        • If you limit control port to localhost you still need to take care of any user logging + into the server with any kind of terminal session.
        • +
        • Run Motion as a harmless user. DO NOT RUN AS ROOT!!
        • +
        + +

        +

        + +

        ipv6_enabled

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default:
        • +
        +

        +# Enable or disable IPV6 for http control and stream (default: off ) +

        + +

        stream_port

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 65535
        • +
        • Default: 0 (disabled)
        • +
        +

        +# The mini-http server listens to this port for requests (default: 0 = disabled) +TCP port on which motion will listen for incoming connects with its webcam server. +Note that each camera thread must have its own unique port number and it must also be different from the control_port number. +A good value to select is 8081 for camera 1, 8082 for camera 2, 8083 for camera 3 etc etc. + +This must be placed in motion.conf and not in a thread config file. + +

        + +

        stream_quality

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 1 - 100
        • +
        • Default: 50
        • +
        +

        +Quality setting in percent for the mjpeg picture frames transferred over the webcam connection. Keep it low to restrict needed bandwidth. +The mjpeg stream consists of a header followed by jpeg frames separated by content-length and boundary string. The quality level defines the size of the individual jpeg pictures in the mjpeg stream. If you set it too high you need quite a high bandwidth to view the stream. + +

        + +

        stream_motion

        +

        +
          +
        • Type: Boolean
        • +
        • Range / Valid values: on, off
        • +
        • Default: off
        • +
        +

        +When set to 'on' slow down the stream to 1 picture per second when no motion is detected. +When motion is detected the stream runs as defined by stream_maxrate +When 'off' the stream always runs as defined by stream_maxrate. +Use this option to save bandwidth when there is not anything important to see from the camera anyway. +

        + +

        stream_maxrate

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 1 - 100
        • +
        • Default: 1
        • +
        +

        +Limit the framerate of the stream in frames per second. Set the value to 100 for practically unlimited. +Don't set this parameter too high unless you only use it on the localhost or on an internal LAN. +

        + +

        stream_localhost

        +

        +
          +
        • Type: Boolean
        • +
        • Range / Valid values: on, off
        • +
        • Default: on
        • +
        +

        +Limits the access to the stream to the localhost. +By setting this to on, the stream can only be accessed on the same machine on which Motion is running. +

        + +

        stream_limit

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default:
        • +
        +

        +This parameter limits the maximum number of images per connection and is +determined by multiplying actual stream rate by desired number of seconds +

        + +

        stream_auth_method

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 to 2
        • +
        • Default: 0
        • +
        +

        +This parameter establishes desired authentication method for the stream and +web control ports. The parameters have the following meaning. +
          +
        • 0 = disabled
        • +
        • 1 = Basic authentication
        • +
        • 2 = MD5 digest (the safer authentication)
        • +
        +

        +Note that if you are enabling the webcontrol feature of Motion, you really really really ... should +enable security authentications. No. Seriously. You really should. See the security warnings in this +document regarding how it completely opens up your system. +

        + + +

        stream_authentication

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default: Not Defined
        • +
        +

        +This parameter establishes the username and password to use for the stream. +The syntax is username:password +

        + +

        stream_preview_scale

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values:
        • +
        • Default: 25
        • +
        +

        +If the webcontrol page has HTML enabled, Motion displays all of the streams on the home webcontrol page in HTML +format so that all the images can be viewed by standard browsers. +

        +This parameter indicates the percentage to scale the stream image when it is placed on the page. +Numbers greater than 100 are permitted. +

        +

        + +

        stream_preview_newline

        +

        +
          +
        • Type: string
        • +
        • Range / Valid values:on / off
        • +
        • Default: on
        • +
        +

        +If the webcontrol page has HTML enabled, Motion displays all of the streams on the home webcontrol page +in HTML format so that all the images can be viewed by standard browsers. +

        +This parameter determines whether the image is placed on a new line in the webcontrol web page. +

        +Preview images are placed on to the webcontrol home page in thread number order. This +This parameter allows the user some flexibility in organizing the images on the page. +

        +Setting this parameter to off will set the image to the right of any image from a lower numbered thread. +Setting it to 'on' will place the image on the start of the next line(below). +

        +Full customization of the webcontrol page is NOT planned in the Motion development. Users that require +a more polished and customized preview page are encouraged to create their own local HTML page that references +the streams. +

        + +

        webcontrol_port

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 65535
        • +
        • Default: 0 (disabled)
        • +
        +

        +Sets the port number for the http based control of the Motion parameters. +This option must be placed in the motion.conf file and not in a thread config file. +Port numbers below 1024 normally require that you have root privileges. +The port 8080 is the typical selection of the port for this purpose. +

        + +

        webcontrol_localhost

        +

        +
          +
        • Type: Boolean
        • +
        • Range / Valid values: on, off
        • +
        • Default: on
        • +
        +

        +This option restricts the control of the Motion parameters to the localhost. +This option must be placed in motion.conf and not in a thread config file. +By setting this to on, the control using http (browser) can only be accessed on the +same machine on which Motion is running. +

        + +

        webcontrol_html_output

        +

        +
          +
        • Type: Boolean
        • +
        • Range / Valid values: on, off
        • +
        • Default: on
        • +
        +

        +Enable HTML in the answer sent back to a browser connecting to the webcontrol_port. +This option must be placed in motion.conf and not in a thread config file. +The recommended value for most is "on" which means that you can navigate and control +Motion with a normal browser. By setting this option to "off" the replies are in plain +text which may be easier to parse for 3rd party programs that control Motion. +

        + +

        webcontrol_authentication

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default:
        • +
        +

        +This parameter establishes the username and password to use for the stream. +The syntax is username:password +

        +

        +
      + +

      Database

      +
        + +Motion can be compiled with MySQL, PostgreSQL or SQLite3 database support. +When enabled Motion can be configured to add a record to a table in the database +as specified by the sql_query. The query can contain the fields that are used and the +value are given by using conversion specifiers for dynamic data like +filename, time, number of detected pixels etc. +Motion does not place any binary images in the database and it cannot remove old records. +

        +Motion only adds records to the database when files are created. +The database contains records of saved files which means to get a +record in the database the feature that enables for example motion +detection, timelapse, snapshots etc must be enabled. +The sql_log options defines which types of files are logged in the database. +

        +The following are sample create table queries for different databases. +

        +Mysql : CREATE TABLE security (camera int, filename char(80) not null, frame int, file_type int, time_stamp timestamp(14), event_time_stamp timestamp(14)); +

        +Postgresql : CREATE TABLE security (camera int, filename char(80) not null, frame int, file_type int, time_stamp timestamp without time zone, event_time_stamp timestamp without time zone); +

        + + +

        +

        sql_log_picture

        +

        +
          +
        • Type: Boolean
        • +
        • Range / Valid values: on, off
        • +
        • Default: on
        • +
        +

        +Log to the database when a motion triggered image file is created. +

        + +

        sql_log_snapshot

        +

        +
          +
        • Type: Boolean
        • +
        • Range / Valid values: on, off
        • +
        • Default: on
        • +
        +

        +Log to the database when creating a snapshot image file. +

        + +

        sql_log_movie

        +

        +
          +
        • Type: Boolean
        • +
        • Range / Valid values: on, off
        • +
        • Default: off
        • +
        +

        +Log to the database when creating motion triggered movie file. +

        + +

        sql_log_timelapse

        +

        +
          +
        • Type: Boolean
        • +
        • Range / Valid values: on, off
        • +
        • Default: off
        • +
        +

        +Log to the database when creating timelapse movie file +

        + +

        sql_query

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default: Not Defined
        • +
        +

        +SQL query string that is sent to the database when the sql_log_* item is triggered. +

        +

        +You can use Conversion Specifiers +within the query. +

        +

        +Sample Query +

        +insert into security(camera, filename, frame, file_type, time_stamp, text_event) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C') +insert or ignore into images (camera_nbr, file_name, year, month, day, hour, minute) values (8, '%f', '%Y','%m','%d','%H','%M') +

        +

        + +

        database_type

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: mysql, postgresql, sqlite3
        • +
        • Default: Not Defined
        • +
        +

        +This option specifies the database type. +

        + +

        database_dbname

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default: Not Defined
        • +
        +

        +The name of the database. For Sqlite3, the full path and name to the database. +

        + +

        database_host

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default: localhost
        • +
        +

        +The host on which the database is located +

        + +

        database_user

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default:
        • +
        +

        +The user account name for database +

        + +

        database_password

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default:
        • +
        +

        +The user password for database +

        + +

        database_port

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values:
        • +
        • Default:
        • +
        +

        +The port number that is used for the database. Typical values are: mysql=3306 and postgresql=5432 +

        + + +

        database_busy_timeout

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values:
        • +
        • Default: 0
        • +
        +

        +If the database is busy when the request is issued, this parameter indicates the time to +wait before issuing a timeout message. +

        +

        + +
      + +

      Tracking

      +
        + +

        +This is still at the experimental stage. +

        +Motion can move the camera to a fixed position given in degrees pan (left-right) and tilt (down-up). +Movement can be set with absolute coordinates or relative to current position. There is also an auto tracking +feature for the Logitech Quickcam Sphere/Orbit but it is not very mature. Search the Motion home website +or community development pages for additional information regarding tracking if these features are required. +

        +

        + + +

        +

        track_type

        +

        +
          +
        • Type: Discrete Strings
        • +
        • Range / Valid values: 0 (none), 1 (stepper), 2 (iomojo), 3 (pwc), 4 (generic), 5 (uvcvideo)
        • +
        • Default: 0 (None)
        • +
        +

        +Type of tracker. +

        +Motion has special tracking options which use either a serial stepper motor controller, +an iomojo smile cam or a Philips WebCam driver compatible pan/tilt camera such as +the Logitech Quickcam Sphere or Orbit. +

        +To disable tracking, set this to 0 and the other track options are ignored. +

        +Value 1 is for the special Motion Tracking project using a stepper motor and a home made controller. +

        +Value 2 is for the iomojo smilecam +

        +Value 3 is for pwc type USB tracking cameras such as the Logitech Quickcam Sphere/Orbit which is driven +by the pwc (Philips WebCam) driver. To use this camera your version of pwc must be at least 8.12. +

        +Value 4 is the generic track type. Currently it has no other function than enabling some of the +internal Motion features related to tracking. +

        +Value 5 is for uvcvideo type USB tracking cameras such as the Logitech Quickcam Sphere/Orbit MP which is driven +by the uvcvideo driver. +

        + +

        + +

        track_auto

        +

        +
          +
        • Type: Boolean
        • +
        • Range / Valid values: on, off
        • +
        • Default: off
        • +
        +

        +Enable auto tracking +Requires a tracking camera type supported by Motion. +

        + +

        track_port

        +

        +
          +
        • Type: String
        • +
        • Range / Valid values: Max 4095 characters
        • +
        • Default:
        • +
        +

        +This is the device name of the serial port to which the stepper motor interface is connected. +Only used for stepper motor tracking. +

        + +

        track_motorx

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        +The motor number that is used for controlling the x-axis. +Only used for stepper motor tracking. +

        + +

        track_motorx_reverse

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        +Description +

        + +

        track_motory

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        +The motor number that is used for controlling the y-axis. +Only used for stepper motor tracking. +

        + +

        track_motory_reverse

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        + +

        + +

        track_maxx

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        +The maximum position for servo x. +Only used for stepper motor tracking. +

        + +

        track_minx

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        + +

        + +

        track_maxy

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        +The maximum position for servo y. +Only used for stepper motor tracking. +

        + +

        track_miny

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        + +

        + +

        track_homex

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        + +

        + +

        track_homey

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        + +

        + +

        track_iomojo_id

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        +Use this option if you have an iomojo smilecam connected to the serial port instead +of a general stepper motor controller. +Only used for iomojo camera. +

        + +

        track_step_angle_x

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        +Angle in degrees the camera moves per step on the X-axis with auto tracking. Currently only used with pwc type cameras. +Requires a tracking camera type pwc. + +

        + +

        track_step_angle_y

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        +Angle in degrees the camera moves per step on the Y-axis with auto tracking. Currently only used with pwc type cameras. +Requires a tracking camera type pwc. +

        +

        + +

        track_move_wait

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        +Delay during which tracking is disabled after auto tracking has moved the camera. +Delay is defined as number of picture frames. +The actual delay is depending on the chosen framerate. +If you want the camera to move maximum once every 2 seconds and the framerate is 10 then you +need to set the track_move_wait value to 2 * 10 = 20. +

        + +

        track_speed

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        +Speed to set the motor to. +Only used for stepper motor tracking. + +

        + +

        track_stepsize

        +

        +
          +
        • Type: Integer
        • +
        • Range / Valid values: 0 - 2147483647
        • +
        • Default: 0
        • +
        +

        +Number of steps to make. +Only used for stepper motor tracking. +

        +
      + +
    diff --git a/netcam.c b/netcam.c index e327a2f..bf63200 100644 --- a/netcam.c +++ b/netcam.c @@ -45,9 +45,7 @@ #include #include "netcam_ftp.h" -#ifdef have_av_get_media_type_string #include "netcam_rtsp.h" -#endif #define CONNECT_TIMEOUT 10 /* Timeout on remote connection attempt */ #define READ_TIMEOUT 5 /* Default timeout on recv requests */ @@ -123,7 +121,7 @@ static char *netcam_url_match(regmatch_t m, const char *input) if (m.rm_so != -1) { len = m.rm_eo - m.rm_so; - if ((match = (char *) mymalloc(len + 1)) != NULL) { + if ((match = mymalloc(len + 1)) != NULL) { strncpy(match, input + m.rm_so, len); match[len] = '\0'; } @@ -149,13 +147,9 @@ static void netcam_url_parse(struct url_t *parse_url, const char *text_url) { char *s; int i; -#ifdef have_av_get_media_type_string - const char *re = "(http|ftp|mjpg|rtsp)://(((.*):(.*))@)?" - "([^/:]|[-.a-z0-9]+)(:([0-9]+))?($|(/[^:]*))"; -#else - const char *re = "(http|ftp|mjpg)://(((.*):(.*))@)?" - "([^/:]|[-.a-z0-9]+)(:([0-9]+))?($|(/[^:]*))"; -#endif + + const char *re = "(http|ftp|mjpg|mjpeg|rtsp)://(((.*):(.*))@)?" + "([^/:]|[-.a-z0-9]+)(:([0-9]+))?($|(/[^*]*))"; regex_t pattbuf; regmatch_t matches[10]; @@ -211,10 +205,8 @@ static void netcam_url_parse(struct url_t *parse_url, const char *text_url) parse_url->port = 80; else if (!strcmp(parse_url->service, "ftp")) parse_url->port = 21; -#ifdef have_av_get_media_type_string else if (!strcmp(parse_url->service, "rtsp") && parse_url->port == 0) parse_url->port = 554; -#endif } regfree(&pattbuf); @@ -232,27 +224,19 @@ static void netcam_url_parse(struct url_t *parse_url, const char *text_url) * Returns: Nothing * */ -static void netcam_url_free(struct url_t *parse_url) +void netcam_url_free(struct url_t *parse_url) { - if (parse_url->service) { - free(parse_url->service); - parse_url->service = NULL; - } + free(parse_url->service); + parse_url->service = NULL; - if (parse_url->userpass) { - free(parse_url->userpass); - parse_url->userpass = NULL; - } + free(parse_url->userpass); + parse_url->userpass = NULL; - if (parse_url->host) { - free(parse_url->host); - parse_url->host = NULL; - } + free(parse_url->host); + parse_url->host = NULL; - if (parse_url->path) { - free(parse_url->path); - parse_url->path = NULL; - } + free(parse_url->path); + parse_url->path = NULL; } /** @@ -341,8 +325,7 @@ static int netcam_check_keepalive(char *header) return -1; /* We do not detect the second field or other case mixes at present. */ - if (content_type) - free(content_type); + free(content_type); return 1; } @@ -372,8 +355,7 @@ static int netcam_check_close(char *header) if (!strcmp(type, "close")) /* strcmp returns 0 for match. */ ret = 1; - if (type) - free(type); + free(type); return ret; } @@ -417,8 +399,7 @@ static int netcam_check_content_type(char *header) ret = 0; } - if (content_type) - free(content_type); + free(content_type); return ret; } @@ -660,8 +641,7 @@ static int netcam_read_first_header(netcam_context_ptr netcam) if ((boundary = strstr(header, "boundary="))) { /* On error recovery this may already be set. */ - if (netcam->boundary) - free(netcam->boundary); + free(netcam->boundary); netcam->boundary = mystrdup(boundary + 9); /* @@ -1150,7 +1130,7 @@ static int netcam_read_html_jpeg(netcam_context_ptr netcam) if (buffer->content_length != 0) remaining = buffer->content_length; else - remaining = 999999; + remaining = 9999999; /* Now read in the data. */ while (remaining) { @@ -1270,7 +1250,7 @@ static int netcam_read_html_jpeg(netcam_context_ptr netcam) * module netcam_wget.c to do this job! */ - MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, + MOTION_LOG(DBG, TYPE_NETCAM, NO_ERRNO, "%s: Potential split boundary - " "%d chars flushed, %d " "re-positioned", ix, @@ -1325,6 +1305,11 @@ static int netcam_read_html_jpeg(netcam_context_ptr netcam) MOTION_LOG(WRN, TYPE_NETCAM, SHOW_ERRNO, "%s: gettimeofday"); netcam->receiving->image_time = curtime; + + /* Fix starting of JPEG if needed , some cameras introduce thrash before + * SOI 0xFFD8 Start Of Image + */ + netcam_fix_jpeg_header(netcam); /* * Calculate our "running average" time for this netcam's @@ -1851,15 +1836,8 @@ static int netcam_read_file_jpeg(netcam_context_ptr netcam) tfile_context *file_new_context(void) { - tfile_context *ret; - /* Note that mymalloc will exit on any problem. */ - ret = mymalloc(sizeof(tfile_context)); - if (!ret) - return ret; - - memset(ret, 0, sizeof(tfile_context)); - return ret; + return mymalloc(sizeof(tfile_context)); } void file_free_context(tfile_context* ctxt) @@ -1867,9 +1845,7 @@ void file_free_context(tfile_context* ctxt) if (ctxt == NULL) return; - if (ctxt->path != NULL) - free(ctxt->path); - + free(ctxt->path); free(ctxt); } @@ -1917,6 +1893,17 @@ static void *netcam_handler_loop(void *arg) netcam_context_ptr netcam = arg; struct context *cnt = netcam->cnt; /* Needed for the SETUP macro :-( */ +#ifdef HAVE_PTHREAD_SETNAME_NP + { + char tname[16]; + snprintf(tname, sizeof(tname), "nc%d%s%s", + cnt->threadnr, + cnt->conf.camera_name ? ":" : "", + cnt->conf.camera_name ? cnt->conf.camera_name : ""); + pthread_setname_np(pthread_self(), tname); + } +#endif + /* Store the corresponding motion thread number in TLS also for this * thread (necessary for 'MOTION_LOG' to function properly). */ @@ -2017,17 +2004,42 @@ static void *netcam_handler_loop(void *arg) */ } } - if (netcam->get_image(netcam) < 0) { - MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Error getting jpeg image"); - /* If FTP connection, attempt to re-connect to server. */ - if (netcam->ftp) { - close(netcam->ftp->control_file_desc); - if (ftp_connect(netcam) < 0) - MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Trying to re-connect"); - + + if (netcam->caps.streaming == NCS_RTSP) { + if (netcam->rtsp->format_context == NULL) { // We must have disconnected. Try to reconnect + if (netcam->rtsp->status == RTSP_CONNECTED){ + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Reconnecting with camera...."); + } + netcam->rtsp->status = RTSP_RECONNECTING; + netcam_connect_rtsp(netcam); + continue; + } else { + // We think we are connected... + if (netcam->get_image(netcam) < 0) { + if (netcam->rtsp->status == RTSP_CONNECTED){ + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Bad image. Reconnecting with camera...."); + } + //Nope. We are not or got bad image. Reconnect + netcam->rtsp->status = RTSP_RECONNECTING; + netcam_connect_rtsp(netcam); + continue; + } + } + } + + if (netcam->caps.streaming != NCS_RTSP) { + if (netcam->get_image(netcam) < 0) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Error getting jpeg image"); + /* If FTP connection, attempt to re-connect to server. */ + if (netcam->ftp) { + close(netcam->ftp->control_file_desc); + if (ftp_connect(netcam) < 0) + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Trying to re-connect"); + } + continue; } - continue; } + /* * FIXME * Need to check whether the image was received / decoded @@ -2111,8 +2123,7 @@ static int netcam_http_build_url(netcam_context_ptr netcam, struct url_t *url) int ix; /* First the http context structure. */ - netcam->response = (struct rbuf *) mymalloc(sizeof(struct rbuf)); - memset(netcam->response, 0, sizeof(struct rbuf)); + netcam->response = mymalloc(sizeof(struct rbuf)); MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO, "%s: Netcam has flags:" " HTTP/1.0: %s HTTP/1.1: %s Keep-Alive %s.", @@ -2186,10 +2197,14 @@ static int netcam_http_build_url(netcam_context_ptr netcam, struct url_t *url) * Allocate space for a working string to contain the path. * The extra 4 is for "://" and string terminator. */ - ptr = mymalloc(strlen(url->service) + strlen(url->host) - + strlen(url->path) + 4); - sprintf((char *)ptr, "http://%s%s", url->host, url->path); - + if (url->port != 0) { + ptr = mymalloc(strlen(url->service) + strlen(url->host) + 7 + strlen(url->path) + 4); + sprintf((char *)ptr, "http://%s:%d%s", url->host, url->port , url->path); + }else { + ptr = mymalloc(strlen(url->service) + strlen(url->host) + strlen(url->path) + 4); + sprintf((char *)ptr, "http://%s%s", url->host, url->path); + } + netcam->connect_keepalive = FALSE; /* Disable Keepalive if proxy */ free((void *)netcam->cnt->conf.netcam_keepalive); netcam->cnt->conf.netcam_keepalive = strdup("off"); @@ -2371,7 +2386,12 @@ static int netcam_setup_ftp(netcam_context_ptr netcam, struct url_t *url) * ownership" of the string away from the URL (i.e. it won't be freed * when we cleanup the url structure later). */ - netcam->ftp->path = url->path; + if (strcmp(url->path,"/")){ + netcam->ftp->path = mystrdup(url->path + 1); + } else { + netcam->ftp->path = mystrdup(url->path); + } + url->path = NULL; if (cnt->conf.netcam_userpass != NULL) { @@ -2400,6 +2420,7 @@ static int netcam_setup_ftp(netcam_context_ptr netcam, struct url_t *url) */ if (ftp_connect(netcam) < 0) { ftp_free_context(netcam->ftp); + netcam->ftp = NULL; return -1; } @@ -2413,71 +2434,6 @@ static int netcam_setup_ftp(netcam_context_ptr netcam, struct url_t *url) return 0; } -#ifdef have_av_get_media_type_string -static int netcam_setup_rtsp(netcam_context_ptr netcam, struct url_t *url) -{ - struct context *cnt = netcam->cnt; - const char *ptr; - - netcam->caps.streaming = NCS_RTSP; - netcam->rtsp = rtsp_new_context(); - - if (netcam->rtsp == NULL) { - MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: unable to create rtsp context"); - return -1; - } - - /* - * Allocate space for a working string to contain the path. - * The extra 5 is for "://", ":" and string terminator. - */ - - // force port to a sane value - if (netcam->connect_port > 65536) { - netcam->connect_port = 65536; - } else if (netcam->connect_port < 0) { - netcam->connect_port = 0; - } - - ptr = mymalloc(strlen(url->service) + strlen(netcam->connect_host) - + 5 + strlen(url->path) + 5); - sprintf((char *)ptr, "%s://%s:%d%s", url->service, - netcam->connect_host, netcam->connect_port, url->path); - - netcam->rtsp->path = (char *)ptr; - - if (cnt->conf.netcam_userpass != NULL) { - ptr = cnt->conf.netcam_userpass; - } else { - ptr = url->userpass; /* Don't set this one NULL, gets freed. */ - } - - if (ptr != NULL) { - char *cptr; - - if ((cptr = strchr(ptr, ':')) == NULL) { - netcam->rtsp->user = mystrdup(ptr); - } else { - netcam->rtsp->user = mymalloc((cptr - ptr)); - memcpy(netcam->rtsp->user, ptr,(cptr - ptr)); - netcam->rtsp->pass = mystrdup(cptr + 1); - } - } - - netcam_url_free(url); - - /* - * The RTSP context should be all ready to attempt a connection with - * the server, so we try .... - */ - rtsp_connect(netcam); - - netcam->get_image = netcam_read_rtsp_image; - - return 0; -} -#endif - /** * netcam_recv * @@ -2617,46 +2573,37 @@ void netcam_cleanup(netcam_context_ptr netcam, int init_retry_flag) pthread_mutex_unlock(&netcam->mutex); /* and cleanup the rest of the netcam_context structure. */ - if (netcam->connect_host != NULL) - free(netcam->connect_host); - - if (netcam->connect_request != NULL) - free(netcam->connect_request); - - - if (netcam->boundary != NULL) - free(netcam->boundary); + free(netcam->connect_host); + free(netcam->connect_request); + free(netcam->boundary); if (netcam->latest != NULL) { - if (netcam->latest->ptr != NULL) - free(netcam->latest->ptr); - + free(netcam->latest->ptr); free(netcam->latest); } if (netcam->receiving != NULL) { - if (netcam->receiving->ptr != NULL) - free(netcam->receiving->ptr); - + free(netcam->receiving->ptr); free(netcam->receiving); } if (netcam->jpegbuf != NULL) { - if (netcam->jpegbuf->ptr != NULL) - free(netcam->jpegbuf->ptr); - + free(netcam->jpegbuf->ptr); free(netcam->jpegbuf); } - if (netcam->ftp != NULL) + if (netcam->ftp != NULL) { ftp_free_context(netcam->ftp); - else + netcam->ftp = NULL; + } else { netcam_disconnect(netcam); + } + free(netcam->response); - if (netcam->response != NULL) - free(netcam->response); + if (netcam->caps.streaming == NCS_RTSP) + netcam_shutdown_rtsp(netcam); pthread_mutex_destroy(&netcam->mutex); pthread_cond_destroy(&netcam->cap_cond); @@ -2709,7 +2656,13 @@ int netcam_next(struct context *cnt, unsigned char *image) } if (netcam->caps.streaming == NCS_RTSP) { - memcpy(image, netcam->latest->ptr, netcam->latest->used); + + if (netcam->rtsp->status == RTSP_RECONNECTING) + return NETCAM_NOTHING_NEW_ERROR; + + if (netcam_next_rtsp(image , netcam) < 0) + return NETCAM_GENERAL_ERROR | NETCAM_JPEG_CONV_ERROR; + return 0; } @@ -2741,7 +2694,7 @@ int netcam_next(struct context *cnt, unsigned char *image) * * Returns: 0 on success * -1 on any failure - * -3 image dimensions are not modulo 16 + * -3 image dimensions are not modulo 8 */ int netcam_start(struct context *cnt) @@ -2759,9 +2712,7 @@ int netcam_start(struct context *cnt) * Create a new netcam_context for this camera * and clear all the entries. */ - cnt->netcam = (struct netcam_context *) - mymalloc(sizeof(struct netcam_context)); - memset(cnt->netcam, 0, sizeof(struct netcam_context)); + cnt->netcam = mymalloc(sizeof(struct netcam_context)); netcam = cnt->netcam; /* Just for clarity in remaining code. */ netcam->cnt = cnt; /* Fill in the "parent" info. */ @@ -2772,15 +2723,12 @@ int netcam_start(struct context *cnt) /* Our image buffers */ netcam->receiving = mymalloc(sizeof(netcam_buff)); - memset(netcam->receiving, 0, sizeof(netcam_buff)); netcam->receiving->ptr = mymalloc(NETCAM_BUFFSIZE); netcam->jpegbuf = mymalloc(sizeof(netcam_buff)); - memset(netcam->jpegbuf, 0, sizeof(netcam_buff)); netcam->jpegbuf->ptr = mymalloc(NETCAM_BUFFSIZE); netcam->latest = mymalloc(sizeof(netcam_buff)); - memset(netcam->latest, 0, sizeof(netcam_buff)); netcam->latest->ptr = mymalloc(NETCAM_BUFFSIZE); netcam->timeout.tv_sec = READ_TIMEOUT; @@ -2890,16 +2838,20 @@ int netcam_start(struct context *cnt) strcpy(url.service, "http"); /* Put back a real URL service. */ retval = netcam_setup_mjpg(netcam, &url); -#ifdef have_av_get_media_type_string + } else if ((url.service) && (!strcmp(url.service, "mjpeg"))) { + MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO, "%s: now calling" + " netcam_setup_mjpeg()"); + + strcpy(url.service, "http"); /* Put back a real URL service. */ + retval = netcam_setup_rtsp(netcam, &url); } else if ((url.service) && (!strcmp(url.service, "rtsp"))) { MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO, "%s: now calling" " netcam_setup_rtsp()"); retval = netcam_setup_rtsp(netcam, &url); -#endif } else { MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: Invalid netcam service '%s' - " - "must be http, ftp, mjpg or file.", url.service); + "must be http, ftp, mjpg, mjpeg or file.", url.service); netcam_url_free(&url); return -1; } @@ -2917,12 +2869,14 @@ int netcam_start(struct context *cnt) if ((retval = netcam->get_image(netcam)) != 0) { MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: Failed trying to " "read first image - retval:%d", retval); + if (netcam->caps.streaming == NCS_RTSP) + netcam->rtsp->status = RTSP_NOTCONNECTED; return -1; } -#ifdef have_av_get_media_type_string + if (netcam->caps.streaming != NCS_RTSP) { -#endif + /* * If an error occurs in the JPEG decompression which follows this, * jpeglib will return to the code within this 'if'. If such an error @@ -2937,29 +2891,23 @@ int netcam_start(struct context *cnt) netcam->netcam_tolerant_check = cnt->conf.netcam_tolerant_check; netcam->JFIF_marker = 0; netcam_get_dimensions(netcam); + } + /* + * Motion currently requires that image height and width is a + * multiple of 8. So we check for this. + */ + if (netcam->width % 8) { + MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: netcam image width (%d)" + " is not modulo 8", netcam->width); + return -2; + } - /* - * Motion currently requires that image height and width is a - * multiple of 16. So we check for this. - */ - if (netcam->width % 8) { - MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: netcam image width (%d)" - " is not modulo 8", netcam->width); - return -3; - } - - if (netcam->height % 8) { - MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: netcam image height (%d)" - " is not modulo 8", netcam->height); - return -3; - } -#ifdef have_av_get_media_type_string - } else { - // not jpeg, get the dimensions - netcam->width = netcam->rtsp->codec_context->width; - netcam->height = netcam->rtsp->codec_context->height; + if (netcam->height % 8) { + MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: netcam image height (%d)" + " is not modulo 8", netcam->height); + return -2; } -#endif + /* Fill in camera details into context structure. */ cnt->imgs.width = netcam->width; diff --git a/netcam.h b/netcam.h index 6062edf..22dc042 100644 --- a/netcam.h +++ b/netcam.h @@ -107,6 +107,11 @@ typedef struct file_context { #define NCS_BLOCK 2 /* streaming is done via MJPG-block */ #define NCS_RTSP 3 /* streaming is done via RTSP */ + +#define RTSP_NOTCONNECTED 0 /* The camera has never connected */ +#define RTSP_CONNECTED 1 /* The camera is currently connected */ +#define RTSP_RECONNECTING 2 /* The camera is trying to reconnect*/ + /* * struct netcam_context contains all the structures and other data * for an individual netcam. @@ -291,11 +296,13 @@ typedef struct { */ /* Within netcam_jpeg.c */ int netcam_proc_jpeg (struct netcam_context *, unsigned char *); +void netcam_fix_jpeg_header(struct netcam_context *); void netcam_get_dimensions (struct netcam_context *); /* Within netcam.c */ int netcam_start (struct context *); int netcam_next (struct context *, unsigned char *); void netcam_cleanup (struct netcam_context *, int); ssize_t netcam_recv(netcam_context_ptr, void *, size_t); +void netcam_url_free(struct url_t *parse_url); #endif diff --git a/netcam_ftp.c b/netcam_ftp.c index 0a129b2..df7055d 100644 --- a/netcam_ftp.c +++ b/netcam_ftp.c @@ -57,15 +57,9 @@ void ftp_free_context(ftp_context_pointer ctxt) if (ctxt == NULL) return; - if (ctxt->path != NULL) - free(ctxt->path); - - if (ctxt->user) - free(ctxt->user); - - if (ctxt->passwd) - free(ctxt->passwd); - + free(ctxt->path); + free(ctxt->user); + free(ctxt->passwd); if (ctxt->control_file_desc >= 0) close(ctxt->control_file_desc); @@ -257,6 +251,8 @@ static int ftp_get_response(ftp_context_pointer ctxt) ctxt->control_buffer_index = ptr - ctxt->control_buffer; + MOTION_LOG(DBG, TYPE_NETCAM, NO_ERRNO, "%s: Server Response: %s",ctxt->control_buffer); + return (res / 100); } @@ -794,8 +790,7 @@ int ftp_send_type(ftp_context_pointer ctxt, char type) int len, res; utype = toupper(type); - /* Assure transfer will be in "image" mode. */ - snprintf(buf, sizeof(buf), "TYPE I\r\n"); + snprintf(buf, sizeof(buf), "TYPE %c\r\n", utype); len = strlen(buf); res = send(ctxt->control_file_desc, buf, len, 0); diff --git a/netcam_jpeg.c b/netcam_jpeg.c index 20fbda2..1b5c65b 100644 --- a/netcam_jpeg.c +++ b/netcam_jpeg.c @@ -67,24 +67,15 @@ static boolean netcam_fill_input_buffer(j_decompress_ptr cinfo) * path when a new image is to be processed. It is assumed that * this routine will only be called once for the entire image. * If an unexpected call (with start_of_file FALSE) occurs, the - * routine will insert a "fake" "end of image" marker and return - * to the library to process whatever data remains from the original - * image (the one with errors). - * - * I'm not yet clear on what the result (from the application's - * point of view) will be from this logic. If the application - * expects that a completely new image will be started, this will - * give trouble. + * routine calls ERREXIT(). */ if (src->start_of_file) { nbytes = src->length; src->buffer = (JOCTET *) src->data; } else { - /* Insert a fake EOI marker - as per jpeglib recommendation */ - MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO, "%s: **fake EOI inserted**"); - src->buffer[0] = (JOCTET) 0xFF; - src->buffer[1] = (JOCTET) JPEG_EOI; /* 0xD9 */ nbytes = 2; + MOTION_LOG(DBG, TYPE_NETCAM, NO_ERRNO, "%s: Not enough data from netcam."); + ERREXIT(cinfo, JERR_INPUT_EOF); } src->pub.next_input_byte = src->buffer; @@ -484,6 +475,42 @@ int netcam_proc_jpeg(netcam_context_ptr netcam, unsigned char *image) return retval; } +/** + * netcam_fix_jpeg_header + * + * Routine to decode an image received from a netcam into a YUV420P buffer + * suitable for processing by motion. + * + * Parameters: + * netcam pointer to the netcam_context structure + * + * Returns: Nothing + * + */ +void netcam_fix_jpeg_header(netcam_context_ptr netcam) +{ + char *ptr_buffer; + + ptr_buffer = memmem(netcam->receiving->ptr, netcam->receiving->used, "\xff\xd8", 2); + + if (ptr_buffer != NULL) { + size_t soi_position = 0; + + soi_position = ptr_buffer - netcam->receiving->ptr; + + if (soi_position > 0) { + memmove(netcam->receiving->ptr, netcam->receiving->ptr + soi_position, + netcam->receiving->used - soi_position); + netcam->receiving->used -= soi_position; + } + + // if (debug_level > CAMERA_INFO) + // motion_log(LOG_INFO, 0, "%s: SOI found , position %d", + // __FUNCTION__, soi_position); + } +} + + /** * netcam_get_dimensions * diff --git a/netcam_rtsp.c b/netcam_rtsp.c index 1fe1357..5ec33e4 100644 --- a/netcam_rtsp.c +++ b/netcam_rtsp.c @@ -1,15 +1,81 @@ +/*********************************************************** + * In the top section are the functions that are used + * when processing the RTSP camera feed. Since these functions + * are internal to the RTSP module, and many require FFmpeg + * structures in their declarations, they are within the + * HAVE_FFMPEG block that eliminates them entirely when + * FFmpeg is not present. + * + * The functions: + * netcam_setup_rtsp + * netcam_connect_rtsp + * netcam_shutdown_rtsp + * netcam_next_rtsp + * are called from netcam.c therefore must be defined even + * if FFmpeg is not present. They must also not have FFmpeg + * structures in the declarations. Simple error + * messages are raised if called when no FFmpeg is found. + * + ***********************************************************/ + #include +#include "rotate.h" /* already includes motion.h */ #include "netcam_rtsp.h" -#include "motion.h" -#ifdef have_av_get_media_type_string +#ifdef HAVE_FFMPEG -/**************************************************** - * Duplicated static functions - FIXME - ****************************************************/ +#include "ffmpeg.h" /** - * netcam_check_buffsize + * netcam_check_pixfmt + * + * Determine whether pix_format is YUV420P + */ +static int netcam_check_pixfmt(netcam_context_ptr netcam){ + int retcd; + + retcd = -1; + + if ((netcam->rtsp->codec_context->pix_fmt == MY_PIX_FMT_YUV420P) || + (netcam->rtsp->codec_context->pix_fmt == MY_PIX_FMT_YUVJ420P)) retcd = 0; + + return retcd; + +} +/** + * netcam_rtsp_null_context + * + * Null all the context + */ +static void netcam_rtsp_null_context(netcam_context_ptr netcam){ + + netcam->rtsp->swsctx = NULL; + netcam->rtsp->swsframe_in = NULL; + netcam->rtsp->swsframe_out = NULL; + netcam->rtsp->frame = NULL; + netcam->rtsp->codec_context = NULL; + netcam->rtsp->format_context = NULL; + +} +/** + * netcam_rtsp_close_context + * + * Close all the context that could be open + */ +static void netcam_rtsp_close_context(netcam_context_ptr netcam){ + + if (netcam->rtsp->swsctx != NULL) sws_freeContext(netcam->rtsp->swsctx); + if (netcam->rtsp->swsframe_in != NULL) my_frame_free(netcam->rtsp->swsframe_in); + if (netcam->rtsp->swsframe_out != NULL) my_frame_free(netcam->rtsp->swsframe_out); + if (netcam->rtsp->frame != NULL) my_frame_free(netcam->rtsp->frame); + if (netcam->rtsp->codec_context != NULL) avcodec_close(netcam->rtsp->codec_context); + if (netcam->rtsp->format_context != NULL) avformat_close_input(&netcam->rtsp->format_context); + + netcam_rtsp_null_context(netcam); +} + +/** + * netcam_buffsize_rtsp * * This routine checks whether there is enough room in a buffer to copy * some additional data. If there is not enough room, it will re-allocate @@ -21,8 +87,8 @@ * * Returns: Nothing */ -static void netcam_check_buffsize(netcam_buff_ptr buff, size_t numbytes) -{ +static void netcam_buffsize_rtsp(netcam_buff_ptr buff, size_t numbytes){ + int min_size_to_alloc; int real_alloc; int new_size; @@ -37,7 +103,7 @@ static void netcam_check_buffsize(netcam_buff_ptr buff, size_t numbytes) real_alloc += NETCAM_BUFFSIZE; new_size = buff->size + real_alloc; - + MOTION_LOG(DBG, TYPE_NETCAM, NO_ERRNO, "%s: expanding buffer from [%d/%d] to [%d/%d] bytes.", (int) buff->used, (int) buff->size, (int) buff->used, new_size); @@ -47,64 +113,103 @@ static void netcam_check_buffsize(netcam_buff_ptr buff, size_t numbytes) buff->size = new_size; } -/**************************************************** - * End Duplicated static functions - FIXME - ****************************************************/ - -static int decode_packet(AVPacket *packet, netcam_buff_ptr buffer, AVFrame *frame, AVCodecContext *cc) -{ - int check = 0; - int ret = avcodec_decode_video2(cc, frame, &check, packet); - - if (ret < 0) { - MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Error decoding video packet"); - return 0; - } - - if (check == 0) { - // no frame could be decoded...keep trying - return 0; - } +/** + * decode_packet + * + * This routine takes in the packet from the read and decodes it into + * the frame. It then takes the frame and copies it into the netcam + * buffer + * + * Parameters: + * packet The packet that was read from av_read + * buffer The buffer that is the final destination + * frame The frame into which we decode the packet + * + * + * Returns: + * Failure 0(zero) + * Success The size of the frame decoded + */ +static int decode_packet(AVPacket *packet, netcam_buff_ptr buffer, AVFrame *frame, AVCodecContext *cc){ + int check = 0; + int frame_size = 0; + int retcd = 0; + + retcd = avcodec_decode_video2(cc, frame, &check, packet); + if (retcd < 0) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Error decoding video packet"); + return 0; + } - int frame_size = av_image_get_buffer_size(cc->pix_fmt, cc->width, cc->height, 1); + if (check == 0) { + return 0; + } - /* Assure there's enough room in the buffer. */ - netcam_check_buffsize(buffer, frame_size); + frame_size = my_image_get_buffer_size(cc->pix_fmt, cc->width, cc->height); - av_image_copy_to_buffer((uint8_t *)buffer->ptr, frame_size, - (const uint8_t **)(frame->data), frame->linesize, - cc->pix_fmt, cc->width, cc->height, 1); + netcam_buffsize_rtsp(buffer, frame_size); + + retcd = my_image_copy_to_buffer(frame, (uint8_t *)buffer->ptr,cc->pix_fmt,cc->width,cc->height, frame_size); + if (retcd < 0) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Error decoding video packet: Copying to buffer"); + return 0; + } - buffer->used = frame_size; - - return frame_size; + buffer->used = frame_size; + + return frame_size; } -static int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaType type) -{ +/** + * netcam_open_codec + * + * This routine opens the codec context for the indicated stream + * + * Parameters: + * stream_idx The index of the stream that was found as "best" + * fmt_ctx The format context that was created upon opening the stream + * type The type of media type (This is a constant) + * + * + * Returns: + * Failure Error code from FFmpeg (Negative number) + * Success 0(Zero) + */ +static int netcam_open_codec(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaType type){ int ret; + char errstr[128]; AVStream *st; AVCodecContext *dec_ctx = NULL; AVCodec *dec = NULL; + ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0); if (ret < 0) { - MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Could not find stream %s in input!", av_get_media_type_string(type)); + av_strerror(ret, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Could not find stream in input!: %s",errstr); return ret; - } else { - *stream_idx = ret; - st = fmt_ctx->streams[*stream_idx]; - /* find decoder for the stream */ - dec_ctx = st->codec; - dec = avcodec_find_decoder(dec_ctx->codec_id); - if (!dec) { - MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Failed to find %s codec!", av_get_media_type_string(type)); - return ret; - } - if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) { - MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Failed to open %s codec!", av_get_media_type_string(type)); - return ret; - } } + + *stream_idx = ret; + st = fmt_ctx->streams[*stream_idx]; + + /* find decoder for the stream */ + dec_ctx = st->codec; + dec = avcodec_find_decoder(dec_ctx->codec_id); + if (dec == NULL) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Failed to find codec!"); + return -1; + } + + /* Open the codec It is not thread safe so lock it*/ + pthread_mutex_lock(&global_lock); + ret = avcodec_open2(dec_ctx, dec, NULL); + pthread_mutex_unlock(&global_lock); + if (ret < 0) { + av_strerror(ret, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Failed to open codec!: %s", errstr); + return ret; + } + return 0; } @@ -120,213 +225,742 @@ static int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AV * Returns: Pointer to the newly-created structure, NULL if error. * */ -struct rtsp_context *rtsp_new_context(void) -{ - struct rtsp_context *ret; - - /* Note that mymalloc will exit on any problem. */ - ret = mymalloc(sizeof(struct rtsp_context)); - - memset(ret, 0, sizeof(struct rtsp_context)); - - return ret; +struct rtsp_context *rtsp_new_context(void){ + struct rtsp_context *ret; + + /* Note that mymalloc will exit on any problem. */ + ret = mymalloc(sizeof(struct rtsp_context)); + + memset(ret, 0, sizeof(struct rtsp_context)); + + return ret; } +/** +* netcam_interrupt_rtsp +* +* This function is called during the FFmpeg blocking functions. +* These include the opening of the format context as well as the +* reading of the packets from the stream. Since this is called +* during all blocking functions, the process uses the readingframe +* flag to determine whether to timeout the process. +* +* Parameters +* +* ctx We pass in the rtsp context to use it to look for the +* readingframe flag as well as the time that we started +* the read attempt. +* +* Returns: +* Failure -1(which triggers an interupt) +* Success 0(zero which indicates to let process continue) +* +*/ +static int netcam_interrupt_rtsp(void *ctx){ + struct rtsp_context *rtsp = (struct rtsp_context *)ctx; + if (rtsp->readingframe != 1) { + return 0; + } else { + struct timeval interrupttime; + if (gettimeofday(&interrupttime, NULL) < 0) { + MOTION_LOG(WRN, TYPE_NETCAM, SHOW_ERRNO, "%s: get interrupt time failed"); + } + if ((interrupttime.tv_sec - rtsp->startreadtime.tv_sec ) > 10){ + MOTION_LOG(WRN, TYPE_NETCAM, NO_ERRNO, "%s: Reading picture timed out for %s",rtsp->path); + return 1; + } else{ + return 0; + } + } + + //should not be possible to get here + return 0; +} /** -* rtsp_free_context +* netcam_read_rtsp_image * -* Free the resources allocated for this context. +* This function reads the packet from the camera. +* It is called extensively so only absolutely essential +* functions and allocations are performed. * * Parameters * -* ctxt Pointer to the rtsp_context structure. +* netcam The netcam context to read from * -* Returns: Nothing +* Returns: +* Failure -1 +* Success 0(zero) * */ -static void rtsp_free_context(struct rtsp_context *ctxt) -{ - if (ctxt == NULL) - return; - - if (ctxt->path != NULL) - free(ctxt->path); - - if (ctxt->user) - free(ctxt->user); - - if (ctxt->pass) - free(ctxt->pass); - - if (ctxt->format_context != NULL) { - avformat_close_input(&ctxt->format_context); - } - - if (ctxt->codec_context != NULL) { - avcodec_close(ctxt->codec_context); - } - - free(ctxt); +int netcam_read_rtsp_image(netcam_context_ptr netcam){ + struct timeval curtime; + netcam_buff_ptr buffer; + AVPacket packet; + int size_decoded; + + /* Point to our working buffer. */ + buffer = netcam->receiving; + buffer->used = 0; + + av_init_packet(&packet); + packet.data = NULL; + packet.size = 0; + + size_decoded = 0; + + if (gettimeofday(&curtime, NULL) < 0) { + MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "%s: gettimeofday"); + } + netcam->rtsp->startreadtime = curtime; + + netcam->rtsp->readingframe = 1; + while (size_decoded == 0 && av_read_frame(netcam->rtsp->format_context, &packet) >= 0) { + if(packet.stream_index != netcam->rtsp->video_stream_index) { + my_packet_unref(packet); + av_init_packet(&packet); + packet.data = NULL; + packet.size = 0; + // not our packet, skip + continue; + } + size_decoded = decode_packet(&packet, buffer, netcam->rtsp->frame, netcam->rtsp->codec_context); + + my_packet_unref(packet); + av_init_packet(&packet); + packet.data = NULL; + packet.size = 0; + } + netcam->rtsp->readingframe = 0; + + // at this point, we are finished with the packet + my_packet_unref(packet); + + if (size_decoded == 0) { + // something went wrong, end of stream? Interupted? + netcam_rtsp_close_context(netcam); + return -1; + } + + /* + * read is complete - set the current 'receiving' buffer atomically + * as 'latest', and make the buffer previously in 'latest' become + * the new 'receiving' and signal pic_ready. + */ + netcam->receiving->image_time = curtime; + netcam->last_image = curtime; + netcam_buff *xchg; + + pthread_mutex_lock(&netcam->mutex); + xchg = netcam->latest; + netcam->latest = netcam->receiving; + netcam->receiving = xchg; + netcam->imgcnt++; + pthread_cond_signal(&netcam->pic_ready); + pthread_mutex_unlock(&netcam->mutex); + + return 0; } +/** +* netcam_rtsp_resize_ntc +* +* This function notifies the user of the need to transcode +* the netcam image which uses a lot of CPU resources +* +* Parameters +* +* netcam The netcam context to read from +* +* Returns: +* Failure -1 +* Success 0(zero) +* +*/ +static int netcam_rtsp_resize_ntc(netcam_context_ptr netcam){ + + if ((netcam->width != (unsigned)netcam->rtsp->codec_context->width) || + (netcam->height != (unsigned)netcam->rtsp->codec_context->height) || + (netcam_check_pixfmt(netcam) != 0) ){ + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: "); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: ****************************************************************"); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: The network camera is sending pictures in a different"); + if ((netcam->width != (unsigned)netcam->rtsp->codec_context->width) || + (netcam->height != (unsigned)netcam->rtsp->codec_context->height)) { + if (netcam_check_pixfmt(netcam) != 0) { + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: size than specified in the config and also a "); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: different picture format. The picture is being"); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: transcoded to YUV420P and into the size requested"); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: in the config file. If possible change netcam to"); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: be in YUV420P format and the size requested in the"); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: config to possibly lower CPU usage."); + } else { + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: size than specified in the configuration file."); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: The picture is being transcoded into the size "); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: requested in the configuration. If possible change"); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: netcam or configuration to indicate the same size"); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: to possibly lower CPU usage."); + } + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: Netcam: %d x %d => Config: %d x %d" + ,netcam->rtsp->codec_context->width,netcam->rtsp->codec_context->height + ,netcam->width,netcam->height); + } else { + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: format than YUV420P. The image sent is being "); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: trancoded to YUV420P. If possible change netcam "); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: picture format to YUV420P to possibly lower CPU usage."); + } + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: ****************************************************************"); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: "); + } -int rtsp_connect(netcam_context_ptr netcam) -{ - if (netcam->rtsp == NULL) { - netcam->rtsp = rtsp_new_context(); + return 0; + +} +/** +* netcam_rtsp_open_context +* +* This function opens the format context for the camera. +* +* Parameters +* +* netcam The netcam context to read from +* +* Returns: +* Failure -1 +* Success 0(zero) +* +*/ +static int netcam_rtsp_open_context(netcam_context_ptr netcam){ - if (netcam->rtsp == NULL) { - MOTION_LOG(ALR, TYPE_NETCAM, NO_ERRNO, "%s: unable to create context(%s)", netcam->rtsp->path); - return -1; + int retcd; + char errstr[128]; + + if (netcam->rtsp->path == NULL) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Null path passed to connect (%s)", netcam->rtsp->path); + } + return -1; } - } - // open the network connection - AVDictionary *opts = 0; - av_dict_set(&opts, "rtsp_transport", "tcp", 0); + // open the network connection + AVDictionary *opts = 0; + netcam->rtsp->format_context = avformat_alloc_context(); + netcam->rtsp->format_context->interrupt_callback.callback = netcam_interrupt_rtsp; + netcam->rtsp->format_context->interrupt_callback.opaque = netcam->rtsp; - int ret = avformat_open_input(&netcam->rtsp->format_context, netcam->rtsp->path, NULL, &opts); - if (ret < 0) { - MOTION_LOG(ALR, TYPE_NETCAM, NO_ERRNO, "%s: unable to open input(%s): %d - %s", netcam->rtsp->path, ret, av_err2str(ret)); - rtsp_free_context(netcam->rtsp); - netcam->rtsp = NULL; - return -1; - } + if (strncmp(netcam->rtsp->path, "http", 4) == 0 ){ + netcam->rtsp->format_context->iformat = av_find_input_format("mjpeg"); + } else { + if (netcam->cnt->conf.rtsp_uses_tcp) { + av_dict_set(&opts, "rtsp_transport", "tcp", 0); + if (netcam->rtsp->status == RTSP_NOTCONNECTED) + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: Using tcp transport"); + } else { + av_dict_set(&opts, "rtsp_transport", "udp", 0); + av_dict_set(&opts, "max_delay", "500000", 0); //100000 is the default + if (netcam->rtsp->status == RTSP_NOTCONNECTED) + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: Using udp transport"); + } + } - // fill out stream information - ret = avformat_find_stream_info(netcam->rtsp->format_context, NULL); - if (ret < 0) { - MOTION_LOG(ALR, TYPE_NETCAM, NO_ERRNO, "%s: unable to find stream info: %d", ret); - rtsp_free_context(netcam->rtsp); - netcam->rtsp = NULL; - return -1; - } + retcd = avformat_open_input(&netcam->rtsp->format_context, netcam->rtsp->path, NULL, &opts); + if (retcd < 0) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + av_strerror(retcd, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: unable to open input(%s): %s", netcam->rtsp->path,errstr); + } + av_dict_free(&opts); + //The format context gets freed upon any error from open_input. + return retcd; + } + av_dict_free(&opts); + + // fill out stream information + retcd = avformat_find_stream_info(netcam->rtsp->format_context, NULL); + if (retcd < 0) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + av_strerror(retcd, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: unable to find stream info: %s", errstr); + } + netcam_rtsp_close_context(netcam); + return -1; + } - ret = open_codec_context(&netcam->rtsp->video_stream_index, netcam->rtsp->format_context, AVMEDIA_TYPE_VIDEO); - if (ret < 0) { - MOTION_LOG(ALR, TYPE_NETCAM, NO_ERRNO, "%s: unable to open codec context: %d", ret); - rtsp_free_context(netcam->rtsp); - netcam->rtsp = NULL; - return -1; - } - - netcam->rtsp->codec_context = netcam->rtsp->format_context->streams[netcam->rtsp->video_stream_index]->codec; - - // start up the feed - av_read_play(netcam->rtsp->format_context); +#ifdef HAVE_PTHREAD_SETNAME_NP + /* there is no way to set the avcodec thread names, but they inherit + * our thread name - so temporarily change our thread name to the + * desired name */ + { + char curtname[16]; + char newtname[16]; + pthread_getname_np(pthread_self(), curtname, sizeof(curtname)); + snprintf(newtname, sizeof(newtname), "av%d%s%s", + netcam->cnt->threadnr, + netcam->cnt->conf.camera_name ? ":" : "", + netcam->cnt->conf.camera_name ? netcam->cnt->conf.camera_name : ""); + pthread_setname_np(pthread_self(), newtname); +#endif + + retcd = netcam_open_codec(&netcam->rtsp->video_stream_index, netcam->rtsp->format_context, AVMEDIA_TYPE_VIDEO); + +#ifdef HAVE_PTHREAD_SETNAME_NP + pthread_setname_np(pthread_self(), curtname); + } +#endif + + if (retcd < 0) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + av_strerror(retcd, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: unable to open codec context: %s", errstr); + } + netcam_rtsp_close_context(netcam); + return -1; + } + + netcam->rtsp->codec_context = netcam->rtsp->format_context->streams[netcam->rtsp->video_stream_index]->codec; + + netcam->rtsp->frame = my_frame_alloc(); + if (netcam->rtsp->frame == NULL) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: unable to allocate frame. Fatal error. Check FFmpeg/Libav configuration"); + } + netcam_rtsp_close_context(netcam); + return -1; + } + + /* + * Validate that the previous steps opened the camera + */ + retcd = netcam_read_rtsp_image(netcam); + if (retcd < 0) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Failed to read first image"); + } + netcam_rtsp_close_context(netcam); + return -1; + } + + return 0; - return 0; } +/** +* netcam_rtsp_open_sws +* +* This function opens the rescaling context components. +* +* Parameters +* +* netcam The netcam context to read from +* +* Returns: +* Failure -1 +* Success 0(zero) +* +*/ +static int netcam_rtsp_open_sws(netcam_context_ptr netcam){ -int netcam_read_rtsp_image(netcam_context_ptr netcam) -{ - if (netcam->rtsp == NULL) { - if (rtsp_connect(netcam) < 0) { - return -1; + netcam->width = ((netcam->cnt->conf.width / 8) * 8); + netcam->height = ((netcam->cnt->conf.height / 8) * 8); + + + netcam->rtsp->swsframe_in = my_frame_alloc(); + if (netcam->rtsp->swsframe_in == NULL) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: unable to allocate frame. Fatal error. Check FFmpeg/Libav configuration"); + } + netcam_rtsp_close_context(netcam); + return -1; } - } - AVCodecContext *cc = netcam->rtsp->codec_context; - AVFormatContext *fc = netcam->rtsp->format_context; - netcam_buff_ptr buffer; + netcam->rtsp->swsframe_out = my_frame_alloc(); + if (netcam->rtsp->swsframe_out == NULL) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: unable to allocate frame. Fatal error. Check FFmpeg/Libav configuration"); + } + netcam_rtsp_close_context(netcam); + return -1; + } - /* Point to our working buffer. */ - buffer = netcam->receiving; - buffer->used = 0; + /* + * The scaling context is used to change dimensions to config file and + * also if the format sent by the camera is not YUV420. + */ + netcam->rtsp->swsctx = sws_getContext( + netcam->rtsp->codec_context->width + ,netcam->rtsp->codec_context->height + ,netcam->rtsp->codec_context->pix_fmt + ,netcam->width + ,netcam->height + ,MY_PIX_FMT_YUV420P + ,SWS_BICUBIC,NULL,NULL,NULL); + if (netcam->rtsp->swsctx == NULL) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: unable to allocate scaling context. Fatal error. Check FFmpeg/Libav configuration"); + } + netcam_rtsp_close_context(netcam); + return -1; + } - AVFrame *frame = avcodec_alloc_frame(); + netcam->rtsp->swsframe_size = my_image_get_buffer_size( + MY_PIX_FMT_YUV420P + ,netcam->width + ,netcam->height); + if (netcam->rtsp->swsframe_size <= 0) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Error determining size of frame out"); + } + netcam_rtsp_close_context(netcam); + return -1; + } - AVPacket packet; - - av_init_packet(&packet); + return 0; - packet.data = NULL; - packet.size = 0; +} +/** +* netcam_rtsp_resize +* +* This function reencodes the image to yuv420p with the desired size +* +* Parameters +* +* netcam The netcam context to read from +* image The destination image. +* +* Returns: +* Failure -1 +* Success 0(zero) +* +*/ +static int netcam_rtsp_resize(unsigned char *image , netcam_context_ptr netcam){ + + int retcd; + char errstr[128]; + uint8_t *buffer_out; + + retcd=my_image_fill_arrays( + netcam->rtsp->swsframe_in + ,(uint8_t*)netcam->latest->ptr + ,netcam->rtsp->codec_context->pix_fmt + ,netcam->rtsp->codec_context->width + ,netcam->rtsp->codec_context->height); + if (retcd < 0) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + av_strerror(retcd, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Error allocating picture in: %s", errstr); + } + netcam_rtsp_close_context(netcam); + return -1; + } - int size_decoded = 0; - static int usual_size_decoded = 0; - while (size_decoded == 0 && av_read_frame(fc, &packet) >= 0) { + buffer_out=(uint8_t *)av_malloc(netcam->rtsp->swsframe_size*sizeof(uint8_t)); - if(packet.stream_index != netcam->rtsp->video_stream_index) { - // not our packet, skip - continue; + retcd=my_image_fill_arrays( + netcam->rtsp->swsframe_out + ,buffer_out + ,MY_PIX_FMT_YUV420P + ,netcam->width + ,netcam->height); + if (retcd < 0) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + av_strerror(retcd, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Error allocating picture out: %s", errstr); + } + netcam_rtsp_close_context(netcam); + return -1; } - size_decoded = decode_packet(&packet, buffer, frame, cc); - } + retcd = sws_scale( + netcam->rtsp->swsctx + ,(const uint8_t* const *)netcam->rtsp->swsframe_in->data + ,netcam->rtsp->swsframe_in->linesize + ,0 + ,netcam->rtsp->codec_context->height + ,netcam->rtsp->swsframe_out->data + ,netcam->rtsp->swsframe_out->linesize); + if (retcd < 0) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + av_strerror(retcd, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Error resizing/reformatting: %s", errstr); + } + netcam_rtsp_close_context(netcam); + return -1; + } + + retcd=my_image_copy_to_buffer( + netcam->rtsp->swsframe_out + ,(uint8_t *)image + ,MY_PIX_FMT_YUV420P + ,netcam->width + ,netcam->height + ,netcam->rtsp->swsframe_size); + if (retcd < 0) { + if (netcam->rtsp->status == RTSP_NOTCONNECTED){ + av_strerror(retcd, errstr, sizeof(errstr)); + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: Error putting frame into output buffer: %s", errstr); + } + netcam_rtsp_close_context(netcam); + return -1; + } + + av_free(buffer_out); + + return 0; + +} +/********************************************************* + * This ends the section of functions that rely upon FFmpeg + ***********************************************************/ +#endif /* End HAVE_FFMPEG */ + +/** +* netcam_connect_rtsp +* +* This function initiates the connection to the rtsp camera. +* +* Parameters +* +* netcam The netcam context to open. +* +* Returns: +* Failure -1 +* Success 0(zero) +* +*/ +int netcam_connect_rtsp(netcam_context_ptr netcam){ +#ifdef HAVE_FFMPEG + + if (netcam_rtsp_open_context(netcam) < 0) return -1; + + if (netcam_rtsp_open_sws(netcam) < 0) return -1; - if (size_decoded == 0) { - // something went wrong, end of stream? - MOTION_LOG(ERR, TYPE_NETCAM, SHOW_ERRNO, "%s: invalid frame!"); + if (netcam_rtsp_resize_ntc(netcam) < 0 ) return -1; + + if (netcam_read_rtsp_image(netcam) < 0) return -1; + + netcam->rtsp->status = RTSP_CONNECTED; + + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO, "%s: Camera connected"); + + return 0; + +#else /* No FFmpeg/Libav */ + netcam->rtsp->status = RTSP_NOTCONNECTED; + netcam->rtsp->format_context = NULL; + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: FFmpeg/Libav not found on computer. No RTSP support"); return -1; - } +#endif /* End #ifdef HAVE_FFMPEG */ +} - if (size_decoded != usual_size_decoded) { - MOTION_LOG(WRN, TYPE_NETCAM, SHOW_ERRNO, "%s: unusual frame size of %d!", size_decoded); - usual_size_decoded = size_decoded; - } +/** +* netcam_shutdown_rtsp +* +* This function closes and frees all the items for rtsp +* +* Parameters +* +* netcam The netcam context to free. +* +* Returns: +* Failure nothing +* Success nothing +* +*/ +void netcam_shutdown_rtsp(netcam_context_ptr netcam){ +#ifdef HAVE_FFMPEG - // at this point, we are finished with the packet and frame, so free them. - av_free_packet(&packet); - av_free(frame); - - struct timeval curtime; - - if (gettimeofday(&curtime, NULL) < 0) { - MOTION_LOG(WRN, TYPE_NETCAM, SHOW_ERRNO, "%s: gettimeofday"); - } - - netcam->receiving->image_time = curtime; - - /* - * Calculate our "running average" time for this netcam's - * frame transmissions (except for the first time). - * Note that the average frame time is held in microseconds. - */ - if (netcam->last_image.tv_sec) { - netcam->av_frame_time = ((9.0 * netcam->av_frame_time) + 1000000.0 * - (curtime.tv_sec - netcam->last_image.tv_sec) + - (curtime.tv_usec- netcam->last_image.tv_usec)) / 10.0; + if (netcam->rtsp->status == RTSP_CONNECTED) { + netcam_rtsp_close_context(netcam); + MOTION_LOG(NTC, TYPE_NETCAM, NO_ERRNO,"%s: netcam shut down"); + } - MOTION_LOG(DBG, TYPE_NETCAM, NO_ERRNO, "%s: Calculated frame time %f", - netcam->av_frame_time); + avformat_network_deinit(); + + free(netcam->rtsp->path); + free(netcam->rtsp->user); + free(netcam->rtsp->pass); + + free(netcam->rtsp); + netcam->rtsp = NULL; + +#else /* No FFmpeg/Libav */ + /* Stop compiler warnings */ + netcam->rtsp->status = RTSP_NOTCONNECTED; + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: FFmpeg/Libav not found on computer. No RTSP support"); +#endif /* End #ifdef HAVE_FFMPEG */ +} + +/** +* netcam_setup_rtsp +* +* This function sets up all the necessary items for the +* rtsp camera. +* +* Parameters +* +* netcam The netcam context to free. +* url The URL of the camera +* +* Returns: +* Failure -1 +* Success 0(zero) +* +*/ +int netcam_setup_rtsp(netcam_context_ptr netcam, struct url_t *url){ +#ifdef HAVE_FFMPEG + + struct context *cnt = netcam->cnt; + const char *ptr; + int ret = -1; + + netcam->caps.streaming = NCS_RTSP; + + netcam->rtsp = rtsp_new_context(); + + netcam_rtsp_null_context(netcam); + + if (netcam->rtsp == NULL) { + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: unable to create rtsp context"); + netcam_shutdown_rtsp(netcam); + return -1; } - - netcam->last_image = curtime; - - netcam_buff *xchg; - - /* - * read is complete - set the current 'receiving' buffer atomically - * as 'latest', and make the buffer previously in 'latest' become - * the new 'receiving'. - */ - pthread_mutex_lock(&netcam->mutex); - xchg = netcam->latest; - netcam->latest = netcam->receiving; - netcam->receiving = xchg; - netcam->imgcnt++; - /* - * We have a new frame ready. We send a signal so that - * any thread (e.g. the motion main loop) waiting for the - * next frame to become available may proceed. + * Allocate space for a working string to contain the path. + * The extra 5 is for "://", ":" and string terminator. */ - pthread_cond_signal(&netcam->pic_ready); - - pthread_mutex_unlock(&netcam->mutex); - + + // force port to a sane value + if (netcam->connect_port > 65536) { + netcam->connect_port = 65536; + } else if (netcam->connect_port < 0) { + netcam->connect_port = 0; + } + + if (cnt->conf.netcam_userpass != NULL) { + ptr = cnt->conf.netcam_userpass; + } else { + ptr = url->userpass; /* Don't set this one NULL, gets freed. */ + } + + if (ptr != NULL) { + char *cptr; + if ((cptr = strchr(ptr, ':')) == NULL) { + netcam->rtsp->user = mystrdup(ptr); + } else { + netcam->rtsp->user = mymalloc((cptr - ptr)+2); //+2 for string terminator + memcpy(netcam->rtsp->user, ptr,(cptr - ptr)); + netcam->rtsp->pass = mystrdup(cptr + 1); + } + } + + /* + * Need a method to query the path and + * determine the authentication type + */ + if ((netcam->rtsp->user != NULL) && (netcam->rtsp->pass != NULL)) { + ptr = mymalloc(strlen(url->service) + strlen(netcam->connect_host) + + 5 + strlen(url->path) + 5 + + strlen(netcam->rtsp->user) + strlen(netcam->rtsp->pass) + 4 ); + sprintf((char *)ptr, "%s://%s:%s@%s:%d%s", + url->service,netcam->rtsp->user,netcam->rtsp->pass, + netcam->connect_host, netcam->connect_port, url->path); + } + else { + ptr = mymalloc(strlen(url->service) + strlen(netcam->connect_host) + + 5 + strlen(url->path) + 5); + sprintf((char *)ptr, "%s://%s:%d%s", url->service, + netcam->connect_host, netcam->connect_port, url->path); + } + netcam->rtsp->path = (char *)ptr; + + netcam_url_free(url); + + /* + * Now we need to set some flags + */ + netcam->rtsp->readingframe = 0; + netcam->rtsp->status = RTSP_NOTCONNECTED; + + /* + * Warn and fix dimensions as needed. + */ + if (netcam->cnt->conf.width % 8) { + MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: Image width (%d) requested is not modulo 8.", netcam->cnt->conf.width); + netcam->cnt->conf.width = netcam->cnt->conf.width - (netcam->cnt->conf.width % 8) + 8; + MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: Adjusting width to next higher multiple of 8 (%d).", netcam->cnt->conf.width); + } + if (netcam->cnt->conf.height % 8) { + MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: Image height (%d) requested is not modulo 8.", netcam->cnt->conf.height); + netcam->cnt->conf.height = netcam->cnt->conf.height - (netcam->cnt->conf.height % 8) + 8; + MOTION_LOG(CRT, TYPE_NETCAM, NO_ERRNO, "%s: Adjusting height to next higher multiple of 8 (%d).", netcam->cnt->conf.height); + } + + /* + * Documentation does not indicate thread safety on these + * init functions but we lock them just in case. + */ + pthread_mutex_lock(&global_lock); + av_register_all(); + avcodec_register_all(); + avformat_network_init(); + pthread_mutex_unlock(&global_lock); + + /* + * The RTSP context should be all ready to attempt a connection with + * the server, so we try .... + */ + ret = netcam_connect_rtsp(netcam); + if (ret < 0){ + return ret; + } + + netcam->get_image = netcam_read_rtsp_image; + return 0; + +#else /* No FFmpeg/Libav */ + /* Stop compiler warnings */ + if (url->port == url->port) netcam->rtsp->status = RTSP_NOTCONNECTED; + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: FFmpeg/Libav not found on computer. No RTSP support"); + return -1; +#endif /* End #ifdef HAVE_FFMPEG */ } +/** +* netcam_next_rtsp +* +* This function moves the picture to the image buffer. +* If the picture is not in the correct format for size +* it will put it into the requested format +* +* Parameters +* +* netcam The netcam context to free. +* url The URL of the camera +* +* Returns: +* Failure -1 +* Success 0(zero) +* +*/ +int netcam_next_rtsp(unsigned char *image , netcam_context_ptr netcam){ +#ifdef HAVE_FFMPEG + + if ((netcam->width != (unsigned)netcam->rtsp->codec_context->width) || + (netcam->height != (unsigned)netcam->rtsp->codec_context->height) || + (netcam_check_pixfmt(netcam) != 0) ){ + netcam_rtsp_resize(image ,netcam); + } else { + memcpy(image, netcam->latest->ptr, netcam->latest->used); + } + if (netcam->cnt->rotate_data.degrees > 0) + /* Rotate as specified */ + rotate_map(netcam->cnt, image); -void netcam_shutdown_rtsp(netcam_context_ptr netcam) -{ - if (netcam->rtsp != NULL) { - rtsp_free_context(netcam->rtsp); - netcam->rtsp = NULL; - } + return 0; +#else /* No FFmpeg/Libav */ + /* Stop compiler warnings */ + if (image == image) netcam->rtsp->status = RTSP_NOTCONNECTED; + MOTION_LOG(ERR, TYPE_NETCAM, NO_ERRNO, "%s: FFmpeg/Libav not found on computer. No RTSP support"); + return -1; +#endif /* End #ifdef HAVE_FFMPEG */ } - -#endif diff --git a/netcam_rtsp.h b/netcam_rtsp.h index 38ef565..325ed69 100644 --- a/netcam_rtsp.h +++ b/netcam_rtsp.h @@ -1,22 +1,53 @@ #include "netcam.h" + +#ifdef HAVE_FFMPEG + #include #include #include #include #include +#include + +struct rtsp_context { + AVFormatContext* format_context; + AVCodecContext* codec_context; + AVFrame* frame; + AVFrame* swsframe_in; + AVFrame* swsframe_out; + int swsframe_size; + int video_stream_index; + char* path; + char* user; + char* pass; + int readingframe; + int status; + struct timeval startreadtime; + struct SwsContext* swsctx; +}; + +struct rtsp_context *rtsp_new_context(void); +void netcam_shutdown_rtsp(netcam_context_ptr netcam); +int netcam_connect_rtsp(netcam_context_ptr netcam); +int netcam_read_rtsp_image(netcam_context_ptr netcam); +int netcam_setup_rtsp(netcam_context_ptr netcam, struct url_t *url); +int netcam_next_rtsp(unsigned char *image , netcam_context_ptr netcam); +#else /* Do not have FFmpeg */ struct rtsp_context { - AVFormatContext* format_context; - AVCodecContext* codec_context; - int video_stream_index; - char* path; - char* user; - char* pass; + int* format_context; + int readingframe; + int status; }; -//int netcam_setup_rtsp(netcam_context_ptr netcam, struct url_t *url); struct rtsp_context *rtsp_new_context(void); void netcam_shutdown_rtsp(netcam_context_ptr netcam); -int rtsp_connect(netcam_context_ptr netcam); +int netcam_connect_rtsp(netcam_context_ptr netcam); int netcam_read_rtsp_image(netcam_context_ptr netcam); +int netcam_setup_rtsp(netcam_context_ptr netcam, struct url_t *url); +int netcam_next_rtsp(unsigned char *image , netcam_context_ptr netcam); + +#endif /* end HAVE_FFMPEG */ + + diff --git a/netcam_wget.c b/netcam_wget.c index 71daac6..4491760 100644 --- a/netcam_wget.c +++ b/netcam_wget.c @@ -70,7 +70,7 @@ int header_get(netcam_context_ptr netcam, char **hdr, enum header_get_flags flag int i; int bufsize = 80; - *hdr = (char *)mymalloc(bufsize); + *hdr = mymalloc(bufsize); for (i = 0; 1; i++) { int res; @@ -257,7 +257,7 @@ void base64_encode(const char *s, char *store, int length) */ char *strdupdelim(const char *beg, const char *end) { - char *res = (char *)mymalloc(end - beg + 1); + char *res = mymalloc(end - beg + 1); memcpy (res, beg, end - beg); res[end - beg] = '\0'; diff --git a/normal.jpg b/normal.jpg new file mode 100644 index 0000000..dc1116d Binary files /dev/null and b/normal.jpg differ diff --git a/outputmotion1.jpg b/outputmotion1.jpg new file mode 100644 index 0000000..fc3a795 Binary files /dev/null and b/outputmotion1.jpg differ diff --git a/outputnormal1.jpg b/outputnormal1.jpg new file mode 100644 index 0000000..9b8da88 Binary files /dev/null and b/outputnormal1.jpg differ diff --git a/picture.c b/picture.c index 196f220..a29e8c7 100644 --- a/picture.c +++ b/picture.c @@ -177,7 +177,7 @@ static void put_direntry(struct tiff_writing *into, const char *data, unsigned l } else { /* Longer entries are stored out-of-line */ unsigned offset = into->data_offset; - + while ((offset & 0x03) != 0) { /* Alignment */ into->base[offset] = 0; offset ++; @@ -324,7 +324,7 @@ static void put_jpeg_exif(j_compress_ptr cinfo, JOCTET *marker = malloc(buffer_size); memcpy(marker, exif_marker_start, 14); /* EXIF and TIFF headers */ - + struct tiff_writing writing = (struct tiff_writing) { .base = marker + 6, /* base address for intra-TIFF offsets */ .buf = marker + 14, /* current write position */ @@ -338,10 +338,10 @@ static void put_jpeg_exif(j_compress_ptr cinfo, if (description) put_stringentry(&writing, TIFF_TAG_IMAGE_DESCRIPTION, description, 0); - + if (datetime) put_stringentry(&writing, TIFF_TAG_DATETIME, datetime, 1); - + if (ifd1_tagcount > 0) { /* Offset of IFD1 - TIFF header + IFD0 size. */ unsigned ifd1_offset = 8 + 6 + ( 12 * ifd0_tagcount ); @@ -369,10 +369,10 @@ static void put_jpeg_exif(j_compress_ptr cinfo, if (datetime) put_stringentry(&writing, EXIF_TAG_ORIGINAL_DATETIME, datetime, 1); - + if (box) put_subjectarea(&writing, box); - + if (subtime) put_stringentry(&writing, EXIF_TAG_ORIGINAL_DATETIME_SS, subtime, 0); @@ -392,9 +392,8 @@ static void put_jpeg_exif(j_compress_ptr cinfo, /* EXIF data lives in a JPEG APP1 marker */ jpeg_write_marker(cinfo, JPEG_APP0 + 1, marker, marker_len); - if (description) - free(description); - + free(description); + free(marker); } @@ -453,21 +452,30 @@ static int put_jpeg_yuv420p_memory(unsigned char *dest_image, int image_size, jpeg_set_quality(&cinfo, quality, TRUE); cinfo.dct_method = JDCT_FASTEST; - + _jpeg_mem_dest(&cinfo, dest_image, image_size); // Data written to mem + jpeg_start_compress(&cinfo, TRUE); put_jpeg_exif(&cinfo, cnt, tm, box); - + + /* If the image is not a multiple of 16, this overruns the buffers + * we'll just pad those last bytes with zeros + */ for (j = 0; j < height; j += 16) { for (i = 0; i < 16; i++) { - y[i] = input_image + width * (i + j); - - if (i % 2 == 0) { - cb[i / 2] = input_image + width * height + width / 2 * ((i + j) /2); - cr[i / 2] = input_image + width * height + width * height / 4 + width / 2 * ((i + j) / 2); - } + if ((width * (i + j)) < (width * height)) { + y[i] = input_image + width * (i + j); + if (i % 2 == 0) { + cb[i / 2] = input_image + width * height + width / 2 * ((i + j) /2); + cr[i / 2] = input_image + width * height + width * height / 4 + width / 2 * ((i + j) / 2); + } + } else { + y[i] = 0x00; + cb[i] = 0x00; + cr[i] = 0x00; + } } jpeg_write_raw_data(&cinfo, data, 16); } @@ -595,12 +603,18 @@ static void put_jpeg_yuv420p_file(FILE *fp, for (j = 0; j < height; j += 16) { for (i = 0; i < 16; i++) { - y[i] = image + width * (i + j); - if (i % 2 == 0) { - cb[i / 2] = image + width * height + width / 2 * ((i + j) / 2); - cr[i / 2] = image + width * height + width * height / 4 + width / 2 * ((i + j) / 2); - } - } + if ((width * (i + j)) < (width * height)) { + y[i] = image + width * (i + j); + if (i % 2 == 0) { + cb[i / 2] = image + width * height + width / 2 * ((i + j) / 2); + cr[i / 2] = image + width * height + width * height / 4 + width / 2 * ((i + j) / 2); + } + } else { + y[i] = 0x00; + cb[i] = 0x00; + cr[i] = 0x00; + } + } jpeg_write_raw_data(&cinfo, data, 16); } @@ -679,7 +693,6 @@ static void put_ppm_bgr24_file(FILE *picture, unsigned char *image, int width, i unsigned char *u = image + width * height; unsigned char *v = u + (width * height) / 4; int r, g, b; - int warningkiller; unsigned char rgb[3]; /* @@ -722,7 +735,7 @@ static void put_ppm_bgr24_file(FILE *picture, unsigned char *image, int width, i v++; } /* ppm is rgb not bgr */ - warningkiller = fwrite(rgb, 1, 3, picture); + fwrite(rgb, 1, 3, picture); } if (y & 1) { u -= width / 2; @@ -890,7 +903,7 @@ int put_picture_memory(struct context *cnt, unsigned char* dest_image, int image return put_jpeg_grey_memory(dest_image, image_size, image, cnt->imgs.width, cnt->imgs.height, quality); default: - MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: Unknow image type %d", + MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: Unknown image type %d", cnt->imgs.type); } @@ -910,7 +923,7 @@ void put_picture_fd(struct context *cnt, FILE *picture, unsigned char *image, in put_jpeg_grey_file(picture, image, cnt->imgs.width, cnt->imgs.height, quality); break; default: - MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: Unknow image type %d", + MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: Unknown image type %d", cnt->imgs.type); } } @@ -921,7 +934,7 @@ void put_picture(struct context *cnt, char *file, unsigned char *image, int ftyp { FILE *picture; - picture = myfopen(file, "w", BUFSIZE_1MEG); + picture = myfopen(file, "w"); if (!picture) { /* Report to syslog - suggest solution if the problem is access rights to target dir. */ if (errno == EACCES) { @@ -950,9 +963,9 @@ void put_picture(struct context *cnt, char *file, unsigned char *image, int ftyp */ unsigned char *get_pgm(FILE *picture, int width, int height) { - int x = 0 , y = 0, maxval; + int x, y, mask_width, mask_height, maxval; char line[256]; - unsigned char *image; + unsigned char *image, *resized_image; line[255] = 0; @@ -973,18 +986,12 @@ unsigned char *get_pgm(FILE *picture, int width, int height) if (!fgets(line, 255, picture)) return NULL; - /* Check size */ - if (sscanf(line, "%d %d", &x, &y) != 2) { + /* Read image size */ + if (sscanf(line, "%d %d", &mask_width, &mask_height) != 2) { MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Failed reading size in pgm file"); return NULL; } - if (x != width || y != height) { - MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Wrong image size %dx%d should be %dx%d", - x, y, width, height); - return NULL; - } - /* Maximum value */ line[0] = '#'; while (line[0] == '#') @@ -998,15 +1005,35 @@ unsigned char *get_pgm(FILE *picture, int width, int height) /* Read data */ - image = mymalloc(width * height); + image = mymalloc(mask_width * mask_height); - for (y = 0; y < height; y++) { - if ((int)fread(&image[y * width], 1, width, picture) != width) + for (y = 0; y < mask_height; y++) { + if ((int)fread(&image[y * mask_width], 1, mask_width, picture) != mask_width) MOTION_LOG(ERR, TYPE_ALL, SHOW_ERRNO, "%s: Failed reading image data from pgm file"); - for (x = 0; x < width; x++) - image[y * width + x] = (int)image[y * width + x] * 255 / maxval; + for (x = 0; x < mask_width; x++) + image[y * mask_width + x] = (int)image[y * mask_width + x] * 255 / maxval; + + } + + /* Resize mask if required */ + if (mask_width != width || mask_height != height) { + MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: The mask file specified is not the same size as image from camera."); + MOTION_LOG(WRN, TYPE_ALL, NO_ERRNO, "%s: Attempting to resize mask image from %dx%d to %dx%d", + mask_width, mask_height, width, height); + + resized_image = mymalloc(width * height); + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + resized_image[y * width + x] = image[ + (mask_height - 1) * y / (height - 1) * mask_width + + (mask_width - 1) * x / (width - 1)]; + } + } + free(image); + image = resized_image; } return image; @@ -1024,7 +1051,7 @@ void put_fixed_mask(struct context *cnt, const char *file) { FILE *picture; - picture = myfopen(file, "w", BUFSIZE_1MEG); + picture = myfopen(file, "w"); if (!picture) { /* Report to syslog - suggest solution if the problem is access rights to target dir. */ if (errno == EACCES) { diff --git a/pwc-ioctl.h b/pwc-ioctl.h index 48a3861..e7f5480 100644 --- a/pwc-ioctl.h +++ b/pwc-ioctl.h @@ -52,7 +52,7 @@ ... the function */ -#if (!defined(BSD)) +#if defined(__linux__) #include #include @@ -309,7 +309,7 @@ struct pwc_table_init_buffer { * use interface offer by v4l2. */ -#if (defined(MOTION_V4L2)) && (!defined(BSD)) +#if (defined(MOTION_V4L2)) && defined(__linux__) #define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0) #define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1) diff --git a/pwc-ioctl.h-10.0.10 b/pwc-ioctl.h-10.0.10 deleted file mode 100644 index 48a3861..0000000 --- a/pwc-ioctl.h-10.0.10 +++ /dev/null @@ -1,334 +0,0 @@ -#ifndef PWC_IOCTL_H -#define PWC_IOCTL_H - -/* (C) 2001-2004 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* This is pwc-ioctl.h belonging to PWC 10.0.10 - It contains structures and defines to communicate from user space - directly to the driver. - */ - -/* - Changes - 2001/08/03 Alvarado Added ioctl constants to access methods for - changing white balance and red/blue gains - 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE - 2003/12/13 Nemosft Unv. Some modifications to make interfacing to - PWCX easier - 2006/01/01 Luc Saillard Add raw format definition - */ - -/* These are private ioctl() commands, specific for the Philips webcams. - They contain functions not found in other webcams, and settings not - specified in the Video4Linux API. - - The #define names are built up like follows: - VIDIOC VIDeo IOCtl prefix - PWC Philps WebCam - G optional: Get - S optional: Set - ... the function - */ - -#if (!defined(BSD)) -#include -#include - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 10) -/* Compatibility for older kernel */ -typedef __u16 __le16; -#endif - -#endif /* ( !BSD ) */ - - /* Enumeration of image sizes */ -#define PSZ_SQCIF 0x00 -#define PSZ_QSIF 0x01 -#define PSZ_QCIF 0x02 -#define PSZ_SIF 0x03 -#define PSZ_CIF 0x04 -#define PSZ_VGA 0x05 -#define PSZ_MAX 6 - - -/* The frame rate is encoded in the video_window.flags parameter using - the upper 16 bits, since some flags are defined nowadays. The following - defines provide a mask and shift to filter out this value. - This value can also be passing using the private flag when using v4l2 and - VIDIOC_S_FMT ioctl. - - In 'Snapshot' mode the camera freezes its automatic exposure and colour - balance controls. - */ -#define PWC_FPS_SHIFT 16 -#define PWC_FPS_MASK 0x00FF0000 -#define PWC_FPS_FRMASK 0x003F0000 -#define PWC_FPS_SNAPSHOT 0x00400000 -#define PWC_QLT_MASK 0x03000000 -#define PWC_QLT_SHIFT 24 - - -/* structure for transferring x & y coordinates */ -struct pwc_coord -{ - int x, y; /* guess what */ - int size; /* size, or offset */ -}; - - -/* Used with VIDIOCPWCPROBE */ -struct pwc_probe -{ - char name[32]; - int type; -}; - -struct pwc_serial -{ - char serial[30]; /* String with serial number. Contains terminating 0 */ -}; - -/* pwc_whitebalance.mode values */ -#define PWC_WB_INDOOR 0 -#define PWC_WB_OUTDOOR 1 -#define PWC_WB_FL 2 -#define PWC_WB_MANUAL 3 -#define PWC_WB_AUTO 4 - -/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). - Set mode to one of the PWC_WB_* values above. - *red and *blue are the respective gains of these colour components inside - the camera; range 0..65535 - When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; - otherwise undefined. - 'read_red' and 'read_blue' are read-only. -*/ -struct pwc_whitebalance -{ - int mode; - int manual_red, manual_blue; /* R/W */ - int read_red, read_blue; /* R/O */ -}; - -/* - 'control_speed' and 'control_delay' are used in automatic whitebalance mode, - and tell the camera how fast it should react to changes in lighting, and - with how much delay. Valid values are 0..65535. -*/ -struct pwc_wb_speed -{ - int control_speed; - int control_delay; - -}; - -/* Used with VIDIOCPWC[SG]LED */ -struct pwc_leds -{ - int led_on; /* Led on-time; range = 0..25000 */ - int led_off; /* Led off-time; range = 0..25000 */ -}; - -/* Image size (used with GREALSIZE) */ -struct pwc_imagesize -{ - int width; - int height; -}; - -/* Defines and structures for Motorized Pan & Tilt */ -#define PWC_MPT_PAN 0x01 -#define PWC_MPT_TILT 0x02 -#define PWC_MPT_TIMEOUT 0x04 /* for status */ - -/* Set angles; when absolute != 0, the angle is absolute and the - driver calculates the relative offset for you. This can only - be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns - absolute angles. - */ -struct pwc_mpt_angles -{ - int absolute; /* write-only */ - int pan; /* degrees * 100 */ - int tilt; /* degress * 100 */ -}; - -/* Range of angles of the camera, both horizontally and vertically. - */ -struct pwc_mpt_range -{ - int pan_min, pan_max; /* degrees * 100 */ - int tilt_min, tilt_max; -}; - -struct pwc_mpt_status -{ - int status; - int time_pan; - int time_tilt; -}; - - -/* This is used for out-of-kernel decompression. With it, you can get - all the necessary information to initialize and use the decompressor - routines in standalone applications. - */ -struct pwc_video_command -{ - int type; /* camera type (645, 675, 730, etc.) */ - int release; /* release number */ - - int size; /* one of PSZ_* */ - int alternate; - int command_len; /* length of USB video command */ - unsigned char command_buf[13]; /* Actual USB video command */ - int bandlength; /* >0 = compressed */ - int frame_size; /* Size of one (un)compressed frame */ -}; - -/* Flags for PWCX subroutines. Not all modules honour all flags. */ -#define PWCX_FLAG_PLANAR 0x0001 -#define PWCX_FLAG_BAYER 0x0008 - - -/* IOCTL definitions */ - - /* Restore user settings */ -#define VIDIOCPWCRUSER _IO('v', 192) - /* Save user settings */ -#define VIDIOCPWCSUSER _IO('v', 193) - /* Restore factory settings */ -#define VIDIOCPWCFACTORY _IO('v', 194) - - /* You can manipulate the compression factor. A compression preference of 0 - means use uncompressed modes when available; 1 is low compression, 2 is - medium and 3 is high compression preferred. Of course, the higher the - compression, the lower the bandwidth used but more chance of artefacts - in the image. The driver automatically chooses a higher compression when - the preferred mode is not available. - */ - /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ -#define VIDIOCPWCSCQUAL _IOW('v', 195, int) - /* Get preferred compression quality */ -#define VIDIOCPWCGCQUAL _IOR('v', 195, int) - - -/* Retrieve serial number of camera */ -#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) - - /* This is a probe function; since so many devices are supported, it - becomes difficult to include all the names in programs that want to - check for the enhanced Philips stuff. So in stead, try this PROBE; - it returns a structure with the original name, and the corresponding - Philips type. - To use, fill the structure with zeroes, call PROBE and if that succeeds, - compare the name with that returned from VIDIOCGCAP; they should be the - same. If so, you can be assured it is a Philips (OEM) cam and the type - is valid. - */ -#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) - - /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ -#define VIDIOCPWCSAGC _IOW('v', 200, int) - /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCGAGC _IOR('v', 200, int) - /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) - - /* Color compensation (Auto White Balance) */ -#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) -#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) - - /* Auto WB speed */ -#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) -#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) - - /* LEDs on/off/blink; int range 0..65535 */ -#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) -#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) - - /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ -#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) -#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) - - /* Backlight compensation; 0 = off, otherwise on */ -#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) -#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) - - /* Flickerless mode; = 0 off, otherwise on */ -#define VIDIOCPWCSFLICKER _IOW('v', 208, int) -#define VIDIOCPWCGFLICKER _IOR('v', 208, int) - - /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ -#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) -#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) - - /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ -#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) - - /* Motorized pan & tilt functions */ -#define VIDIOCPWCMPTRESET _IOW('v', 211, int) -#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) -#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) - - /* Get the USB set-video command; needed for initializing libpwcx */ -#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) -struct pwc_table_init_buffer { - int len; - char *buffer; -}; -#define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) - -/* - * This is private command used when communicating with v4l2. - * In the future all private ioctl will be remove/replace to - * use interface offer by v4l2. - */ - -#if (defined(MOTION_V4L2)) && (!defined(BSD)) - -#define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0) -#define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1) -#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_COLOUR_MODE (V4L2_CID_PRIVATE_BASE + 3) -#define V4L2_CID_PRIVATE_AUTOCONTOUR (V4L2_CID_PRIVATE_BASE + 4) -#define V4L2_CID_PRIVATE_CONTOUR (V4L2_CID_PRIVATE_BASE + 5) -#define V4L2_CID_PRIVATE_BACKLIGHT (V4L2_CID_PRIVATE_BASE + 6) -#define V4L2_CID_PRIVATE_FLICKERLESS (V4L2_CID_PRIVATE_BASE + 7) -#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8) - -struct pwc_raw_frame { - __le16 type; /* type of the webcam */ - __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */ - __u8 cmd[4]; /* the four byte of the command (in case of nala, - only the first 3 bytes is filled) */ - __u8 rawframe[0]; /* frame_size = H/4*vbandlength */ -} __attribute__ ((packed)); - -#endif /* MOTION_V4L2 && (! BSD ) */ - -#endif diff --git a/pwc-ioctl.h-10.0.5 b/pwc-ioctl.h-10.0.5 deleted file mode 100644 index 65805ea..0000000 --- a/pwc-ioctl.h-10.0.5 +++ /dev/null @@ -1,292 +0,0 @@ -#ifndef PWC_IOCTL_H -#define PWC_IOCTL_H - -/* (C) 2001-2004 Nemosoft Unv. - (C) 2004 Luc Saillard (luc@saillard.org) - - NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx - driver and thus may have bugs that are not present in the original version. - Please send bug reports and support requests to . - The decompression routines have been implemented by reverse-engineering the - Nemosoft binary pwcx module. Caveat emptor. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* This is pwc-ioctl.h belonging to PWC 8.12.1 - It contains structures and defines to communicate from user space - directly to the driver. - */ - -/* - Changes - 2001/08/03 Alvarado Added ioctl constants to access methods for - changing white balance and red/blue gains - 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE - 2003/12/13 Nemosft Unv. Some modifications to make interfacing to - PWCX easier - */ - -/* These are private ioctl() commands, specific for the Philips webcams. - They contain functions not found in other webcams, and settings not - specified in the Video4Linux API. - - The #define names are built up like follows: - VIDIOC VIDeo IOCtl prefix - PWC Philps WebCam - G optional: Get - S optional: Set - ... the function - */ - - - /* Enumeration of image sizes */ -#define PSZ_SQCIF 0x00 -#define PSZ_QSIF 0x01 -#define PSZ_QCIF 0x02 -#define PSZ_SIF 0x03 -#define PSZ_CIF 0x04 -#define PSZ_VGA 0x05 -#define PSZ_MAX 6 - - -/* The frame rate is encoded in the video_window.flags parameter using - the upper 16 bits, since some flags are defined nowadays. The following - defines provide a mask and shift to filter out this value. - - In 'Snapshot' mode the camera freezes its automatic exposure and colour - balance controls. - */ -#define PWC_FPS_SHIFT 16 -#define PWC_FPS_MASK 0x00FF0000 -#define PWC_FPS_FRMASK 0x003F0000 -#define PWC_FPS_SNAPSHOT 0x00400000 - - -/* structure for transfering x & y coordinates */ -struct pwc_coord -{ - int x, y; /* guess what */ - int size; /* size, or offset */ -}; - - -/* Used with VIDIOCPWCPROBE */ -struct pwc_probe -{ - char name[32]; - int type; -}; - -struct pwc_serial -{ - char serial[30]; /* String with serial number. Contains terminating 0 */ -}; - -/* pwc_whitebalance.mode values */ -#define PWC_WB_INDOOR 0 -#define PWC_WB_OUTDOOR 1 -#define PWC_WB_FL 2 -#define PWC_WB_MANUAL 3 -#define PWC_WB_AUTO 4 - -/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). - Set mode to one of the PWC_WB_* values above. - *red and *blue are the respective gains of these colour components inside - the camera; range 0..65535 - When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; - otherwise undefined. - 'read_red' and 'read_blue' are read-only. -*/ -struct pwc_whitebalance -{ - int mode; - int manual_red, manual_blue; /* R/W */ - int read_red, read_blue; /* R/O */ -}; - -/* - 'control_speed' and 'control_delay' are used in automatic whitebalance mode, - and tell the camera how fast it should react to changes in lighting, and - with how much delay. Valid values are 0..65535. -*/ -struct pwc_wb_speed -{ - int control_speed; - int control_delay; - -}; - -/* Used with VIDIOCPWC[SG]LED */ -struct pwc_leds -{ - int led_on; /* Led on-time; range = 0..25000 */ - int led_off; /* Led off-time; range = 0..25000 */ -}; - -/* Image size (used with GREALSIZE) */ -struct pwc_imagesize -{ - int width; - int height; -}; - -/* Defines and structures for Motorized Pan & Tilt */ -#define PWC_MPT_PAN 0x01 -#define PWC_MPT_TILT 0x02 -#define PWC_MPT_TIMEOUT 0x04 /* for status */ - -/* Set angles; when absolute != 0, the angle is absolute and the - driver calculates the relative offset for you. This can only - be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns - absolute angles. - */ -struct pwc_mpt_angles -{ - int absolute; /* write-only */ - int pan; /* degrees * 100 */ - int tilt; /* degress * 100 */ -}; - -/* Range of angles of the camera, both horizontally and vertically. - */ -struct pwc_mpt_range -{ - int pan_min, pan_max; /* degrees * 100 */ - int tilt_min, tilt_max; -}; - -struct pwc_mpt_status -{ - int status; - int time_pan; - int time_tilt; -}; - - -/* This is used for out-of-kernel decompression. With it, you can get - all the necessary information to initialize and use the decompressor - routines in standalone applications. - */ -struct pwc_video_command -{ - int type; /* camera type (645, 675, 730, etc.) */ - int release; /* release number */ - - int size; /* one of PSZ_* */ - int alternate; - int command_len; /* length of USB video command */ - unsigned char command_buf[13]; /* Actual USB video command */ - int bandlength; /* >0 = compressed */ - int frame_size; /* Size of one (un)compressed frame */ -}; - -/* Flags for PWCX subroutines. Not all modules honour all flags. */ -#define PWCX_FLAG_PLANAR 0x0001 -#define PWCX_FLAG_BAYER 0x0008 - - -/* IOCTL definitions */ - - /* Restore user settings */ -#define VIDIOCPWCRUSER _IO('v', 192) - /* Save user settings */ -#define VIDIOCPWCSUSER _IO('v', 193) - /* Restore factory settings */ -#define VIDIOCPWCFACTORY _IO('v', 194) - - /* You can manipulate the compression factor. A compression preference of 0 - means use uncompressed modes when available; 1 is low compression, 2 is - medium and 3 is high compression preferred. Of course, the higher the - compression, the lower the bandwidth used but more chance of artefacts - in the image. The driver automatically chooses a higher compression when - the preferred mode is not available. - */ - /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ -#define VIDIOCPWCSCQUAL _IOW('v', 195, int) - /* Get preferred compression quality */ -#define VIDIOCPWCGCQUAL _IOR('v', 195, int) - - -/* Retrieve serial number of camera */ -#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) - - /* This is a probe function; since so many devices are supported, it - becomes difficult to include all the names in programs that want to - check for the enhanced Philips stuff. So in stead, try this PROBE; - it returns a structure with the original name, and the corresponding - Philips type. - To use, fill the structure with zeroes, call PROBE and if that succeeds, - compare the name with that returned from VIDIOCGCAP; they should be the - same. If so, you can be assured it is a Philips (OEM) cam and the type - is valid. - */ -#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) - - /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ -#define VIDIOCPWCSAGC _IOW('v', 200, int) - /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCGAGC _IOR('v', 200, int) - /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) - - /* Color compensation (Auto White Balance) */ -#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) -#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) - - /* Auto WB speed */ -#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) -#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) - - /* LEDs on/off/blink; int range 0..65535 */ -#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) -#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) - - /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ -#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) -#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) - - /* Backlight compensation; 0 = off, otherwise on */ -#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) -#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) - - /* Flickerless mode; = 0 off, otherwise on */ -#define VIDIOCPWCSFLICKER _IOW('v', 208, int) -#define VIDIOCPWCGFLICKER _IOR('v', 208, int) - - /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ -#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) -#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) - - /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ -#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) - - /* Motorized pan & tilt functions */ -#define VIDIOCPWCMPTRESET _IOW('v', 211, int) -#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) -#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) - - /* Get the USB set-video command; needed for initializing libpwcx */ -#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) -struct pwc_table_init_buffer { - int len; - char *buffer; - -}; -#define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) - -#endif diff --git a/pwc-ioctl.h-pwc8.0 b/pwc-ioctl.h-pwc8.0 deleted file mode 100644 index 0161986..0000000 --- a/pwc-ioctl.h-pwc8.0 +++ /dev/null @@ -1,229 +0,0 @@ -#ifndef PWC_IOCTL_H -#define PWC_IOCTL_H - -/* (C) 2001-2003 Nemosoft Unv. webcam@smcc.demon.nl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* This is pwc-ioctl.h belonging to PWC 8.10 */ - -/* - Changes - 2001/08/03 Alvarado Added ioctl constants to access methods for - changing white balance and red/blue gains - 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE - */ - -/* These are private ioctl() commands, specific for the Philips webcams. - They contain functions not found in other webcams, and settings not - specified in the Video4Linux API. - - The #define names are built up like follows: - VIDIOC VIDeo IOCtl prefix - PWC Philps WebCam - G optional: Get - S optional: Set - ... the function - */ - - - - -/* The frame rate is encoded in the video_window.flags parameter using - the upper 16 bits, since some flags are defined nowadays. The following - defines provide a mask and shift to filter out this value. - - In 'Snapshot' mode the camera freezes its automatic exposure and colour - balance controls. - */ -#define PWC_FPS_SHIFT 16 -#define PWC_FPS_MASK 0x00FF0000 -#define PWC_FPS_FRMASK 0x003F0000 -#define PWC_FPS_SNAPSHOT 0x00400000 - - - -struct pwc_probe -{ - char name[32]; - int type; -}; - - -/* pwc_whitebalance.mode values */ -#define PWC_WB_INDOOR 0 -#define PWC_WB_OUTDOOR 1 -#define PWC_WB_FL 2 -#define PWC_WB_MANUAL 3 -#define PWC_WB_AUTO 4 - -/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). - Set mode to one of the PWC_WB_* values above. - *red and *blue are the respective gains of these colour components inside - the camera; range 0..65535 - When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; - otherwise undefined. - 'read_red' and 'read_blue' are read-only. -*/ - -struct pwc_whitebalance -{ - int mode; - int manual_red, manual_blue; /* R/W */ - int read_red, read_blue; /* R/O */ -}; - -/* - 'control_speed' and 'control_delay' are used in automatic whitebalance mode, - and tell the camera how fast it should react to changes in lighting, and - with how much delay. Valid values are 0..65535. -*/ -struct pwc_wb_speed -{ - int control_speed; - int control_delay; - -}; - -/* Used with VIDIOCPWC[SG]LED */ -struct pwc_leds -{ - int led_on; /* Led on-time; range = 0..25000 */ - int led_off; /* Led off-time; range = 0..25000 */ -}; - -/* Image size (used with GREALSIZE) */ -struct pwc_imagesize -{ - int width; - int height; -}; - -/* Defines and structures for Motorized Pan & Tilt */ -#define PWC_MPT_PAN 0x01 -#define PWC_MPT_TILT 0x02 -#define PWC_MPT_TIMEOUT 0x04 /* for status */ - -/* Set angles; when absolute = 1, the angle is absolute and the - driver calculates the relative offset for you. This can only - be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns - absolute angles. - */ -struct pwc_mpt_angles -{ - int absolute; /* write-only */ - int pan; /* degrees * 100 */ - int tilt; /* degress * 100 */ - int zoom; /* N/A, set to -1 */ -}; - -/* Range of angles of the camera, both horizontally and vertically. - The zoom is not used, maybe in the future... - - */ -struct pwc_mpt_range -{ - int pan_min, pan_max; /* degrees * 100 */ - int tilt_min, tilt_max; - int zoom_min, zoom_max; /* -1, -1 */ -}; - -struct pwc_mpt_status -{ - int status; - int time_pan; - int time_tilt; -}; - - - /* Restore user settings */ -#define VIDIOCPWCRUSER _IO('v', 192) - /* Save user settings */ -#define VIDIOCPWCSUSER _IO('v', 193) - /* Restore factory settings */ -#define VIDIOCPWCFACTORY _IO('v', 194) - - /* You can manipulate the compression factor. A compression preference of 0 - means use uncompressed modes when available; 1 is low compression, 2 is - medium and 3 is high compression preferred. Of course, the higher the - compression, the lower the bandwidth used but more chance of artefacts - in the image. The driver automatically chooses a higher compression when - the preferred mode is not available. - */ - /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ -#define VIDIOCPWCSCQUAL _IOW('v', 195, int) - /* Get preferred compression quality */ -#define VIDIOCPWCGCQUAL _IOR('v', 195, int) - - - /* This is a probe function; since so many devices are supported, it - becomes difficult to include all the names in programs that want to - check for the enhanced Philips stuff. So in stead, try this PROBE; - it returns a structure with the original name, and the corresponding - Philips type. - To use, fill the structure with zeroes, call PROBE and if that succeeds, - compare the name with that returned from VIDIOCGCAP; they should be the - same. If so, you can be assured it is a Philips (OEM) cam and the type - is valid. - */ -#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) - - /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ -#define VIDIOCPWCSAGC _IOW('v', 200, int) - /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCGAGC _IOR('v', 200, int) - /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) - - /* Color compensation (Auto White Balance) */ -#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) -#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) - - /* Auto WB speed */ -#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) -#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) - - /* LEDs on/off/blink; int range 0..65535 */ -#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) -#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) - - /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ -#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) -#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) - - /* Backlight compensation; 0 = off, otherwise on */ -#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) -#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) - - /* Flickerless mode; = 0 off, otherwise on */ -#define VIDIOCPWCSFLICKER _IOW('v', 208, int) -#define VIDIOCPWCGFLICKER _IOR('v', 208, int) - - /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ -#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) -#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) - - /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ -#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) - - /* Motorized pan & tilt functions */ -#define VIDIOCPWCMPTRESET _IOW('v', 211, int) -#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) -#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) - -#endif diff --git a/pwc-ioctl.h-pwc9.0.1 b/pwc-ioctl.h-pwc9.0.1 deleted file mode 100644 index 2535a3c..0000000 --- a/pwc-ioctl.h-pwc9.0.1 +++ /dev/null @@ -1,279 +0,0 @@ -#ifndef PWC_IOCTL_H -#define PWC_IOCTL_H - -/* (C) 2001-2004 Nemosoft Unv. webcam@smcc.demon.nl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* This is pwc-ioctl.h belonging to PWC 8.12.1 - It contains structures and defines to communicate from user space - directly to the driver. - */ - -/* - Changes - 2001/08/03 Alvarado Added ioctl constants to access methods for - changing white balance and red/blue gains - 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE - 2003/12/13 Nemosft Unv. Some modifications to make interfacing to - PWCX easier - */ - -/* These are private ioctl() commands, specific for the Philips webcams. - They contain functions not found in other webcams, and settings not - specified in the Video4Linux API. - - The #define names are built up like follows: - VIDIOC VIDeo IOCtl prefix - PWC Philps WebCam - G optional: Get - S optional: Set - ... the function - */ - - - /* Enumeration of image sizes */ -#define PSZ_SQCIF 0x00 -#define PSZ_QSIF 0x01 -#define PSZ_QCIF 0x02 -#define PSZ_SIF 0x03 -#define PSZ_CIF 0x04 -#define PSZ_VGA 0x05 -#define PSZ_MAX 6 - - -/* The frame rate is encoded in the video_window.flags parameter using - the upper 16 bits, since some flags are defined nowadays. The following - defines provide a mask and shift to filter out this value. - - In 'Snapshot' mode the camera freezes its automatic exposure and colour - balance controls. - */ -#define PWC_FPS_SHIFT 16 -#define PWC_FPS_MASK 0x00FF0000 -#define PWC_FPS_FRMASK 0x003F0000 -#define PWC_FPS_SNAPSHOT 0x00400000 - - -/* structure for transfering x & y coordinates */ -struct pwc_coord -{ - int x, y; /* guess what */ - int size; /* size, or offset */ -}; - - -/* Used with VIDIOCPWCPROBE */ -struct pwc_probe -{ - char name[32]; - int type; -}; - -struct pwc_serial -{ - char serial[30]; /* String with serial number. Contains terminating 0 */ -}; - -/* pwc_whitebalance.mode values */ -#define PWC_WB_INDOOR 0 -#define PWC_WB_OUTDOOR 1 -#define PWC_WB_FL 2 -#define PWC_WB_MANUAL 3 -#define PWC_WB_AUTO 4 - -/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). - Set mode to one of the PWC_WB_* values above. - *red and *blue are the respective gains of these colour components inside - the camera; range 0..65535 - When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; - otherwise undefined. - 'read_red' and 'read_blue' are read-only. -*/ -struct pwc_whitebalance -{ - int mode; - int manual_red, manual_blue; /* R/W */ - int read_red, read_blue; /* R/O */ -}; - -/* - 'control_speed' and 'control_delay' are used in automatic whitebalance mode, - and tell the camera how fast it should react to changes in lighting, and - with how much delay. Valid values are 0..65535. -*/ -struct pwc_wb_speed -{ - int control_speed; - int control_delay; - -}; - -/* Used with VIDIOCPWC[SG]LED */ -struct pwc_leds -{ - int led_on; /* Led on-time; range = 0..25000 */ - int led_off; /* Led off-time; range = 0..25000 */ -}; - -/* Image size (used with GREALSIZE) */ -struct pwc_imagesize -{ - int width; - int height; -}; - -/* Defines and structures for Motorized Pan & Tilt */ -#define PWC_MPT_PAN 0x01 -#define PWC_MPT_TILT 0x02 -#define PWC_MPT_TIMEOUT 0x04 /* for status */ - -/* Set angles; when absolute != 0, the angle is absolute and the - driver calculates the relative offset for you. This can only - be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns - absolute angles. - */ -struct pwc_mpt_angles -{ - int absolute; /* write-only */ - int pan; /* degrees * 100 */ - int tilt; /* degress * 100 */ -}; - -/* Range of angles of the camera, both horizontally and vertically. - */ -struct pwc_mpt_range -{ - int pan_min, pan_max; /* degrees * 100 */ - int tilt_min, tilt_max; -}; - -struct pwc_mpt_status -{ - int status; - int time_pan; - int time_tilt; -}; - - -/* This is used for out-of-kernel decompression. With it, you can get - all the necessary information to initialize and use the decompressor - routines in standalone applications. - */ -struct pwc_video_command -{ - int type; /* camera type (645, 675, 730, etc.) */ - int release; /* release number */ - - int size; /* one of PSZ_* */ - int alternate; - int command_len; /* length of USB video command */ - unsigned char command_buf[13]; /* Actual USB video command */ - int bandlength; /* >0 = compressed */ - int frame_size; /* Size of one (un)compressed frame */ -}; - -/* Flags for PWCX subroutines. Not all modules honour all flags. */ -#define PWCX_FLAG_PLANAR 0x0001 -#define PWCX_FLAG_BAYER 0x0008 - - -/* IOCTL definitions */ - - /* Restore user settings */ -#define VIDIOCPWCRUSER _IO('v', 192) - /* Save user settings */ -#define VIDIOCPWCSUSER _IO('v', 193) - /* Restore factory settings */ -#define VIDIOCPWCFACTORY _IO('v', 194) - - /* You can manipulate the compression factor. A compression preference of 0 - means use uncompressed modes when available; 1 is low compression, 2 is - medium and 3 is high compression preferred. Of course, the higher the - compression, the lower the bandwidth used but more chance of artefacts - in the image. The driver automatically chooses a higher compression when - the preferred mode is not available. - */ - /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ -#define VIDIOCPWCSCQUAL _IOW('v', 195, int) - /* Get preferred compression quality */ -#define VIDIOCPWCGCQUAL _IOR('v', 195, int) - - -/* Retrieve serial number of camera */ -#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) - - /* This is a probe function; since so many devices are supported, it - becomes difficult to include all the names in programs that want to - check for the enhanced Philips stuff. So in stead, try this PROBE; - it returns a structure with the original name, and the corresponding - Philips type. - To use, fill the structure with zeroes, call PROBE and if that succeeds, - compare the name with that returned from VIDIOCGCAP; they should be the - same. If so, you can be assured it is a Philips (OEM) cam and the type - is valid. - */ -#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) - - /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ -#define VIDIOCPWCSAGC _IOW('v', 200, int) - /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCGAGC _IOR('v', 200, int) - /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ -#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) - - /* Color compensation (Auto White Balance) */ -#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) -#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) - - /* Auto WB speed */ -#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) -#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) - - /* LEDs on/off/blink; int range 0..65535 */ -#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) -#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) - - /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ -#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) -#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) - - /* Backlight compensation; 0 = off, otherwise on */ -#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) -#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) - - /* Flickerless mode; = 0 off, otherwise on */ -#define VIDIOCPWCSFLICKER _IOW('v', 208, int) -#define VIDIOCPWCGFLICKER _IOR('v', 208, int) - - /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ -#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) -#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) - - /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ -#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) - - /* Motorized pan & tilt functions */ -#define VIDIOCPWCMPTRESET _IOW('v', 211, int) -#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) -#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) -#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) - - /* Get the USB set-video command; needed for initializing libpwcx */ -#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) - -#endif diff --git a/raspicam/README.txt b/raspicam/README.txt new file mode 100644 index 0000000..09a1c6b --- /dev/null +++ b/raspicam/README.txt @@ -0,0 +1,11 @@ +The files in this directory are used in the MMAL/RaspberryPI camera +support code. The files were taken from the Raspberry PI userland git +repository: + +https://github.com/raspberrypi/userland + +The files are unchanged from the userland versions. + +They are used to parse an options string and setup the camera +parameters appropriately. The format of the string is the same as +other raspberry pi camera tools. diff --git a/raspicam/RaspiCLI.c b/raspicam/RaspiCLI.c new file mode 100644 index 0000000..9f858f4 --- /dev/null +++ b/raspicam/RaspiCLI.c @@ -0,0 +1,155 @@ +/* +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, James Hughes +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file RaspiCLI.c + * Code for handling command line parameters + * + * \date 4th March 2013 + * \Author: James Hughes + * + * Description + * + * Some functions/structures for command line parameter parsing + * + */ +#include +#include +#include +#include + +#include "interface/vcos/vcos.h" + +#include "RaspiCLI.h" + + +/** + * Convert a string from command line to a comand_id from the list + * + * @param commands Array of command to check + * @param num_command Number of commands in the array + * @param arg String to search for in the list + * @param num_parameters Returns the number of parameters used by the command + * + * @return command ID if found, -1 if not found + * + */ +int raspicli_get_command_id(const COMMAND_LIST *commands, const int num_commands, const char *arg, int *num_parameters) +{ + int command_id = -1; + int j; + + vcos_assert(commands); + vcos_assert(num_parameters); + vcos_assert(arg); + + if (!commands || !num_parameters || !arg) + return -1; + + for (j = 0; j < num_commands; j++) + { + if (!strcmp(arg, commands[j].command) || + !strcmp(arg, commands[j].abbrev)) + { + // match + command_id = commands[j].id; + *num_parameters = commands[j].num_parameters; + break; + } + } + + return command_id; +} + + +/** + * Display the list of commands in help format + * + * @param commands Array of command to check + * @param num_command Number of commands in the arry + * + * + */ +void raspicli_display_help(const COMMAND_LIST *commands, const int num_commands) +{ + int i; + + vcos_assert(commands); + + if (!commands) + return; + + for (i = 0; i < num_commands; i++) + { + fprintf(stdout, "-%s, -%s\t: %s\n", commands[i].abbrev, + commands[i].command, commands[i].help); + } +} + + +/** + * Function to take a string, a mapping, and return the int equivalent + * @param str Incoming string to match + * @param map Mapping data + * @param num_refs The number of items in the mapping data + * @return The integer match for the string, or -1 if no match + */ +int raspicli_map_xref(const char *str, const XREF_T *map, int num_refs) +{ + int i; + + for (i=0;i +#include +#include + +#include "interface/vcos/vcos.h" + +#include "interface/vmcs_host/vc_vchi_gencmd.h" +#include "interface/mmal/mmal.h" +#include "interface/mmal/mmal_logging.h" +#include "interface/mmal/util/mmal_util.h" +#include "interface/mmal/util/mmal_util_params.h" +#include "interface/mmal/util/mmal_default_components.h" +#include "RaspiCamControl.h" +#include "RaspiCLI.h" + +/// Structure to cross reference exposure strings against the MMAL parameter equivalent +static XREF_T exposure_map[] = +{ + {"off", MMAL_PARAM_EXPOSUREMODE_OFF}, + {"auto", MMAL_PARAM_EXPOSUREMODE_AUTO}, + {"night", MMAL_PARAM_EXPOSUREMODE_NIGHT}, + {"nightpreview", MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW}, + {"backlight", MMAL_PARAM_EXPOSUREMODE_BACKLIGHT}, + {"spotlight", MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT}, + {"sports", MMAL_PARAM_EXPOSUREMODE_SPORTS}, + {"snow", MMAL_PARAM_EXPOSUREMODE_SNOW}, + {"beach", MMAL_PARAM_EXPOSUREMODE_BEACH}, + {"verylong", MMAL_PARAM_EXPOSUREMODE_VERYLONG}, + {"fixedfps", MMAL_PARAM_EXPOSUREMODE_FIXEDFPS}, + {"antishake", MMAL_PARAM_EXPOSUREMODE_ANTISHAKE}, + {"fireworks", MMAL_PARAM_EXPOSUREMODE_FIREWORKS} +}; + +static const int exposure_map_size = sizeof(exposure_map) / sizeof(exposure_map[0]); + +/// Structure to cross reference awb strings against the MMAL parameter equivalent +static XREF_T awb_map[] = +{ + {"off", MMAL_PARAM_AWBMODE_OFF}, + {"auto", MMAL_PARAM_AWBMODE_AUTO}, + {"sun", MMAL_PARAM_AWBMODE_SUNLIGHT}, + {"cloud", MMAL_PARAM_AWBMODE_CLOUDY}, + {"shade", MMAL_PARAM_AWBMODE_SHADE}, + {"tungsten", MMAL_PARAM_AWBMODE_TUNGSTEN}, + {"fluorescent", MMAL_PARAM_AWBMODE_FLUORESCENT}, + {"incandescent", MMAL_PARAM_AWBMODE_INCANDESCENT}, + {"flash", MMAL_PARAM_AWBMODE_FLASH}, + {"horizon", MMAL_PARAM_AWBMODE_HORIZON} +}; + +static const int awb_map_size = sizeof(awb_map) / sizeof(awb_map[0]); + +/// Structure to cross reference image effect against the MMAL parameter equivalent +static XREF_T imagefx_map[] = +{ + {"none", MMAL_PARAM_IMAGEFX_NONE}, + {"negative", MMAL_PARAM_IMAGEFX_NEGATIVE}, + {"solarise", MMAL_PARAM_IMAGEFX_SOLARIZE}, + {"sketch", MMAL_PARAM_IMAGEFX_SKETCH}, + {"denoise", MMAL_PARAM_IMAGEFX_DENOISE}, + {"emboss", MMAL_PARAM_IMAGEFX_EMBOSS}, + {"oilpaint", MMAL_PARAM_IMAGEFX_OILPAINT}, + {"hatch", MMAL_PARAM_IMAGEFX_HATCH}, + {"gpen", MMAL_PARAM_IMAGEFX_GPEN}, + {"pastel", MMAL_PARAM_IMAGEFX_PASTEL}, + {"watercolour", MMAL_PARAM_IMAGEFX_WATERCOLOUR}, + {"film", MMAL_PARAM_IMAGEFX_FILM}, + {"blur", MMAL_PARAM_IMAGEFX_BLUR}, + {"saturation", MMAL_PARAM_IMAGEFX_SATURATION}, + {"colourswap", MMAL_PARAM_IMAGEFX_COLOURSWAP}, + {"washedout", MMAL_PARAM_IMAGEFX_WASHEDOUT}, + {"posterise", MMAL_PARAM_IMAGEFX_POSTERISE}, + {"colourpoint", MMAL_PARAM_IMAGEFX_COLOURPOINT}, + {"colourbalance", MMAL_PARAM_IMAGEFX_COLOURBALANCE}, + {"cartoon", MMAL_PARAM_IMAGEFX_CARTOON} + }; + +static const int imagefx_map_size = sizeof(imagefx_map) / sizeof(imagefx_map[0]); + +static XREF_T metering_mode_map[] = +{ + {"average", MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE}, + {"spot", MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT}, + {"backlit", MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT}, + {"matrix", MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX} +}; + +static const int metering_mode_map_size = sizeof(metering_mode_map)/sizeof(metering_mode_map[0]); + +static XREF_T drc_mode_map[] = +{ + {"off", MMAL_PARAMETER_DRC_STRENGTH_OFF}, + {"low", MMAL_PARAMETER_DRC_STRENGTH_LOW}, + {"med", MMAL_PARAMETER_DRC_STRENGTH_MEDIUM}, + {"high", MMAL_PARAMETER_DRC_STRENGTH_HIGH} +}; + +static const int drc_mode_map_size = sizeof(drc_mode_map)/sizeof(drc_mode_map[0]); + +static XREF_T stereo_mode_map[] = +{ + {"off", MMAL_STEREOSCOPIC_MODE_NONE}, + {"sbs", MMAL_STEREOSCOPIC_MODE_SIDE_BY_SIDE}, + {"tb", MMAL_STEREOSCOPIC_MODE_TOP_BOTTOM}, +}; + +static const int stereo_mode_map_size = sizeof(stereo_mode_map)/sizeof(stereo_mode_map[0]); + + +#define CommandSharpness 0 +#define CommandContrast 1 +#define CommandBrightness 2 +#define CommandSaturation 3 +#define CommandISO 4 +#define CommandVideoStab 5 +#define CommandEVComp 6 +#define CommandExposure 7 +#define CommandAWB 8 +#define CommandImageFX 9 +#define CommandColourFX 10 +#define CommandMeterMode 11 +#define CommandRotation 12 +#define CommandHFlip 13 +#define CommandVFlip 14 +#define CommandROI 15 +#define CommandShutterSpeed 16 +#define CommandAwbGains 17 +#define CommandDRCLevel 18 +#define CommandStatsPass 19 +#define CommandAnnotate 20 +#define CommandStereoMode 21 +#define CommandStereoDecimate 22 +#define CommandStereoSwap 23 +#define CommandAnnotateExtras 24 + +static COMMAND_LIST cmdline_commands[] = +{ + {CommandSharpness, "-sharpness", "sh", "Set image sharpness (-100 to 100)", 1}, + {CommandContrast, "-contrast", "co", "Set image contrast (-100 to 100)", 1}, + {CommandBrightness, "-brightness","br", "Set image brightness (0 to 100)", 1}, + {CommandSaturation, "-saturation","sa", "Set image saturation (-100 to 100)", 1}, + {CommandISO, "-ISO", "ISO","Set capture ISO", 1}, + {CommandVideoStab, "-vstab", "vs", "Turn on video stabilisation", 0}, + {CommandEVComp, "-ev", "ev", "Set EV compensation - steps of 1/6 stop", 1}, + {CommandExposure, "-exposure", "ex", "Set exposure mode (see Notes)", 1}, + {CommandAWB, "-awb", "awb","Set AWB mode (see Notes)", 1}, + {CommandImageFX, "-imxfx", "ifx","Set image effect (see Notes)", 1}, + {CommandColourFX, "-colfx", "cfx","Set colour effect (U:V)", 1}, + {CommandMeterMode, "-metering", "mm", "Set metering mode (see Notes)", 1}, + {CommandRotation, "-rotation", "rot","Set image rotation (0-359)", 1}, + {CommandHFlip, "-hflip", "hf", "Set horizontal flip", 0}, + {CommandVFlip, "-vflip", "vf", "Set vertical flip", 0}, + {CommandROI, "-roi", "roi","Set region of interest (x,y,w,d as normalised coordinates [0.0-1.0])", 1}, + {CommandShutterSpeed,"-shutter", "ss", "Set shutter speed in microseconds", 1}, + {CommandAwbGains, "-awbgains", "awbg", "Set AWB gains - AWB mode must be off", 1}, + {CommandDRCLevel, "-drc", "drc", "Set DRC Level (see Notes)", 1}, + {CommandStatsPass, "-stats", "st", "Force recomputation of statistics on stills capture pass"}, + {CommandAnnotate, "-annotate", "a", "Enable/Set annotate flags or text", 1}, + {CommandStereoMode, "-stereo", "3d", "Select stereoscopic mode", 1}, + {CommandStereoDecimate,"-decimate","dec", "Half width/height of stereo image"}, + {CommandStereoSwap, "-3dswap", "3dswap", "Swap camera order for stereoscopic"}, + {CommandAnnotateExtras,"-annotateex","ae", "Set extra annotation parameters (text size, text colour(hex YUV), bg colour(hex YUV))", 2}, +}; + +static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]); + + +#define parameter_reset -99999 + +/** + * Update the passed in parameter according to the rest of the parameters + * passed in. + * + * + * @return 0 if reached end of cycle for this parameter, !0 otherwise + */ +static int update_cycle_parameter(int *option, int min, int max, int increment) +{ + vcos_assert(option); + if (!option) + return 0; + + if (*option == parameter_reset) + *option = min - increment; + + *option += increment; + + if (*option > max) + { + *option = parameter_reset; + return 0; + } + else + return 1; +} + + +/** + * Test/Demo code to cycle through a bunch of camera settings + * This code is pretty hacky so please don't complain!! + * It only does stuff that should have a visual impact (hence demo!) + * This will override any user supplied parameters + * + * Each call of this function will move on to the next setting + * + * @param camera Pointer to the camera to change settings on. + * @return 0 if reached end of complete sequence, !0 otherwise + */ + +int raspicamcontrol_cycle_test(MMAL_COMPONENT_T *camera) +{ + static int parameter = 0; + static int parameter_option = parameter_reset; // which value the parameter currently has + + vcos_assert(camera); + + // We are going to cycle through all the relevant entries in the parameter block + // and send options to the camera. + if (parameter == 0) + { + // sharpness + if (update_cycle_parameter(¶meter_option, -100, 100, 10)) + raspicamcontrol_set_sharpness(camera, parameter_option); + else + { + raspicamcontrol_set_sharpness(camera, 0); + parameter++; + } + } + else + if (parameter == 1) + { + // contrast + if (update_cycle_parameter(¶meter_option, -100, 100, 10)) + raspicamcontrol_set_contrast(camera, parameter_option); + else + { + raspicamcontrol_set_contrast(camera, 0); + parameter++; + } + } + else + if (parameter == 2) + { + // brightness + if (update_cycle_parameter(¶meter_option, 0, 100, 10)) + raspicamcontrol_set_brightness(camera, parameter_option); + else + { + raspicamcontrol_set_brightness(camera, 50); + parameter++; + } + } + else + if (parameter == 3) + { + // contrast + if (update_cycle_parameter(¶meter_option, -100, 100, 10)) + raspicamcontrol_set_saturation(camera, parameter_option); + else + { + parameter++; + raspicamcontrol_set_saturation(camera, 0); + } + } + else + if (parameter == 4) + { + // EV + if (update_cycle_parameter(¶meter_option, -10, 10, 4)) + raspicamcontrol_set_exposure_compensation(camera, parameter_option); + else + { + raspicamcontrol_set_exposure_compensation(camera, 0); + parameter++; + } + } + else + if (parameter == 5) + { + // MMAL_PARAM_EXPOSUREMODE_T + if (update_cycle_parameter(¶meter_option, 0, exposure_map_size, 1)) + raspicamcontrol_set_exposure_mode(camera, exposure_map[parameter_option].mmal_mode); + else + { + raspicamcontrol_set_exposure_mode(camera, MMAL_PARAM_EXPOSUREMODE_AUTO); + parameter++; + } + } + else + if (parameter == 6) + { + // MMAL_PARAM_AWB_T + if (update_cycle_parameter(¶meter_option, 0, awb_map_size, 1)) + raspicamcontrol_set_awb_mode(camera, awb_map[parameter_option].mmal_mode); + else + { + raspicamcontrol_set_awb_mode(camera, MMAL_PARAM_AWBMODE_AUTO); + parameter++; + } + } + if (parameter == 7) + { + // MMAL_PARAM_IMAGEFX_T + if (update_cycle_parameter(¶meter_option, 0, imagefx_map_size, 1)) + raspicamcontrol_set_imageFX(camera, imagefx_map[parameter_option].mmal_mode); + else + { + raspicamcontrol_set_imageFX(camera, MMAL_PARAM_IMAGEFX_NONE); + parameter++; + } + } + if (parameter == 8) + { + MMAL_PARAM_COLOURFX_T colfx = {0,0,0}; + switch (parameter_option) + { + case parameter_reset : + parameter_option = 1; + colfx.u = 128; + colfx.v = 128; + break; + case 1 : + parameter_option = 2; + colfx.u = 100; + colfx.v = 200; + break; + case 2 : + parameter_option = parameter_reset; + colfx.enable = 0; + parameter++; + break; + } + raspicamcontrol_set_colourFX(camera, &colfx); + } + + // Orientation + if (parameter == 9) + { + switch (parameter_option) + { + case parameter_reset: + raspicamcontrol_set_rotation(camera, 90); + parameter_option = 1; + break; + + case 1 : + raspicamcontrol_set_rotation(camera, 180); + parameter_option = 2; + break; + + case 2 : + raspicamcontrol_set_rotation(camera, 270); + parameter_option = 3; + break; + + case 3 : + { + raspicamcontrol_set_rotation(camera, 0); + raspicamcontrol_set_flips(camera, 1,0); + parameter_option = 4; + break; + } + case 4 : + { + raspicamcontrol_set_flips(camera, 0,1); + parameter_option = 5; + break; + } + case 5 : + { + raspicamcontrol_set_flips(camera, 1, 1); + parameter_option = 6; + break; + } + case 6 : + { + raspicamcontrol_set_flips(camera, 0, 0); + parameter_option = parameter_reset; + parameter++; + break; + } + } + } + + if (parameter == 10) + { + parameter = 1; + return 0; + } + + return 1; +} + + + +/** + * Convert string to the MMAL parameter for exposure mode + * @param str Incoming string to match + * @return MMAL parameter matching the string, or the AUTO option if no match found + */ +static MMAL_PARAM_EXPOSUREMODE_T exposure_mode_from_string(const char *str) +{ + int i = raspicli_map_xref(str, exposure_map, exposure_map_size); + + if( i != -1) + return (MMAL_PARAM_EXPOSUREMODE_T)i; + + vcos_log_error("Unknown exposure mode: %s", str); + return MMAL_PARAM_EXPOSUREMODE_AUTO; +} + +/** + * Convert string to the MMAL parameter for AWB mode + * @param str Incoming string to match + * @return MMAL parameter matching the string, or the AUTO option if no match found + */ +static MMAL_PARAM_AWBMODE_T awb_mode_from_string(const char *str) +{ + int i = raspicli_map_xref(str, awb_map, awb_map_size); + + if( i != -1) + return (MMAL_PARAM_AWBMODE_T)i; + + vcos_log_error("Unknown awb mode: %s", str); + return MMAL_PARAM_AWBMODE_AUTO; +} + +/** + * Convert string to the MMAL parameter for image effects mode + * @param str Incoming string to match + * @return MMAL parameter matching the strong, or the AUTO option if no match found + */ +MMAL_PARAM_IMAGEFX_T imagefx_mode_from_string(const char *str) +{ + int i = raspicli_map_xref(str, imagefx_map, imagefx_map_size); + + if( i != -1) + return (MMAL_PARAM_IMAGEFX_T)i; + + vcos_log_error("Unknown image fx: %s", str); + return MMAL_PARAM_IMAGEFX_NONE; +} + +/** + * Convert string to the MMAL parameter for exposure metering mode + * @param str Incoming string to match + * @return MMAL parameter matching the string, or the AUTO option if no match found + */ +static MMAL_PARAM_EXPOSUREMETERINGMODE_T metering_mode_from_string(const char *str) +{ + int i = raspicli_map_xref(str, metering_mode_map, metering_mode_map_size); + + if( i != -1) + return (MMAL_PARAM_EXPOSUREMETERINGMODE_T)i; + + vcos_log_error("Unknown metering mode: %s", str); + return MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; +} + +/** + * Convert string to the MMAL parameter for DRC level + * @param str Incoming string to match + * @return MMAL parameter matching the string, or the AUTO option if no match found + */ +static MMAL_PARAMETER_DRC_STRENGTH_T drc_mode_from_string(const char *str) +{ + int i = raspicli_map_xref(str, drc_mode_map, drc_mode_map_size); + + if( i != -1) + return (MMAL_PARAMETER_DRC_STRENGTH_T)i; + + vcos_log_error("Unknown DRC level: %s", str); + return MMAL_PARAMETER_DRC_STRENGTH_OFF; +} + +/** + * Convert string to the MMAL parameter for exposure metering mode + * @param str Incoming string to match + * @return MMAL parameter matching the string, or the AUTO option if no match found + */ +static MMAL_STEREOSCOPIC_MODE_T stereo_mode_from_string(const char *str) +{ + int i = raspicli_map_xref(str, stereo_mode_map, stereo_mode_map_size); + + if( i != -1) + return (MMAL_STEREOSCOPIC_MODE_T)i; + + vcos_log_error("Unknown metering mode: %s", str); + return MMAL_STEREOSCOPIC_MODE_NONE; +} + +/** + * Parse a possible command pair - command and parameter + * @param arg1 Command + * @param arg2 Parameter (could be NULL) + * @return How many parameters were used, 0,1,2 + */ +int raspicamcontrol_parse_cmdline(RASPICAM_CAMERA_PARAMETERS *params, const char *arg1, const char *arg2) +{ + int command_id, used = 0, num_parameters; + + if (!arg1) + return 0; + + command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, arg1, &num_parameters); + + // If invalid command, or we are missing a parameter, drop out + if (command_id==-1 || (command_id != -1 && num_parameters > 0 && arg2 == NULL)) + return 0; + + switch (command_id) + { + case CommandSharpness : // sharpness - needs single number parameter + sscanf(arg2, "%d", ¶ms->sharpness); + used = 2; + break; + + case CommandContrast : // contrast - needs single number parameter + sscanf(arg2, "%d", ¶ms->contrast); + used = 2; + break; + + case CommandBrightness : // brightness - needs single number parameter + sscanf(arg2, "%d", ¶ms->brightness); + used = 2; + break; + + case CommandSaturation : // saturation - needs single number parameter + sscanf(arg2, "%d", ¶ms->saturation); + used = 2; + break; + + case CommandISO : // ISO - needs single number parameter + sscanf(arg2, "%d", ¶ms->ISO); + used = 2; + break; + + case CommandVideoStab : // video stabilisation - if here, its on + params->videoStabilisation = 1; + used = 1; + break; + + case CommandEVComp : // EV - needs single number parameter + sscanf(arg2, "%d", ¶ms->exposureCompensation); + used = 2; + break; + + case CommandExposure : // exposure mode - needs string + params->exposureMode = exposure_mode_from_string(arg2); + used = 2; + break; + + case CommandAWB : // AWB mode - needs single number parameter + params->awbMode = awb_mode_from_string(arg2); + used = 2; + break; + + case CommandImageFX : // Image FX - needs string + params->imageEffect = imagefx_mode_from_string(arg2); + used = 2; + break; + + case CommandColourFX : // Colour FX - needs string "u:v" + sscanf(arg2, "%d:%d", ¶ms->colourEffects.u, ¶ms->colourEffects.v); + params->colourEffects.enable = 1; + used = 2; + break; + + case CommandMeterMode: + params->exposureMeterMode = metering_mode_from_string(arg2); + used = 2; + break; + + case CommandRotation : // Rotation - degree + sscanf(arg2, "%d", ¶ms->rotation); + used = 2; + break; + + case CommandHFlip : + params->hflip = 1; + used = 1; + break; + + case CommandVFlip : + params->vflip = 1; + used = 1; + break; + + case CommandROI : + { + double x,y,w,h; + int args; + + args = sscanf(arg2, "%lf,%lf,%lf,%lf", &x,&y,&w,&h); + + if (args != 4 || x > 1.0 || y > 1.0 || w > 1.0 || h > 1.0) + { + return 0; + } + + // Make sure we stay within bounds + if (x + w > 1.0) + w = 1 - x; + + if (y + h > 1.0) + h = 1 - y; + + params->roi.x = x; + params->roi.y = y; + params->roi.w = w; + params->roi.h = h; + + used = 2; + break; + } + + case CommandShutterSpeed : // Shutter speed needs single number parameter + { + sscanf(arg2, "%d", ¶ms->shutter_speed); + used = 2; + break; + } + + case CommandAwbGains : + { + double r,b; + int args; + + args = sscanf(arg2, "%lf,%lf", &r,&b); + + if (args != 2 || r > 8.0 || b > 8.0) + { + return 0; + } + + params->awb_gains_r = r; + params->awb_gains_b = b; + + used = 2; + break; + } + + case CommandDRCLevel: + { + params->drc_level = drc_mode_from_string(arg2); + used = 2; + break; + } + + case CommandStatsPass: + { + params->stats_pass = MMAL_TRUE; + used = 1; + break; + } + + case CommandAnnotate: + { + char dummy; + unsigned int bitmask; + // If parameter is a number, assume its a bitmask, otherwise a string + if (sscanf(arg2, "%u%c", &bitmask, &dummy) == 1) + { + params->enable_annotate |= bitmask; + } + else + { + params->enable_annotate |= ANNOTATE_USER_TEXT; + //copy string char by char and replace "\n" with newline character + unsigned char c; + char const *s = arg2; + char *t = ¶ms->annotate_string[0]; + int n=0; + while ((c = *s++) && n < MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1) + { + if (c == '\\' && *s) + { + switch (c = *s++) + { + case 'n': + c = '\n'; + break; + + default: + c = '\\'; + s--; + break; + } + } + *(t++) = c; + n++; + } + *t='\0'; + + //params->annotate_string[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1] = '\0'; + } + used=2; + break; + } + + case CommandAnnotateExtras: + { + // 3 parameters - text size (6-80), text colour (Hex VVUUYY) and background colour (Hex VVUUYY) + sscanf(arg2, "%u,%X,%X", ¶ms->annotate_text_size, + ¶ms->annotate_text_colour, + ¶ms->annotate_bg_colour); + used=2; + break; + } + + case CommandStereoMode: + { + params->stereo_mode.mode = stereo_mode_from_string(arg2); + used = 2; + break; + } + + case CommandStereoDecimate: + { + params->stereo_mode.decimate = MMAL_TRUE; + used = 1; + break; + } + + case CommandStereoSwap: + { + params->stereo_mode.swap_eyes = MMAL_TRUE; + used = 1; + break; + } + + } + + return used; +} + +/** + * Display help for command line options + */ +void raspicamcontrol_display_help() +{ + int i; + + fprintf(stdout, "\nImage parameter commands\n\n"); + + raspicli_display_help(cmdline_commands, cmdline_commands_size); + + fprintf(stdout, "\n\nNotes\n\nExposure mode options :\n%s", exposure_map[0].mode ); + + for (i=1;iexposureMode, exposure_map, exposure_map_size); + const char *awb_mode = raspicli_unmap_xref(params->awbMode, awb_map, awb_map_size); + const char *image_effect = raspicli_unmap_xref(params->imageEffect, imagefx_map, imagefx_map_size); + const char *metering_mode = raspicli_unmap_xref(params->exposureMeterMode, metering_mode_map, metering_mode_map_size); + + fprintf(stderr, "Sharpness %d, Contrast %d, Brightness %d\n", params->sharpness, params->contrast, params->brightness); + fprintf(stderr, "Saturation %d, ISO %d, Video Stabilisation %s, Exposure compensation %d\n", params->saturation, params->ISO, params->videoStabilisation ? "Yes": "No", params->exposureCompensation); + fprintf(stderr, "Exposure Mode '%s', AWB Mode '%s', Image Effect '%s'\n", exp_mode, awb_mode, image_effect); + fprintf(stderr, "Metering Mode '%s', Colour Effect Enabled %s with U = %d, V = %d\n", metering_mode, params->colourEffects.enable ? "Yes":"No", params->colourEffects.u, params->colourEffects.v); + fprintf(stderr, "Rotation %d, hflip %s, vflip %s\n", params->rotation, params->hflip ? "Yes":"No",params->vflip ? "Yes":"No"); + fprintf(stderr, "ROI x %lf, y %f, w %f h %f\n", params->roi.x, params->roi.y, params->roi.w, params->roi.h); +} + +/** + * Convert a MMAL status return value to a simple boolean of success + * ALso displays a fault if code is not success + * + * @param status The error code to convert + * @return 0 if status is success, 1 otherwise + */ +int mmal_status_to_int(MMAL_STATUS_T status) +{ + if (status == MMAL_SUCCESS) + return 0; + else + { + switch (status) + { + case MMAL_ENOMEM : vcos_log_error("Out of memory"); break; + case MMAL_ENOSPC : vcos_log_error("Out of resources (other than memory)"); break; + case MMAL_EINVAL: vcos_log_error("Argument is invalid"); break; + case MMAL_ENOSYS : vcos_log_error("Function not implemented"); break; + case MMAL_ENOENT : vcos_log_error("No such file or directory"); break; + case MMAL_ENXIO : vcos_log_error("No such device or address"); break; + case MMAL_EIO : vcos_log_error("I/O error"); break; + case MMAL_ESPIPE : vcos_log_error("Illegal seek"); break; + case MMAL_ECORRUPT : vcos_log_error("Data is corrupt \attention FIXME: not POSIX"); break; + case MMAL_ENOTREADY :vcos_log_error("Component is not ready \attention FIXME: not POSIX"); break; + case MMAL_ECONFIG : vcos_log_error("Component is not configured \attention FIXME: not POSIX"); break; + case MMAL_EISCONN : vcos_log_error("Port is already connected "); break; + case MMAL_ENOTCONN : vcos_log_error("Port is disconnected"); break; + case MMAL_EAGAIN : vcos_log_error("Resource temporarily unavailable. Try again later"); break; + case MMAL_EFAULT : vcos_log_error("Bad address"); break; + default : vcos_log_error("Unknown status error"); break; + } + + return 1; + } +} + +/** + * Give the supplied parameter block a set of default values + * @params Pointer to parameter block + */ +void raspicamcontrol_set_defaults(RASPICAM_CAMERA_PARAMETERS *params) +{ + vcos_assert(params); + + params->sharpness = 0; + params->contrast = 0; + params->brightness = 50; + params->saturation = 0; + params->ISO = 0; // 0 = auto + params->videoStabilisation = 0; + params->exposureCompensation = 0; + params->exposureMode = MMAL_PARAM_EXPOSUREMODE_AUTO; + params->exposureMeterMode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; + params->awbMode = MMAL_PARAM_AWBMODE_AUTO; + params->imageEffect = MMAL_PARAM_IMAGEFX_NONE; + params->colourEffects.enable = 0; + params->colourEffects.u = 128; + params->colourEffects.v = 128; + params->rotation = 0; + params->hflip = params->vflip = 0; + params->roi.x = params->roi.y = 0.0; + params->roi.w = params->roi.h = 1.0; + params->shutter_speed = 0; // 0 = auto + params->awb_gains_r = 0; // Only have any function if AWB OFF is used. + params->awb_gains_b = 0; + params->drc_level = MMAL_PARAMETER_DRC_STRENGTH_OFF; + params->stats_pass = MMAL_FALSE; + params->enable_annotate = 0; + params->annotate_string[0] = '\0'; + params->annotate_text_size = 0; //Use firmware default + params->annotate_text_colour = -1; //Use firmware default + params->annotate_bg_colour = -1; //Use firmware default + params->stereo_mode.mode = MMAL_STEREOSCOPIC_MODE_NONE; + params->stereo_mode.decimate = MMAL_FALSE; + params->stereo_mode.swap_eyes = MMAL_FALSE; +} + +/** + * Get all the current camera parameters from specified camera component + * @param camera Pointer to camera component + * @param params Pointer to parameter block to accept settings + * @return 0 if successful, non-zero if unsuccessful + */ +int raspicamcontrol_get_all_parameters(MMAL_COMPONENT_T *camera, RASPICAM_CAMERA_PARAMETERS *params) +{ + vcos_assert(camera); + vcos_assert(params); + + if (!camera || !params) + return 1; + +/* TODO : Write these get functions + params->sharpness = raspicamcontrol_get_sharpness(camera); + params->contrast = raspicamcontrol_get_contrast(camera); + params->brightness = raspicamcontrol_get_brightness(camera); + params->saturation = raspicamcontrol_get_saturation(camera); + params->ISO = raspicamcontrol_get_ISO(camera); + params->videoStabilisation = raspicamcontrol_get_video_stabilisation(camera); + params->exposureCompensation = raspicamcontrol_get_exposure_compensation(camera); + params->exposureMode = raspicamcontrol_get_exposure_mode(camera); + params->awbMode = raspicamcontrol_get_awb_mode(camera); + params->imageEffect = raspicamcontrol_get_image_effect(camera); + params->colourEffects = raspicamcontrol_get_colour_effect(camera); + params->thumbnailConfig = raspicamcontrol_get_thumbnail_config(camera); +*/ + return 0; +} + +/** + * Set the specified camera to all the specified settings + * @param camera Pointer to camera component + * @param params Pointer to parameter block containing parameters + * @return 0 if successful, none-zero if unsuccessful. + */ +int raspicamcontrol_set_all_parameters(MMAL_COMPONENT_T *camera, const RASPICAM_CAMERA_PARAMETERS *params) +{ + int result; + + result = raspicamcontrol_set_saturation(camera, params->saturation); + result += raspicamcontrol_set_sharpness(camera, params->sharpness); + result += raspicamcontrol_set_contrast(camera, params->contrast); + result += raspicamcontrol_set_brightness(camera, params->brightness); + result += raspicamcontrol_set_ISO(camera, params->ISO); + result += raspicamcontrol_set_video_stabilisation(camera, params->videoStabilisation); + result += raspicamcontrol_set_exposure_compensation(camera, params->exposureCompensation); + result += raspicamcontrol_set_exposure_mode(camera, params->exposureMode); + result += raspicamcontrol_set_metering_mode(camera, params->exposureMeterMode); + result += raspicamcontrol_set_awb_mode(camera, params->awbMode); + result += raspicamcontrol_set_awb_gains(camera, params->awb_gains_r, params->awb_gains_b); + result += raspicamcontrol_set_imageFX(camera, params->imageEffect); + result += raspicamcontrol_set_colourFX(camera, ¶ms->colourEffects); + //result += raspicamcontrol_set_thumbnail_parameters(camera, ¶ms->thumbnailConfig); TODO Not working for some reason + result += raspicamcontrol_set_rotation(camera, params->rotation); + result += raspicamcontrol_set_flips(camera, params->hflip, params->vflip); + result += raspicamcontrol_set_ROI(camera, params->roi); + result += raspicamcontrol_set_shutter_speed(camera, params->shutter_speed); + result += raspicamcontrol_set_DRC(camera, params->drc_level); + result += raspicamcontrol_set_stats_pass(camera, params->stats_pass); + result += raspicamcontrol_set_annotate(camera, params->enable_annotate, params->annotate_string, + params->annotate_text_size, + params->annotate_text_colour, + params->annotate_bg_colour); + + return result; +} + +/** + * Adjust the saturation level for images + * @param camera Pointer to camera component + * @param saturation Value to adjust, -100 to 100 + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_saturation(MMAL_COMPONENT_T *camera, int saturation) +{ + int ret = 0; + + if (!camera) + return 1; + + if (saturation >= -100 && saturation <= 100) + { + MMAL_RATIONAL_T value = {saturation, 100}; + ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_SATURATION, value)); + } + else + { + vcos_log_error("Invalid saturation value"); + ret = 1; + } + + return ret; +} + +/** + * Set the sharpness of the image + * @param camera Pointer to camera component + * @param sharpness Sharpness adjustment -100 to 100 + */ +int raspicamcontrol_set_sharpness(MMAL_COMPONENT_T *camera, int sharpness) +{ + int ret = 0; + + if (!camera) + return 1; + + if (sharpness >= -100 && sharpness <= 100) + { + MMAL_RATIONAL_T value = {sharpness, 100}; + ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_SHARPNESS, value)); + } + else + { + vcos_log_error("Invalid sharpness value"); + ret = 1; + } + + return ret; +} + +/** + * Set the contrast adjustment for the image + * @param camera Pointer to camera component + * @param contrast Contrast adjustment -100 to 100 + * @return + */ +int raspicamcontrol_set_contrast(MMAL_COMPONENT_T *camera, int contrast) +{ + int ret = 0; + + if (!camera) + return 1; + + if (contrast >= -100 && contrast <= 100) + { + MMAL_RATIONAL_T value = {contrast, 100}; + ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_CONTRAST, value)); + } + else + { + vcos_log_error("Invalid contrast value"); + ret = 1; + } + + return ret; +} + +/** + * Adjust the brightness level for images + * @param camera Pointer to camera component + * @param brightness Value to adjust, 0 to 100 + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_brightness(MMAL_COMPONENT_T *camera, int brightness) +{ + int ret = 0; + + if (!camera) + return 1; + + if (brightness >= 0 && brightness <= 100) + { + MMAL_RATIONAL_T value = {brightness, 100}; + ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_BRIGHTNESS, value)); + } + else + { + vcos_log_error("Invalid brightness value"); + ret = 1; + } + + return ret; +} + +/** + * Adjust the ISO used for images + * @param camera Pointer to camera component + * @param ISO Value to set TODO : + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_ISO(MMAL_COMPONENT_T *camera, int ISO) +{ + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_ISO, ISO)); +} + +/** + * Adjust the metering mode for images + * @param camera Pointer to camera component + * @param saturation Value from following + * - MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE, + * - MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT, + * - MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT, + * - MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_metering_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMETERINGMODE_T m_mode ) +{ + MMAL_PARAMETER_EXPOSUREMETERINGMODE_T meter_mode = {{MMAL_PARAMETER_EXP_METERING_MODE,sizeof(meter_mode)}, + m_mode}; + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &meter_mode.hdr)); +} + + +/** + * Set the video stabilisation flag. Only used in video mode + * @param camera Pointer to camera component + * @param saturation Flag 0 off 1 on + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_video_stabilisation(MMAL_COMPONENT_T *camera, int vstabilisation) +{ + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set_boolean(camera->control, MMAL_PARAMETER_VIDEO_STABILISATION, vstabilisation)); +} + +/** + * Adjust the exposure compensation for images (EV) + * @param camera Pointer to camera component + * @param exp_comp Value to adjust, -10 to +10 + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_exposure_compensation(MMAL_COMPONENT_T *camera, int exp_comp) +{ + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set_int32(camera->control, MMAL_PARAMETER_EXPOSURE_COMP , exp_comp)); +} + + +/** + * Set exposure mode for images + * @param camera Pointer to camera component + * @param mode Exposure mode to set from + * - MMAL_PARAM_EXPOSUREMODE_OFF, + * - MMAL_PARAM_EXPOSUREMODE_AUTO, + * - MMAL_PARAM_EXPOSUREMODE_NIGHT, + * - MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW, + * - MMAL_PARAM_EXPOSUREMODE_BACKLIGHT, + * - MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT, + * - MMAL_PARAM_EXPOSUREMODE_SPORTS, + * - MMAL_PARAM_EXPOSUREMODE_SNOW, + * - MMAL_PARAM_EXPOSUREMODE_BEACH, + * - MMAL_PARAM_EXPOSUREMODE_VERYLONG, + * - MMAL_PARAM_EXPOSUREMODE_FIXEDFPS, + * - MMAL_PARAM_EXPOSUREMODE_ANTISHAKE, + * - MMAL_PARAM_EXPOSUREMODE_FIREWORKS, + * + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_exposure_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMODE_T mode) +{ + MMAL_PARAMETER_EXPOSUREMODE_T exp_mode = {{MMAL_PARAMETER_EXPOSURE_MODE,sizeof(exp_mode)}, mode}; + + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &exp_mode.hdr)); +} + + +/** + * Set the aWB (auto white balance) mode for images + * @param camera Pointer to camera component + * @param awb_mode Value to set from + * - MMAL_PARAM_AWBMODE_OFF, + * - MMAL_PARAM_AWBMODE_AUTO, + * - MMAL_PARAM_AWBMODE_SUNLIGHT, + * - MMAL_PARAM_AWBMODE_CLOUDY, + * - MMAL_PARAM_AWBMODE_SHADE, + * - MMAL_PARAM_AWBMODE_TUNGSTEN, + * - MMAL_PARAM_AWBMODE_FLUORESCENT, + * - MMAL_PARAM_AWBMODE_INCANDESCENT, + * - MMAL_PARAM_AWBMODE_FLASH, + * - MMAL_PARAM_AWBMODE_HORIZON, + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_awb_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_AWBMODE_T awb_mode) +{ + MMAL_PARAMETER_AWBMODE_T param = {{MMAL_PARAMETER_AWB_MODE,sizeof(param)}, awb_mode}; + + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, ¶m.hdr)); +} + +int raspicamcontrol_set_awb_gains(MMAL_COMPONENT_T *camera, float r_gain, float b_gain) +{ + MMAL_PARAMETER_AWB_GAINS_T param = {{MMAL_PARAMETER_CUSTOM_AWB_GAINS,sizeof(param)}, {0,0}, {0,0}}; + + if (!camera) + return 1; + + if (!r_gain || !b_gain) + return 0; + + param.r_gain.num = (unsigned int)(r_gain * 65536); + param.b_gain.num = (unsigned int)(b_gain * 65536); + param.r_gain.den = param.b_gain.den = 65536; + return mmal_status_to_int(mmal_port_parameter_set(camera->control, ¶m.hdr)); +} + +/** + * Set the image effect for the images + * @param camera Pointer to camera component + * @param imageFX Value from + * - MMAL_PARAM_IMAGEFX_NONE, + * - MMAL_PARAM_IMAGEFX_NEGATIVE, + * - MMAL_PARAM_IMAGEFX_SOLARIZE, + * - MMAL_PARAM_IMAGEFX_POSTERIZE, + * - MMAL_PARAM_IMAGEFX_WHITEBOARD, + * - MMAL_PARAM_IMAGEFX_BLACKBOARD, + * - MMAL_PARAM_IMAGEFX_SKETCH, + * - MMAL_PARAM_IMAGEFX_DENOISE, + * - MMAL_PARAM_IMAGEFX_EMBOSS, + * - MMAL_PARAM_IMAGEFX_OILPAINT, + * - MMAL_PARAM_IMAGEFX_HATCH, + * - MMAL_PARAM_IMAGEFX_GPEN, + * - MMAL_PARAM_IMAGEFX_PASTEL, + * - MMAL_PARAM_IMAGEFX_WATERCOLOUR, + * - MMAL_PARAM_IMAGEFX_FILM, + * - MMAL_PARAM_IMAGEFX_BLUR, + * - MMAL_PARAM_IMAGEFX_SATURATION, + * - MMAL_PARAM_IMAGEFX_COLOURSWAP, + * - MMAL_PARAM_IMAGEFX_WASHEDOUT, + * - MMAL_PARAM_IMAGEFX_POSTERISE, + * - MMAL_PARAM_IMAGEFX_COLOURPOINT, + * - MMAL_PARAM_IMAGEFX_COLOURBALANCE, + * - MMAL_PARAM_IMAGEFX_CARTOON, + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_imageFX(MMAL_COMPONENT_T *camera, MMAL_PARAM_IMAGEFX_T imageFX) +{ + MMAL_PARAMETER_IMAGEFX_T imgFX = {{MMAL_PARAMETER_IMAGE_EFFECT,sizeof(imgFX)}, imageFX}; + + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &imgFX.hdr)); +} + +/* TODO :what to do with the image effects parameters? + MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {{MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,sizeof(imfx_param)}, + imageFX, 0, {0}}; +mmal_port_parameter_set(camera->control, &imfx_param.hdr); + */ + +/** + * Set the colour effect for images (Set UV component) + * @param camera Pointer to camera component + * @param colourFX Contains enable state and U and V numbers to set (e.g. 128,128 = Black and white) + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_colourFX(MMAL_COMPONENT_T *camera, const MMAL_PARAM_COLOURFX_T *colourFX) +{ + MMAL_PARAMETER_COLOURFX_T colfx = {{MMAL_PARAMETER_COLOUR_EFFECT,sizeof(colfx)}, 0, 0, 0}; + + if (!camera) + return 1; + + colfx.enable = colourFX->enable; + colfx.u = colourFX->u; + colfx.v = colourFX->v; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &colfx.hdr)); + +} + + +/** + * Set the rotation of the image + * @param camera Pointer to camera component + * @param rotation Degree of rotation (any number, but will be converted to 0,90,180 or 270 only) + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_rotation(MMAL_COMPONENT_T *camera, int rotation) +{ + int ret; + int my_rotation = ((rotation % 360 ) / 90) * 90; + + ret = mmal_port_parameter_set_int32(camera->output[0], MMAL_PARAMETER_ROTATION, my_rotation); + mmal_port_parameter_set_int32(camera->output[1], MMAL_PARAMETER_ROTATION, my_rotation); + mmal_port_parameter_set_int32(camera->output[2], MMAL_PARAMETER_ROTATION, my_rotation); + + return ret; +} + +/** + * Set the flips state of the image + * @param camera Pointer to camera component + * @param hflip If true, horizontally flip the image + * @param vflip If true, vertically flip the image + * + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_flips(MMAL_COMPONENT_T *camera, int hflip, int vflip) +{ + MMAL_PARAMETER_MIRROR_T mirror = {{MMAL_PARAMETER_MIRROR, sizeof(MMAL_PARAMETER_MIRROR_T)}, MMAL_PARAM_MIRROR_NONE}; + + if (hflip && vflip) + mirror.value = MMAL_PARAM_MIRROR_BOTH; + else + if (hflip) + mirror.value = MMAL_PARAM_MIRROR_HORIZONTAL; + else + if (vflip) + mirror.value = MMAL_PARAM_MIRROR_VERTICAL; + + mmal_port_parameter_set(camera->output[0], &mirror.hdr); + mmal_port_parameter_set(camera->output[1], &mirror.hdr); + return mmal_port_parameter_set(camera->output[2], &mirror.hdr); +} + +/** + * Set the ROI of the sensor to use for captures/preview + * @param camera Pointer to camera component + * @param rect Normalised coordinates of ROI rectangle + * + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_ROI(MMAL_COMPONENT_T *camera, PARAM_FLOAT_RECT_T rect) +{ + MMAL_PARAMETER_INPUT_CROP_T crop = {{MMAL_PARAMETER_INPUT_CROP, sizeof(MMAL_PARAMETER_INPUT_CROP_T)}}; + + crop.rect.x = (65536 * rect.x); + crop.rect.y = (65536 * rect.y); + crop.rect.width = (65536 * rect.w); + crop.rect.height = (65536 * rect.h); + + return mmal_port_parameter_set(camera->control, &crop.hdr); +} + +/** + * Adjust the exposure time used for images + * @param camera Pointer to camera component + * @param shutter speed in microseconds + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_shutter_speed(MMAL_COMPONENT_T *camera, int speed) +{ + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_SHUTTER_SPEED, speed)); +} + +/** + * Adjust the Dynamic range compression level + * @param camera Pointer to camera component + * @param strength Strength of DRC to apply + * MMAL_PARAMETER_DRC_STRENGTH_OFF + * MMAL_PARAMETER_DRC_STRENGTH_LOW + * MMAL_PARAMETER_DRC_STRENGTH_MEDIUM + * MMAL_PARAMETER_DRC_STRENGTH_HIGH + * + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_DRC(MMAL_COMPONENT_T *camera, MMAL_PARAMETER_DRC_STRENGTH_T strength) +{ + MMAL_PARAMETER_DRC_T drc = {{MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, sizeof(MMAL_PARAMETER_DRC_T)}, strength}; + + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &drc.hdr)); +} + +int raspicamcontrol_set_stats_pass(MMAL_COMPONENT_T *camera, int stats_pass) +{ + if (!camera) + return 1; + + return mmal_status_to_int(mmal_port_parameter_set_boolean(camera->control, MMAL_PARAMETER_CAPTURE_STATS_PASS, stats_pass)); +} + + +/** + * Set the annotate data + * @param camera Pointer to camera component + * @param Bitmask of required annotation data. 0 for off. + * @param If set, a pointer to text string to use instead of bitmask, max length 32 characters + * + * @return 0 if successful, non-zero if any parameters out of range + */ +int raspicamcontrol_set_annotate(MMAL_COMPONENT_T *camera, const int settings, const char *string, + const int text_size, const int text_colour, const int bg_colour) +{ + MMAL_PARAMETER_CAMERA_ANNOTATE_V3_T annotate = + {{MMAL_PARAMETER_ANNOTATE, sizeof(MMAL_PARAMETER_CAMERA_ANNOTATE_V3_T)}}; + + if (settings) + { + time_t t = time(NULL); + struct tm tm = *localtime(&t); + char tmp[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3]; + int process_datetime = 1; + + annotate.enable = 1; + + if (settings & (ANNOTATE_APP_TEXT | ANNOTATE_USER_TEXT)) + { + if ((settings & (ANNOTATE_TIME_TEXT | ANNOTATE_DATE_TEXT)) && strchr(string,'%') != NULL) + { //string contains strftime parameter? + strftime(annotate.text, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3, string, &tm ); + process_datetime = 0; + }else{ + strncpy(annotate.text, string, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3); + } + annotate.text[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1] = '\0'; + } + + if (process_datetime && (settings & ANNOTATE_TIME_TEXT)) + { + if(strlen(annotate.text)){ + strftime(tmp, 32, " %X", &tm ); + }else{ + strftime(tmp, 32, "%X", &tm ); + } + strncat(annotate.text, tmp, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3 - strlen(annotate.text) - 1); + } + + if (process_datetime && (settings & ANNOTATE_DATE_TEXT)) + { + if(strlen(annotate.text)){ + strftime(tmp, 32, " %x", &tm ); + }else{ + strftime(tmp, 32, "%x", &tm ); + } + strncat(annotate.text, tmp, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3 - strlen(annotate.text) - 1); + } + + if (settings & ANNOTATE_SHUTTER_SETTINGS) + annotate.show_shutter = MMAL_TRUE; + + if (settings & ANNOTATE_GAIN_SETTINGS) + annotate.show_analog_gain = MMAL_TRUE; + + if (settings & ANNOTATE_LENS_SETTINGS) + annotate.show_lens = MMAL_TRUE; + + if (settings & ANNOTATE_CAF_SETTINGS) + annotate.show_caf = MMAL_TRUE; + + if (settings & ANNOTATE_MOTION_SETTINGS) + annotate.show_motion = MMAL_TRUE; + + if (settings & ANNOTATE_FRAME_NUMBER) + annotate.show_frame_num = MMAL_TRUE; + + if (settings & ANNOTATE_BLACK_BACKGROUND) + annotate.enable_text_background = MMAL_TRUE; + + annotate.text_size = text_size; + + if (text_colour != -1) + { + annotate.custom_text_colour = MMAL_TRUE; + annotate.custom_text_Y = text_colour&0xff; + annotate.custom_text_U = (text_colour>>8)&0xff; + annotate.custom_text_V = (text_colour>>16)&0xff; + } + else + annotate.custom_text_colour = MMAL_FALSE; + + if (bg_colour != -1) + { + annotate.custom_background_colour = MMAL_TRUE; + annotate.custom_background_Y = bg_colour&0xff; + annotate.custom_background_U = (bg_colour>>8)&0xff; + annotate.custom_background_V = (bg_colour>>16)&0xff; + } + else + annotate.custom_background_colour = MMAL_FALSE; + } + else + annotate.enable = 0; + + return mmal_status_to_int(mmal_port_parameter_set(camera->control, &annotate.hdr)); +} + +int raspicamcontrol_set_stereo_mode(MMAL_PORT_T *port, MMAL_PARAMETER_STEREOSCOPIC_MODE_T *stereo_mode) +{ + MMAL_PARAMETER_STEREOSCOPIC_MODE_T stereo = { {MMAL_PARAMETER_STEREOSCOPIC_MODE, sizeof(stereo)}, + MMAL_STEREOSCOPIC_MODE_NONE, MMAL_FALSE, MMAL_FALSE }; + if (stereo_mode->mode != MMAL_STEREOSCOPIC_MODE_NONE) + { + stereo.mode = stereo_mode->mode; + stereo.decimate = stereo_mode->decimate; + stereo.swap_eyes = stereo_mode->swap_eyes; + } + return mmal_status_to_int(mmal_port_parameter_set(port, &stereo.hdr)); +} + +/** + * Asked GPU how much memory it has allocated + * + * @return amount of memory in MB + */ +static int raspicamcontrol_get_mem_gpu(void) +{ + char response[80] = ""; + int gpu_mem = 0; + if (vc_gencmd(response, sizeof response, "get_mem gpu") == 0) + vc_gencmd_number_property(response, "gpu", &gpu_mem); + return gpu_mem; +} + +/** + * Ask GPU about its camera abilities + * @param supported None-zero if software supports the camera + * @param detected None-zero if a camera has been detected + */ +static void raspicamcontrol_get_camera(int *supported, int *detected) +{ + char response[80] = ""; + if (vc_gencmd(response, sizeof response, "get_camera") == 0) + { + if (supported) + vc_gencmd_number_property(response, "supported", supported); + if (detected) + vc_gencmd_number_property(response, "detected", detected); + } +} + +/** + * Check to see if camera is supported, and we have allocated enough meooryAsk GPU about its camera abilities + * @param supported None-zero if software supports the camera + * @param detected None-zero if a camera has been detected + */ +void raspicamcontrol_check_configuration(int min_gpu_mem) +{ + int gpu_mem = raspicamcontrol_get_mem_gpu(); + int supported = 0, detected = 0; + raspicamcontrol_get_camera(&supported, &detected); + if (!supported) + vcos_log_error("Camera is not enabled in this build. Try running \"sudo raspi-config\" and ensure that \"camera\" has been enabled\n"); + else if (gpu_mem < min_gpu_mem) + vcos_log_error("Only %dM of gpu_mem is configured. Try running \"sudo raspi-config\" and ensure that \"memory_split\" has a value of %d or greater\n", gpu_mem, min_gpu_mem); + else if (!detected) + vcos_log_error("Camera is not detected. Please check carefully the camera module is installed correctly\n"); + else + vcos_log_error("Failed to run camera app. Please check for firmware updates\n"); +} + diff --git a/raspicam/RaspiCamControl.h b/raspicam/RaspiCamControl.h new file mode 100644 index 0000000..f4c189a --- /dev/null +++ b/raspicam/RaspiCamControl.h @@ -0,0 +1,217 @@ +/* +Copyright (c) 2013, Broadcom Europe Ltd +Copyright (c) 2013, James Hughes +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef RASPICAMCONTROL_H_ +#define RASPICAMCONTROL_H_ + +/* Various parameters + * + * Exposure Mode + * MMAL_PARAM_EXPOSUREMODE_OFF, + MMAL_PARAM_EXPOSUREMODE_AUTO, + MMAL_PARAM_EXPOSUREMODE_NIGHT, + MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW, + MMAL_PARAM_EXPOSUREMODE_BACKLIGHT, + MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT, + MMAL_PARAM_EXPOSUREMODE_SPORTS, + MMAL_PARAM_EXPOSUREMODE_SNOW, + MMAL_PARAM_EXPOSUREMODE_BEACH, + MMAL_PARAM_EXPOSUREMODE_VERYLONG, + MMAL_PARAM_EXPOSUREMODE_FIXEDFPS, + MMAL_PARAM_EXPOSUREMODE_ANTISHAKE, + MMAL_PARAM_EXPOSUREMODE_FIREWORKS, + * + * AWB Mode + * MMAL_PARAM_AWBMODE_OFF, + MMAL_PARAM_AWBMODE_AUTO, + MMAL_PARAM_AWBMODE_SUNLIGHT, + MMAL_PARAM_AWBMODE_CLOUDY, + MMAL_PARAM_AWBMODE_SHADE, + MMAL_PARAM_AWBMODE_TUNGSTEN, + MMAL_PARAM_AWBMODE_FLUORESCENT, + MMAL_PARAM_AWBMODE_INCANDESCENT, + MMAL_PARAM_AWBMODE_FLASH, + MMAL_PARAM_AWBMODE_HORIZON, + * + * Image FX + MMAL_PARAM_IMAGEFX_NONE, + MMAL_PARAM_IMAGEFX_NEGATIVE, + MMAL_PARAM_IMAGEFX_SOLARIZE, + MMAL_PARAM_IMAGEFX_POSTERIZE, + MMAL_PARAM_IMAGEFX_WHITEBOARD, + MMAL_PARAM_IMAGEFX_BLACKBOARD, + MMAL_PARAM_IMAGEFX_SKETCH, + MMAL_PARAM_IMAGEFX_DENOISE, + MMAL_PARAM_IMAGEFX_EMBOSS, + MMAL_PARAM_IMAGEFX_OILPAINT, + MMAL_PARAM_IMAGEFX_HATCH, + MMAL_PARAM_IMAGEFX_GPEN, + MMAL_PARAM_IMAGEFX_PASTEL, + MMAL_PARAM_IMAGEFX_WATERCOLOUR, + MMAL_PARAM_IMAGEFX_FILM, + MMAL_PARAM_IMAGEFX_BLUR, + MMAL_PARAM_IMAGEFX_SATURATION, + MMAL_PARAM_IMAGEFX_COLOURSWAP, + MMAL_PARAM_IMAGEFX_WASHEDOUT, + MMAL_PARAM_IMAGEFX_POSTERISE, + MMAL_PARAM_IMAGEFX_COLOURPOINT, + MMAL_PARAM_IMAGEFX_COLOURBALANCE, + MMAL_PARAM_IMAGEFX_CARTOON, + + */ + +/// Annotate bitmask options +/// Supplied by user on command line +#define ANNOTATE_USER_TEXT 1 +/// Supplied by app using this module +#define ANNOTATE_APP_TEXT 2 +/// Insert current date +#define ANNOTATE_DATE_TEXT 4 +// Insert current time +#define ANNOTATE_TIME_TEXT 8 + +#define ANNOTATE_SHUTTER_SETTINGS 16 +#define ANNOTATE_CAF_SETTINGS 32 +#define ANNOTATE_GAIN_SETTINGS 64 +#define ANNOTATE_LENS_SETTINGS 128 +#define ANNOTATE_MOTION_SETTINGS 256 +#define ANNOTATE_FRAME_NUMBER 512 +#define ANNOTATE_BLACK_BACKGROUND 1024 + + +// There isn't actually a MMAL structure for the following, so make one +typedef struct mmal_param_colourfx_s +{ + int enable; /// Turn colourFX on or off + int u,v; /// U and V to use +} MMAL_PARAM_COLOURFX_T; + +typedef struct mmal_param_thumbnail_config_s +{ + int enable; + int width,height; + int quality; +} MMAL_PARAM_THUMBNAIL_CONFIG_T; + +typedef struct param_float_rect_s +{ + double x; + double y; + double w; + double h; +} PARAM_FLOAT_RECT_T; + +/// struct contain camera settings +typedef struct raspicam_camera_parameters_s +{ + int sharpness; /// -100 to 100 + int contrast; /// -100 to 100 + int brightness; /// 0 to 100 + int saturation; /// -100 to 100 + int ISO; /// TODO : what range? + int videoStabilisation; /// 0 or 1 (false or true) + int exposureCompensation; /// -10 to +10 ? + MMAL_PARAM_EXPOSUREMODE_T exposureMode; + MMAL_PARAM_EXPOSUREMETERINGMODE_T exposureMeterMode; + MMAL_PARAM_AWBMODE_T awbMode; + MMAL_PARAM_IMAGEFX_T imageEffect; + MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imageEffectsParameters; + MMAL_PARAM_COLOURFX_T colourEffects; + int rotation; /// 0-359 + int hflip; /// 0 or 1 + int vflip; /// 0 or 1 + PARAM_FLOAT_RECT_T roi; /// region of interest to use on the sensor. Normalised [0,1] values in the rect + int shutter_speed; /// 0 = auto, otherwise the shutter speed in ms + float awb_gains_r; /// AWB red gain + float awb_gains_b; /// AWB blue gain + MMAL_PARAMETER_DRC_STRENGTH_T drc_level; // Strength of Dynamic Range compression to apply + MMAL_BOOL_T stats_pass; /// Stills capture statistics pass on/off + int enable_annotate; /// Flag to enable the annotate, 0 = disabled, otherwise a bitmask of what needs to be displayed + char annotate_string[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2]; /// String to use for annotate - overrides certain bitmask settings + int annotate_text_size; // Text size for annotation + int annotate_text_colour; // Text colour for annotation + int annotate_bg_colour; // Background colour for annotation + MMAL_PARAMETER_STEREOSCOPIC_MODE_T stereo_mode; +} RASPICAM_CAMERA_PARAMETERS; + + +void raspicamcontrol_check_configuration(int min_gpu_mem); + +int raspicamcontrol_parse_cmdline(RASPICAM_CAMERA_PARAMETERS *params, const char *arg1, const char *arg2); +void raspicamcontrol_display_help(); +int raspicamcontrol_cycle_test(MMAL_COMPONENT_T *camera); + +int raspicamcontrol_set_all_parameters(MMAL_COMPONENT_T *camera, const RASPICAM_CAMERA_PARAMETERS *params); +int raspicamcontrol_get_all_parameters(MMAL_COMPONENT_T *camera, RASPICAM_CAMERA_PARAMETERS *params); +void raspicamcontrol_dump_parameters(const RASPICAM_CAMERA_PARAMETERS *params); + +void raspicamcontrol_set_defaults(RASPICAM_CAMERA_PARAMETERS *params); + +void raspicamcontrol_check_configuration(int min_gpu_mem); + +// Individual setting functions +int raspicamcontrol_set_saturation(MMAL_COMPONENT_T *camera, int saturation); +int raspicamcontrol_set_sharpness(MMAL_COMPONENT_T *camera, int sharpness); +int raspicamcontrol_set_contrast(MMAL_COMPONENT_T *camera, int contrast); +int raspicamcontrol_set_brightness(MMAL_COMPONENT_T *camera, int brightness); +int raspicamcontrol_set_ISO(MMAL_COMPONENT_T *camera, int ISO); +int raspicamcontrol_set_metering_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMETERINGMODE_T mode); +int raspicamcontrol_set_video_stabilisation(MMAL_COMPONENT_T *camera, int vstabilisation); +int raspicamcontrol_set_exposure_compensation(MMAL_COMPONENT_T *camera, int exp_comp); +int raspicamcontrol_set_exposure_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMODE_T mode); +int raspicamcontrol_set_awb_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_AWBMODE_T awb_mode); +int raspicamcontrol_set_awb_gains(MMAL_COMPONENT_T *camera, float r_gain, float b_gain); +int raspicamcontrol_set_imageFX(MMAL_COMPONENT_T *camera, MMAL_PARAM_IMAGEFX_T imageFX); +int raspicamcontrol_set_colourFX(MMAL_COMPONENT_T *camera, const MMAL_PARAM_COLOURFX_T *colourFX); +int raspicamcontrol_set_rotation(MMAL_COMPONENT_T *camera, int rotation); +int raspicamcontrol_set_flips(MMAL_COMPONENT_T *camera, int hflip, int vflip); +int raspicamcontrol_set_ROI(MMAL_COMPONENT_T *camera, PARAM_FLOAT_RECT_T rect); +int raspicamcontrol_set_shutter_speed(MMAL_COMPONENT_T *camera, int speed_ms); +int raspicamcontrol_set_DRC(MMAL_COMPONENT_T *camera, MMAL_PARAMETER_DRC_STRENGTH_T strength); +int raspicamcontrol_set_stats_pass(MMAL_COMPONENT_T *camera, int stats_pass); +int raspicamcontrol_set_annotate(MMAL_COMPONENT_T *camera, const int bitmask, const char *string, + const int text_size, const int text_colour, const int bg_colour); +int raspicamcontrol_set_stereo_mode(MMAL_PORT_T *port, MMAL_PARAMETER_STEREOSCOPIC_MODE_T *stereo_mode); + +//Individual getting functions +int raspicamcontrol_get_saturation(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_sharpness(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_contrast(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_brightness(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_ISO(MMAL_COMPONENT_T *camera); +MMAL_PARAM_EXPOSUREMETERINGMODE_T raspicamcontrol_get_metering_mode(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_video_stabilisation(MMAL_COMPONENT_T *camera); +int raspicamcontrol_get_exposure_compensation(MMAL_COMPONENT_T *camera); +MMAL_PARAM_THUMBNAIL_CONFIG_T raspicamcontrol_get_thumbnail_parameters(MMAL_COMPONENT_T *camera); +MMAL_PARAM_EXPOSUREMODE_T raspicamcontrol_get_exposure_mode(MMAL_COMPONENT_T *camera); +MMAL_PARAM_AWBMODE_T raspicamcontrol_get_awb_mode(MMAL_COMPONENT_T *camera); +MMAL_PARAM_IMAGEFX_T raspicamcontrol_get_imageFX(MMAL_COMPONENT_T *camera); +MMAL_PARAM_COLOURFX_T raspicamcontrol_get_colourFX(MMAL_COMPONENT_T *camera); + + +#endif /* RASPICAMCONTROL_H_ */ diff --git a/stream.c b/stream.c index 1ed082a..bbdbed7 100644 --- a/stream.c +++ b/stream.c @@ -179,6 +179,10 @@ static void* handle_basic_auth(void* param) "Pragma: no-cache\r\n" "WWW-Authenticate: Basic realm=\""STREAM_REALM"\"\r\n\r\n"; +#ifdef HAVE_PTHREAD_SETNAME_NP + pthread_setname_np(pthread_self(), "handle_basic_auth"); +#endif + pthread_mutex_lock(&stream_auth_mutex); p->thread_count++; pthread_mutex_unlock(&stream_auth_mutex); @@ -205,7 +209,7 @@ static void* handle_basic_auth(void* param) char *userpass = NULL; size_t auth_size = strlen(p->conf->stream_authentication); - authentication = (char *) mymalloc(BASE64_LENGTH(auth_size) + 1); + authentication = mymalloc(BASE64_LENGTH(auth_size) + 1); userpass = mymalloc(auth_size + 4); /* base64_encode can read 3 bytes after the end of the string, initialize it. */ memset(userpass, 0, auth_size + 4); @@ -242,7 +246,8 @@ static void* handle_basic_auth(void* param) pthread_exit(NULL); Error: - write(p->sock, request_auth_response_template, strlen (request_auth_response_template)); + if (write(p->sock, request_auth_response_template, strlen (request_auth_response_template)) < 0) + MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "%s: write failure 1:handle_basic_auth"); Invalid_Request: close(p->sock); @@ -408,26 +413,32 @@ static void* handle_md5_digest(void* param) "Pragma: no-cache\r\n" "WWW-Authenticate: Digest"; static const char *auth_failed_html_template= - "\r\n" - "\r\n" - "401 Authorization Required\r\n" - "\r\n" - "

    Authorization Required

    \r\n" - "This server could not verify that you are authorized to access the document " + "\n" + "\n" + "401 Authorization Required\n" + "\n" + "

    Authorization Required

    \n" + "

    This server could not verify that you are authorized to access the document " "requested. Either you supplied the wrong credentials (e.g., bad password), " - "or your browser doesn't understand how to supply the credentials required.\r\n" - "\r\n"; + "or your browser doesn't understand how to supply the credentials required.

    \n" + "\n" + "\n"; static const char *internal_error_template= "HTTP/1.0 500 Internal Server Error\r\n" "Server: Motion/"VERSION"\r\n" "Content-Type: text/html\r\n" "Connection: Close\r\n\r\n" - "\r\n" - "\r\n" - "500 Internal Server Error\r\n" - "\r\n" - "

    500 Internal Server Error

    \r\n" - "\r\n"; + "\n" + "\n" + "500 Internal Server Error\n" + "\n" + "

    500 Internal Server Error

    \n" + "\n" + "\n"; + +#ifdef HAVE_PTHREAD_SETNAME_NP + pthread_setname_np(pthread_self(), "handle_md5_digest"); +#endif pthread_mutex_lock(&stream_auth_mutex); p->thread_count++; @@ -569,8 +580,10 @@ static void* handle_md5_digest(void* param) "Content-Length: %Zu\r\n\r\n", request_auth_response_template, server_nonce, KEEP_ALIVE_TIMEOUT, strlen(auth_failed_html_template)); - write(p->sock, buffer, strlen(buffer)); - write(p->sock, auth_failed_html_template, strlen(auth_failed_html_template)); + if (write(p->sock, buffer, strlen(buffer)) < 0) + MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "%s: write failure 1:handle_md5_digest"); + if (write(p->sock, auth_failed_html_template, strlen(auth_failed_html_template)) < 0) + MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "%s: write failure 2:handle_md5_digest"); } // OK - Access @@ -581,11 +594,8 @@ static void* handle_md5_digest(void* param) goto Error; } - if(server_user) - free(server_user); - - if(server_pass) - free(server_pass); + free(server_user); + free(server_pass); /* Lock the mutex */ pthread_mutex_lock(&stream_auth_mutex); @@ -601,13 +611,11 @@ static void* handle_md5_digest(void* param) pthread_exit(NULL); InternalError: - if(server_user) - free(server_user); - - if(server_pass) - free(server_pass); + free(server_user); + free(server_pass); - write(p->sock, internal_error_template, strlen(internal_error_template)); + if (write(p->sock, internal_error_template, strlen(internal_error_template)) < 0) + MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "%s: write failure 3:handle_md5_digest"); Invalid_Request: close(p->sock); @@ -694,8 +702,7 @@ static void do_client_auth(struct context *cnt, int sc) Error: close(sc); - if(handle_param) - free(handle_param); + free(handle_param); } /** @@ -955,7 +962,7 @@ static void stream_add_client(struct stream *list, int sc) "Cache-Control: no-cache, private\r\n" "Pragma: no-cache\r\n" "Content-Type: multipart/x-mixed-replace; " - "boundary=--BoundaryString\r\n\r\n"; + "boundary=BoundaryString\r\n\r\n"; memset(new, 0, sizeof(struct stream)); new->socket = sc; diff --git a/track.c b/track.c index 91e89d7..cc0a709 100644 --- a/track.c +++ b/track.c @@ -5,11 +5,13 @@ * Copyright 2000, Jeroen Vreeken * This program is published under the GNU Public license */ - +#ifdef MOTION_V4L2 +#include +#endif /* MOTION_V4L2 */ #include #include "motion.h" -#if defined(HAVE_LINUX_VIDEODEV_H) && (!defined(WITHOUT_V4L)) +#if (defined(HAVE_LINUX_VIDEODEV_H) || defined(HAVE_SYS_VIDEOIO_H)) && (!defined(WITHOUT_V4L)) #include "pwc-ioctl.h" #endif @@ -563,7 +565,6 @@ static unsigned int servo_status(struct context *cnt, unsigned int motor) static unsigned int servo_center(struct context *cnt, int x_offset, int y_offset) { - unsigned int ret = 0; int x_offset_abs; int y_offset_abs; @@ -591,7 +592,7 @@ static unsigned int servo_center(struct context *cnt, int x_offset, int y_offset if (x_offset_abs <= cnt->track.maxx && x_offset_abs >= cnt->track.minx) { /* Set Speed , TODO : it should be done only when speed changes */ servo_command(cnt, cnt->track.motorx, SERVO_COMMAND_SPEED, cnt->track.speed); - ret = servo_command(cnt, cnt->track.motorx, SERVO_COMMAND_ABSOLUTE, x_offset_abs); + servo_command(cnt, cnt->track.motorx, SERVO_COMMAND_ABSOLUTE, x_offset_abs); } /* y-axis */ @@ -603,7 +604,7 @@ static unsigned int servo_center(struct context *cnt, int x_offset, int y_offset if (y_offset_abs <= cnt->track.maxy && y_offset_abs >= cnt->track.minx) { /* Set Speed , TODO : it should be done only when speed changes */ servo_command(cnt, cnt->track.motory, SERVO_COMMAND_SPEED, cnt->track.speed); - ret = servo_command(cnt, cnt->track.motory, SERVO_COMMAND_ABSOLUTE, y_offset_abs); + servo_command(cnt, cnt->track.motory, SERVO_COMMAND_ABSOLUTE, y_offset_abs); } return cnt->track.move_wait; diff --git a/version.sh b/version.sh index 68dc73e..56dfef9 100755 --- a/version.sh +++ b/version.sh @@ -1,6 +1,3 @@ #!/bin/sh - -SNV_VERSION=`cd "$1" && LC_ALL=C svn info 2> /dev/null | grep Revision | cut -d' ' -f2` -test $SNV_VERSION || SNV_VERSION=`cd "$1" && grep revision .svn/entries 2>/dev/null | cut -d '"' -f2` -test $SNV_VERSION || SNV_VERSION=UNKNOWN -echo -n "trunkREV$SNV_VERSION" +SNV_VERSION=`git show -s --format=%h` +echo -n "3.4.1+git$SNV_VERSION" diff --git a/video.h b/video.h index 12f2928..1ac4553 100644 --- a/video.h +++ b/video.h @@ -14,8 +14,12 @@ #include -#if defined(HAVE_LINUX_VIDEODEV_H) && (!defined(WITHOUT_V4L)) +#if !defined(WITHOUT_V4L) +#if defined(HAVE_LINUX_VIDEODEV_H) #include +#elif defined(HAVE_SYS_VIDEOIO_H) +#include +#endif #include "vloopback_motion.h" #include "pwc-ioctl.h" #endif @@ -61,6 +65,7 @@ struct video_dev { int contrast; int saturation; int hue; + int power_line_frequency; unsigned long freq; int tuner_number; int fps; diff --git a/video2.c b/video2.c index 9896edb..798f8f8 100644 --- a/video2.c +++ b/video2.c @@ -144,6 +144,10 @@ static const u32 queried_ctrls[] = { V4L2_CID_CONTRAST, V4L2_CID_SATURATION, V4L2_CID_HUE, +/* first added in Linux kernel v2.6.26 */ +#ifdef V4L2_CID_POWER_LINE_FREQUENCY + V4L2_CID_POWER_LINE_FREQUENCY, +#endif V4L2_CID_RED_BALANCE, V4L2_CID_BLUE_BALANCE, @@ -173,19 +177,24 @@ typedef struct { u32 ctrl_flags; struct v4l2_queryctrl *controls; + volatile unsigned int *finish; /* End the thread */ } src_v4l2_t; /** * xioctl */ -static int xioctl(int fd, int request, void *arg) +#ifdef __OpenBSD__ +static int xioctl(src_v4l2_t *vid_source, unsigned long request, void *arg) +#else +static int xioctl(src_v4l2_t *vid_source, int request, void *arg) +#endif { int ret; do - ret = ioctl(fd, request, arg); - while (-1 == ret && EINTR == errno); + ret = ioctl(vid_source->fd, request, arg); + while (-1 == ret && EINTR == errno && !vid_source->finish); return ret; } @@ -195,7 +204,7 @@ static int xioctl(int fd, int request, void *arg) */ static int v4l2_get_capability(src_v4l2_t * vid_source) { - if (xioctl(vid_source->fd, VIDIOC_QUERYCAP, &vid_source->cap) < 0) { + if (xioctl(vid_source, VIDIOC_QUERYCAP, &vid_source->cap) < 0) { MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, "%s: Not a V4L2 device?"); return -1; } @@ -258,7 +267,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev, input.index = IN_TV; else input.index = in; - if (xioctl(vid_source->fd, VIDIOC_ENUMINPUT, &input) == -1) { + if (xioctl(vid_source, VIDIOC_ENUMINPUT, &input) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Unable to query input %d." " VIDIOC_ENUMINPUT, if you use a WEBCAM change input value in conf by -1", input.index); @@ -274,7 +283,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev, if (input.type & V4L2_INPUT_TYPE_CAMERA) MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "%s: - CAMERA"); - if (xioctl(vid_source->fd, VIDIOC_S_INPUT, &input.index) == -1) { + if (xioctl(vid_source, VIDIOC_S_INPUT, &input.index) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error selecting input %d" " VIDIOC_S_INPUT", input.index); return -1; @@ -286,7 +295,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev, * Set video standard usually webcams doesn't support the ioctl or * return V4L2_STD_UNKNOWN */ - if (xioctl(vid_source->fd, VIDIOC_G_STD, &std_id) == -1) { + if (xioctl(vid_source, VIDIOC_G_STD, &std_id) == -1) { MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO, "%s: Device doesn't support VIDIOC_G_STD"); norm = std_id = 0; // V4L2_STD_UNKNOWN = 0 } @@ -295,7 +304,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev, memset(&standard, 0, sizeof(standard)); standard.index = 0; - while (xioctl(vid_source->fd, VIDIOC_ENUMSTD, &standard) == 0) { + while (xioctl(vid_source, VIDIOC_ENUMSTD, &standard) == 0) { if (standard.id & std_id) MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "%s: - video standard %s", standard.name); @@ -314,7 +323,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev, std_id = V4L2_STD_PAL; } - if (xioctl(vid_source->fd, VIDIOC_S_STD, &std_id) == -1) + if (xioctl(vid_source, VIDIOC_S_STD, &std_id) == -1) MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error selecting standard" " method %d VIDIOC_S_STD", (int)std_id); @@ -334,7 +343,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev, memset(&tuner, 0, sizeof(struct v4l2_tuner)); tuner.index = input.tuner; - if (xioctl(vid_source->fd, VIDIOC_G_TUNER, &tuner) == -1) { + if (xioctl(vid_source, VIDIOC_G_TUNER, &tuner) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: tuner %d VIDIOC_G_TUNER", tuner.index); return 0; @@ -349,7 +358,7 @@ static int v4l2_select_input(struct config *conf, struct video_dev *viddev, freq.type = V4L2_TUNER_ANALOG_TV; freq.frequency = (freq_ / 1000) * 16; - if (xioctl(vid_source->fd, VIDIOC_S_FREQUENCY, &freq) == -1) { + if (xioctl(vid_source, VIDIOC_S_FREQUENCY, &freq) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: freq %ul VIDIOC_S_FREQUENCY", freq.frequency); return 0; @@ -401,7 +410,7 @@ static int v4l2_do_set_pix_format(u32 pixformat, src_v4l2_t * vid_source, vid_source->dst_fmt.fmt.pix.pixelformat = pixformat; vid_source->dst_fmt.fmt.pix.field = V4L2_FIELD_ANY; - if (xioctl(vid_source->fd, VIDIOC_TRY_FMT, &vid_source->dst_fmt) != -1 && + if (xioctl(vid_source, VIDIOC_TRY_FMT, &vid_source->dst_fmt) != -1 && vid_source->dst_fmt.fmt.pix.pixelformat == pixformat) { MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "%s: Testing palette %c%c%c%c (%dx%d)", pixformat >> 0, pixformat >> 8, @@ -419,7 +428,7 @@ static int v4l2_do_set_pix_format(u32 pixformat, src_v4l2_t * vid_source, *height = vid_source->dst_fmt.fmt.pix.height; } - if (xioctl(vid_source->fd, VIDIOC_S_FMT, &vid_source->dst_fmt) == -1) { + if (xioctl(vid_source, VIDIOC_S_FMT, &vid_source->dst_fmt) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error setting pixel " "format.\nVIDIOC_S_FMT: "); return -1; @@ -498,7 +507,7 @@ static int v4l2_set_pix_format(struct context *cnt, src_v4l2_t * vid_source, MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "%s: Supported palettes:"); - while (xioctl(vid_source->fd, VIDIOC_ENUM_FMT, &fmtd) != -1) { + while (xioctl(vid_source, VIDIOC_ENUM_FMT, &fmtd) != -1) { int i; @@ -552,7 +561,7 @@ static void v4l2_set_fps(src_v4l2_t * vid_source) { setfpvid_source->parm.capture.timeperframe.numerator = 1; setfpvid_source->parm.capture.timeperframe.denominator = vid_source->fps; - if (xioctl(vid_source->fd, VIDIOC_S_PARM, setfps) == -1) + if (xioctl(vid_source, VIDIOC_S_PARM, setfps) == -1) MOTION_LOG(ERR, 1, "%s: v4l2_set_fps VIDIOC_S_PARM"); @@ -577,7 +586,7 @@ static int v4l2_set_mmap(src_v4l2_t * vid_source) vid_source->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vid_source->req.memory = V4L2_MEMORY_MMAP; - if (xioctl(vid_source->fd, VIDIOC_REQBUFS, &vid_source->req) == -1) { + if (xioctl(vid_source, VIDIOC_REQBUFS, &vid_source->req) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error requesting buffers" " %d for memory map. VIDIOC_REQBUFS", vid_source->req.count); @@ -609,7 +618,7 @@ static int v4l2_set_mmap(src_v4l2_t * vid_source) buf.memory = V4L2_MEMORY_MMAP; buf.index = buffer_index; - if (xioctl(vid_source->fd, VIDIOC_QUERYBUF, &buf) == -1) { + if (xioctl(vid_source, VIDIOC_QUERYBUF, &buf) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error querying buffer" " %i\nVIDIOC_QUERYBUF: ", buffer_index); free(vid_source->buffers); @@ -638,7 +647,7 @@ static int v4l2_set_mmap(src_v4l2_t * vid_source) vid_source->buf.memory = V4L2_MEMORY_MMAP; vid_source->buf.index = buffer_index; - if (xioctl(vid_source->fd, VIDIOC_QBUF, &vid_source->buf) == -1) { + if (xioctl(vid_source, VIDIOC_QBUF, &vid_source->buf) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: VIDIOC_QBUF"); return -1; } @@ -646,7 +655,7 @@ static int v4l2_set_mmap(src_v4l2_t * vid_source) type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (xioctl(vid_source->fd, VIDIOC_STREAMON, &type) == -1) { + if (xioctl(vid_source, VIDIOC_STREAMON, &type) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: Error starting stream." " VIDIOC_STREAMON"); return -1; @@ -667,7 +676,7 @@ static int v4l2_scan_controls(src_v4l2_t * vid_source) for (i = 0, count = 0; queried_ctrls[i]; i++) { queryctrl.id = queried_ctrls[i]; - if (xioctl(vid_source->fd, VIDIOC_QUERYCTRL, &queryctrl)) + if (xioctl(vid_source, VIDIOC_QUERYCTRL, &queryctrl)) continue; count++; @@ -688,7 +697,7 @@ static int v4l2_scan_controls(src_v4l2_t * vid_source) struct v4l2_control control; queryctrl.id = queried_ctrls[i]; - if (xioctl(vid_source->fd, VIDIOC_QUERYCTRL, &queryctrl)) + if (xioctl(vid_source, VIDIOC_QUERYCTRL, &queryctrl)) continue; memcpy(ctrl, &queryctrl, sizeof(struct v4l2_queryctrl)); @@ -700,7 +709,7 @@ static int v4l2_scan_controls(src_v4l2_t * vid_source) memset(&control, 0, sizeof (control)); control.id = queried_ctrls[i]; - xioctl(vid_source->fd, VIDIOC_G_CTRL, &control); + xioctl(vid_source, VIDIOC_G_CTRL, &control); MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "%s: \t\"%s\", default %d, current %d", ctrl->name, ctrl->default_value, control.value); @@ -736,14 +745,21 @@ static int v4l2_set_control(src_v4l2_t * vid_source, u32 cid, int value) case V4L2_CTRL_TYPE_INTEGER: value = control.value = (value * (ctrl->maximum - ctrl->minimum) / 256) + ctrl->minimum; - ret = xioctl(vid_source->fd, VIDIOC_S_CTRL, &control); + ret = xioctl(vid_source, VIDIOC_S_CTRL, &control); break; case V4L2_CTRL_TYPE_BOOLEAN: value = control.value = value ? 1 : 0; - ret = xioctl(vid_source->fd, VIDIOC_S_CTRL, &control); + ret = xioctl(vid_source, VIDIOC_S_CTRL, &control); break; + case V4L2_CTRL_TYPE_MENU: + /* set as is, no adjustments */ + control.value = value; + ret = xioctl(vid_source, VIDIOC_S_CTRL, &control); + break; + + default: MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO, "%s: control type not supported yet"); return -1; @@ -784,6 +800,14 @@ static void v4l2_picture_controls(struct context *cnt, struct video_dev *viddev) v4l2_set_control(vid_source, V4L2_CID_HUE, viddev->hue); } +#ifdef V4L2_CID_POWER_LINE_FREQUENCY + /* -1 is don't modify as 0 is an option to disable the power line filter */ + if (cnt->conf.power_line_frequency != -1 && cnt->conf.power_line_frequency != viddev->power_line_frequency) { + viddev->power_line_frequency = cnt->conf.power_line_frequency; + v4l2_set_control(vid_source, V4L2_CID_POWER_LINE_FREQUENCY, viddev->power_line_frequency); + } +#endif + if (cnt->conf.autobright) { if (vid_do_autobright(cnt, viddev)) { if (v4l2_set_control(vid_source, V4L2_CID_BRIGHTNESS, viddev->brightness)) @@ -818,6 +842,7 @@ unsigned char *v4l2_start(struct context *cnt, struct video_dev *viddev, int wid vid_source->fd = viddev->fd; vid_source->fps = cnt->conf.frame_limit; vid_source->pframe = -1; + vid_source->finish = &cnt->finish; struct config *conf = &cnt->conf; if (v4l2_get_capability(vid_source)) @@ -854,8 +879,7 @@ unsigned char *v4l2_start(struct context *cnt, struct video_dev *viddev, int wid return (void *) 1; err: - if (vid_source) - free(vid_source); + free(vid_source); viddev->v4l2_private = NULL; viddev->v4l2 = 0; @@ -962,7 +986,7 @@ int v4l2_next(struct context *cnt, struct video_dev *viddev, unsigned char *map, vid_source->pframe); if (vid_source->pframe >= 0) { - if (xioctl(vid_source->fd, VIDIOC_QBUF, &vid_source->buf) == -1) { + if (xioctl(vid_source, VIDIOC_QBUF, &vid_source->buf) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "%s: VIDIOC_QBUF"); pthread_sigmask(SIG_UNBLOCK, &old, NULL); return -1; @@ -973,8 +997,9 @@ int v4l2_next(struct context *cnt, struct video_dev *viddev, unsigned char *map, vid_source->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vid_source->buf.memory = V4L2_MEMORY_MMAP; + vid_source->buf.bytesused = 0; - if (xioctl(vid_source->fd, VIDIOC_DQBUF, &vid_source->buf) == -1) { + if (xioctl(vid_source, VIDIOC_DQBUF, &vid_source->buf) == -1) { int ret; /* * Some drivers return EIO when there is no signal, @@ -1079,7 +1104,7 @@ void v4l2_close(struct video_dev *viddev) enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - xioctl(vid_source->fd, VIDIOC_STREAMOFF, &type); + xioctl(vid_source, VIDIOC_STREAMOFF, &type); close(vid_source->fd); vid_source->fd = -1; } @@ -1101,10 +1126,8 @@ void v4l2_cleanup(struct video_dev *viddev) vid_source->buffers = NULL; } - if (vid_source->controls) { - free(vid_source->controls); - vid_source->controls = NULL; - } + free(vid_source->controls); + vid_source->controls = NULL; free(vid_source); viddev->v4l2_private = NULL; diff --git a/video_common.c b/video_common.c index 9f8d6a0..976b79c 100644 --- a/video_common.c +++ b/video_common.c @@ -387,42 +387,41 @@ void conv_rgb24toyuv420p(unsigned char *map, unsigned char *cap_map, int width, */ int mjpegtoyuv420p(unsigned char *map, unsigned char *cap_map, int width, int height, unsigned int size) { - uint8_t *yuv[3]; - unsigned char *y, *u, *v; - int loop, ret; + unsigned char *ptr_buffer; + size_t soi_pos = 0; + int ret = 0; + + ptr_buffer = memmem(cap_map, size, "\xff\xd8", 2); + if (ptr_buffer != NULL) { + /** + Some cameras are sending multiple SOIs in the buffer. + Move the pointer to the last SOI in the buffer and proceed. + */ + while (ptr_buffer != NULL && ((size - soi_pos - 1) > 2) ){ + soi_pos = ptr_buffer - cap_map; + ptr_buffer = memmem(cap_map + soi_pos + 1, size - soi_pos - 1, "\xff\xd8", 2); + } - yuv[0] = mymalloc(width * height * sizeof(yuv[0][0])); - yuv[1] = mymalloc(width * height / 4 * sizeof(yuv[1][0])); - yuv[2] = mymalloc(width * height / 4 * sizeof(yuv[2][0])); + if (soi_pos != 0){ + MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, "%s: SOI position adjusted by %d bytes.", soi_pos); + } + memmove(cap_map, cap_map + soi_pos, size - soi_pos); + size -= soi_pos; + ret = decode_jpeg_raw(cap_map, size, 0, 420, width, height, + map, + map + (width * height), + map + (width * height) + (width * height) / 4); - ret = decode_jpeg_raw(cap_map, size, 0, 420, width, height, yuv[0], yuv[1], yuv[2]); + } else { + //Buffer does not have a SOI + ret = 1; + } if (ret == 1) { MOTION_LOG(CRT, TYPE_VIDEO, NO_ERRNO, "%s: Corrupt image ... continue"); ret = 2; } - - y = map; - u = y + width * height; - v = u + (width * height) / 4; - memset(y, 0, width * height); - memset(u, 0, width * height / 4); - memset(v, 0, width * height / 4); - - for(loop = 0; loop < width * height; loop++) - *map++ = yuv[0][loop]; - - for(loop = 0; loop < width * height / 4; loop++) - *map++ = yuv[1][loop]; - - for(loop = 0; loop < width * height / 4; loop++) - *map++ = yuv[2][loop]; - - free(yuv[0]); - free(yuv[1]); - free(yuv[2]); - return ret; } @@ -551,6 +550,15 @@ void vid_close(struct context *cnt) #endif /* WITHOUT_V4L */ /* Cleanup the netcam part */ +#ifdef HAVE_MMAL + if (cnt->mmalcam) { + MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, "%s: calling mmalcam_cleanup"); + mmalcam_cleanup(cnt->mmalcam); + cnt->mmalcam = NULL; + return; + } + else +#endif if (cnt->netcam) { MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, "%s: calling netcam_cleanup"); netcam_cleanup(cnt->netcam, 0); @@ -726,7 +734,6 @@ static int vid_v4lx_start(struct context *cnt) conf->video_device, conf->input); dev = mymalloc(sizeof(struct video_dev)); - memset(dev, 0, sizeof(struct video_dev)); dev->video_device = conf->video_device; @@ -760,6 +767,8 @@ static int vid_v4lx_start(struct context *cnt) dev->contrast = 0; dev->saturation = 0; dev->hue = 0; + /* -1 is don't modify, (0 is a valid value) */ + dev->power_line_frequency = -1; dev->owner = -1; dev->v4l_fmt = VIDEO_PALETTE_YUV420P; dev->fps = 0; @@ -858,6 +867,16 @@ int vid_start(struct context *cnt) struct config *conf = &cnt->conf; int dev = -1; +#ifdef HAVE_MMAL + if (conf->mmalcam_name) { + dev = mmalcam_start(cnt); + if (dev < 0) { + mmalcam_cleanup(cnt->mmalcam); + cnt->mmalcam = NULL; + } + } + else +#endif if (conf->netcam_url) { dev = netcam_start(cnt); if (dev < 0) { @@ -901,6 +920,15 @@ int vid_next(struct context *cnt, unsigned char *map) int ret = -2; struct config *conf = &cnt->conf; +#ifdef HAVE_MMAL + if (conf->mmalcam_name) { + if (cnt->mmalcam == NULL) { + return NETCAM_GENERAL_ERROR; + } + return mmalcam_next(cnt, map); + } + else +#endif if (conf->netcam_url) { if (cnt->video_dev == -1) return NETCAM_GENERAL_ERROR; diff --git a/video_freebsd.c b/video_freebsd.c index ec98a55..66a0165 100644 --- a/video_freebsd.c +++ b/video_freebsd.c @@ -1161,7 +1161,6 @@ int vid_start(struct context *cnt) dev = mymalloc(sizeof(struct video_dev)); - memset(dev, 0, sizeof(struct video_dev)); fd_bktr = open(conf->video_device, O_RDWR); diff --git a/vloopback_motion.c b/vloopback_motion.c index 3433bf8..36f8cf2 100644 --- a/vloopback_motion.c +++ b/vloopback_motion.c @@ -41,11 +41,9 @@ static int v4l_open_vidpipe(void) if (strcmp(minor, "5") < 0) { FILE *vloopbacks; - char *loop; char *input; char *istatus; char *output; - char *ostatus; vloopbacks = fopen("/proc/video/vloopback/vloopbacks", "r"); @@ -76,11 +74,9 @@ static int v4l_open_vidpipe(void) while (fgets(buffer, sizeof(buffer), vloopbacks)) { if (strlen(buffer) > 1) { buffer[strlen(buffer)-1] = 0; - loop = strtok(buffer, "\t"); input = strtok(NULL, "\t"); istatus = strtok(NULL, "\t"); output = strtok(NULL, "\t"); - ostatus = strtok(NULL, "\t"); if (istatus[0] == '-') { snprintf(pipepath, sizeof(pipepath), "/dev/%s", input); diff --git a/webhttpd.c b/webhttpd.c index 20fe4e8..87c3673 100644 --- a/webhttpd.c +++ b/webhttpd.c @@ -15,6 +15,10 @@ #include #include #include +#include + +/* Timeout in seconds, used for read and write */ +const int NONBLOCK_TIMEOUT = 1; pthread_mutex_t httpd_mutex; @@ -22,16 +26,23 @@ pthread_mutex_t httpd_mutex; int warningkill; static const char *ini_template = - "Motion "VERSION"\n" + "\n" + "\n" + "Motion "VERSION"\n" "\n"; static const char *set_template = - "\nMotion "VERSION"\n" - "\n"; + "}\n" + "\n" + "\n"; static const char *end_template = "\n" @@ -62,6 +73,7 @@ static const char *ok_response_raw = static const char *bad_request_response = "HTTP/1.0 400 Bad Request\r\n" "Content-type: text/html\r\n\r\n" + "\n" "\n" "\n" "

    Bad Request

    \n" @@ -77,6 +89,7 @@ static const char *bad_request_response_raw = static const char *not_found_response_template = "HTTP/1.0 404 Not Found\r\n" "Content-type: text/html\r\n\r\n" + "\n" "\n" "\n" "

    Not Found

    \n" @@ -92,6 +105,7 @@ static const char *not_found_response_template_raw = static const char *not_found_response_valid = "HTTP/1.0 404 Not Valid\r\n" "Content-type: text/html\r\n\r\n" + "\n" "\n" "\n" "

    Not Valid

    \n" @@ -107,6 +121,7 @@ static const char *not_found_response_valid_raw = static const char *not_valid_syntax = "HTTP/1.0 404 Not Valid Syntax\r\n" "Content-type: text/html\r\n\r\n" + "\n" "\n" "\n" "

    Not Valid Syntax

    \n" @@ -121,6 +136,7 @@ static const char *not_valid_syntax_raw = static const char *not_track = "HTTP/1.0 200 OK\r\n" "Content-type: text/html\r\n\r\n" + "\n" "\n" "\n" "

    Tracking Not Enabled

    \n"; @@ -133,6 +149,7 @@ static const char *not_track_raw = static const char *track_error = "HTTP/1.0 200 OK\r\n" "Content-type: text/html\r\n\r\n" + "\n" "\n" "\n" "

    Track Error

    \n"; @@ -145,6 +162,7 @@ static const char *track_error_raw = static const char *error_value = "HTTP/1.0 200 OK\r\n" "Content-type: text/html\r\n\r\n" + "\n" "\n" "\n" "

    Value Error

    \n"; @@ -157,6 +175,7 @@ static const char *error_value_raw = static const char *not_found_response_valid_command = "HTTP/1.0 404 Not Valid Command\r\n" "Content-type: text/html\r\n\r\n" + "\n" "\n" "\n" "

    Not Valid Command

    \n" @@ -172,6 +191,7 @@ static const char *not_found_response_valid_command_raw = static const char *bad_method_response_template = "HTTP/1.0 501 Method Not Implemented\r\n" "Content-type: text/html\r\n\r\n" + "\n" "\n" "\n" "

    Method Not Implemented

    \n" @@ -197,7 +217,7 @@ static ssize_t write_nonblock(int fd, const void *buf, size_t size) struct timeval tm; fd_set fds; - tm.tv_sec = 1; /* Timeout in seconds */ + tm.tv_sec = NONBLOCK_TIMEOUT; tm.tv_usec = 0; FD_ZERO(&fds); FD_SET(fd, &fds); @@ -223,7 +243,7 @@ static ssize_t read_nonblock(int fd ,void *buf, ssize_t size) struct timeval tm; fd_set fds; - tm.tv_sec = 1; /* Timeout in seconds */ + tm.tv_sec = NONBLOCK_TIMEOUT; /* Timeout in seconds */ tm.tv_usec = 0; FD_ZERO(&fds); FD_SET(fd, &fds); @@ -281,6 +301,8 @@ static void send_template_raw(int client_socket, char *res) { ssize_t nwrite = 0; nwrite = write_nonblock(client_socket, res, strlen(res)); + if (nwrite < 0) + MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "%s: write_nonblock returned value less than zero."); } /** @@ -290,6 +312,9 @@ static void send_template_end_client(int client_socket) { ssize_t nwrite = 0; nwrite = write_nonblock(client_socket, end_template, strlen(end_template)); + if (nwrite < 0) + MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "%s: write_nonblock returned value less than zero."); + } /** @@ -303,6 +328,9 @@ static void response_client(int client_socket, const char *template, char *back) send_template(client_socket, back); send_template_end_client(client_socket); } + if (nwrite < 0) + MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "%s: write_nonblock returned value less than zero."); + } /** @@ -370,9 +398,8 @@ static void url_decode(char *urlencoded, size_t length) *urldecoded++ = c[1]; } - } else if (*data == '+') { + } else if (*data == '<' || *data == '+' || *data == '>') { *urldecoded++ = ' '; - } else { *urldecoded++ = *data; } @@ -408,8 +435,11 @@ static unsigned int config(char *pointer, char *res, unsigned int length_uri, /*call list*/ if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

    \nThread %hu\n
      ", - thread, thread); + sprintf(res, "<– back

      \nThread %hu%s%s\n
        ", + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); + send_template(client_socket, res); for (i=0; config_params[i].param_name != NULL; i++) { @@ -538,10 +568,13 @@ static unsigned int config(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { sprintf(res, "<– back" - "

        \nThread %hu\n" + "

        \nThread %hu%s%s\n" "
        • %s = %s" "
        Done", - thread, thread, thread, config_params[i].param_name, + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + thread, config_params[i].param_name, config_params[i].param_name, Value); send_template_ini_client(client_socket, ini_template); @@ -584,8 +617,11 @@ static unsigned int config(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { sprintf(res, "<– back

        \n" - "Thread %hu\n
        • %s" - "= %s

        Done", thread, thread, thread, + "Thread %hu%s%s\n
        • %s" + "= %s

        Done", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + thread, config_params[i].param_name, config_params[i].param_name, type); send_template_ini_client(client_socket, ini_template); @@ -651,7 +687,7 @@ static unsigned int config(char *pointer, char *res, unsigned int length_uri, "\n"); sprintf(res, "<– back

        \n" - "Thread %hu\n" + "Thread %hu%s%s\n" "
        \n" "%s \n" "\n" "    " "[help]" "
        \n
        %s", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", config_params[i].param_name, config_params[i].param_name, value, TWIKI_URL, config_params[i].param_name, text_help); } @@ -699,8 +739,10 @@ static unsigned int config(char *pointer, char *res, unsigned int length_uri, } else if (length_uri == 0) { if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, set_template); - sprintf(res, "<– back

        \nThread %hu\n" - "
        \n\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); send_template(client_socket, res); for (i=0; config_params[i].param_name != NULL; i++) { @@ -793,10 +835,13 @@ static unsigned int config(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

        \n" - "Thread %hu
        \n
        • %s = %s   " + "Thread %hu%s%s
          \n
          %s", - thread, thread, config_params[i].param_name, value, + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + config_params[i].param_name, value, TWIKI_URL, config_params[i].param_name, text_help); send_template(client_socket, res); @@ -827,9 +872,11 @@ static unsigned int config(char *pointer, char *res, unsigned int length_uri, } else if (length_uri == 0) { if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

          \nThread %hu
          \n" + sprintf(res, "<– back

          \nThread %hu%s%s
          \n" "\n" - "\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); send_template(client_socket, res); for (i=0; config_params[i].param_name != NULL; i++) { if ((thread != 0) && (config_params[i].main_thread)) @@ -886,8 +933,10 @@ static unsigned int config(char *pointer, char *res, unsigned int length_uri, conf_print(cnt); if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

          \nThread %hu write done !\n", - thread, thread); + sprintf(res, "<– back

          \nThread %hu%s%s write done !\n", + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -1121,8 +1170,10 @@ static unsigned int detection(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

          Thread %hu" + sprintf(res, "<– back

          Thread %hu%s%s" " Detection status %s\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", (!cnt[thread]->running)? "NOT RUNNING": (cnt[thread]->pause)? "PAUSE":"ACTIVE"); send_template(client_socket, res); send_template_end_client(client_socket); @@ -1155,8 +1206,10 @@ static unsigned int detection(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

          \nThread %hu" - " Detection resumed\n", thread, thread); + sprintf(res, "<– back

          \nThread %hu%s%s" + " Detection resumed\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -1187,13 +1240,17 @@ static unsigned int detection(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

          \nThread %hu" - " Detection paused\n", thread, thread); + sprintf(res, "<– back

          \nThread %hu%s%s" + " Detection paused\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); send_template(client_socket, res); send_template_end_client(client_socket); } else { send_template_ini_client_raw(client_socket); - sprintf(res, "Thread %hu Detection paused\nDone\n", thread); + sprintf(res, "Thread %hu%s%s Detection paused\nDone\n", thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); send_template_raw(client_socket, res); } } else { @@ -1215,13 +1272,17 @@ static unsigned int detection(char *pointer, char *res, unsigned int length_uri, send_template(client_socket, res); if (thread == 0) { do{ - sprintf(res, "Thread %hu %s
          \n", i, + sprintf(res, "Thread %hu%s%s %s
          \n", i, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", (!cnt[i]->running)? "NOT RUNNING" : (cnt[i]->lost_connection)?CONNECTION_KO:CONNECTION_OK); send_template(client_socket, res); } while (cnt[++i]); } else { - sprintf(res, "Thread %hu %s\n", thread, + sprintf(res, "Thread %hu%s%s %s\n", thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", (!cnt[thread]->running)? "NOT RUNNING" : (cnt[thread]->lost_connection)? CONNECTION_KO: CONNECTION_OK); send_template(client_socket, res); @@ -1393,9 +1454,12 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          " - "Thread %hu
          \n" + "Thread %hu%s%s
          \n" "track set relative pan=%s
          \n", - thread, thread, panvalue); + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + panvalue); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -1407,7 +1471,9 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, /* error in track action */ if (cnt[0]->conf.webcontrol_html_output) { sprintf(res, "<– back

          " - "Thread %hu\n", thread, thread); + "Thread %hu%s%s\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); response_client(client_socket, track_error, res); } else { response_client(client_socket, track_error_raw, NULL); @@ -1430,9 +1496,12 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          " - "Thread %hu
          \n" + "Thread %hu%s%s
          \n" "track set relative tilt=%s\n", - thread, thread, tiltvalue); + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + tiltvalue); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -1444,7 +1513,9 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, /* error in track action */ if (cnt[0]->conf.webcontrol_html_output) { sprintf(res, "<– back

          " - "Thread %hu\n", thread, thread); + "Thread %hu%s%s\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); response_client(client_socket, track_error, res); } else { response_client(client_socket, track_error_raw, NULL); @@ -1459,9 +1530,12 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          " - "Thread %hu
          \n" - "track set absolute x=%s\n", - thread, thread, x_value); + "Thread %hu%s%s
          \n" + "track set absolute x=%s\n", + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + x_value); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -1473,7 +1547,9 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, /* error in track action */ if (cnt[0]->conf.webcontrol_html_output) { sprintf(res, "<– back

          " - "Thread %hu\n", thread, thread); + "Thread %hu%s%s\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); response_client(client_socket, track_error, res); } else { response_client(client_socket, track_error_raw, NULL); @@ -1489,9 +1565,12 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          " - "Thread %hu
          \n" + "Thread %hu%s%s
          \n" "track set absolute y=%s
          \n", - thread, thread, y_value); + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + y_value); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -1503,7 +1582,9 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, /* error in track action */ if (cnt[0]->conf.webcontrol_html_output) { sprintf(res, "<– back

          " - "Thread %hu\n", thread, thread); + "Thread %hu%s%s\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); response_client(client_socket, track_error, res); } else { response_client(client_socket, track_error_raw, NULL); @@ -1661,9 +1742,12 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          " - "Thread %hu
          \n" + "Thread %hu%s%s
          \n" "track absolute set x=%s y=%s
          \n", - thread, thread, x_value, y_value); + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + x_value, y_value); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -1675,7 +1759,9 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, /* error in track action */ if (cnt[0]->conf.webcontrol_html_output) { sprintf(res, "<– back

          " - "Thread %hu\n", thread, thread); + "Thread %hu%s%s\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); response_client(client_socket, track_error, res); } else { response_client(client_socket, track_error_raw, NULL); @@ -1711,9 +1797,12 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          " - "Thread %hu
          \n" + "Thread %hu%s%s
          \n" "track relative pan=%s tilt=%s\n", - thread, thread, panvalue, tiltvalue); + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + panvalue, tiltvalue); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -1727,7 +1816,9 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, /* error in track tilt */ if (cnt[0]->conf.webcontrol_html_output) { sprintf(res, "<– back

          " - "Thread %hu\n", thread, thread); + "Thread %hu%s%s\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); response_client(client_socket, track_error, res); } else { response_client(client_socket, track_error_raw, NULL); @@ -1737,8 +1828,10 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, /* error in track pan */ if (cnt[0]->conf.webcontrol_html_output) { - sprintf(res, "<– back

          Thread %hu\n", - thread, thread); + sprintf(res, "<– back

          Thread %hu%s%s\n", + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); response_client(client_socket, track_error, res); } else { response_client(client_socket, track_error_raw, NULL); @@ -1747,7 +1840,7 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, } else if (length_uri == 0) { if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

          \nThread %hu
          \n" + sprintf(res, "<– back

          \nThread %hu%s%s
          \n" "\n" "Pan\n" "Tilt\n" @@ -1757,7 +1850,9 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, "X\n" "Y\n" "\n" - "
        • \n", thread, thread); + "\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -1783,8 +1878,10 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

          \nThread %hu" - "
          track set center", thread, thread); + sprintf(res, "<– back

          \nThread %hu%s%s" + "
          track set center", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : ""); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -1805,8 +1902,10 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, if (length_uri==0) { if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

          \nThread %hu" + sprintf(res, "<– back

          \nThread %hu%s%s" "
          track auto %s", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", (cnt[thread]->track.active)? "enabled":"disabled"); send_template(client_socket, res); send_template_end_client(client_socket); @@ -1846,9 +1945,11 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          " - "Thread %hu
          " - "track auto %s", thread, thread, - (cnt[thread]->track.active)? "enabled":"disabled"); + "Thread %hu%s%s
          " + "track auto %s", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + (cnt[thread]->track.active)? "enabled":"disabled"); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -1867,8 +1968,10 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          " - "Thread %hu" + "Thread %hu%s%s" "
          track auto %s
          ", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", active ? "enabled":"disabled"); send_template(client_socket, res); send_template_end_client(client_socket); @@ -1900,12 +2003,15 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

          \nThread %hu\n" + sprintf(res, "<– back

          \nThread %hu%s%s\n" "
          \n" - "
          \n", thread, thread, (cnt[thread]->track.active) ? "selected":"", + "\n", thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + (cnt[thread]->track.active) ? "selected":"", (cnt[thread]->track.active) ? "selected":""); send_template(client_socket, res); send_template_end_client(client_socket); @@ -1941,7 +2047,7 @@ static unsigned int track(char *pointer, char *res, unsigned int length_uri, * 0 on action restart or quit * 1 on success */ -static unsigned int handle_get(int client_socket, const char *url, void *userdata) +static unsigned int handle_get(int client_socket, const char *url, void *userdata, const char *httphostname) { struct context **cnt = userdata; @@ -1955,15 +2061,54 @@ static unsigned int handle_get(int client_socket, const char *url, void *userdat /* ROOT_URI -> GET / */ if (!strcmp(url, "/")) { int y; + int counter; + char hostname[1024]; + + //Send the webcontrol section if applicable if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "Motion "VERSION" Running [%hu] Threads
          \n" - "All
          \n", i); + "All\n", i); send_template(client_socket, res); + + counter = 0; for (y = 1; y < i; y++) { - sprintf(res, "Thread %hu
          \n", y, y); + counter++; + if (counter == 6){ + sprintf(res, "
          "); + send_template(client_socket, res); + counter = 0; + } + sprintf(res, "Thread %hu%s%s\n", y, y, + cnt[y]->conf.camera_name ? " -- " : "", + cnt[y]->conf.camera_name ? cnt[y]->conf.camera_name : ""); send_template(client_socket, res); } + sprintf(res, "
          "); + send_template(client_socket, res); + + if (!httphostname) + { + hostname[1023] = '\0'; + gethostname(hostname, 1023); + httphostname = hostname; + } + + //Send the preview section + for (y = 0; y < i; y++) { + if (cnt[y]->conf.stream_port) { + if (cnt[y]->conf.stream_preview_newline) { + sprintf(res, "
          "); + send_template(client_socket, res); + } + sprintf(res, " " + "\n" + ,httphostname,cnt[y]->conf.stream_port + ,httphostname,cnt[y]->conf.stream_port + ,cnt[y]->conf.stream_preview_scale); + send_template(client_socket, res); + } + } send_template_end_client(client_socket); } else { send_template_ini_client_raw(client_socket); @@ -2013,12 +2158,15 @@ static unsigned int handle_get(int client_socket, const char *url, void *userdat if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          \n" - "Thread %hd
          \n" + "Thread %hd%s%s
          \n" "list
          \n" "write
          \n" "set
          \n" "get
          \n", - thread, thread, thread, thread, thread, thread); + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + thread, thread, thread, thread); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -2046,12 +2194,15 @@ static unsigned int handle_get(int client_socket, const char *url, void *userdat if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          \n" - "Thread %hd
          \n" + "Thread %hd%s%s
          \n" "makemovie
          \n" "snapshot
          \n" "restart
          \n" "quit
          \n", - thread, thread, thread, thread, thread, thread); + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + thread, thread, thread, thread); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -2080,12 +2231,15 @@ static unsigned int handle_get(int client_socket, const char *url, void *userdat if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          \n" - "Thread %hd
          \n" + "Thread %hd%s%s
          \n" "status
          \n" "start
          \n" "pause
          \n" "connection
          \n", - thread, thread, thread, thread, thread, thread); + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + thread, thread, thread, thread); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -2111,12 +2265,15 @@ static unsigned int handle_get(int client_socket, const char *url, void *userdat if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); sprintf(res, "<– back

          \n" - "Thread %hd
          \n" + "Thread %hd%s%s
          \n" "track set pan/tilt
          \n" "track center
          \n" "track auto
          \n" "track status
          \n", - thread, thread, thread, thread, thread, thread); + thread, thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + thread, thread, thread, thread); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -2160,12 +2317,15 @@ static unsigned int handle_get(int client_socket, const char *url, void *userdat /* /thread_number/ requested */ if (cnt[0]->conf.webcontrol_html_output) { send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

          \nThread %hd
          \n" + sprintf(res, "<– back

          \nThread %hd%s%s
          \n" "config
          \n" "action
          \n" "detection
          \n" "track
          \n", - thread, thread, thread, thread, thread); + thread, + cnt[thread]->conf.camera_name ? " -- " : "", + cnt[thread]->conf.camera_name ? cnt[thread]->conf.camera_name : "", + thread, thread, thread, thread); send_template(client_socket, res); send_template_end_client(client_socket); } else { @@ -2221,7 +2381,7 @@ static unsigned int read_client(int client_socket, void *userdata, char *auth) nread = read_nonblock(client_socket, buffer, length); if (nread <= 0) { - MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO, "%s: motion-httpd First Read Error"); + MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO, "%s: motion-httpd First Read Error"); pthread_mutex_unlock(&httpd_mutex); return 1; } else { @@ -2229,6 +2389,7 @@ static unsigned int read_client(int client_socket, void *userdata, char *auth) char url[512]={'\0'}; char protocol[10]={'\0'}; char *authentication=NULL; + char *hostname=NULL; buffer[nread] = '\0'; @@ -2303,6 +2464,40 @@ static unsigned int read_client(int client_socket, void *userdata, char *auth) return 1; } + if ((hostname = strstr(buffer,"Host:"))) { + /* use the hostname the browser used to connect to us when + * constructing links to the stream ports. If available + * (which it is in all modern browsers) it is more likely to + * work that the result of gethostname(), which is reliant on + * the machine we're running on having it's hostname setup + * correctly and corresponding DNS in place. */ + hostname += strlen("Host:"); + char *end_host = strstr(hostname,"\r\n"); + if (end_host) { + while (hostname < end_host && isspace(hostname[0])) + hostname++; + while (hostname < end_host && isspace(end_host[-1])) + end_host--; + /* we have a string that is the hostname followed by + * optionally a colon and a port number - strip off any + * port number & colon */ + char *colon = NULL; + if (hostname[0] == '[') { + // hostname is a IPv6 address like "[::1]" + char *end_bracket = memchr(hostname, ']', end_host-hostname); + // look for the colon after the "]" + colon = memchr(end_bracket, ':', end_host-end_bracket); + } else { + colon = memchr(hostname, ':', end_host-hostname); + } + if (colon) + end_host = colon; + hostname = strndup(hostname, end_host-hostname); + } else { + hostname = NULL; + } + } + if (auth != NULL) { if ((authentication = strstr(buffer,"Basic"))) { char *end_auth = NULL; @@ -2314,6 +2509,7 @@ static unsigned int read_client(int client_socket, void *userdata, char *auth) char response[1024]; snprintf(response, sizeof (response), request_auth_response_template, method); warningkill = write_nonblock(client_socket, response, strlen(response)); + free(hostname); pthread_mutex_unlock(&httpd_mutex); return 1; } @@ -2322,10 +2518,11 @@ static unsigned int read_client(int client_socket, void *userdata, char *auth) char response[1024] = {'\0'}; snprintf(response, sizeof (response), request_auth_response_template, method); warningkill = write_nonblock(client_socket, response, strlen(response)); + free(hostname); pthread_mutex_unlock(&httpd_mutex); return 1; } else { - ret = handle_get(client_socket, url, cnt); + ret = handle_get(client_socket, url, cnt, hostname); /* A valid auth request. Process it. */ } } else { @@ -2333,13 +2530,15 @@ static unsigned int read_client(int client_socket, void *userdata, char *auth) char response[1024] = {'\0'}; snprintf(response, sizeof (response), request_auth_response_template, method); warningkill = write_nonblock(client_socket, response, strlen(response)); + free(hostname); pthread_mutex_unlock(&httpd_mutex); return 1; } } else { - ret = handle_get(client_socket, url, cnt); + ret = handle_get(client_socket, url, cnt, hostname); /* A valid request. Process it. */ } + free(hostname); } } pthread_mutex_unlock(&httpd_mutex); @@ -2491,7 +2690,7 @@ void httpd_run(struct context **cnt) char *userpass = NULL; size_t auth_size = strlen(cnt[0]->conf.webcontrol_authentication); - authentication = (char *) mymalloc(BASE64_LENGTH(auth_size) + 1); + authentication = mymalloc(BASE64_LENGTH(auth_size) + 1); userpass = mymalloc(auth_size + 4); /* base64_encode can read 3 bytes after the end of the string, initialize it */ memset(userpass, 0, auth_size + 4); @@ -2502,10 +2701,10 @@ void httpd_run(struct context **cnt) while ((client_sent_quit_message) && (!closehttpd)) { - client_socket_fd = acceptnonblocking(sd, 1); + client_socket_fd = acceptnonblocking(sd, NONBLOCK_TIMEOUT); if (client_socket_fd < 0) { - if ((!cnt[0]) || (cnt[0]->finish)) { + if ((!cnt[0]) || (cnt[0]->webcontrol_finish)) { MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "%s: motion-httpd - Finishing"); closehttpd = 1; } @@ -2521,8 +2720,7 @@ void httpd_run(struct context **cnt) } - if (authentication != NULL) - free(authentication); + free(authentication); close(sd); MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "%s: motion-httpd Closing"); pthread_mutex_destroy(&httpd_mutex); @@ -2535,7 +2733,23 @@ void httpd_run(struct context **cnt) void *motion_web_control(void *arg) { struct context **cnt = arg; + +#ifdef HAVE_PTHREAD_SETNAME_NP + pthread_setname_np(pthread_self(), "web_control"); +#endif + httpd_run(cnt); + + /* + * Update how many threads we have running. This is done within a + * mutex lock to prevent multiple simultaneous updates to + * 'threads_running'. + */ + pthread_mutex_lock(&global_lock); + threads_running--; + cnt[0]->webcontrol_running = 0; + pthread_mutex_unlock(&global_lock); + MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO, "%s: motion-httpd thread exit"); pthread_exit(NULL); }