diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 374b7bf03..e20da017b 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -33,7 +33,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.31.0 +Version: 1.31.1 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/distros/ubuntu1604/zoneminder.postinst b/distros/ubuntu1604/zoneminder.postinst index a8f93c4d0..9e3f117a4 100644 --- a/distros/ubuntu1604/zoneminder.postinst +++ b/distros/ubuntu1604/zoneminder.postinst @@ -4,61 +4,60 @@ set -e if [ "$1" = "configure" ]; then - . /etc/zm/zm.conf + . /etc/zm/zm.conf - # The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group - chown www-data:root /var/log/zm - chown www-data:www-data /var/lib/zm - 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 + # The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group + chown www-data:root /var/log/zm + chown www-data:www-data /var/lib/zm + 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 + # Ensure zoneminder is stopped + deb-systemd-invoke stop zoneminder.service || exit $? if [ "$ZM_DB_HOST" = "localhost" ]; then - if [ -e "/etc/init.d/mysql" ]; then + if [ -e "/etc/init.d/mysql" ]; then - # - # Get mysql started if it isn't - # - if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then - deb-systemd-invoke start mysql.service || exit $? - fi + # + # Get mysql started if it isn't + # + if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then + deb-systemd-invoke start mysql.service || exit $? + fi - if $(/etc/init.d/mysql status >/dev/null 2>&1); then - mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload - # test if database if already present... - if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then - cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf - # This creates the user. - echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql - else - echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql - fi - - # Ensure zoneminder is stopped - deb-systemd-invoke stop zoneminder.service || exit $? - zmupdate.pl --nointeractive - zmupdate.pl --nointeractive -f - echo "Done Updating, starting ZoneMinder" - deb-systemd-invoke start zoneminder.service || exit $? - - else - echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.' - fi + if $(/etc/init.d/mysql status >/dev/null 2>&1); then + mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload + # test if database if already present... + if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then + cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf + # This creates the user. + echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql else - echo 'mysql not found, assuming remote server.' + echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql fi + zmupdate.pl --nointeractive + zmupdate.pl --nointeractive -f + else + echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.' + fi else - echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)" + echo 'mysql not found, assuming remote server.' fi + else + echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)" + fi + echo "Done Updating, starting ZoneMinder" + deb-systemd-invoke restart zoneminder.service || exit $? + fi #DEBHELPER# diff --git a/docs/userguide/definemonitor.rst b/docs/userguide/definemonitor.rst index 70ccbeb4b..66e8928d3 100644 --- a/docs/userguide/definemonitor.rst +++ b/docs/userguide/definemonitor.rst @@ -77,7 +77,7 @@ Source Path Use this field to enter the full URL of the stream or file your camera supports. This is usually an RTSP url. There are several methods to learn this: * Check the documentation that came with your camera - * Look for your camera in the hardware compatibilty list in the wiki http://wiki.zoneminder.com/Hardware_Compatibilty_List + * Look for your camera in the hardware compatibilty list in the wiki http://wiki.zoneminder.com/Hardware_Compatibility_List * Try ZoneMinder's new ONVIF probe feature * Download and install the ONVIF Device Manager onto a Windows machine https://sourceforge.net/projects/onvifdm/ * Use Google to find third party sites, such as ispy, which document this information diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 4cd589b6f..f841c82c6 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -31,7 +31,6 @@ #include "zm.h" #include "zm_db.h" #include "zm_time.h" -#include "zm_mpeg.h" #include "zm_signal.h" #include "zm_event.h" #include "zm_monitor.h" @@ -591,4 +590,3 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * } */ } - diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index c0cb601b3..c34e46a85 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -35,12 +35,11 @@ #include "zm_signal.h" #include "zm_event.h" #include "zm_eventstream.h" -#include "zm_ffmpeg_input.h" +#include "zm_storage.h" +#include "zm_monitor.h" #include "zm_sendfile.h" -//#define USE_PREPARED_SQL 1 - bool EventStream::loadInitialEventData( int monitor_id, time_t event_time ) { static char sql[ZM_SQL_SML_BUFSIZ]; @@ -132,9 +131,13 @@ bool EventStream::loadEventData( int event_id ) { event_data = new EventData; event_data->event_id = event_id; event_data->monitor_id = atoi( dbrow[0] ); - event_data->start_time = atoi(dbrow[3]); - event_data->storage_id = dbrow[1] ? atoi( dbrow[1] ) : 0; + event_data->frame_count = dbrow[2] == NULL ? 0 : atoi(dbrow[2]); + event_data->start_time = atoi(dbrow[3]); + event_data->duration = atof(dbrow[4]); + strncpy( event_data->video_file, dbrow[5], sizeof( event_data->video_file )-1 ); + mysql_free_result( result ); + Storage * storage = new Storage( event_data->storage_id ); const char *storage_path = storage->Path(); @@ -150,13 +153,9 @@ bool EventStream::loadEventData( int event_id ) { else snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%ld", staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id ); } - event_data->frame_count = dbrow[2] == NULL ? 0 : atoi(dbrow[3]); - event_data->duration = atof(dbrow[4]); - strncpy( event_data->video_file, dbrow[5], sizeof( event_data->video_file )-1 ); updateFrameRate( (double)event_data->frame_count/event_data->duration ); - mysql_free_result( result ); snprintf( sql, sizeof(sql), "select FrameId, unix_timestamp( `TimeStamp` ), Delta from Frames where EventId = %d order by FrameId asc", event_id ); if ( mysql_query( &dbconn, sql ) ) { @@ -209,10 +208,10 @@ bool EventStream::loadEventData( int event_id ) { //} if ( event_data->video_file[0] ) { - char *filepath[MAX_PATH]; - snprintf( filepath, sizeof(filepath), "%s/%s", event_data->path, event_data->video_file[0] ); + char filepath[PATH_MAX]; + snprintf( filepath, sizeof(filepath), "%s/%s", event_data->path, event_data->video_file ); ffmpeg_input = new FFmpeg_Input(); - if ( ! ffmpeg->Open() ) { + if ( ! ffmpeg_input->Open( filepath ) ) { delete ffmpeg_input; ffmpeg_input = NULL; } @@ -248,15 +247,18 @@ void EventStream::processCommand( const CmdMsg *msg ) { case CMD_PLAY : { Debug( 1, "Got PLAY command" ); - if ( paused ) - { + if ( paused ) { // Clear paused flag paused = false; } // If we are in single event mode and at the last frame, replay the current event - if ( (mode == MODE_SINGLE) && ((unsigned int)curr_frame_id == event_data->frame_count) ) + if ( (mode == MODE_SINGLE) && ((unsigned int)curr_frame_id == event_data->frame_count) ) { + Debug(1, "Was in single_mode, and last frame, so jumping to 1st frame"); curr_frame_id = 1; + } else { + Debug(1, "mode is %s, current frame is %d, frame count is %d", (mode == MODE_SINGLE ? "single" : "not single" ), curr_frame_id, event_data->frame_count ); + } replay_rate = ZM_RATE_BASE; break; @@ -381,7 +383,9 @@ void EventStream::processCommand( const CmdMsg *msg ) { zoom = 500; break; } + send_frame = true; break; + } case CMD_ZOOMOUT : { @@ -404,6 +408,7 @@ void EventStream::processCommand( const CmdMsg *msg ) { zoom = 100; break; } + send_frame = true; break; } case CMD_PAN : @@ -446,6 +451,7 @@ void EventStream::processCommand( const CmdMsg *msg ) { int offset = ((unsigned char)msg->msg_data[1]<<24)|((unsigned char)msg->msg_data[2]<<16)|((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; curr_frame_id = (int)(event_data->frame_count*offset/event_data->duration); Debug( 1, "Got SEEK command, to %d (new cfid: %d)", offset, curr_frame_id ); + send_frame = true; break; } case CMD_QUERY : @@ -476,13 +482,13 @@ void EventStream::processCommand( const CmdMsg *msg ) { status_data.rate = replay_rate; status_data.zoom = zoom; status_data.paused = paused; - Debug( 2, "E:%d, P:%d, p:%d R:%d, Z:%d", - status_data.event, - status_data.paused, - status_data.progress, - status_data.rate, - status_data.zoom - ); + Debug( 2, "Event:%d, Paused:%d, progress:%d Rate:%d, Zoom:%d", + status_data.event, + status_data.paused, + status_data.progress, + status_data.rate, + status_data.zoom + ); DataMsg status_msg; status_msg.msg_type = MSG_DATA_EVENT; @@ -700,10 +706,10 @@ bool EventStream::sendFrame( int delta_us ) { Error("Unable to send raw frame %u: %s",curr_frame_id,strerror(errno)); return( false ); } -#endif +#endif fclose(fdj); /* Close the file handle */ } else { - fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size ); + fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size ); if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) { Error( "Unable to send stream frame: %s", strerror(errno) ); return( false ); @@ -734,10 +740,13 @@ void EventStream::runStream() { exit( 0 ); } - unsigned int delta_us = 0; while( !zm_terminate ) { gettimeofday( &now, NULL ); + unsigned int delta_us = 0; + send_frame = false; + + // commands may set send_frame to true while(checkCommandQueue()); if ( step != 0 ) @@ -773,17 +782,14 @@ void EventStream::runStream() { } //else //{ - usleep( STREAM_PAUSE_WAIT ); - //curr_stream_time += (replay_rate>0?1:-1) * ((1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000)); - curr_stream_time += (1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000); + usleep( STREAM_PAUSE_WAIT ); + //curr_stream_time += (replay_rate>0?1:-1) * ((1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000)); + curr_stream_time += (1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000); //} continue; } - } - // Figure out if we should send this frame - bool send_frame = false; - if ( !paused ) { + // Figure out if we should send this frame // If we are streaming and this frame is due to be sent if ( ((curr_frame_id-1)%frame_mod) == 0 ) { delta_us = (unsigned int)(frame_data->delta * 1000000); @@ -819,7 +825,8 @@ void EventStream::runStream() { curr_frame_id = 1; if ( send_frame && type != STREAM_MPEG ) { Debug( 3, "dUs: %d", delta_us ); - usleep( delta_us ); + if ( delta_us ) + usleep( delta_us ); } } else { usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) ); diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h index b844913eb..07e161214 100644 --- a/src/zm_eventstream.h +++ b/src/zm_eventstream.h @@ -20,24 +20,13 @@ #ifndef ZM_EVENTSTREAM_H #define ZM_EVENTSTREAM_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include -#include "zm.h" #include "zm_image.h" #include "zm_stream.h" #include "zm_video.h" +#include "zm_ffmpeg_input.h" #ifdef __cplusplus extern "C" { @@ -80,15 +69,15 @@ class EventStream : public StreamBase { static const StreamMode DEFAULT_MODE = MODE_SINGLE; - protected: StreamMode mode; bool forceEventChange; - protected: int curr_frame_id; double curr_stream_time; + bool send_frame; EventData *event_data; + FFmpeg_Input *ffmpeg_input; protected: bool loadEventData( int event_id ); @@ -114,6 +103,7 @@ class EventStream : public StreamBase { input_codec_context = 0; input_codec = 0; + ffmpeg_input = NULL; } void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) { diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index 1e8cad8b5..b47e573b7 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -1,13 +1,17 @@ #include "zm_ffmpeg_input.h" +#include "zm_logger.h" +#include "zm_ffmpeg.h" -void FFmpeg_Input() { +FFmpeg_Input::FFmpeg_Input() { input_format_context = NULL; video_stream_id = -1; audio_stream_id = -1; } +FFmpeg_Input::~FFmpeg_Input() { +} -int Open( const char *filepath ) { +int FFmpeg_Input::Open( const char *filepath ) { int error; @@ -54,18 +58,18 @@ int Open( const char *filepath ) { #endif /** Find a decoder for the audio stream. */ - if (!(streams[i].codec = avcodec_find_decoder((*input_format_context)->streams[i]->codecpar->codec_id))) { + if (!(streams[i].codec = avcodec_find_decoder(input_format_context->streams[i]->codecpar->codec_id))) { Error( "Could not find input codec\n"); - avformat_close_input(input_format_context); + avformat_close_input(&input_format_context); return AVERROR_EXIT; } /** Open the decoder for the audio stream to use it later. */ if ((error = avcodec_open2( streams[i].context, streams[i].codec, NULL)) < 0) { - Errror( "Could not open input codec (error '%s')\n", + Error( "Could not open input codec (error '%s')\n", av_make_error_string(error).c_str() ); - avcodec_free_context( streams[i].context ); - avformat_close_input(input_format_context); + avcodec_free_context( &streams[i].context ); + avformat_close_input(&input_format_context); return error; } @@ -76,5 +80,5 @@ int Open( const char *filepath ) { Debug( 3, "Unable to locate audio stream in %s", filepath ); return 0; -} // end int Open( const char * filepath ) +} // end int FFmpeg::Open( const char * filepath ) diff --git a/src/zm_ffmpeg_input.h b/src/zm_ffmpeg_input.h index bc884c95a..9a2147bd0 100644 --- a/src/zm_ffmpeg_input.h +++ b/src/zm_ffmpeg_input.h @@ -32,6 +32,6 @@ class FFmpeg_Input { int video_stream_id; int audio_stream_id; AVFormatContext *input_format_context; -} +}; #endif diff --git a/src/zm_sendfile.h b/src/zm_sendfile.h index 1d59a7c1e..2f892d693 100644 --- a/src/zm_sendfile.h +++ b/src/zm_sendfile.h @@ -8,30 +8,30 @@ extern "C" { #ifdef HAVE_SENDFILE4_SUPPORT #include int zm_sendfile(int out_fd, int in_fd, off_t *offset, size_t size) { - int err; + int err; - err = sendfile(out_fd, in_fd, offset, size); - if (err < 0) - return -errno; + err = sendfile(out_fd, in_fd, offset, size); + if (err < 0) + return -errno; - return err; + return err; } #elif HAVE_SENDFILE7_SUPPORT #include #include #include int zm_sendfile(int out_fd, int in_fd, off_t *offset, off_t size) { - int err; - err = sendfile(in_fd, out_fd, *offset, size, NULL, &size, 0); - if (err && errno != EAGAIN) - return -errno; + int err; + err = sendfile(in_fd, out_fd, *offset, size, NULL, &size, 0); + if (err && errno != EAGAIN) + return -errno; - if (size) { - *offset += size; - return size; - } + if (size) { + *offset += size; + return size; + } - return -EAGAIN; + return -EAGAIN; } #else #error "Your platform does not support sendfile. Sorry." diff --git a/src/zms.cpp b/src/zms.cpp index c1d577a6d..a7a709f74 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -112,6 +112,8 @@ int main( int argc, const char *argv[] ) { char *value = strtok( NULL, "=" ); if ( !value ) value = (char *)""; + + Debug(4, "Query string parameter (%s)=(%s)", name, value ); if ( !strcmp( name, "source" ) ) { source = !strcmp( value, "event" )?ZMS_EVENT:ZMS_MONITOR; } else if ( !strcmp( name, "mode" ) ) { @@ -187,7 +189,7 @@ int main( int argc, const char *argv[] ) { if ( *auth ) { user = zmLoadAuthUser( auth, config.auth_hash_ips ); } else { - Debug( 1, "Need both username and password" ); + Debug( 1, "Need both username and password if auth not specified" ); } } //else if ( strcmp( config.auth_relay, "plain" ) == 0 ) diff --git a/web/includes/Filter.php b/web/includes/Filter.php index 2652daf31..071b2471a 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -72,6 +72,9 @@ public $defaults = array( if ( ! isset( $this->{'terms'} ) ) { if ( array_key_exists( 'Query', $this ) and $this->{'Query'} ) { $this->{'terms'} = jsonDecode( $this->{'Query'} ); + if ( isset( $this->{'terms'}['terms'] ) ) + $this->{'terms'} = $this->{'terms'}['terms']; + } else { $this->{'terms'} = array(); } diff --git a/web/includes/actions.php b/web/includes/actions.php index 016de090c..7ebed6e18 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -138,7 +138,7 @@ if ( !empty($action) ) { } else { $sql .= ' Name = '.dbEscape($_REQUEST['filter']['Name']); } - $sql .= ', Query = '.dbEscape(jsonEncode($_REQUEST['filter']['terms'])); + $sql .= ', Query = '.dbEscape(jsonEncode($_REQUEST['filter'])); $sql .= ', AutoArchive = '.(!empty($_REQUEST['filter']['AutoArchive']) ? 1 : 0); $sql .= ', AutoVideo = '. ( !empty($_REQUEST['filter']['AutoVideo']) ? 1 : 0); $sql .= ', AutoUpload = '. ( !empty($_REQUEST['filter']['AutoUpload']) ? 1 : 0); diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 1485062c1..0849a827b 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -50,6 +50,7 @@ if ( isset( $_REQUEST['scale'] ) ) { } $replayModes = array( + 'none' => translate('None'), 'single' => translate('ReplaySingle'), 'all' => translate('ReplayAll'), 'gapless' => translate('ReplayGapless'), @@ -64,9 +65,9 @@ if ( isset( $_REQUEST['replayMode'] ) ) $replayMode = validHtmlStr($_REQUEST['replayMode']); if ( isset( $_COOKIE['replayMode']) && preg_match('#^[a-z]+$#', $_COOKIE['replayMode']) ) $replayMode = validHtmlStr($_COOKIE['replayMode']); -else { - $keys = array_keys( $replayModes ); - $replayMode = array_shift( $keys ); + +if ( ( ! $replayMode ) or ( ! $replayModes[$replayMode] ) ) { + $replayMode = 'none'; } // videojs zoomrotate only when direct recording @@ -188,8 +189,8 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) { - - + + @@ -209,7 +210,7 @@ if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT ) { SaveJPEGs() & 3 ) { // frames or analysis + if ( $Event->SaveJPEGs() & 3 ) { // frames or analysis ?>