Merge branch 'master' into filter_by_runstate
This commit is contained in:
commit
01717a5c14
|
@ -0,0 +1,4 @@
|
|||
web/api/lib
|
||||
web/skins/classic/js/jquery-1.11.3.js
|
||||
web/skins/classic/js/jquery.js
|
||||
web/tools/mootools
|
|
@ -0,0 +1,29 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"env": {
|
||||
"browser": true,
|
||||
},
|
||||
"extends": ["google"],
|
||||
"rules": {
|
||||
"brace-style": "off",
|
||||
"camelcase": "off",
|
||||
"comma-dangle": "off",
|
||||
"key-spacing": "off",
|
||||
"max-len": "off",
|
||||
"new-cap": ["error", {
|
||||
capIsNewExceptions: ["Error", "Warning", "Debug", "Polygon_calcArea", "Play", "Stop"],
|
||||
newIsCapExceptionPattern: "^Asset\.."
|
||||
}],
|
||||
"no-array-constructor": "off",
|
||||
"no-caller": "off",
|
||||
"no-new-object": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-var": "off",
|
||||
"object-curly-spacing": "off",
|
||||
"prefer-rest-params": "off",
|
||||
"quotes": "off",
|
||||
"require-jsdoc": "off",
|
||||
"spaced-comment": "off",
|
||||
},
|
||||
};
|
81
.travis.yml
81
.travis.yml
|
@ -1,51 +1,56 @@
|
|||
language: cpp
|
||||
sudo: required
|
||||
dist: trusty
|
||||
git:
|
||||
depth: 9999999
|
||||
notifications:
|
||||
irc: "chat.freenode.net#zoneminder-dev"
|
||||
irc: chat.freenode.net#zoneminder-dev
|
||||
branches:
|
||||
except:
|
||||
- modern
|
||||
- modern
|
||||
cache: ccache
|
||||
addons:
|
||||
sauce_connect:
|
||||
username: "zoneminder"
|
||||
access_key: "046ec7c1-c598-4e7e-949a-f86e725d1722"
|
||||
ssh_known_hosts: zmrepo.zoneminder.com
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: ppa:iconnor/zoneminder
|
||||
- key_url: http://keyserver.ubuntu.com:11371/pks/lookup?op=get&search=0x4D0BF748776FFB04
|
||||
packages:
|
||||
- gdebi
|
||||
- yum-utils
|
||||
- patch
|
||||
- git
|
||||
- curl
|
||||
- sshfs
|
||||
- sed
|
||||
env:
|
||||
global:
|
||||
- LD_LIBRARY_PATH="/usr/local/lib:/opt/libjpeg-turbo/lib:$LD_LIBRARY_PATH"
|
||||
- DEB_HOST_GNU_TYPE=$(dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
- DEB_BUILD_GNU_TYPE=$(dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
- CFLAGS="-DZM_FFMPEG_CVS -DHAVE_LIBCRYPTO -I/usr/local/include"
|
||||
- CXXFLAGS="$CFLAGS"
|
||||
matrix:
|
||||
- ZM_BUILDMETHOD=cmake
|
||||
- OS=el DIST=6
|
||||
- OS=el DIST=7
|
||||
- OS=fedora DIST=24
|
||||
- OS=fedora DIST=25
|
||||
- OS=ubuntu DIST=trusty
|
||||
- OS=ubuntu DIST=xenial
|
||||
- OS=ubuntu DIST=trusty ARCH=i386
|
||||
- OS=ubuntu DIST=xenial ARCH=i386
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
- gcc
|
||||
services:
|
||||
- mysql
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y libpolkit-gobject-1-dev zlib1g-dev apache2 php5 php5-mysql build-essential libmysqlclient-dev libssl-dev libbz2-dev libpcre3-dev libdbi-perl libarchive-zip-perl libdate-manip-perl libdevice-serialport-perl libmime-perl libwww-perl libdbd-mysql-perl libsys-mmap-perl yasm automake autoconf cmake libjpeg-turbo8-dev apache2-mpm-prefork libapache2-mod-php5 php5-cli libtheora-dev libvorbis-dev libvpx-dev libx264-dev libvlccore-dev libvlc-dev
|
||||
install:
|
||||
- git clone -b n3.0 --depth=1 git://source.ffmpeg.org/ffmpeg.git
|
||||
- cd ffmpeg
|
||||
- ./configure --enable-shared --enable-swscale --enable-gpl --enable-libx264 --enable-libvpx --enable-libvorbis --enable-libtheora
|
||||
- make -j `grep processor /proc/cpuinfo|wc -l`
|
||||
- sudo make install
|
||||
- sudo make install-libs
|
||||
before_script:
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- mysql -uroot -e "CREATE DATABASE IF NOT EXISTS zm"
|
||||
- mysql -uroot -e "GRANT ALL ON zm.* TO 'zmuser'@'localhost' IDENTIFIED BY 'zmpass'";
|
||||
- mysql -uroot -e "FLUSH PRIVILEGES"
|
||||
- mysql
|
||||
- docker
|
||||
script:
|
||||
- if [ "$ZM_BUILDMETHOD" = "cmake" ]; then cmake -DZM_ONVIF=OFF -DCMAKE_INSTALL_PREFIX="/usr"; fi
|
||||
- make
|
||||
- sudo make install
|
||||
- if [ "$ZM_BUILDMETHOD" = "cmake" ]; then sudo ./zmlinkcontent.sh; fi
|
||||
- mysql -uzmuser -pzmpass < db/zm_create.sql
|
||||
- mysql -uzmuser -pzmpass zm < db/test.monitor.sql
|
||||
- sudo zmpkg.pl start
|
||||
- sudo zmfilter.pl -f purgewhenfull
|
||||
- utils/packpack/startpackpack.sh
|
||||
|
||||
before_deploy:
|
||||
- openssl aes-256-cbc -K $encrypted_62a62750aa73_key -iv $encrypted_62a62750aa73_iv -in ./utils/packpack/deploy_rsa.enc -out /tmp/deploy_rsa -d
|
||||
- eval "$(ssh-agent -s)"
|
||||
- chmod 600 /tmp/deploy_rsa
|
||||
- ssh-add /tmp/deploy_rsa
|
||||
|
||||
deploy:
|
||||
provider: script
|
||||
skip_cleanup: true
|
||||
script: utils/packpack/rsync_xfer.sh
|
||||
on:
|
||||
branch: master
|
||||
|
||||
|
|
124
CMakeLists.txt
124
CMakeLists.txt
|
@ -66,6 +66,24 @@ set(CMAKE_CXX_FLAGS_DEBUG "-Wall -D__STDC_CONSTANT_MACROS -g")
|
|||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
|
||||
|
||||
# GCC below 6.0 doesn't support __target__("fpu=neon") attribute, required for compiling ARM Neon code, otherwise compilation fails.
|
||||
# Must use -mfpu=neon compiler flag instead, but only do that for processors that support neon, otherwise strip the neon code alltogether,
|
||||
# because passing -fmpu=neon is unsafe to processors that don't support neon
|
||||
IF(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" AND CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
|
||||
EXEC_PROGRAM(grep ARGS " neon " "/proc/cpuinfo" OUTPUT_VARIABLE neonoutput RETURN_VALUE neonresult)
|
||||
IF(neonresult EQUAL 0)
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mfpu=neon")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mfpu=neon")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -mfpu=neon")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -mfpu=neon")
|
||||
ELSE(neonresult EQUAL 0)
|
||||
add_definitions(-DZM_STRIP_NEON=1)
|
||||
message(STATUS "ARM Neon is not available on this processor. Neon functions will be absent")
|
||||
ENDIF(neonresult EQUAL 0)
|
||||
ENDIF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
|
||||
ENDIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" AND CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
|
||||
# Modules that we need:
|
||||
include (GNUInstallDirs)
|
||||
include (CheckIncludeFile)
|
||||
|
@ -85,7 +103,8 @@ mark_as_advanced(
|
|||
ZM_PERL_MM_PARMS
|
||||
ZM_PERL_SEARCH_PATH
|
||||
ZM_TARGET_DISTRO
|
||||
ZM_CONFIG_DIR)
|
||||
ZM_CONFIG_DIR
|
||||
ZM_SYSTEMD)
|
||||
|
||||
set(ZM_RUNDIR "/var/run/zm" CACHE PATH
|
||||
"Location of transient process files, default: /var/run/zm")
|
||||
|
@ -148,6 +167,8 @@ set(ZM_PERL_SEARCH_PATH "" CACHE PATH
|
|||
installed outside Perl's default search path.")
|
||||
set(ZM_TARGET_DISTRO "" CACHE STRING
|
||||
"Build ZoneMinder for a specific distribution. Currently, valid names are: fc24, fc25, el6, el7, OS13, FreeBSD")
|
||||
set(ZM_SYSTEMD "OFF" CACHE BOOL
|
||||
"Set to ON to force building ZM with systemd support. default: OFF")
|
||||
|
||||
# Reassign some variables if a target distro has been specified
|
||||
if((ZM_TARGET_DISTRO STREQUAL "fc24") OR (ZM_TARGET_DISTRO STREQUAL "fc25"))
|
||||
|
@ -205,6 +226,11 @@ include_directories("${CMAKE_BINARY_DIR}")
|
|||
# This is required to enable searching in lib64 (if exists), do not change
|
||||
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON)
|
||||
|
||||
# Set the systemd flag if systemd is autodetected or ZM_SYSTEMD has been set
|
||||
if(ZM_SYSTEMD OR (IS_DIRECTORY /usr/lib/systemd/system) OR (IS_DIRECTORY /lib/systemd/system))
|
||||
set(WITH_SYSTEMD 1)
|
||||
endif(ZM_SYSTEMD OR (IS_DIRECTORY /usr/lib/systemd/system) OR (IS_DIRECTORY /lib/systemd/system))
|
||||
|
||||
# System checks
|
||||
check_include_file("libv4l1-videodev.h" HAVE_LIBV4L1_VIDEODEV_H)
|
||||
if(NOT HAVE_LIBV4L1_VIDEODEV_H)
|
||||
|
@ -386,13 +412,13 @@ find_library(MYSQLCLIENT_LIBRARIES mysqlclient PATH_SUFFIXES mysql)
|
|||
if(MYSQLCLIENT_LIBRARIES)
|
||||
set(HAVE_LIBMYSQLCLIENT 1)
|
||||
list(APPEND ZM_BIN_LIBS "${MYSQLCLIENT_LIBRARIES}")
|
||||
find_path(MYSQLCLIENT_INCLUDE_DIR mysql/mysql.h)
|
||||
find_path(MYSQLCLIENT_INCLUDE_DIR mysql.h PATH_SUFFIXES mysql)
|
||||
if(MYSQLCLIENT_INCLUDE_DIR)
|
||||
include_directories("${MYSQLCLIENT_INCLUDE_DIR}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${MYSQLCLIENT_INCLUDE_DIR}")
|
||||
endif(MYSQLCLIENT_INCLUDE_DIR)
|
||||
mark_as_advanced(FORCE MYSQLCLIENT_LIBRARIES MYSQLCLIENT_INCLUDE_DIR)
|
||||
check_include_file("mysql/mysql.h" HAVE_MYSQL_H)
|
||||
check_include_file("mysql.h" HAVE_MYSQL_H)
|
||||
if(NOT HAVE_MYSQL_H)
|
||||
message(FATAL_ERROR
|
||||
"ZoneMinder requires MySQL headers - check that MySQL development packages are installed")
|
||||
|
@ -402,6 +428,59 @@ else(MYSQLCLIENT_LIBRARIES)
|
|||
"ZoneMinder requires mysqlclient but it was not found on your system")
|
||||
endif(MYSQLCLIENT_LIBRARIES)
|
||||
|
||||
# x264 (using find_library and find_path)
|
||||
find_library(X264_LIBRARIES x264)
|
||||
if(X264_LIBRARIES)
|
||||
set(HAVE_LIBX264 1)
|
||||
list(APPEND ZM_BIN_LIBS "${X264_LIBRARIES}")
|
||||
find_path(X264_INCLUDE_DIR x264.h)
|
||||
if(X264_INCLUDE_DIR)
|
||||
include_directories("${X264_INCLUDE_DIR}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${X264_INCLUDE_DIR}")
|
||||
endif(X264_INCLUDE_DIR)
|
||||
mark_as_advanced(FORCE X264_LIBRARIES X264_INCLUDE_DIR)
|
||||
check_include_files("stdint.h;x264.h" HAVE_X264_H)
|
||||
set(optlibsfound "${optlibsfound} x264")
|
||||
else(X264_LIBRARIES)
|
||||
set(optlibsnotfound "${optlibsnotfound} x264")
|
||||
endif(X264_LIBRARIES)
|
||||
|
||||
# mp4v2 (using find_library and find_path)
|
||||
find_library(MP4V2_LIBRARIES mp4v2)
|
||||
if(MP4V2_LIBRARIES)
|
||||
set(HAVE_LIBMP4V2 1)
|
||||
list(APPEND ZM_BIN_LIBS "${MP4V2_LIBRARIES}")
|
||||
|
||||
# mp4v2/mp4v2.h
|
||||
find_path(MP4V2_INCLUDE_DIR mp4v2/mp4v2.h)
|
||||
if(MP4V2_INCLUDE_DIR)
|
||||
include_directories("${MP4V2_INCLUDE_DIR}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${MP4V2_INCLUDE_DIR}")
|
||||
endif(MP4V2_INCLUDE_DIR)
|
||||
check_include_file("mp4v2/mp4v2.h" HAVE_MP4V2_MP4V2_H)
|
||||
|
||||
# mp4v2.h
|
||||
find_path(MP4V2_INCLUDE_DIR mp4v2.h)
|
||||
if(MP4V2_INCLUDE_DIR)
|
||||
include_directories("${MP4V2_INCLUDE_DIR}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${MP4V2_INCLUDE_DIR}")
|
||||
endif(MP4V2_INCLUDE_DIR)
|
||||
check_include_file("mp4v2.h" HAVE_MP4V2_H)
|
||||
|
||||
# mp4.h
|
||||
find_path(MP4V2_INCLUDE_DIR mp4.h)
|
||||
if(MP4V2_INCLUDE_DIR)
|
||||
include_directories("${MP4V2_INCLUDE_DIR}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${MP4V2_INCLUDE_DIR}")
|
||||
endif(MP4V2_INCLUDE_DIR)
|
||||
check_include_file("mp4.h" HAVE_MP4_H)
|
||||
|
||||
mark_as_advanced(FORCE MP4V2_LIBRARIES MP4V2_INCLUDE_DIR)
|
||||
set(optlibsfound "${optlibsfound} mp4v2")
|
||||
else(MP4V2_LIBRARIES)
|
||||
set(optlibsnotfound "${optlibsnotfound} mp4v2")
|
||||
endif(MP4V2_LIBRARIES)
|
||||
|
||||
set(PATH_FFMPEG "")
|
||||
set(OPT_FFMPEG "no")
|
||||
# Do not check for ffmpeg if ZM_NO_FFMPEG is on
|
||||
|
@ -492,6 +571,23 @@ if(NOT ZM_NO_FFMPEG)
|
|||
set(optlibsnotfound "${optlibsnotfound} SWScale")
|
||||
endif(SWSCALE_LIBRARIES)
|
||||
|
||||
# rescale (using find_library and find_path)
|
||||
find_library(AVRESAMPLE_LIBRARIES avresample)
|
||||
if(AVRESAMPLE_LIBRARIES)
|
||||
set(HAVE_LIBAVRESAMPLE 1)
|
||||
list(APPEND ZM_BIN_LIBS "${AVRESAMPLE_LIBRARIES}")
|
||||
find_path(AVRESAMPLE_INCLUDE_DIR "libavresample/avresample.h" /usr/include/ffmpeg)
|
||||
if(AVRESAMPLE_INCLUDE_DIR)
|
||||
include_directories("${AVRESAMPLE_INCLUDE_DIR}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${AVRESAMPLE_INCLUDE_DIR}")
|
||||
endif(AVRESAMPLE_INCLUDE_DIR)
|
||||
mark_as_advanced(FORCE AVRESAMPLE_LIBRARIES AVRESAMPLE_INCLUDE_DIR)
|
||||
check_include_file("libavresample/avresample.h" HAVE_LIBAVRESAMPLE_AVRESAMPLE_H)
|
||||
set(optlibsfound "${optlibsfound} AVResample")
|
||||
else(AVRESAMPLE_LIBRARIES)
|
||||
set(optlibsnotfound "${optlibsnotfound} AVResample")
|
||||
endif(AVRESAMPLE_LIBRARIES)
|
||||
|
||||
# Find the path to the ffmpeg executable
|
||||
find_program(FFMPEG_EXECUTABLE
|
||||
NAMES ffmpeg avconv
|
||||
|
@ -524,6 +620,13 @@ if(NOT ZM_NO_LIBVLC)
|
|||
endif(LIBVLC_LIBRARIES)
|
||||
endif(NOT ZM_NO_LIBVLC)
|
||||
|
||||
find_package(Boost 1.36.0)
|
||||
if(Boost_FOUND)
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
set(CMAKE_REQUIRED_INCLUDES "${Boost_INCLUDE_DIRS}")
|
||||
list(APPEND ZM_BIN_LIBS "${Boost_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
# *** END OF LIBRARY CHECKS ***
|
||||
|
||||
# Check for gnutls or crypto
|
||||
|
@ -659,12 +762,14 @@ endif(NOT ZM_WEB_GROUP)
|
|||
message(STATUS "Using web user: ${ZM_WEB_USER}")
|
||||
message(STATUS "Using web group: ${ZM_WEB_GROUP}")
|
||||
|
||||
# Check for polkit
|
||||
find_package(Polkit)
|
||||
if(NOT POLKIT_FOUND)
|
||||
message(FATAL_ERROR
|
||||
"Running ZoneMinder requires polkit. Building ZoneMinder requires the polkit development package.")
|
||||
endif(NOT POLKIT_FOUND)
|
||||
if(WITH_SYSTEMD)
|
||||
# Check for polkit
|
||||
find_package(Polkit)
|
||||
if(NOT POLKIT_FOUND)
|
||||
message(FATAL_ERROR
|
||||
"Running ZoneMinder requires polkit. Building ZoneMinder requires the polkit development package.")
|
||||
endif(NOT POLKIT_FOUND)
|
||||
endif(WITH_SYSTEMD)
|
||||
|
||||
# Some variables that zm expects
|
||||
set(ZM_PID "${ZM_RUNDIR}/zm.pid")
|
||||
|
@ -749,3 +854,4 @@ if(CCACHE_FOUND)
|
|||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
endif(CCACHE_FOUND)
|
||||
|
||||
|
|
24
Dockerfile
24
Dockerfile
|
@ -1,7 +1,7 @@
|
|||
# ZoneMinder
|
||||
|
||||
FROM ubuntu:trusty
|
||||
MAINTAINER Kyle Johnson <kjohnson@gnulnx.net>
|
||||
FROM ubuntu:xenial
|
||||
MAINTAINER Markos Vakondios <mvakondios@gmail.com>
|
||||
|
||||
# Resynchronize the package index files
|
||||
RUN apt-get update && \
|
||||
|
@ -10,8 +10,8 @@ RUN apt-get update && \
|
|||
libdbi-perl libarchive-zip-perl libdate-manip-perl libdevice-serialport-perl libmime-perl libpcre3 \
|
||||
libwww-perl libdbd-mysql-perl libsys-mmap-perl yasm cmake libjpeg-turbo8-dev \
|
||||
libjpeg-turbo8 libtheora-dev libvorbis-dev libvpx-dev libx264-dev libmp4v2-dev libav-tools mysql-client \
|
||||
apache2 php5 php5-mysql apache2-mpm-prefork libapache2-mod-php5 php5-cli openssh-server \
|
||||
mysql-server libvlc-dev libvlc5 libvlccore-dev libvlccore7 vlc-data libcurl4-openssl-dev \
|
||||
apache2 php php-mysql libapache2-mod-php php-cli \
|
||||
mysql-server libvlc-dev libvlc5 libvlccore-dev libvlccore8 vlc-data libcurl4-openssl-dev \
|
||||
libavformat-dev libswscale-dev libavutil-dev libavcodec-dev libavfilter-dev \
|
||||
libavresample-dev libavdevice-dev libpostproc-dev libv4l-dev libtool libnetpbm10-dev \
|
||||
libmime-lite-perl dh-autoreconf dpatch \
|
||||
|
@ -42,22 +42,12 @@ ADD utils/docker/start.sh /tmp/start.sh
|
|||
# give files in /usr/local/share/zoneminder/
|
||||
RUN chown -R www-data:www-data /usr/local/share/zoneminder/
|
||||
|
||||
# Creating SSH privilege escalation dir
|
||||
RUN mkdir /var/run/sshd
|
||||
|
||||
# Adding apache virtual hosts file
|
||||
ADD utils/docker/apache-vhost /etc/apache2/sites-available/000-default.conf
|
||||
RUN cp misc/apache.conf /etc/apache2/sites-available/000-default.conf
|
||||
ADD utils/docker/phpdate.ini /etc/php5/apache2/conf.d/25-phpdate.ini
|
||||
|
||||
# Set the root passwd
|
||||
RUN echo 'root:root' | chpasswd
|
||||
|
||||
# Add a user we can actually login with
|
||||
RUN useradd -m -s /bin/bash -G sudo zoneminder
|
||||
RUN echo 'zoneminder:zoneminder' | chpasswd
|
||||
|
||||
# Expose ssh and http ports
|
||||
EXPOSE 22 80
|
||||
# Expose http port
|
||||
EXPOSE 80
|
||||
|
||||
# Initial database and apache setup:
|
||||
RUN "/ZoneMinder/utils/docker/setup.sh"
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -193,6 +193,7 @@ CREATE TABLE `Events` (
|
|||
`Length` decimal(10,2) NOT NULL default '0.00',
|
||||
`Frames` int(10) unsigned default NULL,
|
||||
`AlarmFrames` int(10) unsigned default NULL,
|
||||
`DefaultVideo` VARCHAR( 64 ) NOT NULL,
|
||||
`TotScore` int(10) unsigned NOT NULL default '0',
|
||||
`AvgScore` smallint(5) unsigned default '0',
|
||||
`MaxScore` smallint(5) unsigned default '0',
|
||||
|
@ -323,7 +324,7 @@ CREATE TABLE `Monitors` (
|
|||
`Type` enum('Local','Remote','File','Ffmpeg','Libvlc','cURL') NOT NULL default 'Local',
|
||||
`Function` enum('None','Monitor','Modect','Record','Mocord','Nodect') NOT NULL default 'Monitor',
|
||||
`Enabled` tinyint(3) unsigned NOT NULL default '1',
|
||||
`LinkedMonitors` varchar(255) NOT NULL default '',
|
||||
`LinkedMonitors` varchar(255),
|
||||
`Triggers` set('X10') NOT NULL default '',
|
||||
`Device` tinytext NOT NULL default '',
|
||||
`Channel` tinyint(3) unsigned NOT NULL default '0',
|
||||
|
@ -332,26 +333,30 @@ CREATE TABLE `Monitors` (
|
|||
`V4LCapturesPerFrame` tinyint(3) unsigned,
|
||||
`Protocol` varchar(16) NOT NULL default '',
|
||||
`Method` varchar(16) NOT NULL default '',
|
||||
`Host` varchar(64) NOT NULL default '',
|
||||
`Host` varchar(64),
|
||||
`Port` varchar(8) NOT NULL default '',
|
||||
`SubPath` varchar(64) NOT NULL default '',
|
||||
`Path` varchar(255) NOT NULL default '',
|
||||
`Path` varchar(255),
|
||||
`Options` varchar(255) not null default '',
|
||||
`User` varchar(64) NOT NULL default '',
|
||||
`Pass` varchar(64) NOT NULL default '',
|
||||
`User` varchar(64),
|
||||
`Pass` varchar(64),
|
||||
`Width` smallint(5) unsigned NOT NULL default '0',
|
||||
`Height` smallint(5) unsigned NOT NULL default '0',
|
||||
`Colours` tinyint(3) unsigned NOT NULL default '1',
|
||||
`Palette` int(10) unsigned NOT NULL default '0',
|
||||
`Orientation` enum('0','90','180','270','hori','vert') NOT NULL default '0',
|
||||
`Deinterlacing` int(10) unsigned NOT NULL default '0',
|
||||
`RTSPDescribe` tinyint(1) unsigned NOT NULL default '0',
|
||||
`SaveJPEGs` TINYINT NOT NULL DEFAULT '3' ,
|
||||
`VideoWriter` TINYINT NOT NULL DEFAULT '0',
|
||||
`EncoderParameters` TEXT,
|
||||
`RecordAudio` TINYINT NOT NULL DEFAULT '0',
|
||||
`RTSPDescribe` tinyint(1) unsigned,
|
||||
`Brightness` mediumint(7) NOT NULL default '-1',
|
||||
`Contrast` mediumint(7) NOT NULL default '-1',
|
||||
`Hue` mediumint(7) NOT NULL default '-1',
|
||||
`Colour` mediumint(7) NOT NULL default '-1',
|
||||
`EventPrefix` varchar(32) NOT NULL default 'Event-',
|
||||
`LabelFormat` varchar(64) NOT NULL default '%N - %y/%m/%d %H:%M:%S',
|
||||
`LabelFormat` varchar(64),
|
||||
`LabelX` smallint(5) unsigned NOT NULL default '0',
|
||||
`LabelY` smallint(5) unsigned NOT NULL default '0',
|
||||
`LabelSize` smallint(5) unsigned NOT NULL DEFAULT '1',
|
||||
|
@ -372,14 +377,14 @@ CREATE TABLE `Monitors` (
|
|||
`RefBlendPerc` tinyint(3) unsigned NOT NULL default '6',
|
||||
`AlarmRefBlendPerc` tinyint(3) unsigned NOT NULL default '6',
|
||||
`Controllable` tinyint(3) unsigned NOT NULL default '0',
|
||||
`ControlId` int(10) unsigned NOT NULL default '0',
|
||||
`ControlId` int(10) unsigned,
|
||||
`ControlDevice` varchar(255) default NULL,
|
||||
`ControlAddress` varchar(255) default NULL,
|
||||
`AutoStopTimeout` decimal(5,2) default NULL,
|
||||
`TrackMotion` tinyint(3) unsigned NOT NULL default '0',
|
||||
`TrackDelay` smallint(5) unsigned NOT NULL default '0',
|
||||
`TrackDelay` smallint(5) unsigned,
|
||||
`ReturnLocation` tinyint(3) NOT NULL default '-1',
|
||||
`ReturnDelay` smallint(5) unsigned NOT NULL default '0',
|
||||
`ReturnDelay` smallint(5) unsigned,
|
||||
`DefaultView` enum('Events','Control') NOT NULL default 'Events',
|
||||
`DefaultRate` smallint(5) unsigned NOT NULL default '100',
|
||||
`DefaultScale` smallint(5) unsigned NOT NULL default '100',
|
||||
|
@ -468,7 +473,7 @@ CREATE TABLE `Users` (
|
|||
`Id` int(10) unsigned NOT NULL auto_increment,
|
||||
`Username` varchar(32) character set latin1 collate latin1_bin NOT NULL default '',
|
||||
`Password` varchar(64) NOT NULL default '',
|
||||
`Language` varchar(8) NOT NULL default '',
|
||||
`Language` varchar(8),
|
||||
`Enabled` tinyint(3) unsigned NOT NULL default '1',
|
||||
`Stream` enum('None','View') NOT NULL default 'None',
|
||||
`Events` enum('None','View','Edit') NOT NULL default 'None',
|
||||
|
@ -477,8 +482,8 @@ CREATE TABLE `Users` (
|
|||
`Groups` enum('None','View','Edit') NOT NULL default 'None',
|
||||
`Devices` enum('None','View','Edit') NOT NULL default 'None',
|
||||
`System` enum('None','View','Edit') NOT NULL default 'None',
|
||||
`MaxBandwidth` varchar(16) NOT NULL default '',
|
||||
`MonitorIds` tinytext NOT NULL,
|
||||
`MaxBandwidth` varchar(16),
|
||||
`MonitorIds` tinytext,
|
||||
PRIMARY KEY (`Id`),
|
||||
UNIQUE KEY `UC_Username` (`Username`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
|
|
@ -1,20 +1,5 @@
|
|||
--
|
||||
-- This updates a 1.30.1 database to 1.30.2
|
||||
--
|
||||
-- Add StateId Column to Events.
|
||||
--
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Events'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'StateId'
|
||||
) > 0,
|
||||
"SELECT 'Column StateId exists in Events'",
|
||||
"ALTER TABLE Events ADD `StateId` int(10) unsigned default NULL AFTER `Notes`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
ALTER TABLE Users MODIFY MonitorIds TEXT NOT NULL;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
--
|
||||
-- This updates a 1.30.2 database to 1.30.3
|
||||
--
|
||||
-- No changes required
|
||||
--
|
|
@ -0,0 +1,5 @@
|
|||
--
|
||||
-- This updates a 1.30.3 database to 1.30.4
|
||||
--
|
||||
-- No changes required
|
||||
--
|
|
@ -0,0 +1,97 @@
|
|||
--
|
||||
-- This updates a 1.29.0 database to 1.30.0
|
||||
--
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Monitors'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'SaveJPEGs'
|
||||
) > 0,
|
||||
"SELECT 'Column SaveJPEGs exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `SaveJPEGs` TINYINT NOT NULL DEFAULT '3' AFTER `Deinterlacing`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Monitors'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'VideoWriter'
|
||||
) > 0,
|
||||
"SELECT 'Column VideoWriter exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `VideoWriter` TINYINT NOT NULL DEFAULT '0' AFTER `SaveJPEGs`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Monitors'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'EncoderParameters'
|
||||
) > 0,
|
||||
"SELECT 'Column EncoderParameters exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `EncoderParameters` TEXT NOT NULL AFTER `VideoWriter`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Events'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'DefaultVideo'
|
||||
) > 0,
|
||||
"SELECT 'Column DefaultVideo exists in Events'",
|
||||
"ALTER TABLE `Events` ADD `DefaultVideo` VARCHAR( 64 ) NOT NULL AFTER `AlarmFrames`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Monitors'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'RecordAudio'
|
||||
) > 0,
|
||||
"SELECT 'Column RecordAudio exists in Monitors'",
|
||||
"ALTER TABLE `Monitors` ADD `RecordAudio` TINYINT NOT NULL DEFAULT '0' AFTER `EncoderParameters`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
--
|
||||
-- The following alters various columns to allow NULLs
|
||||
--
|
||||
|
||||
ALTER TABLE Monitors MODIFY Host varchar(64);
|
||||
ALTER TABLE Monitors MODIFY LabelFormat varchar(64);
|
||||
ALTER TABLE Monitors MODIFY LinkedMonitors varchar(255);
|
||||
ALTER TABLE Monitors MODIFY Options varchar(255);
|
||||
ALTER TABLE Monitors MODIFY Protocol varchar(16);
|
||||
ALTER TABLE Monitors MODIFY User varchar(64);
|
||||
ALTER TABLE Monitors MODIFY Pass varchar(64);
|
||||
ALTER TABLE Monitors MODIFY RTSPDescribe tinyint(1) unsigned;
|
||||
ALTER TABLE Monitors MODIFY ControlId int(10) unsigned;
|
||||
ALTER TABLE Monitors MODIFY TrackDelay smallint(5) unsigned;
|
||||
ALTER TABLE Monitors MODIFY ReturnDelay smallint(5) unsigned;
|
||||
ALTER TABLE Monitors MODIFY EncoderParameters TEXT;
|
||||
ALTER TABLE Monitors MODIFY Path varchar(255);
|
||||
ALTER TABLE Monitors MODIFY V4LMultiBuffer tinyint(1) unsigned;
|
||||
|
||||
ALTER TABLE Users MODIFY MonitorIds tinytext;
|
||||
ALTER TABLE Users MODIFY Language varchar(8);
|
||||
ALTER TABLE Users MODIFY MaxBandwidth varchar(16);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
--
|
||||
-- This updates a 1.30.0 database to 1.30.1
|
||||
--
|
||||
-- Add StateId Column to Events.
|
||||
--
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE table_name = 'Events'
|
||||
AND table_schema = DATABASE()
|
||||
AND column_name = 'StateId'
|
||||
) > 0,
|
||||
"SELECT 'Column StateId exists in Events'",
|
||||
"ALTER TABLE Events ADD `StateId` int(10) unsigned default NULL AFTER `Notes`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
|
@ -1,8 +1,20 @@
|
|||
Alias /zm /usr/share/zoneminder/www
|
||||
|
||||
<Directory /usr/share/zoneminder/www>
|
||||
Options -Indexes +FollowSymLinks
|
||||
<IfModule mod_dir.c>
|
||||
DirectoryIndex index.php
|
||||
</IfModule>
|
||||
</Directory>
|
||||
<IfModule mod_fcgid.c>
|
||||
<Directory /usr/share/zoneminder/www>
|
||||
Options -Indexes +ExecCGI
|
||||
AllowOverride All
|
||||
AddHandler fcgid-script .php
|
||||
FCGIWrapper /usr/bin/php5-cgi
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
</IfModule>
|
||||
<IfModule mod_php5.c>
|
||||
<Directory /usr/share/zoneminder/www>
|
||||
Options -Indexes +FollowSymLinks
|
||||
<IfModule mod_dir.c>
|
||||
DirectoryIndex index.php
|
||||
</IfModule>
|
||||
</Directory>
|
||||
</IfModule>
|
||||
|
|
|
@ -6,14 +6,14 @@ Build-Depends: debhelper (>= 9), cmake
|
|||
, libphp-serialization-perl
|
||||
, libgnutls28-dev | libgnutls-dev
|
||||
, libmysqlclient-dev | libmariadbclient-dev
|
||||
, libjpeg8-dev
|
||||
, libjpeg8-dev | libjpeg-dev
|
||||
, libpcre3-dev
|
||||
, libavcodec-dev, libavformat-dev (>= 3:0.svn20090204), libswscale-dev (>= 3:0.svn20090204), libavutil-dev
|
||||
, libavdevice-dev
|
||||
, libv4l-dev (>= 0.8.3)
|
||||
, libbz2-dev
|
||||
, ffmpeg | libav-tools
|
||||
, libnetpbm10-dev
|
||||
, libavdevice-dev
|
||||
, libvlccore-dev, libvlc-dev
|
||||
, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev
|
||||
, libgcrypt11-dev, libpolkit-gobject-1-dev
|
||||
|
@ -42,11 +42,11 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
|||
, libsys-cpu-perl, libsys-meminfo-perl
|
||||
, libdata-uuid-perl
|
||||
, libpcre3
|
||||
, ffmpeg | libav-tools, libavdevice53
|
||||
, ffmpeg | libav-tools, libavdevice53 | libavdevice55 | libavdevice57
|
||||
, rsyslog | system-log-daemon
|
||||
, netpbm , libjpeg8
|
||||
, zip
|
||||
, libvlccore5 | libvlccore7, libvlc5
|
||||
, libvlccore5 | libvlccore7 | libvlccore8, libvlc5
|
||||
, libpolkit-gobject-1-0, php5-gd
|
||||
Recommends: mysql-server | mariadb-server
|
||||
Description: Video camera security and surveillance solution
|
||||
|
|
|
@ -27,9 +27,9 @@ override_dh_auto_configure:
|
|||
override_dh_auto_install:
|
||||
dh_auto_install --buildsystem=cmake
|
||||
install -D -m 0644 debian/apache.conf $(INSTDIR)/etc/zm/apache.conf
|
||||
rm $(INSTDIR)/usr/share/zoneminder/www/api/lib/Cake/LICENSE.txt
|
||||
rm $(INSTDIR)/usr/share/zoneminder/www/api/.gitignore
|
||||
rm -r $(INSTDIR)/usr/share/zoneminder/www/api/lib/Cake/Test
|
||||
rm -f $(INSTDIR)/usr/share/zoneminder/www/api/lib/Cake/LICENSE.txt
|
||||
rm -f $(INSTDIR)/usr/share/zoneminder/www/api/.gitignore
|
||||
rm -rf $(INSTDIR)/usr/share/zoneminder/www/api/lib/Cake/Test
|
||||
|
||||
override_dh_auto_test:
|
||||
# do not run tests...
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
redhat
|
|
@ -1,3 +0,0 @@
|
|||
Fedora rpm build files have been merged with redhat.
|
||||
See /distros/redhat.
|
||||
|
|
@ -51,6 +51,7 @@ file(MAKE_DIRECTORY sock swap zoneminder zoneminder-upload events images temp)
|
|||
# Install the empty folders
|
||||
install(DIRECTORY sock swap DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(DIRECTORY zoneminder DESTINATION /var/log DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(DIRECTORY zoneminder DESTINATION /var/run DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(DIRECTORY zoneminder-upload DESTINATION /var/spool DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(DIRECTORY events images temp DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
|
|
|
@ -157,7 +157,9 @@ Upgrades
|
|||
|
||||
sudo zmupdate.pl --user=root --pass=<mysql_root_pwd> --version=<from version>
|
||||
|
||||
5. Now start zoneminder:
|
||||
5. Now restart nginx and php-fpm then start and zoneminder:
|
||||
|
||||
sudo systemctl restart nginx
|
||||
sudo systemctl restart php-fpm
|
||||
sudo systemctl start zoneminder
|
||||
|
||||
|
|
|
@ -151,7 +151,8 @@ Upgrades
|
|||
|
||||
sudo zmupdate.pl --user=root --pass=<mysql_root_pwd> --version=<from version>
|
||||
|
||||
5. Now start zoneminder:
|
||||
5. Now restart the web server then start zoneminder:
|
||||
|
||||
sudo systemctl restart httpd
|
||||
sudo systemctl start zoneminder
|
||||
|
||||
|
|
|
@ -150,7 +150,8 @@ Upgrades
|
|||
|
||||
sudo zmupdate.pl --user=root --pass=<mysql_root_pwd> --version=<from version>
|
||||
|
||||
5. Now start zoneminder:
|
||||
5. Now restart the web server then start zoneminder:
|
||||
|
||||
sudo service httpd restart
|
||||
sudo service zoneminder start
|
||||
|
||||
|
|
|
@ -142,7 +142,9 @@ Upgrades
|
|||
|
||||
sudo zmupdate.pl --user=root --pass=<mysql_root_pwd> --version=<from version>
|
||||
|
||||
5. Now start zoneminder:
|
||||
5. Now restart the web server then start zoneminder:
|
||||
|
||||
sudo systemctl restart httpd
|
||||
sudo systemctl start zoneminder
|
||||
|
||||
|
||||
|
|
|
@ -23,3 +23,7 @@ here are a couple of considerations you may want to take.
|
|||
directives found in /etc/httpd/conf.d/zoneminder.conf. You should also
|
||||
comment out the HTTP -> HTTPS Rewrite rule.
|
||||
|
||||
3. Install a fully signed certificate from letsencrypt. See the Letsencrypt
|
||||
site for more information. https://letsencrypt.org/
|
||||
This service is totally free!
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
|
||||
%if "%{zmuid_final}" == "nginx"
|
||||
%global with_nginx 1
|
||||
%global wwwconfdir /etc/nginx/default.d
|
||||
%global wwwconfdir %{_sysconfdir}/nginx/default.d
|
||||
%else
|
||||
%global wwwconfdir /etc/httpd/conf.d
|
||||
%global wwwconfdir %{_sysconfdir}/httpd/conf.d
|
||||
%endif
|
||||
|
||||
%global sslcert %{_sysconfdir}/pki/tls/certs/localhost.crt
|
||||
|
@ -17,6 +17,11 @@
|
|||
# This will tell zoneminder's cmake process we are building against a known distro
|
||||
%global zmtargetdistro %{?rhel:el%{rhel}}%{!?rhel:fc%{fedora}}
|
||||
|
||||
# Fedora >= 25 needs apcu backwards compatibility module
|
||||
%if 0%{?fedora} >= 25
|
||||
%global with_apcu_bc 1
|
||||
%endif
|
||||
|
||||
# Include files for SysV init or systemd
|
||||
%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7
|
||||
%global with_init_systemd 1
|
||||
|
@ -24,19 +29,12 @@
|
|||
%global with_init_sysv 1
|
||||
%endif
|
||||
|
||||
# php-mysql deprecated in f25
|
||||
%if 0%{?fedora} >= 25
|
||||
%global with_php_mysqlnd 1
|
||||
%else
|
||||
%global with_php_mysql 1
|
||||
%endif
|
||||
|
||||
%global readme_suffix %{?rhel:Redhat%{?rhel}}%{!?rhel:Fedora}
|
||||
%global _hardened_build 1
|
||||
|
||||
Name: zoneminder
|
||||
Version: 1.30.1
|
||||
Release: 2%{?dist}
|
||||
Version: 1.30.4
|
||||
Release: 1%{?dist}
|
||||
Summary: A camera monitoring and analysis tool
|
||||
Group: System Environment/Daemons
|
||||
# jscalendar is LGPL (any version): http://www.dynarch.com/projects/calendar/
|
||||
|
@ -46,13 +44,15 @@ Group: System Environment/Daemons
|
|||
License: GPLv2+ and LGPLv2+ and MIT
|
||||
URL: http://www.zoneminder.com/
|
||||
|
||||
Source0: https://github.com/ZoneMinder/ZoneMinder/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
|
||||
Source0: https://github.com/ZoneMinder/ZoneMinder/archive/%{version}.tar.gz#/zoneminder-%{version}.tar.gz
|
||||
Source1: https://github.com/FriendsOfCake/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz
|
||||
|
||||
%{?with_init_systemd:BuildRequires: systemd-devel}
|
||||
%{?with_init_systemd:BuildRequires: mariadb-devel}
|
||||
%{?with_init_systemd:BuildRequires: perl-podlators}
|
||||
%{?with_init_systemd:BuildRequires: polkit-devel}
|
||||
%{?with_init_sysv:BuildRequires: mysql-devel}
|
||||
%{?el6:BuildRequires: epel-rpm-macros}
|
||||
BuildRequires: cmake >= 2.8.7
|
||||
BuildRequires: gnutls-devel
|
||||
BuildRequires: bzip2-devel
|
||||
|
@ -82,17 +82,17 @@ BuildRequires: vlc-devel
|
|||
BuildRequires: libcurl-devel
|
||||
BuildRequires: libv4l-devel
|
||||
BuildRequires: ffmpeg-devel
|
||||
BuildRequires: polkit-devel
|
||||
|
||||
%{?with_nginx:Requires: nginx}
|
||||
%{?with_nginx:Requires: fcgiwrap}
|
||||
%{?with_nginx:Requires: php-fpm}
|
||||
%{!?with_nginx:Requires: httpd php}
|
||||
%{!?with_nginx:Requires: httpd}
|
||||
%{!?with_nginx:Requires: php}
|
||||
%{?with_php_mysqlnd:Requires: php-mysqlnd}
|
||||
%{?with_php_mysql:Requires: php-mysql}
|
||||
Requires: php-mysqli
|
||||
Requires: php-common
|
||||
Requires: php-gd
|
||||
Requires: php-pecl-apcu
|
||||
%{?with_apcu_bc:Requires: php-pecl-apcu-bc}
|
||||
Requires: cambozola
|
||||
Requires: net-tools
|
||||
Requires: psmisc
|
||||
|
@ -137,10 +137,9 @@ designed to support as many cameras as you can attach to your computer without
|
|||
too much degradation of performance.
|
||||
|
||||
%prep
|
||||
%autosetup
|
||||
%autosetup -a 1
|
||||
rmdir ./web/api/app/Plugin/Crud
|
||||
mv -f crud-%{crud_version} ./web/api/app/Plugin/Crud
|
||||
%autosetup -p 1 -a 1 -n ZoneMinder-%{version}
|
||||
%{__rm} -rf ./web/api/app/Plugin/Crud
|
||||
%{__mv} -f crud-%{crud_version} ./web/api/app/Plugin/Crud
|
||||
|
||||
# Change the following default values
|
||||
./utils/zmeditconfigdata.sh ZM_PATH_ZMS /cgi-bin-zm/nph-zms
|
||||
|
@ -281,9 +280,9 @@ rm -rf %{_docdir}/%{name}-%{version}
|
|||
%files
|
||||
%license COPYING
|
||||
%doc AUTHORS README.md distros/redhat/readme/README.%{readme_suffix} distros/redhat/readme/README.https distros/redhat/jscalendar-doc
|
||||
%config(noreplace) %attr(640,root,%{zmgid_final}) /etc/zm/zm.conf
|
||||
%config(noreplace) %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/zm.conf
|
||||
%config(noreplace) %attr(644,root,root) %{wwwconfdir}/zoneminder.conf
|
||||
%config(noreplace) /etc/logrotate.d/zoneminder
|
||||
%config(noreplace) %{_sysconfdir}/logrotate.d/zoneminder
|
||||
|
||||
%if 0%{?with_nginx}
|
||||
%config(noreplace) %{_sysconfdir}/php-fpm.d/zoneminder.conf
|
||||
|
@ -292,6 +291,8 @@ rm -rf %{_docdir}/%{name}-%{version}
|
|||
%if 0%{?with_init_systemd}
|
||||
%{_tmpfilesdir}/zoneminder.conf
|
||||
%{_unitdir}/zoneminder.service
|
||||
%{_datadir}/polkit-1/actions/com.zoneminder.systemctl.policy
|
||||
%{_datadir}/polkit-1/rules.d/com.zoneminder.systemctl.rules
|
||||
%endif
|
||||
|
||||
%if 0%{?with_init_sysv}
|
||||
|
@ -304,7 +305,6 @@ rm -rf %{_docdir}/%{name}-%{version}
|
|||
%{_bindir}/zmc
|
||||
%{_bindir}/zmcontrol.pl
|
||||
%{_bindir}/zmdc.pl
|
||||
%{_bindir}/zmf
|
||||
%{_bindir}/zmfilter.pl
|
||||
%{_bindir}/zmpkg.pl
|
||||
%{_bindir}/zmtrack.pl
|
||||
|
@ -329,9 +329,6 @@ rm -rf %{_docdir}/%{name}-%{version}
|
|||
%{_libexecdir}/zoneminder/
|
||||
%{_datadir}/zoneminder/
|
||||
|
||||
%{_datadir}/polkit-1/actions/com.zoneminder.systemctl.policy
|
||||
%{_datadir}/polkit-1/rules.d/com.zoneminder.systemctl.rules
|
||||
|
||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder
|
||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/events
|
||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/images
|
||||
|
@ -340,9 +337,23 @@ rm -rf %{_docdir}/%{name}-%{version}
|
|||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/temp
|
||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/log/zoneminder
|
||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/spool/zoneminder-upload
|
||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %ghost %{_localstatedir}/run/zoneminder
|
||||
%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/run/zoneminder
|
||||
|
||||
%changelog
|
||||
* Tue May 09 2017 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.4-1
|
||||
- modify autosetup macro parameters
|
||||
- modify requirements for php-pecl-acpu-bc package
|
||||
- 1.30.4 release
|
||||
|
||||
* Tue May 02 2017 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.3-1
|
||||
- 1.30.3 release
|
||||
|
||||
* Thu Mar 30 2017 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.2-2
|
||||
- 1.30.2 release
|
||||
|
||||
* Wed Feb 08 2017 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.2-1
|
||||
- Bump version for 1.30.2 release candidate 1
|
||||
|
||||
* Wed Dec 28 2016 Andrew Bauer <zonexpertconsulting@outlook.com> - 1.30.1-2
|
||||
- Changes from rpmfusion #4393
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
zoneminder (1.28.1-1) unstable; urgency=low
|
||||
|
||||
This version is no longer automatically initialize or upgrade database.
|
||||
See README.Debian for details.
|
||||
|
||||
Changed installation paths (please correct your web server configuration):
|
||||
/usr/share/zoneminder --> /usr/share/zoneminder/www
|
||||
/usr/lib/cgi-bin --> /usr/lib/zoneminder/cgi-bin
|
||||
|
||||
-- Dmitry Smirnov <onlyjob@debian.org> Tue, 31 Mar 2015 15:12:17 +1100
|
|
@ -1,573 +0,0 @@
|
|||
zoneminder (1.28.1+1-vivid-SNAPSHOT2015081701) vivid; urgency=medium
|
||||
|
||||
* include api, switch to cmake build
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Mon, 17 Aug 2015 10:29:23 -0400
|
||||
|
||||
|
||||
zoneminder (1.28.1-8) unstable; urgency=medium
|
||||
|
||||
* Patchworks:
|
||||
+ New upstream "980-fix-image-size.patch".
|
||||
+ New "default_cgi-path.patch" to correct default ZM_PATH_ZMS.
|
||||
* postinst: set "root" as group owner for "/var/log/zm" to silence
|
||||
logrotate warnings.
|
||||
* Minor correction to README.Debian.
|
||||
|
||||
-- Dmitry Smirnov <onlyjob@debian.org> Sun, 16 Aug 2015 19:19:50 +1000
|
||||
|
||||
zoneminder (1.28.1-7) unstable; urgency=medium
|
||||
|
||||
* Build-Depends += "cakephp (<< 3.0.0~)";
|
||||
Zoneminder is not compatible with latest CakePHP.
|
||||
* Handle conffile removal from maintscript.
|
||||
* rules: build man pages reproducibly.
|
||||
* gbp.conf: renamed old style config section [git-dch] to [dch].
|
||||
* README
|
||||
+ added instructions to update owner of the "/etc/zm/zm.conf"
|
||||
(Closes: #789327).
|
||||
+ zmupdate.pl needs CREATE rights.
|
||||
+ added note about required number of "fcgiwrap" workers.
|
||||
* New upstream patch: "zmtrigger-plus.patch".
|
||||
|
||||
-- Dmitry Smirnov <onlyjob@debian.org> Mon, 20 Jul 2015 16:30:15 +1000
|
||||
|
||||
zoneminder (1.28.1-6) unstable; urgency=low
|
||||
|
||||
* New "zoneminder-doc" and "zoneminder-dbg" packages.
|
||||
|
||||
-- Dmitry Smirnov <onlyjob@debian.org> Sun, 19 Apr 2015 14:50:41 +1000
|
||||
|
||||
zoneminder (1.28.1-5) unstable; urgency=low
|
||||
|
||||
* Move handling of "/var/run/zm" and "/tmp/zm" from .service into .tmpfile.
|
||||
Let dh_installinit do the job. Thanks, Andrew Bauer.
|
||||
* Use dh_apache2 to install Apache conf file; remove old conf and symlink.
|
||||
* Promote "libapache2-mod-php5 | php5-fpm" to Recommends.
|
||||
* Build-Depends:
|
||||
+ dh-linktree
|
||||
+ cakephp (>= 2.6.3)
|
||||
+ libjs-jquery
|
||||
+ libjs-mootools
|
||||
* Depends:
|
||||
- libjs-jquery
|
||||
- libjs-mootools
|
||||
* Build-time replace bundled CakePHP with system one using "dh-linktree".
|
||||
* Use "dh-linktree" to handle mootools and jquery symlinks.
|
||||
|
||||
-- Dmitry Smirnov <onlyjob@debian.org> Sun, 19 Apr 2015 11:45:01 +1000
|
||||
|
||||
zoneminder (1.28.1-4) unstable; urgency=low
|
||||
|
||||
* New patch to fix HTML export with USE_DEEP_STORAGE (closes: #723706).
|
||||
* New "783.patch" to describe potential data loss in ZM_USE_DEEP_STORAGE.
|
||||
* New patch to change default date format to region-neutral ISO notation
|
||||
with time zone.
|
||||
* Build sphinx documentation:
|
||||
+ Install "zoneminder.1" man page.
|
||||
+ Build-Depends += "python-sphinx | python3-sphinx"
|
||||
+ Added commented "zoneminder-doc" package.
|
||||
+ Added "docs.patch" to unlink distro-specific installation docs.
|
||||
* rules:
|
||||
+ set ZM_CONTENTDIR, ZM_SOCKDIR and ZM_TMPDIR.
|
||||
+ remove mistakengly installed Perl module templates.
|
||||
* Updated startup scripts to create ZM_TMPDIR.
|
||||
* Hurd improvements:
|
||||
+ New patch to add PATH_MAX definitions.
|
||||
+ Build without MMAP support on Hurd.
|
||||
+ libsys-mmap-perl [!hurd-any].
|
||||
|
||||
-- Dmitry Smirnov <onlyjob@debian.org> Mon, 06 Apr 2015 18:18:55 +1000
|
||||
|
||||
zoneminder (1.28.1-3) unstable; urgency=low
|
||||
|
||||
* Updated Apache2 and nginx configuration templates to support CGI.
|
||||
* Updated README.Debian to document cgi-bin setup.
|
||||
* Removed "/usr/share/zoneminder/www/cgi-bin" symlink.
|
||||
* Added "apache2.patch" to correct Apache2 site configuration example.
|
||||
* control: Suggests += "fcgiwrap".
|
||||
* rules: added dh_systemd overrides to prevent automatic service
|
||||
activation and start.
|
||||
* Added note about manual service activation to README.Debian
|
||||
(Closes: #781733).
|
||||
|
||||
-- Dmitry Smirnov <onlyjob@debian.org> Thu, 02 Apr 2015 23:20:20 +1100
|
||||
|
||||
zoneminder (1.28.1-2) unstable; urgency=low
|
||||
|
||||
* Removed word "Linux" from short package description.
|
||||
* Build-Depends: do not require "libv4l-dev" on Hurd i.e. [!hurd-any].
|
||||
* Added run-time Perl Depends:
|
||||
+ libdbd-mysql-perl
|
||||
+ libimage-info-perl
|
||||
+ libmodule-load-conditional-perl
|
||||
+ libnet-sftp-foreign-perl
|
||||
+ liburi-encode-perl
|
||||
* Prepare for package split: added commented "libzoneminder-perl"
|
||||
and "zoneminder-dbg" packages to "debian/control".
|
||||
* rules: do not install worthless ".packlist" file.
|
||||
* Updated "libv4l1-videodev.h.patch" to fix v4lv1 detection in CMake.
|
||||
|
||||
-- Dmitry Smirnov <onlyjob@debian.org> Thu, 02 Apr 2015 13:25:19 +1100
|
||||
|
||||
zoneminder (1.28.1-1) unstable; urgency=low
|
||||
|
||||
[ Dmitry Smirnov <onlyjob@debian.org> ]
|
||||
* New upstream release [February 2015].
|
||||
* Upload to unstable.
|
||||
* Disabled automatic database upgrades: post(inst|rm) scripts no longer
|
||||
touch database or do unexpected stuff (Closes: #779254).
|
||||
See README.Debian for details.
|
||||
* Updated installation paths:
|
||||
+ /usr/share/zoneminder --> /usr/share/zoneminder/www
|
||||
+ /usr/lib/cgi-bin --> /usr/lib/zoneminder/cgi-bin
|
||||
* Added logrotate config (Closes: #544826).
|
||||
Thanks, Alberto Reyes.
|
||||
* Native systemd service; "--with systemd" added to dh.
|
||||
* Build with CMake instead of autoconf; rules clean-up.
|
||||
* Build with all hardening.
|
||||
* Build and install "zmupdate.pl.1" man page.
|
||||
* Added nginx/php5-fpm configuration example.
|
||||
* Install upstream "apache.conf" example.
|
||||
* Described setup of Zoneminer web site and database in README.Debian.
|
||||
* Install "/etc/zm/zm.conf" with tighter permissions.
|
||||
* Added TODO.Debian.
|
||||
* Added "debian/clean"; "debian/gbp.conf"; bug-presubj.
|
||||
* Remove bundled Cake tests to take ~5 MB off big-usr-share.
|
||||
* Standards-Version: 3.9.6; compat/debhelper to version 9.
|
||||
* Vcs links to new git repository at collab-maint.
|
||||
* Build-Depends:
|
||||
+ dh-systemd
|
||||
+ libgcrypt11-dev --> libgcrypt-dev
|
||||
+ libcurl4-gnutls-dev
|
||||
+ libvlc-dev
|
||||
+ policykit-1 (required by "zmsystemctl.pl")
|
||||
- dh-autoreconf, autoconf, automake
|
||||
* Depends:
|
||||
- apache2
|
||||
- libapache2-mod-php5 (moved to Suggests)
|
||||
- libpcre3 (invalid)
|
||||
- libmodule-load-perl (obsolete; replaced with perl-modules)
|
||||
- libarchive-tar-perl (obsolete; replaced with perl-modules)
|
||||
- mysql-server (moved to Recommends, Closes: #759504).
|
||||
- php5
|
||||
+ libav-tools
|
||||
+ libjs-jquery (replaces bundled component)
|
||||
+ libjs-mootool (replaces bundled component)
|
||||
+ libjson-any-perl (Closes: #690803).
|
||||
+ perl-modules (Closes: #745819).
|
||||
* Recommends:
|
||||
+ apache2 | httpd
|
||||
+ mysql-server | virtual-mysql-server (Closes: #732874).
|
||||
* Suggests:
|
||||
+ libapache2-mod-php5 | php5-fpm
|
||||
+ logrotate
|
||||
* Refreshed, renamed and re-ordered patches; added DEP-3 headers.
|
||||
* Removed "vendor_perl" patch (applied-upstream).
|
||||
* New patches:
|
||||
+ cmake-fix-confpath.patch
|
||||
+ cmake-gnutls.patch
|
||||
+ cmake-nossl.patch
|
||||
+ cmake.patch
|
||||
+ format-hardening.patch
|
||||
+ pod_man_fixes.patch
|
||||
+ pod_name_fixes.patch
|
||||
+ pod_zmupdate-to-pod2usage.patch
|
||||
* Lintianisation (incomplete):
|
||||
- extra-license-file
|
||||
- init.d-script-missing-lsb-description
|
||||
- init.d-script-does-not-source-init-functions
|
||||
- privacy-breach-generic
|
||||
- package-contains-empty-directory
|
||||
- manpage-has-errors-from-pod2man
|
||||
- manpage-has-bad-whatis-entry
|
||||
- quilt-patch-missing-description
|
||||
- no-dep5-copyright
|
||||
* Lintian-overrides:
|
||||
+ unusual-interpreter usr/bin/zmsystemctl.pl #!/usr/bin/pkexec
|
||||
+ script-not-executable usr/share/zoneminder/www/api/*
|
||||
+ script-with-language-extension usr/bin/*.pl
|
||||
+ source-is-missing web/tools/mootools/mootools-*-yc.js
|
||||
+ source-is-missing web/skins/*/js/jquery-1.4.2.min.js
|
||||
+ source-contains-prebuilt-javascript-object
|
||||
* Renamed files in "debian".
|
||||
* watch: dfsg repacksuffix and dversionmangle.
|
||||
* "debian/copyright" to Copyright-Format-1.0.
|
||||
* Set myself as new Maintainer (Closes: #760314).
|
||||
|
||||
[ Vagrant Cascadian <vagrant@debian.org> ]
|
||||
* Removed obsolete DM-Upload-Allowed flag.
|
||||
* Update debian/watch to use tarballs from github.
|
||||
* Add Build-Depends on libgcrypt11-dev (Closes: #745819).
|
||||
* Use canonical alioth Vcs-Hg URL.
|
||||
* debian/control: Add Build-Depends: libpolkit-gobject-1-dev.
|
||||
* Removed configure flag "--enable-crashtrace=no", which is no longer
|
||||
present upstream.
|
||||
|
||||
-- Dmitry Smirnov <onlyjob@debian.org> Tue, 31 Mar 2015 15:11:13 +1100
|
||||
|
||||
zoneminder (1.26.5-3.1) experimental; urgency=low
|
||||
|
||||
* Non-maintainer upload.
|
||||
* Add libav10.patch and compile against libav10 (Closes: #739461)
|
||||
|
||||
-- Reinhard Tartler <siretart@tauware.de> Wed, 19 Mar 2014 00:31:22 +0000
|
||||
|
||||
zoneminder (1.26.5-3) unstable; urgency=low
|
||||
|
||||
|
||||
* Previous release still didn't build on PPC - this has been corrected.
|
||||
(Closes: #736516)
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Tue, 4 Feb 2014 02:02:10 +1000
|
||||
|
||||
zoneminder (1.26.5-2) unstable; urgency=low
|
||||
|
||||
* Remove dependency on ffmpeg
|
||||
(Closes: #721161)
|
||||
|
||||
* Builds again on non-x86 target architectures.
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Thu, 23 Jan 2014 01:02:10 +1000
|
||||
|
||||
zoneminder (1.26.5-1) unstable; urgency=low
|
||||
|
||||
* New upstream version
|
||||
(Closes: #694131)
|
||||
* Change Build-Depends on libgnutls-dev to libgnutls-openssl-dev
|
||||
(Closes: #731560)
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Tue, 17 Dec 2013 01:02:10 +1000
|
||||
|
||||
zoneminder (1.25.0-4) unstable; urgency=high
|
||||
|
||||
* Add CVE-2013-0232 patch
|
||||
[SECURITY] CVE-2013-0232: Shell escape commands with untrusted content.
|
||||
Thanks to James McCoy <jamessan@debian.org> (Closes: #698910)
|
||||
Thanks also to Salvatore Bonaccorso <carnil@debian.org>
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Tue, 12 Jun 2013 12:02:10 +1000
|
||||
|
||||
zoneminder (1.25.0-3) unstable; urgency=low
|
||||
|
||||
* debian/rules: Export CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS, to ensure
|
||||
hardening build flags are enabled.
|
||||
|
||||
-- Vagrant Cascadian <vagrant@debian.org> Tue, 28 Aug 2012 12:10:03 -0700
|
||||
|
||||
zoneminder (1.25.0-2) unstable; urgency=low
|
||||
|
||||
[ Vagrant Cascadian ]
|
||||
* Add a patch to disable checking for updated versions by default, as
|
||||
upgrades should happen through package management.
|
||||
* Use dpkg-buildflags in debian/rules to set default compiler flags.
|
||||
* Ensure zoneminder is stopped before starting (Closes: #657407).
|
||||
|
||||
[ Peter Howard ]
|
||||
* Fix postinst to add permission for table creation during upgrade
|
||||
(Closes: #657407).
|
||||
|
||||
-- Vagrant Cascadian <vagrant@debian.org> Thu, 23 Aug 2012 12:40:34 -0700
|
||||
|
||||
zoneminder (1.25.0-1.1) unstable; urgency=low
|
||||
|
||||
* Non-maintainer upload.
|
||||
* Fix "ftbfs with GCC-4.7": add patch Fix-FTBFS-with-gcc-4.7 from Cyril
|
||||
Brulebois: fix missing <unistd.h> includes.
|
||||
(Closes: #667428)
|
||||
|
||||
-- gregor herrmann <gregoa@debian.org> Sun, 13 May 2012 17:02:21 +0200
|
||||
|
||||
zoneminder (1.25.0-1) unstable; urgency=low
|
||||
|
||||
* Fix typo in libv4l1-videodev.h patch that caused v4l1 support to be
|
||||
dropped.
|
||||
* Fail to build if version in postinst doesn't match upstream version.
|
||||
* Add Build-Depends: libavdevice-dev to fix MPEG streaming (Closes: #515558).
|
||||
* debian/rules: Convert to using debhelper overrides.
|
||||
* Set debian/compat to 7.
|
||||
* Simplify debian/watch file.
|
||||
* Refresh debian/patches/use_libjs-mootools.
|
||||
* Refresh debian/patches/libv4l1-videodev.h.
|
||||
* Remove dependencies on php4 and related packages.
|
||||
* Remove build-dependencies on libmysqlclient14-dev and
|
||||
libmysqlclient15-dev.
|
||||
* Update Build-Depends to use libjpeg-dev instead of libjpeg62-dev
|
||||
(Closes: #647114).
|
||||
* Add patch to fix build by testing for C headers rather than C++ headers.
|
||||
Thanks to Ryan Niebur. (Closes: #654230)
|
||||
* Add a patch to fix build problems caused by API changes in libav 0.8.
|
||||
Thanks again to Ryan Niebur. (Closes: #654230)
|
||||
|
||||
-- Vagrant Cascadian <vagrant@debian.org> Mon, 16 Jan 2012 11:58:05 -0800
|
||||
|
||||
zoneminder (1.24.4-1) unstable; urgency=low
|
||||
|
||||
[ Peter Howard ]
|
||||
* Initial release of 1.24.4 (Closes: #634985).
|
||||
- Fix 32/64-bit type declarations (Closes: #614404).
|
||||
* Update patches.
|
||||
|
||||
[ Vagrant Cascadian ]
|
||||
* Add patch to fix FTBFS by using libv4l1-videodev.h from libv4l-dev.
|
||||
Thanks to Andreas Metzler for reporting the issue.
|
||||
(Closes: #619813).
|
||||
* Document adding the www-data user to the video group in README.Debian.
|
||||
(Closes: #611324)
|
||||
* Depend on libsys-mmap-perl to enable mapped memory support.
|
||||
(Closes: #607331)
|
||||
* Update libjs-mootools patch to use -nc variants (Closes: #635075).
|
||||
* Depend on javascript-common, to ensure that /javascript is available in
|
||||
the web server.
|
||||
* Set the upstream version in postinst at build time.
|
||||
* Use dh-autoreconf to properly clean up autogenerated files during build.
|
||||
* Add Vcs-HG to debian/control.
|
||||
* Add Build-Depends: libv4l-dev, libbz2-dev, dh-autoreconf, libsys-mmap-perl.
|
||||
|
||||
-- Vagrant Cascadian <vagrant@debian.org> Sun, 24 Jul 2011 16:44:30 +0200
|
||||
|
||||
zoneminder (1.24.2-9) unstable; urgency=low
|
||||
|
||||
* Apply patch from Ubuntu to fix FTBFS with ffmpeg 0.6:
|
||||
- Add -D__STDC_CONSTANT_MACROS to CPPFLAGS (closes: 614080).
|
||||
* Update Standards-Version to 3.9.1, no changes necessary.
|
||||
|
||||
-- Vagrant Cascadian <vagrant@debian.org> Sun, 20 Feb 2011 23:43:02 -0800
|
||||
|
||||
zoneminder (1.24.2-8) unstable; urgency=medium
|
||||
|
||||
[ Vagrant Cascadian ]
|
||||
* Apply patch to fix V4L2 cameras without crop support (closes: #608790).
|
||||
Thanks to piratebab.
|
||||
* Add preinst script which aborts if dangerous symlinks exist.
|
||||
(closes: #608793)
|
||||
|
||||
[ Peter Howard ]
|
||||
* Added to README.Debian with info about images and events directories.
|
||||
(closes: #608793)
|
||||
|
||||
-- Vagrant Cascadian <vagrant@debian.org> Sat, 15 Jan 2011 19:39:26 -0800
|
||||
|
||||
zoneminder (1.24.2-7) unstable; urgency=medium
|
||||
|
||||
* Do not set ownership of /var/cache/zoneminder when upgrading, which fixes a
|
||||
regression causing upgrades to take inordinately long with large
|
||||
installations (closes: #597040).
|
||||
|
||||
-- Vagrant Cascadian <vagrant@debian.org> Fri, 17 Sep 2010 11:24:41 -0700
|
||||
|
||||
zoneminder (1.24.2-6) unstable; urgency=low
|
||||
|
||||
* Only remove database on purge. This requires only creating the database if
|
||||
it doesn't already exist, and upgrading the database only if the database
|
||||
is an older version (closes: #497107).
|
||||
|
||||
* Do not prompt the user on database upgrades by using the --nointeractive
|
||||
flag when calling zmupdate.pl from postinst (closes: #595902).
|
||||
|
||||
-- Vagrant Cascadian <vagrant@debian.org> Fri, 10 Sep 2010 10:06:06 -0700
|
||||
|
||||
zoneminder (1.24.2-5) unstable; urgency=low
|
||||
|
||||
[ Peter Howard ]
|
||||
* Add zip dependency
|
||||
(closes: #494261)
|
||||
* Add debian/watch file
|
||||
(closes: #545552)
|
||||
* Use packaged libjs-mootools
|
||||
(closes: #585590)
|
||||
* Miscellaneous cleanups
|
||||
|
||||
[ Vagrant Cascadian ]
|
||||
* Add vagrant@debian.org as uploader
|
||||
* Update Standards-Version to 3.9.0, no changes necessary.
|
||||
|
||||
-- Vagrant Cascadian <vagrant@debian.org> Fri, 23 Jul 2010 18:12:50 -0500
|
||||
|
||||
zoneminder (1.24.2-4.1) unstable; urgency=low
|
||||
|
||||
* Non-maintainer upload.
|
||||
* Fix "package removed, processes still running": apply patch to
|
||||
debian/postinst by Vagrant Cascadian: use invoke-rc.d and run
|
||||
mysql-related actions only when mysql is running (closes: #583648).
|
||||
|
||||
-- gregor herrmann <gregoa@debian.org> Thu, 01 Jul 2010 19:47:10 +0200
|
||||
|
||||
zoneminder (1.24.2-4) unstable; urgency=high
|
||||
* Update init.d to list mysql dependency
|
||||
(closes: #583505)
|
||||
* Change dependency from libmime-perl to libmime-tools-perl
|
||||
(closes: #585589)
|
||||
* Problems in changelog format fixed
|
||||
(closes: #585592)
|
||||
* Fix debian-rules-ignores-make-clean-error
|
||||
(closes: #585593)
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 14 jun 2010 15:02:10 +1000
|
||||
|
||||
zoneminder (1.24.2-3) unstable; urgency=high
|
||||
* Changes symbols to build with libjpeg8
|
||||
(closes: #565326, #568327)
|
||||
* Note: location of all perl files should have been fixed in previous release
|
||||
(closes: #553096)
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 26 apr 2010 15:02:10 +1000
|
||||
|
||||
zoneminder (1.24.2-2) unstable; urgency=high
|
||||
|
||||
* Remove custom perl parth from zmpkg.pl, fix location of manpages.
|
||||
(closes: #551746, #553092)
|
||||
* Fix GCC4.4 bug
|
||||
(closes: #531717)
|
||||
* Fix potential bug in postinst script
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Sat, 14 Nov 2009 15:02:10 +1000
|
||||
|
||||
zoneminder (1.24.2-1) unstable; urgency=high
|
||||
|
||||
* Initial release of zoneminder 1.24.2
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Fri, 11 Sep 2009 07:02:50 +1000
|
||||
|
||||
zoneminder (1.24.1-1) unstable; urgency=high
|
||||
|
||||
* Initial release of zoneminder 1.24.1, closing CVE-2008-3882,
|
||||
CVE-2008-3881, CVE-2008-3880
|
||||
(closes: #497640)
|
||||
* Change syslog dependency to rsyslog.
|
||||
(closes: #526918)
|
||||
* Add missing perl dependency.
|
||||
* Restore patch to disable "check for updates" by default.
|
||||
* Removed spurious '$' in init script.
|
||||
(closes: #486064)
|
||||
* Change permission of zm.conf from 0600 to 0400 for CVE-2008-6755
|
||||
(closes: #528252)
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Sat, 16 May 2009 07:02:50 +1000
|
||||
|
||||
zoneminder (1.23.3-4) unstable; urgency=high
|
||||
|
||||
* update to get it building with latest unstable. Thanks to waldi@debian.org
|
||||
(closes: #517569)
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Thu, 16 Apr 2009 01:02:50 +1000
|
||||
|
||||
zoneminder (1.23.3-3) unstable; urgency=high
|
||||
|
||||
* ffmpeg confirmed working
|
||||
(closes: #475145)
|
||||
* Fix upgrade problem intrudouced in 1.23.3-1
|
||||
(closes: #481637)
|
||||
* Include libmime-lite-perl in dependencies
|
||||
(closes: #486312)
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Thu, 18 Sep 2008 01:02:50 +1000
|
||||
|
||||
zoneminder (1.23.3-2) unstable; urgency=high
|
||||
|
||||
* ffmpeg finally working?
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Wed, 13 Aug 2008 01:02:50 +1000
|
||||
|
||||
zoneminder (1.23.3-1) unstable; urgency=high
|
||||
|
||||
* Initial version for 1.23.3 - security fix.
|
||||
(closes: #479034)
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Wed, 19 Mar 2008 01:02:50 +1000
|
||||
|
||||
zoneminder (1.23.2-2) unstable; urgency=low
|
||||
|
||||
* Update to init.d
|
||||
(closes: #468856)
|
||||
* Add dependency on logging daemon
|
||||
(closes: #471277)
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Wed, 19 Mar 2008 01:02:50 +1000
|
||||
|
||||
zoneminder (1.23.2-1) unstable; urgency=low
|
||||
|
||||
* Initial version for 1.23.2
|
||||
(closes: #464152)
|
||||
* Zoneminder 1.23.2 upstream includes fix for GCC 4.3
|
||||
(closes: #454980)
|
||||
* Includes ffmpeg patch by Alexander Kushnirenko <kushnir@uni-protvino.ru>
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Sat, 01 Mar 2008 16:02:50 +1000
|
||||
|
||||
zoneminder (1.22.3-10) unstable; urgency=low
|
||||
|
||||
* Fix bug introduced in -9 where perl is put under /usr/local
|
||||
(closes: #457507)
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 24 Dec 2007 16:02:50 +1000
|
||||
|
||||
zoneminder (1.22.3-9) unstable; urgency=low
|
||||
|
||||
* Starting zoneminder via init script now invokes "zmfix -a"
|
||||
(closes: #481637)
|
||||
* Change apache2-mpm-prefork dependency to apache2
|
||||
* Temp dir for export under /var/cache/zoneminder (but linked back to
|
||||
/usr/share/zoneminder for now)
|
||||
* Redo use of gnutls rather than openssl for md5 hashes
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 10 Dec 2007 16:02:50 +1000
|
||||
|
||||
zoneminder (1.22.3-8) unstable; urgency=low
|
||||
|
||||
* Build now includes libpcre3
|
||||
(closes: #437533)
|
||||
* "Monitor Presets" patch now applied to package during build.
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Sat, 18 Aug 2007 14:35:23 +1000
|
||||
|
||||
zoneminder (1.22.3-7) unstable; urgency=low
|
||||
|
||||
* Turn off debug trace and crash dump on build
|
||||
(closes:#414857,#414891)
|
||||
* Additional perl libraries added in dependencies
|
||||
(closes:#416291)
|
||||
* Change preferred PHP version from 4 to 5
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Sun, 29 Jul 2007 15:11:13 +1000
|
||||
|
||||
zoneminder (1.22.3-6) unstable; urgency=low
|
||||
|
||||
* Removed a similar bash only statement from zmpkg.pl
|
||||
(closes:414882)
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Sat, 14 Apr 2007 11:46:56 +1000
|
||||
|
||||
zoneminder (1.22.3-5) unstable; urgency=low
|
||||
|
||||
* Installs with "phone home" feature turned off by default, and permissions
|
||||
on /etc/zm/zm.conf fixed (now the 0600 it s hould be)
|
||||
(closes:415349)
|
||||
* Removed "stupid bash-ism" on mysqld check in postinst file.
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Fri, 6 Apr 2007 15:50:00 +1000
|
||||
|
||||
zoneminder (1.22.3-4) unstable; urgency=low
|
||||
|
||||
* Put libmysqlclient-15-dev in front of -14-dev so sbuild works
|
||||
(closes: #414410)
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 12 Mar 2007 11:38:56 +1100
|
||||
|
||||
zoneminder (1.22.3-3) unstable; urgency=low
|
||||
|
||||
* Clean up of postinstall, postrm ; user "zm" definitely was a mistake
|
||||
* Also in postinstall: check and start MySQL if it's not running.
|
||||
* init.d script now checks if zoneminder isn't running and still returns 0
|
||||
(which helps uninstalling)
|
||||
* Addition of php5 dependency options as well as php4.
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Mon, 26 Feb 2007 10:40:52 +1100
|
||||
|
||||
zoneminder (1.22.3-2) unstable; urgency=low
|
||||
|
||||
* Added zmuser in the mysql creation; this should fix the install problem
|
||||
for people, but needs to be cleaned up (in -3)
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Fri, 16 Feb 2007 14:16:03 +1100
|
||||
|
||||
zoneminder (1.22.3-1) unstable; urgency=low
|
||||
|
||||
* Initial Version. (closes: #248393)
|
||||
* Patched out use of openssl; uses gnutls instead for MD5 hashes.
|
||||
* Removed MakeMaker-inserted Perl licensing (with authors permission) in
|
||||
various scripts; replaced with GPL.
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au> Wed, 7 Feb 2007 14:09:01 +1100
|
|
@ -6,6 +6,7 @@ Uploaders: Vagrant Cascadian <vagrant@debian.org>
|
|||
Build-Depends: debhelper (>= 9), python-sphinx | python3-sphinx, apache2-dev, dh-linktree
|
||||
,cmake
|
||||
,libavcodec-dev, libavformat-dev (>= 3:0.svn20090204), libswscale-dev (>= 3:0.svn20090204), libavutil-dev, libavdevice-dev
|
||||
,libboost1.55-dev
|
||||
,libbz2-dev
|
||||
,libgcrypt-dev
|
||||
,libcurl4-gnutls-dev
|
||||
|
@ -54,7 +55,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
|||
,libdata-uuid-perl
|
||||
,mysql-client | virtual-mysql-client
|
||||
,perl-modules
|
||||
,php5-mysql, php5-gd
|
||||
,php5-mysql, php5-gd, php5-apcu, php-apc
|
||||
,policykit-1
|
||||
,rsyslog | system-log-daemon
|
||||
,zip
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
Last-Update: 2015-08-16
|
||||
Forwarded: no
|
||||
Author: Dmitry Smirnov <onlyjob@member.fsf.org>
|
||||
Description: correct path to CGI app according to default web server configuration.
|
||||
|
||||
--- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in
|
||||
+++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in
|
||||
@@ -428,7 +428,7 @@ our @options =
|
||||
},
|
||||
{
|
||||
name => "ZM_PATH_ZMS",
|
||||
- default => "/cgi-bin/nph-zms",
|
||||
+ default => "/zm/cgi-bin/nph-zms",
|
||||
description => "Web path to zms streaming server",
|
||||
help => qqq("
|
||||
The ZoneMinder streaming server is required to send streamed
|
|
@ -1,2 +0,0 @@
|
|||
default_cgi-path.patch
|
||||
use_libjs-mootools.patch
|
|
@ -1,18 +0,0 @@
|
|||
Last-Update: 2015-03-29
|
||||
Forwarded: no
|
||||
Bug-Debian: http://bugs.debian.org/585590
|
||||
Reviewed-By: Dmitry Smirnov <onlyjob@member.fsf.org>
|
||||
Description: use mootools shipped by debian, rather than the zoneminder included mootools.
|
||||
|
||||
--- a/web/skins/classic/includes/functions.php
|
||||
+++ b/web/skins/classic/includes/functions.php
|
||||
@@ -63,9 +63,8 @@
|
||||
}
|
||||
?>
|
||||
<script type="text/javascript" src="tools/mootools/mootools-core.js"></script>
|
||||
<script type="text/javascript" src="tools/mootools/mootools-more.js"></script>
|
||||
- <script type="text/javascript" src="js/mootools.ext.js"></script>
|
||||
<script type="text/javascript" src="js/logger.js"></script>
|
||||
<script type="text/javascript" src="js/overlay.js"></script>
|
||||
<?php
|
||||
if ( $skinJsPhpFile )
|
|
@ -58,8 +58,10 @@ override_dh_auto_install:
|
|||
|
||||
override_dh_fixperms:
|
||||
dh_fixperms
|
||||
## 637685
|
||||
chmod -c o-r $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
|
||||
#
|
||||
# As requested by the Debian Webapps Policy Manual §3.2.1
|
||||
chown root:www-data $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
|
||||
chmod 640 $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
|
||||
|
||||
override_dh_installinit:
|
||||
dh_installinit --no-start
|
||||
|
|
|
@ -1 +1 @@
|
|||
3.0 (native)
|
||||
3.0 (quilt)
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
missingok
|
||||
notifempty
|
||||
sharedscripts
|
||||
delaycompress
|
||||
compress
|
||||
postrotate
|
||||
/usr/bin/zmpkg.pl logrot >>/dev/null 2>&1 || :
|
||||
endscript
|
||||
weekly
|
||||
rotate 3
|
||||
daily
|
||||
rotate 7
|
||||
}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
d /var/run/zm 0755 www-data www-data
|
||||
d /tmp/zm 0755 www-data www-data
|
||||
d /var/tmp/zm 0755 www-data www-data
|
||||
|
|
|
@ -8,7 +8,7 @@ ScriptAlias /zm/cgi-bin "/usr/lib/zoneminder/cgi-bin"
|
|||
|
||||
Alias /zm /usr/share/zoneminder/www
|
||||
<Directory /usr/share/zoneminder/www>
|
||||
Options -Indexes +ollowSymLinks
|
||||
Options -Indexes +FollowSymLinks
|
||||
<IfModule mod_dir.c>
|
||||
DirectoryIndex index.php
|
||||
</IfModule>
|
||||
|
|
|
@ -5,6 +5,8 @@ Maintainer: Dmitry Smirnov <onlyjob@debian.org>
|
|||
Uploaders: Vagrant Cascadian <vagrant@debian.org>
|
||||
Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apache2-dev, dh-linktree
|
||||
,cmake
|
||||
,libx264-dev, libmp4v2-dev
|
||||
,libboost-dev
|
||||
,libavdevice-dev (>= 6:10~)
|
||||
,libavcodec-dev (>= 6:10~)
|
||||
,libavformat-dev (>= 6:10~)
|
||||
|
@ -14,7 +16,7 @@ Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apa
|
|||
,libgcrypt-dev
|
||||
,libcurl4-gnutls-dev
|
||||
,libgnutls-openssl-dev
|
||||
,libjpeg-dev
|
||||
,libjpeg8-dev | libjpeg9-dev | libjpeg62-turbo-dev
|
||||
,libmysqlclient-dev
|
||||
,libpcre3-dev
|
||||
,libpolkit-gobject-1-dev
|
||||
|
@ -25,11 +27,11 @@ Build-Depends: debhelper (>= 9), dh-systemd, python-sphinx | python3-sphinx, apa
|
|||
,libphp-serialization-perl
|
||||
,libsys-mmap-perl [!hurd-any]
|
||||
,libwww-perl
|
||||
,libdata-uuid-perl
|
||||
,libdata-uuid-perl
|
||||
# Unbundled (dh_linktree):
|
||||
,libjs-jquery
|
||||
,libjs-mootools
|
||||
Standards-Version: 3.9.6
|
||||
Standards-Version: 3.9.8
|
||||
Homepage: http://www.zoneminder.com/
|
||||
Vcs-Browser: http://anonscm.debian.org/cgit/collab-maint/zoneminder.git
|
||||
Vcs-Git: git://anonscm.debian.org/collab-maint/zoneminder.git
|
||||
|
@ -38,11 +40,10 @@ Package: zoneminder
|
|||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
||||
,javascript-common
|
||||
,libmp4v2-2, libx264-142|libx264-148, libswscale-ffmpeg3|libswscale4|libswscale3
|
||||
,ffmpeg | libav-tools
|
||||
,libdate-manip-perl
|
||||
,libdate-manip-perl, libmime-lite-perl, libmime-tools-perl
|
||||
,libdbd-mysql-perl
|
||||
,libmime-lite-perl
|
||||
,libmime-tools-perl
|
||||
,libphp-serialization-perl
|
||||
,libmodule-load-conditional-perl
|
||||
,libnet-sftp-foreign-perl
|
||||
|
@ -60,13 +61,14 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
|
|||
,libio-socket-multicast-perl
|
||||
,libdigest-sha-perl
|
||||
,libsys-cpu-perl, libsys-meminfo-perl
|
||||
,libdata-uuid-perl
|
||||
,libdata-uuid-perl
|
||||
,mysql-client | virtual-mysql-client
|
||||
,perl-modules
|
||||
,php5-mysql | php-mysql, php5-gd | php-gd
|
||||
,php5-mysql | php-mysql, php5-gd | php-gd , php5-apcu | php-apcu , php-apc | php-apcu-bc
|
||||
,policykit-1
|
||||
,rsyslog | system-log-daemon
|
||||
,zip
|
||||
,libpcre3
|
||||
Recommends: ${misc:Recommends}
|
||||
,libapache2-mod-php5 | libapache2-mod-php | php5-fpm | php-fpm
|
||||
,mysql-server | virtual-mysql-server
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
default_cgi-path.patch
|
||||
use_libjs-mootools.patch
|
|
@ -28,7 +28,7 @@ override_dh_auto_configure:
|
|||
|
||||
override_dh_clean:
|
||||
dh_clean $(MANPAGES1)
|
||||
$(RM) -r docs/_build docs/installationguide
|
||||
$(RM) -r docs/_build
|
||||
|
||||
build-indep:
|
||||
#$(MAKE) -C docs text
|
||||
|
@ -58,8 +58,10 @@ override_dh_auto_install:
|
|||
|
||||
override_dh_fixperms:
|
||||
dh_fixperms
|
||||
## 637685
|
||||
chmod -c o-r $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
|
||||
#
|
||||
# As requested by the Debian Webapps Policy Manual §3.2.1
|
||||
chown root:www-data $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
|
||||
chmod 640 $(CURDIR)/debian/zoneminder/etc/zm/zm.conf
|
||||
|
||||
override_dh_installinit:
|
||||
dh_installinit --no-start
|
||||
|
|
|
@ -1 +1 @@
|
|||
3.0 (native)
|
||||
3.0 (quilt)
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
version=3
|
||||
|
||||
opts=\
|
||||
repacksuffix=+dfsg,\
|
||||
dversionmangle=s{\+dfsg\d*}{},\
|
||||
https://github.com/ZoneMinder/ZoneMinder/releases \
|
||||
.*/ZoneMinder/archive/v(.*).tar.gz
|
|
@ -3,6 +3,7 @@ usr/bin
|
|||
usr/lib/zoneminder
|
||||
usr/share/polkit-1
|
||||
usr/share/zoneminder/db
|
||||
usr/share/zoneminder/icons
|
||||
usr/share/zoneminder/www
|
||||
|
||||
# libzoneminder-perl files:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/var/cache/zoneminder/events /usr/share/zoneminder/www/events
|
||||
/var/cache/zoneminder/images /usr/share/zoneminder/www/images
|
||||
/var/cache/zoneminder/temp /usr/share/zoneminder/www/temp
|
||||
/var/tmp /usr/share/zoneminder/www/api/app/tmp
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
missingok
|
||||
notifempty
|
||||
sharedscripts
|
||||
delaycompress
|
||||
compress
|
||||
postrotate
|
||||
/usr/bin/zmpkg.pl logrot >>/dev/null 2>&1 || :
|
||||
endscript
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
?package(zoneminder):needs="x11" section="Applications/Video" title="ZoneMinder" command="/usr/bin/x-www-browser http://localhost/zm" icon="/usr/share/zoneminder/icons/16x16/icon.xpm"
|
||||
|
|
@ -12,6 +12,10 @@ if [ "$1" = "configure" ]; then
|
|||
if [ -z "$2" ]; then
|
||||
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
|
||||
fi
|
||||
if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ]; then
|
||||
echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi."
|
||||
a2enmod cgi
|
||||
fi
|
||||
|
||||
# Do this every time the package is installed or upgraded
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
d /var/run/zm 0755 www-data www-data
|
||||
d /tmp/zm 0755 www-data www-data
|
||||
d /var/run/zm 0755 www-data www-data
|
||||
d /tmp/zm 0755 www-data www-data
|
||||
d /var/tmp/zm 0755 www-data www-data
|
||||
|
|
|
@ -309,7 +309,7 @@ The main causes are.
|
|||
* Capture frame rates. Unless there's a compelling reason in your case there is often little benefit in running cameras at 25fps when 5-10fps would often get you results just as good. Try changing your monitor settings to limit your cameras to lower frame rates. You can still configure ZM to ignore these limits and capture as fast as possible when motion is detected.
|
||||
* Run function. Obviously running in Record or Mocord modes or in Modect with lots of events generates a lot of DB and file activity and so CPU and load will increase.
|
||||
* Basic default detection zones. By default when a camera is added one detection zone is added which covers the whole image with a default set of parameters. If your camera covers a view in which various regions are unlikely to generate a valid alarm (ie the sky) then I would experiment with reducing the zone sizes or adding inactive zones to blank out areas you don't want to monitor. Additionally the actual settings of the zone themselves may not be optimal. When doing motion detection the number of changed pixels above a threshold is examined, then this is filter, then contiguous regions are calculated to see if an alarm is generated. If any maximum or minimum threshold is exceeded according to your zone settings at any time the calculation stops. If your settings always result in the calculations going through to the last stage before being failed then additional CPU time is used unnecessarily. Make sure your maximum and minimumzone thresholds are set to sensible values and experiment by switching RECORD_EVENT_STATS on and seeing what the actual values of alarmed pixels etc are during sample events.
|
||||
* Optimise your settings. After you've got some settings you're happy with then switching off RECORD_EVENT_STATS will prevent the statistics being written to the database which saves some time. Other settings which might make a difference are ZM_FAST_RGB_DIFFS, ZM_OPT_FRAME_SERVER and the JPEG_xxx_QUALITY ones.
|
||||
* Optimise your settings. After you've got some settings you're happy with then switching off RECORD_EVENT_STATS will prevent the statistics being written to the database which saves some time. Other settings which might make a difference are ZM_FAST_RGB_DIFFS and the JPEG_xxx_QUALITY ones.
|
||||
|
||||
I'm sure there are other things which might make a difference such as what else you have running on the box and memory sizes (make sure there's no swapping going on). Also speed of disk etc will make some difference during event capture and also if you are watching the whole time then you may have a bunch of zms processes running also.
|
||||
|
||||
|
|
|
@ -42,8 +42,6 @@ Note that these commands are just an example and might not be secure enough for
|
|||
|
||||
7. If you have chosen to change the ZoneMinder database account credentials to something other than zmuser/zmpass, you must now update zm.conf on each ZoneMinder Server. Change ZM_DB_USER and ZM_DB_PASS to the values you created in the previous step.
|
||||
|
||||
Additionally, you must also edit /usr/share/zoneminder/www/api/app/Config/database.php in a similar manner on each ZoneMinder Server. Scroll down and change login and password to the values you created in the previous step.
|
||||
|
||||
8. All ZoneMinders Servers must share a common events folder. This can be done in any manner supported by the underlying operating system. From the Storage Server, share/export a folder to be used for ZoneMinder events.
|
||||
|
||||
9. From each ZoneMinder Server, mount the shared events folder on the Storage Server to the events folder on the local ZoneMinder Server.
|
||||
|
|
|
@ -169,8 +169,6 @@ Now clone the ZoneMinder git repository:
|
|||
cd
|
||||
git clone https://github.com/ZoneMinder/ZoneMinder
|
||||
cd ZoneMinder
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
This will create a sub-folder called ZoneMinder, which will contain the latest development.
|
||||
|
||||
|
@ -180,21 +178,21 @@ We want to turn this into a tarball, but first we need to figure out what to nam
|
|||
|
||||
ls ~/rpmbuild/SOURCES
|
||||
|
||||
The tarball from the previsouly installed SRPM should be there. This is the name we will use. For this example, the name is ZoneMinder-1.28.1.tar.gz. From one folder above the local ZoneMinder git repository, execute the following:
|
||||
The tarball from the previsouly installed SRPM should be there. This is the name we will use. For this example, the name is ZoneMinder-1.28.1.tar.gz. From the root folder of the local ZoneMinder git repository, execute the following:
|
||||
|
||||
::
|
||||
|
||||
mv ZoneMinder ZoneMinder-1.28.1
|
||||
tar -cvzf ~/rpmbuild/SOURCES/ZoneMinder-1.28.1.tar.gz ZoneMinder-1.28.1/*
|
||||
git archive --prefix=ZoneMinder-1.28.1/ -o ~/rpmbuild/SOURCES/zoneminder-1.28.1.tar.gz HEAD
|
||||
|
||||
The trailing "/\*" leaves off the hidden dot "." file and folders from the git repo, which is what we want.
|
||||
Note that we are overwriting the original tarball. If you wish to keep the original tarball then create a copy prior to creating the new tarball.
|
||||
|
||||
Now build a new src.rpm:
|
||||
From the root of the local ZoneMinder git repo, execute the following:
|
||||
|
||||
::
|
||||
|
||||
rpmbuild -bs --nodeps ~/rpmbuild/SPECS/zoneminder.el7.spec
|
||||
rpmbuild -bs --nodeps distros/redhat/zoneminder.spec
|
||||
|
||||
Notice we used the rpm specfile that is part of the latest master branch you just downloaded, rather than the one that may be in your ~/rpmbbuild/SOURCES folder.
|
||||
|
||||
This step will overwrite the SRPM you originally downloaded, so you may want to back it up prior to completing this step. Note that the name of the specfile will vary slightly depending on the target distro.
|
||||
|
||||
|
|
|
@ -287,19 +287,19 @@ To build the latest master snapshot:
|
|||
|
||||
::
|
||||
|
||||
./do_debian_package.sh `lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'` `date +%Y%m%d`01 local master
|
||||
./do_debian_package.sh --snapshot=NOW --branch=master --type=local
|
||||
|
||||
|
||||
To build the latest stable release:
|
||||
|
||||
::
|
||||
|
||||
./do_debian_package.sh `lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'` `date +%Y%m%d`01 local stable
|
||||
./do_debian_package.sh --snapshot=stable --type=local
|
||||
|
||||
|
||||
Note that the ``lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'``
|
||||
part simply extracts your distribution name - like "vivid", "trusty" etc. You
|
||||
can always replace it by your distro name if you know it. As far as the script
|
||||
Note that the distribution will be guessed using ``lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'``
|
||||
which simply extracts your distribution name - like "vivid", "trusty" etc. You
|
||||
can always specify it using --distro=your distro name if you know it. As far as the script
|
||||
goes, it checks if your distro is "trusty" in which case it pulls in pre-systemd
|
||||
release configurations and if its not "trusty" it assumes its based on systemd
|
||||
and pulls in systemd related config files.
|
||||
|
@ -358,24 +358,6 @@ Changed Default DB User
|
|||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you have changed your DB login/password from zmuser/zmpass, you need to
|
||||
update these values in zm.conf and the API's database.php file.
|
||||
update these values in zm.conf.
|
||||
|
||||
1. Edit zm.conf to change ZM_DB_USER and ZM_DB_PASS to the values you used.
|
||||
|
||||
2. Edit databse.php which can be found in the web server folder zoneminder/www/api/app/Config
|
||||
|
||||
There is a class there called DATABASE_CONFIG -
|
||||
change the $default array to reflect your new details. Example:
|
||||
|
||||
::
|
||||
|
||||
public $default = array(
|
||||
'datasource' => 'Database/Mysql',
|
||||
'persistent' => false,
|
||||
'host' => 'localhost',
|
||||
'login' => 'mynewDBusername',
|
||||
'password' => 'mynewDBpassword'
|
||||
'database' => 'zm',
|
||||
'prefix' => '',
|
||||
//'encoding' => 'utf8',
|
||||
);
|
|
@ -40,6 +40,8 @@ Type
|
|||
Preset
|
||||
The preset chooser sets sensible default values based on computational needs (fast v. best) and sensitivity (low, medium, high.) It is not required that you select a preset, and you can alter any of the parameters after choosing a preset. For a small number of monitors with ZoneMinder running on modern equipment, Best, high sensitivity can be chosen as a good starting point.
|
||||
|
||||
It is important to understand that the available presets are intended merely as a starting point. Since every camera's view is unique, they are not guaranteed to work properly in every case. Presets tend to work acceptably for indoor cameras, where the objects of interest are relatively close and there typically are few or no unwanted objects moving within the cameras view. Presets, on the other hand, tend to not work acceptably for outdoor cameras, where the field of view is typically much wider, objects of interest are farther away, and changing weather patterns can cause false triggers. For outdoor cameras in particular, you will almost certainly have to tune your motion detection zone to get desired results. Please refer to `this guide <http://www.zoneminder.com/wiki/index.php/Understanding_ZoneMinder%27s_Zoning_system_for_Dummies>`__ to learn how to do this.
|
||||
|
||||
Units
|
||||
* Pixels - Selecting this option will allow many of the following values to be entered (or viewed) in units of pixels.
|
||||
* Percentage - Selecting this option will allow may of the following values to be entered (or viewed) as a percentage. The sense of the percentage values refers to the area of the zone and not the image as a whole. This makes trying to work out necessary sizes rather easier.
|
||||
|
|
|
@ -29,7 +29,7 @@ Here is what the filter window looks like
|
|||
events later and also make sure archived events don't get deleted, for example
|
||||
* Email details of all matches: Sends an email to the configured address with details about the event.
|
||||
The email can be customized as per TBD
|
||||
* Execute command on all matches: Allows you to execute any arbitrary command on the matched events
|
||||
* Execute command on all matches: Allows you to execute any arbitrary command on the matched events. You can use replacement tokens as subsequent arguents to the command, the last argument will be the absolute path to the event, preceeded by replacement arguents. eg: /usr/bin/script.sh %MN% will excecute as /usr/bin/script.sh MonitorName /path/to/event.
|
||||
* Delete all matches: Deletes all the matched events
|
||||
* *E*: Use 'Submit' to 'test' your matching conditions. This will just match and show you what filters match. Use 'Execute' to actually execute the action after matching your conditions. Use 'Save' to save the filter for future use and 'Reset' to clear your settings
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
The XML images present in this folder have been drawn using http://draw.io
|
||||
To edit images, simple go to draw.io and load the .xml files
|
Binary file not shown.
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 93 KiB |
File diff suppressed because one or more lines are too long
|
@ -33,10 +33,6 @@ RUN_AUDIT - The zmaudit daemon exists to check that the saved information in the
|
|||
|
||||
AUDIT_CHECK_INTERVAL - The zmaudit daemon exists to check that the saved information in the database and on the filesystem match and are consistent with each other. If an error occurs or if you are using 'fast deletes' it may be that database records are deleted but files remain. In this case, and similar, zmaudit will remove redundant information to synchronise the two data stores. The default check interval of 900 seconds (15 minutes) is fine for most systems however if you have a very large number of events the process of scanning the database and filesystem may take a long time and impact performance. In this case you may prefer to make this interval much larger to reduce the impact on your system. This option determines how often these checks are performed.
|
||||
|
||||
OPT_FRAME_SERVER - In some circumstances it is possible for a slow disk to take so long writing images to disk that it causes the analysis daemon to fall behind especially during high frame rate events. Setting this option to yes enables a frame server daemon (zmf) which will be sent the images from the analysis daemon and will do the actual writing of images itself freeing up the analysis daemon to get on with other things. Should this transmission fail or other permanent or transient error occur, this function will fall back to the analysis daemon.
|
||||
|
||||
FRAME_SOCKET_SIZE - For large captured images it is possible for the writes from the analysis daemon to the frame server to fail as the amount to be written exceeds the default buffer size. While the images are then written by the analysis daemon so no data is lost, it defeats the object of the frame server daemon in the first place. You can use this option to indicate that a larger buffer size should be used. Note that you may have to change the existing maximum socket buffer size on your system via sysctl (or in /proc/sys/net/core/wmem_max) to allow this new size to be set. Alternatively you can change the default buffer size on your system in the same way in which case that will be used with no change necessary in this option
|
||||
|
||||
OPT_CONTROL - ZoneMinder includes limited support for controllable cameras. A number of sample protocols are included and others can easily be added. If you wish to control your cameras via ZoneMinder then select this option otherwise if you only have static cameras or use other control methods then leave this option off.
|
||||
|
||||
OPT_TRIGGERS - ZoneMinder can interact with external systems which prompt or cancel alarms. This is done via the zmtrigger.pl script. This option indicates whether you want to use these external triggers. Most people will say no here.
|
||||
|
|
|
@ -12,7 +12,8 @@ configure_file(zoneminder-tmpfiles.conf.in "${CMAKE_CURRENT_BINARY_DIR}/zonemind
|
|||
# Do not install the misc files by default
|
||||
#install(FILES "${CMAKE_CURRENT_BINARY_DIR}/apache.conf" "${CMAKE_CURRENT_BINARY_DIR}/logrotate.conf" "${CMAKE_CURRENT_BINARY_DIR}/syslog.conf" DESTINATION "${CMAKE_INSTALL_DATADIR}/zoneminder/misc")
|
||||
|
||||
# Install Policykit rules and actions into the proper folders
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.zoneminder.systemctl.policy" DESTINATION "${PC_POLKIT_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/polkit-1/actions")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.zoneminder.systemctl.rules" DESTINATION "${PC_POLKIT_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/polkit-1/rules.d")
|
||||
|
||||
# Install Policykit rules and actions into the proper folders only on systems with systemd
|
||||
if(WITH_SYSTEMD)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.zoneminder.systemctl.policy" DESTINATION "${PC_POLKIT_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/polkit-1/actions")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/com.zoneminder.systemctl.rules" DESTINATION "${PC_POLKIT_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/polkit-1/rules.d")
|
||||
endif(WITH_SYSTEMD)
|
||||
|
|
|
@ -5,13 +5,22 @@
|
|||
# Some values may need to manually adjusted to suit your setup
|
||||
#
|
||||
<VirtualHost *:80>
|
||||
ServerName @WEB_HOST@
|
||||
ServerAdmin webmaster@localhost
|
||||
|
||||
DocumentRoot "@WEB_PREFIX@"
|
||||
Alias /zm/ "@WEB_PREFIX@/"
|
||||
<Directory "@WEB_PREFIX@">
|
||||
Options -Indexes +FollowSymLinks
|
||||
AllowOverride All
|
||||
<IfModule mod_authz_core.c>
|
||||
# Apache 2.4
|
||||
Require all granted
|
||||
</IfModule>
|
||||
<IfModule !mod_authz_core.c>
|
||||
# Apache 2.2
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
ScriptAlias /cgi-bin "@CGI_PREFIX@"
|
||||
|
|
|
@ -12,7 +12,7 @@ Type=forking
|
|||
ExecStart=@BINDIR@/zmpkg.pl start
|
||||
ExecReload=@BINDIR@/zmpkg.pl restart
|
||||
ExecStop=@BINDIR@/zmpkg.pl stop
|
||||
PIDFile="@ZM_RUNDIR@/zm.pid"
|
||||
PIDFile=@ZM_RUNDIR@/zm.pid
|
||||
Environment=TZ=:/etc/localtime
|
||||
|
||||
[Install]
|
||||
|
|
|
@ -26,9 +26,10 @@ configure_file(zm.in "${CMAKE_CURRENT_BINARY_DIR}/zm" @ONLY)
|
|||
#configure_file(zmeventdump.in zmeventdump @ONLY)
|
||||
|
||||
# Generate man files for the perl scripts destined for the bin folder
|
||||
file(GLOB perlscripts RELATIVE "${CMAKE_CURRENT_BINARY_DIR}" "*.pl")
|
||||
file(GLOB perlscripts "*.pl")
|
||||
FOREACH(PERLSCRIPT ${perlscripts})
|
||||
POD2MAN(${CMAKE_CURRENT_SOURCE_DIR}/${PERLSCRIPT} zoneminder-${PERLSCRIPT} 8)
|
||||
get_filename_component(PERLSCRIPTNAME ${PERLSCRIPT} NAME)
|
||||
POD2MAN(${PERLSCRIPT} zoneminder-${PERLSCRIPTNAME} 8)
|
||||
ENDFOREACH(PERLSCRIPT ${perlscripts})
|
||||
|
||||
# Install the perl scripts
|
||||
|
|
|
@ -129,7 +129,7 @@ BEGIN {
|
|||
} # end BEGIN
|
||||
|
||||
sub loadConfigFromDB {
|
||||
print( "Loading config from DB\n" );
|
||||
print( "Loading config from DB" );
|
||||
my $dbh = ZoneMinder::Database::zmDbConnect();
|
||||
if ( !$dbh ) {
|
||||
print( "Error: unable to load options from database: $DBI::errstr\n" );
|
||||
|
@ -160,11 +160,12 @@ sub loadConfigFromDB {
|
|||
$option_count++;;
|
||||
}
|
||||
$sth->finish();
|
||||
print( " $option_count entries\n" );
|
||||
return( $option_count );
|
||||
} # end sub loadConfigFromDB
|
||||
|
||||
sub saveConfigToDB {
|
||||
print( "Saving config to DB\n" );
|
||||
print( "Saving config to DB " . @options . " entries\n" );
|
||||
my $dbh = ZoneMinder::Database::zmDbConnect();
|
||||
if ( !$dbh ) {
|
||||
print( "Error: unable to save options to database: $DBI::errstr\n" );
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -215,6 +215,55 @@ sub presetHome
|
|||
$self->sendCmd( 'decoder_control.cgi?command=25&' );
|
||||
}
|
||||
|
||||
sub moveRelUp
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Up" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=0&onestep=1&' );
|
||||
}
|
||||
|
||||
#Down Arrow
|
||||
sub moveRelDown
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Down" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=2&onestep=1&' );
|
||||
}
|
||||
|
||||
#Left Arrow
|
||||
sub moveRelLeft
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Left" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=6&onestep=1&' );
|
||||
}
|
||||
|
||||
#Right Arrow
|
||||
sub moveRelRight
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Right" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=4&onestep=1&' );
|
||||
}
|
||||
|
||||
#Go to preset
|
||||
sub presetGoto
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
my $result = undef;
|
||||
if ( $preset > 0 && $preset <= 32 ) {
|
||||
my $command=31+(($preset-1) * 2);
|
||||
Debug( "Goto Preset $preset with command $command" );
|
||||
$result=$self->sendCmd( 'decoder_control.cgi?command=' . $command . '&' );
|
||||
}
|
||||
else {
|
||||
Error( "Unsupported preset $preset : must be between 1 and 32" );
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#
|
||||
# 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.
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
|
|
|
@ -1,27 +1,34 @@
|
|||
# ==========================================================================
|
||||
#
|
||||
# ZoneMinder SunEyes SP-P1802SWPTZ IP Control Protocol Module, $Date: 2017-03-19 23:00:00 +1000 (Sat, 19 March 2017) $, $Revision: 0002 $
|
||||
# Copyright (C) 2001-2008 Philip Coombes
|
||||
# Modified for use with Foscam FI8918W IP Camera by Dave Harris
|
||||
# Modified Feb 2011 by Howard Durdle (http://durdl.es/x) to:
|
||||
# fix horizontal panning, add presets and IR on/off
|
||||
# use Control Device field to pass username and password
|
||||
# Modified May 2014 by Arun Horne (http://arunhorne.co.uk) to:
|
||||
# use HTTP basic auth as required by firmware 11.37.x.x upward
|
||||
# Modified on Sep 28 2015 by Bobby Billingsley
|
||||
# Changes made
|
||||
# - Copied FI8918W.pm to SPP1802SWPTZ.pm
|
||||
# - modified to control a SunEyes SP-P1802SWPTZ
|
||||
|
||||
# ==========================================================================
|
||||
# ZoneMinder SunEyes SP-P1802SWPTZ IP Control Protocol Module
|
||||
# Modified on 13 March 2017 by Steve Gilvarry
|
||||
# -Address license and copyright issues
|
||||
#
|
||||
# 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 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.
|
||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the implementation of the SunEyes SP-P1802SWPTZ IP
|
||||
# camera control protocol
|
||||
#
|
||||
|
|
|
@ -45,265 +45,239 @@ use ZoneMinder::Config qw(:all);
|
|||
|
||||
use Time::HiRes qw( usleep );
|
||||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $id = shift;
|
||||
my $self = ZoneMinder::Control->new( $id );
|
||||
bless( $self, $class );
|
||||
srand( time() );
|
||||
return $self;
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my $id = shift;
|
||||
my $self = ZoneMinder::Control->new( $id );
|
||||
bless( $self, $class );
|
||||
srand( time() );
|
||||
return $self;
|
||||
}
|
||||
|
||||
our $AUTOLOAD;
|
||||
|
||||
sub AUTOLOAD
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( exists($self->{$name}) )
|
||||
{
|
||||
return( $self->{$name} );
|
||||
}
|
||||
Fatal( "Can't access $name member of object of class $class" );
|
||||
sub AUTOLOAD {
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( exists($self->{$name}) ) {
|
||||
return( $self->{$name} );
|
||||
}
|
||||
Fatal( "Can't access $name member of object of class $class" );
|
||||
}
|
||||
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
sub open {
|
||||
my $self = shift;
|
||||
|
||||
$self->loadMonitor();
|
||||
$self->loadMonitor();
|
||||
|
||||
use LWP::UserAgent;
|
||||
$self->{ua} = LWP::UserAgent->new;
|
||||
$self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION );
|
||||
use LWP::UserAgent;
|
||||
$self->{ua} = LWP::UserAgent->new;
|
||||
$self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION );
|
||||
|
||||
$self->{state} = 'open';
|
||||
$self->{state} = 'open';
|
||||
}
|
||||
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
$self->{state} = 'closed';
|
||||
sub close {
|
||||
my $self = shift;
|
||||
$self->{state} = 'closed';
|
||||
}
|
||||
|
||||
sub printMsg
|
||||
{
|
||||
my $self = shift;
|
||||
my $msg = shift;
|
||||
my $msg_len = length($msg);
|
||||
sub printMsg {
|
||||
my $self = shift;
|
||||
my $msg = shift;
|
||||
my $msg_len = length($msg);
|
||||
|
||||
Debug( $msg."[".$msg_len."]" );
|
||||
Debug( $msg."[".$msg_len."]" );
|
||||
}
|
||||
|
||||
sub sendCmd
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = shift;
|
||||
sub sendCmd {
|
||||
my $self = shift;
|
||||
my $cmd = shift;
|
||||
|
||||
my $result = undef;
|
||||
my $result = undef;
|
||||
|
||||
printMsg( $cmd, "Tx" );
|
||||
printMsg( $cmd, "Tx" );
|
||||
|
||||
my $url;
|
||||
if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) {
|
||||
$url = $self->{Monitor}->{ControlAddress}.$cmd;
|
||||
} else {
|
||||
$url = 'http://'.$self->{Monitor}->{ControlAddress}.$cmd;
|
||||
} # en dif
|
||||
my $req = HTTP::Request->new( GET=>$url );
|
||||
my $url;
|
||||
if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) {
|
||||
$url = $self->{Monitor}->{ControlAddress}.$cmd;
|
||||
} else {
|
||||
$url = 'http://'.$self->{Monitor}->{ControlAddress}.$cmd;
|
||||
} # en dif
|
||||
my $req = HTTP::Request->new( GET=>$url );
|
||||
|
||||
my $res = $self->{ua}->request($req);
|
||||
my $res = $self->{ua}->request($req);
|
||||
|
||||
if ( $res->is_success )
|
||||
{
|
||||
$result = !undef;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error( "Error check failed: '".$res->status_line()."'" );
|
||||
}
|
||||
if ( $res->is_success ) {
|
||||
$result = !undef;
|
||||
} else {
|
||||
Error( "Error check failed: '".$res->status_line()."'" );
|
||||
}
|
||||
|
||||
return( $result );
|
||||
return( $result );
|
||||
}
|
||||
|
||||
sub reset
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Camera Reset" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=reset";
|
||||
$self->sendCmd( $cmd );
|
||||
sub reset {
|
||||
my $self = shift;
|
||||
Debug( "Camera Reset" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=reset";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
sub moveMap
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $xcoord = $self->getParam( $params, 'xcoord' );
|
||||
my $ycoord = $self->getParam( $params, 'ycoord' );
|
||||
sub moveMap {
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $xcoord = $self->getParam( $params, 'xcoord' );
|
||||
my $ycoord = $self->getParam( $params, 'ycoord' );
|
||||
|
||||
my $hor = $xcoord * 100 / $self->{Monitor}->{Width};
|
||||
my $ver = $ycoord * 100 / $self->{Monitor}->{Height};
|
||||
my $hor = $xcoord * 100 / $self->{Monitor}->{Width};
|
||||
my $ver = $ycoord * 100 / $self->{Monitor}->{Height};
|
||||
|
||||
my $maxver = 8;
|
||||
my $maxhor = 30;
|
||||
|
||||
my $horDir = "right";
|
||||
my $verDir = "up";
|
||||
my $horSteps = 0;
|
||||
my $verSteps = 0;
|
||||
my $maxver = 8;
|
||||
my $maxhor = 30;
|
||||
|
||||
# Horizontal movement
|
||||
if ($hor < 50) {
|
||||
# left
|
||||
$horSteps = ((50 - $hor) / 50) * $maxhor;
|
||||
$horDir = "left";
|
||||
}
|
||||
elsif ($hor > 50) {
|
||||
# right
|
||||
$horSteps = (($hor - 50) / 50) * $maxhor;
|
||||
$horDir = "right";
|
||||
}
|
||||
|
||||
# Vertical movement
|
||||
if ($ver < 50) {
|
||||
# up
|
||||
$verSteps = ((50 - $ver) / 50) * $maxver;
|
||||
$verDir = "up";
|
||||
}
|
||||
elsif ($ver > 50) {
|
||||
# down
|
||||
$verSteps = (($ver - 50) / 50) * $maxver;
|
||||
$verDir = "down";
|
||||
}
|
||||
my $horDir = "right";
|
||||
my $verDir = "up";
|
||||
my $horSteps = 0;
|
||||
my $verSteps = 0;
|
||||
|
||||
my $v = int($verSteps);
|
||||
my $h = int($horSteps);
|
||||
# Horizontal movement
|
||||
if ( $hor < 50 ) {
|
||||
# left
|
||||
$horSteps = ((50 - $hor) / 50) * $maxhor;
|
||||
$horDir = "left";
|
||||
}
|
||||
elsif ( $hor > 50 ) {
|
||||
# right
|
||||
$horSteps = (($hor - 50) / 50) * $maxhor;
|
||||
$horDir = "right";
|
||||
}
|
||||
|
||||
Debug( "Move Map to $xcoord,$ycoord, hor=$h $horDir, ver=$v $verDir");
|
||||
my $cmd = "/cgi/admin/ptctrl.cgi?action=movedegree&Cmd=$horDir&Degree=$h";
|
||||
$self->sendCmd( $cmd );
|
||||
$cmd = "/cgi/admin/ptctrl.cgi?action=movedegree&Cmd=$verDir&Degree=$v";
|
||||
$self->sendCmd( $cmd );
|
||||
# Vertical movement
|
||||
if ( $ver < 50 ) {
|
||||
# up
|
||||
$verSteps = ((50 - $ver) / 50) * $maxver;
|
||||
$verDir = "up";
|
||||
}
|
||||
elsif ( $ver > 50 ) {
|
||||
# down
|
||||
$verSteps = (($ver - 50) / 50) * $maxver;
|
||||
$verDir = "down";
|
||||
}
|
||||
|
||||
my $v = int($verSteps);
|
||||
my $h = int($horSteps);
|
||||
|
||||
Debug( "Move Map to $xcoord,$ycoord, hor=$h $horDir, ver=$v $verDir");
|
||||
my $cmd = "/cgi/admin/ptctrl.cgi?action=movedegree&Cmd=$horDir&Degree=$h";
|
||||
$self->sendCmd( $cmd );
|
||||
$cmd = "/cgi/admin/ptctrl.cgi?action=movedegree&Cmd=$verDir&Degree=$v";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
sub moveRelUp
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $step = $self->getParam( $params, 'tiltstep' );
|
||||
Debug( "Step Up $step" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=up";
|
||||
$self->sendCmd( $cmd );
|
||||
sub moveRelUp {
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $step = $self->getParam( $params, 'tiltstep' );
|
||||
Debug( "Step Up $step" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=up";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
sub moveRelDown
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $step = $self->getParam( $params, 'tiltstep' );
|
||||
Debug( "Step Down $step" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=down";
|
||||
$self->sendCmd( $cmd );
|
||||
sub moveRelDown {
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $step = $self->getParam( $params, 'tiltstep' );
|
||||
Debug( "Step Down $step" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=down";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
sub moveRelLeft
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $step = $self->getParam( $params, 'panstep' );
|
||||
Debug( "Step Left $step" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=left";
|
||||
$self->sendCmd( $cmd );
|
||||
sub moveRelLeft {
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $step = $self->getParam( $params, 'panstep' );
|
||||
|
||||
if ( $self->{Monitor}->{Orientation} eq "hori" ) {
|
||||
Debug( "Stepping Right because flipped horizontally " );
|
||||
$self->sendCmd( "/admin/ptctl.cgi?move=right" );
|
||||
} else {
|
||||
Debug( "Step Left" );
|
||||
$self->sendCmd( "/admin/ptctl.cgi?move=left" );
|
||||
}
|
||||
}
|
||||
|
||||
sub moveRelRight
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $step = $self->getParam( $params, 'panstep' );
|
||||
Debug( "Step Right $step" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=right";
|
||||
$self->sendCmd( $cmd );
|
||||
sub moveRelRight {
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $step = $self->getParam( $params, 'panstep' );
|
||||
if ( $self->{Monitor}->{Orientation} eq "hori" ) {
|
||||
Debug( "Stepping Left because flipped horizontally " );
|
||||
$self->sendCmd( "/admin/ptctl.cgi?move=left" );
|
||||
} else {
|
||||
Debug( "Step Right" );
|
||||
$self->sendCmd( "/admin/ptctl.cgi?move=right" );
|
||||
}
|
||||
}
|
||||
|
||||
sub presetClear
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
Debug( "Clear Preset $preset" );
|
||||
#my $cmd = "/axis-cgi/com/ptz.cgi?removeserverpresetno=$preset";
|
||||
#$self->sendCmd( $cmd );
|
||||
sub presetClear {
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
Debug( "Clear Preset $preset" );
|
||||
#my $cmd = "/axis-cgi/com/ptz.cgi?removeserverpresetno=$preset";
|
||||
#$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
sub presetSet
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
Debug( "Set Preset $preset" );
|
||||
my $cmd = "/admin/ptctl.cgi?position=" . ($preset - 1) . "&positionname=zm$preset";
|
||||
$self->sendCmd( $cmd );
|
||||
sub presetSet {
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
Debug( "Set Preset $preset" );
|
||||
my $cmd = "/admin/ptctl.cgi?position=" . ($preset - 1) . "&positionname=zm$preset";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
sub presetGoto
|
||||
{
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
Debug( "Goto Preset $preset" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=p" . ($preset - 1);
|
||||
$self->sendCmd( $cmd );
|
||||
sub presetGoto {
|
||||
my $self = shift;
|
||||
my $params = shift;
|
||||
my $preset = $self->getParam( $params, 'preset' );
|
||||
Debug( "Goto Preset $preset" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=p" . ($preset - 1);
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
sub presetHome
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Home Preset" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=h";
|
||||
$self->sendCmd( $cmd );
|
||||
sub presetHome {
|
||||
my $self = shift;
|
||||
Debug( "Home Preset" );
|
||||
my $cmd = "/admin/ptctl.cgi?move=h";
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
# Below is stub documentation for your module. You'd better edit it!
|
||||
|
||||
=head1 NAME
|
||||
|
||||
ZoneMinder::Database - Perl extension for blah blah blah
|
||||
ZoneMinder::Control::SkyIPCam7xx.pm - Module for controlling AirLink101 SkyIPams
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use ZoneMinder::Database;
|
||||
blah blah blah
|
||||
use ZoneMinder::Control::SkyIPCam7xx;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Stub documentation for ZoneMinder, created by h2xs. It looks like the
|
||||
author of the extension was negligent enough to leave the stub
|
||||
unedited.
|
||||
|
||||
Blah blah blah.
|
||||
Module for controlling AirLink101 Cameras.
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
None by default.
|
||||
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
Mention other useful documentation such as the documentation of
|
||||
related modules or operating system documentation (such as man pages
|
||||
in UNIX), or any relevant external documentation such as RFCs or
|
||||
standards.
|
||||
|
||||
If you have a mailing list set up for your module, mention it here.
|
||||
|
||||
If you have a web site set up for your module, mention it here.
|
||||
ZoneMinder::Control
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
|
@ -318,5 +292,4 @@ This library is free software; you can redistribute it and/or modify
|
|||
it under the same terms as Perl itself, either Perl version 5.8.3 or,
|
||||
at your option, any later version of Perl 5 you may have available.
|
||||
|
||||
|
||||
=cut
|
||||
|
|
|
@ -75,9 +75,11 @@ sub zmDbConnect {
|
|||
if ( $force ) {
|
||||
zmDbDisconnect();
|
||||
}
|
||||
if ( !defined( $dbh ) ) {
|
||||
my $options = shift;
|
||||
|
||||
if ( ( ! defined( $dbh ) ) or ! $dbh->ping() ) {
|
||||
my ( $host, $portOrSocket ) = ( $ZoneMinder::Config::Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
|
||||
my $socket;
|
||||
my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
|
||||
|
||||
if ( defined($portOrSocket) ) {
|
||||
if ( $portOrSocket =~ /^\// ) {
|
||||
|
@ -89,7 +91,7 @@ sub zmDbConnect {
|
|||
$socket = ";host=".$Config{ZM_DB_HOST};
|
||||
}
|
||||
$dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||
.$socket
|
||||
.$socket . ($options?';'.join(';', map { $_.'='.$$options{$_} } keys %{$options} ) : '' )
|
||||
, $Config{ZM_DB_USER}
|
||||
, $Config{ZM_DB_PASS}
|
||||
);
|
||||
|
|
|
@ -28,30 +28,12 @@ use 5.006;
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
require Exporter;
|
||||
require ZoneMinder::Base;
|
||||
require ZoneMinder::Object;
|
||||
require Date::Manip;
|
||||
|
||||
our @ISA = qw(Exporter ZoneMinder::Base);
|
||||
|
||||
# Items to export into callers namespace by default. Note: do not export
|
||||
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||
# Do not simply export all your public functions/methods/constants.
|
||||
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our %EXPORT_TAGS = (
|
||||
'functions' => [ qw(
|
||||
) ]
|
||||
);
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
|
||||
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
|
||||
|
||||
our @EXPORT = qw();
|
||||
|
||||
our $VERSION = $ZoneMinder::Base::VERSION;
|
||||
#our @ISA = qw(ZoneMinder::Object);
|
||||
use parent qw(ZoneMinder::Object);
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
|
@ -62,39 +44,24 @@ our $VERSION = $ZoneMinder::Base::VERSION;
|
|||
use ZoneMinder::Config qw(:all);
|
||||
use ZoneMinder::Logger qw(:all);
|
||||
use ZoneMinder::Database qw(:all);
|
||||
require Date::Parse;
|
||||
|
||||
use vars qw/ $table $primary_key /;
|
||||
$table = 'Events';
|
||||
$primary_key = 'Id';
|
||||
|
||||
use POSIX;
|
||||
|
||||
sub new {
|
||||
my ( $parent, $id, $data ) = @_;
|
||||
|
||||
my $self = {};
|
||||
bless $self, $parent;
|
||||
$$self{dbh} = $ZoneMinder::Database::dbh;
|
||||
#zmDbConnect();
|
||||
if ( ( $$self{Id} = $id ) or $data ) {
|
||||
#$log->debug("loading $parent $id") if $debug or DEBUG_ALL;
|
||||
$self->load( $data );
|
||||
sub Time {
|
||||
if ( @_ > 1 ) {
|
||||
$_[0]{Time} = $_[1];
|
||||
}
|
||||
return $self;
|
||||
} # end sub new
|
||||
if ( ! defined $_[0]{Time} ) {
|
||||
|
||||
sub load {
|
||||
my ( $self, $data ) = @_;
|
||||
my $type = ref $self;
|
||||
if ( ! $data ) {
|
||||
#$log->debug("Object::load Loading from db $type");
|
||||
$data = $$self{dbh}->selectrow_hashref( 'SELECT * FROM Events WHERE Id=?', {}, $$self{Id} );
|
||||
if ( ! $data ) {
|
||||
Error( "Failure to load Event record for $$self{Id}: Reason: " . $$self{dbh}->errstr );
|
||||
} else {
|
||||
Debug( 3, "Loaded Event $$self{Id}" );
|
||||
} # end if
|
||||
} # end if ! $data
|
||||
if ( $data and %$data ) {
|
||||
@$self{keys %$data} = values %$data;
|
||||
} # end if
|
||||
} # end sub load
|
||||
$_[0]{Time} = Date::Parse::str2time( $_[0]{StartTime} );
|
||||
}
|
||||
return $_[0]{Time};
|
||||
}
|
||||
|
||||
sub Name {
|
||||
if ( @_ > 1 ) {
|
||||
|
@ -130,6 +97,7 @@ sub find {
|
|||
my $filter = new ZoneMinder::Event( $$db_filter{Id}, $db_filter );
|
||||
push @results, $filter;
|
||||
} # end while
|
||||
$sth->finish();
|
||||
return @results;
|
||||
}
|
||||
|
||||
|
@ -138,36 +106,51 @@ sub find_one {
|
|||
return $results[0] if @results;
|
||||
}
|
||||
|
||||
sub getEventPath {
|
||||
sub getPath {
|
||||
return Path( @_ );
|
||||
}
|
||||
sub Path {
|
||||
my $event = shift;
|
||||
|
||||
my $event_path = "";
|
||||
if ( $Config{ZM_USE_DEEP_STORAGE} ) {
|
||||
$event_path = $Config{ZM_DIR_EVENTS}
|
||||
.'/'.$event->{MonitorId}
|
||||
.'/'.strftime( "%y/%m/%d/%H/%M/%S",
|
||||
localtime($event->{Time})
|
||||
)
|
||||
;
|
||||
} else {
|
||||
$event_path = $Config{ZM_DIR_EVENTS}
|
||||
.'/'.$event->{MonitorId}
|
||||
.'/'.$event->{Id}
|
||||
;
|
||||
if ( @_ > 1 ) {
|
||||
$$event{Path} = $_[1];
|
||||
if ( ! -e $$event{Path} ) {
|
||||
Error("Setting path for event $$event{Id} to $_[1] but does not exist!");
|
||||
}
|
||||
}
|
||||
|
||||
if ( index($Config{ZM_DIR_EVENTS},'/') != 0 ){
|
||||
$event_path = $Config{ZM_PATH_WEB}
|
||||
.'/'.$event_path
|
||||
;
|
||||
}
|
||||
return( $event_path );
|
||||
if ( ! $$event{Path} ) {
|
||||
my $path = ($Config{ZM_DIR_EVENTS}=~/^\//) ? $Config{ZM_DIR_EVENTS} : $Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS};
|
||||
|
||||
if ( $Config{ZM_USE_DEEP_STORAGE} ) {
|
||||
if ( $event->Time() ) {
|
||||
$$event{Path} = join('/',
|
||||
$path,
|
||||
$event->{MonitorId},
|
||||
strftime( "%y/%m/%d/%H/%M/%S",
|
||||
localtime($event->Time())
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Error("Event $$event{Id} has no value for Time(), unable to determine path");
|
||||
$$event{Path} = '';
|
||||
}
|
||||
} else {
|
||||
$$event{Path} = join('/',
|
||||
$path,
|
||||
$event->{MonitorId},
|
||||
$event->{Id},
|
||||
);
|
||||
}
|
||||
} # end if
|
||||
|
||||
return $$event{Path};
|
||||
}
|
||||
|
||||
sub GenerateVideo {
|
||||
my ( $self, $rate, $fps, $scale, $size, $overwrite, $format ) = @_;
|
||||
|
||||
my $event_path = getEventPath( $self );
|
||||
my $event_path = $self->getPath( );
|
||||
chdir( $event_path );
|
||||
( my $video_name = $self->{Name} ) =~ s/\s/_/g;
|
||||
|
||||
|
@ -228,9 +211,7 @@ sub GenerateVideo {
|
|||
my $command = $Config{ZM_PATH_FFMPEG}
|
||||
." -y -r $frame_rate "
|
||||
.$Config{ZM_FFMPEG_INPUT_OPTIONS}
|
||||
." -i %0"
|
||||
.$Config{ZM_EVENT_IMAGE_DIGITS}
|
||||
."d-capture.jpg -s $video_size "
|
||||
.' -i ' . ( $$self{DefaultVideo} ? $$self{DefaultVideo} : '%0'.$Config{ZM_EVENT_IMAGE_DIGITS} .'d-capture.jpg' )
|
||||
#. " -f concat -i /tmp/event_files.txt"
|
||||
." -s $video_size "
|
||||
.$Config{ZM_FFMPEG_OUTPUT_OPTIONS}
|
||||
|
@ -253,54 +234,143 @@ sub GenerateVideo {
|
|||
Info( "Video file $video_file already exists for event $self->{Id}\n" );
|
||||
return $event_path.'/'.$video_file;
|
||||
}
|
||||
return;
|
||||
return;
|
||||
} # end sub GenerateVideo
|
||||
|
||||
sub delete {
|
||||
my $event = $_[0];
|
||||
Info( "Deleting event $event->{Id} from Monitor $event->{MonitorId} $event->{StartTime}\n" );
|
||||
$ZoneMinder::Database::dbh->ping();
|
||||
# Do it individually to avoid locking up the table for new events
|
||||
my $sql = 'delete from Events where Id = ?';
|
||||
my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
$sth->finish();
|
||||
|
||||
if ( ! $Config{ZM_OPT_FAST_DELETE} ) {
|
||||
my $sql = 'delete from Frames where EventId = ?';
|
||||
my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
$sth->finish();
|
||||
|
||||
$sql = 'delete from Stats where EventId = ?';
|
||||
$sth = $ZoneMinder::Database::dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() );
|
||||
$res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
$sth->finish();
|
||||
|
||||
$event->delete_files( );
|
||||
} else {
|
||||
Debug('Not deleting frames, stats and files for speed.');
|
||||
}
|
||||
} # end sub delete
|
||||
|
||||
|
||||
sub delete_files {
|
||||
|
||||
my $storage_path = ($Config{ZM_DIR_EVENTS}=~/^\//) ? $Config{ZM_DIR_EVENTS} : $Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS};
|
||||
|
||||
if ( ! $storage_path ) {
|
||||
Fatal("Empty path when deleting files for event $_[0]{Id} ");
|
||||
return;
|
||||
}
|
||||
|
||||
chdir ( $storage_path );
|
||||
|
||||
if ( $Config{ZM_USE_DEEP_STORAGE} ) {
|
||||
if ( ! $_[0]{MonitorId} ) {
|
||||
Error("No monitor id assigned to event $_[0]{Id}");
|
||||
return;
|
||||
}
|
||||
Debug("Deleting files for Event $_[0]{Id} from $storage_path.");
|
||||
my $link_path = $_[0]{MonitorId}.'/*/*/*/.'.$_[0]{Id};
|
||||
#Debug( "LP1:$link_path" );
|
||||
my @links = glob($link_path);
|
||||
#Debug( "L:".$links[0].": $!" );
|
||||
if ( @links ) {
|
||||
( $link_path ) = ( $links[0] =~ /^(.*)$/ ); # De-taint
|
||||
#Debug( "LP2:$link_path" );
|
||||
|
||||
( my $day_path = $link_path ) =~ s/\.\d+//;
|
||||
#Debug( "DP:$day_path" );
|
||||
my $event_path = $day_path.readlink( $link_path );
|
||||
( $event_path ) = ( $event_path =~ /^(.*)$/ ); # De-taint
|
||||
#Debug( "EP:$event_path" );
|
||||
my $command = "/bin/rm -rf $event_path";
|
||||
#Debug( "C:$command" );
|
||||
ZoneMinder::General::executeShellCommand( $command );
|
||||
|
||||
unlink( $link_path ) or Error( "Unable to unlink '$link_path': $!" );
|
||||
|
||||
my @path_parts = split( /\//, $event_path );
|
||||
for ( my $i = int(@path_parts)-2; $i >= 1; $i-- ) {
|
||||
my $delete_path = join( '/', @path_parts[0..$i] );
|
||||
#Debug( "DP$i:$delete_path" );
|
||||
my @has_files = glob( join('/', $storage_path,$delete_path,'*' ) );
|
||||
#Debug( "HF1:".$has_files[0] ) if ( @has_files );
|
||||
last if ( @has_files );
|
||||
@has_files = glob( join('/', $storage_path, $delete_path, '.[0-9]*' ) );
|
||||
#Debug( "HF2:".$has_files[0] ) if ( @has_files );
|
||||
last if ( @has_files );
|
||||
my $command = "/bin/rm -rf $storage_path/$delete_path";
|
||||
ZoneMinder::General::executeShellCommand( $command );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
my $command = "/bin/rm -rf $storage_path/$_[0]{MonitorId}/$_[0]{Id}";
|
||||
ZoneMinder::General::executeShellCommand( $command );
|
||||
}
|
||||
} # end sub delete_files
|
||||
|
||||
sub Storage {
|
||||
return new ZoneMinder::Storage( $_[0]{StorageId} );
|
||||
}
|
||||
|
||||
sub check_for_in_filesystem {
|
||||
my $path = $_[0]->Path();
|
||||
if ( $path ) {
|
||||
my @files = glob( $path . '/*' );
|
||||
Debug("Checking for files for event $_[0]{Id} at $path using glob $path/* found " . scalar @files . " files");
|
||||
return 1 if @files;
|
||||
}
|
||||
Debug("Checking for files for event $_[0]{Id} at $path using glob $path/* found no files");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub age {
|
||||
if ( ! $_[0]{age} ) {
|
||||
$_[0]{age} = (time() - ($^T - ((-M $_[0]->Path() ) * 24*60*60)));
|
||||
}
|
||||
return $_[0]{age};
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
# Below is stub documentation for your module. You'd better edit it!
|
||||
|
||||
=head1 NAME
|
||||
|
||||
ZoneMinder::Database - Perl extension for blah blah blah
|
||||
ZoneMinder::Event - Perl Class for events
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use ZoneMinder::Event;
|
||||
blah blah blah
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Stub documentation for ZoneMinder, created by h2xs. It looks like the
|
||||
author of the extension was negligent enough to leave the stub
|
||||
unedited.
|
||||
|
||||
Blah blah blah.
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
None by default.
|
||||
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
Mention other useful documentation such as the documentation of
|
||||
related modules or operating system documentation (such as man pages
|
||||
in UNIX), or any relevant external documentation such as RFCs or
|
||||
standards.
|
||||
|
||||
If you have a mailing list set up for your module, mention it here.
|
||||
|
||||
If you have a web site set up for your module, mention it here.
|
||||
The Event class has everything you need to deal with events from Perl.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Philip Coombes, E<lt>philip.coombes@zoneminder.comE<gt>
|
||||
Isaac Connor, E<lt>isaac@zoneminder.comE<gt>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
Copyright (C) 2001-2008 Philip Coombes
|
||||
Copyright (C) 2001-2017 ZoneMinder LLC
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself, either Perl version 5.8.3 or,
|
||||
|
|
|
@ -28,31 +28,14 @@ use 5.006;
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
require Exporter;
|
||||
require ZoneMinder::Base;
|
||||
require Date::Manip;
|
||||
|
||||
our @ISA = qw(Exporter ZoneMinder::Base);
|
||||
|
||||
# Items to export into callers namespace by default. Note: do not export
|
||||
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||
# Do not simply export all your public functions/methods/constants.
|
||||
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our %EXPORT_TAGS = (
|
||||
'functions' => [ qw(
|
||||
) ]
|
||||
);
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
|
||||
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
|
||||
|
||||
our @EXPORT = qw();
|
||||
|
||||
our $VERSION = $ZoneMinder::Base::VERSION;
|
||||
use parent qw(ZoneMinder::Object);
|
||||
|
||||
use vars qw/ $table $primary_key /;
|
||||
$table = 'Filters';
|
||||
$primary_key = 'Id';
|
||||
# ==========================================================================
|
||||
#
|
||||
# General Utility Functions
|
||||
|
@ -62,40 +45,10 @@ our $VERSION = $ZoneMinder::Base::VERSION;
|
|||
use ZoneMinder::Config qw(:all);
|
||||
use ZoneMinder::Logger qw(:all);
|
||||
use ZoneMinder::Database qw(:all);
|
||||
require ZoneMinder::Server;
|
||||
|
||||
use POSIX;
|
||||
|
||||
sub new {
|
||||
my ( $parent, $id, $data ) = @_;
|
||||
|
||||
my $self = {};
|
||||
bless $self, $parent;
|
||||
$$self{dbh} = $ZoneMinder::Database::dbh;
|
||||
#zmDbConnect();
|
||||
if ( ( $$self{Id} = $id ) or $data ) {
|
||||
#$log->debug("loading $parent $id") if $debug or DEBUG_ALL;
|
||||
$self->load( $data );
|
||||
}
|
||||
return $self;
|
||||
} # end sub new
|
||||
|
||||
sub load {
|
||||
my ( $self, $data ) = @_;
|
||||
my $type = ref $self;
|
||||
if ( ! $data ) {
|
||||
#$log->debug("Object::load Loading from db $type");
|
||||
$data = $$self{dbh}->selectrow_hashref( 'SELECT * FROM Filter WHERE Id=?', {}, $$self{Id} );
|
||||
if ( ! $data ) {
|
||||
Error( "Failure to load Filter record for $$self{Id}: Reason: " . $$self{dbh}->errstr );
|
||||
} else {
|
||||
Debug( 3, "Loaded Filter $$self{Id}" );
|
||||
} # end if
|
||||
} # end if ! $data
|
||||
if ( $data and %$data ) {
|
||||
@$self{keys %$data} = values %$data;
|
||||
} # end if
|
||||
} # end sub load
|
||||
|
||||
sub Name {
|
||||
if ( @_ > 1 ) {
|
||||
$_[0]{Name} = $_[1];
|
||||
|
@ -130,6 +83,8 @@ sub find {
|
|||
my $filter = new ZoneMinder::Filter( $$db_filter{Id}, $db_filter );
|
||||
push @results, $filter;
|
||||
} # end while
|
||||
$sth->finish();
|
||||
|
||||
return @results;
|
||||
}
|
||||
|
||||
|
@ -140,7 +95,6 @@ sub find_one {
|
|||
|
||||
sub Execute {
|
||||
my $self = $_[0];
|
||||
|
||||
my $sql = $self->Sql();
|
||||
|
||||
if ( $self->{HasDiskPercent} ) {
|
||||
|
@ -156,8 +110,9 @@ sub Execute {
|
|||
$sql =~ s/zmSystemLoad/$load/g;
|
||||
}
|
||||
|
||||
my $sth = $$self{dbh}->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$$self{dbh}->errstr() );
|
||||
Debug("Filter::Execute SQL ($sql)");
|
||||
my $sth = $ZoneMinder::Database::dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr() );
|
||||
my $res = $sth->execute();
|
||||
if ( !$res ) {
|
||||
Error( "Can't execute filter '$sql', ignoring: ".$sth->errstr() );
|
||||
|
@ -169,6 +124,7 @@ sub Execute {
|
|||
push @results, $event;
|
||||
}
|
||||
$sth->finish();
|
||||
Debug("Loaded " . @results . " events for filter $_[0]{Name} using query ($sql)");
|
||||
return @results;
|
||||
}
|
||||
|
||||
|
@ -176,78 +132,74 @@ sub Sql {
|
|||
my $self = $_[0];
|
||||
if ( ! $$self{Sql} ) {
|
||||
my $filter_expr = ZoneMinder::General::jsonDecode( $self->{Query} );
|
||||
my $sql = "SELECT E.Id,
|
||||
E.MonitorId,
|
||||
my $sql = "SELECT E.*,
|
||||
unix_timestamp(E.StartTime) as Time,
|
||||
M.Name as MonitorName,
|
||||
M.DefaultRate,
|
||||
M.DefaultScale,
|
||||
E.Name,
|
||||
E.Cause,
|
||||
E.Notes,
|
||||
E.StartTime,
|
||||
unix_timestamp(E.StartTime) as Time,
|
||||
E.Length,
|
||||
E.Frames,
|
||||
E.AlarmFrames,
|
||||
E.TotScore,
|
||||
E.AvgScore,
|
||||
E.MaxScore,
|
||||
E.Archived,
|
||||
E.Videoed,
|
||||
E.Uploaded,
|
||||
E.Emailed,
|
||||
E.Messaged,
|
||||
E.Executed
|
||||
M.DefaultScale
|
||||
FROM Events as E
|
||||
INNER JOIN Monitors as M on M.Id = E.MonitorId
|
||||
";
|
||||
$self->{Sql} = '';
|
||||
|
||||
if ( $filter_expr->{terms} ) {
|
||||
for ( my $i = 0; $i < @{$filter_expr->{terms}}; $i++ ) {
|
||||
if ( exists($filter_expr->{terms}[$i]->{cnj}) ) {
|
||||
$self->{Sql} .= " ".$filter_expr->{terms}[$i]->{cnj}." ";
|
||||
foreach my $term ( @{$filter_expr->{terms}} ) {
|
||||
|
||||
if ( exists($term->{cnj}) ) {
|
||||
$self->{Sql} .= " ".$term->{cnj}." ";
|
||||
}
|
||||
if ( exists($filter_expr->{terms}[$i]->{obr}) ) {
|
||||
$self->{Sql} .= " ".str_repeat( "(", $filter_expr->{terms}[$i]->{obr} )." ";
|
||||
if ( exists($term->{obr}) ) {
|
||||
$self->{Sql} .= " ".str_repeat( "(", $term->{obr} )." ";
|
||||
}
|
||||
my $value = $filter_expr->{terms}[$i]->{val};
|
||||
my $value = $term->{val};
|
||||
my @value_list;
|
||||
if ( $filter_expr->{terms}[$i]->{attr} ) {
|
||||
if ( $filter_expr->{terms}[$i]->{attr} =~ /^Monitor/ ) {
|
||||
my ( $temp_attr_name ) = $filter_expr->{terms}[$i]->{attr} =~ /^Monitor(.+)$/;
|
||||
if ( $term->{attr} ) {
|
||||
if ( $term->{attr} =~ /^Monitor/ ) {
|
||||
my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/;
|
||||
$self->{Sql} .= "M.".$temp_attr_name;
|
||||
} elsif ( $filter_expr->{terms}[$i]->{attr} eq 'DateTime' ) {
|
||||
} elsif ( $term->{attr} =~ /^Server/ ) {
|
||||
$self->{Sql} .= "M.".$term->{attr};
|
||||
} elsif ( $term->{attr} eq 'DateTime' ) {
|
||||
$self->{Sql} .= "E.StartTime";
|
||||
} elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Date' ) {
|
||||
} elsif ( $term->{attr} eq 'Date' ) {
|
||||
$self->{Sql} .= "to_days( E.StartTime )";
|
||||
} elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Time' ) {
|
||||
} elsif ( $term->{attr} eq 'Time' ) {
|
||||
$self->{Sql} .= "extract( hour_second from E.StartTime )";
|
||||
} elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Weekday' ) {
|
||||
} elsif ( $term->{attr} eq 'Weekday' ) {
|
||||
$self->{Sql} .= "weekday( E.StartTime )";
|
||||
} elsif ( $filter_expr->{terms}[$i]->{attr} eq 'DiskPercent' ) {
|
||||
} elsif ( $term->{attr} eq 'DiskPercent' ) {
|
||||
$self->{Sql} .= "zmDiskPercent";
|
||||
$self->{HasDiskPercent} = !undef;
|
||||
} elsif ( $filter_expr->{terms}[$i]->{attr} eq 'DiskBlocks' ) {
|
||||
} elsif ( $term->{attr} eq 'DiskBlocks' ) {
|
||||
$self->{Sql} .= "zmDiskBlocks";
|
||||
$self->{HasDiskBlocks} = !undef;
|
||||
} elsif ( $filter_expr->{terms}[$i]->{attr} eq 'SystemLoad' ) {
|
||||
} elsif ( $term->{attr} eq 'SystemLoad' ) {
|
||||
$self->{Sql} .= "zmSystemLoad";
|
||||
$self->{HasSystemLoad} = !undef;
|
||||
} else {
|
||||
$self->{Sql} .= "E.".$filter_expr->{terms}[$i]->{attr};
|
||||
$self->{Sql} .= "E.".$term->{attr};
|
||||
}
|
||||
|
||||
( my $stripped_value = $value ) =~ s/^["\']+?(.+)["\']+?$/$1/;
|
||||
foreach my $temp_value ( split( /["'\s]*?,["'\s]*?/, $stripped_value ) ) {
|
||||
if ( $filter_expr->{terms}[$i]->{attr} =~ /^Monitor/ ) {
|
||||
if ( $term->{attr} =~ /^Monitor/ ) {
|
||||
$value = "'$temp_value'";
|
||||
} elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Name'
|
||||
|| $filter_expr->{terms}[$i]->{attr} eq 'Cause'
|
||||
|| $filter_expr->{terms}[$i]->{attr} eq 'Notes'
|
||||
} elsif ( $term->{attr} eq 'ServerId' ) {
|
||||
if ( $temp_value eq 'ZM_SERVER_ID' ) {
|
||||
$value = "'$Config{ZM_SERVER_ID}'";
|
||||
# This gets used later, I forget for what
|
||||
$$self{Server} = new ZoneMinder::Server( $Config{ZM_SERVER_ID} );
|
||||
} else {
|
||||
$value = "'$temp_value'";
|
||||
# This gets used later, I forget for what
|
||||
$$self{Server} = new ZoneMinder::Server( $temp_value );
|
||||
}
|
||||
} elsif ( $term->{attr} eq 'Name'
|
||||
|| $term->{attr} eq 'Cause'
|
||||
|| $term->{attr} eq 'Notes'
|
||||
) {
|
||||
$value = "'$temp_value'";
|
||||
} elsif ( $filter_expr->{terms}[$i]->{attr} eq 'DateTime' ) {
|
||||
} elsif ( $term->{attr} eq 'DateTime' ) {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
|
@ -255,7 +207,7 @@ sub Sql {
|
|||
return;
|
||||
}
|
||||
$value = "'$value'";
|
||||
} elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Date' ) {
|
||||
} elsif ( $term->{attr} eq 'Date' ) {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
|
@ -263,7 +215,7 @@ sub Sql {
|
|||
return;
|
||||
}
|
||||
$value = "to_days( '$value' )";
|
||||
} elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Time' ) {
|
||||
} elsif ( $term->{attr} eq 'Time' ) {
|
||||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value ) {
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
|
@ -277,21 +229,21 @@ sub Sql {
|
|||
push( @value_list, $value );
|
||||
} # end foreach temp_value
|
||||
} # end if has an attr
|
||||
if ( $filter_expr->{terms}[$i]->{op} ) {
|
||||
if ( $filter_expr->{terms}[$i]->{op} eq '=~' ) {
|
||||
if ( $term->{op} ) {
|
||||
if ( $term->{op} eq '=~' ) {
|
||||
$self->{Sql} .= " regexp $value";
|
||||
} elsif ( $filter_expr->{terms}[$i]->{op} eq '!~' ) {
|
||||
} elsif ( $term->{op} eq '!~' ) {
|
||||
$self->{Sql} .= " not regexp $value";
|
||||
} elsif ( $filter_expr->{terms}[$i]->{op} eq '=[]' ) {
|
||||
} elsif ( $term->{op} eq '=[]' ) {
|
||||
$self->{Sql} .= " in (".join( ",", @value_list ).")";
|
||||
} elsif ( $filter_expr->{terms}[$i]->{op} eq '!~' ) {
|
||||
} elsif ( $term->{op} eq '!~' ) {
|
||||
$self->{Sql} .= " not in (".join( ",", @value_list ).")";
|
||||
} else {
|
||||
$self->{Sql} .= " ".$filter_expr->{terms}[$i]->{op}." $value";
|
||||
$self->{Sql} .= " ".$term->{op}." $value";
|
||||
}
|
||||
} # end if has an operator
|
||||
if ( exists($filter_expr->{terms}[$i]->{cbr}) ) {
|
||||
$self->{Sql} .= " ".str_repeat( ")", $filter_expr->{terms}[$i]->{cbr} )." ";
|
||||
if ( exists($term->{cbr}) ) {
|
||||
$self->{Sql} .= " ".str_repeat( ")", $term->{cbr} )." ";
|
||||
}
|
||||
} # end foreach term
|
||||
} # end if terms
|
||||
|
@ -308,22 +260,24 @@ sub Sql {
|
|||
}
|
||||
my @auto_terms;
|
||||
if ( $self->{AutoArchive} ) {
|
||||
push( @auto_terms, "E.Archived = 0" )
|
||||
push @auto_terms, "E.Archived = 0";
|
||||
}
|
||||
# Don't do this, it prevents re-generation and concatenation.
|
||||
# If the file already exists, then the video won't be re-recreated
|
||||
if ( $self->{AutoVideo} ) {
|
||||
push( @auto_terms, "E.Videoed = 0" )
|
||||
push @auto_terms, "E.Videoed = 0";
|
||||
}
|
||||
if ( $self->{AutoUpload} ) {
|
||||
push( @auto_terms, "E.Uploaded = 0" )
|
||||
push @auto_terms, "E.Uploaded = 0";
|
||||
}
|
||||
if ( $self->{AutoEmail} ) {
|
||||
push( @auto_terms, "E.Emailed = 0" )
|
||||
push @auto_terms, "E.Emailed = 0";
|
||||
}
|
||||
if ( $self->{AutoMessage} ) {
|
||||
push( @auto_terms, "E.Messaged = 0" )
|
||||
push @auto_terms, "E.Messaged = 0";
|
||||
}
|
||||
if ( $self->{AutoExecute} ) {
|
||||
push( @auto_terms, "E.Executed = 0" )
|
||||
push @auto_terms, "E.Executed = 0";
|
||||
}
|
||||
if ( @auto_terms ) {
|
||||
$sql .= " and ( ".join( " or ", @auto_terms )." )";
|
||||
|
@ -361,14 +315,13 @@ sub Sql {
|
|||
if ( $filter_expr->{limit} ) {
|
||||
$sql .= " limit 0,".$filter_expr->{limit};
|
||||
}
|
||||
Debug( "SQL:$sql\n" );
|
||||
$self->{Sql} = $sql;
|
||||
} # end if has Sql
|
||||
return $self->{Sql};
|
||||
} # end sub Sql
|
||||
|
||||
sub getDiskPercent {
|
||||
my $command = "df .";
|
||||
my $command = "df " . ($_[0] ? $_[0] : '.');
|
||||
my $df = qx( $command );
|
||||
my $space = -1;
|
||||
if ( $df =~ /\s(\d+)%/ms ) {
|
||||
|
|
|
@ -103,8 +103,10 @@ sub getCmdFormat {
|
|||
my $suffix = "";
|
||||
my $command = $prefix.$null_command.$suffix;
|
||||
Debug( "Testing \"$command\"\n" );
|
||||
my $output = qx($command);
|
||||
my $output = qx($command 2>&1);
|
||||
my $status = $? >> 8;
|
||||
$output //= $!;
|
||||
|
||||
if ( !$status ) {
|
||||
Debug( "Test ok, using format \"$prefix<command>$suffix\"\n" );
|
||||
return( $prefix, $suffix );
|
||||
|
@ -116,8 +118,10 @@ sub getCmdFormat {
|
|||
$suffix = "'";
|
||||
$command = $prefix.$null_command.$suffix;
|
||||
Debug( "Testing \"$command\"\n" );
|
||||
my $output = qx($command);
|
||||
my $output = qx($command 2>&1);
|
||||
my $status = $? >> 8;
|
||||
$output //= $!;
|
||||
|
||||
if ( !$status ) {
|
||||
Debug( "Test ok, using format \"$prefix<command>$suffix\"\n" );
|
||||
return( $prefix, $suffix );
|
||||
|
@ -129,8 +133,10 @@ sub getCmdFormat {
|
|||
$suffix = "'";
|
||||
$command = $prefix.$null_command.$suffix;
|
||||
Debug( "Testing \"$command\"\n" );
|
||||
$output = qx($command);
|
||||
$output = qx($command 2>&1);
|
||||
$status = $? >> 8;
|
||||
$output //= $!;
|
||||
|
||||
if ( !$status ) {
|
||||
Debug( "Test ok, using format \"$prefix<command>$suffix\"\n" );
|
||||
return( $prefix, $suffix );
|
||||
|
|
|
@ -41,7 +41,7 @@ our @ISA = qw(Exporter ZoneMinder::Base);
|
|||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our %EXPORT_TAGS = (
|
||||
'constants' => [ qw(
|
||||
constants => [ qw(
|
||||
STATE_IDLE
|
||||
STATE_PREALARM
|
||||
STATE_ALARM
|
||||
|
@ -56,7 +56,7 @@ our %EXPORT_TAGS = (
|
|||
TRIGGER_ON
|
||||
TRIGGER_OFF
|
||||
) ],
|
||||
'functions' => [ qw(
|
||||
functions => [ qw(
|
||||
zmMemVerify
|
||||
zmMemInvalidate
|
||||
zmMemRead
|
||||
|
@ -77,12 +77,12 @@ our %EXPORT_TAGS = (
|
|||
zmTriggerEventOn
|
||||
zmTriggerEventOff
|
||||
zmTriggerEventCancel
|
||||
zmTriggerShowtext
|
||||
zmTriggerShowtext
|
||||
) ],
|
||||
);
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
|
||||
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
|
||||
our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} } );
|
||||
|
||||
our @EXPORT = qw();
|
||||
|
||||
|
@ -115,7 +115,7 @@ use constant TRIGGER_OFF => 2;
|
|||
|
||||
use Storable qw( freeze thaw );
|
||||
|
||||
if ( "@ENABLE_MMAP@" eq 'yes' ) {
|
||||
if ( '@ENABLE_MMAP@' eq 'yes' ) {
|
||||
# 'yes' if memory is mmapped
|
||||
require ZoneMinder::Memory::Mapped;
|
||||
ZoneMinder::Memory::Mapped->import();
|
||||
|
@ -141,46 +141,45 @@ our $native = $arch/8;
|
|||
our $mem_seq = 0;
|
||||
|
||||
our $mem_data = {
|
||||
"shared_data" => { "type"=>"SharedData", "seq"=>$mem_seq++, "contents"=> {
|
||||
"size" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"last_write_index" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"last_read_index" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"state" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"last_event" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"action" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"brightness" => { "type"=>"int32", "seq"=>$mem_seq++ },
|
||||
"hue" => { "type"=>"int32", "seq"=>$mem_seq++ },
|
||||
"colour" => { "type"=>"int32", "seq"=>$mem_seq++ },
|
||||
"contrast" => { "type"=>"int32", "seq"=>$mem_seq++ },
|
||||
"alarm_x" => { "type"=>"int32", "seq"=>$mem_seq++ },
|
||||
"alarm_y" => { "type"=>"int32", "seq"=>$mem_seq++ },
|
||||
"valid" => { "type"=>"uint8", "seq"=>$mem_seq++ },
|
||||
"active" => { "type"=>"uint8", "seq"=>$mem_seq++ },
|
||||
"signal" => { "type"=>"uint8", "seq"=>$mem_seq++ },
|
||||
"format" => { "type"=>"uint8", "seq"=>$mem_seq++ },
|
||||
"imagesize" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"epadding1" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"epadding2" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"last_write_time" => { "type"=>"time_t64", "seq"=>$mem_seq++ },
|
||||
"last_read_time" => { "type"=>"time_t64", "seq"=>$mem_seq++ },
|
||||
"control_state" => { "type"=>"uint8[256]", "seq"=>$mem_seq++ },
|
||||
shared_data => { type=>'SharedData', seq=>$mem_seq++, contents=> {
|
||||
size => { type=>'uint32', seq=>$mem_seq++ },
|
||||
last_write_index => { type=>'uint32', seq=>$mem_seq++ },
|
||||
last_read_index => { type=>'uint32', seq=>$mem_seq++ },
|
||||
state => { type=>'uint32', seq=>$mem_seq++ },
|
||||
last_event => { type=>'uint32', seq=>$mem_seq++ },
|
||||
action => { type=>'uint32', seq=>$mem_seq++ },
|
||||
brightness => { type=>'int32', seq=>$mem_seq++ },
|
||||
hue => { type=>'int32', seq=>$mem_seq++ },
|
||||
colour => { type=>'int32', seq=>$mem_seq++ },
|
||||
contrast => { type=>'int32', seq=>$mem_seq++ },
|
||||
alarm_x => { type=>'int32', seq=>$mem_seq++ },
|
||||
alarm_y => { type=>'int32', seq=>$mem_seq++ },
|
||||
valid => { type=>'uint8', seq=>$mem_seq++ },
|
||||
active => { type=>'uint8', seq=>$mem_seq++ },
|
||||
signal => { type=>'uint8', seq=>$mem_seq++ },
|
||||
format => { type=>'uint8', seq=>$mem_seq++ },
|
||||
imagesize => { type=>'uint32', seq=>$mem_seq++ },
|
||||
epadding1 => { type=>'uint32', seq=>$mem_seq++ },
|
||||
epadding2 => { type=>'uint32', seq=>$mem_seq++ },
|
||||
last_write_time => { type=>'time_t64', seq=>$mem_seq++ },
|
||||
last_read_time => { type=>'time_t64', seq=>$mem_seq++ },
|
||||
control_state => { type=>'uint8[256]', seq=>$mem_seq++ },
|
||||
}
|
||||
},
|
||||
"trigger_data" => { "type"=>"TriggerData", "seq"=>$mem_seq++, "contents"=> {
|
||||
"size" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"trigger_state" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"trigger_score" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"padding" => { "type"=>"uint32", "seq"=>$mem_seq++ },
|
||||
"trigger_cause" => { "type"=>"int8[32]", "seq"=>$mem_seq++ },
|
||||
"trigger_text" => { "type"=>"int8[256]", "seq"=>$mem_seq++ },
|
||||
"trigger_showtext" => { "type"=>"int8[256]", "seq"=>$mem_seq++ },
|
||||
trigger_data => { type=>'TriggerData', seq=>$mem_seq++, 'contents'=> {
|
||||
size => { type=>'uint32', seq=>$mem_seq++ },
|
||||
trigger_state => { type=>'uint32', seq=>$mem_seq++ },
|
||||
trigger_score => { type=>'uint32', seq=>$mem_seq++ },
|
||||
padding => { type=>'uint32', seq=>$mem_seq++ },
|
||||
trigger_cause => { type=>'int8[32]', seq=>$mem_seq++ },
|
||||
trigger_text => { type=>'int8[256]', seq=>$mem_seq++ },
|
||||
trigger_showtext => { type=>'int8[256]', seq=>$mem_seq++ },
|
||||
}
|
||||
},
|
||||
"end" => { "seq"=>$mem_seq++, "size"=> 0 }
|
||||
end => { seq=>$mem_seq++, size=>0 }
|
||||
};
|
||||
|
||||
our $mem_size = 0;
|
||||
our $mem_verified = {};
|
||||
|
||||
sub zmMemInit {
|
||||
my $offset = 0;
|
||||
|
@ -196,28 +195,28 @@ sub zmMemInit {
|
|||
}
|
||||
}
|
||||
foreach my $member_data ( sort { $a->{seq} <=> $b->{seq} } values( %{$section_data->{contents}} ) ) {
|
||||
if ( $member_data->{type} eq "long"
|
||||
|| $member_data->{type} eq "ulong"
|
||||
|| $member_data->{type} eq "size_t"
|
||||
if ( $member_data->{type} eq 'long'
|
||||
|| $member_data->{type} eq 'ulong'
|
||||
|| $member_data->{type} eq 'size_t'
|
||||
) {
|
||||
$member_data->{size} = $member_data->{align} = $native;
|
||||
} elsif ( $member_data->{type} eq "int64"
|
||||
|| $member_data->{type} eq "uint64"
|
||||
|| $member_data->{type} eq "time_t64"
|
||||
} elsif ( $member_data->{type} eq 'int64'
|
||||
|| $member_data->{type} eq 'uint64'
|
||||
|| $member_data->{type} eq 'time_t64'
|
||||
) {
|
||||
$member_data->{size} = $member_data->{align} = 8;
|
||||
} elsif ( $member_data->{type} eq "int32"
|
||||
|| $member_data->{type} eq "uint32"
|
||||
|| $member_data->{type} eq "bool4"
|
||||
} elsif ( $member_data->{type} eq 'int32'
|
||||
|| $member_data->{type} eq 'uint32'
|
||||
|| $member_data->{type} eq 'bool4'
|
||||
) {
|
||||
$member_data->{size} = $member_data->{align} = 4;
|
||||
} elsif ($member_data->{type} eq "int16"
|
||||
|| $member_data->{type} eq "uint16"
|
||||
} elsif ($member_data->{type} eq 'int16'
|
||||
|| $member_data->{type} eq 'uint16'
|
||||
) {
|
||||
$member_data->{size} = $member_data->{align} = 2;
|
||||
} elsif ( $member_data->{type} eq "int8"
|
||||
|| $member_data->{type} eq "uint8"
|
||||
|| $member_data->{type} eq "bool1"
|
||||
} elsif ( $member_data->{type} eq 'int8'
|
||||
|| $member_data->{type} eq 'uint8'
|
||||
|| $member_data->{type} eq 'bool1'
|
||||
) {
|
||||
$member_data->{size} = $member_data->{align} = 1;
|
||||
} elsif ( $member_data->{type} =~ /^u?int8\[(\d+)\]$/ ) {
|
||||
|
@ -249,51 +248,52 @@ sub zmMemVerify {
|
|||
return( undef );
|
||||
}
|
||||
|
||||
my $mem_key = zmMemKey( $monitor );
|
||||
if ( !defined($mem_verified->{$mem_key}) ) {
|
||||
my $sd_size = zmMemRead( $monitor, "shared_data:size", 1 );
|
||||
if ( $sd_size != $mem_data->{shared_data}->{size} ) {
|
||||
if ( $sd_size ) {
|
||||
Error( "Shared data size conflict in shared_data for monitor "
|
||||
.$monitor->{Name}
|
||||
.", expected "
|
||||
.$mem_data->{shared_data}->{size}
|
||||
.", got "
|
||||
.$sd_size
|
||||
);
|
||||
} else {
|
||||
Debug( "Shared data size conflict in shared_data for monitor "
|
||||
.$monitor->{Name}
|
||||
.", expected "
|
||||
.$mem_data->{shared_data}->{size}
|
||||
.", got ".$sd_size
|
||||
);
|
||||
}
|
||||
return( undef );
|
||||
my $sd_size = zmMemRead( $monitor, 'shared_data:size', 1 );
|
||||
if ( $sd_size != $mem_data->{shared_data}->{size} ) {
|
||||
if ( $sd_size ) {
|
||||
Error( "Shared data size conflict in shared_data for monitor "
|
||||
.$monitor->{Name}
|
||||
.", expected "
|
||||
.$mem_data->{shared_data}->{size}
|
||||
.", got "
|
||||
.$sd_size
|
||||
);
|
||||
} else {
|
||||
Debug( "Shared data size conflict in shared_data for monitor "
|
||||
.$monitor->{Name}
|
||||
.", expected "
|
||||
.$mem_data->{shared_data}->{size}
|
||||
.", got ".$sd_size
|
||||
);
|
||||
}
|
||||
my $td_size = zmMemRead( $monitor, "trigger_data:size", 1 );
|
||||
if ( $td_size != $mem_data->{trigger_data}->{size} ) {
|
||||
if ( $td_size ) {
|
||||
Error( "Shared data size conflict in trigger_data for monitor "
|
||||
.$monitor->{Name}
|
||||
.", expected "
|
||||
.$mem_data->{triggger_data}->{size}
|
||||
.", got "
|
||||
.$td_size
|
||||
);
|
||||
} else {
|
||||
Debug( "Shared data size conflict in trigger_data for monitor "
|
||||
.$monitor->{Name}
|
||||
.", expected "
|
||||
.$mem_data->{triggger_data}->{size}
|
||||
.", got "
|
||||
.$td_size
|
||||
);
|
||||
}
|
||||
return( undef );
|
||||
}
|
||||
$mem_verified->{$mem_key} = !undef;
|
||||
return( undef );
|
||||
}
|
||||
my $td_size = zmMemRead( $monitor, 'trigger_data:size', 1 );
|
||||
if ( $td_size != $mem_data->{trigger_data}->{size} ) {
|
||||
if ( $td_size ) {
|
||||
Error( "Shared data size conflict in trigger_data for monitor "
|
||||
.$monitor->{Name}
|
||||
.", expected "
|
||||
.$mem_data->{triggger_data}->{size}
|
||||
.", got "
|
||||
.$td_size
|
||||
);
|
||||
} else {
|
||||
Debug( "Shared data size conflict in trigger_data for monitor "
|
||||
.$monitor->{Name}
|
||||
.", expected "
|
||||
.$mem_data->{triggger_data}->{size}
|
||||
.", got "
|
||||
.$td_size
|
||||
);
|
||||
}
|
||||
return( undef );
|
||||
}
|
||||
if ( !zmMemRead($monitor, 'shared_data:valid',1) ) {
|
||||
Error( "Shared data not valid for monitor $$monitor{Id}" );
|
||||
return( undef );
|
||||
}
|
||||
|
||||
return( !undef );
|
||||
}
|
||||
|
||||
|
@ -325,32 +325,32 @@ sub zmMemRead {
|
|||
return( undef );
|
||||
}
|
||||
my $value;
|
||||
if ( $type eq "long" ) {
|
||||
( $value ) = unpack( "l!", $data );
|
||||
} elsif ( $type eq "ulong" || $type eq "size_t" ) {
|
||||
( $value ) = unpack( "L!", $data );
|
||||
} elsif ( $type eq "int64" || $type eq "time_t64" ) {
|
||||
# The "q" type is only available on 64bit platforms, so use native.
|
||||
( $value ) = unpack( "l!", $data );
|
||||
} elsif ( $type eq "uint64" ) {
|
||||
# The "q" type is only available on 64bit platforms, so use native.
|
||||
( $value ) = unpack( "L!", $data );
|
||||
} elsif ( $type eq "int32" ) {
|
||||
( $value ) = unpack( "l", $data );
|
||||
} elsif ( $type eq "uint32" || $type eq "bool4" ) {
|
||||
( $value ) = unpack( "L", $data );
|
||||
} elsif ( $type eq "int16" ) {
|
||||
( $value ) = unpack( "s", $data );
|
||||
} elsif ( $type eq "uint16" ) {
|
||||
( $value ) = unpack( "S", $data );
|
||||
} elsif ( $type eq "int8" ) {
|
||||
( $value ) = unpack( "c", $data );
|
||||
} elsif ( $type eq "uint8" || $type eq "bool1" ) {
|
||||
( $value ) = unpack( "C", $data );
|
||||
if ( $type eq 'long' ) {
|
||||
( $value ) = unpack( 'l!', $data );
|
||||
} elsif ( $type eq 'ulong' || $type eq 'size_t' ) {
|
||||
( $value ) = unpack( 'L!', $data );
|
||||
} elsif ( $type eq 'int64' || $type eq 'time_t64' ) {
|
||||
# The 'q' type is only available on 64bit platforms, so use native.
|
||||
( $value ) = unpack( 'l!', $data );
|
||||
} elsif ( $type eq 'uint64' ) {
|
||||
# The 'q' type is only available on 64bit platforms, so use native.
|
||||
( $value ) = unpack( 'L!', $data );
|
||||
} elsif ( $type eq 'int32' ) {
|
||||
( $value ) = unpack( 'l', $data );
|
||||
} elsif ( $type eq 'uint32' || $type eq 'bool4' ) {
|
||||
( $value ) = unpack( 'L', $data );
|
||||
} elsif ( $type eq 'int16' ) {
|
||||
( $value ) = unpack( 's', $data );
|
||||
} elsif ( $type eq 'uint16' ) {
|
||||
( $value ) = unpack( 'S', $data );
|
||||
} elsif ( $type eq 'int8' ) {
|
||||
( $value ) = unpack( 'c', $data );
|
||||
} elsif ( $type eq 'uint8' || $type eq 'bool1' ) {
|
||||
( $value ) = unpack( 'C', $data );
|
||||
} elsif ( $type =~ /^int8\[\d+\]$/ ) {
|
||||
( $value ) = unpack( "Z".$size, $data );
|
||||
( $value ) = unpack( 'Z'.$size, $data );
|
||||
} elsif ( $type =~ /^uint8\[\d+\]$/ ) {
|
||||
( $value ) = unpack( "C".$size, $data );
|
||||
( $value ) = unpack( 'C'.$size, $data );
|
||||
} else {
|
||||
Fatal( "Unexpected type '".$type."' found for '".$field."'" );
|
||||
}
|
||||
|
@ -366,7 +366,6 @@ sub zmMemInvalidate {
|
|||
my $monitor = shift;
|
||||
my $mem_key = zmMemKey($monitor);
|
||||
if ( $mem_key ) {
|
||||
delete $mem_verified->{$mem_key};
|
||||
zmMemDetach( $monitor );
|
||||
}
|
||||
}
|
||||
|
@ -395,34 +394,34 @@ sub zmMemWrite {
|
|||
my $size = $mem_data->{$section}->{contents}->{$element}->{size};
|
||||
|
||||
my $data;
|
||||
if ( $type eq "long" ) {
|
||||
$data = pack( "l!", $value );
|
||||
} elsif ( $type eq "ulong" || $type eq "size_t" ) {
|
||||
$data = pack( "L!", $value );
|
||||
} elsif ( $type eq "int64" || $type eq "time_t64" ) {
|
||||
# The "q" type is only available on 64bit platforms, so use native.
|
||||
$data = pack( "l!", $value );
|
||||
} elsif ( $type eq "uint64" ) {
|
||||
# The "q" type is only available on 64bit platforms, so use native.
|
||||
$data = pack( "L!", $value );
|
||||
} elsif ( $type eq "int32" ) {
|
||||
$data = pack( "l", $value );
|
||||
} elsif ( $type eq "uint32" || $type eq "bool4" ) {
|
||||
$data = pack( "L", $value );
|
||||
} elsif ( $type eq "int16" ) {
|
||||
$data = pack( "s", $value );
|
||||
} elsif ( $type eq "uint16" ) {
|
||||
$data = pack( "S", $value );
|
||||
} elsif ( $type eq "int8" ) {
|
||||
$data = pack( "c", $value );
|
||||
} elsif ( $type eq "uint8" || $type eq "bool1" ) {
|
||||
$data = pack( "C", $value );
|
||||
if ( $type eq 'long' ) {
|
||||
$data = pack( 'l!', $value );
|
||||
} elsif ( $type eq 'ulong' || $type eq 'size_t' ) {
|
||||
$data = pack( 'L!', $value );
|
||||
} elsif ( $type eq 'int64' || $type eq 'time_t64' ) {
|
||||
# The 'q' type is only available on 64bit platforms, so use native.
|
||||
$data = pack( 'l!', $value );
|
||||
} elsif ( $type eq 'uint64' ) {
|
||||
# The 'q' type is only available on 64bit platforms, so use native.
|
||||
$data = pack( 'L!', $value );
|
||||
} elsif ( $type eq 'int32' ) {
|
||||
$data = pack( 'l', $value );
|
||||
} elsif ( $type eq 'uint32' || $type eq 'bool4' ) {
|
||||
$data = pack( 'L', $value );
|
||||
} elsif ( $type eq 'int16' ) {
|
||||
$data = pack( 's', $value );
|
||||
} elsif ( $type eq 'uint16' ) {
|
||||
$data = pack( 'S', $value );
|
||||
} elsif ( $type eq 'int8' ) {
|
||||
$data = pack( 'c', $value );
|
||||
} elsif ( $type eq 'uint8' || $type eq 'bool1' ) {
|
||||
$data = pack( 'C', $value );
|
||||
} elsif ( $type =~ /^int8\[\d+\]$/ ) {
|
||||
$data = pack( "Z".$size, $value );
|
||||
$data = pack( 'Z'.$size, $value );
|
||||
} elsif ( $type =~ /^uint8\[\d+\]$/ ) {
|
||||
$data = pack( "C".$size, $value );
|
||||
$data = pack( 'C'.$size, $value );
|
||||
} else {
|
||||
Fatal( "Unexpected type '".$type."' found for '".$field."'" );
|
||||
Fatal( "Unexpected type \"$type\" found for \"$field\"" );
|
||||
}
|
||||
|
||||
if ( !zmMemPut( $monitor, $offset, $size, $data ) ) {
|
||||
|
@ -439,26 +438,26 @@ sub zmMemWrite {
|
|||
sub zmGetMonitorState {
|
||||
my $monitor = shift;
|
||||
|
||||
return( zmMemRead( $monitor, "shared_data:state" ) );
|
||||
return( zmMemRead( $monitor, 'shared_data:state' ) );
|
||||
}
|
||||
|
||||
sub zmGetAlarmLocation {
|
||||
my $monitor = shift;
|
||||
|
||||
return( zmMemRead( $monitor, [ "shared_data:alarm_x", "shared_data:alarm_y" ] ) );
|
||||
return( zmMemRead( $monitor, [ 'shared_data:alarm_x', 'shared_data:alarm_y' ] ) );
|
||||
}
|
||||
|
||||
sub zmSetControlState {
|
||||
my $monitor = shift;
|
||||
my $control_state = shift;
|
||||
|
||||
zmMemWrite( $monitor, { "shared_data:control_state" => $control_state } );
|
||||
zmMemWrite( $monitor, { 'shared_data:control_state' => $control_state } );
|
||||
}
|
||||
|
||||
sub zmGetControlState {
|
||||
my $monitor = shift;
|
||||
|
||||
return( zmMemRead( $monitor, "shared_data:control_state" ) );
|
||||
return( zmMemRead( $monitor, 'shared_data:control_state' ) );
|
||||
}
|
||||
|
||||
sub zmSaveControlState {
|
||||
|
@ -494,8 +493,8 @@ sub zmHasAlarmed {
|
|||
my $monitor = shift;
|
||||
my $last_event_id = shift;
|
||||
|
||||
my ( $state, $last_event ) = zmMemRead( $monitor, [ "shared_data:state"
|
||||
,"shared_data:last_event"
|
||||
my ( $state, $last_event ) = zmMemRead( $monitor, [ 'shared_data:state'
|
||||
,'shared_data:last_event'
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -510,63 +509,63 @@ sub zmHasAlarmed {
|
|||
sub zmGetLastEvent {
|
||||
my $monitor = shift;
|
||||
|
||||
return( zmMemRead( $monitor, "shared_data:last_event" ) );
|
||||
return( zmMemRead( $monitor, 'shared_data:last_event' ) );
|
||||
}
|
||||
|
||||
sub zmGetLastWriteTime {
|
||||
my $monitor = shift;
|
||||
|
||||
return( zmMemRead( $monitor, "shared_data:last_write_time" ) );
|
||||
return( zmMemRead( $monitor, 'shared_data:last_write_time' ) );
|
||||
}
|
||||
|
||||
sub zmGetLastReadTime {
|
||||
my $monitor = shift;
|
||||
|
||||
return( zmMemRead( $monitor, "shared_data:last_read_time" ) );
|
||||
return( zmMemRead( $monitor, 'shared_data:last_read_time' ) );
|
||||
}
|
||||
|
||||
sub zmGetMonitorActions {
|
||||
my $monitor = shift;
|
||||
|
||||
return( zmMemRead( $monitor, "shared_data:action" ) );
|
||||
return( zmMemRead( $monitor, 'shared_data:action' ) );
|
||||
}
|
||||
|
||||
sub zmMonitorEnable {
|
||||
my $monitor = shift;
|
||||
|
||||
my $action = zmMemRead( $monitor, "shared_data:action" );
|
||||
my $action = zmMemRead( $monitor, 'shared_data:action' );
|
||||
$action |= ACTION_SUSPEND;
|
||||
zmMemWrite( $monitor, { "shared_data:action" => $action } );
|
||||
zmMemWrite( $monitor, { 'shared_data:action' => $action } );
|
||||
}
|
||||
|
||||
sub zmMonitorDisable {
|
||||
my $monitor = shift;
|
||||
|
||||
my $action = zmMemRead( $monitor, "shared_data:action" );
|
||||
my $action = zmMemRead( $monitor, 'shared_data:action' );
|
||||
$action |= ACTION_RESUME;
|
||||
zmMemWrite( $monitor, { "shared_data:action" => $action } );
|
||||
zmMemWrite( $monitor, { 'shared_data:action' => $action } );
|
||||
}
|
||||
|
||||
sub zmMonitorSuspend {
|
||||
my $monitor = shift;
|
||||
|
||||
my $action = zmMemRead( $monitor, "shared_data:action" );
|
||||
my $action = zmMemRead( $monitor, 'shared_data:action' );
|
||||
$action |= ACTION_SUSPEND;
|
||||
zmMemWrite( $monitor, { "shared_data:action" => $action } );
|
||||
zmMemWrite( $monitor, { 'shared_data:action' => $action } );
|
||||
}
|
||||
|
||||
sub zmMonitorResume {
|
||||
my $monitor = shift;
|
||||
|
||||
my $action = zmMemRead( $monitor, "shared_data:action" );
|
||||
my $action = zmMemRead( $monitor, 'shared_data:action' );
|
||||
$action |= ACTION_RESUME;
|
||||
zmMemWrite( $monitor, { "shared_data:action" => $action } );
|
||||
zmMemWrite( $monitor, { 'shared_data:action' => $action } );
|
||||
}
|
||||
|
||||
sub zmGetTriggerState {
|
||||
my $monitor = shift;
|
||||
|
||||
return( zmMemRead( $monitor, "trigger_data:trigger_state" ) );
|
||||
return( zmMemRead( $monitor, 'trigger_data:trigger_state' ) );
|
||||
}
|
||||
|
||||
sub zmTriggerEventOn {
|
||||
|
@ -577,12 +576,12 @@ sub zmTriggerEventOn {
|
|||
my $showtext = shift;
|
||||
|
||||
my $values = {
|
||||
"trigger_data:trigger_score" => $score,
|
||||
"trigger_data:trigger_cause" => $cause,
|
||||
'trigger_data:trigger_score' => $score,
|
||||
'trigger_data:trigger_cause' => $cause,
|
||||
};
|
||||
$values->{"trigger_data:trigger_text"} = $text if ( defined($text) );
|
||||
$values->{"trigger_data:trigger_showtext"} = $showtext if ( defined($showtext) );
|
||||
$values->{"trigger_data:trigger_state"} = TRIGGER_ON; # Write state last so event not read incomplete
|
||||
$values->{'trigger_data:trigger_text'} = $text if ( defined($text) );
|
||||
$values->{'trigger_data:trigger_showtext'} = $showtext if ( defined($showtext) );
|
||||
$values->{'trigger_data:trigger_state'} = TRIGGER_ON; # Write state last so event not read incomplete
|
||||
|
||||
zmMemWrite( $monitor, $values );
|
||||
}
|
||||
|
@ -591,11 +590,11 @@ sub zmTriggerEventOff {
|
|||
my $monitor = shift;
|
||||
|
||||
my $values = {
|
||||
"trigger_data:trigger_state" => TRIGGER_OFF,
|
||||
"trigger_data:trigger_score" => 0,
|
||||
"trigger_data:trigger_cause" => "",
|
||||
"trigger_data:trigger_text" => "",
|
||||
"trigger_data:trigger_showtext" => "",
|
||||
'trigger_data:trigger_state' => TRIGGER_OFF,
|
||||
'trigger_data:trigger_score' => 0,
|
||||
'trigger_data:trigger_cause' => '',
|
||||
'trigger_data:trigger_text' => '',
|
||||
'trigger_data:trigger_showtext' => '',
|
||||
};
|
||||
|
||||
zmMemWrite( $monitor, $values );
|
||||
|
@ -605,11 +604,11 @@ sub zmTriggerEventCancel {
|
|||
my $monitor = shift;
|
||||
|
||||
my $values = {
|
||||
"trigger_data:trigger_state" => TRIGGER_CANCEL,
|
||||
"trigger_data:trigger_score" => 0,
|
||||
"trigger_data:trigger_cause" => "",
|
||||
"trigger_data:trigger_text" => "",
|
||||
"trigger_data:trigger_showtext" => "",
|
||||
'trigger_data:trigger_state' => TRIGGER_CANCEL,
|
||||
'trigger_data:trigger_score' => 0,
|
||||
'trigger_data:trigger_cause' => '',
|
||||
'trigger_data:trigger_text' => '',
|
||||
'trigger_data:trigger_showtext' => '',
|
||||
};
|
||||
|
||||
zmMemWrite( $monitor, $values );
|
||||
|
@ -620,7 +619,7 @@ sub zmTriggerShowtext {
|
|||
my $showtext = shift;
|
||||
|
||||
my $values = {
|
||||
"trigger_data:trigger_showtext" => $showtext,
|
||||
'trigger_data:trigger_showtext' => $showtext,
|
||||
};
|
||||
|
||||
zmMemWrite( $monitor, $values );
|
||||
|
@ -649,7 +648,7 @@ if ( zmMemVerify( $monitor ) ) {
|
|||
"shared_data:last_write_index"
|
||||
]
|
||||
);
|
||||
zmMemWrite( $monitor, { "trigger_data:trigger_showtext" => "Some Text" } );
|
||||
zmMemWrite( $monitor, { 'trigger_data:trigger_showtext' => "Some Text" } );
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
|
|
|
@ -40,15 +40,15 @@ our @ISA = qw(Exporter ZoneMinder::Base);
|
|||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our %EXPORT_TAGS = (
|
||||
'functions' => [ qw(
|
||||
zmMemKey
|
||||
zmMemAttach
|
||||
zmMemDetach
|
||||
zmMemGet
|
||||
zmMemPut
|
||||
zmMemClean
|
||||
) ],
|
||||
);
|
||||
functions => [ qw(
|
||||
zmMemKey
|
||||
zmMemAttach
|
||||
zmMemDetach
|
||||
zmMemGet
|
||||
zmMemPut
|
||||
zmMemClean
|
||||
) ],
|
||||
);
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
|
||||
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
|
||||
|
@ -68,133 +68,119 @@ use ZoneMinder::Logger qw(:all);
|
|||
|
||||
use Sys::Mmap;
|
||||
|
||||
sub zmMemKey
|
||||
{
|
||||
my $monitor = shift;
|
||||
return( defined($monitor->{MMapAddr})?$monitor->{MMapAddr}:undef );
|
||||
sub zmMemKey {
|
||||
my $monitor = shift;
|
||||
return( defined($monitor->{MMapAddr})?$monitor->{MMapAddr}:undef );
|
||||
}
|
||||
|
||||
sub zmMemAttach
|
||||
{
|
||||
my ( $monitor, $size ) = @_;
|
||||
if ( ! $size ) {
|
||||
Error( "No size passed to zmMemAttach for monitor $$monitor{Id}\n" );
|
||||
return( undef );
|
||||
sub zmMemAttach {
|
||||
my ( $monitor, $size ) = @_;
|
||||
if ( ! $size ) {
|
||||
Error( "No size passed to zmMemAttach for monitor $$monitor{Id}\n" );
|
||||
return( undef );
|
||||
}
|
||||
if ( !defined($monitor->{MMapAddr}) ) {
|
||||
|
||||
my $mmap_file = $Config{ZM_PATH_MAP}."/zm.mmap.".$monitor->{Id};
|
||||
if ( ! -e $mmap_file ) {
|
||||
Error( sprintf( "Memory map file '%s' does not exist. zmc might not be running."
|
||||
, $mmap_file
|
||||
)
|
||||
);
|
||||
return ( undef );
|
||||
}
|
||||
if ( !defined($monitor->{MMapAddr}) )
|
||||
{
|
||||
|
||||
my $mmap_file = $Config{ZM_PATH_MAP}."/zm.mmap.".$monitor->{Id};
|
||||
if ( ! -e $mmap_file ) {
|
||||
Error( sprintf( "Memory map file '%s' does not exist. zmc might not be running."
|
||||
, $mmap_file
|
||||
)
|
||||
);
|
||||
return ( undef );
|
||||
}
|
||||
my $mmap_file_size = -s $mmap_file;
|
||||
|
||||
my $mmap_file_size = -s $mmap_file;
|
||||
|
||||
if ( $mmap_file_size < $size ) {
|
||||
Error( sprintf( "Memory map file '%s' should have been %d but was instead %d"
|
||||
, $mmap_file
|
||||
, $size
|
||||
, $mmap_file_size
|
||||
)
|
||||
);
|
||||
return ( undef );
|
||||
}
|
||||
if ( !open( MMAP, "+<", $mmap_file ) )
|
||||
{
|
||||
Error( sprintf( "Can't open memory map file '%s': $!\n", $mmap_file ) );
|
||||
return( undef );
|
||||
}
|
||||
my $mmap = undef;
|
||||
my $mmap_addr = mmap( $mmap, $size, PROT_READ|PROT_WRITE, MAP_SHARED, \*MMAP );
|
||||
if ( !$mmap_addr || !$mmap )
|
||||
{
|
||||
Error( sprintf( "Can't mmap to file '%s': $!\n", $mmap_file ) );
|
||||
close( MMAP );
|
||||
return( undef );
|
||||
}
|
||||
$monitor->{MMapHandle} = \*MMAP;
|
||||
$monitor->{MMapAddr} = $mmap_addr;
|
||||
$monitor->{MMap} = \$mmap;
|
||||
if ( $mmap_file_size < $size ) {
|
||||
Error( sprintf( "Memory map file '%s' should have been %d but was instead %d"
|
||||
, $mmap_file
|
||||
, $size
|
||||
, $mmap_file_size
|
||||
)
|
||||
);
|
||||
return ( undef );
|
||||
}
|
||||
return( !undef );
|
||||
my $MMAP;
|
||||
if ( !open( $MMAP, '+<', $mmap_file ) ) {
|
||||
Error( sprintf( "Can't open memory map file '%s': $!\n", $mmap_file ) );
|
||||
return( undef );
|
||||
}
|
||||
my $mmap = undef;
|
||||
my $mmap_addr = mmap( $mmap, $size, PROT_READ|PROT_WRITE, MAP_SHARED, $MMAP );
|
||||
if ( !$mmap_addr || !$mmap ) {
|
||||
Error( sprintf( "Can't mmap to file '%s': $!\n", $mmap_file ) );
|
||||
close( $MMAP );
|
||||
return( undef );
|
||||
}
|
||||
$monitor->{MMapHandle} = $MMAP;
|
||||
$monitor->{MMapAddr} = $mmap_addr;
|
||||
$monitor->{MMap} = \$mmap;
|
||||
}
|
||||
return( !undef );
|
||||
}
|
||||
|
||||
sub zmMemDetach
|
||||
{
|
||||
my $monitor = shift;
|
||||
sub zmMemDetach {
|
||||
my $monitor = shift;
|
||||
|
||||
if ( $monitor->{MMap} )
|
||||
{
|
||||
if ( ! munmap( ${$monitor->{MMap}} ) ) {
|
||||
Warn( "Unable to munmap for monitor $$monitor{Id}\n");
|
||||
}
|
||||
delete $monitor->{MMap};
|
||||
}
|
||||
if ( $monitor->{MMapAddr} )
|
||||
{
|
||||
delete $monitor->{MMapAddr};
|
||||
}
|
||||
if ( $monitor->{MMapHandle} )
|
||||
{
|
||||
close( $monitor->{MMapHandle} );
|
||||
delete $monitor->{MMapHandle};
|
||||
if ( $monitor->{MMap} ) {
|
||||
if ( ! munmap( ${$monitor->{MMap}} ) ) {
|
||||
Warn( "Unable to munmap for monitor $$monitor{Id}\n");
|
||||
}
|
||||
delete $monitor->{MMap};
|
||||
}
|
||||
if ( $monitor->{MMapAddr} ) {
|
||||
delete $monitor->{MMapAddr};
|
||||
}
|
||||
if ( $monitor->{MMapHandle} ) {
|
||||
close( $monitor->{MMapHandle} );
|
||||
delete $monitor->{MMapHandle};
|
||||
}
|
||||
}
|
||||
|
||||
sub zmMemGet
|
||||
{
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
sub zmMemGet {
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
|
||||
my $mmap = $monitor->{MMap};
|
||||
if ( !$mmap || !$$mmap )
|
||||
{
|
||||
Error( sprintf( "Can't read from mapped memory for monitor '%d', gone away?"
|
||||
, $monitor->{Id}
|
||||
)
|
||||
my $mmap = $monitor->{MMap};
|
||||
if ( !$mmap || !$$mmap ) {
|
||||
Error( sprintf( "Can't read from mapped memory for monitor '%d', gone away?"
|
||||
, $monitor->{Id}
|
||||
)
|
||||
);
|
||||
return( undef );
|
||||
}
|
||||
my $data = substr( $$mmap, $offset, $size );
|
||||
return( $data );
|
||||
return( undef );
|
||||
}
|
||||
my $data = substr( $$mmap, $offset, $size );
|
||||
return( $data );
|
||||
}
|
||||
|
||||
sub zmMemPut
|
||||
{
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
my $data = shift;
|
||||
sub zmMemPut {
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
my $data = shift;
|
||||
|
||||
my $mmap = $monitor->{MMap};
|
||||
if ( !$mmap || !$$mmap )
|
||||
{
|
||||
Error( sprintf( "Can't write mapped memory for monitor '%d', gone away?"
|
||||
, $monitor->{Id}
|
||||
)
|
||||
my $mmap = $monitor->{MMap};
|
||||
if ( !$mmap || !$$mmap ) {
|
||||
Error( sprintf( "Can't write mapped memory for monitor '%d', gone away?"
|
||||
, $monitor->{Id}
|
||||
)
|
||||
);
|
||||
return( undef );
|
||||
}
|
||||
substr( $$mmap, $offset, $size ) = $data;
|
||||
return( !undef );
|
||||
return( undef );
|
||||
}
|
||||
substr( $$mmap, $offset, $size ) = $data;
|
||||
return( !undef );
|
||||
}
|
||||
|
||||
sub zmMemClean
|
||||
{
|
||||
Debug( "Removing memory map files\n" );
|
||||
my $mapPath = $Config{ZM_PATH_MAP}."/zm.mmap.*";
|
||||
foreach my $mapFile( glob( $mapPath ) )
|
||||
{
|
||||
( $mapFile ) = $mapFile =~ /^(.+)$/;
|
||||
Debug( "Removing memory map file '$mapFile'\n" );
|
||||
unlink( $mapFile );
|
||||
}
|
||||
sub zmMemClean {
|
||||
Debug( "Removing memory map files\n" );
|
||||
my $mapPath = $Config{ZM_PATH_MAP}.'/zm.mmap.*';
|
||||
foreach my $mapFile( glob( $mapPath ) ) {
|
||||
( $mapFile ) = $mapFile =~ /^(.+)$/;
|
||||
Debug( "Removing memory map file '$mapFile'\n" );
|
||||
unlink( $mapFile );
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
# ==========================================================================
|
||||
#
|
||||
# ZoneMinder Monitor Module, $Date$, $Revision$
|
||||
# Copyright (C) 2001-2008 Philip Coombes
|
||||
#
|
||||
# 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 module contains the common definitions and functions used by the rest
|
||||
# of the ZoneMinder scripts
|
||||
#
|
||||
package ZoneMinder::Monitor;
|
||||
|
||||
use 5.006;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
require ZoneMinder::Base;
|
||||
require ZoneMinder::Object;
|
||||
require ZoneMinder::Server;
|
||||
|
||||
#our @ISA = qw(Exporter ZoneMinder::Base);
|
||||
use parent qw(ZoneMinder::Object);
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
# General Utility Functions
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
use ZoneMinder::Config qw(:all);
|
||||
use ZoneMinder::Logger qw(:all);
|
||||
use ZoneMinder::Database qw(:all);
|
||||
|
||||
use POSIX;
|
||||
use vars qw/ $table $primary_key /;
|
||||
$table = 'Monitors';
|
||||
$primary_key = 'Id';
|
||||
|
||||
sub Server {
|
||||
return new ZoneMinder::Server( $_[0]{ServerId} );
|
||||
} # end sub Server
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
ZoneMinder::Monitor - Perl Class for Monitors
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use ZoneMinder::Monitor;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Isaac Connor, E<lt>isaac@zoneminder.comE<gt>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
Copyright (C) 2001-2017 ZoneMinder LLC
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself, either Perl version 5.8.3 or,
|
||||
at your option, any later version of Perl 5 you may have available.
|
||||
|
||||
|
||||
=cut
|
|
@ -0,0 +1,150 @@
|
|||
# ==========================================================================
|
||||
#
|
||||
# ZoneMinder Object Module, $Date$, $Revision$
|
||||
# Copyright (C) 2001-2017 ZoneMinder LLC
|
||||
#
|
||||
# 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 module contains the common definitions and functions used by the rest
|
||||
# of the ZoneMinder scripts
|
||||
#
|
||||
package ZoneMinder::Object;
|
||||
|
||||
use 5.006;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
require ZoneMinder::Base;
|
||||
|
||||
our @ISA = qw(ZoneMinder::Base);
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
# General Utility Functions
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
use ZoneMinder::Config qw(:all);
|
||||
use ZoneMinder::Logger qw(:all);
|
||||
use ZoneMinder::Database qw(:all);
|
||||
|
||||
use vars qw/ $AUTOLOAD /;
|
||||
|
||||
sub new {
|
||||
my ( $parent, $id, $data ) = @_;
|
||||
|
||||
my $self = {};
|
||||
bless $self, $parent;
|
||||
no strict 'refs';
|
||||
my $primary_key = ${$parent.'::primary_key'};
|
||||
if ( ! $primary_key ) {
|
||||
Error( 'NO primary_key for type ' . $parent );
|
||||
return;
|
||||
} # end if
|
||||
if ( ( $$self{$primary_key} = $id ) or $data ) {
|
||||
#$log->debug("loading $parent $id") if $debug or DEBUG_ALL;
|
||||
$self->load( $data );
|
||||
}
|
||||
return $self;
|
||||
} # end sub new
|
||||
|
||||
sub load {
|
||||
my ( $self, $data ) = @_;
|
||||
my $type = ref $self;
|
||||
if ( ! $data ) {
|
||||
no strict 'refs';
|
||||
my $table = ${$type.'::table'};
|
||||
if ( ! $table ) {
|
||||
Error( 'NO table for type ' . $type );
|
||||
return;
|
||||
} # end if
|
||||
my $primary_key = ${$type.'::primary_key'};
|
||||
if ( ! $primary_key ) {
|
||||
Error( 'NO primary_key for type ' . $type );
|
||||
return;
|
||||
} # end if
|
||||
|
||||
if ( ! $$self{$primary_key} ) {
|
||||
my ( $caller, undef, $line ) = caller;
|
||||
Error( (ref $self) . "::load called without $primary_key from $caller:$line");
|
||||
} else {
|
||||
#$log->debug("Object::load Loading from db $type");
|
||||
Debug("Loading $type from $table WHERE $primary_key = $$self{$primary_key}");
|
||||
$data = $ZoneMinder::Database::dbh->selectrow_hashref( "SELECT * FROM $table WHERE $primary_key=?", {}, $$self{$primary_key} );
|
||||
if ( ! $data ) {
|
||||
if ( $ZoneMinder::Database::dbh->errstr ) {
|
||||
Error( "Failure to load Object record for $$self{$primary_key}: Reason: " . $ZoneMinder::Database::dbh->errstr );
|
||||
} else {
|
||||
Debug("No Results Loading $type from $table WHERE $primary_key = $$self{$primary_key}");
|
||||
} # end if
|
||||
} # end if
|
||||
} # end if
|
||||
} # end if ! $data
|
||||
if ( $data and %$data ) {
|
||||
@$self{keys %$data} = values %$data;
|
||||
} # end if
|
||||
} # end sub load
|
||||
|
||||
sub AUTOLOAD {
|
||||
my ( $self, $newvalue ) = @_;
|
||||
my $type = ref($_[0]);
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( @_ > 1 ) {
|
||||
return $_[0]{$name} = $_[1];
|
||||
}
|
||||
return $_[0]{$name};
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
# Below is stub documentation for your module. You'd better edit it!
|
||||
|
||||
=head1 NAME
|
||||
|
||||
ZoneMinder::Object
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use parent ZoneMinder::Object;
|
||||
|
||||
This package should likely not be used directly, as it is meant mainly to be a parent for all other ZoneMinder classes.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
A base Object to act as parent for other ZoneMinder Objects.
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
None by default.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Isaac Connor, E<lt>isaac@zoneminder.comE<gt>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
Copyright (C) 2001-2017 ZoneMinder LLC
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself, either Perl version 5.8.3 or,
|
||||
at your option, any later version of Perl 5 you may have available.
|
||||
|
||||
|
||||
=cut
|
|
@ -41,9 +41,9 @@ yet.
|
|||
|
||||
=head1 OPTIONS
|
||||
|
||||
-r, --report - Just report don't actually do anything
|
||||
-i, --interactive - Ask before applying any changes
|
||||
-c, --continuous - Run continuously
|
||||
-i, --interactive - Ask before applying any changes
|
||||
-r, --report - Just report don't actually do anything
|
||||
-v, --version - Print the installed version of ZoneMinder
|
||||
|
||||
=cut
|
||||
|
@ -57,8 +57,8 @@ use bytes;
|
|||
# ==========================================================================
|
||||
|
||||
use constant MAX_AGED_DIRS => 10; # Number of event dirs to check age on
|
||||
use constant RECOVER_TAG => "(r)"; # Tag to append to event name when recovered
|
||||
use constant RECOVER_TEXT => "Recovered."; # Text to append to event notes when recovered
|
||||
use constant RECOVER_TAG => '(r)'; # Tag to append to event name when recovered
|
||||
use constant RECOVER_TEXT => 'Recovered.'; # Text to append to event notes when recovered
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
|
@ -96,20 +96,23 @@ logInit();
|
|||
logSetSignal();
|
||||
|
||||
GetOptions(
|
||||
'report' =>\$report,
|
||||
'interactive' =>\$interactive,
|
||||
'continuous' =>\$continuous,
|
||||
'version' =>\$version
|
||||
) or pod2usage(-exitstatus => -1);
|
||||
continuous =>\$continuous,
|
||||
interactive =>\$interactive,
|
||||
report =>\$report,
|
||||
version =>\$version
|
||||
) or pod2usage(-exitstatus => -1);
|
||||
|
||||
if ( $version ) {
|
||||
print( ZoneMinder::Base::ZM_VERSION . "\n");
|
||||
exit(0);
|
||||
print( ZoneMinder::Base::ZM_VERSION . "\n");
|
||||
exit(0);
|
||||
}
|
||||
if ( ($report + $interactive + $continuous) > 1 )
|
||||
{
|
||||
print( STDERR "Error, only one option may be specified\n" );
|
||||
pod2usage(-exitstatus => -1);
|
||||
if ( ($report + $interactive + $continuous) > 1 ) {
|
||||
print( STDERR "Error, only one option may be specified\n" );
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
if ( ! exists $Config{ZM_AUDIT_MIN_AGE} ) {
|
||||
Fatal('ZM_AUDIT_MIN_AGE is not set in config.');
|
||||
}
|
||||
|
||||
my $dbh = zmDbConnect();
|
||||
|
@ -123,517 +126,439 @@ my $image_path = IMAGE_PATH;
|
|||
my $loop = 1;
|
||||
my $cleaned = 0;
|
||||
MAIN: while( $loop ) {
|
||||
while ( ! ( $dbh and $dbh->ping() ) ) {
|
||||
$dbh = zmDbConnect();
|
||||
while ( ! ( $dbh and $dbh->ping() ) ) {
|
||||
$dbh = zmDbConnect();
|
||||
|
||||
if ( $continuous ) {
|
||||
Error("Unable to connect to database");
|
||||
# if we are running continuously, then just skip to the next
|
||||
# interval, otherwise we are a one off run, so wait a second and
|
||||
# retry until someone kills us.
|
||||
sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} );
|
||||
} else {
|
||||
Fatal("Unable to connect to database");
|
||||
} # end if
|
||||
} # end while can't connect to the db
|
||||
if ( $continuous ) {
|
||||
Error('Unable to connect to database');
|
||||
# if we are running continuously, then just skip to the next
|
||||
# interval, otherwise we are a one off run, so wait a second and
|
||||
# retry until someone kills us.
|
||||
sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} );
|
||||
} else {
|
||||
Fatal('Unable to connect to database');
|
||||
} # end if
|
||||
} # end while can't connect to the db
|
||||
|
||||
if ( $continuous ) {
|
||||
# if we are running continuously, then just skip to the next
|
||||
# interval, otherwise we are a one off run, so wait a second and
|
||||
# retry until someone kills us.
|
||||
sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} );
|
||||
} else {
|
||||
sleep 1;
|
||||
} # end if
|
||||
if ( $continuous ) {
|
||||
# if we are running continuously, then just skip to the next
|
||||
# interval, otherwise we are a one off run, so wait a second and
|
||||
# retry until someone kills us.
|
||||
sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} );
|
||||
} else {
|
||||
sleep 1;
|
||||
} # end if
|
||||
|
||||
if ( ! exists $Config{ZM_AUDIT_MIN_AGE} ) {
|
||||
Fatal("ZM_AUDIT_MIN_AGE is not set in config.");
|
||||
my $db_monitors;
|
||||
my $monitorSelectSql = 'select Id from Monitors order by Id';
|
||||
my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql )
|
||||
or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() );
|
||||
my $eventSelectSql = 'SELECT Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age
|
||||
FROM Events WHERE MonitorId = ? ORDER BY Id';
|
||||
my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql )
|
||||
or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() );
|
||||
|
||||
$cleaned = 0;
|
||||
my $res = $monitorSelectSth->execute()
|
||||
or Fatal( "Can't execute: ".$monitorSelectSth->errstr() );
|
||||
while( my $monitor = $monitorSelectSth->fetchrow_hashref() ) {
|
||||
Debug( "Found database monitor '$monitor->{Id}'" );
|
||||
my $db_events = $db_monitors->{$monitor->{Id}} = {};
|
||||
my $res = $eventSelectSth->execute( $monitor->{Id} )
|
||||
or Fatal( "Can't execute: ".$eventSelectSth->errstr() );
|
||||
while ( my $event = $eventSelectSth->fetchrow_hashref() ) {
|
||||
$db_events->{$event->{Id}} = $event->{Age};
|
||||
}
|
||||
Debug( 'Got '.int(keys(%$db_events))." events\n" );
|
||||
}
|
||||
|
||||
my $db_monitors;
|
||||
my $monitorSelectSql = "select Id from Monitors order by Id";
|
||||
my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql )
|
||||
or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() );
|
||||
my $eventSelectSql = "SELECT Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age
|
||||
FROM Events WHERE MonitorId = ? ORDER BY Id";
|
||||
my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql )
|
||||
or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() );
|
||||
my $fs_monitors;
|
||||
foreach my $monitor ( glob('[0-9]*') ) {
|
||||
# Thie glob above gives all files starting with a digit. So a monitor with a name starting with a digit will be in this list.
|
||||
next if $monitor =~ /\D/;
|
||||
Debug( "Found filesystem monitor '$monitor'" );
|
||||
my $fs_events = $fs_monitors->{$monitor} = {};
|
||||
( my $monitor_dir ) = ( $monitor =~ /^(.*)$/ ); # De-taint
|
||||
|
||||
$cleaned = 0;
|
||||
my $res = $monitorSelectSth->execute()
|
||||
or Fatal( "Can't execute: ".$monitorSelectSth->errstr() );
|
||||
while( my $monitor = $monitorSelectSth->fetchrow_hashref() )
|
||||
{
|
||||
Debug( "Found database monitor '$monitor->{Id}'" );
|
||||
my $db_events = $db_monitors->{$monitor->{Id}} = {};
|
||||
my $res = $eventSelectSth->execute( $monitor->{Id} )
|
||||
or Fatal( "Can't execute: ".$eventSelectSth->errstr() );
|
||||
while ( my $event = $eventSelectSth->fetchrow_hashref() )
|
||||
{
|
||||
$db_events->{$event->{Id}} = $event->{Age};
|
||||
if ( $Config{ZM_USE_DEEP_STORAGE} ) {
|
||||
foreach my $day_dir ( glob("$monitor_dir/*/*/*") ) {
|
||||
Debug( "Checking day dir $day_dir" );
|
||||
( $day_dir ) = ( $day_dir =~ /^(.*)$/ ); # De-taint
|
||||
if ( ! chdir( $day_dir ) ) {
|
||||
Error( "Can't chdir to '$day_dir': $!" );
|
||||
next;
|
||||
}
|
||||
Debug( "Got ".int(keys(%$db_events))." events\n" );
|
||||
}
|
||||
|
||||
my $fs_monitors;
|
||||
foreach my $monitor ( glob("[0-9]*") )
|
||||
{
|
||||
# Thie glob above gives all files starting with a digit. So a monitor with a name starting with a digit will be in this list.
|
||||
next if $monitor =~ /\D/;
|
||||
Debug( "Found filesystem monitor '$monitor'" );
|
||||
my $fs_events = $fs_monitors->{$monitor} = {};
|
||||
( my $monitor_dir ) = ( $monitor =~ /^(.*)$/ ); # De-taint
|
||||
|
||||
if ( $Config{ZM_USE_DEEP_STORAGE} )
|
||||
{
|
||||
foreach my $day_dir ( glob("$monitor_dir/*/*/*") )
|
||||
{
|
||||
Debug( "Checking $day_dir" );
|
||||
( $day_dir ) = ( $day_dir =~ /^(.*)$/ ); # De-taint
|
||||
chdir( $day_dir );
|
||||
opendir( DIR, "." )
|
||||
or Fatal( "Can't open directory '$day_dir': $!" );
|
||||
my @event_links = sort { $b <=> $a } grep { -l $_ } readdir( DIR );
|
||||
closedir( DIR );
|
||||
my $count = 0;
|
||||
foreach my $event_link ( @event_links )
|
||||
{
|
||||
Debug( "Checking link $event_link" );
|
||||
( my $event = $event_link ) =~ s/^.*\.//;
|
||||
my $event_path = readlink( $event_link );
|
||||
if ( $count++ > MAX_AGED_DIRS )
|
||||
{
|
||||
$fs_events->{$event} = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !-e $event_path )
|
||||
{
|
||||
aud_print( "Event link $day_dir/$event_link does not point to valid target" );
|
||||
if ( confirm() )
|
||||
{
|
||||
( $event_link ) = ( $event_link =~ /^(.*)$/ ); # De-taint
|
||||
unlink( $event_link );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$fs_events->{$event} = (time() - ($^T - ((-M $event_path) * 24*60*60)));
|
||||
}
|
||||
}
|
||||
}
|
||||
chdir( EVENT_PATH );
|
||||
}
|
||||
if ( ! opendir( DIR, '.' ) ) {
|
||||
Error( "Can't open directory '$day_dir': $!" );
|
||||
next;
|
||||
}
|
||||
else
|
||||
{
|
||||
chdir( $monitor_dir );
|
||||
opendir( DIR, "." ) or Fatal( "Can't open directory '$monitor_dir': $!" );
|
||||
my @temp_events = sort { $b <=> $a } grep { -d $_ && $_ =~ /^\d+$/ } readdir( DIR );
|
||||
closedir( DIR );
|
||||
my $count = 0;
|
||||
foreach my $event ( @temp_events )
|
||||
{
|
||||
if ( $count++ > MAX_AGED_DIRS )
|
||||
{
|
||||
$fs_events->{$event} = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$fs_events->{$event} = (time() - ($^T - ((-M $event) * 24*60*60)));
|
||||
}
|
||||
}
|
||||
chdir( EVENT_PATH );
|
||||
}
|
||||
Debug( "Got ".int(keys(%$fs_events))." events\n" );
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
$cleaned = 0;
|
||||
while ( my ( $fs_monitor, $fs_events ) = each(%$fs_monitors) )
|
||||
{
|
||||
if ( my $db_events = $db_monitors->{$fs_monitor} )
|
||||
{
|
||||
if ( $fs_events )
|
||||
{
|
||||
while ( my ( $fs_event, $age ) = each(%$fs_events ) )
|
||||
{
|
||||
if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > $Config{ZM_AUDIT_MIN_AGE})) )
|
||||
{
|
||||
aud_print( "Filesystem event '$fs_monitor/$fs_event' does not exist in database" );
|
||||
if ( confirm() )
|
||||
{
|
||||
deleteEventFiles( $fs_event, $fs_monitor );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aud_print( "Filesystem monitor '$fs_monitor' does not exist in database" );
|
||||
if ( confirm() )
|
||||
{
|
||||
my $command = "rm -rf $fs_monitor";
|
||||
executeShellCommand( $command );
|
||||
my @event_links = sort { $b <=> $a } grep { -l $_ } readdir( DIR );
|
||||
closedir( DIR );
|
||||
my $count = 0;
|
||||
foreach my $event_link ( @event_links ) {
|
||||
Debug( "Checking link $event_link" );
|
||||
( my $event = $event_link ) =~ s/^.*\.//;
|
||||
my $event_path = readlink( $event_link );
|
||||
if ( $count++ > MAX_AGED_DIRS ) {
|
||||
$fs_events->{$event} = -1;
|
||||
} else {
|
||||
if ( !-e $event_path ) {
|
||||
aud_print( "Event link $day_dir/$event_link does not point to valid target" );
|
||||
if ( confirm() ) {
|
||||
( $event_link ) = ( $event_link =~ /^(.*)$/ ); # De-taint
|
||||
unlink( $event_link );
|
||||
$cleaned = 1;
|
||||
}
|
||||
} else {
|
||||
$fs_events->{$event} = (time() - ($^T - ((-M $event_path) * 24*60*60)));
|
||||
}
|
||||
}
|
||||
} # end foreach event_link
|
||||
chdir( EVENT_PATH );
|
||||
} # end foreach day_dir
|
||||
} else {
|
||||
chdir( $monitor_dir );
|
||||
opendir( DIR, "." ) or Fatal( "Can't open directory '$monitor_dir': $!" );
|
||||
my @temp_events = sort { $b <=> $a } grep { -d $_ && $_ =~ /^\d+$/ } readdir( DIR );
|
||||
closedir( DIR );
|
||||
my $count = 0;
|
||||
foreach my $event ( @temp_events ) {
|
||||
if ( $count++ > MAX_AGED_DIRS ) {
|
||||
$fs_events->{$event} = -1;
|
||||
} else {
|
||||
$fs_events->{$event} = (time() - ($^T - ((-M $event) * 24*60*60)));
|
||||
}
|
||||
}
|
||||
chdir( EVENT_PATH );
|
||||
}
|
||||
Debug( 'Got '.int(keys(%$fs_events))." events\n" );
|
||||
} # end foreach monitor Id
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
my $monitor_links;
|
||||
foreach my $link ( glob("*") )
|
||||
{
|
||||
next if ( !-l $link );
|
||||
next if ( -e $link );
|
||||
|
||||
aud_print( "Filesystem monitor link '$link' does not point to valid monitor directory" );
|
||||
if ( confirm() )
|
||||
{
|
||||
( $link ) = ( $link =~ /^(.*)$/ ); # De-taint
|
||||
my $command = qq`rm "$link"`;
|
||||
executeShellCommand( $command );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
$cleaned = 0;
|
||||
my $deleteMonitorSql = "delete low_priority from Monitors where Id = ?";
|
||||
my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql )
|
||||
or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() );
|
||||
my $deleteEventSql = "delete low_priority from Events where Id = ?";
|
||||
my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql )
|
||||
or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() );
|
||||
my $deleteFramesSql = "delete low_priority from Frames where EventId = ?";
|
||||
my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql )
|
||||
or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() );
|
||||
my $deleteStatsSql = "delete low_priority from Stats where EventId = ?";
|
||||
my $deleteStatsSth = $dbh->prepare_cached( $deleteStatsSql )
|
||||
or Fatal( "Can't prepare '$deleteStatsSql': ".$dbh->errstr() );
|
||||
while ( my ( $db_monitor, $db_events ) = each(%$db_monitors) )
|
||||
{
|
||||
if ( my $fs_events = $fs_monitors->{$db_monitor} )
|
||||
{
|
||||
if ( $db_events )
|
||||
{
|
||||
while ( my ( $db_event, $age ) = each(%$db_events ) )
|
||||
{
|
||||
if ( !defined($fs_events->{$db_event}) ) {
|
||||
if ( $age > $Config{ZM_AUDIT_MIN_AGE} ) {
|
||||
aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem" );
|
||||
if ( confirm() ) {
|
||||
my $res = $deleteEventSth->execute( $db_event )
|
||||
or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$res = $deleteFramesSth->execute( $db_event )
|
||||
or Fatal( "Can't execute: ".$deleteFramesSth->errstr() );
|
||||
$res = $deleteStatsSth->execute( $db_event )
|
||||
or Fatal( "Can't execute: ".$deleteStatsSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
} else {
|
||||
aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem but too young to delete." );
|
||||
}
|
||||
}
|
||||
}
|
||||
$cleaned = 0;
|
||||
while ( my ( $fs_monitor, $fs_events ) = each(%$fs_monitors) ) {
|
||||
if ( my $db_events = $db_monitors->{$fs_monitor} ) {
|
||||
if ( $fs_events ) {
|
||||
while ( my ( $fs_event, $age ) = each(%$fs_events ) ) {
|
||||
if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > $Config{ZM_AUDIT_MIN_AGE})) ) {
|
||||
aud_print( "Filesystem event '$fs_monitor/$fs_event' does not exist in database" );
|
||||
if ( confirm() ) {
|
||||
deleteEventFiles( $fs_event, $fs_monitor );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aud_print( "Database monitor '$db_monitor' does not exist in filesystem" );
|
||||
#if ( confirm() )
|
||||
#{
|
||||
# We don't actually do this in case it's new
|
||||
#my $res = $deleteMonitorSth->execute( $db_monitor )
|
||||
# or Fatal( "Can't execute: ".$deleteMonitorSth->errstr() );
|
||||
#$cleaned = 1;
|
||||
#}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
aud_print( "Filesystem monitor '$fs_monitor' does not exist in database" );
|
||||
if ( confirm() ) {
|
||||
my $command = "rm -rf $fs_monitor";
|
||||
executeShellCommand( $command );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
}
|
||||
|
||||
# Remove orphaned events (with no monitor)
|
||||
$cleaned = 0;
|
||||
my $selectOrphanedEventsSql = "SELECT Events.Id, Events.Name
|
||||
FROM Events LEFT JOIN Monitors ON (Events.MonitorId = Monitors.Id)
|
||||
WHERE isnull(Monitors.Id)";
|
||||
my $selectOrphanedEventsSth = $dbh->prepare_cached( $selectOrphanedEventsSql )
|
||||
or Fatal( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedEventsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectOrphanedEventsSth->errstr() );
|
||||
while( my $event = $selectOrphanedEventsSth->fetchrow_hashref() )
|
||||
{
|
||||
aud_print( "Found orphaned event with no monitor '$event->{Id}'" );
|
||||
if ( confirm() )
|
||||
{
|
||||
$res = $deleteEventSth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
my $monitor_links;
|
||||
foreach my $link ( glob('*') ) {
|
||||
next if ( !-l $link );
|
||||
next if ( -e $link );
|
||||
|
||||
aud_print( "Filesystem monitor link '$link' does not point to valid monitor directory" );
|
||||
if ( confirm() ) {
|
||||
( $link ) = ( $link =~ /^(.*)$/ ); # De-taint
|
||||
my $command = qq`rm "$link"`;
|
||||
executeShellCommand( $command );
|
||||
$cleaned = 1;
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
# Remove empty events (with no frames)
|
||||
$cleaned = 0;
|
||||
my $selectEmptyEventsSql = "SELECT E.Id AS Id, E.StartTime, F.EventId FROM Events as E LEFT JOIN Frames as F ON (E.Id = F.EventId)
|
||||
WHERE isnull(F.EventId) AND now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second > E.StartTime";
|
||||
my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql )
|
||||
or Fatal( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectEmptyEventsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectEmptyEventsSth->errstr() );
|
||||
while( my $event = $selectEmptyEventsSth->fetchrow_hashref() )
|
||||
{
|
||||
aud_print( "Found empty event with no frame records '$event->{Id}'" );
|
||||
if ( confirm() )
|
||||
{
|
||||
$res = $deleteEventSth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
# Remove orphaned frame records
|
||||
$cleaned = 0;
|
||||
my $selectOrphanedFramesSql = "SELECT DISTINCT EventId FROM Frames
|
||||
WHERE EventId NOT IN (SELECT Id FROM Events)";
|
||||
my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql )
|
||||
or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedFramesSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectOrphanedFramesSth->errstr() );
|
||||
while( my $frame = $selectOrphanedFramesSth->fetchrow_hashref() )
|
||||
{
|
||||
aud_print( "Found orphaned frame records for event '$frame->{EventId}'" );
|
||||
if ( confirm() )
|
||||
{
|
||||
$res = $deleteFramesSth->execute( $frame->{EventId} )
|
||||
or Fatal( "Can't execute: ".$deleteFramesSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
# Remove orphaned stats records
|
||||
$cleaned = 0;
|
||||
my $selectOrphanedStatsSql = "SELECT DISTINCT EventId FROM Stats
|
||||
WHERE EventId NOT IN (SELECT Id FROM Events)";
|
||||
my $selectOrphanedStatsSth = $dbh->prepare_cached( $selectOrphanedStatsSql )
|
||||
or Fatal( "Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedStatsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectOrphanedStatsSth->errstr() );
|
||||
while( my $stat = $selectOrphanedStatsSth->fetchrow_hashref() )
|
||||
{
|
||||
aud_print( "Found orphaned statistic records for event '$stat->{EventId}'" );
|
||||
if ( confirm() )
|
||||
{
|
||||
$res = $deleteStatsSth->execute( $stat->{EventId} )
|
||||
or Fatal( "Can't execute: ".$deleteStatsSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
# New audit to close any events that were left open for longer than MIN_AGE seconds
|
||||
my $selectUnclosedEventsSql =
|
||||
"SELECT E.Id,
|
||||
max(F.TimeStamp) as EndTime,
|
||||
unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length,
|
||||
max(F.FrameId) as Frames,
|
||||
count(if(F.Score>0,1,NULL)) as AlarmFrames,
|
||||
sum(F.Score) as TotScore,
|
||||
max(F.Score) as MaxScore,
|
||||
M.EventPrefix as Prefix
|
||||
FROM Events as E
|
||||
LEFT JOIN Monitors as M on E.MonitorId = M.Id
|
||||
INNER JOIN Frames as F on E.Id = F.EventId
|
||||
WHERE isnull(E.Frames) or isnull(E.EndTime)
|
||||
GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)"
|
||||
;
|
||||
my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql )
|
||||
or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() );
|
||||
my $updateUnclosedEventsSql =
|
||||
"UPDATE low_priority Events
|
||||
SET Name = ?,
|
||||
EndTime = ?,
|
||||
Length = ?,
|
||||
Frames = ?,
|
||||
AlarmFrames = ?,
|
||||
TotScore = ?,
|
||||
AvgScore = ?,
|
||||
MaxScore = ?,
|
||||
Notes = concat_ws( ' ', Notes, ? )
|
||||
WHERE Id = ?"
|
||||
;
|
||||
my $updateUnclosedEventsSth = $dbh->prepare_cached( $updateUnclosedEventsSql )
|
||||
or Fatal( "Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectUnclosedEventsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectUnclosedEventsSth->errstr() );
|
||||
while( my $event = $selectUnclosedEventsSth->fetchrow_hashref() )
|
||||
{
|
||||
aud_print( "Found open event '$event->{Id}'" );
|
||||
if ( confirm( 'close', 'closing' ) )
|
||||
{
|
||||
$res = $updateUnclosedEventsSth->execute
|
||||
(
|
||||
sprintf("%s%d%s",
|
||||
$event->{Prefix},
|
||||
$event->{Id},
|
||||
RECOVER_TAG
|
||||
),
|
||||
$event->{EndTime},
|
||||
$event->{Length},
|
||||
$event->{Frames},
|
||||
$event->{AlarmFrames},
|
||||
$event->{TotScore},
|
||||
$event->{AlarmFrames}
|
||||
? int($event->{TotScore} / $event->{AlarmFrames})
|
||||
: 0
|
||||
,
|
||||
$event->{MaxScore},
|
||||
RECOVER_TEXT,
|
||||
$event->{Id}
|
||||
) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() );
|
||||
}
|
||||
}
|
||||
|
||||
# Now delete any old image files
|
||||
if ( my @old_files = grep { -M > $max_image_age } <$image_path/*.{jpg,gif,wbmp}> )
|
||||
{
|
||||
aud_print( "Deleting ".int(@old_files)." old images\n" );
|
||||
my $untainted_old_files = join( ";", @old_files );
|
||||
( $untainted_old_files ) = ( $untainted_old_files =~ /^(.*)$/ );
|
||||
unlink( split( /;/, $untainted_old_files ) );
|
||||
}
|
||||
|
||||
# Now delete any old swap files
|
||||
( my $swap_image_root ) = ( $Config{ZM_PATH_SWAP} =~ /^(.*)$/ ); # De-taint
|
||||
File::Find::find( { wanted=>\&deleteSwapImage, untaint=>1 }, $swap_image_root );
|
||||
|
||||
# Prune the Logs table if required
|
||||
if ( $Config{ZM_LOG_DATABASE_LIMIT} )
|
||||
{
|
||||
if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^\d+$/ )
|
||||
{
|
||||
# Number of rows
|
||||
my $selectLogRowCountSql = "SELECT count(*) as Rows from Logs";
|
||||
my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql )
|
||||
or Fatal( "Can't prepare '$selectLogRowCountSql': ".$dbh->errstr() );
|
||||
$res = $selectLogRowCountSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectLogRowCountSth->errstr() );
|
||||
my $row = $selectLogRowCountSth->fetchrow_hashref();
|
||||
my $logRows = $row->{Rows};
|
||||
if ( $logRows > $Config{ZM_LOG_DATABASE_LIMIT} )
|
||||
{
|
||||
my $deleteLogByRowsSql = "DELETE low_priority FROM Logs ORDER BY TimeKey ASC LIMIT ?";
|
||||
my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql )
|
||||
or Fatal( "Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr() );
|
||||
$res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} )
|
||||
or Fatal( "Can't execute: ".$deleteLogByRowsSth->errstr() );
|
||||
if ( $deleteLogByRowsSth->rows() )
|
||||
{
|
||||
aud_print( "Deleted ".$deleteLogByRowsSth->rows()
|
||||
." log table entries by count\n" )
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# Time of record
|
||||
my $deleteLogByTimeSql =
|
||||
"DELETE low_priority FROM Logs
|
||||
WHERE TimeKey < unix_timestamp(now() - interval ".$Config{ZM_LOG_DATABASE_LIMIT}.")";
|
||||
my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql )
|
||||
or Fatal( "Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr() );
|
||||
$res = $deleteLogByTimeSth->execute()
|
||||
or Fatal( "Can't execute: ".$deleteLogByTimeSth->errstr() );
|
||||
if ( $deleteLogByTimeSth->rows() ){
|
||||
aud_print( "Deleted ".$deleteLogByTimeSth->rows()
|
||||
." log table entries by time\n" )
|
||||
;
|
||||
$cleaned = 0;
|
||||
my $deleteMonitorSql = 'delete low_priority from Monitors where Id = ?';
|
||||
my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql )
|
||||
or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() );
|
||||
my $deleteEventSql = 'delete low_priority from Events where Id = ?';
|
||||
my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql )
|
||||
or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() );
|
||||
my $deleteFramesSql = 'delete low_priority from Frames where EventId = ?';
|
||||
my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql )
|
||||
or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() );
|
||||
my $deleteStatsSql = 'delete low_priority from Stats where EventId = ?';
|
||||
my $deleteStatsSth = $dbh->prepare_cached( $deleteStatsSql )
|
||||
or Fatal( "Can't prepare '$deleteStatsSql': ".$dbh->errstr() );
|
||||
while ( my ( $db_monitor, $db_events ) = each(%$db_monitors) ) {
|
||||
if ( my $fs_events = $fs_monitors->{$db_monitor} ) {
|
||||
if ( $db_events ) {
|
||||
while ( my ( $db_event, $age ) = each(%$db_events ) ) {
|
||||
if ( !defined($fs_events->{$db_event}) ) {
|
||||
if ( $age > $Config{ZM_AUDIT_MIN_AGE} ) {
|
||||
aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem" );
|
||||
if ( confirm() ) {
|
||||
my $res = $deleteEventSth->execute( $db_event )
|
||||
or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$res = $deleteFramesSth->execute( $db_event )
|
||||
or Fatal( "Can't execute: ".$deleteFramesSth->errstr() );
|
||||
$res = $deleteStatsSth->execute( $db_event )
|
||||
or Fatal( "Can't execute: ".$deleteStatsSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
} else {
|
||||
aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem but too young to delete." );
|
||||
}
|
||||
}
|
||||
}
|
||||
} # end if db_events
|
||||
} else {
|
||||
aud_print( "Database monitor '$db_monitor' does not exist in filesystem" );
|
||||
#if ( confirm() )
|
||||
#{
|
||||
# We don't actually do this in case it's new
|
||||
#my $res = $deleteMonitorSth->execute( $db_monitor )
|
||||
# or Fatal( "Can't execute: ".$deleteMonitorSth->errstr() );
|
||||
#$cleaned = 1;
|
||||
#}
|
||||
}
|
||||
$loop = $continuous;
|
||||
} # end foreach db_monitor
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} ) if $continuous;
|
||||
# Remove orphaned events (with no monitor)
|
||||
$cleaned = 0;
|
||||
my $selectOrphanedEventsSql = 'SELECT Events.Id, Events.Name
|
||||
FROM Events LEFT JOIN Monitors ON (Events.MonitorId = Monitors.Id)
|
||||
WHERE isnull(Monitors.Id)';
|
||||
my $selectOrphanedEventsSth = $dbh->prepare_cached( $selectOrphanedEventsSql )
|
||||
or Fatal( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedEventsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectOrphanedEventsSth->errstr() );
|
||||
while( my $event = $selectOrphanedEventsSth->fetchrow_hashref() ) {
|
||||
aud_print( "Found orphaned event with no monitor '$event->{Id}'" );
|
||||
if ( confirm() ) {
|
||||
$res = $deleteEventSth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
# Remove empty events (with no frames)
|
||||
$cleaned = 0;
|
||||
my $selectEmptyEventsSql = "SELECT E.Id AS Id, E.StartTime, F.EventId FROM Events as E LEFT JOIN Frames as F ON (E.Id = F.EventId)
|
||||
WHERE isnull(F.EventId) AND now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second > E.StartTime";
|
||||
my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql )
|
||||
or Fatal( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectEmptyEventsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectEmptyEventsSth->errstr() );
|
||||
while( my $event = $selectEmptyEventsSth->fetchrow_hashref() ) {
|
||||
aud_print( "Found empty event with no frame records '$event->{Id}'" );
|
||||
if ( confirm() ) {
|
||||
$res = $deleteEventSth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
# Remove orphaned frame records
|
||||
$cleaned = 0;
|
||||
my $selectOrphanedFramesSql = 'SELECT DISTINCT EventId FROM Frames
|
||||
WHERE EventId NOT IN (SELECT Id FROM Events)';
|
||||
my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql )
|
||||
or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedFramesSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectOrphanedFramesSth->errstr() );
|
||||
while( my $frame = $selectOrphanedFramesSth->fetchrow_hashref() ) {
|
||||
aud_print( "Found orphaned frame records for event '$frame->{EventId}'" );
|
||||
if ( confirm() ) {
|
||||
$res = $deleteFramesSth->execute( $frame->{EventId} )
|
||||
or Fatal( "Can't execute: ".$deleteFramesSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
# Remove orphaned stats records
|
||||
$cleaned = 0;
|
||||
my $selectOrphanedStatsSql = 'SELECT DISTINCT EventId FROM Stats
|
||||
WHERE EventId NOT IN (SELECT Id FROM Events)';
|
||||
my $selectOrphanedStatsSth = $dbh->prepare_cached( $selectOrphanedStatsSql )
|
||||
or Fatal( "Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedStatsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectOrphanedStatsSth->errstr() );
|
||||
while( my $stat = $selectOrphanedStatsSth->fetchrow_hashref() ) {
|
||||
aud_print( "Found orphaned statistic records for event '$stat->{EventId}'" );
|
||||
if ( confirm() ) {
|
||||
$res = $deleteStatsSth->execute( $stat->{EventId} )
|
||||
or Fatal( "Can't execute: ".$deleteStatsSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
# New audit to close any events that were left open for longer than MIN_AGE seconds
|
||||
my $selectUnclosedEventsSql =
|
||||
"SELECT E.Id,
|
||||
max(F.TimeStamp) as EndTime,
|
||||
unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length,
|
||||
max(F.FrameId) as Frames,
|
||||
count(if(F.Score>0,1,NULL)) as AlarmFrames,
|
||||
sum(F.Score) as TotScore,
|
||||
max(F.Score) as MaxScore,
|
||||
M.EventPrefix as Prefix
|
||||
FROM Events as E
|
||||
LEFT JOIN Monitors as M on E.MonitorId = M.Id
|
||||
INNER JOIN Frames as F on E.Id = F.EventId
|
||||
WHERE isnull(E.Frames) or isnull(E.EndTime)
|
||||
GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)"
|
||||
;
|
||||
my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql )
|
||||
or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() );
|
||||
my $updateUnclosedEventsSql =
|
||||
"UPDATE low_priority Events
|
||||
SET Name = ?,
|
||||
EndTime = ?,
|
||||
Length = ?,
|
||||
Frames = ?,
|
||||
AlarmFrames = ?,
|
||||
TotScore = ?,
|
||||
AvgScore = ?,
|
||||
MaxScore = ?,
|
||||
Notes = concat_ws( ' ', Notes, ? )
|
||||
WHERE Id = ?"
|
||||
;
|
||||
my $updateUnclosedEventsSth = $dbh->prepare_cached( $updateUnclosedEventsSql )
|
||||
or Fatal( "Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectUnclosedEventsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectUnclosedEventsSth->errstr() );
|
||||
while( my $event = $selectUnclosedEventsSth->fetchrow_hashref() ) {
|
||||
aud_print( "Found open event '$event->{Id}'" );
|
||||
if ( confirm( 'close', 'closing' ) ) {
|
||||
$res = $updateUnclosedEventsSth->execute(
|
||||
sprintf('%s%d%s', $event->{Prefix}, $event->{Id}, RECOVER_TAG),
|
||||
$event->{EndTime},
|
||||
$event->{Length},
|
||||
$event->{Frames},
|
||||
$event->{AlarmFrames},
|
||||
$event->{TotScore},
|
||||
$event->{AlarmFrames} ? int($event->{TotScore} / $event->{AlarmFrames}) : 0,
|
||||
$event->{MaxScore},
|
||||
RECOVER_TEXT,
|
||||
$event->{Id}
|
||||
) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() );
|
||||
}
|
||||
}
|
||||
|
||||
# Now delete any old image files
|
||||
my @old_files = grep { -M > $max_image_age } <$image_path/*.{jpg,gif,wbmp}>;
|
||||
if ( @old_files ) {
|
||||
aud_print( 'Deleting '.( scalar @old_files )." old images\n" );
|
||||
my $untainted_old_files = join( ';', @old_files );
|
||||
( $untainted_old_files ) = ( $untainted_old_files =~ /^(.*)$/ );
|
||||
unlink( split( /;/, $untainted_old_files ) );
|
||||
}
|
||||
|
||||
# Now delete any old swap files
|
||||
( my $swap_image_root ) = ( $Config{ZM_PATH_SWAP} =~ /^(.*)$/ ); # De-taint
|
||||
File::Find::find( { wanted=>\&deleteSwapImage, untaint=>1 }, $swap_image_root );
|
||||
|
||||
# Prune the Logs table if required
|
||||
if ( $Config{ZM_LOG_DATABASE_LIMIT} ) {
|
||||
if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^\d+$/ ) {
|
||||
# Number of rows
|
||||
my $selectLogRowCountSql = 'SELECT count(*) AS Rows FROM Logs';
|
||||
my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql )
|
||||
or Fatal( "Can't prepare '$selectLogRowCountSql': ".$dbh->errstr() );
|
||||
$res = $selectLogRowCountSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectLogRowCountSth->errstr() );
|
||||
my $row = $selectLogRowCountSth->fetchrow_hashref();
|
||||
my $logRows = $row->{Rows};
|
||||
if ( $logRows > $Config{ZM_LOG_DATABASE_LIMIT} ) {
|
||||
my $deleteLogByRowsSql = 'DELETE low_priority FROM Logs ORDER BY TimeKey ASC LIMIT ?';
|
||||
my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql )
|
||||
or Fatal( "Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr() );
|
||||
$res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} )
|
||||
or Fatal( "Can't execute: ".$deleteLogByRowsSth->errstr() );
|
||||
if ( $deleteLogByRowsSth->rows() ) {
|
||||
aud_print( 'Deleted '.$deleteLogByRowsSth->rows() ." log table entries by count\n" );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# Time of record
|
||||
my $deleteLogByTimeSql =
|
||||
'DELETE low_priority FROM Logs
|
||||
WHERE TimeKey < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.')';
|
||||
my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql )
|
||||
or Fatal( "Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr() );
|
||||
$res = $deleteLogByTimeSth->execute()
|
||||
or Fatal( "Can't execute: ".$deleteLogByTimeSth->errstr() );
|
||||
if ( $deleteLogByTimeSth->rows() ){
|
||||
aud_print( "Deleted ".$deleteLogByTimeSth->rows() ." log table entries by time\n" );
|
||||
}
|
||||
}
|
||||
} # end if ( $Config{ZM_LOG_DATABASE_LIMIT} )
|
||||
$loop = $continuous;
|
||||
|
||||
sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} ) if $continuous;
|
||||
};
|
||||
|
||||
exit( 0 );
|
||||
|
||||
sub aud_print
|
||||
{
|
||||
my $string = shift;
|
||||
if ( !$continuous )
|
||||
{
|
||||
print( $string );
|
||||
}
|
||||
else
|
||||
{
|
||||
Info( $string );
|
||||
}
|
||||
sub aud_print {
|
||||
my $string = shift;
|
||||
if ( ! $continuous ) {
|
||||
print( $string );
|
||||
} else {
|
||||
Info( $string );
|
||||
}
|
||||
}
|
||||
|
||||
sub confirm
|
||||
{
|
||||
my $prompt = shift || "delete";
|
||||
my $action = shift || "deleting";
|
||||
sub confirm {
|
||||
my $prompt = shift || 'delete';
|
||||
my $action = shift || 'deleting';
|
||||
|
||||
my $yesno = 0;
|
||||
if ( $report )
|
||||
{
|
||||
print( "\n" );
|
||||
my $yesno = 0;
|
||||
if ( $report ) {
|
||||
print( "\n" );
|
||||
} elsif ( $interactive ) {
|
||||
print( ", $prompt y/n: " );
|
||||
my $char = <>;
|
||||
chomp( $char );
|
||||
if ( $char eq 'q' ) {
|
||||
exit( 0 );
|
||||
}
|
||||
elsif ( $interactive )
|
||||
{
|
||||
print( ", $prompt y/n: " );
|
||||
my $char = <>;
|
||||
chomp( $char );
|
||||
if ( $char eq 'q' )
|
||||
{
|
||||
exit( 0 );
|
||||
}
|
||||
if ( !$char )
|
||||
{
|
||||
$char = 'y';
|
||||
}
|
||||
$yesno = ( $char =~ /[yY]/ );
|
||||
if ( !$char ) {
|
||||
$char = 'y';
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !$continuous )
|
||||
{
|
||||
print( ", $action\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
Info( $action );
|
||||
}
|
||||
$yesno = 1;
|
||||
$yesno = ( $char =~ /[yY]/ );
|
||||
} else {
|
||||
if ( !$continuous ) {
|
||||
print( ", $action\n" );
|
||||
} else {
|
||||
Info( $action );
|
||||
}
|
||||
return( $yesno );
|
||||
$yesno = 1;
|
||||
}
|
||||
return( $yesno );
|
||||
}
|
||||
|
||||
sub deleteSwapImage
|
||||
{
|
||||
my $file = $_;
|
||||
sub deleteSwapImage {
|
||||
my $file = $_;
|
||||
|
||||
if ( $file !~ /^zmswap-/ )
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ( $file !~ /^zmswap-/ ) {
|
||||
return;
|
||||
}
|
||||
|
||||
# Ignore directories
|
||||
if ( -d $file )
|
||||
{
|
||||
return;
|
||||
}
|
||||
# Ignore directories
|
||||
if ( -d $file ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( -M $file > $max_swap_age )
|
||||
{
|
||||
Debug( "Deleting $file" );
|
||||
#unlink( $file );
|
||||
}
|
||||
if ( -M $file > $max_swap_age ) {
|
||||
Debug( "Deleting $file" );
|
||||
#unlink( $file );
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
|
|
@ -89,7 +89,6 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
|||
my @daemons = (
|
||||
'zmc',
|
||||
'zma',
|
||||
'zmf',
|
||||
'zmfilter.pl',
|
||||
'zmaudit.pl',
|
||||
'zmtrigger.pl',
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -251,10 +251,6 @@ if ( $command =~ /^(?:start|restart)$/ )
|
|||
}
|
||||
if ( $monitor->{Function} ne 'Monitor' )
|
||||
{
|
||||
if ( $Config{ZM_OPT_FRAME_SERVER} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmf -m $monitor->{Id}" );
|
||||
}
|
||||
runCommand( "zmdc.pl start zma -m $monitor->{Id}" );
|
||||
}
|
||||
if ( $Config{ZM_OPT_CONTROL} )
|
||||
|
|
|
@ -196,8 +196,10 @@ foreach my $connection ( @in_select_connections )
|
|||
|
||||
my %spawned_connections;
|
||||
my %monitors;
|
||||
|
||||
my $monitor_reload_time = 0;
|
||||
my $needsReload = 0;
|
||||
loadMonitors();
|
||||
|
||||
|
||||
$! = undef;
|
||||
my $rin = '';
|
||||
|
@ -313,6 +315,14 @@ while( 1 )
|
|||
my @out_messages;
|
||||
foreach my $monitor ( values(%monitors) )
|
||||
{
|
||||
|
||||
if ( ! zmMemVerify($monitor) ) {
|
||||
# Our attempt to verify the memory handle failed. We should reload the monitors.
|
||||
# Don't need to zmMemInvalidate because the monitor reload will do it.
|
||||
$needsReload = 1;
|
||||
next;
|
||||
}
|
||||
|
||||
my ( $state, $last_event )
|
||||
= zmMemRead( $monitor,
|
||||
[ "shared_data:state",
|
||||
|
@ -413,7 +423,7 @@ while( 1 )
|
|||
}
|
||||
|
||||
# If necessary reload monitors
|
||||
if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL )
|
||||
if ( $needsReload || ((time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL ))
|
||||
{
|
||||
foreach my $monitor ( values(%monitors) )
|
||||
{
|
||||
|
@ -421,6 +431,7 @@ while( 1 )
|
|||
zmMemInvalidate( $monitor );
|
||||
}
|
||||
loadMonitors();
|
||||
$needsReload = 0;
|
||||
}
|
||||
}
|
||||
Info( "Trigger daemon exiting\n" );
|
||||
|
@ -443,7 +454,11 @@ sub loadMonitors
|
|||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok
|
||||
# Check shared memory ok
|
||||
if ( !zmMemVerify( $monitor ) ) {
|
||||
zmMemInvalidate( $monitor );
|
||||
next;
|
||||
}
|
||||
|
||||
if ( defined($monitors{$monitor->{Id}}->{LastState}) )
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -87,24 +87,19 @@ while( 1 )
|
|||
{
|
||||
next if $monitor->{Function} eq 'None';
|
||||
my $restart = 0;
|
||||
# Prevent open handles building up if we have connect to shared memory
|
||||
# Many of our error checks below do a next without closing the mem handle.
|
||||
# zmMemInvalidate will just return of nothing is open, so we can just do this here.
|
||||
zmMemInvalidate( $monitor );
|
||||
if ( zmMemVerify( $monitor )
|
||||
&& zmMemRead( $monitor, "shared_data:valid" )
|
||||
)
|
||||
{
|
||||
if ( zmMemVerify( $monitor ) ) {
|
||||
# Check we have got an image recently
|
||||
my $image_time = zmGetLastWriteTime( $monitor );
|
||||
if ( !defined($image_time) ) {
|
||||
# Can't read from shared data
|
||||
Debug( "LastWriteTime is not defined." );
|
||||
zmMemInvalidate( $monitor );
|
||||
next;
|
||||
}
|
||||
if ( !$image_time ) {
|
||||
# We can't get the last capture time so can't be sure it's died.
|
||||
Debug( "LastWriteTime is = $image_time." );
|
||||
zmMemInvalidate( $monitor );
|
||||
next;
|
||||
}
|
||||
|
||||
|
|
|
@ -474,7 +474,11 @@ sub loadTasks
|
|||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok
|
||||
# Check shared memory ok
|
||||
if ( !zmMemVerify( $monitor ) ) {
|
||||
zmMemInvalidate( $monitor );
|
||||
next ;
|
||||
}
|
||||
|
||||
$monitor_hash{$monitor->{Id}} = $monitor;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
configure_file(zm_config.h.in "${CMAKE_CURRENT_BINARY_DIR}/zm_config.h" @ONLY)
|
||||
|
||||
# Group together all the source files that are used by all the binaries (zmc, zma, zmu, zms etc)
|
||||
set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_camera.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_zone.cpp)
|
||||
set(ZM_BIN_SRC_FILES zm_box.cpp zm_buffer.cpp zm_camera.cpp zm_comms.cpp zm_config.cpp zm_coord.cpp zm_curl_camera.cpp zm.cpp zm_db.cpp zm_logger.cpp zm_event.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_camera.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_ffmpeg.cpp zm_mpeg.cpp zm_packet.cpp zm_packetqueue.cpp zm_poly.cpp zm_regexp.cpp zm_remote_camera.cpp zm_remote_camera_http.cpp zm_remote_camera_rtsp.cpp zm_rtp.cpp zm_rtp_ctrl.cpp zm_rtp_data.cpp zm_rtp_source.cpp zm_rtsp.cpp zm_rtsp_auth.cpp zm_sdp.cpp zm_signal.cpp zm_stream.cpp zm_thread.cpp zm_time.cpp zm_timer.cpp zm_user.cpp zm_utils.cpp zm_video.cpp zm_videostore.cpp zm_zone.cpp)
|
||||
|
||||
# A fix for cmake recompiling the source files for every target.
|
||||
add_library(zm STATIC ${ZM_BIN_SRC_FILES})
|
||||
|
@ -12,21 +12,19 @@ add_library(zm STATIC ${ZM_BIN_SRC_FILES})
|
|||
add_executable(zmc zmc.cpp)
|
||||
add_executable(zma zma.cpp)
|
||||
add_executable(zmu zmu.cpp)
|
||||
add_executable(zmf zmf.cpp)
|
||||
add_executable(zms zms.cpp)
|
||||
|
||||
target_link_libraries(zmc zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
target_link_libraries(zma zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
target_link_libraries(zmu zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
target_link_libraries(zmf zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
target_link_libraries(zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
|
||||
# Generate man files for the binaries destined for the bin folder
|
||||
FOREACH(CBINARY zma zmc zmf zmu)
|
||||
FOREACH(CBINARY zma zmc zmu)
|
||||
POD2MAN(${CMAKE_CURRENT_SOURCE_DIR}/${CBINARY}.cpp zoneminder-${CBINARY} 8)
|
||||
ENDFOREACH(CBINARY zma zmc zmf zmu)
|
||||
ENDFOREACH(CBINARY zma zmc zmu)
|
||||
|
||||
install(TARGETS zmc zma zmu zmf RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(TARGETS zmc zma zmu RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(TARGETS zms RUNTIME DESTINATION "${ZM_CGIDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(CODE "execute_process(COMMAND ln -sf zms nph-zms WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})" )
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/nph-zms DESTINATION "${ZM_CGIDIR}")
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
snprintf( swap_path, sizeof(swap_path), "%s/zmswap-m%d/zmswap-q%06d", config.path_swap, monitor->Id(), connkey );
|
||||
|
||||
int len = snprintf(NULL, 0, "/zmswap-m%d", monitor->Id());
|
||||
|
||||
|
||||
int swap_path_length = strlen(config.path_swap) + snprintf(NULL, 0, "/zmswap-m%d", monitor->Id() ) + snprintf(NULL, 0, "/zmswap-q%06d", connkey ) + 1; // +1 for NULL terminator
|
||||
|
||||
if ( connkey && playback_buffer > 0 ) {
|
||||
|
||||
if ( swap_path_length + max_swap_len_suffix > PATH_MAX ) {
|
||||
Error( "Swap Path is too long. %d > %d ", swap_path_length+max_swap_len_suffix, PATH_MAX );
|
||||
} else {
|
||||
swap_path = (char *)malloc( swap_path_length+max_swap_len_suffix );
|
||||
Debug( 3, "Checking swap image path %s", config.path_swap );
|
||||
strncpy( swap_path, config.path_swap, swap_path_length );
|
||||
if ( checkSwapPath( swap_path, false ) ) {
|
||||
snprintf( &(swap_path[swap_path_length]), max_swap_len_suffix, "/zmswap-m%d", monitor->Id() );
|
||||
if ( checkSwapPath( swap_path, true ) ) {
|
||||
snprintf( &(swap_path[swap_path_length]), max_swap_len_suffix, "/zmswap-q%06d", connkey );
|
||||
if ( checkSwapPath( swap_path, true ) ) {
|
||||
buffered_playback = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -153,7 +153,7 @@ public:
|
|||
mHead = mTail = mStorage;
|
||||
else if ( level )
|
||||
{
|
||||
if ( (mHead-mStorage) > mSize )
|
||||
if ( ((uintptr_t)mHead-(uintptr_t)mStorage) > mSize )
|
||||
{
|
||||
memcpy( mStorage, mHead, mSize );
|
||||
mHead = mStorage;
|
||||
|
|
|
@ -20,33 +20,43 @@
|
|||
#include "zm.h"
|
||||
#include "zm_camera.h"
|
||||
|
||||
Camera::Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) :
|
||||
id( p_id ),
|
||||
type( p_type ),
|
||||
width( p_width),
|
||||
height( p_height ),
|
||||
colours( p_colours ),
|
||||
subpixelorder( p_subpixelorder ),
|
||||
brightness( p_brightness ),
|
||||
hue( p_hue ),
|
||||
colour( p_colour ),
|
||||
contrast( p_contrast ),
|
||||
capture( p_capture )
|
||||
Camera::Camera( unsigned int p_monitor_id, SourceType p_type, unsigned int p_width, unsigned int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) :
|
||||
monitor_id( p_monitor_id ),
|
||||
type( p_type ),
|
||||
width( p_width),
|
||||
height( p_height ),
|
||||
colours( p_colours ),
|
||||
subpixelorder( p_subpixelorder ),
|
||||
brightness( p_brightness ),
|
||||
hue( p_hue ),
|
||||
colour( p_colour ),
|
||||
contrast( p_contrast ),
|
||||
capture( p_capture ),
|
||||
record_audio( p_record_audio )
|
||||
{
|
||||
pixels = width * height;
|
||||
imagesize = pixels * colours;
|
||||
|
||||
Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",id,width,height,colours,subpixelorder,capture);
|
||||
Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",monitor_id,width,height,colours,subpixelorder,capture);
|
||||
|
||||
/* Because many loops are unrolled and work on 16 colours/time or 4 pixels/time, we have to meet requirements */
|
||||
if((colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB32) && (imagesize % 16) != 0) {
|
||||
Fatal("Image size is not multiples of 16");
|
||||
} else if(colours == ZM_COLOUR_RGB24 && ((imagesize % 16) != 0 || (imagesize % 12) != 0)) {
|
||||
Fatal("Image size is not multiples of 12 and 16");
|
||||
if((colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB32) && (imagesize % 64) != 0) {
|
||||
Fatal("Image size is not multiples of 64");
|
||||
} else if(colours == ZM_COLOUR_RGB24 && ((imagesize % 64) != 0 || (imagesize % 12) != 0)) {
|
||||
Fatal("Image size is not multiples of 12 and 64");
|
||||
}
|
||||
}
|
||||
|
||||
Camera::~Camera()
|
||||
{
|
||||
Camera::~Camera() {
|
||||
}
|
||||
|
||||
Monitor *Camera::getMonitor() {
|
||||
if ( ! monitor )
|
||||
monitor = Monitor::Load( monitor_id, false, Monitor::QUERY );
|
||||
return monitor;
|
||||
}
|
||||
|
||||
void Camera::setMonitor( Monitor *p_monitor ) {
|
||||
monitor = p_monitor;
|
||||
monitor_id = monitor->Id();
|
||||
}
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
|
||||
#include "zm_image.h"
|
||||
|
||||
class Camera;
|
||||
|
||||
#include "zm_monitor.h"
|
||||
|
||||
//
|
||||
// Abstract base class for cameras. This is intended just to express
|
||||
// common attributes
|
||||
|
@ -34,7 +38,8 @@ class Camera
|
|||
protected:
|
||||
typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC, CURL_SRC } SourceType;
|
||||
|
||||
int id;
|
||||
unsigned int monitor_id;
|
||||
Monitor * monitor; // Null on instantiation, set as soon as possible.
|
||||
SourceType type;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
|
@ -42,17 +47,20 @@ protected:
|
|||
unsigned int subpixelorder;
|
||||
unsigned int pixels;
|
||||
unsigned int imagesize;
|
||||
int brightness;
|
||||
int hue;
|
||||
int colour;
|
||||
int contrast;
|
||||
bool capture;
|
||||
int brightness;
|
||||
int hue;
|
||||
int colour;
|
||||
int contrast;
|
||||
bool capture;
|
||||
bool record_audio;
|
||||
|
||||
public:
|
||||
Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture );
|
||||
Camera( unsigned int p_monitor_id, SourceType p_type, unsigned int p_width, unsigned int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio );
|
||||
virtual ~Camera();
|
||||
|
||||
int getId() const { return( id ); }
|
||||
unsigned int getId() const { return( monitor_id ); }
|
||||
Monitor *getMonitor();
|
||||
void setMonitor( Monitor *p_monitor );
|
||||
SourceType Type() const { return( type ); }
|
||||
bool IsLocal() const { return( type == LOCAL_SRC ); }
|
||||
bool IsRemote() const { return( type == REMOTE_SRC ); }
|
||||
|
@ -73,11 +81,14 @@ public:
|
|||
virtual int Contrast( int/*p_contrast*/=-1 ) { return( -1 ); }
|
||||
|
||||
bool CanCapture() const { return( capture ); }
|
||||
|
||||
|
||||
bool SupportsNativeVideo() const { return( (type == FFMPEG_SRC )||(type == REMOTE_SRC)); }
|
||||
|
||||
virtual int PrimeCapture() { return( 0 ); }
|
||||
virtual int PreCapture()=0;
|
||||
virtual int Capture( Image &image )=0;
|
||||
virtual int PostCapture()=0;
|
||||
virtual int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) = 0;
|
||||
};
|
||||
|
||||
#endif // ZM_CAMERA_H
|
||||
|
|
|
@ -27,16 +27,13 @@
|
|||
|
||||
#include "zm_utils.h"
|
||||
|
||||
void zmLoadConfig()
|
||||
{
|
||||
void zmLoadConfig() {
|
||||
FILE *cfg;
|
||||
char line[512];
|
||||
if ( (cfg = fopen( ZM_CONFIG, "r")) == NULL )
|
||||
{
|
||||
if ( (cfg = fopen( ZM_CONFIG, "r")) == NULL ) {
|
||||
Fatal( "Can't open %s: %s", ZM_CONFIG, strerror(errno) );
|
||||
}
|
||||
while ( fgets( line, sizeof(line), cfg ) != NULL )
|
||||
{
|
||||
while ( fgets( line, sizeof(line), cfg ) != NULL ) {
|
||||
char *line_ptr = line;
|
||||
|
||||
// Trim off any cr/lf line endings
|
||||
|
@ -53,16 +50,14 @@ void zmLoadConfig()
|
|||
|
||||
// Remove trailing white space
|
||||
char *temp_ptr = line_ptr+strlen(line_ptr)-1;
|
||||
while ( *temp_ptr == ' ' || *temp_ptr == '\t' )
|
||||
{
|
||||
while ( *temp_ptr == ' ' || *temp_ptr == '\t' ) {
|
||||
*temp_ptr-- = '\0';
|
||||
temp_ptr--;
|
||||
}
|
||||
|
||||
// Now look for the '=' in the middle of the line
|
||||
temp_ptr = strchr( line_ptr, '=' );
|
||||
if ( !temp_ptr )
|
||||
{
|
||||
if ( !temp_ptr ) {
|
||||
Warning( "Invalid data in %s: '%s'", ZM_CONFIG, line );
|
||||
continue;
|
||||
}
|
||||
|
@ -72,12 +67,10 @@ void zmLoadConfig()
|
|||
char *val_ptr = temp_ptr+1;
|
||||
|
||||
// Trim trailing space from the name part
|
||||
do
|
||||
{
|
||||
do {
|
||||
*temp_ptr = '\0';
|
||||
temp_ptr--;
|
||||
}
|
||||
while ( *temp_ptr == ' ' || *temp_ptr == '\t' );
|
||||
} while ( *temp_ptr == ' ' || *temp_ptr == '\t' );
|
||||
|
||||
// Remove leading white space from the value part
|
||||
white_len = strspn( val_ptr, " \t" );
|
||||
|
@ -99,8 +92,7 @@ void zmLoadConfig()
|
|||
staticConfig.SERVER_NAME = std::string(val_ptr);
|
||||
else if ( strcasecmp( name_ptr, "ZM_SERVER_ID" ) == 0 )
|
||||
staticConfig.SERVER_ID = atoi(val_ptr);
|
||||
else
|
||||
{
|
||||
else {
|
||||
// We ignore this now as there may be more parameters than the
|
||||
// c/c++ binaries are bothered about
|
||||
// Warning( "Invalid parameter '%s' in %s", name_ptr, ZM_CONFIG );
|
||||
|
@ -143,8 +135,7 @@ void zmLoadConfig()
|
|||
|
||||
StaticConfig staticConfig;
|
||||
|
||||
ConfigItem::ConfigItem( const char *p_name, const char *p_value, const char *const p_type )
|
||||
{
|
||||
ConfigItem::ConfigItem( const char *p_name, const char *p_value, const char *const p_type ) {
|
||||
name = new char[strlen(p_name)+1];
|
||||
strcpy( name, p_name );
|
||||
value = new char[strlen(p_value)+1];
|
||||
|
@ -157,50 +148,37 @@ ConfigItem::ConfigItem( const char *p_name, const char *p_value, const char *con
|
|||
accessed = false;
|
||||
}
|
||||
|
||||
ConfigItem::~ConfigItem()
|
||||
{
|
||||
ConfigItem::~ConfigItem() {
|
||||
delete[] name;
|
||||
delete[] value;
|
||||
delete[] type;
|
||||
}
|
||||
|
||||
void ConfigItem::ConvertValue() const
|
||||
{
|
||||
if ( !strcmp( type, "boolean" ) )
|
||||
{
|
||||
void ConfigItem::ConvertValue() const {
|
||||
if ( !strcmp( type, "boolean" ) ) {
|
||||
cfg_type = CFG_BOOLEAN;
|
||||
cfg_value.boolean_value = (bool)strtol( value, 0, 0 );
|
||||
}
|
||||
else if ( !strcmp( type, "integer" ) )
|
||||
{
|
||||
} else if ( !strcmp( type, "integer" ) ) {
|
||||
cfg_type = CFG_INTEGER;
|
||||
cfg_value.integer_value = strtol( value, 0, 10 );
|
||||
}
|
||||
else if ( !strcmp( type, "hexadecimal" ) )
|
||||
{
|
||||
} else if ( !strcmp( type, "hexadecimal" ) ) {
|
||||
cfg_type = CFG_INTEGER;
|
||||
cfg_value.integer_value = strtol( value, 0, 16 );
|
||||
}
|
||||
else if ( !strcmp( type, "decimal" ) )
|
||||
{
|
||||
} else if ( !strcmp( type, "decimal" ) ) {
|
||||
cfg_type = CFG_DECIMAL;
|
||||
cfg_value.decimal_value = strtod( value, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
cfg_type = CFG_STRING;
|
||||
cfg_value.string_value = value;
|
||||
}
|
||||
accessed = true;
|
||||
}
|
||||
|
||||
bool ConfigItem::BooleanValue() const
|
||||
{
|
||||
bool ConfigItem::BooleanValue() const {
|
||||
if ( !accessed )
|
||||
ConvertValue();
|
||||
|
||||
if ( cfg_type != CFG_BOOLEAN )
|
||||
{
|
||||
if ( cfg_type != CFG_BOOLEAN ) {
|
||||
Error( "Attempt to fetch boolean value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
||||
exit( -1 );
|
||||
}
|
||||
|
@ -208,13 +186,11 @@ bool ConfigItem::BooleanValue() const
|
|||
return( cfg_value.boolean_value );
|
||||
}
|
||||
|
||||
int ConfigItem::IntegerValue() const
|
||||
{
|
||||
int ConfigItem::IntegerValue() const {
|
||||
if ( !accessed )
|
||||
ConvertValue();
|
||||
|
||||
if ( cfg_type != CFG_INTEGER )
|
||||
{
|
||||
if ( cfg_type != CFG_INTEGER ) {
|
||||
Error( "Attempt to fetch integer value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
||||
exit( -1 );
|
||||
}
|
||||
|
@ -222,13 +198,11 @@ int ConfigItem::IntegerValue() const
|
|||
return( cfg_value.integer_value );
|
||||
}
|
||||
|
||||
double ConfigItem::DecimalValue() const
|
||||
{
|
||||
double ConfigItem::DecimalValue() const {
|
||||
if ( !accessed )
|
||||
ConvertValue();
|
||||
|
||||
if ( cfg_type != CFG_DECIMAL )
|
||||
{
|
||||
if ( cfg_type != CFG_DECIMAL ) {
|
||||
Error( "Attempt to fetch decimal value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
||||
exit( -1 );
|
||||
}
|
||||
|
@ -236,13 +210,11 @@ double ConfigItem::DecimalValue() const
|
|||
return( cfg_value.decimal_value );
|
||||
}
|
||||
|
||||
const char *ConfigItem::StringValue() const
|
||||
{
|
||||
const char *ConfigItem::StringValue() const {
|
||||
if ( !accessed )
|
||||
ConvertValue();
|
||||
|
||||
if ( cfg_type != CFG_STRING )
|
||||
{
|
||||
if ( cfg_type != CFG_STRING ) {
|
||||
Error( "Attempt to fetch string value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
||||
exit( -1 );
|
||||
}
|
||||
|
@ -250,80 +222,66 @@ const char *ConfigItem::StringValue() const
|
|||
return( cfg_value.string_value );
|
||||
}
|
||||
|
||||
Config::Config()
|
||||
{
|
||||
Config::Config() {
|
||||
n_items = 0;
|
||||
items = 0;
|
||||
}
|
||||
|
||||
Config::~Config()
|
||||
{
|
||||
if ( items )
|
||||
{
|
||||
for ( int i = 0; i < n_items; i++ )
|
||||
{
|
||||
Config::~Config() {
|
||||
if ( items ) {
|
||||
for ( int i = 0; i < n_items; i++ ) {
|
||||
delete items[i];
|
||||
}
|
||||
delete[] items;
|
||||
}
|
||||
}
|
||||
|
||||
void Config::Load()
|
||||
{
|
||||
void Config::Load() {
|
||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||
|
||||
strncpy( sql, "select Name, Value, Type from Config order by Id", sizeof(sql) );
|
||||
if ( mysql_query( &dbconn, sql ) )
|
||||
{
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
|
||||
MYSQL_RES *result = mysql_store_result( &dbconn );
|
||||
if ( !result )
|
||||
{
|
||||
if ( !result ) {
|
||||
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
n_items = mysql_num_rows( result );
|
||||
|
||||
if ( n_items <= ZM_MAX_CFG_ID )
|
||||
{
|
||||
if ( n_items <= ZM_MAX_CFG_ID ) {
|
||||
Error( "Config mismatch, expected %d items, read %d. Try running 'zmupdate.pl -f' to reload config.", ZM_MAX_CFG_ID+1, n_items );
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
items = new ConfigItem *[n_items];
|
||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ )
|
||||
{
|
||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) {
|
||||
items[i] = new ConfigItem( dbrow[0], dbrow[1], dbrow[2] );
|
||||
}
|
||||
mysql_free_result( result );
|
||||
}
|
||||
|
||||
void Config::Assign()
|
||||
{
|
||||
void Config::Assign() {
|
||||
ZM_CFG_ASSIGN_LIST
|
||||
}
|
||||
|
||||
const ConfigItem &Config::Item( int id )
|
||||
{
|
||||
if ( !n_items )
|
||||
{
|
||||
const ConfigItem &Config::Item( int id ) {
|
||||
if ( !n_items ) {
|
||||
Load();
|
||||
Assign();
|
||||
}
|
||||
|
||||
if ( id < 0 || id > ZM_MAX_CFG_ID )
|
||||
{
|
||||
if ( id < 0 || id > ZM_MAX_CFG_ID ) {
|
||||
Error( "Attempt to access invalid config, id = %d. Try running 'zmupdate.pl -f' to reload config.", id );
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
ConfigItem *item = items[id];
|
||||
|
||||
if ( !item )
|
||||
{
|
||||
if ( !item ) {
|
||||
Error( "Can't find config item %d", id );
|
||||
exit( -1 );
|
||||
}
|
||||
|
|
|
@ -18,8 +18,11 @@
|
|||
//
|
||||
|
||||
#include "zm.h"
|
||||
|
||||
#include "zm_curl_camera.h"
|
||||
|
||||
#include "zm_packetqueue.h"
|
||||
|
||||
#if HAVE_LIBCURL
|
||||
|
||||
#define CURL_MAXRETRY 5
|
||||
|
@ -30,28 +33,24 @@ const char* content_type_match = "Content-Type:";
|
|||
size_t content_length_match_len;
|
||||
size_t content_type_match_len;
|
||||
|
||||
cURLCamera::cURLCamera( int p_id, const std::string &p_path, const std::string &p_user, const std::string &p_pass, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) :
|
||||
Camera( p_id, CURL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ),
|
||||
cURLCamera::cURLCamera( int p_id, const std::string &p_path, const std::string &p_user, const std::string &p_pass, unsigned int p_width, unsigned int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) :
|
||||
Camera( p_id, CURL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ),
|
||||
mPath( p_path ), mUser( p_user ), mPass ( p_pass ), bTerminate( false ), bReset( false ), mode ( MODE_UNSET )
|
||||
{
|
||||
|
||||
if ( capture )
|
||||
{
|
||||
if ( capture ) {
|
||||
Initialise();
|
||||
}
|
||||
}
|
||||
|
||||
cURLCamera::~cURLCamera()
|
||||
{
|
||||
if ( capture )
|
||||
{
|
||||
cURLCamera::~cURLCamera() {
|
||||
if ( capture ) {
|
||||
|
||||
Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void cURLCamera::Initialise()
|
||||
{
|
||||
void cURLCamera::Initialise() {
|
||||
content_length_match_len = strlen(content_length_match);
|
||||
content_type_match_len = strlen(content_type_match);
|
||||
|
||||
|
@ -88,8 +87,7 @@ void cURLCamera::Initialise()
|
|||
}
|
||||
}
|
||||
|
||||
void cURLCamera::Terminate()
|
||||
{
|
||||
void cURLCamera::Terminate() {
|
||||
/* Signal the thread to terminate */
|
||||
bTerminate = true;
|
||||
|
||||
|
@ -108,20 +106,17 @@ void cURLCamera::Terminate()
|
|||
|
||||
}
|
||||
|
||||
int cURLCamera::PrimeCapture()
|
||||
{
|
||||
int cURLCamera::PrimeCapture() {
|
||||
//Info( "Priming capture from %s", mPath.c_str() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cURLCamera::PreCapture()
|
||||
{
|
||||
// Nothing to do here
|
||||
return( 0 );
|
||||
int cURLCamera::PreCapture() {
|
||||
// Nothing to do here
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int cURLCamera::Capture( Image &image )
|
||||
{
|
||||
int cURLCamera::Capture( Image &image ) {
|
||||
bool frameComplete = false;
|
||||
|
||||
/* MODE_STREAM specific variables */
|
||||
|
@ -305,14 +300,18 @@ int cURLCamera::Capture( Image &image )
|
|||
return 0;
|
||||
}
|
||||
|
||||
int cURLCamera::PostCapture()
|
||||
{
|
||||
int cURLCamera::PostCapture() {
|
||||
// Nothing to do here
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int cURLCamera::CaptureAndRecord( Image &image, struct timeval recording, char* event_directory ) {
|
||||
Error("Capture and Record not implemented for the cURL camera type");
|
||||
// Nothing to do here
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
size_t cURLCamera::data_callback(void *buffer, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
size_t cURLCamera::data_callback(void *buffer, size_t size, size_t nmemb, void *userdata) {
|
||||
lock();
|
||||
|
||||
/* Append the data we just received to our buffer */
|
||||
|
@ -331,10 +330,7 @@ size_t cURLCamera::data_callback(void *buffer, size_t size, size_t nmemb, void *
|
|||
return size*nmemb;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t cURLCamera::header_callback( void *buffer, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
size_t cURLCamera::header_callback( void *buffer, size_t size, size_t nmemb, void *userdata) {
|
||||
std::string header;
|
||||
header.assign((const char*)buffer, size*nmemb);
|
||||
|
||||
|
@ -374,8 +370,7 @@ size_t cURLCamera::header_callback( void *buffer, size_t size, size_t nmemb, voi
|
|||
return size*nmemb;
|
||||
}
|
||||
|
||||
void* cURLCamera::thread_func()
|
||||
{
|
||||
void* cURLCamera::thread_func() {
|
||||
long tRet;
|
||||
double dSize;
|
||||
|
||||
|
@ -521,8 +516,7 @@ int cURLCamera::unlock() {
|
|||
return nRet;
|
||||
}
|
||||
|
||||
int cURLCamera::progress_callback(void *userdata, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||
{
|
||||
int cURLCamera::progress_callback(void *userdata, double dltotal, double dlnow, double ultotal, double ulnow) {
|
||||
/* Signal the curl thread to terminate */
|
||||
if(bTerminate)
|
||||
return -10;
|
||||
|
@ -531,18 +525,15 @@ int cURLCamera::progress_callback(void *userdata, double dltotal, double dlnow,
|
|||
}
|
||||
|
||||
/* These functions call the functions in the class for the correct object */
|
||||
size_t data_callback_dispatcher(void *buffer, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
size_t data_callback_dispatcher(void *buffer, size_t size, size_t nmemb, void *userdata) {
|
||||
return ((cURLCamera*)userdata)->data_callback(buffer,size,nmemb,userdata);
|
||||
}
|
||||
|
||||
size_t header_callback_dispatcher(void *buffer, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
size_t header_callback_dispatcher(void *buffer, size_t size, size_t nmemb, void *userdata) {
|
||||
return ((cURLCamera*)userdata)->header_callback(buffer,size,nmemb,userdata);
|
||||
}
|
||||
|
||||
int progress_callback_dispatcher(void *userdata, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||
{
|
||||
int progress_callback_dispatcher(void *userdata, double dltotal, double dlnow, double ultotal, double ulnow) {
|
||||
return ((cURLCamera*)userdata)->progress_callback(userdata,dltotal,dlnow,ultotal,ulnow);
|
||||
}
|
||||
|
||||
|
@ -550,6 +541,4 @@ void* thread_func_dispatcher(void* object) {
|
|||
return ((cURLCamera*)object)->thread_func();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // HAVE_LIBCURL
|
||||
|
|
|
@ -39,8 +39,7 @@
|
|||
// Class representing 'curl' cameras, i.e. those which are
|
||||
// accessed using the curl library
|
||||
//
|
||||
class cURLCamera : public Camera
|
||||
{
|
||||
class cURLCamera : public Camera {
|
||||
protected:
|
||||
typedef enum {MODE_UNSET, MODE_SINGLE, MODE_STREAM} mode_t;
|
||||
|
||||
|
@ -65,7 +64,7 @@ protected:
|
|||
pthread_cond_t request_complete_cond;
|
||||
|
||||
public:
|
||||
cURLCamera( int p_id, const std::string &path, const std::string &username, const std::string &password, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture );
|
||||
cURLCamera( int p_id, const std::string &path, const std::string &username, const std::string &password, unsigned int p_width, unsigned int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio );
|
||||
~cURLCamera();
|
||||
|
||||
const std::string &Path() const { return( mPath ); }
|
||||
|
@ -79,6 +78,7 @@ public:
|
|||
int PreCapture();
|
||||
int Capture( Image &image );
|
||||
int PostCapture();
|
||||
int CaptureAndRecord( Image &image, struct timeval recording, char* event_directory );
|
||||
|
||||
size_t data_callback(void *buffer, size_t size, size_t nmemb, void *userdata);
|
||||
size_t header_callback(void *buffer, size_t size, size_t nmemb, void *userdata);
|
||||
|
|
1221
src/zm_event.cpp
1221
src/zm_event.cpp
File diff suppressed because it is too large
Load Diff
|
@ -37,6 +37,7 @@
|
|||
#include "zm.h"
|
||||
#include "zm_image.h"
|
||||
#include "zm_stream.h"
|
||||
#include "zm_video.h"
|
||||
|
||||
class Zone;
|
||||
class Monitor;
|
||||
|
@ -46,8 +47,7 @@ class Monitor;
|
|||
//
|
||||
// Class describing events, i.e. captured periods of activity.
|
||||
//
|
||||
class Event
|
||||
{
|
||||
class Event {
|
||||
friend class EventStream;
|
||||
|
||||
protected:
|
||||
|
@ -55,6 +55,7 @@ protected:
|
|||
static char capture_file_format[PATH_MAX];
|
||||
static char analyse_file_format[PATH_MAX];
|
||||
static char general_file_format[PATH_MAX];
|
||||
static char video_file_format[PATH_MAX];
|
||||
|
||||
protected:
|
||||
static int sd;
|
||||
|
@ -66,8 +67,7 @@ public:
|
|||
protected:
|
||||
typedef enum { NORMAL, BULK, ALARM } FrameType;
|
||||
|
||||
struct PreAlarmData
|
||||
{
|
||||
struct PreAlarmData {
|
||||
Image *image;
|
||||
struct timeval timestamp;
|
||||
unsigned int score;
|
||||
|
@ -84,24 +84,31 @@ protected:
|
|||
struct timeval end_time;
|
||||
std::string cause;
|
||||
StringSetMap noteSetMap;
|
||||
bool videoEvent;
|
||||
int frames;
|
||||
int alarm_frames;
|
||||
unsigned int tot_score;
|
||||
unsigned int max_score;
|
||||
char path[PATH_MAX];
|
||||
VideoWriter* videowriter;
|
||||
FILE* timecodes_fd;
|
||||
char video_name[PATH_MAX];
|
||||
char video_file[PATH_MAX];
|
||||
char timecodes_name[PATH_MAX];
|
||||
char timecodes_file[PATH_MAX];
|
||||
|
||||
protected:
|
||||
int last_db_frame;
|
||||
|
||||
protected:
|
||||
static void Initialise()
|
||||
{
|
||||
static void Initialise() {
|
||||
if ( initialised )
|
||||
return;
|
||||
|
||||
snprintf( capture_file_format, sizeof(capture_file_format), "%%s/%%0%dd-capture.jpg", config.event_image_digits );
|
||||
snprintf( analyse_file_format, sizeof(analyse_file_format), "%%s/%%0%dd-analyse.jpg", config.event_image_digits );
|
||||
snprintf( general_file_format, sizeof(general_file_format), "%%s/%%0%dd-%%s", config.event_image_digits );
|
||||
snprintf( video_file_format, sizeof(video_file_format), "%%s/%%s");
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
|
@ -113,7 +120,7 @@ public:
|
|||
static bool ValidateFrameSocket( int );
|
||||
|
||||
public:
|
||||
Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap );
|
||||
Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent=false );
|
||||
~Event();
|
||||
|
||||
int Id() const { return( id ); }
|
||||
|
@ -127,6 +134,7 @@ public:
|
|||
|
||||
bool SendFrameImage( const Image *image, bool alarm_frame=false );
|
||||
bool WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame=false );
|
||||
bool WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow );
|
||||
|
||||
void updateNotes( const StringSetMap &stringSetMap );
|
||||
|
||||
|
@ -137,28 +145,26 @@ private:
|
|||
void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps );
|
||||
|
||||
public:
|
||||
static const char *getSubPath( struct tm *time )
|
||||
{
|
||||
static const char *getSubPath( struct tm *time ) {
|
||||
static char subpath[PATH_MAX] = "";
|
||||
snprintf( subpath, sizeof(subpath), "%02d/%02d/%02d/%02d/%02d/%02d", time->tm_year-100, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec );
|
||||
return( subpath );
|
||||
}
|
||||
static const char *getSubPath( time_t *time )
|
||||
{
|
||||
static const char *getSubPath( time_t *time ) {
|
||||
return( Event::getSubPath( localtime( time ) ) );
|
||||
}
|
||||
|
||||
char* getEventFile(void) {
|
||||
return video_file;
|
||||
}
|
||||
|
||||
public:
|
||||
static int PreAlarmCount()
|
||||
{
|
||||
static int PreAlarmCount() {
|
||||
return( pre_alarm_count );
|
||||
}
|
||||
static void EmptyPreAlarmFrames()
|
||||
{
|
||||
if ( pre_alarm_count > 0 )
|
||||
{
|
||||
for ( int i = 0; i < MAX_PRE_ALARM_FRAMES; i++ )
|
||||
{
|
||||
static void EmptyPreAlarmFrames() {
|
||||
if ( pre_alarm_count > 0 ) {
|
||||
for ( int i = 0; i < MAX_PRE_ALARM_FRAMES; i++ ) {
|
||||
delete pre_alarm_data[i].image;
|
||||
delete pre_alarm_data[i].alarm_frame;
|
||||
}
|
||||
|
@ -166,29 +172,24 @@ public:
|
|||
}
|
||||
pre_alarm_count = 0;
|
||||
}
|
||||
static void AddPreAlarmFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL )
|
||||
{
|
||||
static void AddPreAlarmFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ) {
|
||||
pre_alarm_data[pre_alarm_count].image = new Image( *image );
|
||||
pre_alarm_data[pre_alarm_count].timestamp = timestamp;
|
||||
pre_alarm_data[pre_alarm_count].score = score;
|
||||
if ( alarm_frame )
|
||||
{
|
||||
if ( alarm_frame ) {
|
||||
pre_alarm_data[pre_alarm_count].alarm_frame = new Image( *alarm_frame );
|
||||
}
|
||||
pre_alarm_count++;
|
||||
}
|
||||
void SavePreAlarmFrames()
|
||||
{
|
||||
for ( int i = 0; i < pre_alarm_count; i++ )
|
||||
{
|
||||
void SavePreAlarmFrames() {
|
||||
for ( int i = 0; i < pre_alarm_count; i++ ) {
|
||||
AddFrame( pre_alarm_data[i].image, pre_alarm_data[i].timestamp, pre_alarm_data[i].score, pre_alarm_data[i].alarm_frame );
|
||||
}
|
||||
EmptyPreAlarmFrames();
|
||||
}
|
||||
};
|
||||
|
||||
class EventStream : public StreamBase
|
||||
{
|
||||
class EventStream : public StreamBase {
|
||||
public:
|
||||
typedef enum { MODE_SINGLE, MODE_ALL, MODE_ALL_GAPLESS } StreamMode;
|
||||
|
||||
|
@ -201,16 +202,16 @@ protected:
|
|||
bool in_db;
|
||||
};
|
||||
|
||||
struct EventData
|
||||
{
|
||||
struct EventData {
|
||||
unsigned long event_id;
|
||||
unsigned long monitor_id;
|
||||
unsigned long frame_count;
|
||||
time_t start_time;
|
||||
double duration;
|
||||
char path[PATH_MAX];
|
||||
int n_frames;
|
||||
FrameData *frames;
|
||||
time_t start_time;
|
||||
double duration;
|
||||
char path[PATH_MAX];
|
||||
int n_frames;
|
||||
FrameData *frames;
|
||||
char video_file[PATH_MAX];
|
||||
};
|
||||
|
||||
protected:
|
||||
|
@ -238,8 +239,7 @@ protected:
|
|||
bool sendFrame( int delta_us );
|
||||
|
||||
public:
|
||||
EventStream()
|
||||
{
|
||||
EventStream() {
|
||||
mode = DEFAULT_MODE;
|
||||
|
||||
forceEventChange = false;
|
||||
|
@ -249,18 +249,15 @@ public:
|
|||
|
||||
event_data = 0;
|
||||
}
|
||||
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 )
|
||||
{
|
||||
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) {
|
||||
loadInitialEventData( init_event_id, init_frame_id );
|
||||
loadMonitor( event_data->monitor_id );
|
||||
}
|
||||
void setStreamStart( int monitor_id, time_t event_time )
|
||||
{
|
||||
void setStreamStart( int monitor_id, time_t event_time ) {
|
||||
loadInitialEventData( monitor_id, event_time );
|
||||
loadMonitor( monitor_id );
|
||||
}
|
||||
void setStreamMode( StreamMode p_mode )
|
||||
{
|
||||
void setStreamMode( StreamMode p_mode ) {
|
||||
mode = p_mode;
|
||||
}
|
||||
void runStream();
|
||||
|
|
|
@ -23,6 +23,16 @@
|
|||
|
||||
#if HAVE_LIBAVCODEC || HAVE_LIBAVUTIL || HAVE_LIBSWSCALE
|
||||
|
||||
void FFMPEGInit() {
|
||||
static bool bInit = false;
|
||||
|
||||
if(!bInit) {
|
||||
av_register_all();
|
||||
av_log_set_level(AV_LOG_DEBUG);
|
||||
bInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_LIBAVUTIL
|
||||
enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder) {
|
||||
enum _AVPIXELFORMAT pf;
|
||||
|
@ -31,40 +41,40 @@ enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subp
|
|||
|
||||
switch(p_colours) {
|
||||
case ZM_COLOUR_RGB24:
|
||||
{
|
||||
if(p_subpixelorder == ZM_SUBPIX_ORDER_BGR) {
|
||||
/* BGR subpixel order */
|
||||
pf = AV_PIX_FMT_BGR24;
|
||||
} else {
|
||||
/* Assume RGB subpixel order */
|
||||
pf = AV_PIX_FMT_RGB24;
|
||||
}
|
||||
break;
|
||||
}
|
||||
{
|
||||
if(p_subpixelorder == ZM_SUBPIX_ORDER_BGR) {
|
||||
/* BGR subpixel order */
|
||||
pf = AV_PIX_FMT_BGR24;
|
||||
} else {
|
||||
/* Assume RGB subpixel order */
|
||||
pf = AV_PIX_FMT_RGB24;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ZM_COLOUR_RGB32:
|
||||
{
|
||||
if(p_subpixelorder == ZM_SUBPIX_ORDER_ARGB) {
|
||||
/* ARGB subpixel order */
|
||||
pf = AV_PIX_FMT_ARGB;
|
||||
} else if(p_subpixelorder == ZM_SUBPIX_ORDER_ABGR) {
|
||||
/* ABGR subpixel order */
|
||||
pf = AV_PIX_FMT_ABGR;
|
||||
} else if(p_subpixelorder == ZM_SUBPIX_ORDER_BGRA) {
|
||||
/* BGRA subpixel order */
|
||||
pf = AV_PIX_FMT_BGRA;
|
||||
} else {
|
||||
/* Assume RGBA subpixel order */
|
||||
pf = AV_PIX_FMT_RGBA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
{
|
||||
if(p_subpixelorder == ZM_SUBPIX_ORDER_ARGB) {
|
||||
/* ARGB subpixel order */
|
||||
pf = AV_PIX_FMT_ARGB;
|
||||
} else if(p_subpixelorder == ZM_SUBPIX_ORDER_ABGR) {
|
||||
/* ABGR subpixel order */
|
||||
pf = AV_PIX_FMT_ABGR;
|
||||
} else if(p_subpixelorder == ZM_SUBPIX_ORDER_BGRA) {
|
||||
/* BGRA subpixel order */
|
||||
pf = AV_PIX_FMT_BGRA;
|
||||
} else {
|
||||
/* Assume RGBA subpixel order */
|
||||
pf = AV_PIX_FMT_RGBA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ZM_COLOUR_GRAY8:
|
||||
pf = AV_PIX_FMT_GRAY8;
|
||||
break;
|
||||
pf = AV_PIX_FMT_GRAY8;
|
||||
break;
|
||||
default:
|
||||
Panic("Unexpected colours: %d",p_colours);
|
||||
pf = AV_PIX_FMT_GRAY8; /* Just to shush gcc variable may be unused warning */
|
||||
break;
|
||||
Panic("Unexpected colours: %d",p_colours);
|
||||
pf = AV_PIX_FMT_GRAY8; /* Just to shush gcc variable may be unused warning */
|
||||
break;
|
||||
}
|
||||
|
||||
return pf;
|
||||
|
@ -148,25 +158,17 @@ SWScale::SWScale() : gotdefaults(false), swscale_ctx(NULL), input_avframe(NULL),
|
|||
SWScale::~SWScale() {
|
||||
|
||||
/* Free up everything */
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
av_frame_free( &input_avframe );
|
||||
#else
|
||||
av_freep( &input_avframe );
|
||||
#endif
|
||||
//input_avframe = NULL;
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
av_frame_free( &output_avframe );
|
||||
#else
|
||||
av_freep( &output_avframe );
|
||||
#endif
|
||||
//output_avframe = NULL;
|
||||
|
||||
if(swscale_ctx) {
|
||||
sws_freeContext(swscale_ctx);
|
||||
swscale_ctx = NULL;
|
||||
}
|
||||
|
||||
|
||||
Debug(4,"SWScale object destroyed");
|
||||
}
|
||||
|
||||
|
@ -189,11 +191,11 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
|
|||
Error("NULL Input or output buffer");
|
||||
return -1;
|
||||
}
|
||||
if(in_pf == 0 || out_pf == 0) {
|
||||
Error("Invalid input or output pixel formats");
|
||||
return -2;
|
||||
}
|
||||
if(!width || !height) {
|
||||
// if(in_pf == 0 || out_pf == 0) {
|
||||
// Error("Invalid input or output pixel formats");
|
||||
// return -2;
|
||||
// }
|
||||
if (!width || !height) {
|
||||
Error("Invalid width or height");
|
||||
return -3;
|
||||
}
|
||||
|
@ -223,24 +225,37 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
|
|||
#else
|
||||
size_t outsize = avpicture_get_size(out_pf, width, height);
|
||||
#endif
|
||||
|
||||
if(outsize < out_buffer_size) {
|
||||
Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size);
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Get the context */
|
||||
swscale_ctx = sws_getCachedContext( NULL, width, height, in_pf, width, height, out_pf, 0, NULL, NULL, NULL );
|
||||
swscale_ctx = sws_getCachedContext( swscale_ctx, width, height, in_pf, width, height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL );
|
||||
if(swscale_ctx == NULL) {
|
||||
Error("Failed getting swscale context");
|
||||
return -6;
|
||||
}
|
||||
|
||||
/* Fill in the buffers */
|
||||
if(!avpicture_fill( (AVPicture*)input_avframe, (uint8_t*)in_buffer, in_pf, width, height ) ) {
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
if (av_image_fill_arrays(input_avframe->data, input_avframe->linesize,
|
||||
(uint8_t*) in_buffer, in_pf, width, height, 1) <= 0) {
|
||||
#else
|
||||
if (avpicture_fill((AVPicture*) input_avframe, (uint8_t*) in_buffer,
|
||||
in_pf, width, height) <= 0) {
|
||||
#endif
|
||||
Error("Failed filling input frame with input buffer");
|
||||
return -7;
|
||||
}
|
||||
if(!avpicture_fill( (AVPicture*)output_avframe, out_buffer, out_pf, width, height ) ) {
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize,
|
||||
out_buffer, out_pf, width, height, 1) <= 0) {
|
||||
#else
|
||||
if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, width,
|
||||
height) <= 0) {
|
||||
#endif
|
||||
Error("Failed filling output frame with output buffer");
|
||||
return -8;
|
||||
}
|
||||
|
@ -291,3 +306,206 @@ int SWScale::ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_si
|
|||
|
||||
|
||||
#endif // HAVE_LIBAVCODEC || HAVE_LIBAVUTIL || HAVE_LIBSWSCALE
|
||||
|
||||
#if HAVE_LIBAVUTIL
|
||||
int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){
|
||||
int64_t a, b, this_thing;
|
||||
|
||||
av_assert0(in_ts != AV_NOPTS_VALUE);
|
||||
av_assert0(duration >= 0);
|
||||
|
||||
if (*last == AV_NOPTS_VALUE || !duration || in_tb.num*(int64_t)out_tb.den <= out_tb.num*(int64_t)in_tb.den) {
|
||||
simple_round:
|
||||
*last = av_rescale_q(in_ts, in_tb, fs_tb) + duration;
|
||||
return av_rescale_q(in_ts, in_tb, out_tb);
|
||||
}
|
||||
|
||||
a = av_rescale_q_rnd(2*in_ts-1, in_tb, fs_tb, AV_ROUND_DOWN) >>1;
|
||||
b = (av_rescale_q_rnd(2*in_ts+1, in_tb, fs_tb, AV_ROUND_UP )+1)>>1;
|
||||
if (*last < 2*a - b || *last > 2*b - a)
|
||||
goto simple_round;
|
||||
|
||||
this_thing = av_clip64(*last, a, b);
|
||||
*last = this_thing + duration;
|
||||
|
||||
return av_rescale_q(this_thing, fs_tb, out_tb);
|
||||
}
|
||||
#endif
|
||||
|
||||
int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat *oformat, const char *format, const char *filename) {
|
||||
AVFormatContext *s = avformat_alloc_context();
|
||||
int ret = 0;
|
||||
|
||||
*avctx = NULL;
|
||||
if (!s) {
|
||||
av_log(s, AV_LOG_ERROR, "Out of memory\n");
|
||||
ret = AVERROR(ENOMEM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!oformat) {
|
||||
if (format) {
|
||||
oformat = av_guess_format(format, NULL, NULL);
|
||||
if (!oformat) {
|
||||
av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);
|
||||
ret = AVERROR(EINVAL);
|
||||
}
|
||||
} else {
|
||||
oformat = av_guess_format(NULL, filename, NULL);
|
||||
if (!oformat) {
|
||||
ret = AVERROR(EINVAL);
|
||||
av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n", filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!oformat) {
|
||||
if (format) {
|
||||
oformat = av_guess_format(format, NULL, NULL);
|
||||
if (!oformat) {
|
||||
av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);
|
||||
ret = AVERROR(EINVAL);
|
||||
}
|
||||
} else {
|
||||
oformat = av_guess_format(NULL, filename, NULL);
|
||||
if (!oformat) {
|
||||
ret = AVERROR(EINVAL);
|
||||
av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n", filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
avformat_free_context(s);
|
||||
return ret;
|
||||
} else {
|
||||
s->oformat = oformat;
|
||||
if (s->oformat->priv_data_size > 0) {
|
||||
s->priv_data = av_mallocz(s->oformat->priv_data_size);
|
||||
if (s->priv_data) {
|
||||
if (s->oformat->priv_class) {
|
||||
*(const AVClass**)s->priv_data= s->oformat->priv_class;
|
||||
av_opt_set_defaults(s->priv_data);
|
||||
}
|
||||
} else {
|
||||
av_log(s, AV_LOG_ERROR, "Out of memory\n");
|
||||
ret = AVERROR(ENOMEM);
|
||||
return ret;
|
||||
}
|
||||
s->priv_data = NULL;
|
||||
}
|
||||
|
||||
if (filename) strncpy(s->filename, filename, sizeof(s->filename));
|
||||
*avctx = s;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void zm_log_fps(double d, const char *postfix) {
|
||||
uint64_t v = lrintf(d * 100);
|
||||
if (!v) {
|
||||
Debug(1, "%1.4f %s", d, postfix);
|
||||
} else if (v % 100) {
|
||||
Debug(1, "%3.2f %s", d, postfix);
|
||||
} else if (v % (100 * 1000)) {
|
||||
Debug(1, "%1.0f %s", d, postfix);
|
||||
} else
|
||||
Debug(1, "%1.0fk %s", d / 1000, postfix);
|
||||
}
|
||||
|
||||
/* "user interface" functions */
|
||||
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) {
|
||||
char buf[256];
|
||||
Debug(1, "Dumping stream index i(%d) index(%d)", i, index );
|
||||
int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
|
||||
AVStream *st = ic->streams[i];
|
||||
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
|
||||
|
||||
avcodec_string(buf, sizeof(buf), st->codec, is_output);
|
||||
Debug(1, " Stream #%d:%d", index, i);
|
||||
|
||||
/* the pid is an important information, so we display it */
|
||||
/* XXX: add a generic system */
|
||||
if (flags & AVFMT_SHOW_IDS)
|
||||
Debug(1, "[0x%x]", st->id);
|
||||
if (lang)
|
||||
Debug(1, "(%s)", lang->value);
|
||||
Debug(1, ", %d, %d/%d", st->codec_info_nb_frames, st->time_base.num, st->time_base.den);
|
||||
Debug(1, ": %s", buf);
|
||||
|
||||
if (st->sample_aspect_ratio.num && // default
|
||||
av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)) {
|
||||
AVRational display_aspect_ratio;
|
||||
av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
|
||||
st->codec->width * (int64_t)st->sample_aspect_ratio.num,
|
||||
st->codec->height * (int64_t)st->sample_aspect_ratio.den,
|
||||
1024 * 1024);
|
||||
Debug(1, ", SAR %d:%d DAR %d:%d",
|
||||
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
|
||||
display_aspect_ratio.num, display_aspect_ratio.den);
|
||||
}
|
||||
|
||||
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
int fps = st->avg_frame_rate.den && st->avg_frame_rate.num;
|
||||
int tbn = st->time_base.den && st->time_base.num;
|
||||
int tbc = st->codec->time_base.den && st->codec->time_base.num;
|
||||
|
||||
if (fps || tbn || tbc)
|
||||
Debug(3, "\n" );
|
||||
|
||||
if (fps)
|
||||
zm_log_fps(av_q2d(st->avg_frame_rate), tbn || tbc ? "fps, " : "fps");
|
||||
if (tbn)
|
||||
zm_log_fps(1 / av_q2d(st->time_base), tbc ? "stream tb numerator , " : "stream tb numerator");
|
||||
if (tbc)
|
||||
zm_log_fps(1 / av_q2d(st->codec->time_base), "codec time base:");
|
||||
}
|
||||
|
||||
if (st->disposition & AV_DISPOSITION_DEFAULT)
|
||||
Debug(1, " (default)");
|
||||
if (st->disposition & AV_DISPOSITION_DUB)
|
||||
Debug(1, " (dub)");
|
||||
if (st->disposition & AV_DISPOSITION_ORIGINAL)
|
||||
Debug(1, " (original)");
|
||||
if (st->disposition & AV_DISPOSITION_COMMENT)
|
||||
Debug(1, " (comment)");
|
||||
if (st->disposition & AV_DISPOSITION_LYRICS)
|
||||
Debug(1, " (lyrics)");
|
||||
if (st->disposition & AV_DISPOSITION_KARAOKE)
|
||||
Debug(1, " (karaoke)");
|
||||
if (st->disposition & AV_DISPOSITION_FORCED)
|
||||
Debug(1, " (forced)");
|
||||
if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
|
||||
Debug(1, " (hearing impaired)");
|
||||
if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
|
||||
Debug(1, " (visual impaired)");
|
||||
if (st->disposition & AV_DISPOSITION_CLEAN_EFFECTS)
|
||||
Debug(1, " (clean effects)");
|
||||
Debug(1, "\n");
|
||||
|
||||
//dump_metadata(NULL, st->metadata, " ");
|
||||
|
||||
//dump_sidedata(NULL, st, " ");
|
||||
}
|
||||
|
||||
int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt) {
|
||||
const enum AVSampleFormat *p = codec->sample_fmts;
|
||||
|
||||
while (*p != AV_SAMPLE_FMT_NONE) {
|
||||
if (*p == sample_fmt)
|
||||
return 1;
|
||||
else Debug(2, "Not %s", av_get_sample_fmt_name( *p ) );
|
||||
p++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
|
||||
#else
|
||||
unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src ) {
|
||||
dst->data = reinterpret_cast<uint8_t*>(new uint64_t[(src->size + FF_INPUT_BUFFER_PADDING_SIZE)/sizeof(uint64_t) + 1]);
|
||||
memcpy(dst->data, src->data, src->size );
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
224
src/zm_ffmpeg.h
224
src/zm_ffmpeg.h
|
@ -29,6 +29,7 @@ extern "C" {
|
|||
|
||||
// AVUTIL
|
||||
#if HAVE_LIBAVUTIL_AVUTIL_H
|
||||
#include "libavutil/avassert.h"
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavutil/base64.h>
|
||||
#include <libavutil/mathematics.h>
|
||||
|
@ -40,8 +41,8 @@ extern "C" {
|
|||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVUTIL_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBAVUTIL_VERSION_MICRO < 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
( (LIBAVUTIL_VERSION_MICRO < 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
|
||||
#if LIBAVUTIL_VERSION_CHECK(50, 29, 0, 29, 0)
|
||||
#include <libavutil/opt.h>
|
||||
|
@ -58,55 +59,55 @@ extern "C" {
|
|||
#include <ffmpeg/mathematics.h>
|
||||
#include <ffmpeg/opt.h>
|
||||
#endif /* HAVE_LIBAVUTIL_AVUTIL_H */
|
||||
|
||||
|
||||
#if defined(HAVE_LIBAVUTIL_AVUTIL_H)
|
||||
#if LIBAVUTIL_VERSION_CHECK(51, 42, 0, 74, 100)
|
||||
#define _AVPIXELFORMAT AVPixelFormat
|
||||
#define _AVPIXELFORMAT AVPixelFormat
|
||||
#else
|
||||
#define _AVPIXELFORMAT PixelFormat
|
||||
#define AV_PIX_FMT_NONE PIX_FMT_NONE
|
||||
#define AV_PIX_FMT_RGB444 PIX_FMT_RGB444
|
||||
#define AV_PIX_FMT_RGB555 PIX_FMT_RGB555
|
||||
#define AV_PIX_FMT_RGB565 PIX_FMT_RGB565
|
||||
#define AV_PIX_FMT_BGR24 PIX_FMT_BGR24
|
||||
#define AV_PIX_FMT_RGB24 PIX_FMT_RGB24
|
||||
#define AV_PIX_FMT_BGRA PIX_FMT_BGRA
|
||||
#define AV_PIX_FMT_ARGB PIX_FMT_ARGB
|
||||
#define AV_PIX_FMT_ABGR PIX_FMT_ABGR
|
||||
#define AV_PIX_FMT_RGBA PIX_FMT_RGBA
|
||||
#define AV_PIX_FMT_GRAY8 PIX_FMT_GRAY8
|
||||
#define AV_PIX_FMT_YUYV422 PIX_FMT_YUYV422
|
||||
#define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P
|
||||
#define AV_PIX_FMT_YUV411P PIX_FMT_YUV411P
|
||||
#define AV_PIX_FMT_YUV444P PIX_FMT_YUV444P
|
||||
#define AV_PIX_FMT_YUV410P PIX_FMT_YUV410P
|
||||
#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
|
||||
#define AV_PIX_FMT_YUVJ444P PIX_FMT_YUVJ444P
|
||||
#define AV_PIX_FMT_UYVY422 PIX_FMT_UYVY422
|
||||
#define AV_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P
|
||||
#define AV_PIX_FMT_YUVJ422P PIX_FMT_YUVJ422P
|
||||
#define AV_PIX_FMT_UYVY422 PIX_FMT_UYVY422
|
||||
#define AV_PIX_FMT_UYYVYY411 PIX_FMT_UYYVYY411
|
||||
#define AV_PIX_FMT_BGR565 PIX_FMT_BGR565
|
||||
#define AV_PIX_FMT_BGR555 PIX_FMT_BGR555
|
||||
#define AV_PIX_FMT_BGR8 PIX_FMT_BGR8
|
||||
#define AV_PIX_FMT_BGR4 PIX_FMT_BGR4
|
||||
#define AV_PIX_FMT_BGR4_BYTE PIX_FMT_BGR4_BYTE
|
||||
#define AV_PIX_FMT_RGB8 PIX_FMT_RGB8
|
||||
#define AV_PIX_FMT_RGB4 PIX_FMT_RGB4
|
||||
#define AV_PIX_FMT_RGB4_BYTE PIX_FMT_RGB4_BYTE
|
||||
#define AV_PIX_FMT_NV12 PIX_FMT_NV12
|
||||
#define AV_PIX_FMT_NV21 PIX_FMT_NV21
|
||||
#define AV_PIX_FMT_RGB32_1 PIX_FMT_RGB32_1
|
||||
#define AV_PIX_FMT_BGR32_1 PIX_FMT_BGR32_1
|
||||
#define AV_PIX_FMT_GRAY16BE PIX_FMT_GRAY16BE
|
||||
#define AV_PIX_FMT_GRAY16LE PIX_FMT_GRAY16LE
|
||||
#define AV_PIX_FMT_YUV440P PIX_FMT_YUV440P
|
||||
#define AV_PIX_FMT_YUVJ440P PIX_FMT_YUVJ440P
|
||||
#define AV_PIX_FMT_YUVA420P PIX_FMT_YUVA420P
|
||||
//#define AV_PIX_FMT_VDPAU_H264 PIX_FMT_VDPAU_H264
|
||||
//#define AV_PIX_FMT_VDPAU_MPEG1 PIX_FMT_VDPAU_MPEG1
|
||||
//#define AV_PIX_FMT_VDPAU_MPEG2 PIX_FMT_VDPAU_MPEG2
|
||||
#define _AVPIXELFORMAT PixelFormat
|
||||
#define AV_PIX_FMT_NONE PIX_FMT_NONE
|
||||
#define AV_PIX_FMT_RGB444 PIX_FMT_RGB444
|
||||
#define AV_PIX_FMT_RGB555 PIX_FMT_RGB555
|
||||
#define AV_PIX_FMT_RGB565 PIX_FMT_RGB565
|
||||
#define AV_PIX_FMT_BGR24 PIX_FMT_BGR24
|
||||
#define AV_PIX_FMT_RGB24 PIX_FMT_RGB24
|
||||
#define AV_PIX_FMT_BGRA PIX_FMT_BGRA
|
||||
#define AV_PIX_FMT_ARGB PIX_FMT_ARGB
|
||||
#define AV_PIX_FMT_ABGR PIX_FMT_ABGR
|
||||
#define AV_PIX_FMT_RGBA PIX_FMT_RGBA
|
||||
#define AV_PIX_FMT_GRAY8 PIX_FMT_GRAY8
|
||||
#define AV_PIX_FMT_YUYV422 PIX_FMT_YUYV422
|
||||
#define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P
|
||||
#define AV_PIX_FMT_YUV411P PIX_FMT_YUV411P
|
||||
#define AV_PIX_FMT_YUV444P PIX_FMT_YUV444P
|
||||
#define AV_PIX_FMT_YUV410P PIX_FMT_YUV410P
|
||||
#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
|
||||
#define AV_PIX_FMT_YUVJ444P PIX_FMT_YUVJ444P
|
||||
#define AV_PIX_FMT_UYVY422 PIX_FMT_UYVY422
|
||||
#define AV_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P
|
||||
#define AV_PIX_FMT_YUVJ422P PIX_FMT_YUVJ422P
|
||||
#define AV_PIX_FMT_UYVY422 PIX_FMT_UYVY422
|
||||
#define AV_PIX_FMT_UYYVYY411 PIX_FMT_UYYVYY411
|
||||
#define AV_PIX_FMT_BGR565 PIX_FMT_BGR565
|
||||
#define AV_PIX_FMT_BGR555 PIX_FMT_BGR555
|
||||
#define AV_PIX_FMT_BGR8 PIX_FMT_BGR8
|
||||
#define AV_PIX_FMT_BGR4 PIX_FMT_BGR4
|
||||
#define AV_PIX_FMT_BGR4_BYTE PIX_FMT_BGR4_BYTE
|
||||
#define AV_PIX_FMT_RGB8 PIX_FMT_RGB8
|
||||
#define AV_PIX_FMT_RGB4 PIX_FMT_RGB4
|
||||
#define AV_PIX_FMT_RGB4_BYTE PIX_FMT_RGB4_BYTE
|
||||
#define AV_PIX_FMT_NV12 PIX_FMT_NV12
|
||||
#define AV_PIX_FMT_NV21 PIX_FMT_NV21
|
||||
#define AV_PIX_FMT_RGB32_1 PIX_FMT_RGB32_1
|
||||
#define AV_PIX_FMT_BGR32_1 PIX_FMT_BGR32_1
|
||||
#define AV_PIX_FMT_GRAY16BE PIX_FMT_GRAY16BE
|
||||
#define AV_PIX_FMT_GRAY16LE PIX_FMT_GRAY16LE
|
||||
#define AV_PIX_FMT_YUV440P PIX_FMT_YUV440P
|
||||
#define AV_PIX_FMT_YUVJ440P PIX_FMT_YUVJ440P
|
||||
#define AV_PIX_FMT_YUVA420P PIX_FMT_YUVA420P
|
||||
//#define AV_PIX_FMT_VDPAU_H264 PIX_FMT_VDPAU_H264
|
||||
//#define AV_PIX_FMT_VDPAU_MPEG1 PIX_FMT_VDPAU_MPEG1
|
||||
//#define AV_PIX_FMT_VDPAU_MPEG2 PIX_FMT_VDPAU_MPEG2
|
||||
#endif
|
||||
#endif /* HAVE_LIBAVUTIL_AVUTIL_H */
|
||||
|
||||
|
@ -121,8 +122,8 @@ extern "C" {
|
|||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVCODEC_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBAVCODEC_VERSION_MICRO < 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVCODEC_VERSION_MICRO >= 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
( (LIBAVCODEC_VERSION_MICRO < 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVCODEC_VERSION_MICRO >= 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
|
||||
#elif HAVE_FFMPEG_AVCODEC_H
|
||||
#include <ffmpeg/avcodec.h>
|
||||
|
@ -130,9 +131,9 @@ extern "C" {
|
|||
|
||||
#if defined(HAVE_LIBAVCODEC_AVCODEC_H)
|
||||
#if LIBAVCODEC_VERSION_CHECK(54, 25, 0, 51, 100)
|
||||
#define _AVCODECID AVCodecID
|
||||
#define _AVCODECID AVCodecID
|
||||
#else
|
||||
#define _AVCODECID CodecID
|
||||
#define _AVCODECID CodecID
|
||||
#endif
|
||||
#endif /* HAVE_LIBAVCODEC_AVCODEC_H */
|
||||
|
||||
|
@ -146,8 +147,8 @@ extern "C" {
|
|||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVFORMAT_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBAVFORMAT_VERSION_MICRO < 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVFORMAT_VERSION_MICRO >= 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
( (LIBAVFORMAT_VERSION_MICRO < 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVFORMAT_VERSION_MICRO >= 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
|
||||
#elif HAVE_FFMPEG_AVFORMAT_H
|
||||
#include <ffmpeg/avformat.h>
|
||||
|
@ -162,8 +163,8 @@ extern "C" {
|
|||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVDEVICE_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBAVDEVICE_VERSION_MICRO < 100 && LIBAVDEVICE_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVDEVICE_VERSION_MICRO >= 100 && LIBAVDEVICE_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
( (LIBAVDEVICE_VERSION_MICRO < 100 && LIBAVDEVICE_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVDEVICE_VERSION_MICRO >= 100 && LIBAVDEVICE_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
|
||||
#elif HAVE_FFMPEG_AVDEVICE_H
|
||||
#include <ffmpeg/avdevice.h>
|
||||
|
@ -178,8 +179,8 @@ extern "C" {
|
|||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBSWSCALE_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBSWSCALE_VERSION_MICRO < 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBSWSCALE_VERSION_MICRO >= 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
( (LIBSWSCALE_VERSION_MICRO < 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBSWSCALE_VERSION_MICRO >= 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
|
||||
#elif HAVE_FFMPEG_SWSCALE_H
|
||||
#include <ffmpeg/swscale.h>
|
||||
|
@ -199,6 +200,9 @@ extern "C" {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/* A single function to initialize ffmpeg, to avoid multiple initializations */
|
||||
void FFMPEGInit();
|
||||
|
||||
#if HAVE_LIBAVUTIL
|
||||
enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder);
|
||||
#endif // HAVE_LIBAVUTIL
|
||||
|
@ -208,23 +212,23 @@ enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subp
|
|||
#if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
||||
class SWScale {
|
||||
public:
|
||||
SWScale();
|
||||
~SWScale();
|
||||
int SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
int ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size);
|
||||
int ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size);
|
||||
int Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
SWScale();
|
||||
~SWScale();
|
||||
int SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
int ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size);
|
||||
int ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size);
|
||||
int Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height);
|
||||
|
||||
protected:
|
||||
bool gotdefaults;
|
||||
struct SwsContext* swscale_ctx;
|
||||
AVFrame* input_avframe;
|
||||
AVFrame* output_avframe;
|
||||
enum _AVPIXELFORMAT default_input_pf;
|
||||
enum _AVPIXELFORMAT default_output_pf;
|
||||
unsigned int default_width;
|
||||
unsigned int default_height;
|
||||
bool gotdefaults;
|
||||
struct SwsContext* swscale_ctx;
|
||||
AVFrame* input_avframe;
|
||||
AVFrame* output_avframe;
|
||||
enum _AVPIXELFORMAT default_input_pf;
|
||||
enum _AVPIXELFORMAT default_output_pf;
|
||||
unsigned int default_width;
|
||||
unsigned int default_height;
|
||||
};
|
||||
#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
||||
|
||||
|
@ -261,19 +265,19 @@ protected:
|
|||
*/
|
||||
#ifdef __cplusplus
|
||||
|
||||
inline static const std::string av_make_error_string(int errnum)
|
||||
{
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
inline static const std::string av_make_error_string(int errnum)
|
||||
{
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
#if LIBAVUTIL_VERSION_CHECK(50, 13, 0, 13, 0)
|
||||
av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
#else
|
||||
snprintf(errbuf, AV_ERROR_MAX_STRING_SIZE, "libav error %d", errnum);
|
||||
snprintf(errbuf, AV_ERROR_MAX_STRING_SIZE, "libav error %d", errnum);
|
||||
#endif
|
||||
return (std::string)errbuf;
|
||||
}
|
||||
return (std::string)errbuf;
|
||||
}
|
||||
|
||||
#undef av_err2str
|
||||
#define av_err2str(errnum) av_make_error_string(errnum).c_str()
|
||||
#undef av_err2str
|
||||
#define av_err2str(errnum) av_make_error_string(errnum).c_str()
|
||||
|
||||
/* The following is copied directly from newer ffmpeg */
|
||||
#if LIBAVUTIL_VERSION_CHECK(52, 7, 0, 17, 100)
|
||||
|
@ -288,4 +292,60 @@ protected:
|
|||
|
||||
#endif // ( HAVE_LIBAVUTIL_AVUTIL_H || HAVE_LIBAVCODEC_AVCODEC_H || HAVE_LIBAVFORMAT_AVFORMAT_H || HAVE_LIBAVDEVICE_AVDEVICE_H )
|
||||
|
||||
#ifndef avformat_alloc_output_context2
|
||||
int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat *oformat, const char *format, const char *filename);
|
||||
#define avformat_alloc_output_context2(x,y,z,a) hacked_up_context2_for_older_ffmpeg(x,y,z,a)
|
||||
#endif
|
||||
|
||||
#ifndef av_rescale_delta
|
||||
/**
|
||||
* Rescale a timestamp while preserving known durations.
|
||||
*/
|
||||
int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb);
|
||||
#endif
|
||||
|
||||
#ifndef av_clip64
|
||||
/**
|
||||
* Clip a signed 64bit integer value into the amin-amax range.
|
||||
* @param a value to clip
|
||||
* @param amin minimum value of the clip range
|
||||
* @param amax maximum value of the clip range
|
||||
* @return clipped value
|
||||
*/
|
||||
static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax)
|
||||
{
|
||||
if (a < amin) return amin;
|
||||
else if (a > amax) return amax;
|
||||
else return a;
|
||||
}
|
||||
|
||||
#define av_clip64 av_clip64_c
|
||||
#endif
|
||||
|
||||
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output);
|
||||
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
|
||||
#define zm_av_packet_unref( packet ) av_packet_unref( packet )
|
||||
#define zm_av_packet_ref( dst, src ) av_packet_ref( dst, src )
|
||||
#else
|
||||
#define zm_av_packet_unref( packet ) av_free_packet( packet )
|
||||
unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src );
|
||||
#endif
|
||||
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
|
||||
#define zm_avcodec_decode_video( context, rawFrame, frameComplete, packet ) avcodec_decode_video2( context, rawFrame, frameComplete, packet )
|
||||
#else
|
||||
#define zm_avcodec_decode_video(context, rawFrame, frameComplete, packet ) avcodec_decode_video( context, rawFrame, frameComplete, packet->data, packet->size)
|
||||
#endif
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
#define zm_av_frame_alloc() av_frame_alloc()
|
||||
#else
|
||||
#define zm_av_frame_alloc() avcodec_alloc_frame()
|
||||
#endif
|
||||
|
||||
#if ! LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
#define av_frame_free( input_avframe ) av_freep( input_avframe )
|
||||
#endif
|
||||
|
||||
int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt);
|
||||
|
||||
#endif // ZM_FFMPEG_H
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
|
||||
#include "zm_ffmpeg_camera.h"
|
||||
|
||||
extern "C" {
|
||||
#include "libavutil/time.h"
|
||||
}
|
||||
#ifndef AV_ERROR_MAX_STRING_SIZE
|
||||
#define AV_ERROR_MAX_STRING_SIZE 64
|
||||
#endif
|
||||
|
@ -33,29 +36,34 @@
|
|||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) :
|
||||
Camera( p_id, FFMPEG_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ),
|
||||
FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) :
|
||||
Camera( p_id, FFMPEG_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ),
|
||||
mPath( p_path ),
|
||||
mMethod( p_method ),
|
||||
mOptions( p_options )
|
||||
{
|
||||
if ( capture )
|
||||
{
|
||||
if ( capture ) {
|
||||
Initialise();
|
||||
}
|
||||
|
||||
|
||||
mFormatContext = NULL;
|
||||
mVideoStreamId = -1;
|
||||
mCodecContext = NULL;
|
||||
mCodec = NULL;
|
||||
mAudioStreamId = -1;
|
||||
mVideoCodecContext = NULL;
|
||||
mAudioCodecContext = NULL;
|
||||
mVideoCodec = NULL;
|
||||
mAudioCodec = NULL;
|
||||
mRawFrame = NULL;
|
||||
mFrame = NULL;
|
||||
frameCount = 0;
|
||||
startTime=0;
|
||||
mIsOpening = false;
|
||||
mCanCapture = false;
|
||||
mOpenStart = 0;
|
||||
mReopenThread = 0;
|
||||
|
||||
videoStore = NULL;
|
||||
video_last_pts = 0;
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
mConvertContext = NULL;
|
||||
#endif
|
||||
|
@ -72,35 +80,37 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri
|
|||
} else {
|
||||
Panic("Unexpected colours: %d",colours);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
FfmpegCamera::~FfmpegCamera()
|
||||
{
|
||||
FfmpegCamera::~FfmpegCamera() {
|
||||
|
||||
if ( videoStore ) {
|
||||
delete videoStore;
|
||||
}
|
||||
CloseFfmpeg();
|
||||
|
||||
if ( capture )
|
||||
{
|
||||
if ( capture ) {
|
||||
Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void FfmpegCamera::Initialise()
|
||||
{
|
||||
void FfmpegCamera::Initialise() {
|
||||
if ( logDebugging() )
|
||||
av_log_set_level( AV_LOG_DEBUG );
|
||||
else
|
||||
av_log_set_level( AV_LOG_QUIET );
|
||||
|
||||
av_register_all();
|
||||
avformat_network_init();
|
||||
}
|
||||
|
||||
void FfmpegCamera::Terminate()
|
||||
{
|
||||
void FfmpegCamera::Terminate() {
|
||||
}
|
||||
|
||||
int FfmpegCamera::PrimeCapture()
|
||||
{
|
||||
int FfmpegCamera::PrimeCapture() {
|
||||
mVideoStreamId = -1;
|
||||
mAudioStreamId = -1;
|
||||
Info( "Priming capture from %s", mPath.c_str() );
|
||||
|
||||
if (OpenFfmpeg() != 0){
|
||||
|
@ -115,109 +125,102 @@ int FfmpegCamera::PreCapture()
|
|||
return( 0 );
|
||||
}
|
||||
|
||||
int FfmpegCamera::Capture( Image &image )
|
||||
{
|
||||
int FfmpegCamera::Capture( Image &image ) {
|
||||
if (!mCanCapture){
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// If the reopen thread has a value, but mCanCapture != 0, then we have just reopened the connection to the ffmpeg device, and we can clean up the thread.
|
||||
if (mReopenThread != 0) {
|
||||
void *retval = 0;
|
||||
int ret;
|
||||
|
||||
|
||||
ret = pthread_join(mReopenThread, &retval);
|
||||
if (ret != 0){
|
||||
Error("Could not join reopen thread.");
|
||||
}
|
||||
|
||||
|
||||
Info( "Successfully reopened stream." );
|
||||
mReopenThread = 0;
|
||||
}
|
||||
|
||||
AVPacket packet;
|
||||
uint8_t* directbuffer;
|
||||
|
||||
/* Request a writeable buffer of the target image */
|
||||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
||||
if(directbuffer == NULL) {
|
||||
Error("Failed requesting writeable buffer for the captured image.");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int frameComplete = false;
|
||||
while ( !frameComplete )
|
||||
{
|
||||
while ( !frameComplete ) {
|
||||
int avResult = av_read_frame( mFormatContext, &packet );
|
||||
if ( avResult < 0 )
|
||||
{
|
||||
if ( avResult < 0 ) {
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
av_strerror(avResult, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
if (
|
||||
// Check if EOF.
|
||||
(avResult == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(avResult == -110)
|
||||
)
|
||||
{
|
||||
Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf);
|
||||
// Check if EOF.
|
||||
(avResult == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(avResult == -110)
|
||||
) {
|
||||
Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf );
|
||||
ReopenFfmpeg();
|
||||
}
|
||||
|
||||
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, avResult, errbuf );
|
||||
return( -1 );
|
||||
}
|
||||
Debug( 5, "Got packet from stream %d", packet.stream_index );
|
||||
if ( packet.stream_index == mVideoStreamId )
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
|
||||
if ( avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ) < 0 )
|
||||
#else
|
||||
if ( avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ) < 0 )
|
||||
#endif
|
||||
Debug( 5, "Got packet from stream %d dts (%d) pts(%d)", packet.stream_index, packet.pts, packet.dts );
|
||||
// What about audio stream? Maybe someday we could do sound detection...
|
||||
if ( packet.stream_index == mVideoStreamId ) {
|
||||
int ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet );
|
||||
if ( ret < 0 )
|
||||
Fatal( "Unable to decode frame at frame %d", frameCount );
|
||||
|
||||
Debug( 4, "Decoded video packet at frame %d", frameCount );
|
||||
|
||||
if ( frameComplete )
|
||||
{
|
||||
Debug( 3, "Got frame %d", frameCount );
|
||||
if ( frameComplete ) {
|
||||
Debug( 4, "Got frame %d", frameCount );
|
||||
|
||||
uint8_t* directbuffer;
|
||||
|
||||
/* Request a writeable buffer of the target image */
|
||||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
||||
if(directbuffer == NULL) {
|
||||
Error("Failed requesting writeable buffer for the captured image.");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
av_image_fill_arrays(mFrame->data, mFrame->linesize,
|
||||
directbuffer, imagePixFormat, width, height, 1);
|
||||
directbuffer, imagePixFormat, width, height, 1);
|
||||
#else
|
||||
avpicture_fill( (AVPicture *)mFrame, directbuffer,
|
||||
imagePixFormat, width, height);
|
||||
imagePixFormat, width, height);
|
||||
#endif
|
||||
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
if(mConvertContext == NULL) {
|
||||
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL );
|
||||
if(mConvertContext == NULL) {
|
||||
mConvertContext = sws_getContext(mVideoCodecContext->width,
|
||||
mVideoCodecContext->height,
|
||||
mVideoCodecContext->pix_fmt,
|
||||
width, height, imagePixFormat,
|
||||
SWS_BICUBIC, NULL, NULL, NULL);
|
||||
|
||||
if(mConvertContext == NULL)
|
||||
Fatal( "Unable to create conversion context for %s", mPath.c_str() );
|
||||
}
|
||||
|
||||
if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 )
|
||||
Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount );
|
||||
if(mConvertContext == NULL)
|
||||
Fatal( "Unable to create conversion context for %s", mPath.c_str() );
|
||||
}
|
||||
|
||||
if (sws_scale(mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0)
|
||||
Fatal("Unable to convert raw format %u to target format %u at frame %d", mVideoCodecContext->pix_fmt, imagePixFormat, frameCount);
|
||||
#else // HAVE_LIBSWSCALE
|
||||
Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" );
|
||||
Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" );
|
||||
#endif // HAVE_LIBSWSCALE
|
||||
|
||||
frameCount++;
|
||||
}
|
||||
}
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 8, 0, 12, 100)
|
||||
av_packet_unref( &packet);
|
||||
#else
|
||||
av_free_packet( &packet );
|
||||
#endif
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int FfmpegCamera::PostCapture()
|
||||
{
|
||||
frameCount++;
|
||||
} // end if frameComplete
|
||||
} else {
|
||||
Debug( 4, "Different stream_index %d", packet.stream_index );
|
||||
} // end if packet.stream_index == mVideoStreamId
|
||||
zm_av_packet_unref( &packet );
|
||||
} // end while ! frameComplete
|
||||
return (0);
|
||||
} // FfmpegCamera::Capture
|
||||
|
||||
int FfmpegCamera::PostCapture() {
|
||||
// Nothing to do here
|
||||
return( 0 );
|
||||
}
|
||||
|
@ -278,70 +281,111 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
mIsOpening = false;
|
||||
Debug ( 1, "Opened input" );
|
||||
|
||||
Info( "Stream open %s", mPath.c_str() );
|
||||
|
||||
//FIXME can speed up initial analysis but need sensible parameters...
|
||||
//mFormatContext->probesize = 32;
|
||||
//mFormatContext->max_analyze_duration = 32;
|
||||
// Locate stream info from avformat_open_input
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 6, 0, 6, 0)
|
||||
Debug ( 1, "Calling av_find_stream_info" );
|
||||
if ( av_find_stream_info( mFormatContext ) < 0 )
|
||||
#else
|
||||
Debug ( 1, "Calling avformat_find_stream_info" );
|
||||
Debug ( 1, "Calling avformat_find_stream_info" );
|
||||
if ( avformat_find_stream_info( mFormatContext, 0 ) < 0 )
|
||||
#endif
|
||||
Fatal( "Unable to find stream info from %s due to: %s", mPath.c_str(), strerror(errno) );
|
||||
|
||||
startTime = av_gettime();//FIXME here or after find_Stream_info
|
||||
Debug ( 1, "Got stream info" );
|
||||
|
||||
// Find first video stream present
|
||||
// The one we want Might not be the first
|
||||
mVideoStreamId = -1;
|
||||
for (unsigned int i=0; i < mFormatContext->nb_streams; i++ )
|
||||
{
|
||||
mAudioStreamId = -1;
|
||||
for (unsigned int i=0; i < mFormatContext->nb_streams; i++ ) {
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO )
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
|
||||
#else
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) {
|
||||
#endif
|
||||
{
|
||||
mVideoStreamId = i;
|
||||
break;
|
||||
if ( mVideoStreamId == -1 ) {
|
||||
mVideoStreamId = i;
|
||||
// if we break, then we won't find the audio stream
|
||||
continue;
|
||||
} else {
|
||||
Debug(2, "Have another video stream." );
|
||||
}
|
||||
}
|
||||
}
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO ) {
|
||||
#else
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO ) {
|
||||
#endif
|
||||
if ( mAudioStreamId == -1 ) {
|
||||
mAudioStreamId = i;
|
||||
} else {
|
||||
Debug(2, "Have another audio stream." );
|
||||
}
|
||||
}
|
||||
} // end foreach stream
|
||||
if ( mVideoStreamId == -1 )
|
||||
Fatal( "Unable to locate video stream in %s", mPath.c_str() );
|
||||
if ( mAudioStreamId == -1 )
|
||||
Debug( 3, "Unable to locate audio stream in %s", mPath.c_str() );
|
||||
|
||||
Debug ( 1, "Found video stream" );
|
||||
Debug ( 3, "Found video stream at index %d", mVideoStreamId );
|
||||
Debug ( 3, "Found audio stream at index %d", mAudioStreamId );
|
||||
|
||||
mCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
|
||||
mVideoCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
|
||||
// STolen from ispy
|
||||
//this fixes issues with rtsp streams!! woot.
|
||||
//mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG2_CHUNKS | CODEC_FLAG_LOW_DELAY; // Enable faster H264 decode.
|
||||
mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG_LOW_DELAY;
|
||||
|
||||
// Try and get the codec from the codec context
|
||||
if ( (mCodec = avcodec_find_decoder( mCodecContext->codec_id )) == NULL )
|
||||
Fatal( "Can't find codec for video stream from %s", mPath.c_str() );
|
||||
|
||||
Debug ( 1, "Found decoder" );
|
||||
|
||||
if ((mVideoCodec = avcodec_find_decoder(mVideoCodecContext->codec_id)) == NULL) {
|
||||
Fatal("Can't find codec for video stream from %s", mPath.c_str());
|
||||
} else {
|
||||
Debug(1, "Video Found decoder");
|
||||
zm_dump_stream_format(mFormatContext, mVideoStreamId, 0, 0);
|
||||
// Open the codec
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
|
||||
Debug ( 1, "Calling avcodec_open" );
|
||||
if ( avcodec_open( mCodecContext, mCodec ) < 0 )
|
||||
if (avcodec_open(mVideoCodecContext, mVideoCodec) < 0)
|
||||
#else
|
||||
Debug ( 1, "Calling avcodec_open2" );
|
||||
if ( avcodec_open2( mCodecContext, mCodec, 0 ) < 0 )
|
||||
Debug ( 1, "Calling avcodec_open2" );
|
||||
if (avcodec_open2(mVideoCodecContext, mVideoCodec, 0) < 0)
|
||||
#endif
|
||||
Fatal( "Unable to open codec for video stream from %s", mPath.c_str() );
|
||||
}
|
||||
|
||||
if ( mAudioStreamId >= 0 ) {
|
||||
mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec;
|
||||
if ((mAudioCodec = avcodec_find_decoder(mAudioCodecContext->codec_id)) == NULL) {
|
||||
Debug(1, "Can't find codec for audio stream from %s", mPath.c_str());
|
||||
} else {
|
||||
Debug(1, "Audio Found decoder");
|
||||
zm_dump_stream_format(mFormatContext, mAudioStreamId, 0, 0);
|
||||
// Open the codec
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
|
||||
Debug ( 1, "Calling avcodec_open" );
|
||||
if (avcodec_open(mAudioCodecContext, mAudioCodec) < 0)
|
||||
#else
|
||||
Debug ( 1, "Calling avcodec_open2" );
|
||||
if (avcodec_open2(mAudioCodecContext, mAudioCodec, 0) < 0)
|
||||
#endif
|
||||
Fatal( "Unable to open codec for video stream from %s", mPath.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
Debug ( 1, "Opened codec" );
|
||||
|
||||
// Allocate space for the native video frame
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
mRawFrame = av_frame_alloc();
|
||||
#else
|
||||
mRawFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
mRawFrame = zm_av_frame_alloc();
|
||||
|
||||
// Allocate space for the converted video frame
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
mFrame = av_frame_alloc();
|
||||
#else
|
||||
mFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
mFrame = zm_av_frame_alloc();
|
||||
|
||||
if(mRawFrame == NULL || mFrame == NULL)
|
||||
Fatal( "Unable to allocate frame for %s", mPath.c_str() );
|
||||
|
@ -359,25 +403,37 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
}
|
||||
|
||||
Debug ( 1, "Validated imagesize" );
|
||||
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
Debug ( 1, "Calling sws_isSupportedInput" );
|
||||
if(!sws_isSupportedInput(mCodecContext->pix_fmt)) {
|
||||
Fatal("swscale does not support the codec format: %c%c%c%c",(mCodecContext->pix_fmt)&0xff,((mCodecContext->pix_fmt>>8)&0xff),((mCodecContext->pix_fmt>>16)&0xff),((mCodecContext->pix_fmt>>24)&0xff));
|
||||
if (!sws_isSupportedInput(mVideoCodecContext->pix_fmt)) {
|
||||
Fatal("swscale does not support the codec format: %c%c%c%c", (mVideoCodecContext->pix_fmt)&0xff, ((mVideoCodecContext->pix_fmt >> 8)&0xff), ((mVideoCodecContext->pix_fmt >> 16)&0xff), ((mVideoCodecContext->pix_fmt >> 24)&0xff));
|
||||
}
|
||||
|
||||
|
||||
if(!sws_isSupportedOutput(imagePixFormat)) {
|
||||
Fatal("swscale does not support the target format: %c%c%c%c",(imagePixFormat)&0xff,((imagePixFormat>>8)&0xff),((imagePixFormat>>16)&0xff),((imagePixFormat>>24)&0xff));
|
||||
}
|
||||
|
||||
|
||||
mConvertContext = sws_getContext(mVideoCodecContext->width,
|
||||
mVideoCodecContext->height,
|
||||
mVideoCodecContext->pix_fmt,
|
||||
width, height,
|
||||
imagePixFormat, SWS_BICUBIC, NULL,
|
||||
NULL, NULL);
|
||||
if ( mConvertContext == NULL )
|
||||
Fatal( "Unable to create conversion context for %s", mPath.c_str() );
|
||||
#else // HAVE_LIBSWSCALE
|
||||
Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" );
|
||||
#endif // HAVE_LIBSWSCALE
|
||||
|
||||
if ( (unsigned int)mVideoCodecContext->width != width || (unsigned int)mVideoCodecContext->height != height ) {
|
||||
Warning( "Monitor dimensions are %dx%d but camera is sending %dx%d", width, height, mVideoCodecContext->width, mVideoCodecContext->height );
|
||||
}
|
||||
|
||||
mCanCapture = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // int FfmpegCamera::OpenFfmpeg()
|
||||
|
||||
int FfmpegCamera::ReopenFfmpeg() {
|
||||
|
||||
|
@ -398,29 +454,26 @@ int FfmpegCamera::CloseFfmpeg(){
|
|||
|
||||
mCanCapture = false;
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
av_frame_free( &mFrame );
|
||||
av_frame_free( &mRawFrame );
|
||||
#else
|
||||
av_freep( &mFrame );
|
||||
av_freep( &mRawFrame );
|
||||
#endif
|
||||
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
if ( mConvertContext )
|
||||
{
|
||||
if ( mConvertContext ) {
|
||||
sws_freeContext( mConvertContext );
|
||||
mConvertContext = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( mCodecContext )
|
||||
{
|
||||
avcodec_close( mCodecContext );
|
||||
mCodecContext = NULL; // Freed by av_close_input_file
|
||||
if (mVideoCodecContext) {
|
||||
avcodec_close(mVideoCodecContext);
|
||||
mVideoCodecContext = NULL; // Freed by av_close_input_file
|
||||
}
|
||||
if ( mFormatContext )
|
||||
{
|
||||
if (mAudioCodecContext) {
|
||||
avcodec_close(mAudioCodecContext);
|
||||
mAudioCodecContext = NULL; // Freed by av_close_input_file
|
||||
}
|
||||
|
||||
if ( mFormatContext ) {
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0)
|
||||
av_close_input_file( mFormatContext );
|
||||
#else
|
||||
|
@ -432,8 +485,7 @@ int FfmpegCamera::CloseFfmpeg(){
|
|||
return 0;
|
||||
}
|
||||
|
||||
int FfmpegCamera::FfmpegInterruptCallback(void *ctx)
|
||||
{
|
||||
int FfmpegCamera::FfmpegInterruptCallback(void *ctx) {
|
||||
FfmpegCamera* camera = reinterpret_cast<FfmpegCamera*>(ctx);
|
||||
if (camera->mIsOpening){
|
||||
int now = time(NULL);
|
||||
|
@ -469,4 +521,282 @@ void *FfmpegCamera::ReopenFfmpegThreadCallback(void *ctx){
|
|||
}
|
||||
}
|
||||
|
||||
//Function to handle capture and store
|
||||
int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event_file ) {
|
||||
if ( ! mCanCapture ) {
|
||||
return -1;
|
||||
}
|
||||
int ret;
|
||||
static char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
|
||||
// If the reopen thread has a value, but mCanCapture != 0, then we have just reopened the connection to the ffmpeg device, and we can clean up the thread.
|
||||
if ( mReopenThread != 0 ) {
|
||||
void *retval = 0;
|
||||
|
||||
ret = pthread_join(mReopenThread, &retval);
|
||||
if (ret != 0){
|
||||
Error("Could not join reopen thread.");
|
||||
}
|
||||
|
||||
Info( "Successfully reopened stream." );
|
||||
mReopenThread = 0;
|
||||
}
|
||||
|
||||
if ( mVideoCodecContext->codec_id != AV_CODEC_ID_H264 ) {
|
||||
Error( "Input stream is not h264. The stored event file may not be viewable in browser." );
|
||||
}
|
||||
|
||||
int frameComplete = false;
|
||||
while ( ! frameComplete ) {
|
||||
av_init_packet( &packet );
|
||||
|
||||
ret = av_read_frame( mFormatContext, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
if (
|
||||
// Check if EOF.
|
||||
(ret == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(ret == -110)
|
||||
) {
|
||||
Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf);
|
||||
ReopenFfmpeg();
|
||||
}
|
||||
|
||||
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, errbuf );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
int key_frame = packet.flags & AV_PKT_FLAG_KEY;
|
||||
|
||||
Debug( 4, "Got packet from stream %d packet pts (%d) dts(%d), key?(%d)",
|
||||
packet.stream_index, packet.pts, packet.dts,
|
||||
key_frame
|
||||
);
|
||||
|
||||
//Video recording
|
||||
if ( recording.tv_sec ) {
|
||||
// The directory we are recording to is no longer tied to the current event.
|
||||
// Need to re-init the videostore with the correct directory and start recording again
|
||||
// for efficiency's sake, we should test for keyframe before we test for directory change...
|
||||
if ( videoStore && key_frame && (strcmp(oldDirectory, event_file) != 0 ) ) {
|
||||
// don't open new videostore until we're on a key frame..would this require an offset adjustment for the event as a result?...
|
||||
// if we store our key frame location with the event will that be enough?
|
||||
Info("Re-starting video storage module");
|
||||
|
||||
// I don't know if this is important or not... but I figure we might as well write this last packet out to the store before closing it.
|
||||
// Also don't know how much it matters for audio.
|
||||
if ( packet.stream_index == mVideoStreamId ) {
|
||||
//Write the packet to our video store
|
||||
int ret = videoStore->writeVideoFramePacket( &packet );
|
||||
if ( ret < 0 ) { //Less than zero and we skipped a frame
|
||||
Warning("Error writing last packet to videostore.");
|
||||
}
|
||||
} // end if video
|
||||
|
||||
delete videoStore;
|
||||
videoStore = NULL;
|
||||
} // end if end of recording
|
||||
|
||||
if ( ( ! videoStore ) && key_frame && ( packet.stream_index == mVideoStreamId ) ) {
|
||||
//Instantiate the video storage module
|
||||
|
||||
if (record_audio) {
|
||||
if (mAudioStreamId == -1) {
|
||||
Debug(3, "Record Audio on but no audio stream found");
|
||||
videoStore = new VideoStore((const char *) event_file, "mp4",
|
||||
mFormatContext->streams[mVideoStreamId],
|
||||
NULL,
|
||||
startTime,
|
||||
this->getMonitor());
|
||||
|
||||
} else {
|
||||
Debug(3, "Video module initiated with audio stream");
|
||||
videoStore = new VideoStore((const char *) event_file, "mp4",
|
||||
mFormatContext->streams[mVideoStreamId],
|
||||
mFormatContext->streams[mAudioStreamId],
|
||||
startTime,
|
||||
this->getMonitor());
|
||||
}
|
||||
} else {
|
||||
Debug(3, "Record_audio is false so exclude audio stream");
|
||||
videoStore = new VideoStore((const char *) event_file, "mp4",
|
||||
mFormatContext->streams[mVideoStreamId],
|
||||
NULL,
|
||||
startTime,
|
||||
this->getMonitor());
|
||||
} // end if record_audio
|
||||
strcpy(oldDirectory, event_file);
|
||||
|
||||
// Need to write out all the frames from the last keyframe?
|
||||
// No... need to write out all frames from when the event began. Due to PreEventFrames, this could be more than since the last keyframe.
|
||||
unsigned int packet_count = 0;
|
||||
ZMPacket *queued_packet;
|
||||
|
||||
// Clear all packets that predate the moment when the recording began
|
||||
packetqueue.clear_unwanted_packets( &recording, mVideoStreamId );
|
||||
|
||||
while ( ( queued_packet = packetqueue.popPacket() ) ) {
|
||||
AVPacket *avp = queued_packet->av_packet();
|
||||
|
||||
packet_count += 1;
|
||||
//Write the packet to our video store
|
||||
Debug(2, "Writing queued packet stream: %d KEY %d, remaining (%d)", avp->stream_index, avp->flags & AV_PKT_FLAG_KEY, packetqueue.size() );
|
||||
if ( avp->stream_index == mVideoStreamId ) {
|
||||
ret = videoStore->writeVideoFramePacket( avp );
|
||||
} else if ( avp->stream_index == mAudioStreamId ) {
|
||||
ret = videoStore->writeAudioFramePacket( avp );
|
||||
} else {
|
||||
Warning("Unknown stream id in queued packet (%d)", avp->stream_index );
|
||||
ret = -1;
|
||||
}
|
||||
if ( ret < 0 ) {
|
||||
//Less than zero and we skipped a frame
|
||||
}
|
||||
delete queued_packet;
|
||||
} // end while packets in the packetqueue
|
||||
Debug(2, "Wrote %d queued packets", packet_count );
|
||||
} // end if ! was recording
|
||||
|
||||
} else {
|
||||
// Not recording
|
||||
if ( videoStore ) {
|
||||
Info("Deleting videoStore instance");
|
||||
delete videoStore;
|
||||
videoStore = NULL;
|
||||
}
|
||||
|
||||
// Buffer video packets, since we are not recording.
|
||||
// All audio packets are keyframes, so only if it's a video keyframe
|
||||
if ( packet.stream_index == mVideoStreamId ) {
|
||||
if ( key_frame ) {
|
||||
Debug(3, "Clearing queue");
|
||||
packetqueue.clearQueue( monitor->GetPreEventCount(), mVideoStreamId );
|
||||
}
|
||||
#if 0
|
||||
// Not sure this is valid. While a camera will PROBABLY always have an increasing pts... it doesn't have to.
|
||||
// Also, I think there are integer wrap-around issues.
|
||||
|
||||
else if ( packet.pts && video_last_pts > packet.pts ) {
|
||||
Warning( "Clearing queue due to out of order pts packet.pts(%d) < video_last_pts(%d)");
|
||||
packetqueue.clearQueue();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// The following lines should ensure that the queue always begins with a video keyframe
|
||||
if ( packet.stream_index == mAudioStreamId ) {
|
||||
//Debug(2, "Have audio packet, reocrd_audio is (%d) and packetqueue.size is (%d)", record_audio, packetqueue.size() );
|
||||
if ( record_audio && packetqueue.size() ) {
|
||||
// if it's audio, and we are doing audio, and there is already something in the queue
|
||||
packetqueue.queuePacket( &packet );
|
||||
}
|
||||
} else if ( packet.stream_index == mVideoStreamId ) {
|
||||
if ( key_frame || packetqueue.size() ) // it's a keyframe or we already have something in the queue
|
||||
packetqueue.queuePacket( &packet );
|
||||
}
|
||||
} // end if recording or not
|
||||
|
||||
if ( packet.stream_index == mVideoStreamId ) {
|
||||
if ( videoStore ) {
|
||||
//Write the packet to our video store
|
||||
int ret = videoStore->writeVideoFramePacket( &packet );
|
||||
if ( ret < 0 ) { //Less than zero and we skipped a frame
|
||||
zm_av_packet_unref( &packet );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Debug(4, "about to decode video" );
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(58, 0, 0, 0, 0)
|
||||
ret = avcodec_send_packet( mVideoCodecContext, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
frameComplete = 1;
|
||||
# else
|
||||
ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet );
|
||||
if ( ret < 0 ) {
|
||||
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
|
||||
Error( "Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf );
|
||||
zm_av_packet_unref( &packet );
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
Debug( 4, "Decoded video packet at frame %d", frameCount );
|
||||
|
||||
if ( frameComplete ) {
|
||||
Debug( 4, "Got frame %d", frameCount );
|
||||
|
||||
uint8_t* directbuffer;
|
||||
|
||||
/* Request a writeable buffer of the target image */
|
||||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
||||
if ( directbuffer == NULL ) {
|
||||
Error("Failed requesting writeable buffer for the captured image.");
|
||||
zm_av_packet_unref( &packet );
|
||||
return (-1);
|
||||
}
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
av_image_fill_arrays(mFrame->data, mFrame->linesize, directbuffer, imagePixFormat, width, height, 1);
|
||||
#else
|
||||
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
|
||||
#endif
|
||||
|
||||
|
||||
if (sws_scale(mConvertContext, mRawFrame->data, mRawFrame->linesize,
|
||||
0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0) {
|
||||
Fatal("Unable to convert raw format %u to target format %u at frame %d",
|
||||
mVideoCodecContext->pix_fmt, imagePixFormat, frameCount);
|
||||
}
|
||||
|
||||
frameCount++;
|
||||
} else {
|
||||
Debug( 3, "Not framecomplete after av_read_frame" );
|
||||
} // end if frameComplete
|
||||
} else if ( packet.stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams
|
||||
if ( videoStore ) {
|
||||
if ( record_audio ) {
|
||||
Debug(3, "Recording audio packet streamindex(%d) packetstreamindex(%d)", mAudioStreamId, packet.stream_index );
|
||||
//Write the packet to our video store
|
||||
//FIXME no relevance of last key frame
|
||||
int ret = videoStore->writeAudioFramePacket( &packet );
|
||||
if ( ret < 0 ) {//Less than zero and we skipped a frame
|
||||
Warning("Failure to write audio packet.");
|
||||
zm_av_packet_unref( &packet );
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
Debug(4, "Not doing recording of audio packet" );
|
||||
}
|
||||
} else {
|
||||
Debug(4, "Have audio packet, but not recording atm" );
|
||||
}
|
||||
} else {
|
||||
#if LIBAVUTIL_VERSION_CHECK(56, 23, 0, 23, 0)
|
||||
Debug( 3, "Some other stream index %d, %s", packet.stream_index, av_get_media_type_string( mFormatContext->streams[packet.stream_index]->codecpar->codec_type) );
|
||||
#else
|
||||
Debug( 3, "Some other stream index %d", packet.stream_index );
|
||||
#endif
|
||||
}
|
||||
//if ( videoStore ) {
|
||||
|
||||
// the packet contents are ref counted... when queuing, we allocate another packet and reference it with that one, so we should always need to unref here, which should not affect the queued version.
|
||||
zm_av_packet_unref( &packet );
|
||||
//}
|
||||
} // end while ! frameComplete
|
||||
return (frameCount);
|
||||
} // end FfmpegCamera::CaptureAndRecord
|
||||
|
||||
#endif // HAVE_LIBAVFORMAT
|
||||
|
|
|
@ -25,59 +25,82 @@
|
|||
#include "zm_buffer.h"
|
||||
//#include "zm_utils.h"
|
||||
#include "zm_ffmpeg.h"
|
||||
#include "zm_videostore.h"
|
||||
#include "zm_packetqueue.h"
|
||||
|
||||
//
|
||||
// Class representing 'ffmpeg' cameras, i.e. those which are
|
||||
// accessed using ffmpeg multimedia framework
|
||||
//
|
||||
class FfmpegCamera : public Camera
|
||||
{
|
||||
protected:
|
||||
std::string mPath;
|
||||
std::string mMethod;
|
||||
std::string mOptions;
|
||||
class FfmpegCamera : public Camera {
|
||||
protected:
|
||||
std::string mPath;
|
||||
std::string mMethod;
|
||||
std::string mOptions;
|
||||
|
||||
int frameCount;
|
||||
int frameCount;
|
||||
|
||||
#if HAVE_LIBAVFORMAT
|
||||
AVFormatContext *mFormatContext;
|
||||
int mVideoStreamId;
|
||||
AVCodecContext *mCodecContext;
|
||||
AVCodec *mCodec;
|
||||
AVFrame *mRawFrame;
|
||||
AVFrame *mFrame;
|
||||
_AVPIXELFORMAT imagePixFormat;
|
||||
AVFormatContext *mFormatContext;
|
||||
int mVideoStreamId;
|
||||
int mAudioStreamId;
|
||||
AVCodecContext *mVideoCodecContext;
|
||||
AVCodecContext *mAudioCodecContext;
|
||||
AVCodec *mVideoCodec;
|
||||
AVCodec *mAudioCodec;
|
||||
AVFrame *mRawFrame;
|
||||
AVFrame *mFrame;
|
||||
_AVPIXELFORMAT imagePixFormat;
|
||||
|
||||
int OpenFfmpeg();
|
||||
int ReopenFfmpeg();
|
||||
int CloseFfmpeg();
|
||||
static int FfmpegInterruptCallback(void *ctx);
|
||||
static void* ReopenFfmpegThreadCallback(void *ctx);
|
||||
bool mIsOpening;
|
||||
bool mCanCapture;
|
||||
int mOpenStart;
|
||||
pthread_t mReopenThread;
|
||||
// Need to keep track of these because apparently the stream can start with values for pts/dts and then subsequent packets start at zero.
|
||||
int64_t audio_last_pts;
|
||||
int64_t audio_last_dts;
|
||||
int64_t video_last_pts;
|
||||
int64_t video_last_dts;
|
||||
|
||||
// Used to store the incoming packet, it will get copied when queued.
|
||||
// We only ever need one at a time, so instead of constantly allocating
|
||||
// and freeing this structure, we will just make it a member of the object.
|
||||
AVPacket packet;
|
||||
|
||||
int OpenFfmpeg();
|
||||
int ReopenFfmpeg();
|
||||
int CloseFfmpeg();
|
||||
static int FfmpegInterruptCallback(void *ctx);
|
||||
static void* ReopenFfmpegThreadCallback(void *ctx);
|
||||
bool mIsOpening;
|
||||
bool mCanCapture;
|
||||
int mOpenStart;
|
||||
pthread_t mReopenThread;
|
||||
#endif // HAVE_LIBAVFORMAT
|
||||
|
||||
VideoStore *videoStore;
|
||||
char oldDirectory[4096];
|
||||
unsigned int old_event_id;
|
||||
zm_packetqueue packetqueue;
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
struct SwsContext *mConvertContext;
|
||||
struct SwsContext *mConvertContext;
|
||||
#endif
|
||||
|
||||
public:
|
||||
FfmpegCamera( int p_id, const std::string &path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture );
|
||||
~FfmpegCamera();
|
||||
int64_t startTime;
|
||||
|
||||
const std::string &Path() const { return( mPath ); }
|
||||
const std::string &Options() const { return( mOptions ); }
|
||||
const std::string &Method() const { return( mMethod ); }
|
||||
public:
|
||||
FfmpegCamera( int p_id, const std::string &path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio );
|
||||
~FfmpegCamera();
|
||||
|
||||
void Initialise();
|
||||
void Terminate();
|
||||
const std::string &Path() const { return( mPath ); }
|
||||
const std::string &Options() const { return( mOptions ); }
|
||||
const std::string &Method() const { return( mMethod ); }
|
||||
|
||||
int PrimeCapture();
|
||||
int PreCapture();
|
||||
int Capture( Image &image );
|
||||
int PostCapture();
|
||||
void Initialise();
|
||||
void Terminate();
|
||||
|
||||
int PrimeCapture();
|
||||
int PreCapture();
|
||||
int Capture( Image &image );
|
||||
int CaptureAndRecord( Image &image, timeval recording, char* event_directory );
|
||||
int PostCapture();
|
||||
};
|
||||
|
||||
#endif // ZM_FFMPEG_CAMERA_H
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include "zm.h"
|
||||
#include "zm_file_camera.h"
|
||||
|
||||
FileCamera::FileCamera( int p_id, const char *p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) : Camera( p_id, FILE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture )
|
||||
FileCamera::FileCamera( int p_id, const char *p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : Camera( p_id, FILE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio )
|
||||
{
|
||||
strncpy( path, p_path, sizeof(path) );
|
||||
if ( capture )
|
||||
|
@ -87,5 +87,5 @@ int FileCamera::Capture( Image &image )
|
|||
|
||||
int FileCamera::PostCapture()
|
||||
{
|
||||
return( 0 );
|
||||
return( 0 );
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "zm_camera.h"
|
||||
#include "zm_buffer.h"
|
||||
#include "zm_regexp.h"
|
||||
#include "zm_packetqueue.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
|
@ -36,7 +37,7 @@ protected:
|
|||
char path[PATH_MAX];
|
||||
|
||||
public:
|
||||
FileCamera( int p_id, const char *p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture );
|
||||
FileCamera( int p_id, const char *p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio );
|
||||
~FileCamera();
|
||||
|
||||
const char *Path() const { return( path ); }
|
||||
|
@ -46,6 +47,7 @@ public:
|
|||
int PreCapture();
|
||||
int Capture( Image &image );
|
||||
int PostCapture();
|
||||
int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);};
|
||||
};
|
||||
|
||||
#endif // ZM_FILE_CAMERA_H
|
||||
|
|
3796
src/zm_image.cpp
3796
src/zm_image.cpp
File diff suppressed because it is too large
Load Diff
|
@ -54,7 +54,7 @@ extern imgbufcpy_fptr_t fptr_imgbufcpy;
|
|||
|
||||
/* Should be called from Image class functions */
|
||||
inline static uint8_t* AllocBuffer(size_t p_bufsize) {
|
||||
uint8_t* buffer = (uint8_t*)zm_mallocaligned(16,p_bufsize);
|
||||
uint8_t* buffer = (uint8_t*)zm_mallocaligned(64,p_bufsize);
|
||||
if(buffer == NULL)
|
||||
Fatal("Memory allocation failed: %s",strerror(errno));
|
||||
|
||||
|
@ -122,8 +122,8 @@ protected:
|
|||
}
|
||||
|
||||
public:
|
||||
enum { CHAR_HEIGHT=11, CHAR_WIDTH=6 };
|
||||
enum { LINE_HEIGHT=CHAR_HEIGHT+0 };
|
||||
enum { ZM_CHAR_HEIGHT=11, ZM_CHAR_WIDTH=6 };
|
||||
enum { LINE_HEIGHT=ZM_CHAR_HEIGHT+0 };
|
||||
|
||||
protected:
|
||||
static bool initialised;
|
||||
|
@ -264,6 +264,8 @@ public:
|
|||
/* Blend functions */
|
||||
void sse2_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent);
|
||||
void std_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent);
|
||||
void neon32_armv7_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent);
|
||||
void neon64_armv8_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent);
|
||||
void std_blend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent);
|
||||
|
||||
/* Delta functions */
|
||||
|
@ -274,6 +276,16 @@ void std_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result,
|
|||
void std_delta8_bgra(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void std_delta8_argb(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void std_delta8_abgr(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void neon32_armv7_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void neon32_armv7_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void neon32_armv7_delta8_bgra(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void neon32_armv7_delta8_argb(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void neon32_armv7_delta8_abgr(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void neon64_armv8_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void neon64_armv8_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void neon64_armv8_delta8_bgra(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void neon64_armv8_delta8_argb(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void neon64_armv8_delta8_abgr(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void sse2_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void sse2_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
void sse2_delta8_bgra(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
|
||||
|
@ -293,6 +305,9 @@ void std_convert_argb_gray8(const uint8_t* col1, uint8_t* result, unsigned long
|
|||
void std_convert_abgr_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
|
||||
void std_convert_yuyv_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
|
||||
void ssse3_convert_rgba_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
|
||||
void ssse3_convert_bgra_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
|
||||
void ssse3_convert_argb_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
|
||||
void ssse3_convert_abgr_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
|
||||
void ssse3_convert_yuyv_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
|
||||
void zm_convert_yuyv_rgb(const uint8_t* col1, uint8_t* result, unsigned long count);
|
||||
void zm_convert_yuyv_rgba(const uint8_t* col1, uint8_t* result, unsigned long count);
|
||||
|
@ -309,8 +324,3 @@ void std_deinterlace_4field_rgba(uint8_t* col1, uint8_t* col2, unsigned int thre
|
|||
void std_deinterlace_4field_bgra(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
|
||||
void std_deinterlace_4field_argb(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
|
||||
void std_deinterlace_4field_abgr(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
|
||||
void ssse3_deinterlace_4field_gray8(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
|
||||
void ssse3_deinterlace_4field_rgba(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
|
||||
void ssse3_deinterlace_4field_bgra(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
|
||||
void ssse3_deinterlace_4field_argb(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
|
||||
void ssse3_deinterlace_4field_abgr(uint8_t* col1, uint8_t* col2, unsigned int threshold, unsigned int width, unsigned int height);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue